【问题标题】:Serial port programming in LinuxLinux中的串口编程
【发布时间】:2016-01-27 20:22:49
【问题描述】:

我想使用开发板上的RS232 端口与PC 通信。我了解我可以为此目的使用 "dev/ttyS0"

我可以使用 write() 函数打开和写入数据到 PC。但问题是我无法从“dev/ttyS0”读取。每次使用读取功能时,我都会收到“资源暂时不可用”。各位大佬能告诉我怎么解决这个问题吗?

这是我的代码:

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

int main()
{
    int n = 0, fd = 0, bytes = 0;
    char ch = 0;

    char buffer[10], *bufPtr;
    int nBytes = 0, tries = 0, x = 0;

    struct termios term;

    fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);

    if (fd == -1)
    {
        perror("open");
        return;
    }
    else
    {
        fcntl(fd, F_SETFL, 0);
        perror("Port");
    }

    if (n = tcgetattr(fd, &term) == -1)
    {
        perror("tcgetattr");
        return;
    }

    if (n = cfsetispeed(&term, B115200) == -1)
    {
        perror("cfsetispeed");
        return;
    }

    if (n = cfsetospeed(&term, B115200) == -1)
    {
        perror("cfsetospeed");
        return;
    }

    term.c_cflag |= (CLOCAL | CREAD);
    term.c_cflag &= ~PARENB;
    term.c_cflag &= ~CSTOPB;
    term.c_cflag &= ~CSIZE;
    term.c_cflag |= CS8;
    term.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    term.c_iflag &= ~(IXON | IXOFF | IXANY);
    term.c_cflag &= ~CRTSCTS;
    term.c_oflag &= ~OPOST; 

    if (n = tcsetattr(fd, TCSANOW, &term) == -1)
    {
        perror("tcsetattr");
        return;
    }

    write(fd,"LINUX",5);
    perror("write");

    fcntl(fd, F_SETFL, FNDELAY);    
    perror("fcntl");
    bytes = read(fd, buffer, sizeof(buffer));
    perror("read");
    printf("Bytes : %d and data: %s\n", bytes, buffer);
}

【问题讨论】:

    标签: c linux serial-port


    【解决方案1】:

    你的测试是什么?您是否正在缩短 RS232 DB9 连接器的针脚 2 和 3?

    否则read如果没有要读取的数据将始终返回-1。

    这是您的代码应该使用O_NDELAY 标志打开串行线路的操作。

    如果没有要读取的数据,为了避免读取,您可以使用select 在你的情况下:

    struct timeval tv;
    fd_set rset;
    int retV;
    int timeout = 5000; // 5 seconds
    
    tv.tv_usec = (timeout * 1000) % 1000000;
    tv.tv_sec = timeout / 1000;
    
    FD_ZERO ( &rset );
    FD_SET (  fd, &rset );
    retV = select ( fd+1, &rset, NULL, NULL, &tv );
    
    if( retV == 0 )
    {
       // timeout stuff
    }
    else if( retV < 0 )
    {
        // Error stuff. Read errno to see what happened
    }
    else
    {
       // read data
    }
    

    编辑

    删除fcntl(fd, F_SETFL, FNDELAY); 如果您想要正常的阻塞读取,请取消设置该标志。

    在您的代码中,您还假设read 将返回所有发送的字符,但事实并非如此。 read 将返回可供读取的字符。这意味着如果您发送“LINUX”,则可能会请求读取 5 次以读取所有发送的 5 个字符。

    最后一件事

    printf("Bytes : %d and data: %s\n", bytes, buffer);
    

    Undefined Behavior,因为buffer 不是NULL 终止的字符串。您可以在接收到的字符上循环解决它并使用 %c 格式打印它,或者NULL 终止您的缓冲区:

    if (bytes > 0)
       buffer[bytes] = '\0';
    

    char stringToSend[] = "LINUX";
    size_t len = strlen(stringToSend) +1 ;
    
    write(fd,"LINUX", len);
    perror("write");
    
    size_t receivedBytes = 0;
    bytes = 0;
    while (receivedBytes<len)
    {
       bytes = read(fd, &buffer[receivedBytes], sizeof(buffer)-1);
       perror("read");
    
       if (bytes > 0)
           receivedBytes += bytes;
    }
    
    printf("Bytes : %d and data: %s\n", receivedBytes, buffer);
    

    【讨论】:

    • 删除代码fcntl(fd, F_SETFL, FNDELAY); 这可能会重置重要的错误。如果您想要正常的阻塞读取,请取消设置该标志。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多