STM32F4 HAL库 UART相关API介绍
本文绝大部分翻译自ST的官方用户手册 Description of STM32F4 HAL and LL driversUSART 与 UART 的区别在于有没有同步通信的功能。
USART: 通用同步异步收发器 ; UART: 通用异步收发器。当进行异步通信时,这两者是没有区别的。
这个同步通信功能可以把USART当做SPI来用,比如用USART来驱动SPI设备。同步(阻塞模式)是指:发送方发出数据后,等接收方发回响应以后才发下一个数据包的通讯方式。
异步(非阻塞模式)是指:发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式。其中SPI IIC为同步通信 UART为异步通信, usart为同步&异步通信。
参考:https://blog.csdn.net/anbaixi...
硬件相关知识
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/u013797...
相关结构体变量
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)的一些参数
- 该结构体中只有
*Instance
与Init
两个成员变量是需要我们配置的
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, /*!
Lock == HAL_LOCKED) \ { \ return HAL_BUSY; \ } \ else \ { \ (__HANDLE__)->Lock = HAL_LOCKED; \ } \ }while (0) #define __HAL_UNLOCK(__HANDLE__) \ do{ \ (__HANDLE__)->Lock = HAL_UNLOCKED; \ }while (0)
使用方法
- 声明
UART_HandleTyperDef
句柄结构体 使用
HAL_UART_MspInit()
初始化 UART 的底层资源- 打开 USARTx 接口的时钟
配置 UART 引脚
- 开启 GPIO 时钟
- 配置引脚模式为 复用上拉
如果使用了中断需要配合 NVIC 中断优先级
- 配置优先级
- 启动 NVIC USART IRQ 句柄
如果使用了DMA处理需要配置DMA
- 为 输入流 或 输出流 声明DMA句柄
- 开启DMAx接口的时钟
- 配置DMA句柄结构体的参数
- 配置DMA的输入输出流
- 将DMA句柄与UART DMA Tx/Rx句柄关联
- 配置并启用 NVIC
- 配置 UART 通信的上层参数,包括波特率、字长、停止位等
- 根据不同的工作模式调用不同的初始化函数
HAL_UART_Init()
异步通信HAL_HalfDuplex_Init()
半双工通信HAL_LIN_Init()
LIN总线通信HAL_MultiProcessor_Init()
多处理器通信
相关函数API介绍
初始化类函数
HAL_StatusTypeDef HAL_UART_Init (UART_HandleTypeDef * huart)
HAL_StatusTypeDef HAL_HalfDuplex_Init (UART_HandleTypeDef * huart)
HAL_StatusTypeDef HAL_LIN_Init (UART_HandleTypeDef * huart, uint32_t BreakDetectLength)
HAL_StatusTypeDef HAL_MultiProcessor_Init (UART_HandleTypeDef * huart, uint8_t Address, uint32_t WakeUpMethod)
HAL_StatusTypeDef HAL_UART_DeInit (UART_HandleTypeDef * huart)
- UART上层参数的初始化/注销函数,根据工作模式选用相应的初始化函数
- 需要配置的参数包括 波特率、字长、停止位、奇偶校验模式、是否开启硬件流控制、收发模式、过采样模式
参数说明:
*huart
UART句柄结构体的指针
- 返回API的执行情况,调用时注意检查
void HAL_UART_MspInit (UART_HandleTypeDef * huart)
void HAL_UART_MspDeInit (UART_HandleTypeDef * huart)
- UART底层参数的初始化/注销函数,具体配置内容见使用方法说明
- 在代码移植时修改该配置初始化函数即可
轮询(Polling)模式的IO操作
HAL_StatusTypeDef HAL_UART_Transmit (UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size, uint32_t Timeout)
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操作
HAL_StatusTypeDef HAL_UART_Transmit_IT (UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size)
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;
}
}
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通信的流程
- 调用
HAL_UART_Init()
初始化UART(该函数会调用HAL_UART_MspInit()
来初始化底层服务) - 调用
HAL_UART_Receive/Transmit_IT()
准备开始接收或者发送数据 - 每接收/发送一个字节的数据时便会触发中断服务函数
USARTx_IRQHandler()
- 中断服务函数中调用中断公共函数
HAL_UART_IRQHandler()
- 检查没有错误后按照条件调用
UART_Receive_IT()
UART_Transmit_IT()
UART_EndTransmit_IT()
三个函数中的一个,当发送/接收完成后调用相应的回调函数(根据HAL_UART_Receive/Transmit_IT()
的size参数来判断是否完成发送/接收) - 若发生错误则调用处理错误的回调函数。
- 其中需要用户实现的函数只有UARTx的中断服务函数与相应的回调函数
如要提高程序执行的效率可以重写USARTx的中断服务函数,无需调用UART中断的公共接口而自行更具相应的标识来处理接收或发送的流程。
DMA模式的IO操作
HAL_StatusTypeDef HAL_UART_Transmit_DMA (UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size)
HAL_StatusTypeDef HAL_UART_Receive_DMA (UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size)
6
- DMA模式下的发送/接收API
- 非阻塞模式
UART外设状态函数
HAL_UART_StateTypeDef HAL_UART_GetState (UART_HandleTypeDef * huart)
uint32_t HAL_UART_GetError (UART_HandleTypeDef * huart)
- 分别获取UART的状态与错误代码(宏定义)
宏定义介绍
具体参见stm32f4xx_hal.h
头文件