在《STM32CubeMX初识与工程创建》的基础上,首先对串口进行设置,以实现通过串口对数据的收发。STM32CubeMX生成的HAL库中,提供了三类串口数据收发的接口,分别为阻塞模式,非阻塞模式和DMA模式,文本主要对DMA模式进行了分析并依据提供的接口提出了更加实用的串口数据收发方案。通过对网上资料的查找和分析,主要存在下述两个问题:
1、在数据接收过程中,采用了串口的空闲中断实现了DMA模式下不定长数据的接收,但存在的限制是单次接收的数据长度必须小于DMA缓冲区的长度,如果接收的数据长度大于DMA缓冲区的长度,就数据丢失了。
2、在数据发送过程中,DMA在发送阶段是不能再使能DMA发送的,即调用HAL库中的HAL_UART_Transmit_DMA接口后,在DMA传输数据完成之前是不能再调用该接口的,常用的方式是通过一个标志变量来确定是否可发送,但程序中若存在等待标志变量等逻辑的话,会降低程序运行的效率。
本文通过采用DMA的循环模式配合DMA传输完成中断和串口空闲中断解决DMA缓冲区长度对串口接收数据量的限制问题。采用类递归的逻辑解决串口发送数据等待发送完成标志的问题。
1 硬件配置
首先,应用STM32CubeMX对串口进行配置,
在Connectivity中勾选usart1,具体引脚根据硬件确定。重点注意的是,勾选USART1 global interrupt 使能;将收发的DMA添加上,将USART1_RX的DMA设置为Circular模式,将USART1_TX的DMA设置为Normal模式。
2 软件实现方案
2.1 初始化准备
将程序内部做驱动层和应用层的区分,串口数据收发接口的封装属于驱动层面,应用层面调用驱动层的接口实现数据的发送和获取,通过收发两个缓冲区实现数据的交互,本文中采用一组循环FIFO实现数据的缓冲。新建一组文件提供对串口收发数据的中间件接口,在头文件中定义串口中间件属性:
typedef struct
{
UART_HandleTypeDef *handle; /*HAL库提供的串口句柄*/
int16_t TransFlag; /*数据发送标志位*/
int32_t DmaSize; /*DMA缓冲区的大小*/
int32_t DamOffset; /*获取数据在DMA缓冲区的偏移量*/
uint8_t *pReadDma; /*指向接收DMA缓冲区的首地址*/
uint8_t *pWriteDma; /*指向发送DMA缓冲区的首地址*/
CFIFO ReadCFifo; /*接受数据的循环缓冲区*/
CFIFO WriteCFifo; /*发送数据的循环缓冲区*/
}MW_UART_ATTR;
上述属性值中包括了缓冲区,DMA等参数,后续实现中具体讲述各参数的用途。本文仅提供对一个串口进行配置用作演示,实际中在属性中添加了id参数实现多串口的管理,或者采用其他方式。
#define MW_TRANS_IDLE 0
#define MW_TRANS_BUSY 1
#define MW_UART_BUFFER_LEN 1024
#define MW_UART_DMA_LEN 256
static uint8_t Uart1TxBuff[MW_UART_BUF