9-4串口收发HEX数据包&串口收发文本数据包

HEX数据包

HEX数据包
固定包长,含包头包尾:每个数据包的长度固定不变,前面是包头,后面是包尾
可变包头,含包头包尾:每个数据包的长度可以不一样,前面是包头,后面是包尾

固定包头这里规定,每组4个字节,在这4个字节之前,加上定义的包头0xFF,后面加上定义的包尾0xFE

另外,还可以不要包尾,只使用一个包头FF,接收到包头FF后,开始接收,收够4个字节之后,置标志位,一个数据包接收完成。

如果传输的数据本身就是FF和FE怎么办呢?

限制载荷数据的范围,在发送时进行限幅;
或者使用固定长度的数据包,可以通过包头包尾对其数据,哪个数据是包头,哪个数据是包尾,哪个数据是载荷数据,在接收载荷数据时,不会判断这个数据是否为包头或包尾;
或者增加包头包尾的数量,让它尽量呈现出载荷数据出现不了的状态

如果载荷不会和包头包尾重复,可以选择可变包长

数据长度可以任意改变,因为包头和包尾都是唯一的,出现包头,就接收,出现包尾,就停止接收。

文本数据包

文本数据包
在文本数据包中,数据经过了一次编码和译码,表现出来的文本格式。
由于数据译码成了字符形式,就可以有大量的字符作为包头和包尾,可以有效避免载荷和包头包尾重复的问题。

HEX数据包接收

HEX数据包接收
对于数据包来说,接收具有前后的关联性,包头->数据->包尾,对于这三种状态,需要不同的处理逻辑,即状态机
对于接收数据,可以定义为三个状态。等待包头,然后接收数据,最后等待包尾,每个状态用一个变量来标志一下。

文本数据包接收

文本数据包接收

串口收发HEX数据包

Serial.c

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
#include "stm32f10x.h"                  // Device header#include <stdio.h>#include <stdarg.h> uint8_t Serial_TxPacket[4];//发数组uint8_t Serial_RxPacket[4];//收数组uint8_t Serial_RxFlag;//收到标志位   void Serial_Init(void){	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//开启USART1的时钟	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启GPIOA的时钟 	GPIO_InitTypeDef GPIO_InitStructure;	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//引脚模式,TX是USART外设控制的输出脚,选择复用推挽输出;RX引脚是USART外设控制的输入脚,选择输入模式,一般RX配置为浮空输入或者上拉输入。	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	GPIO_Init(GPIOA, &GPIO_InitStructure); 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//RX配置为浮空输入	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	GPIO_Init(GPIOA, &GPIO_InitStructure); 	USART_InitTypeDef USART_InitStructure;	USART_InitStructure.USART_BaudRate = 9600;//波特率	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流控制	USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//发送模式	USART_InitStructure.USART_Parity = USART_Parity_No;//校验位,选择不需要校验	USART_InitStructure.USART_StopBits = USART_StopBits_1;//停止位	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长,由于前面没有选择校验,这里选8位	USART_Init(USART1,&USART_InitStructure); 	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//开启RXNE标志位到NVIC的输出	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 	NVIC_InitTypeDef NVIC_InitStructure;	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;	NVIC_Init(&NVIC_InitStructure); 	USART_Cmd(USART1,ENABLE);} void Serial_SendByte(uint8_t Byte){	USART_SendData(USART1, Byte);	while( USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET );//获取标志位,发送寄存器空标志位,避免产生数据覆盖的问题 } void Serial_SendArray(uint8_t *Array, uint16_t Length){	uint16_t i;	for (i=0;i<Length;i++)	{		Serial_SendByte(Array[i]);	}} void Serial_SendString(char *String){	uint8_t i;	for ( i = 0; String[i] != '\0'; i++ )	{		Serial_SendByte(String[i]);	}} uint32_t Serial_Pow(uint32_t X,uint32_t Y){	uint32_t Result = 1;	while (Y--)	{		Result *= X;	}	return Result;}  void Serial_SendNumber(uint32_t Number, uint8_t Length){	uint8_t i;	for ( i = 0; i<Length; i++ )	{		Serial_SendByte(Number / Serial_Pow(10,Length - i - 1) % 10 + '0');	}} int fputc(int ch, FILE *f)//printf 输出到串口{	Serial_SendByte(ch);	return ch;} void Serial_Printf(char *format, ... ){	char String[100];	va_list arg;	va_start(arg,format);	vsprintf(String, format, arg);	va_end(arg);	Serial_SendString(String);} void Serial_SendPacket(void)//发送数据包{	Serial_SendByte(0xFF);//发送包头	Serial_SendArray(Serial_TxPacket,4);//发送数据包内容	Serial_SendByte(0xFE);//发送包尾} uint8_t Serial_GetRxFlag(void){	if(Serial_RxFlag == 1)	{		Serial_RxFlag = 0;		return 1;	}	return 0;} void USART1_IRQHandler(void){	static uint8_t RxState = 0;	static uint8_t PRxPacket = 0;	if(USART_GetFlagStatus(USART1,USART_IT_RXNE) == SET)	{		//三种状态		uint8_t RxData = USART_ReceiveData(USART1);//获取当前接收到的数据		if(RxState == 0)		{			if(RxData == 0xFF)//接收到包头			{				RxState = 1;//进入下一步,开始接收有效载荷			}		}		else if(RxState == 1)		{			Serial_RxPacket[PRxPacket] = RxData;//接收一个数据			PRxPacket++;//存的位置自增			if(PRxPacket >= 4)//4组数据全部记录完			{				RxState = 2;//进入下一步,等待包尾				PRxPacket = 0;//记录的位置清0,为下一次准备			}		}		else if(RxState == 2)		{			if(RxData == 0xFE)//接收到包尾			{				RxState = 0;//回到最初状态,一个数据包接收完成				Serial_RxFlag = 1;//接收完成标志位置1			}		}		USART_ClearITPendingBit(USART1,USART_IT_RXNE);	}} 

