Forum: PC-Programmierung gcc unter Linux - serielle Schnittstelle


von Raptor (Gast)


Lesenswert?

Hi,

wie kann ich in C programmieren, dass der Eingabepuffer abgefragt wird, 
ob sich dort noch Daten befinden?

if (weitere Daten vorhanden?)
{
    lies ein Zeichen von Seriell ein
}

Gruß
R.

von Raptor (Gast)


Lesenswert?

Zusatzfrage: Gibt es überhaupt einen Puffer? Wie groß ist er?

von block (Gast)


Lesenswert?

Du musst die Schnittstelle im NONBLOCKing modus öffnen. Dann gibt er dir 
beim lesen genau so viele bytes zurück, wie er im puffer hat.

von Raptor (Gast)


Lesenswert?

Wenn ich die Zeichen byteweise einlese, dann komme ich irgendwann an 
einen Punkt, wo keine Zeichen mehr zur Verfügung stehen.

Das Programm hängt bei 'read(port, buffer, 1)'.

von Use the source (Gast)


Lesenswert?

Raptor schrieb:
> Wenn ich die Zeichen byteweise einlese, dann komme ich irgendwann an
> einen Punkt, wo keine Zeichen mehr zur Verfügung stehen.
>
> Das Programm hängt bei 'read(port, buffer, 1)'.

Quellcode ?

von Raptor (Gast)


Lesenswert?

Der Quellcode sieht im Moment so aus:
1
for (x=0; x<30; x++)
2
{
3
    // Jetzt können Daten gelesen werden
4
    bytes = read(port, buffer, sizeof(buffer));
5
    printf(buffer);
6
    if (buffer[0] == '\n')
7
    {
8
        break;
9
    }
10
}

Wenn aus irgendeinem Grund weniger als 30 Zeichen und kein '\n' 
geliefert werden, dann hängt das Programm an dieser Stelle.

Was kann ich dagegen machen?

von raute (Gast)


Lesenswert?

Die serielle Schnittstelle muss auch richtig konfiguriert werden, Rest 
siehe:
http://tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html

P.S.: Ich vermute mal, dass du auch select verwenden möchtest.

von Raptor (Gast)


Lesenswert?

Ja, ich habe die Schnittstelle auch initialisiert:
1
        // serielle Schnittstelle für die Kommunikation zum Arduiono öffnen
2
        // beim Arduino wird dadurch ein RESET durchgeführt, Grund: DTR geht auf LOW
3
        port = open(COM_DEVICE, O_RDWR);
4
        // prüfen, ob die Schnittstelle erfolgreich geöffnet wurde
5
        if (port == -1)
6
        {       // das ist der Fehlerfall
7
                printf("Schnittstelle konnte nicht geöffnet werden.\n");
8
                return(1);
9
        }
10
        // Geschwindigkeit einstellen und sonstige Einstellungen
11
        if (tcgetattr(port, &com_attr)!= 0)
12
        {
13
                printf("Schnittstelle fehlerhaft: tcgetattr()");
14
                return(1);
15
        }
16
        // jetzt die Einstellungen
17
        com_attr.c_cflag        = COM_SPEED | CS8 | CRTSCTS | CLOCAL | CREAD;
18
        com_attr.c_iflag        = 0;
19
        com_attr.c_oflag        = OPOST | ONLCR;
20
        com_attr.c_lflag        = 0;
21
        if (tcsetattr(port,TCSAFLUSH, &com_attr) != 0)
22
        {
23
                printf("Schnittstelle fehlerhaft: tcsetattr()");
24
        }

Was ist 'select'? Ist das das Zauberwort? Ich werde es mir mal ansehen.

von Der Weise (Gast)


Lesenswert?

Raptor schrieb:
> port = open(COM_DEVICE, O_RDWR);
durch
port = open (COM_DEVICE; O_RDWR | O_NONBLOCK);
ersetzen.
block schrieb:
> Dann gibt er dir
> beim lesen genau so viele bytes zurück, wie er im puffer hat.

von Rolf Magnus (Gast)


Lesenswert?

Raptor schrieb:
> Wenn aus irgendeinem Grund weniger als 30 Zeichen und kein '\n'
> geliefert werden, dann hängt das Programm an dieser Stelle.
>
> Was kann ich dagegen machen?

