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, /*!<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
头文件