STM32
直播中

LL-LING宁

8年用户 1309经验值
擅长:电源/新能源
私信 关注
[问答]

STM32CubeIDE UART01中断收发的知识点汇总,错过绝对后悔

STM32CubeIDE UART01中断收发的知识点汇总,错过绝对后悔

回帖(1)

何珊

2021-12-8 09:42:13
一.UART中断概述


















如figure 302所示,在stm32中UART有多个中断,下面来逐一说明这些中断及其应用。
一.发送中断







1.1TXE:发送数据寄存器为空状态标志位


当TDR寄存器的内容已转移到移位寄存器中时,此位由硬件置1。 如果USART_CR1寄存器中的TXEIE位= 1,则会产生一个中断。 通过写USART_DR寄存器将其清除。


0:数据未传输到移位寄存器


1:数据传输到移位寄存器)


注:在单缓冲区传输期间使用此位。TXE位总是通过写数据寄存器来清除。TXE位由硬件置1,它指示:


•数据已从TDR移至移位寄存器,并且数据传输已开始。


•TDR寄存器为空。


•可以将下一个数据写入USART_DR寄存器,而不会覆盖前一个数据。


如果TXEIE位置1,此标志将产生中断。


1.2.TC 传输完成状态标志位


传输完成中断,如果包含数据的帧的传输完成并且TXE被置位,则该位置1。 如果USART_CR1寄存器中的TCIE = 1,则产生一个中断。 通过软件序列(从USART_SR寄存器读取,然后写入USART_DR寄存器)将其清除。 TC位也可以通过向其写入“ 0”来清除。 建议仅对多缓冲区通信使用此清除序列。


0:传输未完成。


1:传输完成。


1.3.CTS


<待整理>


1.4.中断发送


通过STM32CubeIDE创建工程后,设置好UART及其它相关的配置后,在UART的中断发送过程中,HAL库的相互调用关系如下:HAL_UART_Transmit_IT ---》 HAL_UART_IRQHandler  ---》 UART_Transmit_IT  ---》 UART_EndTransmit_IT。


HAL_UART_Transmit_IT :


此函数会将要发送的数据赋值给UART结构体。然后使能UART_IT_TXE中断,进入中断处理函数。


HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
/*
*此函数会将要发送的数据赋值给UART结构体。然后使能UART_IT_TXE中断,进入中断处理函数;从发送时序图Fig 282可以看到
*在使能UART_IT_TXE中断后会马上触发一次UART_IT_TXE中断中断。TXE flag在初始状态就是保持在高电平。
*
**/
  /* Check that a Tx process is not already ongoing */
  if (huart->gState == HAL_UART_STATE_READY)
  {
    if ((pData == NULL) || (Size == 0U))
    {
      return HAL_ERROR;
    }

    /* Process Locked */
    __HAL_LOCK(huart);

    huart->pTxBuffPtr = pData;
    huart->TxXferSize = Size;
    huart->TxXferCount = Size;

    huart->ErrorCode = HAL_UART_ERROR_NONE;
    huart->gState = HAL_UART_STATE_BUSY_TX;

    /* Process Unlocked */
    __HAL_UNLOCK(huart);

    /* Enable the UART Transmit data register empty Interrupt */
    __HAL_UART_ENABLE_IT(huart, UART_IT_TXE);

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}
HAL_UART_IRQHandler :


进入UART中断入口函数后,会调用中断处理函数HAL_UART_IRQHandler,在中断处理函数HAL_UART_IRQHandler中会根据中断标志位(TC TXE)不同调用不同的函数UART_Transmit_IT 和UART_EndTransmit_IT。其中UART_Transmit_IT在huart->gState == HAL_UART_STATE_BUSY_TX控制下循环将要发送的数据一帧一帧的写入串口的发送数据寄存器,并关闭TXE中断,使能TC中断。UART_EndTransmit_IT会关闭TC中断并调用用户自己的中断处理函数HAL_UART_TxCpltCallback。


