C 如何在Linux上正确设置串行通信

C 如何在Linux上正确设置串行通信,c,linux,embedded,serial-port,termios,C,Linux,Embedded,Serial Port,Termios,我正在尝试从FPGA板读写数据。该板本身带有一个驱动程序,每当插入该板时,该驱动程序就会创建一个名为ttyUSB0的终端设备。在FPGA上,实现了异步接收机和发射机,它们似乎可以工作 然而,C方面似乎存在一个问题。我一直在使用一些测试向量来测试FPGA是否输出了正确的信息。我注意到了一些事情: 设备有时无法正确打开 终端属性有时无法检索或设置 读取有时是非阻塞的,无法检索正确的值 下面是我如何设置终端和文件描述符选项的。大部分是从这里取走的: 任何关于该计划失败原因的建议或评论都会非常有用 #i

我正在尝试从FPGA板读写数据。该板本身带有一个驱动程序,每当插入该板时,该驱动程序就会创建一个名为ttyUSB0的终端设备。在FPGA上,实现了异步接收机和发射机,它们似乎可以工作

然而,C方面似乎存在一个问题。我一直在使用一些测试向量来测试FPGA是否输出了正确的信息。我注意到了一些事情:

  • 设备有时无法正确打开
  • 终端属性有时无法检索或设置
  • 读取有时是非阻塞的,无法检索正确的值
  • 下面是我如何设置终端和文件描述符选项的。大部分是从这里取走的:

    任何关于该计划失败原因的建议或评论都会非常有用

    #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