目录
[1 CubeMX配置串口参数](#1 CubeMX配置串口参数)
[1.1 STM32CUB配置参数](#1.1 STM32CUB配置参数)
[1.2 生成代码](#1.2 生成代码)
[2 核心代码介绍](#2 核心代码介绍)
[2.1 初始化函数](#2.1 初始化函数)
[2.2 中断函数](#2.2 中断函数)
[2.3 重要的用户函数](#2.3 重要的用户函数)
[2.4 实现用户接口函数](#2.4 实现用户接口函数)
[3 接收数据函数的优化](#3 接收数据函数的优化)
[3.1 HAL库接收函数的缺陷](#3.1 HAL库接收函数的缺陷)
[3.2 改进接收函数](#3.2 改进接收函数)
概述
在STM32开发中使用HAL库操作串口(UART)主要分为以下几个步骤,下面以中断接收和轮询发送为例进行详细说明:
1 CubeMX配置串口参数
1.1 STM32CUB配置参数
使用STM32 Cube工具配置UART参数,具体配置如下:
1)选择端口
STM32F103RCTX有5个串口可供使用,其中USART(1~3)为增强型串口, UART(4-5)为普通串口。
2) baud rate 和其他参数
笔者选择默认参数,其具体参数如下

注意: 关于选择Baud的注意点
使用STM32串口应该注意,系统的工作频率会影响串口数据的误差率,官方已经给了测试数据,具体如下:

3) 配置中断
4) 给IO添加User Label (可选择)
1.2 生成代码
通过以上配置,完成串口功能的参数配置 。接下来可已使用STM32CUBE工具生成代码。在生成代码前,应该选择相应的开发工具,堆栈参数等

完成以上配置后,可点击GENERATE CODE生成代码,具体架构如下:

2 核心代码介绍
2.1 初始化函数
在usart.c文件中生成串口的初始代码,其包括2个部分
1) 对串口的参数进行初始化

2)IO 参数初始化
包括开启串口和IO的时钟,配置IO的工作模式,配置中断参数

2.2 中断函数
在stm32fxx_it.c文件中实现了所有已经使能中断的中断函数,这里至关注和USART相关的中断函数。

2.3 重要的用户函数
功能 | 函数 | 说明 |
---|---|---|
中断发送 | HAL_UART_Transmit_IT() |
非阻塞发送(需等待发送完成中断) |
DMA发送 | HAL_UART_Transmit_DMA() |
DMA传输(高效不占用CPU) |
DMA接收 | HAL_UART_Receive_DMA() |
DMA接收 |
发送函数 | HAL_UART_Transmit() | 查询方式发送数据 |
查询接收状态 | HAL_UART_GetState(&huart1) == HAL_OK |
检查串口状态 |
接收数据回调函数 | HAL_UART_RxCpltCallback | 用于处理接收的数据 |
2.4 实现用户接口函数
串口的重要作用是发送和接收数据,STM32Hal库已经给了相应的函数接口,程序员需要了解这些函数,并合理的使用它们。
1) 发送数据函数

要使用该函数需要对其进行改造,具体写法如下:
cpp
static void user_send(const uint8_t *buff, uint16_t len )
{
HAL_UART_Transmit(&UartHandle, buff, len, 1000);
}
2) 接收数据
STM32 HAL库已经提供了接收数据的函数 ,这里使用中断的方式接收数据,其函数原型如下:

通过在主函数中调用该函数就能接收数据。
3 接收数据函数的优化
3.1 HAL库接收函数的缺陷
如下是HAl库提供的接收函数,其包含3个参数
1) huart: 串口对象
2) pData: 接收数据的buff
3) Size: 接收数据的大小
cpp
/**
* @brief Receives an amount of data in non blocking mode.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the received data is handled as a set of u16. In this case, Size must indicate the number
* of u16 available through pData.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be received.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
/* Check that a Rx process is not already ongoing */
if (huart->RxState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Set Reception type to Standard reception */
huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
return (UART_Start_Receive_IT(huart, pData, Size));
}
else
{
return HAL_BUSY;
}
}
使用该函数接收数据,其timeout的时间取决于Size, 当Size越大,其timeout的时间会越长。
3.2 改进接收函数
通过操作STM32的寄存器实现单个字节的接收,这样可以根据接收数据的需要,随时调整Timerout的时间。具体方法如下:
1) 在回调函数中实现接收代码
cpp
uint32_t isrflags = READ_REG(huart->Instance->SR);
uint32_t cr1its = READ_REG(huart->Instance->CR1);
if( huart->Instance == USART1 )
{
/* UART in mode Receiver */
if(( isrflags & USART_SR_RXNE) != RESET )
{
data = huart->Instance->DR;
// protocol_data_recvByte(data);
}
SET_BIT(huart->Instance->CR1, USART_CR1_RXNEIE);
CLEAR_BIT(huart->Instance->SR, USART_SR_ORE);
}

2) 初始化函数中添加触发中断语句
cpp
/* USER CODE BEGIN USART1_Init 2 */
SET_BIT(huart1.Instance->CR1, USART_CR1_RXNEIE);
/* USER CODE END USART1_Init 2 *

3) 在中断函数中直接调用回调函数
cpp
/* USER CODE BEGIN USART1_IRQn 0 */
HAL_UART_RxCpltCallback(&huart1);
/* USER CODE END USART1_IRQn 0 *