void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
  uint32_t isrflags   = READ_REG(huart->Instance->SR);
  uint32_t cr1its     = READ_REG(huart->Instance->CR1);
  uint32_t cr3its     = READ_REG(huart->Instance->CR3);
  uint32_t errorflags = 0x00U;
  uint32_t dmarequest = 0x00U;

  /* If no error occurs */
  errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
  if (errorflags == RESET)
  {
    /* UART in mode Receiver -------------------------------------------------*/
    if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
    {
      UART_Receive_IT(huart);
      return;
    }
  }

  /* If some errors occur */
  if ((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))
  {
    //error flag
    //此处代码暂时不关注已删除
  } /* End if some error occurs */

  /* UART in mode Transmitter ------------------------------------------------*/
  if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
  {
        //中断发送,每次发生TXE中断,就调用一次UART_Transmit_IT。
    UART_Transmit_IT(huart);
    return;
  }

  /* UART in mode Transmitter end --------------------------------------------*/
  if (((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
  {
        //如果是发送TC中断,则调用UART_EndTransmit_IT。
    UART_EndTransmit_IT(huart);
    return;
  }
UART_Transmit_IT :


huart->gState == HAL_UART_STATE_BUSY_TX软件定义的传输完成标志变量,如果特定的帧数据发送完成,会触发TC中断再次调用HAL_UART_IRQHandler,并在HAL_UART_IRQHandler中调用TC中断处理函数UART_EndTransmit_IT中复位HAL_UART_STATE_BUSY_TX。


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

  /* Check that a Tx process is ongoing */
  if (huart->gState == HAL_UART_STATE_BUSY_TX)
  {
    if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
    {
    //如果数据位是9位,则需要发送一个16位数
      tmp = (uint16_t *) huart->pTxBuffPtr;
      huart->Instance->DR = (uint16_t)(*tmp & (uint16_t)0x01FF);
      huart->pTxBuffPtr += 2U;
    }
    else
    {
      //如果数据位是8位,则只需要发送一个8位数
      huart->Instance->DR = (uint8_t)(*huart->pTxBuffPtr++ & (uint8_t)0x00FF);
    }

    if (--huart->TxXferCount == 0U)
    {
      /* Disable the UART Transmit Complete Interrupt */
      __HAL_UART_DISABLE_IT(huart, UART_IT_TXE);

      /* Enable the UART Transmit Complete Interrupt */
      __HAL_UART_ENABLE_IT(huart, UART_IT_TC);
    }
    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}
UART_EndTransmit_IT :


执行到这里标志串口发送完成,在UART_EndTransmit_IT中关闭TC中断,复位HAL_UART_STATE_BUSY_TX,然后调用发送完成的用户中断处理程序HAL_UART_TxCpltCallback。


static HAL_StatusTypeDef UART_EndTransmit_IT(UART_HandleTypeDef *huart)
{
  /* Disable the UART Transmit Complete Interrupt */
  __HAL_UART_DISABLE_IT(huart, UART_IT_TC);

  /* Tx process is ended, restore huart->gState to Ready */
  huart->gState = HAL_UART_STATE_READY;

#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
  /*Call registered Tx complete callback*/
  huart->TxCpltCallback(huart);
#else
  /*Call legacy weak Tx complete callback*/
  HAL_UART_TxCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */

  return HAL_OK;
}
二.接收中断





















https://blog.csdn.net/Hola_ya/article/details/81560204?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&dist_request_id=5e1deb95-ae63-46d4-8bf3-744ae8dc909d&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.control

https://blog.csdn.net/qq_29413829/article/details/63262321?utm_medium=distribute.pc_relevant_download.none-task-blog-baidujs-1.nonecase&depth_1-utm_source=distribute.pc_relevant_download.none-task-blog-baidujs-1.nonecase
2.1 IDLE:IDLE line detected
当检测到空闲线时,该位置1。 如果USART_CR1寄存器中的IDLEIE = 1,则产生一个中断。 它由软件序列清除(先读取USART_SR寄存器,再读取USART_DR寄存器)。
0:未检测到空闲线
1:检测到空闲线
注意:在RXNE位本身被置位之前(即出现新的空闲线),IDLE位将不会再次置位。
2.2 ORE:Overrun error(溢出错误)
当RXNE = 1时,当移位寄存器中当前接收的字准备好被传送到RDR寄存器中时,该位由硬件置1。 如果USART_CR1寄存器中的RXNEIE = 1,则产生一个中断。 它由软件序列清除(先读取USART_SR寄存器,再读取USART_DR寄存器)。
0:无溢出错误
1:检测到超限错误
注:置位时,RDR寄存器的内容不会丢失,但移位寄存器将被覆盖。 如果EIE位置1,则在进行多缓冲区通信时,在ORE标志上会产生一个中断。
2.3 RXNE : Read data register not empty
当RDR移位寄存器的内容已传输到USART_DR寄存器时,此位由硬件置1。 如果USART_CR1寄存器中的RXNEIE = 1,则产生一个中断。通过读取USART_DR寄存器将其清除。 也可以通过向其写入零来清除RXNE标志。 建议仅对多缓冲区通信使用此清除序列。
0:未收到数据
1:已准备好读取已接收的数据。

2.4 PE :Parity error
当在接收器模式下发生奇偶校验错误时,此位由硬件设置。 它由软件序列清除(先读取状态寄存器,然后读取USART_DR数据寄存器)。 在清除PE位之前,软件必须等待RXNE标志置1。
如果USART_CR1寄存器中的PEIE = 1,则会产生一个中断。
0:无奇偶校验错误
1:奇偶校验错误
2.5 LBD : LIN break detection flag
当检测到LIN中断时,由硬件将该位置1。 通过软件清除(将其写入0)。 如果USART_CR2寄存器中的LBDIE = 1,则会产生一个中断。
0:未检测到LIN Break
1:检测到LIN中断
注意:如果LBDIE = 1,则当LBD = 1时会产生一个中断。

2.6 NE/ORE/FE
NE: Noise error flag
当在接收到的帧上检测到噪声时,该位由硬件设置。 它由软件序列清除(先读取USART_SR寄存器,再读取USART_DR寄存器)。
0:未检测到噪音
1:检测到噪音
注意:如果EIE位置1,则在多缓冲区通信的情况下,NE标志上会生成与本身产生中断中断的RXNE位同时出现的该位,不会产生中断。
ORE: Overrun error
当RXNE = 1时,当移位寄存器中当前接收的字准备好被传送到RDR寄存器中时,该位由硬件置1。 如果USART_CR1寄存器中的RXNEIE = 1,则产生一个中断。 它由软件序列清除(先读取USART_SR寄存器,再读取USART_DR寄存器)。
0:无溢出错误
1:检测到超限错误
注:置位时,RDR寄存器的内容不会丢失,但移位寄存器将被覆盖。 如果EIE位置1,则在进行多缓冲区通信时,在ORE标志上会产生一个中断。
FE: Framing error
当检测到去同步,过多的噪声或中断字符时,该位将由硬件置位。 它由软件序列清除(先读取USART_SR寄存器,再读取USART_DR寄存器)。
0:未检测到构图错误
1:检测到帧错误或中断字符
注:该位不会产生中断,因为它与本身会产生中断的RXNE位同时出现。 如果当前正在传输的字同时引起帧错误和溢出错误,则将传输该字,并且仅将ORE位置1。 如果EIE位置1,则在多缓冲区通信的情况下,FE标志上会产生一个中断。
EIE: Error interrupt enable
如果发生多缓冲器通信(DMAR = 1时),则在发生帧错误,溢出错误或噪声错误(USART_SR寄存器中的FE = 1或ORE = 1或NE = 1)时,需要错误中断允许位来使能中断生成。 USART_CR3寄存器)。
0:禁止中断
1:每当USART_CR3寄存器中的DMAR = 1和USART_SR寄存器中的FE = 1或ORE = 1或NE = 1时,都会产生一个中断。
DMAR :DMA enable receiver
该位由软件置位/复位
1:启用DMA模式进行接收
0:禁用DMA模式进行接收
该位不适用于UART5。

HAL_UART_Receive_IT : Enable the UART Parity Error ,Frame error, noise error, overrun error,UART Data Register not empty Interrupt.


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;
  }
}
HAL_UART_IRQHandler :



