Ich versuche zu Senden/Empfangen von Daten über einen USB-Port mit FTDI, also muss ich die serielle Kommunikation mit C/C++ handhaben. Ich arbeite an Linux (Ubuntu).
Grundsätzlich bin ich mit einem Gerät verbunden, das auf eingehende Befehle wartet. Ich muss diese Befehle senden und die Antwort des Geräts lesen. Sowohl Befehle als auch Antwort sind ASCII-Zeichen.
Mit GtkTerm funktioniert alles einwandfrei, aber wenn ich zur C-Programmierung wechsle, treten Probleme auf.
Hier ist mein Code:
#include <stdio.h> // standard input / output functions
#include <stdlib.h>
#include <string.h> // string function definitions
#include <unistd.h> // UNIX standard function definitions
#include <fcntl.h> // File control definitions
#include <errno.h> // Error number definitions
#include <termios.h> // POSIX terminal control definitions
/* Open File Descriptor */
int USB = open( "/dev/ttyUSB0", O_RDWR| O_NONBLOCK | O_NDELAY );
/* Error Handling */
if ( USB < 0 )
{
cout << "Error " << errno << " opening " << "/dev/ttyUSB0" << ": " << strerror (errno) << endl;
}
/* *** Configure Port *** */
struct termios tty;
memset (&tty, 0, sizeof tty);
/* Error Handling */
if ( tcgetattr ( USB, &tty ) != 0 )
{
cout << "Error " << errno << " from tcgetattr: " << strerror(errno) << endl;
}
/* Set Baud Rate */
cfsetospeed (&tty, B9600);
cfsetispeed (&tty, B9600);
/* Setting other Port Stuff */
tty.c_cflag &= ~PARENB; // Make 8n1
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8;
tty.c_cflag &= ~CRTSCTS; // no flow control
tty.c_lflag = 0; // no signaling chars, no echo, no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines
tty.c_iflag &= ~(IXON | IXOFF | IXANY);// turn off s/w flow ctrl
tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
tty.c_oflag &= ~OPOST; // make raw
/* Flush Port, then applies attributes */
tcflush( USB, TCIFLUSH );
if ( tcsetattr ( USB, TCSANOW, &tty ) != 0)
{
cout << "Error " << errno << " from tcsetattr" << endl;
}
/* *** WRITE *** */
unsigned char cmd[] = {'I', 'N', 'I', 'T', ' ', '\r', '\0'};
int n_written = write( USB, cmd, sizeof(cmd) -1 );
/* Allocate memory for read buffer */
char buf [256];
memset (&buf, '\0', sizeof buf);
/* *** READ *** */
int n = read( USB, &buf , sizeof buf );
/* Error Handling */
if (n < 0)
{
cout << "Error reading: " << strerror(errno) << endl;
}
/* Print what I read... */
cout << "Read: " << buf << endl;
close(USB);
Was passiert, ist das read()
gibt 0 zurück (überhaupt keine Bytes gelesen) oder blockiert bis zum Timeout (VTIME
). Ich gehe davon aus, dass dies geschieht, weil write()
sendet nichts. In diesem Fall würde das Gerät keinen Befehl empfangen und ich kann keine Antwort erhalten. Tatsächlich war es beim Ausschalten des Geräts, während mein Programm beim Lesen blockiert war, tatsächlich erfolgreich, eine Antwort zu erhalten (das Gerät sendet etwas, während es heruntergefahren wird).
Seltsam ist, dass dies hinzugefügt wird
cout << "I've written: " << n_written << "bytes" << endl;
gleich nach write()
Anruf, ich erhalte:
I've written 6 bytes
das ist genau das, was ich erwarte. Nur mein Programm funktioniert nicht so wie es soll, wie z Mein Gerät kann nicht empfangen, was ich schreibe am Hafen.
Ich habe verschiedene Dinge und Lösungen ausprobiert, auch in Bezug auf Datentypen (ich habe versucht, std::string zu verwenden, z cmd = "INIT \r"
oder const char
), aber nichts hat wirklich funktioniert.
Kann mir jemand sagen wo ich falsch liege?
Danke im Voraus.
BEARBEITEN:
Frühere Version dieses Codes verwendet
unsigned char cmd[] = "INIT \n"
und auch cmd[] = "INIT \r\n"
. Ich habe es geändert, weil Befehlssyntax für mein Gerät als gemeldet wird
<command><SPACE><CR>
.
Ich habe auch versucht, das zu vermeiden O_NONBLOCK
Flag beim Lesen, aber dann blockiere ich nur bis für immer. Ich habe versucht, mit select()
aber nichts passiert. Nur für einen Versuch habe ich eine Warteschleife erstellt, bis Daten verfügbar sind, aber mein Code verlässt die Schleife nie. Btw, abwarten bzw usleep()
ist etwas, das ich vermeiden muss. Gemeldet ist nur ein Auszug meines Codes. Vollständiger Code muss in einer Echtzeitumgebung funktionieren (insbesondere OROCOS), also möchte ich keine schlafähnliche Funktion.
std::cout
ist C++. Im Allgemeinen sollte sich Ihr MCVE an eine Sprache halten, es sei denn, Sie vermuten eine schlechte Interaktion. Andernfalls beginnen einige Leute zu argumentieren, dass C++ nicht C ist.– jww
12. Mai 2019 um 22:56 Uhr