如何在 Linux 上正确设置串行通信
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15890903/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to properly set up serial communication on Linux
提问by sj755
I'm attempting to read and write data from and to an FPGA board. The board itself came with a driver that create a terminal device called ttyUSB0 whenever the board is plugged in. On the FPGA, an asynchronous receiver and transmitter were implemented, and they seem to work.
我正在尝试从 FPGA 板读取数据和向 FPGA 板写入数据。板子本身带有一个驱动程序,只要插入板子,它就会创建一个名为 ttyUSB0 的终端设备。在 FPGA 上,实现了异步接收器和发送器,它们似乎可以工作。
However, there seems to be an issue on C side of things. I've been using some test vectors to test if the FPGA is outputting the proper information. I've noticed a few things things:
但是,C 方面似乎存在问题。我一直在使用一些测试向量来测试 FPGA 是否输出正确的信息。我注意到了一些事情:
- The device sometimes does not open correctly
- The terminal attributes sometimes fail to be retrieved or set.
- The read is sometimes non-blocking and doesn't retrieve the proper value.
- 设备有时无法正确打开
- 有时无法检索或设置终端属性。
- 读取有时是非阻塞的,并且不会检索到正确的值。
Below is how I set up terminal and file descriptor options. Much of it was taken from here: http://slackware.osuosl.org/slackware-3.3/docs/mini/Serial-Port-Programming
下面是我如何设置终端和文件描述符选项。其中大部分取自此处:http: //slackware.osuosl.org/slackware-3.3/docs/mini/Serial-Port-Programming
Any advice or comments as to why the program may be failing would be greatly helpful.
关于程序可能失败的原因的任何建议或评论都会非常有帮助。
#include <stdio.h> // Standard input/output definitions
#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
int open_port(void){
int fd; // File descriptor for the port
fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY);
if (fd == -1){
fprintf(stderr, "open_port: Unable to open /dev/ttyUSB0 %s\n",strerror(errno));
exit(EXIT_FAILURE);
}
return (fd);
}
int main(void){
int fd = 0; // File descriptor
struct termios options; // Terminal options
fd = open_port(); // Open tty device for RD and WR
fcntl(fd, F_SETFL); // Configure port reading
tcgetattr(fd, &options); // Get the current options for the port
cfsetispeed(&options, B230400); // Set the baud rates to 230400
cfsetospeed(&options, B230400);
options.c_cflag |= (CLOCAL | CREAD); // Enable the receiver and set local mode
options.c_cflag &= ~PARENB; // No parity bit
options.c_cflag &= ~CSTOPB; // 1 stop bit
options.c_cflag &= ~CSIZE; // Mask data size
options.c_cflag |= CS8; // Select 8 data bits
options.c_cflag &= ~CRTSCTS; // Disable hardware flow control
// Enable data to be processed as raw input
options.c_lflag &= ~(ICANON | ECHO | ISIG);
// Set the new attributes
tcsetattr(fd, TCSANOW, &options);
////////////////////////////////////
// Simple read and write code here//
////////////////////////////////////
// Close file descriptor & exit
close(fd)
return EXIT_SUCCESS
}
UPDATEI've modified my code based on the first answer. This is what I have now:
更新我已经根据第一个答案修改了我的代码。这就是我现在所拥有的:
#include <errno.h> // Error number definitions
#include <stdint.h> // C99 fixed data types
#include <stdio.h> // Standard input/output definitions
#include <stdlib.h> // C standard library
#include <string.h> // String function definitions
#include <unistd.h> // UNIX standard function definitions
#include <fcntl.h> // File control definitions
#include <termios.h> // POSIX terminal control definitions
// Open usb-serial port for reading & writing
int open_port(void){
int fd; // File descriptor for the port
fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY);
if (fd == -1){
fprintf(stderr, "open_port: Unable to open /dev/ttyUSB0 %s\n",strerror(errno));
exit(EXIT_FAILURE);
}
return fd;
}
int main(void){
int fd = 0; // File descriptor
struct termios options; // Terminal options
int rc; // Return value
fd = open_port(); // Open tty device for RD and WR
// Get the current options for the port
if((rc = tcgetattr(fd, &options)) < 0){
fprintf(stderr, "failed to get attr: %d, %s\n", fd, strerror(errno));
exit(EXIT_FAILURE);
}
// Set the baud rates to 230400
cfsetispeed(&options, B230400);
// Set the baud rates to 230400
cfsetospeed(&options, B230400);
cfmakeraw(&options);
options.c_cflag |= (CLOCAL | CREAD); // Enable the receiver and set local mode
options.c_cflag &= ~CSTOPB; // 1 stop bit
options.c_cflag &= ~CRTSCTS; // Disable hardware flow control
options.c_cc[VMIN] = 1;
options.c_cc[VTIME] = 2;
// Set the new attributes
if((rc = tcsetattr(fd, TCSANOW, &options)) < 0){
fprintf(stderr, "failed to set attr: %d, %s\n", fd, strerror(errno));
exit(EXIT_FAILURE);
}
////////////////////////////////
// Simple Read/Write Code Here//
////////////////////////////////
// Close file descriptor & exit
close(fd);
return EXIT_SUCCESS;
}
Just to clarify, the receiver and transmitter use 8 data bits, 1 stop bit, and no parity bit.
只是为了澄清,接收器和发送器使用 8 个数据位,1 个停止位,没有奇偶校验位。
采纳答案by sawdust
I prefer Serial Programming Guide for POSIX Operating Systems.
我更喜欢POSIX 操作系统的串行编程指南。
You should delete the fcntl(mainfd, F_SETFL)
statement, since it's not required and incorrectly implemented (F_GETFL not done prior and missing third argument).
您应该删除该fcntl(mainfd, F_SETFL)
语句,因为它不是必需的且未正确实现(F_GETFL 之前未完成且缺少第三个参数)。
Try using cfmakerawto setup non-canonical mode, since your initialization code is incomplete:
尝试使用cfmakeraw设置非规范模式,因为您的初始化代码不完整:
options->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
| INLCR | IGNCR | ICRNL | IXON);
options->c_oflag &= ~OPOST;
For non-canonical mode, you also need to define
对于非规范模式,您还需要定义
options.c_cc[VMIN] = 1;
options.c_cc[VTIME] = 2;
1 and 2 are just suggested values.
1 和 2 只是建议值。
Add testing of return status after allsystem calls.
在所有系统调用后添加返回状态测试。
rc = tcgetattr(mainfd, &options);
if (rc < 0) {
printf("failed to get attr: %d, %s\n", mainfd, strerror(errno));
exit (-3);
}
Try testing with slower baudrates (e.g. 115200 or even 9600).
尝试使用较慢的波特率(例如 115200 甚至 9600)进行测试。