void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
  uint32_t isrflags   = READ_REG(huart->Instance->SR);
  uint32_t cr1its     = READ_REG(huart->Instance->CR1);
  uint32_t cr3its     = READ_REG(huart->Instance->CR3);
  uint32_t errorflags = 0x00U;
  uint32_t dmarequest = 0x00U;

  /* If no error occurs */
  errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
  if (errorflags == RESET)
  {
    /* UART in mode Receiver -------------------------------------------------*/
    if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
    {
      UART_Receive_IT(huart);
      return;
    }
  }

  /* If some errors occur */

  /* UART in mode Transmitter ------------------------------------------------*/
  /* UART in mode Transmitter end --------------------------------------------*/

}


UART_Receive_IT :


static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)
{
  uint8_t  *pdata8bits;
  uint16_t *pdata16bits;

  /* Check that a Rx process is ongoing */
  if (huart->RxState == HAL_UART_STATE_BUSY_RX)
  {
    if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
    {
      pdata8bits  = NULL;
      pdata16bits = (uint16_t *) huart->pRxBuffPtr;
      *pdata16bits = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF);
      huart->pRxBuffPtr += 2U;
    }
    else
    {
      pdata8bits = (uint8_t *) huart->pRxBuffPtr;
      pdata16bits  = NULL;

      if ((huart->Init.WordLength == UART_WORDLENGTH_9B) || ((huart->Init.WordLength == UART_WORDLENGTH_8B) && (huart->Init.Parity == UART_PARITY_NONE)))
      {
        *pdata8bits = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
      }
      else
      {
        *pdata8bits = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F);
      }
      huart->pRxBuffPtr += 1U;
    }

    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;
  }
}




举报

更多回帖

发帖
×
20
完善资料,
赚取积分