如何在 Linux 上正确设置串行通信 [英] How to properly set up serial communication on Linux

查看:17
本文介绍了如何在 Linux 上正确设置串行通信的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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.

但是,C 方面似乎存在问题.我一直在使用一些测试向量来测试 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:

  1. 设备有时无法正确打开
  2. 有时无法检索或设置终端属性.
  3. 读取有时是非阻塞的,不会检索到正确的值.

以下是我如何设置终端和文件描述符选项.大部分内容来自这里:http://slackware.osuosl.org/slackware-3.3/docs/mini/串口编程

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

任何关于程序失败原因的建议或评论都会非常有帮助.

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
",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
",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
", 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
", fd, strerror(errno));
        exit(EXIT_FAILURE);
    }

    ////////////////////////////////
        // Simple Read/Write Code Here//
        ////////////////////////////////

    // Close file descriptor & exit
    close(fd);
    return EXIT_SUCCESS;
} 

澄清一下,接收器和发送器使用 8 个数据位,1 个停止位,并且没有奇偶校验位.

Just to clarify, the receiver and transmitter use 8 data bits, 1 stop bit, and no parity bit.

推荐答案

我更喜欢 SerialPOSIX 操作系统编程指南.

您应该删除 fcntl(mainfd, F_SETFL) 语句,因为它不是必需的并且执行不正确(F_GETFL 之前没有完成并且缺少第三个参数).

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).

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

Try using cfmakeraw to setup non-canonical mode, since your initialization code is incomplete:

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 和 2 只是建议值.

1 and 2 are just suggested values.

所有系统调用之后添加返回状态测试.

Add testing of return status after all system calls.

rc = tcgetattr(mainfd, &options);
if (rc < 0) {
    printf("failed to get attr: %d, %s
", mainfd, strerror(errno));
    exit (-3);
}

尝试使用较慢的波特率(例如 115200 甚至 9600)进行测试.

Try testing with slower baudrates (e.g. 115200 or even 9600).

这篇关于如何在 Linux 上正确设置串行通信的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