前言
不知道你们定义通讯数据包格式是什么样的?我刚开始“包头+数据+包尾“,这样就算好了。虽然能用,但是过于粗糙,因为不够严谨所以可能回丢包,也导致比较难添加新命令。
提示:以下是本篇文章正文内容,下面案例可供参考
一、通讯协议
一.数据以命令包的形式发送
二.通讯方式:半双工
三.设备: 包头 {| 两个字节 ASCII 0X7B,0X7C + 包长度2 BYTE(每字节值0-99)
共计 4字节
计算机:包头 {| 两个字节 ASCII 0X7B,0X7C + 包长度2 BYTE(每字节值0-99)
共计 4个字节
四.包尾 包数据(命令+数据主体)校验码 2个字节 + |} 两个字节 ASCII 0X7C,0X7D.
五.包格式
包头 4BYTE 命令 1BYTE 数据主体 包尾 4BYTE
数据主体每个字节 小于100
五 数据为双字节时,高字节在前,低字节在后,高字节权重是100 (H/100,L%100)
六 包长度包含:命令及数据主体长度。
看到这里估计一头雾水,下面举例看。
二、各个命令
1–升级命令 U
UI 数据包
包头 U 数据主体 包尾
数据主体:
文件大小 4byte 99999999 byte.
文件数据校验码 2byte (异或计算)
设备回应
包头 U 数据主体 包尾
数据主体 1—进入升级状态。 0 – 未进入。(1个字节)
举例:
发送:7B 7C 00 07 55 00 05 33 58 00 51 01 06 7C 7D
。。。 ——包头—— ———数据———— ——包尾——
应答:7B 7C 00 02 55 01 00 54 7C 7D
。。。 ——包头— —数据— ——包尾——
发送包围内部CRC:01 06是根据数据主体异或结果:55 XOR 00 XOR 05 XOR 33 XOR 58 XOR 00 XOR51= 6A ,十进制为106,拆开为 01 06。
数据:55 00 05 33 58 00 51
55: ‘W’
00 05 33 58 = 001000000+510000+51*100+58=5 51 58
由此可以看出,数据不会超过100 即不超过0x64
2-- 读取设备缓冲状态
UI 数据包
包头 V ‘0’,‘0’ 包尾
设备回应
包头 V 数据主体 包尾
数据主体 1—准备好。 0 – 未准备好
举例:
7B 7C 00 03 56 30 30 00 56 7C 7D
7B 7C 00 02 56 01 00 57 7C 7D
3—发送数据
UI 数据包
包头 W 数据主体 包尾
数据主体:
数据包的索引数(0,1,…) 2byte //要
实际有效文件数据大小 2byte //要
文件数据 512byte //不需要
文件数据校验码 2byte //要
设备回应
包头 W 数据主体 包尾
数据主体 1—接受正确。 0 – 不正确
举例:
7B 7C 05 13 57 00 00 05 0C 33 30 34 43 30 30 31 30 43 31 30 31 30 30 32 30 32 39 37 31 30…00 0F 00 33 7C 7D
———包头— ———————————————数据主体———————————————————— ——包尾—
7B 7C 00 02 57 01 00 56 7C 7D
——包头— —数据— ——包尾——
数据主体代表的意思:
57—— ‘W’ 命令,
05 0C ——512个有效数据
00 00—— 第 00x100+00x0 包数据
33 30 34 43 30 30 31 30 43 31 30 31 30 30 32 30 32 39 37 31 30…——为数据内容"30 4C 00 10 C1 01 00 02 02 97 10…"以字符方式拆分。
00 0F——数据主体校验
4—确认
UI 数据包
包头 X ‘0’, ’0’ 包尾
设备回应
包头 X 数据主体 包尾
数据主体 1—升级成功 2- 数据包丢失 3—校验错误
举例:
7B 7C 00 03 58 30 30 00 58 7C 7D
7B 7C 00 02 58 01 00 59 7C 7D
升级流程
1.发送 升级命令
2.读取设备缓冲状态
3.设备准备好发送文件数据
数据包按 编号 0 1 2 3… n 每发送一个数据包 确认是否正确。不正确重发
文件数据发送方式 如 二进制字节 FE 10 23 45 (4个字节)
实际发生数据为字符串 “FE102345“ (8个字节,一个字符一个字节)
实际发送数据 是 文件字节2倍。
计算包数:文件长2/512+1(判断是否整除:整除 文件长2/512).
解析举例如下(示例):
typedef struct
{
uint16_t dataLength;
uint8_t packdata[uartBufLength];
}uartPack;
uint8_t RxBuffer_PC; // 用来接收串口1发送的数据
uartPack uart3_RcvData;
uint16_t uart3_Rd_Point=0;
uint8_t uart3_RcvHead = 0;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
uint16_t temp_crc;
loopData_Typedef buffer_loop;
if(huart->Instance == USART1) // 判断是由哪个串口触发的中断
{
//升级数据解析
uart3_Rd_Point++;
uart3_RcvData.packdata[uart3_Rd_Point-1]=RxBuffer_PC;
if (RxBuffer_PC == '{')
{
uart3_Rd_Point=1;
uart3_RcvHead = 0;
}
else if (RxBuffer_PC == '|') //收到‘|’
{
if((uart3_RcvData.packdata[0]=='{')&& (uart3_RcvData.packdata[1]=='|'))
uart3_RcvHead = 1;
}
else
{
if (uart3_RcvHead)//收到头
{
if(uart3_Rd_Point == 4)
pakagelen = uart3_RcvData.packdata[2]*100+uart3_RcvData.packdata[3]+8;//数据长度
if (RxBuffer_PC == '}')
{
temp_crc = uart3_RcvData.packdata[pakagelen-4]*100+uart3_RcvData.packdata[pakagelen-3];
if((uart3_RcvData.packdata[pakagelen-2]=='|') && //结尾倒数第二个字节
((uint8_t)temp_crc==(uint8_t)Cal_CRC_XOR(&uart3_RcvData.packdata[4],pakagelen-8)) && //CRC低位
((uint8_t)(temp_crc>>8)==(uint8_t)(Cal_CRC_XOR(&uart3_RcvData.packdata[4],pakagelen-8)>>8)))//CRC高位
// (uart3_RcvData.packdata[pakagelen-3]==(uint8_t)Cal_CRC_XOR(&uart3_RcvData.packdata[4],pakagelen-8)) && //CRC低位
// (uart3_RcvData.packdata[pakagelen-4]==(uint8_t)(Cal_CRC_XOR(&uart3_RcvData.packdata[4],pakagelen-8)>>8)))//CRC高位
{
uart3_RcvData.dataLength = uart3_Rd_Point;
/*数据接收完成*/
buffer_loop.addr=FlashUpdata_rb_rx.rbTail;
buffer_loop.len=uart3_Rd_Point;
rbWrite(&FlashUpdata_rb_rx, &uart3_RcvData.packdata, (size_tt) uart3_Rd_Point); /*数据入环*/
osMessageQueuePut(mid_MsgQueue_usart1_rx_falshupdata,(void *)&buffer_loop,0,0);
uart3_Rd_Point= 0;
uart3_RcvHead = 0;
}
else
{
uart3_Rd_Point = 0;
uart3_RcvHead = 0;
}
}
}
else
{
uart3_Rd_Point = 0