644 字
3 分钟
串口应用层通信协议代码解析
背景介绍
串口这里不再多说,不懂的进链接去了解一下。在STM32中,串口的通信协议一般是应用层协议,即上位机和下位机之间的通信协议。这里的应用层协议是师兄设计的,之前也看过几遍,但没看懂,今天来仔细分析一下。
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
是串口接收中断的回调函数,简单理解就是每次串口接收到数据都会调用这个函数。
协议格式
A00B0000
// A后面的两位数字代表通道号
// B后面的四位数字代表值
// 注:均为字符格式
A01B1200
代码正文
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
/*define a symbol
rcvstate: | 7 | 6 | 5 | 4 |3| 2| 1| 0|
state bit |'A'received|'B'received|cmd rcv cplt| ERROR | receive index |
*/
static uint8_t rcvstate = 0x00;
switch (UART_RCV_DATA) //switch the received data
{
case 'A': //data head is 'A'
UART_RCV_BUFFER[0] = 'A';
rcvstate |= 0x81; //set A flag and data cnt 1
break;
case 'B': //data head2 is 'B'
if(rcvstate == 0x83) //if get 'A' and data index equals 3
{
rcvstate = 0xC4; //set A and B flag and data cnt 4
UART_RCV_BUFFER[3] = 'B';
}
else
{
rcvstate = 0x00; //reset state
}
break;
default:
if(UART_RCV_DATA - '0' <= 9) //check if data is numbers
{
if(rcvstate & 0xC0) //if rcvstate is 0x8X or 0xCX, result is true
{
UART_RCV_BUFFER[rcvstate & 0x0F] = UART_RCV_DATA; //save data to buffer[index]
rcvstate += 1; //data index increase
}
else
{
rcvstate = 0x00; //reset state
}
}
else //other data received
{
//now no other CMD is defined
rcvstate = 0x00; //reset state
}
if((rcvstate & 0x0F) == 8) //Data receive completed
{
rcvstate |= 0x20; //SET complete flag
/*
CMD_temp:
high 16 bits = Contral Channel
low 16 bits = Contral Value
*/
uint32_t CMD_temp = 0x00000000;
CMD_temp = 10 * (UART_RCV_BUFFER[1] - '0') //calculate ctrl channel
+ (UART_RCV_BUFFER[2] - '0');
CMD_temp <<= 16; //move channel data to high 16 bits
CMD_temp += 1000 * (UART_RCV_BUFFER[4] - '0') //calculate ctrl value
+ 100 * (UART_RCV_BUFFER[5] - '0')
+ 10 * (UART_RCV_BUFFER[6] - '0')
+ 1 * (UART_RCV_BUFFER[7] - '0');
//send CMD message
if(osMessageQueuePut(CMD_QueueHandle, &CMD_temp, 0, 0) == osOK)
{
rcvstate = 0x00; //reset state
}
else
{
rcvstate |= 0x10; //report error
}
}
break;
}
if(rcvstate & 0x10) //ERROR report signal
{
//send error report
rcvstate = 0x00; //reset state
}
}
解析过程
代码里面有注释可以参考,口头表述比较困难这里用结果来表示吧。
//char input[13] = "A02B0005CCCC";
输入的数据为 :A rcvstate: 81
输入的数据为 :0 rcvstate: 82
输入的数据为 :2 rcvstate: 83
输入的数据为 :B rcvstate: c4
输入的数据为 :0 rcvstate: c5
输入的数据为 :0 rcvstate: c6
输入的数据为 :0 rcvstate: c7
输入的数据为 :5 rcvstate: e8
输入的数据为 :C rcvstate: 0
输入的数据为 :C rcvstate: 0
输入的数据为 :C rcvstate: 0
输入的数据为 :C rcvstate: 0
输入的数据为 : rcvstate: 0
已知的BUG
发送 A02B010
也会有数据产生,而且会乱码