Skocz do zawartości

Kurs Qt – #2 – komunikacja z Arduino przez UART


Komentator

Pomocna odpowiedź

Kurs Qt – #2 – komunikacja z Arduino przez UART

Pora na kolejny artykuł omawiający podstawy Qt. Tym razem zajmiemy się komunikacją przez port szeregowy. Dzięki temu połączymy komputer PC z Arduino (lub innym mikrokontrolerem). W ramach ćwiczeń stworzymy własny monitor portu szeregowego, który będzie mógł sterować pracą Arduino.

UWAGA, to tylko wstęp! Dalsza część artykułu dostępna jest na blogu.

Przeczytaj całość »

Poniżej znajdują się komentarze powiązane z tym wpisem.

Link do komentarza
Share on other sites

Bardzo fajny poradnik 🙂

Znalazłem jednak jedną rzecz, mianowicie nie usuwasz nigdzie QSerialPort. Najprościej zamienić ten fragment kodu:

//this->device = new QSerialPort;
this->device = new QSerialPort(this); //Ustawiamy rodzica obiektu

Dzięki temu w momencie usunięcia obiektu klasy MainWindow zostanie usunięty obiekt device.

pozdrawiam i czekam na kolejne części 🙂

  • Lubię! 2
Link do komentarza
Share on other sites

Bardzo cenna uwaga (y). Dla czytelników, którzy bedą to czytać - zawsze zwalniajcie poprawnie pamięć w swoich programach niezależne od sytuacji - w tym przykładzie akurat taki memory leak to jeszcze nie jest nic złego. Tworzymy obiekt QSerialPort raz i żyje on sobie do momentu aż proces naszej aplikacji się zakończy, wtedy pamięć po naszym obiekcie powinien zwolnić system (powinien jeśli to obsługuje - dyskusja na stacku). Sprawa przybrałaby bardzo nieprzyjemny obrót gdybyśmy tworzyli nowe obiekty cyklicznie i nie zwalniali po nich pamięci, a nasz program miałby pracować przez długi czas. Więc szanujmy naszą pamięć. 

Jest tutaj jeszcze jeden wysublimowany problem: gdybyśmy otworzyli port i zamknęli aplikację (wcześniej tego portu nie zamykając) to nie wywoła się destruktor obiektu QSerialPort, który między innymi ten port zamyka gdy jest otwarty. Wtedy przy ponownym uruchomieniu aplikacji moglibyśmy się bardzo zirytować niemogąc otworzyć portu ponownie (kto miał taki problem ten wie).


Poprawka powinna się niedługo pojawić na stronie.

  • Lubię! 1
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Skoro masz uwagi do czytelników, pozwól że ja będę miał uwagę do pisarzy. Alokowane zasoby należy zawsze zwalniać. Poleganie na systemie świadczy o słabej jakości programu i nawet jeśli nie doprowadzi do katastrofy, należałoby tego unikać.

Jak dla mnie wystarczyłoby napisać - w przykładzie pojawił się błąd, każdemu się zdarza i koniec.

Edit: Trochę przesadziłem ze złośliwością w pierwszej wersji, dokonałem autocenzury, przepraszam.

Edytowano przez Elvis
Link do komentarza
Share on other sites

5 minut temu, Elvis napisał:

Alokowane zasoby należy zawsze zwalniać

To już jako offtopicowa ciekawostka - cytat z jakiekośtam podręcznika do PHP z początku tysiąclecia (niedokładny bo z pamięci):

"Nie należy wywoływać funkcji mysql_result_free, zasoby zostaną zwolnione automatycznie po wykonaniu skryptu."

Niestety - wśród starszych "programistów" tego "języka programowania" do dziś jest to chyba dogmatem 😞

 

Link do komentarza
Share on other sites

17 godzin temu, erulission napisał:

Znalazłem jednak jedną rzecz, mianowicie nie usuwasz nigdzie QSerialPort. Najprościej zamienić ten fragment kodu:


//this->device = new QSerialPort;
this->device = new QSerialPort(this); //Ustawiamy rodzica obiektu

Dzięki temu w momencie usunięcia obiektu klasy MainWindow zostanie usunięty obiekt device.

Poprawka i opis do niej znajduje się już w artykule.

  • Lubię! 1
Link do komentarza
Share on other sites

W przypadku testowania programu z Arduino Due spotkałem się z dziwnym zjawiskiem:

Przesyłanie danych do Arduino odbywa się bez przeszkód, ale nie mogę odczytać informacji z płytki. Problem rozwiązuje się po wcześniejszym uruchomieniu Arduino IDE i włączeniu i wyłączeniu w nim monitora portu szeregowego.

Sprawdzałem program na Arduino Uno i wszystko działało bez problemu. (między programami w Arduino Uno i Due zmieniałem Serial -> SerialUSB oraz dodałem dla DUE funkcję SerialEvent, bo z tego co wiem to ta płytka takowej nie posiada).

Ktoś ma może jakiś pomysł z czego to może wynikać?

Link do komentarza
Share on other sites

@klarec 

Sprawdziłem właśnie u siebie korzystając z Due - wgrałem identyczny soft jak w kursie - korzystam z Serial (Serial0) i nie mam żadnych problemów z komunikacją w obie strony. 

Czy Qt otworzyło Ci port bez problemu? Możesz wykorzystać sygnał QSerialPort::errorOccurred żeby zobaczyć błąd jeśli jakiś się pojawi:

//mainwindow.h:
private slots:
	//...
    void onErrorOccurred(QSerialPort::SerialPortError error);

