HAL_UART_IRQHandler(UART_HandleTypeDef *huart)里面的中断接收函数

前言

看了很长时间串口中断的HAL库,最容易混淆的就是函数的名称,主要集中在UART_Receive_ITHAL_UART_ReceiveHAL_UART_Receive_IT。有点傻傻分不清楚,接下来分析一下他们各自的含义。

1、UART_Receive_IT

函数代码如下:

static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)
{
  uint16_t *tmp;

  /* Check that a Rx process is ongoing */
  if (huart->RxState == HAL_UART_STATE_BUSY_RX)
  {
    if (huart->Init.WordLength == UART_WORDLENGTH_9B)//判断CR寄存器的第12位W是否为1 ,为1则代表设置为一个起始位, 9个数据位, n个停止位
    {
      tmp = (uint16_t *) huart->pRxBuffPtr;//将pRxBuffPtr这个缓冲区的首地址先转化为16位的整型再赋值给tmp
      if (huart->Init.Parity == UART_PARITY_NONE)//奇偶校验位
      {
        *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF);
        huart->pRxBuffPtr += 2U;
      }
      else
      {
        *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x00FF);
        huart->pRxBuffPtr += 1U;
      }
    }
    else
    {
      if (huart->Init.Parity == UART_PARITY_NONE)
      {
        *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);//将数据寄存器DR的值载入到huart的缓冲区指针所指向的位置
      }
      else
      {
        *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F);
      }
    }

    if (--huart->RxXferCount == 0U)
    {
      /* Disable the UART Data Register not empty Interrupt */
      __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);

      /* Disable the UART Parity Error Interrupt */
      __HAL_UART_DISABLE_IT(huart, UART_IT_PE);

      /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */
      __HAL_UART_DISABLE_IT(huart, UART_IT_ERR);//接收数据完成,关闭中断并开始回调函数

      /* Rx process is completed, restore huart->RxState to Ready */
      huart->RxState = HAL_UART_STATE_READY;

#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
      /*Call registered Rx complete callback*/
      huart->RxCpltCallback(huart);
#else
      /*Call legacy weak Rx complete callback*/
      HAL_UART_RxCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */

      return HAL_OK;
    }
    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

前半部分其实我觉得tmp这个变量存在与否没有什么关键含义,因为if-else的两种情况都是将USARTDR寄存器的值存放到pRxBuffPtr这个缓存区,只不过这个pRxBuffPtr是一个指向缓存区首地址的指针。这个函数是把所有输入的数据一个一个存放到缓存区中,也就是,一个数据对应一次中断,直到确认所有的数据都存放到缓存区中,huart->RxXferCount对应的值也会自减为0,此时会执行3个__HAL_UART_DISABLE_IT函数来关闭中断(我也不知道为什么HAL库要这样设置),之后会进入回调函数,我们只需在回调函数中写入我们的用户代码即可。但是其中一定要包含打开中断的函数,因为__HAL_UART_DISABLE_IT这个函数已经关闭中断。可以仔细品读这个函数,详细的注释我已经写在了代码块里面,有了注释应该就不难理解。

2、HAL_UART_Receive

这个代码如下

HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
  uint16_t *tmp;
  uint32_t tickstart = 0U;

  /* Check that a Rx process is not already ongoing */
  if (huart->RxState == HAL_UART_STATE_READY)
  {
    if ((pData == NULL) || (Size == 0U))
    {
      return  HAL_ERROR;
    }

    /* Process Locked */
    __HAL_LOCK(huart);

    huart->ErrorCode = HAL_UART_ERROR_NONE;
    huart->RxState = HAL_UART_STATE_BUSY_RX;

    /* Init tickstart for timeout managment */
    tickstart = HAL_GetTick();

    huart->RxXferSize = Size;
    huart->RxXferCount = Size;

    /* Check the remain data to be received */
    while (huart->RxXferCount > 0U)
    {
      huart->RxXferCount--;
      if (huart->Init.WordLength == UART_WORDLENGTH_9B)
      {
        if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
        {
          return HAL_TIMEOUT;
        }
        tmp = (uint16_t *) pData;
        if (huart->Init.Parity == UART_PARITY_NONE)
        {
          *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF);
          pData += 2U;
        }
        else
        {
          *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x00FF);
          pData += 1U;
        }

      }
      else
      {
        if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
        {
          return HAL_TIMEOUT;
        }
        if (huart->Init.Parity == UART_PARITY_NONE)
        {
          *pData++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
        }
        else
        {
          *pData++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F);
        }

      }
    }

    /* At end of Rx process, restore huart->RxState to Ready */
    huart->RxState = HAL_UART_STATE_READY;

    /* Process Unlocked */
    __HAL_UNLOCK(huart);

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

这个函数和UART_Receive_IT这个函数内容大同小异,只是少了回调函数而已,可以参考上面的函数。

3、 HAL_UART_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;
    }

    /* Process Locked */
    __HAL_LOCK(huart);

    huart->pRxBuffPtr = pData;
    huart->RxXferSize = Size;
    huart->RxXferCount = Size;

    huart->ErrorCode = HAL_UART_ERROR_NONE;
    huart->RxState = HAL_UART_STATE_BUSY_RX;

    /* Process Unlocked */
    __HAL_UNLOCK(huart);

    /* 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);

    /* Enable the UART Data Register not empty Interrupt */
    __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

记住!这个函数不是用来接收数据的!这个函数不是用来接收数据的!这个函数不是用来接收数据的!他是用来打开中断,配置串口中断的!不是真正的接收数据的中断函数,很容易把它和其他两个函数混淆。看了上面两个函数的解释,这个函数的内容应该不难理解,这也就是,我们要手动打开串口中断,就要在main函数里面首先写下它,否则无法进入串口中断(亲测如此),其次还要在回调函数里面添加这个函数(因为之前就说过一旦进入回调函数,串口中断就会关闭),为了下一次接收数据考虑,需要这么做。

PS:很多人一直觉得用户代码可以在中断函数里面写,但是我们一般不写在中断函数中,而是在回调函数里面写。如果写在中断函数中,和标准库没什么两样。而HAL库将函数都已封装完整,回调函数完好地提供一个API接口,供用户使用。回调函数和普通函数还是有一定区别的,读者可以查阅其他资料,在此不再赘述。

想要更加细致地了解这三个函数,推荐一下这篇文章:关于HAL库串口中断接收哪些路子 第二弹

希望看完本文能对串口接收函数有了更加深入的理解,每一个函数的内容都值得推敲一下

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

做梦咸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值