Skocz do zawartości

Problem z połączeniem szeregowym przez USB


Rysiek

Pomocna odpowiedź

Cześć,

Próbuję napisać mały program komunikujący się z arduino po USB. niestety nie działa poprawnie i niespecjalnie jestem w stanie dojść dlaczego tak sie dzieje.

Problem polega na tym, że na wyjściu dostaje dosyć losowe dane... czasami przychodzi poprawny ciąg znaków, ale przeważnie jest to albo fragment, albo nic. dodatkowo nigdy nie zapala mi zielonej diody, tak jakby arduino nigdy nie dostał poprawnego stringa

Część c++:


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <sys/ioctl.h>


int main(int argc, char *argv[])
{
 int fd, n, i;
 char buf[64];
 struct termios toptions;


 fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY);
 printf("fd opened as %i\n", fd);

 usleep(3500000);

 tcgetattr(fd, &toptions);
 cfsetispeed(&toptions, B9600);
 cfsetospeed(&toptions, B9600);
 toptions.c_cflag &= ~PARENB;
 toptions.c_cflag &= ~CSTOPB;
 toptions.c_cflag &= ~CSIZE;
 toptions.c_cflag |= CS8;
 toptions.c_lflag |= ICANON;
 tcsetattr(fd, TCSANOW, &toptions);

 char dane[] = "greenOn\n";

 write(fd, dane, sizeof(dane));
 n = read(fd, buf, 64);
 buf[n] = 0;

 printf("%i recived: %s\n", n, buf);


 return 0;
}

a część arduino:

String odebraneDane = "";
void setup()
{
 Serial.begin(9600);
 pinMode(9, OUTPUT);
}

void loop()
{
 if (Serial.available() > 0)
 {
   odebraneDane = Serial.readStringUntil('\n');
   if (odebraneDane.equals("greenOn")){
   digitalWrite(9, HIGH);
   }
   Serial.println(odebraneDane);
   Serial.read();
 }
}

resultaty wywołań:

fd opened as 3

10 recived:

fd opened as 3

3 recived:

fd opened as 3

11 recived: gregreenOn

fd opened as 3

9 recived:

czy ktos wie może co robię źle?

Pozdrawiam

Link do komentarza
Share on other sites

Masz w zasadzie dwa oddzielne problemy:

1) Przesyłanie danych PC-> arduino i zapalanie diody

Spróbuj za pomocą terminala wysłać string 'greenOn\n', a w kodzie Arduino dodać sobie Serial.println(odebraneDane) i zobacz co odbiera Arduino. Jakbyś miał debugger to nie trzeba by się w takie rzeczy bawić. Uroki Arduino.

2) Odbieranie danych na PC

Pierwsza rzecz jaka mi przychodzi do głowy to brak oczekiwania po wysłaniu danych - zakładając, że po wysłaniu danych z PC oczekujesz odpowiedzi układu. Teoretycznie zabezpieczasz się przed tym przez wykorzystanie zmiennej 'n'.

Spróbuj uprościć problem i na Arduino napisz program, który co np. 1000ms wysyła jakiś string, a w programie na PC w pętli nieskończonej odbierasz dane (jeśli są dostępne - funkcja ioctl).

Link do komentarza
Share on other sites

Masz w zasadzie dwa oddzielne problemy:

1) Przesyłanie danych PC-> arduino i zapalanie diody

Spróbuj za pomocą terminala wysłać string 'greenOn\n', a w kodzie Arduino dodać sobie Serial.println(odebraneDane) i zobacz co odbiera Arduino. Jakbyś miał debugger to nie trzeba by się w takie rzeczy bawić. Uroki Arduino.

To już próbowałem, jeśli wysyłam ciąg z monitora portu w adrduinoIDE to wszystko działa super. 😋 problem pojawił się tylko w przypadku mojego programu.

2) Odbieranie danych na PC

Pierwsza rzecz jaka mi przychodzi do głowy to brak oczekiwania po wysłaniu danych - zakładając, że po wysłaniu danych z PC oczekujesz odpowiedzi układu. Teoretycznie zabezpieczasz się przed tym przez wykorzystanie zmiennej 'n'.

Spróbuj uprościć problem i na Arduino napisz program, który co np. 1000ms wysyła jakiś string, a w programie na PC w pętli nieskończonej odbierasz dane (jeśli są dostępne - funkcja ioctl).

Hmmm jeśli po prostu wysyłam stringa z arduino komputer bez problemu go odbiera. poprawnie.

Cięzko powiedzieć co się dzieje, ale wrzuciłem w pentli wysyłanie i odbieranie (z 1 sekundowym sleepem) i wyszło dysyć ciekawie...

Zdarzały się odstępstwa, ale bardzo rzadko, większość prób wyglądało tak:

fd opened as 3

Cycle 0

9 send: greenOn

3 recived:

Cycle 1

