抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

前言

最近学明白了一个比较实用的队列算法在串口通信方面的应用,记录一下。

本文开发环境

STM8L101F3、STlink、USB串口

软件配置

1.串口基础配置

创建hal_usart.c进行串口配置,从规格书来看,STM8L101F3只有一个串口,串口的配置按照官方给的函数static void USART_Config(void)进行修改为如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void hal_Usart_Config(void)
{
CLK_MasterPrescalerConfig(CLK_MasterPrescaler_HSIDiv1);
GPIO_ExternalPullUpConfig(GPIOC,GPIO_Pin_3|GPIO_Pin_4, ENABLE);
CLK_PeripheralClockConfig(CLK_Peripheral_USART, ENABLE);

USART_DeInit();

USART_Init((uint32_t)115200, USART_WordLength_8D, USART_StopBits_1,USART_Parity_No, (USART_Mode_TypeDef)(USART_Mode_Rx | USART_Mode_Tx));

USART_ITConfig(USART_IT_TXE, DISABLE);
USART_ITConfig(USART_IT_RXNE, ENABLE);
enableInterrupts();

}

修改参数:

波特率修改为115200

奇偶校验: 修改为无校验。

把stm8l10x_it.c里面的串口中断处理函数INTERRUPT_HANDLER(USART_TX_IRQHandler, 27)INTERRUPT_HANDLER(USART_RX_IRQHandler, 28)移到hal_usart.c里。

2.加入消息队列模块

首先添加queue.c和queue.h文件,在hal_usart.c里引入queue头文件。

消息队列的使用流程:

消息根据需求定义队列的大小

初始化队列:清空队列 新定义的队列一定要先初始化,然后再使用。

数据入列

数据出列

下面进行以串口收发相同的功能进行实战演练:

定义变量

1
2
3
4
5
6
Queue256 UsartRxMsg;//定义256个字节的串口接收消息队列
Queue256 UsartTxMsg;//定义256个字节的串口发送消息队列
unsigned char TxBuffer[256];//串口数据发送数据的缓存
unsigned int TxCounter = 0;//0表示没有发送数据 其他值表示发送数据的下标
unsigned int TxDataSize = 0;//串口需要发送的有效数据的长度

修改void hal_Usart_Config(void)函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void hal_Usart_Config(void)
{
CLK_MasterPrescalerConfig(CLK_MasterPrescaler_HSIDiv1);
GPIO_ExternalPullUpConfig(GPIOC,GPIO_Pin_3|GPIO_Pin_4, ENABLE);
CLK_PeripheralClockConfig(CLK_Peripheral_USART, ENABLE);

USART_DeInit();

USART_Init((uint32_t)115200, USART_WordLength_8D, USART_StopBits_1,USART_Parity_No, (USART_Mode_TypeDef)(USART_Mode_Rx | USART_Mode_Tx));

USART_ITConfig(USART_IT_TXE, DISABLE);
USART_ITConfig(USART_IT_RXNE, ENABLE);
enableInterrupts();

QueueEmpty(UsartRxMsg);//清空队列
QueueEmpty(UsartTxMsg);

TxCounter = 0;
TxDataSize = 0; //串口发送数据的长度
}

现在假设PC端向单片机发送“1234”,下面就要对串口接收到的字节进行“消息入列”到UsartRxMsg中进行存储,代码如下:

1
2
3
4
5
6
7
INTERRUPT_HANDLER(USART_RX_IRQHandler, 28)
{
unsigned char dat;
dat = (uint8_t)USART_ReceiveData8();
// 参数:定义的队列的名称,需要入列的数据的指针地址,入列数据的长度
QueueDataIn(UsartRxMsg,&dat,1);
}

紧接着我们要让单片机将收到的信息原封不动的发回PC端,因此我们要定义static void hal_Usart_RxHandler(void)函数先把UsartRxMsg的数据传输给UsartTxMsg,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static void hal_Usart_RxHandler(void)
{
unsigned char len,i;
unsigned char usartRxBuffer[128];
//返回值:消息中有效数据的长度 形参:需要查询的队列
len = QueueDataLen(UsartRxMsg);
if(len)
{ //消息处理函数
for(i=0;i<len;i++)
{
//形参:需要出列的消息队列 指针变量:用来保存出列的数据
QueueDataOut(UsartRxMsg,&usartRxBuffer[i]);
}
QueueDataIn(UsartTxMsg,usartRxBuffer,len);
}
}

之后要把UsartTxMsg的数据取出来,再通过串口发送给PC端,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
static void hal_Usart_TxHandler(void)
{
unsigned char len,i;
if(TxCounter == 0)
{///表示无线发送数据空闲
len = QueueDataLen(UsartTxMsg);
if(len)
{
for(i=0;i<len;i++)
{
QueueDataOut(UsartTxMsg,&TxBuffer[i]);
}
USART_SendData8(TxBuffer[0]);
TxCounter = 1;
TxDataSize = len; //串口发送数据的长度
USART_ITConfig(USART_IT_TXE, ENABLE);
}
}
}
INTERRUPT_HANDLER(USART_TX_IRQHandler, 27)
{
if (TxCounter == TxDataSize)
{
USART_ITConfig(USART_IT_TXE, DISABLE);
TxCounter = 0;
}
else
{
USART_SendData8(TxBuffer[TxCounter++]);
}
}

注意这里的两个静态函数static void hal_Usart_RxHandler(void)static void hal_Usart_TxHandler(void),为了能让外部调用我们需要封装一下:

1
2
3
4
5
void hal_Usart_Pro(void)
{
hal_Usart_RxHandler();
hal_Usart_TxHandler();
}

最后在main.c文件内调用相应代码完成串口收发相同的功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include "stm8l10x.h"
#include "hal_tim4.h"
#include "hal_usart.h"

//定义systick
__IO uint8_t systick;

void main(void)
{
CLK_MasterPrescalerConfig(CLK_MasterPrescaler_HSIDiv1);//16M
hal_TIM4_Config();
hal_Usart_Config();
systick = 0;
while (1)
{
if(systick == 1)
{
systick = 0;
hal_Usart_Pro();
}
}
}

INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler, 25)
{
systick = 1; ///1MS
TIM4_ClearITPendingBit(TIM4_IT_Update);
}

结语

虽然看起来好像代码量增加了、逻辑更绕了、数据传递的路径更长了,但是加入消息队列的好处:可以避免消息数据的丢失、更加方便程序逻辑的处理。因此,在延迟可以容忍的情况下保障信息安全完整、可靠,应该是要优先考虑的。