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

串口应用层通信协议代码解析
https://f.undf.top/posts/code/embedded/串口应用层通信协议代码解析/
作者
小魏的个人分享
发布于
2023-01-12
许可协议
CC BY-NC-SA 4.0