Forum: PC-Programmierung Serielle Schnittstelle unter Linux, nicht blockierend lesen?


von Martin W. (Gast)


Lesenswert?

Hallo,

ich programmiere meistens den USART auf einem AVR und finde das 
Interrupt-Konzept sehr schön, weil man in der Routine die Daten mit 
einer State-Machine sammeln kann und immer genau weiß, wann ein 
Datensatz komplett da ist.

Ich möchte jetzt auf einem Embedded System unter Linux Daten in einem 
bestimmten Format auslesen, die von einem AVR über die serielle 
Schnittstelle hereinkommen. Interrupt-gesteuert geht ja leider nicht, 
also muss ich wohl in der Hauptschleife die Daten einsammeln.

Ich habe jetzt mal probiert, das Verhalten unter dem AVR nachzubilden, 
indem ich die Schnittstelle mit O_NONBLOCK öffne und den Aufruf von read 
auf jeweils ein Byte begrenze. Das ist aber total langsam.

Mit einem Testprogramm habe ich herausgefunden, dass die Daten da 
blockweise einlaufen, mit größeren Pausen dazwischen. Wobei die Länge 
der Blocks um einen Mittelwert herumschwankt, aber immer mal größer und 
mal kleiner ist. Manchmal kommt auch tatsächlich nur ein Byte.

Wie macht man das am geschicktesten? Den Artikel serielle Schnittstelle 
habe ich natürlich gelesen aber leider nichts gefunden, was mir da 
weiterhelfen würde. Wäre nett, wenn jemand mit einem Beispiel aushelfen 
könnte.

von ... (Gast)


Lesenswert?

Wie wärs mit einem Lese-Thread, der die Daten blockweise liest und in 
einem FIFO speichert?

von Peter II (Gast)


Lesenswert?

Martin W. schrieb:
> Wie macht man das am geschicktesten?

du kannst mit select warten bis daten kommen wenn du eine hauptschleife 
hast die ständig durlaufen wird. Oder die startest einen Thread und man 
einfach ein blockierendes Read.

von jiffies (Gast)


Lesenswert?

select oder poll, google mal danach. Das ist an sich schon so bewährt, 
dass du da praktisch nur noch abschreiben musst.

von Klaus W. (mfgkw)


Lesenswert?

Martin W. schrieb:
> Ich habe jetzt mal probiert, das Verhalten unter dem AVR nachzubilden,
> indem ich die Schnittstelle mit O_NONBLOCK öffne und den Aufruf von read
> auf jeweils ein Byte begrenze. Das ist aber total langsam.

mit einem non blocking file descriptor kann man auch zügig arbeiten; 
wenn es langsam ist dann aus anderen Gründen.

Du hast in so einem Fall immer folgende Möglichkeiten (schon genannt, 
aber mal als Übersicht):

- für jeden zu lesenden fd einen Thread
- select (wenn man den timeout-Wert entsprechend klein setzt,
  kann man nebenbei etwas sinnvolles tun)
- non blocking fd
- asynchrones Lesen

Nur im ersten Fall nutzt du nebenbei mehrere Prozessoren.

von Georg A. (georga)


Lesenswert?

> Mit einem Testprogramm habe ich herausgefunden, dass die Daten da
> blockweise einlaufen, mit größeren Pausen dazwischen. Wobei die Länge
> der Blocks um einen Mittelwert herumschwankt, aber immer mal größer
> und mal kleiner ist.

Das Verhalten kommt übrigens vom FIFO der PC-UART (16550&Co). Damit das 
FIFO tatsächlich gegen unnötige Interruptlast hilft, aber auch nicht 
ewig verzögert, wenn es noch nicht ganz voll ist, gibt es eine Wartezeit 
bis zur Interruptauslösung. Ist der FIFO-Stand unterhalb einer gewissen 
Marke und kommt währenddessen ein neues Zeichen rein, wird mit dem IRQ 
noch gewartet.

von Juergen R. (stumpjumper)


Lesenswert?

Wie jiffies oben schon sagte ist select() da der Weg zum Glück.
Schau mal da http://www.zotteljedi.de/socket-tipps/index.html da ist das 
recht gut erklärt.
Falls Du nicht klar kommst melde dich noch mal dann kram ich meinen 
alten Code mal raus, hab das vor jahren mal gemacht.

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.