【问题标题】:linux serial port read() wrong datalinux串口read()错误数据
【发布时间】:2011-11-08 16:37:35
【问题描述】:

我正在编写一个与AVR MCU通信的小程序,在PC端我使用posix write()和read()来访问串口,我连接了串口的RX和TX引脚来测试它是否可以正常发送和接收数据,理论上发送出去的所有东西在接收缓冲区中应该是完全一样的,当发送的消息很短并且发送频率很低时,read()返回的消息和发送出去的一样,但是当消息变得更长并且发送更频繁时, read() 返回错误的数据,字符似乎顺序错误,我的猜测是 read() 或 write() 不是块模式,所以当旧传输没有'还没有完成,新的传输(write()?)到达,中断旧的传输并更改了 TX 缓冲区。

我是 Linux 编程的新手,请任何人帮助我,这让我很生气...... 非常感谢任何帮助。

编辑:我在 write() 手册页中注意到: write() 的成功返回并不能保证数据已提交到磁盘。事实上,在一些有缺陷的实现中,它甚至不能保证已成功为数据保留空间。唯一可以确定的方法是在完成所有数据的写入后调用 fsync(2)。

我尝试了 fsync() 函数,仍然得到同样的错误结果。

代码如下:

#include <stdio.h>
#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 main(void) {

    int fd;
//  fd = open("/dev/tty.usbmodem1a21", O_RDWR | O_NOCTTY | O_NDELAY);
    fd = open("/dev/tty.usbmodem1a21", O_RDWR | O_NOCTTY);
    if (fd == -1) {
        //Could not open the port.
        perror("open_port: Unable to open port ");
    }
        else
        fcntl(fd, F_SETFL, 0);

    char s[] = "Hello, this is a test of the serial port access";

    int cnt;
    unsigned char in[100];
    for(cnt=0; cnt<10; cnt++) {
        int n = write(fd, s, sizeof(s));
        if (n < 0)
            fputs("write() failed!\n", stderr);

        usleep(50000);  // works fine with delay

        read(fd, in, 100);


            printf("%s\n", in);
    }

    return 0;
}

埃里克

【问题讨论】:

    标签: linux serial-port posix


    【解决方案1】:

    首先使用 read() 的返回值。请记住:读取不会产生以空字符结尾的字符串。

    n=read(fd, in, 100);
    
            printf("%*.*s\n", n,n, in);
    

    【讨论】:

    • 嗨 wildplasser,感谢您的快速回复,我尝试了您的建议,但我仍然得到错误的数据,我附上了 2 个错误和正确数据的屏幕截图(在 write() 之间使用 sleep()和 read()),他们有什么告诉吗?再次感谢!
    【解决方案2】:

    (1) 始终检查返回码。 (2) 如果您尝试 printf 一个尚未以 null 终止的字符串,您最终将打印内存中的任何垃圾(或更糟)。

    我的猜测是你真正的问题是读/写不能保证写入你指定的字节数。他们实际读/写的数字在返回码中。因此,当 fd 缓冲区填满时,您可能正在写入 1 个字节,然后尝试打印该 1 个字节的非空字符串以及之后的所有内容。

    尝试这样的事情,看看情况是否会改变。

    int cnt;
    unsigned char in[100];
    
    for(cnt=0; cnt<10; cnt++) 
    {
        int n = write(fd, s, sizeof(s));
    
        if (n < 0)
        {
            perror("write");
            exit(EXIT_FAILURE);
        }
    
        n = read(fd, in, 100);
    
        if (n < 0)
        {
            perror("read");
            exit(EXIT_FAILURE);
        }
    
        in[n] = '\0';
    
        printf("%s\n", in);
    }
    

    【讨论】:

    • Hi Duck :) 我尝试了你的建议,仍然没有得到我期望的结果,这次我打印出实际接收到的字节数 - n,奇怪的是循环的第一次运行收到了 100 个字节,意味着缓冲区已满?然后循环中的每个 read() 调用只获得 1 个字节,我尝试在 write() 之前用 tcflush(fd, TCIOFLUSH) 刷新缓冲区,并在 write() 之后添加一个 tcdrain(fd),仍然不起作用。我开始认为我使用串口的方式是错误的,去看看其他的源代码,看看他们是如何实现串口访问的。谢谢。
    • 好吧,如果只有一个字节,那么只接收一个字节是正常的。你还能期待什么?
    猜你喜欢
    • 1970-01-01
    • 2013-12-18
    • 2013-03-18
    • 2016-10-11
    • 1970-01-01
    • 2022-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多