// mianwindow.cpp:
MainWindow::MainWindow(QWidget *parent) :
    //...
{
    //...
    connect(device, SIGNAL(errorOccurred(QSerialPort::SerialPortError)), this, SLOT(onErrorOccurred(QSerialPort::SerialPortError)));
}

void MainWindow::onErrorOccurred(QSerialPort::SerialPortError error)
{
    qDebug() << error << device->error();
}

Może sprawa dotyczy dostępu do portu? Może np. IDE otworzyło port i go nie zamknęło, wtedy ponowne otwarcie i zamknięcie portu go odblokowało? Może problem wynika z tego, że korzystasz z SerialUSB - na Serial jest to samo?

  • Lubię! 1
Link do komentarza
Share on other sites

@Matthew11 Sprawdziłem czy występują błędy Twoją metodą, błędów nie ma: QSerialPort::NoError QSerialPort::NoError.

Spróbowałem też użyć Serial, ale wtedy nie działa komunikacja w żadną stronę, nie pokazuje też w monitorze portu szeregowego.

Kod, który użyłem na Arduino (podmienione na Serial):

const uint8_t ledPin = LED_BUILTIN;
uint32_t interval = 1000;
uint32_t previousMillis = 0;

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);
}

void loop() {
  uint32_t currentMillis = millis();
  if(currentMillis - previousMillis > interval) {
    previousMillis = currentMillis;
    Serial.println("Czas procesora = " + String(currentMillis));
  }
  while (Serial.available()) {
    
    char state = (char)Serial.read();
    if(state == '0') {
      digitalWrite(ledPin, 0);
    } else if(state == '1') {
      digitalWrite(ledPin, 1);
    }

    Serial.println("Potwierdzam odbior. Status diody = " + String(state));
  
}
}

 

Myślę, że to też nie jest kwestia niezamknięcia portu przez Arduino IDE, testowałem program po wgraniu i resecie Arduino, na wszelki wypadek też przy wyłączonym IDE i nadal było to samo.

 

@Treker Moje Due to klon. Może faktycznie to decyduje o działaniu programu. ( klon na CH340)

Link do komentarza
Share on other sites

Mam problem z NucleoF446RE a mianowicie program w Qt zadziała tylko raz. Po połączeniu mogę tylko raz zapalić diode, później musze rozłączyć i połączyć i tak w kółko. Co może być problemem?? Wygląda jakbym miał zapchany port.

Terminal działa za to bez problemowo..

Obsługa w Qt oraz nucleo... Proszę o pomoc.. już nie mam siły a chciałbym się z tym dogadać i zrozumieć żeby ruszyć dalej;/

/* USER CODE BEGIN PFP */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	uint8_t Data[50]; // Tablica przechowujaca wysylana wiadomosc.
	uint16_t size = 0; // Rozmiar wysylanej wiadomosci
{

		 // Odebrany znak zostaje przekonwertowany na liczbe calkowita i sprawdzony
		 // instrukcja warunkowa
		 switch (atoi(&Received)) {

		 case 0: // Jezeli odebrany zostanie znak 0
		 size = sprintf(Data, "STOP\n\r");
		 HAL_GPIO_WritePin(D1_GPIO_Port, D1_Pin, GPIO_PIN_RESET);
		 break;

		 case 1: // Jezeli odebrany zostanie znak 1
		 size = sprintf(Data, "START\n\r");
		 HAL_GPIO_WritePin(D1_GPIO_Port, D1_Pin, GPIO_PIN_SET);
		 break;

		 }
HAL_UART_Transmit_IT(&huart2, Data, size); // Rozpoczecie nadawania danych z wykorzystaniem przerwan
 HAL_UART_Receive_IT(&huart2, &Received, 1); // Ponowne włączenie nasłuchiwania
}
}
/* USER CODE END PFP */
void MainWindow::sendMessageToDevice(QString message)
{
    if(this->device->isOpen() && this->device->isWritable())
    {
        this->addToLogs("Wysyłam informacje do urządzenia " + message);
        this->device->write(message.toStdString().c_str());
    }
    else
    {
        this->addToLogs("Nie mogę wysłać wiadomości. Port nie jest otwarty!");
    }
}
void MainWindow::on_pushButtonLedOn_clicked()
{
    this->sendMessageToDevice("1");

}

void MainWindow::on_pushButtonLedOff_clicked()
{
    this->sendMessageToDevice("0") ;
    return;
}

 

Link do komentarza
Share on other sites

Cześć @dernis czy fragment "Terminal działa za to bez problemowo" mam rozumieć tak, że łącząc się przez Putty lub coś podobnego z STMem wysyłając 1 lub 0 możesz sterować diodą? Co sugeruje że problem znajduje się po stronie programu w Qt. Fragmenty aplikacji, które załączyłeś wyglądają w porządku, w on_pushButtonLedOff_clicked() masz dodatkowo return; na końcu, którego nie ma w on_pushButtonLedOn_clicked() ale nie sądzę żeby to było problemem. 

Możesz też nieco przepisać kod i odsyłać to samo co wysyła PC na zasadzie echa żeby zobaczyć co dokładnie wysyła aplikacja w Qt a co terminal, żeby sprawdzić zawartość Received. Możesz też dodać default case w switchu switch (atoi(&Received)) i za komentować case 0 - na zasadzie jak 1 to zapal, a wszystko inne zgaś. Musisz dokładniej opisać zachowanie, żeby można było powiedzieć coś więcej.

Edytowano przez Matthew11
  • Lubię! 2
Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.