注:参考ST公司HAL库附带UART-IT例程。 参考资料:ST-《STM32F4xx中文参考手册》、野火-《零死角玩转STM-F429》
主要数据类型:
UART_HandleTypeDef UartHandle;主要HAL函数:
初始化函数:
HAL_StatusTypeDef HAL_UART_Init ( UART_HandleTypeDef * huart );
void HAL_UART_MspInit ( UART_HandleTypeDef *huart ) ;
回调函数:
void HAL_UART_TxCpltCallback( UART_HandleTypeDef * UartHandle );
void HAL_UART_RxCpltCallback( UART_HandleTypeDef * UartHandle );
void HAL_UART_ErrorCallback( UART_HandleTypeDef *UartHandle )
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 );
中断响应函数:
void USARTx_IRQHandler();
步骤:
1.进行UART外设配置:
<span style="white-space:pre"> </span>UART_HandleTypeDef UartHandle; //全局或在主函数中定义
UartHandle.Instance = USARTx; //选择所需端口,例程中将USART1作为UART使用
//以下为示例
UartHandle.Init.BaudRate = 9600; //波特率设置
UartHandle.Init.WordLength = UART_WORDLENGTH_8B; //数据长度设置
UartHandle.Init.StopBits = UART_STOPBITS_1; //停止位设置
UartHandle.Init.Parity = UART_PARITY_NONE; //奇偶校验设置
UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE; //流控制设置 (RTS以及CTS)
UartHandle.Init.Mode = UART_MODE_TX_RX; //模式设置 例程中同时用到收发功能
UartHandle.Init.OverSampling = UART_OVERSAMPLING_16;
//使用初始化函数进行配置
HAL_UART_Init(&UartHandle); //若配置成功,该函数返回值 HAL_OK
UART_HandleTypeDef 结构体内的成员有许多,但是使用HAL库进行配置则只需要用户设置其中的 Init 成员,其余的由初始化库函数以及操作库函数自行配置完成。
注意,在 HAL_UART_Init 函数结束时则使能了对应UART外设(相应时钟还未使能)
2.进行GPIO、NVIC、相应时钟配置
在HAL_UART_Init函数中,有语句
if(huart->State == HAL_UART_STATE_RESET)
{
/* Allocate lock resource and initialize it */
huart->Lock = HAL_UNLOCKED;
/* Init the low level hardware */
HAL_UART_MspInit(huart);
}
即若传入的 UART_HandleTypeDef 类型结构体的 State 成员为 HAL_UART_STATE_RESET 状态,则对其解锁限制,然后调用一个WEAK定义的HAL函数
void HAL_UART_MspInit ( UART_HandleTypeDef * huart );
一般用户可以在外部自行重新定义该函数,用来初始化板载上GPIO的UART复用,以及相应时钟配置、NVIC配置。在例程中便是如此
/**
* @brief UART MSP Initialization
* This function configures the hardware resources used in this example:
* - Peripheral's clock enable
* - Peripheral's GPIO Configuration
* - NVIC configuration for UART interrupt request enable
* @param huart: UART handle pointer
* @retval None
*/
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
GPIO_InitTypeDef GPIO_InitStruct;
/*##-1- Enable peripherals and GPIO Clocks #################################*/
/* Enable GPIO TX/RX clock */
USARTx_TX_GPIO_CLK_ENABLE(); //使能相应使用的Tx引脚GPIO口时钟
USARTx_RX_GPIO_CLK_ENABLE(); //使能相应使用的Rx引脚GPIO口时钟
/* Enable USART1 clock */
USARTx_CLK_ENABLE(); //使能相应UART\USART时钟
/*##-2- Configure peripheral GPIO ##########################################*/
/* UART TX GPIO pin configuration */
GPIO_InitStruct.Pin = USARTx_TX_PIN; //可使用的引脚需要参考手册
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
GPIO_InitStruct.Alternate = USARTx_TX_AF;
HAL_GPIO_Init(USARTx_TX_GPIO_PORT, &GPIO_InitStruct);
/* UART RX GPIO pin configuration */
GPIO_InitStruct.Pin = USARTx_RX_PIN; //可使用的引脚需要参考手册
GPIO_InitStruct.Alternate = USARTx_RX_AF;
HAL_GPIO_Init(USARTx_RX_GPIO_PORT, &GPIO_InitStruct);
/*##-3- Configure the NVIC for UART ########################################*/
/* NVIC for USART1 */
HAL_NVIC_SetPriority(USARTx_IRQn, 0, 1); //配置NVIC优先级
HAL_NVIC_EnableIRQ(USARTx_IRQn); //使能使用的UART\USART中断
}
注意:
1.每个 USART\UART 可使用来作为Tx、Rx的引脚是各不相同的,这点需要具体参考手册进行配置
2.所使用的 USART\UART 时钟以及对应中断需要使能
3.若程序中使用到了 SysTick,建议将 SysTick 的中断优先级提在USART\UART之前
" The the SysTick interrupt must have higher priority (numerically lower) than the peripheral interrupt. Otherwise the caller ISR process will be blocked. "
4.如果想要使用 HAL_UART_MspInit 函数来调用板载外设初始化语句,那么应当确保参数的 Status 值
3.收发函数
这里是用到的IT方式,故只举例IT方式的库函数。
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 )
HAL_UART_Transmit_IT 函数为发送函数。在其中自动将奇偶校验错误、帧错误、噪音错误、上溢错误以及数据寄存器( DR )为空 中断使能。
调用该函数后则将把 pData 所指向的数组中的 Size 个数据发送出去。应当在调用该函数后利用一个循环等待发送完成。可通过判断作为参数传入该函数的 UART_HandleTypeDef 类型结构体的 Status 成员是否为 HAL_UART_STATE_READY 来判断是否发送完成(该成员在刚被该函数调用时被设置为 HAL_UART_STATE_BUSY_TX_RX 或 HAL_UART_STATE_BUSY_TX,在程序运行至 UART_EndTransmit_IT 并发送成功后被设置为 HAL_UART_STATE_READY )
HAL_UART_Receive_IT 函数为接收函数。在其中自动将奇偶校验错误、帧错误、噪音错误、上溢错误以及数据寄存器( DR )为空 中断使能。
调用该函数后则将把从端口中接收的 Size 个数据存放到 pData 所指向的数组去。应当在调用该函数后利用一个循环等待接收完成。可通过判断作为参数传入该函数的 UART_HandleTypeDef 类型结构体的 Status 成员是否为 HAL_UART_STATE_READY 来判断是否接收完成(该成员在刚被该函数调用时被设置为 HAL_UART_STATE_BUSY_TX_RX 或 HAL_UART_STATE_BUSY_TX,在程序运行至 UART_Receive_IT 并接收成功后被设置为 HAL_UART_STATE_READY )
PS:DMA方式中相应函数用到了函数指针知识。
4.对应中断响应函数以及回调函数
在这里,主要用到的中断响应函数有
SysTick_Handler() //Systick计时到点中断
USARTx_IRQHandler() //USART中断 因为我们使用的是USART1,所以是USART中断
回调函数有
HAL_UART_TxCpltCallback(UART_HandleTypeDef *UartHandle) //发送完成回调函数
HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle) //接收完成回调函数
HAL_UART_ErrorCallback(UART_HandleTypeDef *UartHandle) //错误回调函数
其中,USARTx_IRQHandler 中断响应函数在 USART 发送、接收、以及错误等时候会响应。使用HAL库,我们可以这样编写该中断响应函数
/* UART handler declared in other file */
extern UART_HandleTypeDef UartHandle;
.
.
.
void USARTx_IRQHandler(void)
{
HAL_UART_IRQHandler(& UartHandle);
}
这里,该中断响应函数里面调用了库函数 HAL_UART_IRQHandler 函数,并将我们之前定义的 UART_HandleTypeDef 类型的结构体 UartHandle 的地址作为参数传入。
在 HAL_UART_IRQHandler 函数里,主要进行了清除错误标志位、记录错误码 (HAL库中定义的 UART Error Code)以及判断是否进入接收( UART_Receive_IT(& UartHandle) )、发送( UART_Transmit_IT(& UartHandle) )、发送结束( UART_EndTransmit_IT(& UartHandle) )以及错误回调函数 (HAL_UART_ErrorCallback(& UartHandle) 函数默认为空,WEAK定义。)。
--------------------------------------------------------------------------------------
UART Error Code为一系列宏定义
<span style="white-space:pre"> </span>#define HAL_UART_ERROR_NONE ((uint32_t)0x00000000) //无
#define HAL_UART_ERROR_PE ((uint32_t)0x00000001) //奇偶校验错误
#define HAL_UART_ERROR_NE ((uint32_t)0x00000002) //噪声错误
#define HAL_UART_ERROR_FE ((uint32_t)0x00000004) //帧错误
#define HAL_UART_ERROR_ORE ((uint32_t)0x00000008) //上溢错误
#define HAL_UART_ERROR_DMA ((uint32_t)0x00000010) //DMA传输错误
static HAL_StatusTypeDef UART_Receive_IT ( UART_HandleTypeDef * huart ) //接收数据,如果当前端口不忙,接收成功返回 HAL_OK ,否则返回 HAL_BUSY。并且在接受完成后关闭由 HAL_UART_Receive_IT 开启的一系列中断,调用 HAL_UART_RxCpltCallback 函数。默认为空,WEAK定义。
static HAL_StatusTypeDef UART_Transmit_IT ( UART_HandleTypeDef * huart ) //发送数据,如果当前端口不忙,发送成功返回 HAL_OK ,否则返回 HAL_BUSY。
static HAL_StatusTypeDef UART_EndTransmit_IT ( UART_HandleTypeDef * huart ) //结束传输置传入结构体 State 成员为非阻塞状态。并且在完成后关闭由 HAL_UART_Transmit_IT 开启的一系列中断。调用 HAL_UART_TxCpltCallback 函数。默认为空,WEAK定义。
--------------------------------------------------------------------------------------
以上的都是由 HAL_UART_IRQHandler 函数自动调用配置。