STM32 HAL库串口的功能实现与改进

目录

概述

[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 *