STM32F4 HAL库 UART相关操作API介绍

STM32F4 HAL库 UART相关操作API介绍

本文绝大部分翻译自ST的官方用户手册 Description of STM32F4 HAL and LL drivers

USART 与 UART 的区别在于有没有同步通信的功能。
USART: 通用同步异步收发器 ; UART: 通用异步收发器。

当进行异步通信时,这两者是没有区别的。
这个同步通信功能可以把USART当做SPI来用,比如用USART来驱动SPI设备。

同步(阻塞模式)是指:发送方发出数据后,等接收方发回响应以后才发下一个数据包的通讯方式。
异步(非阻塞模式)是指:发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式。

其中SPI IIC为同步通信 UART为异步通信, usart为同步&异步通信。

参考:https://blog.csdn.net/anbaixiu/article/details/78635913



硬件相关知识

STM32F427/STM32F429 共有4个USART与4个UART,如下表

序号 U(S)ART_RX引脚 U(S)ART_TX引脚 U(S)ART_CK引脚 USART_ CTS引脚 USART_ RTS引脚
USART1 PA10 PA9 PA8 PA11 PA12
USART2 PA3/PD6 PA2/PD5 PA4/PD7 PA0/PD3 PA1/PD4
USART3 PB11/PC11/PD9 PB10/PC10/PD8 PB12/PC12/PD10 PB13/PD11 PB14/PD12
UART4 PA1/PC11 PA0/PC10
UART5 PD2 PC12
USART6 PC7/PG9 PC6/PG14 PC8/PG7 PG13/PG15 PG8/PG12
UART7 PE7 PE8
UART8 PE0 PE1

RT: Receive Data 接收数据
TX: Transmit Data 发送数据
CK: Clock (同步)时钟

硬件流控制

RTS: Request To Send 请求发送数据
CTS: Clear To Send 允许发送数据

参见: UART通信中流控RTS和CTS的理解 https://blog.csdn.net/u013797023/article/details/77935535

相关结构体变量

USRT_InitTypeDef

  • 该结构体定义了用于初始化UART的一些相关参数
typedef struct
{
  uint32_t BaudRate;  //波特率
  uint32_t WordLength;//字长 取值参考 UART_Word_Length 宏定义              
  uint32_t StopBits;  //停止位 取值参考 UART_Stop_Bits 宏定义         
  uint32_t Parity;    //奇偶校验模式 取值参考 UART_Parity 宏定义 
  uint32_t Mode;      //收发模式 取值参考 UART_Mode 宏定义                
  uint32_t HwFlowCtl; //是否打开硬件流控制 取值参考 UART_Hardware_Flow_Control 宏定义                 
  uint32_t OverSampling;//是否打开过采样模式 取值参考 UART_Over_Sampling 宏定义            .
}UART_InitTypeDef;

UART_HandleTypeDef

  • 该结构体定义的则是UART句柄(个人理解为用于操作UART)的一些参数

  • 该结构体中只有*InstanceInit两个成员变量是需要我们配置的

