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
structtermiosoption;
2
3
serialfd=open("/dev/ttyUSB0",O_RDWR|O_NOCTTY);
4
5
memset(&option,0,sizeof(structtermios));
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.
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
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.
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?
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).
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?
@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
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.
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.
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.
@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.
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.