串口接收不定长数据的几种方式
来源:互联网 发布:极客学院 java 编辑:程序博客网 时间:2024/06/07 22:08
在阅读本文前,你需要先做到串口成功接收一个数据(相信这一点是很简单的)
这几天简单总结了一下用串口怎么接收一帧数据的办法,个人使用的有三种,下面逐一介绍:
第一种:使用中断的方式;
这种是最高效,也是最简单的(ps:个人认为)。既然是使用中断,所以自然需要硬件的支持,比如stm32就可以这么做,具体操作见我之前的博客stm32串口中断接收一帧数据
8位单片机估计是没有的,嵌入式32位的处理器应该会有,可以依据自己使用的芯片查一下对应的寄存器手册,重点关注一下中断寄存器和uart寄存器的介绍部分。
第二种:使用自定义结束符;
这种也是很高效的,具体的做法是,在一帧数据尾部添加一个小尾巴 ~ ~
拿我的做法举例,因为我传输的内容里面不会出现特殊字符,所以我选择特殊字符 ‘#’标识一帧数据接收完成,然后立一个flag,交由通讯处理函数去处理。
这里结束符的选取,不可以是通讯中可能传输的字符,尽量使用一个字符,简化逻辑判断。
这种方式缺点也是很明显的,即只适用于自定义的通讯格式,或者尾部结束符唯一确定的情况。代码如下:
#define MAX_LEN 10 //单个数据包的最大长度unsigned char rxDataBuff[MAX_LEN]; //串口数据接收区unsigned char rxLen = 0; //串口接收数据计数unsigned char rxFlag = 0; //*************************************************// 串口中断服务程序// 依据你具体使用的mcu对应修改,这里只给出一个逻辑// params:none// return: none// note:修改了全局变量 rxFlag 、 rxDataBuff[MAX_LEN] 、reLen//*************************************************void serialHandle(){ unsigned char dataTmp; if(RI == INT->status)//判断是否为接收中断 { dataTmp = INT->data; //将串口buff的数据读出 if('#' != dataTmp) { // //非结束符,把数据放到接收区 // rxDataBuff[reLen++] = dataTmp; } else { // //结束符 // rxDataBuff[reLen] = '\0'; rxFlag = 1; } }}//*************************************************// 循环内处理函数// 此函数应该放到你的主循环里面// // note:检测到flag首先清除标志位和接收计数//*************************************************void serialLoop(){ if(rxFlag == 1) { rxFlag = 0; //清除标志位 rxLen = 0; //清除接收计数 // //通讯处理 // }}
第三种:外加一个定时器
这种方式相对来说延时大一点,具体做法是在串口接收数据时启动定时器,每接收一帧数据要复位定时值以保证定时器不会溢出。定时器的超时值设置为1.5倍接收一个数据的时间,这样一来,当定时器超时时候,就意味着串口接收数据停止了。此时同样立一个flag,然后交由通讯处理函数处理。
这里的定时器大可不必单独再用一个定时器,可以使用系统滴答定时器,让滴答一次计数加一。超时的值设置要根据波特率调整,例如9600的波特率下,接收数据速率为9600bit/s = 1200B/s 也就是 0.83ms/B 那么我们的超时值可以设置为0.84*1.5 = 1.26ms 取个整1.3ms。其他波特率以此类推……
如果数据过去频繁,这种方式可能会产生粘包的情况(没测,如果有这方面使用需求一定要自己测试一下)。关于粘包处理,如果每个包数据长度基本相等的话,可以简单做一个根据包长度判断是否发生粘包。
#define MAX_LEN 10 //单个数据包的最大长度unsigned char rxDataBuff[MAX_LEN]; //串口数据接收区unsigned char rxLen = 0; //串口接收数据计数unsigned char rxFlag = 0;volatile unsigned char usCnt = 0; // 滴答计数变量,必须用volatile修饰volatile unsigned char rxStart = 0; //开始接收标识//*************************************************// 串口中断服务程序// 依据你具体使用的mcu对应修改,这里只给出一个逻辑// params:none// return: none// note:修改了全局变量 rxFlag 、 rxDataBuff[MAX_LEN] 、reLen//*************************************************void serialHandle(){ unsigned char dataTmp; if(RI == INT->status)//判断是否为接收中断 { rxStart = 1; rxDataBuff[rxLen++] = INT->data; usCnt = 0; }}//*************************************************// 循环内处理函数// 此函数应该放到你的主循环里面// // note:检测到flag首先清除标志位和接收计数//*************************************************void serialLoop(){ if(rxFlag == 1) { rxFlag = 0; //清除标志位 rxLen = 0; //清除接收计数 // //通讯处理………… // }}//*************************************************// 串口超时检测函数// 此函数应该放到你系统滴答定时器处理函数里面// 我的滴答设置是500us中断一次// note://*************************************************void serialTimeOut(){ if(rxStart == 1) { if(++usCnt > 3) { rxStart = 0; rxFlag = 1; } }}
这就是我目前所能想到和已经实践过的三种串口接收一帧数据的方式了,如果觉得有用就顶一下吧
,___ .-;' "-.`\_...._/.` , \ / .-' ', / () ()\`'._ \ /() . (| > .' ;, -'- / / < |;, __.; '-.'-.| , \ , \ `>.|;, \_) \_) `-; , / \ / < '. <`'-,_) '._)
- 串口接收不定长数据的几种方式
- STM32使用串口IDLE中断的两种接收不定长数据的方式
- QT 串口接收不定长数据的各种不合格版本
- STM32F207运用串口空闲中断+DMA接收不定长数据
- STM32F207运用串口空闲中断+DMA接收不定长数据
- STM32串口接收不定长数据原理与源程序
- STM32F207运用串口空闲中断+DMA接收不定长数据
- stm32 串口接收不定长数据 清测可行
- STM32串口接收不定长数据原理与源程序
- STM32串口接收不定长数据原理与源程序
- Linux 串口 一次性read接收不定长的数据(非阻塞,非延时) 程序分析
- STM32F4的HAL库开启串口空闲中断 不定长数据接收很好用
- stm32使用两路串口及接收不定长数据的实现
- STM32接收不定长数据
- 使用stm32CubeMX自动配置的工程文件,进行串口的不定长接收(非DMA方式)
- Stm32——串口空闲中断+DMA接收不定长数据
- stm32串口DMA收发,可以接收不定长数据,格式化输出。
- STM32串口使用IDLE中断接收不定长数据原理与源程序
- 如何将PDF文件中不需要的文字进行删除
- SQL操作数据
- [笔记分享] [Exception] 内核空间异常之Call Stack解析
- 一次tornado升级导致的bug,排查了好久,比较坑
- USACO-Section2.3 Money Systems
- 串口接收不定长数据的几种方式
- ucos-iii学习之关中断
- Freemarker遍历查询
- HDU Today HDU2112
- XML解析
- [性能调优]PeopleSoft Trace 分析工具
- OpenCV中mat内存管理
- Xcode多种Build Configuration配置使用
- Redux超酷的开发工具Redux-Devtools