typedef struct
{
  USART_TypeDef                 *Instance;        /*!< UART registers base address        */
    											  // UART/USART相关寄存器的地址 已经在HAL库中定义完 参数为 U(S)ARTx x=1...8 
  UART_InitTypeDef              Init;             /*!< UART communication parameters      */
    											  // UART初始化参数结构体
  uint8_t                       *pTxBuffPtr;      /*!< Pointer to UART Tx transfer Buffer */
    											  // 缓存指针
  uint16_t                      TxXferSize;       /*!< UART Tx Transfer size              */
    											  // 缓存指针指向的数据的大小(字节)
  uint16_t                      TxXferCount;      /*!< UART Tx Transfer Counter           */
    											  // 缓存指针指向的数据的的数量(字节)
  uint8_t                       *pRxBuffPtr;      /*!< Pointer to UART Rx transfer Buffer */
  uint16_t                      RxXferSize;       /*!< UART Rx Transfer size              */
  uint16_t                      RxXferCount;      /*!< UART Rx Transfer Counter           */  
  DMA_HandleTypeDef             *hdmatx;          /*!< UART Tx DMA Handle parameters      *
  												  // DMA句柄
  DMA_HandleTypeDef             *hdmarx;          /*!< UART Rx DMA Handle parameters      */
  HAL_LockTypeDef               Lock;             /*!< Locking object                     */
    											  // 锁对象
  __IO HAL_UART_StateTypeDef    State;            /*!< UART communication state           */
    											  // UART通信状态
  __IO uint32_t                 ErrorCode;        /*!< UART Error code                    */
    											  // 错误码
}UART_HandleTypeDef;
  • HAL Locked The HAL lock is used by all HAL APIs to prevent accessing by accident shared resources.
    HAL库中的API通过该参数来判断某个API是否正在执行,如__HAL_LOCK(__HANDLE__)__HAL_UNLOCK(__HANDLE__)所实现的

    typedef enum { 
        HAL_UNLOCKED = 0x00, /*!<Resources unlocked*/ 
        HAL_LOCKED = 0x01 /*!< Resources locked */ 
    }HAL_LockTypeDef;
    #define __HAL_LOCK(__HANDLE__)                                           \
                                    do{                                        \
                                        if((__HANDLE__)->Lock == HAL_LOCKED)   \
                                        {                                      \
                                           return HAL_BUSY;                    \
                                        }                                      \
                                        else                                   \
                                        {                                      \
                                           (__HANDLE__)->Lock = HAL_LOCKED;    \
                                        }                                      \
                                      }while (0)
    #define __HAL_UNLOCK(__HANDLE__)                                          \
                                      do{                                       \
                                          (__HANDLE__)->Lock = HAL_UNLOCKED;    \
                                        }while (0)
    

使用方法

  1. 声明 UART_HandleTyperDef 句柄结构体
  2. 使用HAL_UART_MspInit()初始化 UART 的底层资源
    1. 打开 USARTx 接口的时钟
    2. 配置 UART 引脚
      1. 开启 GPIO 时钟
      2. 配置引脚模式为 复用上拉
    3. 如果使用了中断需要配合 NVIC 中断优先级
      1. 配置优先级
      2. 启动 NVIC USART IRQ 句柄
    4. 如果使用了DMA处理需要配置DMA
      1. 为 输入流 或 输出流 声明DMA句柄
      2. 开启DMAx接口的时钟
      3. 配置DMA句柄结构体的参数
      4. 配置DMA的输入输出流
      5. 将DMA句柄与UART DMA Tx/Rx句柄关联
      6. 配置并启用 NVIC
  3. 配置 UART 通信的上层参数,包括波特率、字长、停止位等
  4. 根据不同的工作模式调用不同的初始化函数HAL_UART_Init() 异步通信 HAL_HalfDuplex_Init() 半双工通信HAL_LIN_Init() LIN总线通信HAL_MultiProcessor_Init() 多处理器通信

相关函数API介绍

初始化类函数

  1. HAL_StatusTypeDef HAL_UART_Init (UART_HandleTypeDef * huart)
  2. HAL_StatusTypeDef HAL_HalfDuplex_Init (UART_HandleTypeDef * huart)
  3. HAL_StatusTypeDef HAL_LIN_Init (UART_HandleTypeDef * huart, uint32_t BreakDetectLength)
  4. HAL_StatusTypeDef HAL_MultiProcessor_Init (UART_HandleTypeDef * huart, uint8_t Address, uint32_t WakeUpMethod)
  5. HAL_StatusTypeDef HAL_UART_DeInit (UART_HandleTypeDef * huart)
  • UART上层参数的初始化/注销函数,根据工作模式选用相应的初始化函数

  • 需要配置的参数包括 波特率、字长、停止位、奇偶校验模式、是否开启硬件流控制、收发模式、过采样模式

  • 参数说明:

    • *huart UART句柄结构体的指针
  • 返回API的执行情况,调用时注意检查

  1. void HAL_UART_MspInit (UART_HandleTypeDef * huart)
  2. void HAL_UART_MspDeInit (UART_HandleTypeDef * huart)
  • UART底层参数的初始化/注销函数,具体配置内容见使用方法说明
  • 在代码移植时修改该配置初始化函数即可

