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/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, /*!<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)
应用办法
- 申明
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
头文件
发表回复