STM32的HAL库开发系列 - 串口定长接收
串口接收可以分为 定长接收 与 不定长接收 。
定长接收 就是要接收的数据量大小是事先知道的。
比如MCU与部分硬件外设的串口通信,外设会按通信协议间断地发送电机转速给MCU,这便是定长接收。
定长接收的实现非常简单。只需要处理好下面这三个函数。
/* @brief 串口接收中断函数
* @param huart 串口句柄
* @param pData 用于接收数据的缓冲数组指针
* @param Size 缓冲数组字节数
* @retval HAL_Status 返回值 HAL_OK、HAL_ERROR、HAL_BUSY、HAL_TIMEOUT
* */
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
// 串口接收中断回调函数
__weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_UART_RxCpltCallback could be implemented in the user file
*/
}
关于中断,一号串口的中断服务函数USART1_IRQHandler
是CubeMX自动生成的,函数位置在stm32f4xx_it.c中。中断服务函数会调用HAL_UART_IRQHandler(&huart1);
函数,经过一些列调用后最终会调用HAL_UART_RxCpltCallback
串口接收中断回调函数。
建议在中断回调函数内执行业务代码,即通过二次声明弱函数的方式。这样使得代码更易迁移。
// 串口中断服务函数
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
举实际的例子
// 在main中开启接收中断,在数据接收完成后会进入接收回调函数
HAL_UART_Receive_IT(&huart1, data_buffer, 2);
/* Cube自动生成的串口一中断服务函数在(stm32f4xx_it.c)中加入中断接收,方便下一次数据的接收 */
/*每一个字节的接收完成都会产生中断,进入到串口中断服务函数当中*/
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
uint8_t receive_data[2]; // 接收数组
// 串口中断接收回调函数,中断接收中指定的数据长度接收完成后会执行回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
HAL_UART_Receive_IT(&huart1, &receive_data, 1); // 将接收到的数据存入数组receive_data
}
}
其中:
huart->Instance == USART1
核心等价于huart1.Instance->SR & UART_FLAG_RXNE
再加上额外的判断。是用来判断,读取数据寄存器不是空的。
HAL_UART_Receive_IT(&huart1, &receive_data, 1);
核心等价于receive_data = huart1.Instance->DR;
再加上额外的判断。