9 send: greenOn

9 recived: greenOn

Cycle 2

9 send: greenOn

10 recived:

Cycle 3

9 send: greenOn

10 recived:

Cycle 4

9 send: greenOn

10 recived:

prawie zawsze w drugiej próbie wychodziło dobrze...

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

pewnie będzie trzeba....

Mam coraz większe przekonanie, że to jest kwestia wysyłania danych do arduino, jeśli zamiast tego co przychodzi wysyłam z powrotem cokolwiek innego, to odbieram całkiem nieźle...

[ Dodano: 13-04-2018, 18:57 ]

No dobra, wygląda że obszedłem problem i działa... przepisałem kod na jakiś znaleziony w internecie i w ten sposób to działa. Ważne jest, żeby zamiast \n jako terminatora stringu użyć innego znaku (u mnie .) z jakiegoś powodu znak końca linii się nie przesyła 😋

#include <fstream>
#include <iostream>
#include <unistd.h>
int main()
{
   std::cout << "Opening fstream" << std::endl;
   std::fstream file("/dev/ttyACM0");
    usleep(3500000);
   std::cout << "Lit the green led" << std::endl;
   file << "greenOn." << std::endl; // endl does flush, which may be important
   std::cout << "Data Sent" << std::endl;
   std::cout << "Awaiting response" << std::endl;
   std::string response;
   file >> response;
   std::cout << "Response: " << response << std::endl;

   return 0;
}

po stronie andirino:

void setup()
{
 Serial.begin(9600);
 pinMode(9, OUTPUT);
}

void loop()
{
 if (Serial.available() > 0)
 {
   String odebraneDane = Serial.readStringUntil('.');

   if (odebraneDane.equals("greenOn")){
   digitalWrite(9, HIGH);
   Serial.println("odebraneDane");
   } else {
   Serial.println(odebraneDane);
   }
 }
}
Link do komentarza
Share on other sites

Gość es2

Jak raz jest dobrze raz źle to potencjalnymi problemami jest:

- przepełnianie bufora

- brak ram

- przerwania

Stawiam na jedna z dwu pierwszych opcji.

Link do komentarza
Share on other sites

es2, lepiej dzisiaj w totka nie graj.

* Przepełnienie bufora - nie bierze się znikąd, program wygląda ok

* brak ram - problemy są po stronie PC, pewnie kilka GB ramu, myślisz że taki programik wykorzysta cały?

* przerwania - program nic w przerwaniach nie robi, tzn. robi wszystko za niego system operacyjny i biblioteki Arduino

Więc proponowałbym inne typowanie:

1) trzeba doczytać jak działają funkcje read() i write() pod Linuxem. Podpowiem, że nie zapisują ani nie odczytują tylu bajtów ile im się podaje jako parametr. Mogą obsłużyć mniej i nie będzie to błędem.

2) końce linii mają wiele standardów - co najmniej 4, możliwe że sterownik dodaje \r przed \n

3) pierwszy program na arduino po odebraniu linijki "pożerał" następny bajt (Serial.read()) - więc nawet jakby dostał greenOn to G zginęło

4) zapisy w systemie Linux są buforowane i ogólnie wywołanie write() nie daje żadnej gwarancji że dane zostały zapisane na dysku, czy w urządzeniu docelowym. Port szeregowy na ogół buforuje całą linię, ale jeśli chcesz mieć pewność że wysyłasz a nie tylko buforujesz, poczytaj o funkcji sync()

Ja typuję 1+2+3, wydaje mi się że 4 przypadkiem nie jest istotne - dzięki użyciu znaku końca linii właśnie.

Może być jeszcze opcja 5 - konfiguracja portu szeregowego, ale skoro czasem działa to mało prawdopodobna opcja.

Link do komentarza
Share on other sites

Gość es2
es2, lepiej dzisiaj w totka nie graj.

* Przepełnienie bufora - nie bierze się znikąd, program wygląda ok

* brak ram - problemy są po stronie PC, pewnie kilka GB ramu, myślisz że taki programik wykorzysta cały?

* przerwania - program nic w przerwaniach nie robi, tzn. robi wszystko za niego system operacyjny i biblioteki Arduino

Opisałem potencjalne problemy po stronie Arduino.

Problemy z programem/systemem łatwo wyeliminować i użyć terminala (np Putty, Minicom). Jeśli terminal działa poprawnie, to już wiadomo gdzie szukać.

Link do komentarza
Share on other sites

Pierwszy program na Linuxa używa błędnie operatora sizeof zamiast funkcji strlen, co powoduje przesłanie dodatkowego zera. Tajemniczy Serial.read() miał pewnie pożerać owo zero 😉

To raczej nie ma znaczenia. Po stronie arduino i tak jest ucinane wszystko po greenOn z /n włącznie. poza tym próbowałem również ustawić ręcznie wielkość.

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.