Forum: PC-Programmierung Linux RS232 sendet willkürlich keine Daten


von auron2008 (Gast)


Lesenswert?

Hallo zusammen,

bei meinem Projekt erfolgt die Kommunikation zwischen einem Linuxrechner 
und einem Controller über RS232. Um es kurz zu halten, der Controller 
ist ständig am messen und der PC fragt zwischendurch Messwerte ab die 
dann vom Controller an den PC gesendet werden.

1. PC -- gib Messdaten --> µC
2- µC -- sendet Messdaten --> PC

Nun zu meinem Problem. Nach einer unbestimmten Zeit hört der PC auf 
Daten zu senden. Das kann nach der 10. Anfrage oder nach der 5000. 
Anfrage kommen. Ich konnte das Problem soweit eingrenzen, das ich 
herausgefunden habe das der PC keine Daten mehr absendet.

Da der Quellcode vom ganzen Projekt etwas lang ist, versuch ich's auf 
das wesentliche zu kürzen. (Fehlerausgaben lasse ich hier weg).

Serielle Schnittstelle öffnen:
1
  struct termios option;
2
3
  serialfd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY);
4
5
  memset(&option, 0, sizeof(struct termios));
6
  tcgetattr (serialfd , &option);
7
8
  option.c_cflag = BAUDRATE | CS8 | CLOCAL;
9
  option.c_iflag = 0;//IGNPAR | IXON | IXOFF;
10
  option.c_oflag = OPOST | ONLCR; //0;
11
  option.c_lflag = 0;
12
  option.c_cc[VTIME] = 0;
13
  option.c_cc[VMIN] = 1;
14
15
  cfsetispeed(&option, BAUDRATE);
16
  cfsetospeed(&option, BAUDRATE);
17
18
  tcflush(serialfd, TCIFLUSH);
19
  tcsetattr(serialfd, TCSANOW, &option);

Schreiben auf Serielle Schnittstelle
1
result = write(serialfd, data, length);

Lesen von serieller Schnittstelle
1
read(serialfd, &dat[i], 1);

Es wird immer nur 1 Byte gelesen und anschließend wird geprüft ob der 
Befehl vollständig ist, wenn nicht wird weiter gelesen.

Die Hauptschleife habe ich folgendermaßen aufgebaut.
1
    while(1)
2
    {
3
      FD_ZERO(&read_fd);
4
      FD_SET(fd_serial, &read_fd);
5
      FD_SET(fd_timer, &read_fd);
6
7
      select(sizeof(read_fd)*8, &read_fd, NULL, NULL, NULL);
8
9
10
      if(FD_ISSET(fd_serial, &read_fd))
11
      {
12
        serial_receiveBuffer(NULL);
13
      }
14
      if(FD_ISSET(fd_timer, &read_fd))
15
      {
16
        cmdMeasure_send(); // fordert einen Messwert an
17
        test = read(fd_timer, &exp, sizeof(uint64_t));
18
      }
19
    }
Die Funktion serial_receiveBuffer(NULL) ruft dabei die Funktion zum 
lesen auf.

Meine Vorgehensweise war bisher. Ich lass das Programm im Debugger 
solange laufen bis ein Fehler kommt. Bei einem Fehler hab ich einen 
Breakpoint auf cmdMeasure_send() gesetzt und bin diese Funktion stück 
für Stück durchgegangen. Dabei sind mir nur keine Fehler aufgefallen. 
Selbst die Funktion result = write(serialfd, data, length); liefert die 
Anzahl der "scheinbar" geschriebenen Bytes zurück. Habe testweise die 
Funktion tcdrain(serialfd); nach dem schreiben eingefügt damit solange 
gewartet wird, bis die Daten gesendet wurden. Leider brachte das keine 
Verbesserung, das Programm bleibt dort nicht hängen und denkt vermutlich 
das alles korrekt gesendet wurde.

Ich würde mich freuen wenn jemand eine Idee hätte wie ich diesen Problem 
lösen kann.

mfg auron2008

von Sven B. (scummos)


Lesenswert?

Vielleicht dasselbe Problem wie hier?
Beitrag "Virtuelle serielle Schnittstelle verliert Daten"
Soweit ich das sehen kann, betrifft das alle Serial-Treiber ungefähr 
gleichermaßen, nicht nur den cdc-acm.

von Peter II (Gast)


Lesenswert?

auron2008 schrieb:
> Ich würde mich freuen wenn jemand eine Idee hätte wie ich diesen Problem
> lösen kann.

Ich würde erst mal prüfen ob wirklich keine Daten gesendet werden. Oszi 
oder LED einfach mal an den Tx Leitung hängen.

von Peter II (Gast)


Lesenswert?

Sven B. schrieb:
> Vielleicht dasselbe Problem wie hier?
> Beitrag "Virtuelle serielle Schnittstelle verliert Daten"
> Soweit ich das sehen kann, betrifft das alle Serial-Treiber ungefähr
> gleichermaßen, nicht nur den cdc-acm.

wird wohl hier nicht das Problem sein, dafür überträgt er viel zu 
langsam Daten wegen seinem polling.


@ auron2008

was musst du machen, damit es wieder geht? Programm neu starten?

von auron2008 (Gast)


Lesenswert?

Ui das ging aber schnell.

@Sven B. hmm da ich über eine Virtuelle Maschine einen USB zu RS232 
Converter (Digitus)einsetze kann das schon möglich sein, aber der sendet 
zu Beginn die Daten immer erfolgreich und dann keine mehr.

@Peter II , ja ich muss das Programm neustarten und dann läuft's wieder. 
Und es werden keine Daten gesendet, hab ich am Controller und mit einem 
Oszi geprüft.

