【问题标题】:Programming Linux serial port, ttyS0编程Linux串口,ttyS0
【发布时间】:2012-04-20 08:20:06
【问题描述】:

我正在尝试学习如何使用 C 在 Linux 中对 ttyS0 串行端口进行编程。我有另一台机器连接到我的串行端口,大约每两秒发送 5f 和 6f 的交替十六进制值。我已经通过其他端口监控应用程序验证了这些值出现在端口上。在我的代码中,我使用阻塞 read() 进入 10 字符长度的缓冲区。即使我的另一台机器仍在发送数据,read() 也会永远阻塞。如果我包含 fcntl(fd, F_SETFL, FNDELAY); 行,它将 read() 设置为非阻塞 read() 总是返回值 -1,这意味着 UART 缓冲区中没有数据,而我的 for 循环代码只是打印出缓冲区中的随机值。所以简而言之,我的假设是我的代码没有读取 ttyS0,我不知道为什么。下面是我的代码,希望有人能看到导致我的问题的原因并让我直截了当。顺便说一句,我使用的是 Scientific Linux,我相信 ttyS0 是 com 端口 1,就像在 RedHat 和 Fedora 中一样。下面是我运行代码时的输出。它似乎正在毫无问题地写入 COM 端口,但读取它说它不可用。另外很明显,我打印出来的缓冲区只是随机值,而不是读入的数据。谢谢

控制台输出

hello world
hi again
write error: : Success
 wrote 4 bytes
number of bytes read is -1
read error:: Resource temporarily unavailable
4  8  120  -99  -73  -65  41  -120  4  8  
should of put something out

代码

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>

int main()
{
    printf("hello world\n");
    int n;
    int fd;
    char c;
    int bytes;

    char buffer[10];
    char *bufptr;
    int nbytes;
    int tries;
    int x;
    struct termios options;


    fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
    if(fd == -1)
    {
        perror("open_port: Unable to open:");
    }
    else
    {
        fcntl(fd, F_SETFL, 0);
        printf("hi again\n");
    }

    tcgetattr(fd, &options);

    cfsetispeed(&options, B115200);
    cfsetospeed(&options, B115200);
    options.c_cflag |= (CLOCAL | CREAD);
    options.c_cflag &= ~PARENB;
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;
    options.c_cflag &= ~( ICANON | ECHO | ECHOE |ISIG );
    options.c_iflag &= ~(IXON | IXOFF | IXANY );
    options.c_oflag &= ~OPOST;

    tcsetattr(fd, TCSANOW, &options);


    write(fd, "ATZ\r",4);
    printf(" wrote\n");
    bufptr = buffer;


    fcntl(fd, F_SETFL, FNDELAY);
     bytes = read(fd, bufptr, sizeof(buffer));
    printf("number of bytes read is %d\n", bytes);
    perror ("read error:");

    for (x = 0; x < 10 ; x++)
    {
        c = buffer[x];
        printf("%d  ",c);
    }
    close(fd);

    //puts(buffer[0]);
    printf("\nshould of put something out \n");

    return (0);
}

【问题讨论】:

  • 如果您使文件描述符非阻塞,read 返回-1 可能还意味着其他事情。您必须查看errno 才能了解它的真正含义。
  • @JoachimPileborg 好的。我在 read()write() 之后添加了 perrer() 行。看起来写得很好,但无法访问端口进行读取。
  • @FrankDejay 在options.c_cflag &amp;= ~( ICANON | ECHO | ECHOE |ISIG ); 行中,您的意思是设置options.c_lflag 而不是options.c_cflag
  • 您的代码的三个主要问题是: (1) 您的程序使用非阻塞模式进行输入。使用阻塞模式会好得多。 (2) 你的程序使用了非规范模式。由于输出和输入是文本行,因此您可以将终端配置为规范模式。见stackoverflow.com/questions/25996171/… (3) termios 配置很拙劣,@VilhelmGray 提到

标签: c linux serial-port tty


【解决方案1】:

以下行会导致问题:

options.c_cflag &= CSTOPB;

它将重置 c_cflag 的所有其他位。

如果要使用 1 个停止位,请使用:

options.c_cflag &= ~CSTOPB;

如果要使用 2 个停止位,请使用:

options.c_cflag |= CSTOPB;

编辑:

以下行也会导致问题:

fcntl(fd, F_SETFL, 0);

它将重置几个重要的标志。

【讨论】:

  • 感谢我进行了这些更改。但它仍然无法正常工作。我在帖子中编辑了我的代码以表示更改。我还添加了 perror() 行。看起来它写得很好,但它无法访问端口进行读取。你认为这是为什么?
  • @Frank Dejay 标志设置也有些奇怪。我更新了我的答案。
  • “下面这行也会导致问题: fcntl(fd, F_SETFL, 0); 它会重置几个重要的标志。” -- 实际上这不会导致问题;系统调用只能修改已记录且受限制的文件描述符选项集。在这种情况下,它只会清除 O_NDELAY 标志(但它稍后会重新启用并导致 OP 出现问题)。
猜你喜欢
  • 1970-01-01
  • 2019-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多