main.c

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
#include "stm32f10x.h"                  // Device header#include "Delay.h"#include "OLED.h"#include "Serial.h"#include "Key.h" uint8_t KeyNum; int main(void){	OLED_Init();	KEY_Init();	Serial_Init(); 	OLED_ShowString(1,1,"TxPacket:");	OLED_ShowString(3,1,"RxPacket:");	//给数组一个初值	Serial_TxPacket[0] = 0x01;	Serial_TxPacket[1] = 0x02;	Serial_TxPacket[2] = 0x03;	Serial_TxPacket[3] = 0x04; 	while (1)	{ 		KeyNum = Key_GetNum();		if (KeyNum == 1)//按钮按下		{			Serial_TxPacket[0] ++;//发数组的值自增1			Serial_TxPacket[1] ++;			Serial_TxPacket[2] ++;			Serial_TxPacket[3] ++;			Serial_SendPacket();//发送数组			OLED_ShowHexNum(2,1,Serial_TxPacket[0],2);//显示发送的数组			OLED_ShowHexNum(2,4,Serial_TxPacket[1],2);			OLED_ShowHexNum(2,7,Serial_TxPacket[2],2);			OLED_ShowHexNum(2,10,Serial_TxPacket[3],2);		}		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);		}	}} 

串口收发文本数据包

