STM32HAL库USART源代码解析
- 前言
- STM32CubeIDE配置串口
-
- USART和UART的选择
- 使用模式
- 参数设置
- GPIO配置
- DMA配置
- 中断配置
- 硬件流控制使能
- 生成代码解析和使用方法
-
- 串口初始化
- __UART_HandleTypeDef结构体浅析
- HAL库代码实际使用方法
-
- 使用轮询方式发送
- 使用轮询方式接收
- 使用中断方式发送
- 使用中断方式接收
前言
本文从STM32CubeIDE的配置出发,详细介绍了配置流程,另外深入解析USART生成的HAL库初始化相关代码,并给出通过中断和轮询的接收、发送函数的使用方法。尤其对于中断发送函数、中断接收函数的使用和内部原理给出独到而又准确的见解,相信对你有很大的帮助!如果你有这方面的需要,相信你阅读完成会满载而归。
STM32CubeIDE配置串口
对于串口的配置,比较简单,下面截几张图来描述一下。
USART和UART的选择
先说①,选择芯片上的某一个USART或者UART。二者的区别是,前者是“通用同步异步收发器”,后者是“通用异步收发器”。前者比后者多了一个“同步模式”,也就是说,它会输出时钟信号,以此来配合这TX和RX引脚发送和接收信息。如果你之前了解过SPI,就知道我在说什么了。没有了解过也没有关系,跟着我的节奏看就行了,不要给自己加压力哈!如上图,我选择了USART1。
使用模式
②,选择当前使用的模式,图上显示了很多种,有“异步模式”、“同步模式”、“单线半双工模式”、“多处理器通信模式”、“IrDA模式”、“LIN模式”、“智能卡模式”、“智能卡带卡时钟的模式”。我们当前选择了“异步模式”。对于这么多种模式分别是什么,应用与哪些场景,这些我之后写一篇文章详细讲解。
参数设置
③,参数设置,包括传输的波特率,这里是默认的115200Bits/s,传输的字长是8位,如果我下面使能了校验位,那么这8位的最后一位就是校验位;也就是说,如果我的数据位只能是7位了!这个可以选择是8位还是9位。由于我在校验位上选择了None,那么就是说,我的8位字长全部用于传输数据。下面是停止位,可以i选择1或者2,在传输中表示一帧数据的结束的。之后就是数据传输方向,我选择既发送又接收,当然可以选择只接收或者只发送。最后是过采样倍数选择,可以是8倍,也可以是16倍。
GPIO配置
可以选择具体的引脚来复用,在右边有芯片引脚分布,可以进行自由选择。(补充一下:要先确定了哪两个引脚复用,再进行参数设置、模式设置等)
DMA配置
关于DMA的配置比较简单,如下图,保持默认配置就可以。
接收的话,自然是外设到内存,内存地址需要自增,外设每次都读DR寄存器,自然不用自增地址。
发送的话,自然是内存到外设,内存地址需要自增,外设不用自增地址。
中断配置
在使能框打勾,表示使能了串口中断。但我们注意到优先级都是0,这就有点高,可以修改下。
在NVIC里面,选择中断优先级分组,之后就是下面的中断进行使能和设定优先级。数字越小,优先级越高。滴答定时器优先级设置为最高,串口设置的低一些。你肯定不愿意在串口的中断函数里如果使用了HAL_Delay函数之后,就卡死出不来了,是不是?那么就把滴答定时器优先级设置的高一些!当然在中断函数里一般不会去延时,这样不明智。但凡事考虑周到嘛。
硬件流控制使能
补充说明一下,所谓的硬件流,就是通信双方在接收或者发送过程中“通个气”,告诉对方,我现在是否方便接收或者发送,如果不方便,你先别发送数据过来,或者我先不发送数据给你。如果我告诉你,我现在不方便发送,那么总线上的电平信号,你不用采集,也不用管。
生成代码解析和使用方法
上面已经完成了配置介绍,下面就讲一下生成的代码吧。
串口初始化
在main.c文件中会在主函数初始化阶段调用下面的函数:
MX_USART1_UART_Init();
我们也就先从这个函数入手,看看它做了什么。跟我们上面的配置是怎么一一对应的。
在usart.c文件中,定义了此函数的函数体,如下:
void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
}
还记得我们上面的配置吧,看看是不是我们使用的USART1、波特率,字长、停止位、奇偶校验、数据传输方向是接收和发送,过采样使用16倍。这些跟我们的配置是一一对应的。
但我们看到还有一些信息没有对应进来,比如我们使用的GPIO,在HAL_UART_Init()函数内部也有操作。进去看看?
HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart)
{
/* Check the UART handle allocation */
if (huart == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
if (huart->Init.HwFlowCtl != UART_HWCONTROL_NONE)
{
/* The hardware flow control is available only for USART1, USART2, USART3 and USART6.
Except for STM32F446xx devices, that is available for USART1, USART2, USART3, USART6, UART4 and UART5.
*/
assert_param(IS_UART_HWFLOW_INSTANCE(huart->Instance));
assert_param(IS_UART_HARDWARE_FLOW_CONTROL(huart->Init.HwFlowCtl));
}
else
{
assert_param(IS_UART_INSTANCE(huart->Instance));
}
assert_param(IS_UART_WORD_LENGTH(huart->Init.WordLength));
assert_param(IS_UART_OVERSAMPLING(huart->Init.OverSampling));
if