Linux C串口读/写

我试图通过使用FTDI的USB端口发送/接收数据 ,所以我需要使用C / C ++来处理串行通信。 我正在研究Linux (Ubuntu)。

基本上,我连接到正在侦听传入命令的设备。 我需要发送这些命令并阅读设备的响应。 命令和响应都是ASCII字符

一切工作正常使用GtkTerm,但是,当我切换到C编程,我遇到问题。

这是我的代码:

#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); 

会发生什么是read()返回0(根本没有字节读取)或阻塞,直到超时( VTIME )。 我假设这是因为write()不发送任何东西。 在这种情况下,设备不会收到命令,我不能收到回应。 实际上,当我的程序在读取时被阻塞时closures设备实际上已经成功地得到响应(设备在closures时发送某些东西)。

奇怪的是,join这个

 cout << "I've written: " << n_written << "bytes" << endl; 

write()调用后,我收到:

 I've written 6 bytes 

这正是我所期望的。 只有我的程序无法正常工作,就像我的设备无法收到我实际上在端口上写的内容。

我已经尝试了不同的事情和解决scheme,也关于数据types(我试过使用std :: string,如cmd = "INIT \r"const char ),但没有真正的工作。

有人能告诉我我错了吗?

先谢谢你。

编辑:以前版本的代码使用

unsigned char cmd[] = "INIT \n"

还有cmd[] = "INIT \r\n" 。 我改变了它,因为我的设备的命令sintax被报告为

<command><SPACE><CR>

我也尝试避免读取O_NONBLOCK标志,但是,我只阻止,直到永远。 我试过使用select()但没有任何反应。 只是为了尝试,我创build了一个等待循环,直到数据可用,但我的代码永远不会退出循环。 顺便说一句,等待或usleep()是我需要避免的。 报告的一个只是我的代码的摘录。 完整的代码需要在实时环境 (特别是OROCOS)中工作,所以我不太想睡眠式function。

Solutions Collecting From Web of "Linux C串口读/写"

我解决了我的问题,所以我在这里发布正确的代码,以防有人需要类似的东西。

打开端口

 int USB = open( "/dev/ttyUSB0", O_RDWR| O_NOCTTY ); 

设置参数

 struct termios tty; struct termios tty_old; memset (&tty, 0, sizeof tty); /* Error Handling */ if ( tcgetattr ( USB, &tty ) != 0 ) { std::cout << "Error " << errno << " from tcgetattr: " << strerror(errno) << std::endl; } /* Save old tty parameters */ tty_old = tty; /* Set Baud Rate */ cfsetospeed (&tty, (speed_t)B9600); cfsetispeed (&tty, (speed_t)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_cc[VMIN] = 1; // 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 /* Make raw */ cfmakeraw(&tty); /* Flush Port, then applies attributes */ tcflush( USB, TCIFLUSH ); if ( tcsetattr ( USB, TCSANOW, &tty ) != 0) { std::cout << "Error " << errno << " from tcsetattr" << std::endl; } 

 unsigned char cmd[] = "INIT \r"; int n_written = 0, spot = 0; do { n_written = write( USB, &cmd[spot], 1 ); spot += n_written; } while (cmd[spot-1] != '\r' && n_written > 0); 

这是绝对没有必要写每字节的字节,也int n_written = write( USB, cmd, sizeof(cmd) -1)工作正常。

最后, 请阅读

 int n = 0, spot = 0; char buf = '\0'; /* Whole response*/ char response[1024]; memset(response, '\0', sizeof response); do { n = read( USB, &buf, 1 ); sprintf( &response[spot], "%c", buf ); spot += n; } while( buf != '\r' && n > 0); if (n < 0) { std::cout << "Error reading: " << strerror(errno) << std::endl; } else if (n == 0) { std::cout << "Read nothing!" << std::endl; } else { std::cout << "Response: " << response << std::endl; } 

这个为我工作。 谢谢你们!

一些接收器期望EOL序列,通常是两个字符\r\n ,所以请在您的代码中替换行

 unsigned char cmd[] = {'I', 'N', 'I', 'T', ' ', '\r', '\0'}; 

 unsigned char cmd[] = "INIT\r\n"; 

顺便说一句,上面的方式可能更有效率。 没有必要引用每个字符。

1)我会在init之后添加一个/ n。 即写入(USB,“init \ n”,5);