Es "hängt" nicht, sondern es blockiert. Es wartet auf ein Zeichen. Du 
hast ja immerhin mit read() gesagt, daß das nächste Zeichen gelesen 
werden soll. Wenn keins da ist, wird halt gewartet, bis eins da ist. Wo 
soll es auch sonst herkommen?

Raptor schrieb:
> Was ist 'select'? Ist das das Zauberwort? Ich werde es mir mal ansehen.

Kommt drauf an, was du denn nun genau tun willst. Mit select() kannst du 
auf eine oder mehrere Dateien/Geräte/Sockets mit Timeout warten.
Wenn du also das Warten nach einer bestimmten Zeit abbrechen willst, 
gige das mit select().

von Georg A. (georga)


Lesenswert?

poll ist heutzutage eher der passende Call. Das hilft aber nicht gegen 
das Blockieren, wenn man danach mehr als ein Zeichen lesen will. D.h. 
man sollte mit NONBLOCK öffnen und dann zur Vermeidung von 
zeitfressenden Schleifen (weil read immer mit -1 zurückkommt) mit poll 
feststellen, ob was da ist und sonst einfach Zeit (aber nicht CPU...) 
verbraten.

von Vlad T. (vlad_tepesch)


Lesenswert?

Ehrlich gesagt habe ich den Anwendungszweck das nichtblockierenden 
Lesens noch nie so richtig verstanden. Wenn ich von irgend was Daten 
will, dann warte ich doch so lange, bis diese da sind. Will ich parallel 
was anderes machen, benutze ich Threads.

was bringt das "Ich lese nichtblockierend und wenn nix da war, warte 
ich". Das ist doch auch nur blockierendes Lesen in kompliziert.

von Georg A. (georga)


Lesenswert?

> Ehrlich gesagt habe ich den Anwendungszweck das nichtblockierenden
> Lesens noch nie so richtig verstanden.

Wenn man zB. nicht weiss, wie lange die Message ist, die da eigentlich 
so reinkommt... Entweder popele ich dann jedes einzelne Byte aus dem 
Device (naja, ginge bei RS232 noch so) oder man nimmt alles, was man 
bekommen kann aber ohne das Warten auf das Füllen des Gesamtbuffers...

> Will ich parallel was anderes machen, benutze ich Threads.

Die helfen gegen obiges Problem nicht.

von Rolf Magnus (Gast)


Lesenswert?

Vlad Tepesch schrieb:
> Ehrlich gesagt habe ich den Anwendungszweck das nichtblockierenden
> Lesens noch nie so richtig verstanden. Wenn ich von irgend was Daten
> will, dann warte ich doch so lange, bis diese da sind. Will ich parallel
> was anderes machen, benutze ich Threads.

Für sowas muß man doch nicht gleich mit Threads und deren 
Synchronisation hantieren. Einen Thread zu erzeugen, der dann quasi 
nichts anderes tut, als blockierend auf Daten zu warten, finde ich 
irgendwie unsinnig. Und nun müssen die Daten auch wieder irgendwie vom 
Lese-Thread in den anderen Thread kommen, und dann habe ich wieder das 
gleiche Problem.

> was bringt das "Ich lese nichtblockierend und wenn nix da war, warte
> ich". Das ist doch auch nur blockierendes Lesen in kompliziert.

Es sei denn, ich erwarte eine bestimmte Menge Daten, will aber nicht bis 
zum Sanktnimmerleinstag warten, wenn doch mal nicht alles ankommt.
read() hat halt keine Möglichkeit einen Timeout anzugeben, select() 
schon. Wenn man das benutzt, muß man aber darauf achten, daß es nicht 
passieren kann, daß read() doch mal blockiert, also öffnet man das Gerät 
non-blocking und wartet dann nur im select().

von Der Weise (Gast)


Lesenswert?

select() hat vor allem den Vorteil, dass bei mehreren Streams 
gleichzeitig warten kann, ob etwas ankommt, um dann nur bei dem, bei dem 
was angekommen ist, read() aufrufen zu müssen. Wobei einer der Streams 
natürlich auch stdin o.ä. sein kann.

von der Thomas (Gast)


Lesenswert?

Du kannst Dir auch bevor "read" ausgeführt wird die Anzahl der Bytes im 
Puffer mittels ioctl abholen, ist recht nützlich!

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.