文章目录
前言
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