2)仔细检查串口配置。 在那里赔率是不正确的。 只是因为你不使用^ Q / ^ S或者硬件流量控制,并不意味着对方并不期待它。

3) 最有可能的是:write()之后添加一个“usleep(100000)”,文件描述符被设置为不阻塞或等待,对吗?在调用read之前需要多长时间才能得到响应?它必须由内核接收和缓冲,通过系统硬件中断,然后才能读取()它。)你有没有考虑过使用select()等待某些东西来读取() ?也许有一个超时?

编辑添加:

你需要DTR / RTS线吗? 硬件流程控制告诉对方发送计算机数据? 例如

 int tmp, serialLines; cout << "Dropping Reading DTR and RTS\n"; ioctl ( readFd, TIOCMGET, & serialLines ); serialLines &= ~TIOCM_DTR; serialLines &= ~TIOCM_RTS; ioctl ( readFd, TIOCMSET, & serialLines ); usleep(100000); ioctl ( readFd, TIOCMGET, & tmp ); cout << "Reading DTR status: " << (tmp & TIOCM_DTR) << endl; sleep (2); cout << "Setting Reading DTR and RTS\n"; serialLines |= TIOCM_DTR; serialLines |= TIOCM_RTS; ioctl ( readFd, TIOCMSET, & serialLines ); ioctl ( readFd, TIOCMGET, & tmp ); cout << "Reading DTR status: " << (tmp & TIOCM_DTR) << endl; 

这是一个工作串行读/写代码的例子。 在Ubuntu上测试 采取从http://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c/38318768#comment71422395_38318768

 /* * Source: http://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c/38318768#comment71422395_38318768 * Compile: g++ SerialExample.cpp -o SerialExample * Run: ./SerialExample * */ #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <termios.h> #include <unistd.h> 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 |= (CLOCAL | CREAD); /* ignore modem controls */ 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 */ /* setup for non-canonical mode */ tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); tty.c_oflag &= ~OPOST; /* fetch bytes as they become available */ tty.c_cc[VMIN] = 1; tty.c_cc[VTIME] = 1; if (tcsetattr(fd, TCSANOW, &tty) != 0) { printf("Error from tcsetattr: %s\n", strerror(errno)); return -1; } return 0; } void set_mincount(int fd, int mcount) { struct termios tty; if (tcgetattr(fd, &tty) < 0) { printf("Error tcgetattr: %s\n", strerror(errno)); return; } tty.c_cc[VMIN] = mcount ? 1 : 0; tty.c_cc[VTIME] = 5; /* half second timer */ if (tcsetattr(fd, TCSANOW, &tty) < 0) printf("Error tcsetattr: %s\n", strerror(errno)); } int open_serial(const char * portname) { const char *port = portname; int fd; // to access serial port on linux, you need to open file. fd = open(port, O_RDWR | O_NOCTTY | O_SYNC); if (fd < 0) { printf("Error opening %s: %s\n", portname, strerror(errno)); return -1; } /*baudrate 115200, 8 bits, no parity, 1 stop bit */ set_interface_attribs(fd, B115200); //set_mincount(fd, 0); /* set to pure timed read */ return fd; } /* * Read data from serial port into buffer array. fd is int returned from open_serial. */ int read_serial(int fd, unsigned char *buffer) { /* Loop until data is read */ do { int rdlen; rdlen = read(fd, buffer, sizeof(buffer) - 1); if (rdlen > 0) { buffer[rdlen] = 0; //printf("Read %d: \"%s\"\n", rdlen, buffer); return 0; } else if (rdlen < 0) { printf("Error from read: %d: %s\n", rdlen, strerror(errno)); return -1; } /* repeat read to get full message */ } while (1); } /* * */ int write_serial(int fd, const char *data) { int datalen = strlen(data); printf("Length = %d", datalen); int wrlen = write(fd, data, datalen); if (wrlen != datalen) { printf("Error from write: %d, %d\n", wrlen, errno); return -1; } tcdrain(fd); /* delay for output */ return 0; } int main() { int fd; const char *port_name = "/dev/ttyACM0"; fd = open_serial(port_name); // Example to write data. int write = write_serial(fd, "1,0,250"); // Example for reading data. unsigned char buf[80]; int read = read_serial(fd,buf); printf("Data = %s\n", buf); }