STM32 HAL库里 串口中断回调函数是在怎么被调用的?

发布于:2024-07-04 ⋅ 阅读:(21) ⋅ 点赞:(0)

跟着正点原子学习的HAL库写串口接收程序的时候一直有困惑,使用HAL_UART_Receive_IT开启接收中断后,为啥处理函数要写在HAL_UART_RxCpltCallback里,中断发生的时候是怎么到这个回调函数里去的?

void MX_USART1_UART_Init(void)
{
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */
  uint8_t byte;
  HAL_UART_Receive_IT(&huart1, &byte, 1); /* 这里开启接收中断!!!!!*/
  /* USER CODE END USART1_Init 2 */
}

接下来我们代码里面一步步看,HAL_UART_Receive_IT检查了下串口是不是在等待状态,是的话就执行UART_Start_Receive_IT:

HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
  /* Check that a Rx process is not already ongoing */
  if (huart->RxState == HAL_UART_STATE_READY)
  {
    if ((pData == NULL) || (Size == 0U))
    {
      return HAL_ERROR;
    }
    /* 设置接收类型为标准类型 */
    huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
    return (UART_Start_Receive_IT(huart, pData, Size));
  }
  else
  {
    return HAL_BUSY;
  }
}

UART_Start_Receive_IT主要设置了中断寄存器。

HAL_StatusTypeDef UART_Start_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
  huart->pRxBuffPtr = pData;
  huart->RxXferSize = Size;
  huart->RxXferCount = Size;
  huart->ErrorCode = HAL_UART_ERROR_NONE;
  huart->RxState = HAL_UART_STATE_BUSY_RX;
  if (huart->Init.Parity != UART_PARITY_NONE){
    /* 启用奇偶校验错误中断 */
    __HAL_UART_ENABLE_IT(huart, UART_IT_PE);
  }
  /* 启用UART错误中断:(帧错误、噪声错误、溢出错误) */
  __HAL_UART_ENABLE_IT(huart, UART_IT_ERR);
  /* 启用 UART 数据寄存器非空中断 */
  __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);
  return HAL_OK;
}

其中这个非空中断就是触发HAL_UART_RxCpltCallback回调函数的伏笔。

开启中断后,串口收到数据,就会触发外部中断,代码在启动时的那个汇编文件里。
在这里插入图片描述
然后就跳转到了stm32f4xx_it.c里,如果文件里找不到出现这个函数看看是不是Cube配置的时候没打开中断。

__weak void USART1_IRQHandler(void)
{
  HAL_UART_IRQHandler(&huart1);
}

在这里插入图片描述
HAL_UART_IRQHandler有将近200行,主要做了如下事情:
1.读取中断标志和控制寄存器;
2.没有错误中断的情况下是否设置了非空中断,如果是调用UART_Receive_IT;
3.如果有错误中断则处理错误中断;
4.处理空闲线路检测(上面设置接收模式为标准);
5.处理发送中断,在接收完直接处理发送流程;

然后UART_Receive_IT又调用了HAL_UART_RxCpltCallback。所以在这个回调函数里写操作过程。
在这里插入图片描述
那能不能在USART1_IRQHandler里写呢?也是可以的,但是回调函数结构上更清晰,以前STM32最早的标准库就写在USART1_IRQHandler里。