如何正确设置串行通信在Linux上(How to properly set up serial co

2019-08-20 12:26发布

我试图读出和写入到FPGA板的数据。 板本身来到与创建一个名为ttyUSB0每当板已插入一个终端设备的驱动器。在FPGA,异步接收机和发射机被实现,并且它们似乎工作。

然而,似乎是对的事情C面的问题。 我已经使用了一些测试向量以测试FPGA正在输出正确的信息。 我注意到一些东西的事情:

  1. 该装置有时不能正常打开
  2. 终端属性有时无法可检索或设置。
  3. 读有时是无阻塞,不检索正确的值。

下面是我如何设置终端和文件描述符选项。 其中很大一部分是从这里取: http://slackware.osuosl.org/slackware-3.3/docs/mini/Serial-Port-Programming

任何意见或评论,为什么程序可能会失败将是很大的帮助。

#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我基于第一个答案修改我的代码。 这是我现在有:

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

只是为了澄清,接收机和发射机使用8位数据位,1位停止位,并且无奇偶校验位。

Answer 1:

我喜欢的POSIX操作系统串行编程指南 。

您应该删除fcntl(mainfd, F_SETFL)声明,因为它不是必需的,正确实现(F_GETFL没有这样做之前和失踪的第三个参数)。

尝试使用cfmakeraw设置不规范的模式,因为你的初始化代码不完整:

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

尝试较慢的波特率(如115200或甚至9600)测试。



文章来源: How to properly set up serial communication on Linux