背景介绍

串口这里不再多说,不懂的进链接去了解一下。在STM32中,串口的通信协议一般是应用层协议,即上位机和下位机之间的通信协议。这里的应用层协议是师兄设计的,之前也看过几遍,但没看懂,今天来仔细分析一下。

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 是串口接收中断的回调函数,简单理解就是每次串口接收到数据都会调用这个函数。

协议格式

1
2
3
4
5
6
7
8
9

A00B0000

// A后面的两位数字代表通道号
// B后面的四位数字代表值
// 注:均为字符格式

A01B1200

代码正文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
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
}
}

解析过程

代码里面有注释可以参考,口头表述比较困难这里用结果来表示吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

//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 也会有数据产生,而且会乱码