当前位置:网站首页>高效的串口循环Buffer接收处理思路及代码2
高效的串口循环Buffer接收处理思路及代码2
2022-04-23 19:24:00 【ToneChip】
前面的文章
下面先自定义将串口协议定出来,按照这个协议发送的数据格式进行解析,因为串口数据快,多帧的数据就混到一起,我们要把多帧的数据按照协议提出解析出来,因此就有这篇文章进行数据解析,我的注释写的很详细,串口的接收是一个循环的fifo,也就是每个字节接收到之后从0开始存到缓存的最后,存满之后再从缓存的0开始存,是一个循环的结构
14字节设置命令'S'协议基本格式 | |||
字节序号 | Hex内容 | 说明 | 备注 |
0 | 0x55 | 固定桢头 | 固定桢头 |
1 | 0xAA | 固定桢头 | |
2 | 0x0E | 表示字节长度 | 固定为0x0E,表示14字节 |
3 | 0x53 | 大写字符'S' | 0x53 = 字符'S'(表示set) |
4 | 0xmn | u8ModuleType | 模块类型码,详见模块类型列表,最多255种模块类型 |
5 | (m<<6)|n | (u8PageProperty<<6)|u8EQBandIndex | 因为属性页面只有0x01或者0x02,所以只用2bit来表示属性,而EQ的段属性从0开始,占用6个bit位,所以最大可以表示0b111111 = 63(段) m表示页面属性占用高2位,n表示段属性占用低6位, |
6 | 0x00~0x04(最多4个参数) | u8ModuleItem | 模块的第几个参数0x00~0xmn(模块参数顶多6个) |
7 | 0x00~0x07,从0x00开始 | u8StartCh开始通道号 | 如果开始通道号与结束通道号相等,则表明只设置该一个通道号,且结束通道号需要>=开始通道号,否则不执行 |
8 | 0x00~0x07,从0x00开始 | u8EndCh结束通道号 | |
9 | ParamAccess | 一个float或者int类型的设置参数 | 用ParamAccess方法转换,用这种方式表示浮点数据占4字节 |
10 | |||
11 | |||
12 | |||
13 | CRC | 校验位字节 | 最后一个字节做"和校验",将前13个字节相加后取低八位 |
下面插入解析代码,可能有些宏定义没有贴出来,我定义的2种协议是14和56字节,也就是上位机发送和传输要么是14字节或者56字节两种情况进行解析
/*********************************************************************************************************
** 处理和解析显示串口数据,处理原则是快收慢发
** 设备和上位机之间传输要么是14字节,要么是56字节
** Uart0RxDataProcess(void)
** 时间计算 56*16*10/115200 = 77.77778ms约78ms缓存
** 上位机发送不能78ms内发送太多字节
*********************************************************************************************************/
void Uart0RxDataProcess(void)
{
int i = 0;
//串口数据处理,g_u8Uart0RxDataMem是运行到这函数里面时接收到数据的总缓存
unsigned char *pUart0RxDataMem = (unsigned char * )g_u8Uart0RxDataMem;
unsigned char u8UartParaBuf[UART0_FRAME_MAX_LEN] = {0}; //临时变量,每次处理一帧数据
unsigned char u8DataLen = 0;
unsigned short u16TempRxStartIndex = 0;
if(pUart0RxDataMem == NULL)
{
return ;
}
//开始解析数据,gUart0RxByteNum是表示的接收到的字节个数
u8DataLen = 0;
while(gUart0RxByteNum >= 3) //如果接收到的数据长度大于3个字节,就可以进行帧头0x55AA的判断
{
//用桢头完整字节判断,一个字节容易出错
if((pUart0RxDataMem[gUart0RxStartIndex] == 0x55) &&
(pUart0RxDataMem[(gUart0RxStartIndex + 1) % UART0_RX_BUFF_LEN] == 0xAA))
{
u8DataLen = pUart0RxDataMem[((gUart0RxStartIndex + 2) % UART0_RX_BUFF_LEN)];//第3个字节时本帧的长度,取出来判断一下是不是14或者56
if((UART_RX_PROTOCOL_SIZE == u8DataLen) ||
(UART_RX_ExPROTOCOL_SIZE == u8DataLen) ) //检测到指定的协议长度就结束循环
{
break;
}
}
//如果帧长不等于14或者56,那么把帧头的第一个字节置0,去掉一个字节,再循环判断,直到检测到0x55AA就跳出循环
pUart0RxDataMem[gUart0RxStartIndex % UART0_RX_BUFF_LEN] = 0;
gUart0RxStartIndex = (gUart0RxStartIndex + 1) % UART0_RX_BUFF_LEN; //gUart0RxStartIndex的大小始终都在0~UART0_RX_BUFF_LEN之间,防止溢出
gUart0RxByteNum--; //接收到的总字节数减掉1
gUart0RxByteNum = ( gUart0RxByteNum <= 0) ? 0 : gUart0RxByteNum; //防接收负数处理
}
//执行到这里,表示检测到了0x55AA
if((gUart0RxByteNum >= u8DataLen) && (u8DataLen > 0)) //如果接收的字节数大于协议中的帧长
{
//先把数据取出(gUart0RxStartIndex读取的偏置先不变)做校验
u16TempRxStartIndex = gUart0RxStartIndex;
for(i = 0; i < u8DataLen; i++)
{
u8UartParaBuf[i] = pUart0RxDataMem[u16TempRxStartIndex];//校验通过将数据取出存放到u8UartParaBuf
u16TempRxStartIndex = (u16TempRxStartIndex + 1) % UART0_RX_BUFF_LEN;
}
if(CheckReciveDataCRC(u8UartParaBuf, u8DataLen))//如果校验正确即可从原大缓存中清除对应的字节数后按照协议提取数据
{
for(i = 0; i < u8DataLen; i++) //清除取出的数据
{
pUart0RxDataMem[gUart0RxStartIndex] = 0;
gUart0RxStartIndex = (gUart0RxStartIndex + 1) % UART0_RX_BUFF_LEN;
gUart0RxByteNum--;
gUart0RxByteNum = ( gUart0RxByteNum <= 0) ? 0 : gUart0RxByteNum; //防接收负数处理
}
u8DataLen = ProcessingProtocolData(u8UartParaBuf, u8DataLen);
UART0_SendBuf(u8UartParaBuf, u8DataLen); //返回发送最大消耗时间为56*10/115200 = 4.86ms
}
else
{
//如果校验错误,前面的数据已经被清除为0,因此这桢数据就丢弃
pUart0RxDataMem[gUart0RxStartIndex] = 0; //只需清除一个字节让while循环去清除其他数据
gUart0RxStartIndex = (gUart0RxStartIndex + 1) % UART0_RX_BUFF_LEN;
gUart0RxByteNum--;
gUart0RxByteNum = ( gUart0RxByteNum <= 0) ? 0 : gUart0RxByteNum; //防接收负数处理
}
}
}
版权声明
本文为[ToneChip]所创,转载请带上原文链接,感谢
https://tonechip.blog.csdn.net/article/details/121827631
边栏推荐
- Network protocol: SCTP flow control transmission protocol
- arcMap 发布切片服务
- js获取本机ip地址
- No, some people can't do the National Day avatar applet (you can open the traffic master and earn pocket money)
- 山大网安靶场实验平台项目—个人记录(四)
- ArcMap连接 arcgis server
- 考试系统进入试卷优化思路
- Strange passion
- 高层次人才一站式服务平台开发 人才综合服务平台系统
- Solve the problem of invalid listview Click
猜你喜欢
Android Development: the client obtains the latest value in the database in real time and displays it on the interface
深度学习——特征工程小总结
Redis optimization series (III) solve common problems after master-slave configuration
网络协议之:sctp流控制传输协议
Is meituan, a profit-making company with zero foundation, hungry? Coupon CPS applet (with source code)
C6748 软件仿真和硬件测试 ---附详细FFT硬件测量时间
MySQL syntax collation (5) -- functions, stored procedures and triggers
White screen processing method of fulter startup page
OpenHarmony开源开发者成长计划,寻找改变世界的开源新生力!
Decompile and get the source code of any wechat applet - just read this (latest)
随机推荐
PostgreSQL
Audio signal processing and coding - 2.5.3 the discrete cosine transform
ArcGIS JS API dojoconfig configuration
arcgis js api dojoConfig配置
Web Security
Build intelligent garbage classification applet based on Zero
Transaction processing of SQL Server database
Class loading mechanism
JS calculation time difference
An example of using JNI to directly access surface data
Decompile and get the source code of any wechat applet - just read this (latest)
浅谈c语言指针的强制转换
Easy mock local deployment (you need to experience three times in a crowded time. Li Zao will do the same as me. Love is like a festival mock)
Steps to build a deep learning environment GPU
RuntimeError: Providing a bool or integral fill value without setting the optional `dtype` or `out`
How to uninstall easyton
Lottery applet, mother no longer have to worry about who does the dishes (assign tasks), so easy
SQL of contention for system time plus time in ocrale database
什么是消息队列
2021-2022-2 ACM集训队每周程序设计竞赛(8)题解