2016-12-28 6 views
0

Ich benutze ein Raspberry Pi Zero im Gerätemodus und ein Raspberry Pi B im Host-Modus. Ich verbinde die beiden mit einem USB-Kabel. Mein Ziel ist gerade, einfache, willkürliche Daten zwischen den beiden Pi's hin und her zu schicken.Lesen von der seriellen Schnittstelle gibt immer zurück, was geschrieben wurde

Das Problem ist, welches Pi in den seriellen Port schreibt zuerst liest, was es geschrieben hat. Das Programm, das ich geschrieben habe, hat das Gerät senden d\n und der Host senden h\n. Wenn also das Gerät zuerst schreibt, liest der Host korrekt d\n und schreibt h\n an den seriellen Port. Aber das Gerät liest d\n! Das Problem bleibt bestehen, wenn ich es so umschalte, dass der Host zuerst schreibt.

Ich habe versucht, verschiedene tcflush Aufrufe an das Programm nach dem Schreiben, aber vor dem Lesen, aber es funktioniert nicht. Ich habe auch versucht, für verschiedene Zeitabschnitte zu schlafen. Ich habe für jeden geschriebenen Charakter 100 Mikrosekunden gelesen und habe mehrere Sekunden geschlafen.

Mein Setup erfordert, dass ich nicht gleichzeitig eine konstante Verbindung zwischen beiden Pi's habe, weil der einzelne Daten-fähige USB-Port von Pi Zero zur Verfügung steht. Also, um zu testen, stecke ich tatsächlich eine Tastatur ein und führe das Programm aus und stecke dann das richtige Kabel ein, um Daten zu übertragen. Ich kann Daten übertragen, aber nicht nach dem Schreiben, weil das Programm einfach zurückschreibt, was es geschrieben hat.

Ich fange an zu denken, dass ich in eine Noob Falle gefallen bin, die ich nicht ergründen kann. Hier ist der Code Ich verwende:

#include <stdio.h> 
#include <unistd.h> 
#include <fcntl.h>  
#include <termios.h> 
#include <errno.h> 

/* 
* gcc -o device_rw -DDEVICE serial_rw.c 
* gcc -o host_rw serial_rw.c 
*/ 

#define SERIAL_DEVICE "/dev/ttyGS0" 
#define SERIAL_HOST "/dev/ttyACM0" 

#ifdef DEVICE 
#define _TTY SERIAL_DEVICE 
#else 
#define _TTY SERIAL_HOST 
#endif 

int 
set_interface_attribs(int fd, int speed) 
{ 
    struct termios tty; 

    if (tcgetattr(fd, &tty) < 0) { 
     printf("Error from tcgetattr: %s\n", strerror(errno)); 
     return -1; 
    } 

    cfsetospeed(&tty, (speed_t)speed); 
    cfsetispeed(&tty, (speed_t)speed); 

    tty.c_cflag &= ~PARENB;  /* no parity bit */ 
    tty.c_cflag &= ~CSTOPB;  /* only need 1 stop bit */ 
    tty.c_cflag &= ~CSIZE; 
    tty.c_cflag |= CS8;   /* 8-bit characters */ 

    tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */ 
    tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */ 

    tty.c_iflag |= IGNPAR | IGNCR; 
    tty.c_iflag &= ~(IXON | IXOFF | IXANY); 
    tty.c_iflag |= ICANON; 
    tty.c_iflag &= ~OPOST; 

    if (tcsetattr(fd, TCSANOW, &tty) != 0) { 
     printf("Error from tcsetattr: %s\n", strerror(errno)); 
     return -1; 
    } 

    return 0; 
} 

void 
write_serial (int fd, const char *buf, int len) 
{ 
    printf("WRITE: %s\n", buf); 
    write(fd, buf, len); 
} 

void 
read_serial (int fd, char *buf, int len) 
{ 
    ssize_t nread = read(fd, buf, len); 
    if (nread > 0 && nread <= len) { 
     buf[nread] = 0; 
     printf(" READ: %s\n", buf); 
    } 
} 