Serial.c

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
#include "stm32f10x.h"                  // Device header#include <stdio.h>#include <stdarg.h> char Serial_RxPacket[100];uint8_t Serial_RxFlag;   void Serial_Init(void){	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//开启USART1的时钟	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启GPIOA的时钟 	GPIO_InitTypeDef GPIO_InitStructure;	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//引脚模式,TX是USART外设控制的输出脚,选择复用推挽输出;RX引脚是USART外设控制的输入脚,选择输入模式,一般RX配置为浮空输入或者上拉输入。	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	GPIO_Init(GPIOA, &GPIO_InitStructure); 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//RX配置为浮空输入	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	GPIO_Init(GPIOA, &GPIO_InitStructure); 	USART_InitTypeDef USART_InitStructure;	USART_InitStructure.USART_BaudRate = 9600;//波特率	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流控制	USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//发送模式	USART_InitStructure.USART_Parity = USART_Parity_No;//校验位,选择不需要校验	USART_InitStructure.USART_StopBits = USART_StopBits_1;//停止位	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长,由于前面没有选择校验,这里选8位	USART_Init(USART1,&USART_InitStructure); 	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//开启RXNE标志位到NVIC的输出	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 	NVIC_InitTypeDef NVIC_InitStructure;	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;	NVIC_Init(&NVIC_InitStructure); 	USART_Cmd(USART1,ENABLE);} void Serial_SendByte(uint8_t Byte){	USART_SendData(USART1, Byte);	while( USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET );//获取标志位,发送寄存器空标志位,避免产生数据覆盖的问题 } void Serial_SendArray(uint8_t *Array, uint16_t Length){	uint16_t i;	for (i=0;i<Length;i++)	{		Serial_SendByte(Array[i]);	}} void Serial_SendString(char *String){	uint8_t i;	for ( i = 0; String[i] != '\0'; i++ )	{		Serial_SendByte(String[i]);	}} uint32_t Serial_Pow(uint32_t X,uint32_t Y){	uint32_t Result = 1;	while (Y--)	{		Result *= X;	}	return Result;}  void Serial_SendNumber(uint32_t Number, uint8_t Length){	uint8_t i;	for ( i = 0; i<Length; i++ )	{		Serial_SendByte(Number / Serial_Pow(10,Length - i - 1) % 10 + '0');	}} int fputc(int ch, FILE *f)//printf 输出到串口{	Serial_SendByte(ch);	return ch;} void Serial_Printf(char *format, ... ){	char String[100];	va_list arg;	va_start(arg,format);	vsprintf(String, format, arg);	va_end(arg);	Serial_SendString(String);}    void USART1_IRQHandler(void){	static uint8_t RxState = 0;	static uint8_t PRxPacket = 0;	if(USART_GetFlagStatus(USART1,USART_IT_RXNE) == SET)	{		//三种状态		uint8_t RxData = USART_ReceiveData(USART1);//获取当前接收到的数据		if(RxState == 0)		{			if(RxData == '@' && Serial_RxFlag == 0)//接收到包头			{				RxState = 1;//进入下一步,开始接收有效载荷				PRxPacket = 0;//计数器清0			}		}		else if(RxState == 1)		{			if(RxData == '\r')//先判断接收到的是不是包尾			{				RxState = 2;			}			else//不是包尾,记录数据			{			Serial_RxPacket[PRxPacket] = RxData;//接收一个数据			PRxPacket++;//存的位置自增			}		}		else if(RxState == 2)		{			if(RxData == '\n')//接收到包尾			{				RxState = 0;//回到最初状态,一个数据包接收完成				Serial_RxPacket[PRxPacket] = '\0';				Serial_RxFlag = 1;//接收完成标志位置1			}		}		USART_ClearITPendingBit(USART1,USART_IT_RXNE);	}} 

main.c

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
#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();	LED_Init();	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); 			if(strcmp(Serial_RxPacket,"LED_ON") == 0)			{				LED1_ON();				Serial_SendString("LED_ON_OK");				OLED_ShowString(4,1,"                ");				OLED_ShowString(4,1,"LED_ON_OK");			}			else if(strcmp(Serial_RxPacket,"LED_OFF") == 0)			{				LED1_OFF();				Serial_SendString("LED_OFF_OK");				OLED_ShowString(4,1,"                ");				OLED_ShowString(4,1,"LED_OFF_OK");			}			else			{				Serial_SendString("ERROR");				OLED_ShowString(4,1,"                ");				OLED_ShowString(4,1,"ERROR");			}			Serial_RxFlag = 0;		}	}}  
🔍 ×