轮询(Polling)模式的IO操作

  1. HAL_StatusTypeDef HAL_UART_Transmit (UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size, uint32_t Timeout)

  2. HAL_StatusTypeDef HAL_UART_Receive (UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size, uint32_t Timeout)

  • 用于接收与发送数据

  • 阻塞模式,在接收、发送数据时无法进行其他操作

  • 参数说明:

    • *huart: UART句柄,用于操作UART
    • *pData: 缓冲区指针
    • Size: 缓冲区大小(以字节为单位)
    • Timeout: 超时时间,不可能让程序一直等待数据接收或发送,超过这个时间之后将放弃发送或接收
  • 返回该API的执行状态

中断模式的IO操作

  1. HAL_StatusTypeDef HAL_UART_Transmit_IT (UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size)

  2. HAL_StatusTypeDef HAL_UART_Receive_IT (UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size)

  • 用于开启UART接收/发送中断,这两个函数会设置发送/接收的缓冲区地址,大小,数量并且开启相应的中断

  • 参数说明:

    • *huart: UART句柄,用于操作UART
    • *pData: 缓冲区指针
    • Size: 缓冲区大小(以字节为单位)
  • 返回该API的执行状态,调用时注意检查

HAL_UART_Receive_IT()为例

/**
  * @brief  Receives an amount of data in non blocking mode 
  * @param  huart: pointer to a UART_HandleTypeDef structure that contains
  *                the configuration information for the specified UART module.
  * @param  pData: Pointer to data buffer
  * @param  Size: Amount of data to be received
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
  uint32_t tmp = 0;
  tmp = huart->State;  
  if((tmp == HAL_UART_STATE_READY) || (tmp == HAL_UART_STATE_BUSY_TX))
  {
    if((pData == NULL ) || (Size == 0)) 
    {
      return HAL_ERROR;
    }
    /* Process Locked */
    __HAL_LOCK(huart);
    
    huart->pRxBuffPtr = pData;
    huart->RxXferSize = Size;
    huart->RxXferCount = Size;
    
    huart->ErrorCode = HAL_UART_ERROR_NONE;
    /* Check if a transmit process is ongoing or not */
    if(huart->State == HAL_UART_STATE_BUSY_TX) 
    {
      huart->State = HAL_UART_STATE_BUSY_TX_RX;
    }
    else
    {
      huart->State = HAL_UART_STATE_BUSY_RX;
    }
    
    /* Enable the UART Parity Error Interrupt */
    __HAL_UART_ENABLE_IT(huart, UART_IT_PE);
    
    /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
    __HAL_UART_ENABLE_IT(huart, UART_IT_ERR);
    
    /* Process Unlocked */
    __HAL_UNLOCK(huart);
    
    /* Enable the UART Data Register not empty Interrupt */
    __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);
    
    return HAL_OK;
  }
  else
  {
    return HAL_BUSY; 
  }
}
  1. void HAL_UART_IRQHandler (UART_HandleTypeDef * huart)
  • UART中断处理的公共函数,需要用户在中断处理函数void USARTx_IRQHandler()中调用该函数,或者可以由STM32CubeMX程序自动生成。
  • 该函数会遍历所有与UART有关的中断类型并判断是否发生错误(设置错误代码),若没有发生错误则进行发送/接收操作
  • 若发生错误会调用 回调函数HAL_UART_ErrorCallback()
  • 发送完成将调用 回掉函数HAL_UART_TxCpltCallback()
  • 接收完成(接收缓冲区满)将调用会 回调函数HAL_UART_RxCpltCallback() ,若不想关闭接收需要在该回调函数中重新开启接收中断HAL_UART_Receive_IT()

