学习STM32第七天
一、USART串口数据包
-
HEX数据包
HEX数据包里数据都是以原始的字节数据呈现,有两种类型
1、包长固定,含包头包尾;2、包长可变,含包头包尾。
上图表示一种以FF
为包头,FE
为包尾的HEX数据包格式。如果数据中有FF
或FE
数据时,可以对数据进行限幅,只取所需要范围内的数据;也可以使用固定长度的数据包,通过包头包尾对齐数据;还可以增加包头包尾的数量。对于各种数据转换为字节流的问题,数据内部还是由一个个字节组成,需要指针指向对应的数据,将其当作一个字节数组发送即可。 -
文本数据包
文本数据包里数据经过编码译码以文本字符呈现,有两种类型
1、包长固定,含包头包尾;2、包长可变,含包头包尾。
上图表示一种以@
为包头,回车键和换行符为包尾的文本数据包格式。 -
HEX数据包发送/接收
- 数据包发送
对于HEX数据包发送,可定义数组,用于填充数据以进行发送;对于文本数据包,可定义字符串,用以填充数据以进行发送。 - 数据包接收
对于固定包长的HEX数据包,每接收到一个字节,程序会进一遍中断,在中断函数里可得到这一个字节数据,得到后需退出中断。因此每得到一个字节数据都是一个独立的过程,数据包具有前后关联性,对于包头、数据和包尾需要配置不同的处理逻辑,在不同状态执行不同的操作,同时进行状态的合理转移。即采用状态机思维编程。
对于不固定包长的文本数据包,由于包长不固定所以在第二个状态下要时刻等待包尾的接收。这里继续设置一个状态接收包尾是为了避免数据错位的现象。
二、案例实验
- 定长Hex数据包发送加接收
这里HEX数据包包头为0xFF
包尾为0xFE
,数据长度为4,采用中断接收,配置代码如下
void Serial_Init()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
//USART1对应引脚复用映射
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
//配置引脚
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//配置USART1
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;//1位停止位
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8位长度
USART_Init(USART1, &USART_InitStructure);
//配置中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
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_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_GetITStatus(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 == 0xFE)
{
RxState = 0;
Serial_RxFlag = 1;
}
}
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
}
main函数代码如下
uint8_t KeyNum;
uint8_t TxPacket[4];
int main()
{
LED_Init();
Key_Init();
Serial_Init();
OLED_Init();
OLED_ShowString(1, 1, "TxPacket");
OLED_ShowString(3, 1, "Rxpacket");
TxPacket[0] = 0x11;
TxPacket[1] = 0x21;
TxPacket[2] = 0x31;
TxPacket[3] = 0x41;
while(1)
{
KeyNum = Key_GetNum();
if(KeyNum == 1)
{
OLED_ShowHexNum(2, 1, TxPacket[0], 2);
OLED_ShowHexNum(2, 4, TxPacket[1], 2);
OLED_ShowHexNum(2, 7, TxPacket[2], 2);
OLED_ShowHexNum(2, 10, TxPacket[3], 2);
Serial_SendHexPacket(TxPacket);
}
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);
}
}
}
- 不定长文本数据包发送加接收
这里只需修改中断函数,代码如下
void USART1_IRQHandler(void)
{
static uint8_t RxState = 0;
static uint8_t pRxPacket = 0;
if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
uint8_t RxData = USART_ReceiveData(USART1);
if (RxState == 0)
{
if (RxData == '@' && Serial_RxFlag == 0)
{
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')
{
RxState = 0;
Serial_RxPacket[pRxPacket] = '\0';
Serial_RxFlag = 1;
}
}
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
}
main函数如下
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\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");
}
Serial_RxFlag = 0;
}
}
}