[英]How to properly set up serial communication on Linux
I'm attempting to read and write data from and to an FPGA board. 我正在尝试从FPGA板读写数据。 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.
该板本身带有一个驱动程序,只要插入该板,驱动程序就会创建一个名为ttyUSB0的终端设备。在FPGA上,实现了异步接收器和发送器,它们似乎可以工作。
However, there seems to be an issue on C side of things. 但是,似乎C方面存在问题。 I've been using some test vectors to test if the FPGA is outputting the proper information.
我一直在使用一些测试向量来测试FPGA是否输出正确的信息。 I've noticed a few things things:
我注意到一些事情:
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
}
UPDATE I'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个停止位和无奇偶校验位。
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 cfmakeraw to 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 all system 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 (eg 115200 or even 9600). 尝试使用较慢的波特率进行测试(例如115200甚至9600)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.