int 
main (int argc, char **argv) 
{ 
    char buf[80]; 
    int fd = open(_TTY, O_RDWR | O_NOCTTY); 

    if (fd < 0) { 
     fprintf(stderr, "Can't open %s: %s\n", _TTY, strerror(errno)); 
     goto exit; 
    } 

    if (set_interface_attribs(fd, B115200) < 0) { 
     goto exit; 
    } 

#ifdef DEVICE 
    printf("device: %s\n", _TTY); 
    write_serial(fd, "d\n", 2); 
    usleep((2 + 25) * 100); 
    read_serial(fd, buf, 2); 
#else 
    printf("host: %s\n", _TTY); 
    read_serial(fd, buf, 2); 
    //usleep((2 + 25) * 100); 
    write_serial(fd, "h\n", 2); 
#endif 

    close(fd); 
exit: 
    return 0; 
} 
+0

Wo haben Sie '#define DEVICE' eingestellt, um Ihre Kompilierungsversionen zu erfüllen, die von' #ifdef DEVICE' gesteuert werden? –

+0

Ich kompiliere mit '-DDEVICE', um es auszulösen. – Leroy

+0

Oh ich sehe, wie im Code kommentiert. Aber ich mag es nicht - kann zu Fingerproblemen führen. Ich schlage vor, dass ein * spezifischer Wert * definiert sein muss, damit die Kompilierung ohne sie fehlschlägt. –

Antwort

0

Ich habe eine Menge aus den Antworten von allen gelernt und bin dankbar für sie, denn ich werde sie brauchen, wenn ich mit diesem Projekt fortfahre. Für dieser Sonderfall, das Problem endete jedoch als Berechtigungen. Ja, Dateiberechtigungen für ttyGSO.

Ich erwartete vollständig permission denied Fehler von open und bekam nie einen, also habe ich nie die Möglichkeit in Betracht gezogen. Vor allem, da ich die Dateien in Modus geöffnet habe, konnte ich in die serielle Datei schreiben, und es erschien Ich las Daten (obwohl die gleichen Daten) es dämmerte mir nie, dass ich vielleicht keine Berechtigungen gelesen hatte.

4

Neben nicht deaktivieren die ECHO-Attribute (wie @MarkPlotnick kommentiert), Sie haben zwei falsch angewandt Zuordnungen:

tty.c_iflag |= ICANON; 

ICANON-Bit zum lflag Mitglied gehört, und

tty.c_iflag &= ~OPOST; 

OPOST gehört zum Oflag-Mitglied.
In Anbetracht dieser Fehler haben Sie @ MarkPlotnick's Vorschlag richtig angewendet?

Siehe Working with linux serial port in C, Not able to get full data für eine funktionierende kanonische Einrichtung.

cfsetospeed(&tty, (speed_t)speed); 
cfsetispeed(&tty, (speed_t)speed); 

tty.c_cflag |= CLOCAL | CREAD; 
tty.c_cflag &= ~CSIZE; 
tty.c_cflag |= CS8;   /* 8-bit characters */ 
tty.c_cflag &= ~PARENB;  /* no parity bit */ 
tty.c_cflag &= ~CSTOPB;  /* only need 1 stop bit */ 
tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */ 

tty.c_lflag |= ICANON | ISIG; /* canonical input */ 
tty.c_lflag &= ~(ECHO | ECHOE | ECHONL | IEXTEN); 

tty.c_iflag &= ~INPCK; 
tty.c_iflag |= IGNCR; 
tty.c_iflag &= ~(INLCR | ICRNL | IUCLC | IMAXBEL); 
tty.c_iflag &= ~(IXON | IXOFF | IXANY); /* no SW flowcontrol */ 

tty.c_oflag &= ~OPOST; 

Beachten Sie, dass es auch möglich ist, haben Echo am anderen Ende aktiviert.
Um zu bestimmen, ob das Echo lokal oder vom entfernten Ende erzeugt wird, trennen Sie einfach das Remote-Gerät (vorausgesetzt Sie verwenden UARTs und/oder USB-zu-Seriell-Adapter) und übertragen Sie es.
Wenn Sie immer noch Echo erhalten, dann wird es lokal generiert, was durch die ECHO-Attribute termios gesteuert wird.
Wenn Sie kein Echo mehr empfangen, wiederholt die Gegenstelle ihre Eingabe zurück zum Sender.


BTW Ihr Programm wie gepostet wird nicht sauber kompilieren.
Es fehlt #include <string.h>
Die termios Initialisierungsroutine, die Sie kopiert (aber dann falsch geändert) hat ordnungsgemäße Überprüfung der Rückgabewerte, aber Ihre Lese- und Schreibroutinen prüfen nicht auf Fehler.

Verwandte Themen