Was mir gerade aufgefallen ist, an tcdrain() hängt er scheinbar doch. 
Ist mir vorher nicht aufgefallen, da ich den Debugger kurz pausiert und 
wieder gestartet hatte (dabei springt er aus tcdrain() raus und macht 
weiter).

von thorsten (Gast)


Lesenswert?

Sollte
1
       FD_ZERO(&read_fd);
2
       FD_SET(fd_serial, &read_fd);
3
       FD_SET(fd_timer, &read_fd);

nicht außerhalb deiner Schleife sein?

von Peter II (Gast)


Lesenswert?

auron2008 schrieb:
> @Peter II , ja ich muss das Programm neustarten und dann läuft's wieder.
> Und es werden keine Daten gesendet, hab ich am Controller und mit einem
> Oszi geprüft.

und du bist sicher das  cmdMeasure_send();  wirklich aufgerufen wird?

von auron2008 (Gast)


Lesenswert?

@thorsten , soweit ich das verstanden habe muss das mit in die while 
Schleife.

@Peter II , ich habe einen Breakpoint auf cmdMeasure_send(); gemacht und 
da wurde die Funktion aufgerufen. Ich hatte mir Testweise auch die 
Ausgabe von
1
test = read(fd_timer, &exp, sizeof(uint64_t));
2
printf("%d | %d \n", test, exp);
anzeigen lassen und die lief unverändert weiter.

von auron2008 (Gast)


Lesenswert?

Habe jetzt einen Breakpoint direkt in die Funktion gesetzt und er 
springt rein, also wird sie aufgerufen.

von auron2008 (Gast)


Lesenswert?

Ich bin jetzt mal vorsichtig optimistisch. Habe das Programm für den 
Raspberry übersetzt und es läuft jetzt schon ne Stunde (3600 Messwerte) 
ohne Probleme. Scheinbar liegt's an der virtuellen Maschine.

von min (Gast)


Lesenswert?

Ich hatte auch die VM in Verdacht. Auf einem nativen Linux wird's besser 
laufen. Man kann ein Live-Linux auch probeweise von CD starten.

von TriHexagon (Gast)


Lesenswert?

Wenn ich das richtig verstanden habe, dann hast du das gleiche Problem, 
das ich vor ein paar Wochen auch hatte.

Ich verwende einen USB-UART Adapter mit CP2102. Ich hatte immer das 
Problem, dass nur Teile der Daten (PC Seite) gesendet wurden. Der Anfang 
hat immer gepasst, aber das Ende fehlte. Wenn der µC was gesendet hat, 
gab es keine Probleme. Habe auch mit tcdrain/tcflush versucht das 
Problem zu lösen. Hat aber nichts genutzt.

 Nach einiger Recherche im Internet habe ich dann herausgefunden, was 
das Problem ist. Der Grund ist, dass es zwei Puffer gibt. Einmal am PC 
und noch mal einen im Controller (CP2102). Das flushen bewirkt dabei das 
der ganze Puffer zum Controller übertragen wird, aber nicht, dass der 
Controller auch den Puffer zum µC ausgibt. Das Problem lässt sich hier 
leider von der Software Seite auch nicht lösen, da zu dem Zeitpunkt als 
die API entworfen wurde, es keine USB-UART Adapter gab, das Problem also 
nicht bestand. Die einzige Möglichkeit sicher zu stellen, dass auch alle 
Daten am µC ankommen ist einfach nach dem Flushen zu warten. Also 
ausrechnen wie schnell der Controller die Daten übertragen kann 
(Baudrate) und dementsprechend warten.

So habe ich das Ganze verstanden und mit dem Warten klappt das ganz gut, 
auch wenn ich mit der "Lösung" nicht ganz zufrieden bin, aber anders 
gehts wohl nicht, zumindest ohne extra Hardware.

von TriHexagon (Gast)


Lesenswert?

auron2008 schrieb:
> Ich bin jetzt mal vorsichtig optimistisch. Habe das Programm für den
> Raspberry übersetzt und es läuft jetzt schon ne Stunde (3600 Messwerte)
> ohne Probleme. Scheinbar liegt's an der virtuellen Maschine.

Du benutzt sicher die native UART Schnittstelle am Raspberry, richtig? 
Dann würde sich das genau mit meiner Schilderung decken, denn an einer 
nativen Schnittstelle hat man das Problem eben nicht, da gibt es nur 
einen Puffer.

von auron2008 (Gast)


Lesenswert?

@TriHexagon

so ganz ist es bei mir nicht. Ich sende aller 1 Sekunde einen Befehl 
über die RS232 Schnittstelle. Nach x mal senden hört der einfach auf, 
bis dahin sendet er aber komplett. Das kann nach 20 oder nach 5000 
Werten passieren. Bei tcdrain() hängt er dann und macht nicht mehr 
weiter.

Und am Raspberry verwende ich momentan denselben USB <-> RS232 Adapter 
wie zuvor an der VM (wegen Spannung). Läuft heute seit 5 Stunden mit 
18000 Werten durch ohne zu hängen. Ich schließe einfach daraus das es an 
der VM liegt. Um das Problem weiter aufzuschlüsseln könnte ich mal die 
serielle Schnittstelle in die VM durchreichen, so wüsste man ob's an der 
Kombination VM + Adapter liegt oder nur an der VM.

von TriHexagon (Gast)


Lesenswert?

Ah Ok, anderes Problem. Hatte ich bisher auch noch nicht, wahrscheinlich 
ist es wirklich die VM. Benutzt du Virtual Box? Das ist bekannt für 
seine schlechten USB Treiber. Versuchs mal mit einer anderen VM 
Software. VM Ware soll ganz gut sein.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.