实时读取和保存串口数据问题解决记录(附Windows和Linux下的代码) 您所在的位置:网站首页 serialread函数 实时读取和保存串口数据问题解决记录(附Windows和Linux下的代码)

实时读取和保存串口数据问题解决记录(附Windows和Linux下的代码)

2023-02-24 18:36| 来源: 网络整理| 查看: 265

这两天在研究用C语言从串口接收数据。在Windows下接收数据网上已经有例子直接能用,但是在Linux下接收数据总是有问题,费了几天时间才解决,这里简单记录一下踩过的坑。

Linux下使用termios库来进行串口通信,主要是VTIME和VMIN两个参数的配置,具体的参数含义和组合说明有文章已经写得很清楚了,具体看Linux 串口编程学习记录(termios.h)

但是按照这样配置完成后发现读取的数据老是掉帧。把录制下来的数据打开后一个个字节地寻找帧头帧尾查看问题原因,发现是循环read的过程中,每次read经常是漏了一两个字节的数据,造成数据丢失,解析不出完整帧导致掉帧。最后发现是其中一些特定数据被用作特殊控制了。具体解决方法在解决方法:Linux串口接收字节0x11,0x0d,0x13丢失。简单来说就是网上的很多Linux下读写串口的示例程序都没对c_iflag进行有效的设置,这样传送ASCII码时没什么问题,但传送二进制数据时遇到0x0d,0x11和0x13却会被用作特殊控制了,关掉 ICRNL 和 IXON 选项即可解决。

实际数据特殊控制字符0x0d回车符CR0x11^Q VSTART字符0x13^S VSTOP字符

在我的程序中具体表现是360000字节的数据中没有一个0x11或者0x13,0x0d倒还是正常的。

插入一行代码就能解决

// 把终端I/O设置为原始模式(串口通讯就是终端I/O的原始模式)时输入属性设置为 options.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);

具体在Linux下读取串口数据并保存在二进制文件中的完整代码附在下面

#include #include #include #include #include #include #include int main(int argc, char *argv[]) { int fd; uint8_t buf[60]; int msg_length; // 用来存储原始串口消息 FILE *fp_msg = fopen("msg_result.txt", "wb+"); // O_RDWR表示以读写方式打开,O_NOCTTY表示不将串口设备作为控制终端 fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY ); if (fd msg_length = read(fd, buf, sizeof(buf)); printf("%d attempt get %d byte\n", j, msg_length); if (msg_length > 0) { fwrite(buf, sizeof(uint8_t), msg_length, fp_msg); } } fclose(fp_msg); close(fd); return 1; }

顺便把Windows下读取串口数据并保存在二进制文件中的完整代码也附上吧

#include #include #include #include #include #include #include int main() { HANDLE hCom; TCHAR serial_port[100]; uint8_t buf[58] = {0}; DWORD RLen = 0; BOOL status; wsprintf(serial_port, TEXT("\\\\.\\COM%d"), 5); // COM口 // 允许读和写 // 指定共享属性,由于串口不能共享,所以该参数必须为0 // 打开已经存在的串口 // 属性描述,该值为FILE_FLAG_OVERLAPPED,表示使用异步I/O,该参数为0,表示同步I/O操作 hCom = CreateFile(serial_port, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hCom == INVALID_HANDLE_VALUE){ // printf("打开COM口失败! %s\n", serial_port); return 0; } SetupComm(hCom, 5800, 5800); //设置输入缓冲区和输出缓冲区的大小 // 超时设置 COMMTIMEOUTS TimeOuts; // 设定读超时 TimeOuts.ReadIntervalTimeout = 0; //读间隔超时 TimeOuts.ReadTotalTimeoutMultiplier = 0; //读时间系数 TimeOuts.ReadTotalTimeoutConstant = 5000; //读时间常量 // 设定写超时 TimeOuts.WriteTotalTimeoutMultiplier = 1; //写时间系数 TimeOuts.WriteTotalTimeoutConstant = 1; //写时间常量 SetCommTimeouts(hCom, &TimeOuts); //设置超时 // 配置串口 DCB dcb; GetCommState(hCom, &dcb); dcb.BaudRate = 921600; // 波特率 dcb.ByteSize = 8; // 每个字节有8位 dcb.Parity = NOPARITY; // 无奇偶校验位 dcb.StopBits = ONESTOPBIT; // 一个停止位 SetCommState(hCom, &dcb); // 用来存储原始串口消息 FILE *msg_result_txt = fopen("msg_result.txt", "wb+"); assert(msg_result_txt != NULL); // while (1) for(int32_t j = 0; j fwrite(buf, sizeof(uint8_t), RLen, msg_result_txt); printf("%d attempt get %d byte\n", j, RLen); } } fclose(msg_result_txt); CloseHandle(hCom); return 1; }


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有