/**
  * @brief  This function handles UART interrupt request.
  * @param  huart: pointer to a UART_HandleTypeDef structure that contains
  *                the configuration information for the specified UART module.
  * @retval None
  */
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
  uint32_t tmp1 = 0, tmp2 = 0;

  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_PE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_PE);  
  /* UART parity error interrupt occurred ------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  { 
    __HAL_UART_CLEAR_PEFLAG(huart);
    
    huart->ErrorCode |= HAL_UART_ERROR_PE;
  }
  
  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_FE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);
  /* UART frame error interrupt occurred -------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  { 
    __HAL_UART_CLEAR_FEFLAG(huart);
    
    huart->ErrorCode |= HAL_UART_ERROR_FE;
  }
  
  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_NE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);
  /* UART noise error interrupt occurred -------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  { 
    __HAL_UART_CLEAR_NEFLAG(huart);
    
    huart->ErrorCode |= HAL_UART_ERROR_NE;
  }
  
  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_ORE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);
  /* UART Over-Run interrupt occurred ----------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  { 
    __HAL_UART_CLEAR_OREFLAG(huart);
    
    huart->ErrorCode |= HAL_UART_ERROR_ORE;
  }
  
  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_RXNE);
  /* UART in mode Receiver ---------------------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  { 
    UART_Receive_IT(huart);
  }
  
  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_TXE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_TXE);
  /* UART in mode Transmitter ------------------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  {
    UART_Transmit_IT(huart);
  }
  
  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_TC);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_TC);
  /* UART in mode Transmitter end --------------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  {
    UART_EndTransmit_IT(huart);
  }

  if(huart->ErrorCode != HAL_UART_ERROR_NONE)
  {
    /* Set the UART state ready to be able to start again the process */
    huart->State = HAL_UART_STATE_READY;
    
    HAL_UART_ErrorCallback(huart);
  }  
}

总结一下中断模式下HAL库实现UART通信的流程

  1. 调用HAL_UART_Init()初始化UART(该函数会调用HAL_UART_MspInit()来初始化底层服务)

  2. 调用HAL_UART_Receive/Transmit_IT()准备开始接收或者发送数据

  3. 每接收/发送一个字节的数据时便会触发中断服务函数USARTx_IRQHandler()

  4. 中断服务函数中调用中断公共函数HAL_UART_IRQHandler()

  5. 检查没有错误后按照条件调用UART_Receive_IT() UART_Transmit_IT() UART_EndTransmit_IT()三个函数中的一个,当发送/接收完成后调用相应的回调函数(根据HAL_UART_Receive/Transmit_IT()的size参数来判断是否完成发送/接收)

  6. 若发生错误则调用处理错误的回调函数。

  • 其中需要用户实现的函数只有UARTx的中断服务函数与相应的回调函数

如要提高程序执行的效率可以重写USARTx的中断服务函数,无需调用UART中断的公共接口而自行更具相应的标识来处理接收或发送的流程。

DMA模式的IO操作

  1. HAL_StatusTypeDef HAL_UART_Transmit_DMA (UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size)
  2. HAL_StatusTypeDef HAL_UART_Receive_DMA (UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size)6
  • DMA模式下的发送/接收API
  • 非阻塞模式

UART外设状态函数

  1. HAL_UART_StateTypeDef HAL_UART_GetState (UART_HandleTypeDef * huart)
  2. uint32_t HAL_UART_GetError (UART_HandleTypeDef * huart)
  • 分别获取UART的状态与错误代码(宏定义)

宏定义介绍

具体参见stm32f4xx_hal.h头文件

posted @ 2020-08-03 22:44  SEVENFO  阅读(1036)  评论(0编辑  收藏  举报