当前位置:网站首页>高效的串口循环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
边栏推荐
- OpenHarmony开源开发者成长计划,寻找改变世界的开源新生力!
- MySQL restores or rolls back data through binlog
- JVM的类加载过程
- openlayers 5.0 加载arcgis server 切片服务
- OpenHarmony开源开发者成长计划,寻找改变世界的开源新生力!
- MySQL syntax collation (5) -- functions, stored procedures and triggers
- MySQL practical skills
- FTP, SSH Remote Access and control
- 点云数据集常用处理
- Codeforces Round #784 (Div. 4)
猜你喜欢

Class loading mechanism

RuntimeError: Providing a bool or integral fill value without setting the optional `dtype` or `out`

Pdf reference learning notes

Oracle配置st_geometry

Wechat applet part of the mobile phone Preview PDF did not respond

深度学习——特征工程小总结

ArcMap publishing slicing service

Kubernetes入门到精通-裸机LoadBalence 80 443 端口暴露注意事项

mysql通过binlog恢复或回滚数据

FTP, SSH Remote Access and control
随机推荐
SSDB foundation 1
The platinum library cannot search the debug process records of some projection devices
The flyer realizes page Jump through routing routes
RuntimeError: Providing a bool or integral fill value without setting the optional `dtype` or `out`
Installation, use and problem summary of binlog2sql tool
One stop service platform for high-level talents and development of comprehensive service platform system for talents
ArcMap连接 arcgis server
Redis core technology and practice 1 - start with building a simple key value database simplekv
Why is PostgreSQL about to surpass SQL Server?
山大网安靶场实验平台项目—个人记录(四)
[报告] Microsoft :Application of deep learning methods in speech enhancement
How to uninstall easyton
浅谈c语言指针的强制转换
JS controls the file type and size when uploading files
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)
RuntimeError: Providing a bool or integral fill value without setting the optional `dtype` or `out`
Codeforces Round #783 (Div. 2) D题解
Oracle configuration st_ geometry
An algorithm problem was encountered during the interview_ Find the mirrored word pairs in the dictionary
Convert string to JSON