C 如何在Linux上正确设置串行通信
我正在尝试从FPGA板读写数据。该板本身带有一个驱动程序,每当插入该板时,该驱动程序就会创建一个名为ttyUSB0的终端设备。在FPGA上,实现了异步接收机和发射机,它们似乎可以工作 然而,C方面似乎存在一个问题。我一直在使用一些测试向量来测试FPGA是否输出了正确的信息。我注意到了一些事情:C 如何在Linux上正确设置串行通信,c,linux,embedded,serial-port,termios,C,Linux,Embedded,Serial Port,Termios,我正在尝试从FPGA板读写数据。该板本身带有一个驱动程序,每当插入该板时,该驱动程序就会创建一个名为ttyUSB0的终端设备。在FPGA上,实现了异步接收机和发射机,它们似乎可以工作 然而,C方面似乎存在一个问题。我一直在使用一些测试向量来测试FPGA是否输出了正确的信息。我注意到了一些事情: 设备有时无法正确打开 终端属性有时无法检索或设置 读取有时是非阻塞的,无法检索正确的值 下面是我如何设置终端和文件描述符选项的。大部分是从这里取走的: 任何关于该计划失败原因的建议或评论都会非常有用 #i
#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
}
#包括//标准输入/输出定义
#包含//字符串函数定义
#包含//UNIX标准函数定义
#包含//文件控制定义
#包括//错误号定义
#包括//POSIX终端控制定义
int open_端口(无效){
int fd;//端口的文件描述符
fd=打开(“/dev/ttyUSB0”,O|RDWR | O|NOCTTY);
如果(fd==-1){
fprintf(stderr,“打开端口:无法打开/dev/ttyUSB0%s\n”,strerror(errno));
退出(退出失败);
}
返回(fd);
}
内部主(空){
int fd=0;//文件描述符
struct termios options;//终端选项
fd=open_port();//为RD和WR打开tty设备
fcntl(fd,F_SETFL);//配置端口读取
tcgetattr(fd,&options);//获取端口的当前选项
cfsetispeed(&options,B230400);//将波特率设置为230400
cfsetospeed(和选项,B230400);
options.c|u cflag |=(CLOCAL | CREAD);//启用接收器并设置本地模式
options.c_cflag&=~PARENB;//无奇偶校验位
options.c_cflag&=~CSTOPB;//1停止位
options.c_cflag&=~CSIZE;//掩码数据大小
options.c_cflag |=CS8;//选择8个数据位
options.c\u cflag&=~CRTSCTS;//禁用硬件流控制
//允许将数据作为原始输入进行处理
options.c|lflag&=~(ICANON | ECHO | ISIG);
//设置新属性
tcsetattr(fd、TCSANOW和选项);
////////////////////////////////////
//这里有简单的读写代码//
////////////////////////////////////
//关闭文件描述符&退出
关闭(fd)
返回退出成功
}
更新
我已经根据第一个答案修改了代码。这就是我现在拥有的:
#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;
}
#包括//错误号定义
#包括//C99固定数据类型
#包括//标准输入/输出定义
#include//C标准库
#包含//字符串函数定义
#包含//UNIX标准函数定义
#包含//文件控制定义
#包括//POSIX终端控制定义
//打开usb串行端口进行读写
int open_端口(无效){
int fd;//端口的文件描述符
fd=打开(“/dev/ttyUSB0”,O|RDWR | O|NOCTTY);
如果(fd==-1){
fprintf(stderr,“打开端口:无法打开/dev/ttyUSB0%s\n”,strerror(errno));
退出(退出失败);
}
返回fd;
}
内部主(空){
int fd=0;//文件描述符
struct termios options;//终端选项
int rc;//返回值
fd=open_port();//为RD和WR打开tty设备
//获取端口的当前选项
如果((rc=tcgetattr(fd和选项))<0){
fprintf(stderr,“无法获取属性:%d,%s\n”,fd,strerror(errno));
退出(退出失败);
}
//将波特率设置为230400
cfsetispeed(和选项,B230400);
//将波特率设置为230400
cfsetospeed(和选项,B230400);
cfmakeraw(和选项);
options.c|u cflag |=(CLOCAL | CREAD);//启用接收器并设置本地模式
options.c_cflag&=~CSTOPB;//1停止位
options.c\u cflag&=~CRTSCTS;//禁用硬件流控制
选项c_cc[VMIN]=1;
选项c_cc[VTIME]=2;
//设置新属性
如果((rc=tcsetattr(fd、TCSANOW和options))<0){
fprintf(stderr,“未能设置属性:%d,%s\n”,fd,strerror(errno));
退出(退出失败);
}
////////////////////////////////
//这里有简单的读/写代码//
////////////////////////////////
//关闭文件描述符&退出
关闭(fd);
返回退出成功;
}
只是澄清一下,接收机和发射机使用8个数据位,1个停止位,没有奇偶校验位。我更喜欢
您应该删除fcntl(mainfd,F_SETFL)
语句,因为它不是必需的,并且没有正确实现(F_GETFL没有在前面完成并且缺少第三个参数)
尝试使用设置非规范模式,因为您的初始化代码不完整:
options->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
| INLCR | IGNCR | ICRNL | IXON);
options->c_oflag &= ~OPOST;
对于非规范模式,还需要定义
options.c_cc[VMIN] = 1;
options.c_cc[VTIME] = 2;
1和2只是建议值
在所有系统调用之后添加返回状态测试
rc = tcgetattr(mainfd, &options);
if (rc < 0) {
printf("failed to get attr: %d, %s\n", mainfd, strerror(errno));
exit (-3);
}
rc=tcgetattr(mainfd和选项);
if(rc<0){
printf(“未能获取属性:%d,%s\n”,mainfd,strerror(errno));
出口(-3);
}
尝试使用较慢的波特率(例如115200甚至9600)进行测试 我已经更新并发布了我的当前代码。由于某些原因,程序无法从电路板读取任何内容,它只是等待读取功能。有什么想法吗?你不需要
c\cflag&=~PARENB
,因为cfmakeraw()
会处理这个问题。您可能确实需要删除的c\u cflag&=~CSTOPB
和c\u cflag&=~CRTSCTS
!我已经添加了1停止位标志并禁用了硬件流控制,bu