接线图


HEX数据包

发送数据包
/*为了发送数据包,在这里先定义个缓存区的数组*/
uint8_t Serial_TXPacket[4];//发送载荷数据
void Serial_SendPacket() //调用这个函数TxPacket数组数据就会自动加上包头包尾发送出去
{
Serial_SendByte(0xFF);//发送包头
Serial_SendArray(Serial_TXPacket,4); //发送载荷数据
Serial_SendByte(0xFC);//发送包尾
}
接收数据包
/*为了接收数据包,在这里先定义个缓存区的数组*/
uint8_t Serial_RXPacket[4];//接收载荷数据
uint8_t Serial_RxFlag; //让主程序判断是否接收完毕的标志位
if(USART_GetFlagStatus(USART1,USART_IT_RXNE) ==SET)
{
uint8_t RxData = USART_ReceiveData(USART1);
if(RxState == 0)
{
//等待包头的程序
if(RxData == 0xFF)
{
RxState = 1;
pRxPacket = 0;
}
}
else if(RxState == 1)
{
//接收数据的程序
Serial_RXPacket[pRxPacket] = RxData;
pRxPacket++;
if(pRxPacket >= 4)
{
RxState = 2;
}
}
else if(RxState == 2)
{
//等待包尾的程序
if (RxData == 0XFC)
{
RxState = 0;
Serial_RxFlag =1;
}
}
}
}
uint8_t Serial_GetRxFlag(void)
{
if(Serial_RxFlag == 1)
{
Serial_RxFlag = 0;
return 1;
}
return 0;
}
通过上面的函数,可以写出整体的逻辑函数,让串口正常的收发HEX数据包,并在OLED屏幕上显示:
int main(void){
OLED_Init();
Serial_Init();
Anjian_Init();
OLED_ShowString(1,1,"TxPacket");
OLED_ShowString(3,1,"RxPacket");
Serial_TXPacket[0]= 0x1;
Serial_TXPacket[1]= 0x2;
Serial_TXPacket[2]= 0x3;
Serial_TXPacket[3]= 0x4;
while(1)
{
if(Anjian() == 1)
{
Serial_TXPacket[0]++;
Serial_TXPacket[1]++;
Serial_TXPacket[2]++;
Serial_TXPacket[3]++;
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);
Serial_SendPacket();
}
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_SendString(char* String)函数即可,无需其他操作。
接收数据包
/*为了发送数据包,在这里先定义个缓存区的数组*/
char Serial_RxPacket[100];
uint8_t Serial_RxFlag;
void USART1_IRQHandler()
{
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 == '@')
{
RxState = 1;
pRxPacket = 0;
}
}
else if(RxState == 1)
{
if(RxData == '\r')
{
RxState = 2;
}else
{
Serial_RxPacket[pRxPacket] = RxData;
pRxPacket++;
}
}
else if(RxState == 2)
{
//等待包尾的程序
if (RxData == '\n')
{
Serial_RxPacket[pRxPacket] = '\0';
RxState = 0;
Serial_RxFlag =1;
}
}
}
}
uint8_t Serial_GetRxFlag(void)
{
if(Serial_RxFlag == 1)
{
Serial_RxFlag = 0;
return 1;
}
return 0;
}
有了上面的函数,可以进行逻辑代码的编写了:
int main(void){
OLED_Init();
Serial_Init();
LED_Init();
OLED_ShowString(1,1,"TxData"); //发送数据
OLED_ShowString(3,1,"RxData"); //接收数据
while(1)
{
if (Serial_GetRxFlag() == 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\r\n");
OLED_ShowString(2,1," ");
OLED_ShowString(2,1,"LED_ON_OK");
}
else if(strcmp(Serial_RxPacket,"LED_OFF") == 0)
{
LED1_OFF();
Serial_SendString("LED_OFF_OK\r\n");
OLED_ShowString(2,1," ");
OLED_ShowString(2,1,"LED_OFF_OK");
}
else
{
Serial_SendString("ERROR_COMMAND\r\n");
OLED_ShowString(2,1," ");
OLED_ShowString(2,1,"ERROR_COMMAND");
}
}
}
}
最后还有个问题需要说明,如果连续发送数据包,程序处理不及时,可能会导致数据包错位,在这里,文本数据包,每个数据包是独立的,不存在连续,这如果错位了,问题就比较大了,所以在程序里,可以改成每次处理完成之后,再开始接收下一个数据包。
具体怎么处理呢?
if(RxData == ‘@’ && Serial_RxFlag == 0),即再加一个判断条件,只有标志位等于0了,再开始接收下一个数据,这样写数据和读数据就严格分开了,不会同时进行,避免数据包错位的现象。