Serielle Schnittstelle unter Linux mit C



  • Hallo!

    Ich möchten einem Entwicklungsboard über die serielle Schnittstelle Befehle schicken, welches daraufhin sofort eine Antwort (z.B. einen Messwert) zurück sendet.

    Das Schreiben auf /dec/ttyXY klappt auch ganz gut und das Board antwortet auch. Allerdings habe ich Probleme mit dem ungepufferten Lesen.

    Meine Funktion hierzu (inkl. dem Schreiben) sieht so aus:

    void WriteToPort(int fd){
    
        char buffer[255];
    
        int n = write(fd, "0av\n", 4);
        if (n < 0)
        fputs("write() of 4 bytes failed!\n", stderr);
    
        int res = read(fd,buffer,255);  
        buffer[res]=0;               
        printf("%s", buffer);
    
        }
    

    Von der Antwort kommt irgendwie immer nur eine willkürliche Zeichenanzahl der Antwort. Also mal ein Zeichen, mal zwei, manachmal auch alle 16...
    Ich weiß dass die Umsetzung der read-Funktion so nicht korrekt ist, habe aber auch keine Idee wie ich das besser amchen könnte. Finde dazu auch keine konkreten Infos...

    Danke für eure Hilfe!



  • ich hab das unter M$ VS gebaut um mit meinem roboter zu kommunizieren, in 3h könnt ich dirs online stellen wenn ich wieder zuhause bin, ich verwende einen atmega8 und die fehlerkontrolle iss auch stabil (über IR iss die quali echt bescheiden :p)



  • Hallo!

    Danke für die schnelle Antwort!

    Meine Applikation läuft jedoch unter Linux. Ich hätte gerne mal die grundsätzliche Funktion von read() erklärt bekommen und woran es liegt das ich nur eine wilkürliche Zeichenanzahl aus der File-Deskriptor lese...

    Fehlübertragung haben ich keine!



  • ich habs ja c++ konform gehalten, btw. lässt sich das sehr schnell konvertieren mit ein paar kleinsten handgriffen.
    Frage: ist der rückgabewert von read denn korrekt ?

    wie auch bei sockets ist nie gewährleistet das von 10 gesendeten byte auch 10 bei einem read ankommen, versuch einen minimalen header mitzusenden, ala sizebyte = n und dann n datenbytes, beim read liesst du dann gezielt 1 byte aus und wartest bis genügend datenbytes ankommen um es vollständig auswerten zu können ....
    zur fehlerfreiheit: ich hab mir mal sagen lassen das auch die übertragung über ein serielles kabel sehr anfällig sein kann, ausserdem kann es doch passieren das wer am kabel wackelt und dir ein paar bytes verloren gehen, dann steht dein programm ... weils nich genug bekommt!!! oder ein paar byte zu viel eingestreut bekommt stimmt das ergebnis nicht mehr ... what ever, ich wollts nr zu bedenken geben



  • just for interest

    wenn du dem board sagst es soll einfach mal was an die serielle senden, ohne das du eine anfrage stellst und du das ganze mit cat /dev/ttySxx abfragst kommt was richtiges raus?

    wenn nicht solltest du ev checken, ob datenbits und stop bits richtig eingestellt sind



  • @killerkipferl:
    Ja das klappt einwandfrei!
    Die Sache ist halt woher soll read() wissen wann die Antwort vollständig ist. Ich glaube das er willkürlich auf das dev-File zugreift und es nicht gesichtert ist, dass die Antwort schon vollständig ist...



  • kommt jetzt auf die daten drauf an die du da empfangen willst...
    aber vielleicht wäre ein stop charackter ein lösungsansatz



  • Das habe ich jetzt geatan!
    Der Controller sendet nach dem Antwortzen immer ein Line Feed (ASCII 10).
    Danach frage ich ab. Aber es kommt trotzdem total undefinierter Kram raus. Meiner Meinung nach eine Überlagerung der alten und neuen Antwort. Mal nur zwei Zeichen der Antwort, mal die Antwort in mehrfacher Ausführung...



  • poste mal deine einstellungen für die serielle übertragung...

    wie öffnest du das device?



  • ich rufe nacheinander diese beiden Funktionen auf:

    /* Öffnet den übergebenen Port und liefert den zugehörigen File-Descriptor zurück. -1 = Fehler*/
    	int open_port(char Port[])
    	{ 		
    		int fd;
    		fd = open(Port, O_RDWR);
    		fcntl(fd, F_SETFL, 0);
    		return (fd);
    	}
    
    	/* Stellt die Portparameter für einen übergenen File-Descriptor ein. -1 = Fehler */
    	int setPortParam(int fd)
    	{
    
    		struct termios term_attr;
    
    		if (tcgetattr(fd, &term_attr) != 0)
    		{
    			perror("terminal: tcgetattr() failed");
    			return(-1);
    		}
    
    		term_attr.c_cflag = B9600 | CS8 | CRTSCTS
    					  | CLOCAL | CREAD;
    		term_attr.c_iflag = 0;
    		term_attr.c_oflag = 0;//OPOST; //| ONLCR | OCRNL;
    		term_attr.c_lflag = 0;
    
    		if (tcsetattr(fd, TCSAFLUSH, &term_attr) != 0)
    		{
    			perror("terminal: tcsetattr() failed");
    			return -1;
    		}
    
    		return 1;
    	}
    


  • term_attr.c_cflag = B9600 | CS8 | CRTSCTS

    ich weis natürlich nicht wie dein board getaktet ist, aber "eigentlich" arbeiten die meisten chips mit 2400 bps voreingestellt



  • so hab mal weiter rum experimentiert...

    Die Sache ist wohl die, dass der Controller die Zeichen nicht nacheinander sondern in einem Schwung sendet. Wenn ich das mit einem Terminalprogramm durch senden einer Textdatei nachbild habe ich die gleichen Effekte!
    Wenn also die Zeichen über ein Terminalprogramm schön nacheinader gesendet werden klappt alles einwandfrei, wenn der Kontroller sie jedoch alle nacheinander sendet, treten die Fehler auf (wahrscheinlich irgendwelche Pufferfehler).
    Was kann ich da tun???



  • @Ceos

    die Porteinstellungen sind auf jeden Fall richtig!
    9600 8N1 no handshaking!
    Es klappt ja auch im Prinzip, nur wird es falsch dargestellt / bearbeitet... siehe mein letzter Beitrag...


Anmelden zum Antworten