【stm32】USART 串口打包(数据与文本)



前言

B站江科大网课


一、定义概念 + 缩写

1. HEX 数据包

在这里插入图片描述

  • 橙色的是包头,蓝色的是包尾,中间绿色的是数据。
    数据包的目的是将数据分割,方便下位机的识别。
    分为固定包长可变包长,固定包长比较稳定。
    在笔者的毫米波雷达物联网模块中,为了稳定,所有串口都是固定包长。实际上思路也很简单,我传几个多余的参数,维护了稳定性,利远大于弊。

在这里插入图片描述

  • 文本数据包同理。优点是易于理解,缺点是解析速度代价。“好用” 和 “高效”,“顶层” 和 “底层” 的矛盾。

2. Tx 与 Rx 的 x 的含义

没有含义

参考文献 [1]

二、数据包的接收流程

在这里插入图片描述

数电状态图(Statechart Diagram)(草),之前还不明白这个为什么要这么画,现在一眼懂

三、数据包发送 代码

1. 需要删除的代码

由于删去了串口接收变量 Serial_RxData,需要删除以下的代码

  • Serial_GetRxData
/**
  * 函    数:获取串口接收的数据
  * 参    数:无
  * 返 回 值:接收的数据,范围:0~255
  */
uint8_t Serial_GetRxData(void)
{
	return Serial_RxData;			//返回接收的数据变量
}
  • 中断里面 Serial_RxData 相关的代码
Serial_RxData = USART_ReceiveData(USART1); //读取数据寄存器,存放在接收的数据变量
  • 定义缓冲发送与接收数据的变量
uint8_t Serial_TxPacket[4];				//定义发送数据包数组,数据包格式:FF 01 02 03 04 FE
uint8_t Serial_RxPacket[4];				//定义接收数据包数组

2. 添加的代码(serial.h 中)

  • 串口发送数据包
/**
  * 函    数:串口发送数据包
  * 参    数:无
  * 返 回 值:无
  * 说    明:调用此函数后,Serial_TxPacket数组的内容将加上包头(FF)包尾(FE)后,作为数据包发送出去
  */
void Serial_SendPacket(void)
{
	// 发送包头
	Serial_SendByte(0xFF);

	// 发送包身
	Serial_SendArray(Serial_TxPacket, 4);
	
	// 发送包尾
	Serial_SendByte(0xFE);
}
  • 声明数组为外部可调用(关键字 extern)
extern uint8_t Serial_TxPacket[];
extern uint8_t Serial_RxPacket[];

3. 主函数中的代码块

  • 定义串口发送的数组元素
/*设置发送数据包数组的初始值,用于测试*/
Serial_TxPacket[0] = 0x01;
Serial_TxPacket[1] = 0x02;
Serial_TxPacket[2] = 0x03;
Serial_TxPacket[3] = 0x04;
  • 串口发送数据包
Serial_SendPacket();

四 数据包接收 代码

1. 配置接收(R)中断

  • 设置接收数据的中断处理函数,RsState 的值变化按照下面状态转移图的状态机的 S 值进行设置(调控分支结构)
    在这里插入图片描述

  • 接收数据中断处理函数

void USART1_IRQHandler(void)
{
	// 定义表示当前状态机状态的静态变量
	static uint8_t RxState = 0;		

	// 定义表示当前接收数据位置的静态变量,p =place
	static uint8_t pRxPacket = 0;	
	
	// 判断是否是USART1的接收事件触发的中断
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)		
	{	
		//读取数据寄存器,存放在接收的数据变量 
		uint8_t RxData = USART_ReceiveData(USART1);				
		
		/*使用状态机的思路,依次处理数据包的不同部分*/
		
		/*当前状态为0,接收数据包包头*/
		if (RxState == 0)
		{
			if (RxData == 0xFF)			//如果数据确实是包头
			{
				RxState = 1;			//置下一个状态
				pRxPacket = 0;			//数据包的位置归零
			}
		}
		
		/*当前状态为1,接收数据包数据*/
		else if (RxState == 1)
		{	
			// 获取数据,存入数据包数组的指定位置
			Serial_RxPacket[pRxPacket] = RxData;	
			pRxPacket ++;				//数据包的位置自增
			if (pRxPacket >= 4)			//如果收够4个数据
			{
				RxState = 2;			//置下一个状态
			}
		}
		
		/*当前状态为2,接收数据包包尾*/
		else if (RxState == 2)
		{
			if (RxData == 0xFE)			//如果数据确实是包尾部
			{
				RxState = 0;			//状态归0
				Serial_RxFlag = 1;		//接收数据包标志位置1,成功接收一个数据包
			}
		}
			
		//清除中断的标志位
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);		
	}
}

  • 这里 up 主先写好了程序的框架,再往里面填程序
    在这里插入图片描述

2. 主函数中的代码块

  • 接收数据包的代码在 serial.h 里面,这里直接读取 Rx 的标志位
if (Serial_GetRxFlag() == 1)	//如果接收到数据包
{
	OLED_ShowHexNum(4, 1, Serial_RxPacket[0], 2);	//显示接收的数据包
	OLED_ShowHexNum(4, 4, Serial_RxPacket[1], 2);
	OLED_ShowHexNum(4, 7, Serial_RxPacket[2], 2);
	OLED_ShowHexNum(4, 10, Serial_RxPacket[3], 2);
}

总结

  • 串口手法数据包常常在各种模块中使用,比较重要
  • 由于项目中没有用到,所以本文没有写串口接收文本数据包的内容

参考文献

[1] rx,tx中的x什么意思 https://www.zhihu.com/question/36993913
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值