HEX数据包
固定包长,包含包头包尾
通过判断第一个数据是否为包头,如果是的话,开始接收数据。接收固定个数的数据后开始读取包尾,若包尾读取成功,则数据传输完成。
读取固定个数的数据的好处就是,如果数据中含有与包头包尾一样的数据,也会读取,并不会产生影响。
如果数据不会与包头包尾重复,可以选择不固定数据长度,采用可变包长。
代码实例
Serial GetRXFlag用于数据接收完成的标志,置1代表数据接收完成。
uint8_t Serial_GetRxFlag(void)
{
if(Serial_RxFlag==1)
{
Serial_RxFlag=0;
return 1;
}
return 0;
}
void USART1_IRQHandler(void)
{
static uint8_t pRxPacket=0; //已接收数据个数
static uint8_t RxState=0; //接收状态位,状态0位检测包头,状态1位接收数据,状态2位检测包尾
if(USART_GetITStatus(USART1 ,USART_IT_RXNE )==SET )
{
uint8_t RxData=USART_ReceiveData (USART1 );
if(RxState==0)
{
if(RxData==0xFF) //检测包头
{
RxState=1; //接收包头后置1开始接收数据
}
}
else if(RxState==1)
{
Serial_RxPacket[pRxPacket]=RxData;
pRxPacket++;
if(pRxPacket ==4) //判断是否接收数据完成
{
RxState=2; //接收完成后置状态2检测包尾
pRxPacket=0; //接收完成后已接收数据位清0
}
}
else if(RxState==2)
{
if(RxData==0xFE) //检测包尾
{
RxState=0;
Serial_RxFlag =1; //数据接收完成置结束标志位1
}
}
USART_ClearITPendingBit(USART1 ,USART_IT_RXNE );
}
}
在串口助手上发送数据
OLED上显示
可变包长,包含包头包尾
通过判断第一个数据是否为包头,如果是的话,开始接收数据。接收固定个数的数据后开始读取包尾,若包尾读取成功,则数据传输完成。
可变包长只适用于数据不与包头和包尾重复时候,数据个数可以写入多个。
文本数据包
固定包长,包含包头包尾
void USART1_IRQHandler(void)
{
static uint8_t RxState = 0; //定义表示当前状态机状态的静态变量
static uint8_t pRxPacket = 0; //定义表示当前接收数据位置的静态变量
if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET) //判断是否是USART1的接收事件触发的中断
{
uint8_t RxData = USART_ReceiveData(USART1); //读取数据寄存器,存放在接收的数据变量
/*使用状态机的思路,依次处理数据包的不同部分*/
/*当前状态为0,接收数据包包头*/
if (RxState == 0)
{
if (RxData == '@' && Serial_RxFlag == 0) //如果数据确实是包头,并且上一个数据包已处理完毕
{
RxState = 1; //置下一个状态
pRxPacket = 0; //数据包的位置归零
}
}
/*当前状态为1,接收数据包数据,同时判断是否接收到了第一个包尾*/
else if (RxState == 1)
{
if (RxData == '\r') //如果收到第一个包尾
{
RxState = 2; //置下一个状态
}
else //接收到了正常的数据
{
Serial_RxPacket[pRxPacket] = RxData; //将数据存入数据包数组的指定位置
pRxPacket ++; //数据包的位置自增
}
}
/*当前状态为2,接收数据包第二个包尾*/
else if (RxState == 2)
{
if (RxData == '\n') //如果收到第二个包尾
{
RxState = 0; //状态归0
Serial_RxPacket[pRxPacket] = '\0'; //将收到的字符数据包添加一个字符串结束标志
Serial_RxFlag = 1; //接收数据包标志位置1,成功接收一个数据包
}
}
USART_ClearITPendingBit(USART1, USART_IT_RXNE); //清除标志位
}
}
主程序代码
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
#include "LED.h"
#include "string.h"
int main(void)
{
/*模块初始化*/
OLED_Init(); //OLED初始化
LED_Init(); //LED初始化
Serial_Init(); //串口初始化
/*显示静态字符串*/
OLED_ShowString(1, 1, "TxPacket");
OLED_ShowString(3, 1, "RxPacket");
while (1)
{
if (Serial_RxFlag == 1) //如果接收到数据包
{
OLED_ShowString(4, 1, " ");
OLED_ShowString(4, 1, Serial_RxPacket); //OLED清除指定位置,并显示接收到的数据包
/*将收到的数据包与预设的指令对比,以此决定将要执行的操作*/
if (strcmp(Serial_RxPacket, "LED_ON") == 0) //如果收到LED_ON指令
{
LED1_ON(); //点亮LED
Serial_SendString("LED_ON_OK\r\n"); //串口回传一个字符串LED_ON_OK
OLED_ShowString(2, 1, " ");
OLED_ShowString(2, 1, "LED_ON_OK"); //OLED清除指定位置,并显示LED_ON_OK
}
else if (strcmp(Serial_RxPacket, "LED_OFF") == 0) //如果收到LED_OFF指令
{
LED1_OFF(); //熄灭LED
Serial_SendString("LED_OFF_OK\r\n"); //串口回传一个字符串LED_OFF_OK
OLED_ShowString(2, 1, " ");
OLED_ShowString(2, 1, "LED_OFF_OK"); //OLED清除指定位置,并显示LED_OFF_OK
}
else //上述所有条件均不满足,即收到了未知指令
{
Serial_SendString("ERROR_COMMAND\r\n"); //串口回传一个字符串ERROR_COMMAND
OLED_ShowString(2, 1, " ");
OLED_ShowString(2, 1, "ERROR_COMMAND"); //OLED清除指定位置,并显示ERROR_COMMAND
}
Serial_RxFlag = 0; //处理完成后,需要将接收数据包标志位清零,否则将无法接收后续数据包
}
}
}