cubemx_usart_r&t_it分析

我们再cubemx中配置USART的时候选择开启USART1全局中断,对应到代码当中,只是开启了中断通道,配置了此中断通道的两个优先级。这一步的目的是当某个中断源对应的中断事件发生时,我们可以通过此通道向内核发出请求,即满足条件的时候可以进入中断服务函数。

然而一个中断通道,对应着的是一个外设,而一个外设有好多中断源。所以当我们使用发送和接受中断时,必须开启它们的中断源。而且发送中断搭配了发送完成中断。

我们先贴出使用的中断标志位和中断使能位



HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

上面是使能接受中断的函数,我们把代码主要的部分拿出来分析。

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


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

主要是把传入的地址赋值给句柄的接受缓冲区的指针。把接受的字节数赋值给句柄的计数和大小。然后是开启了一系列错误中断,最后开启了接受中断,即RXNEIE置1。

当有数据从RX引脚进来后,根据采样把数据接受到RDR移位寄存器,硬件把数据转移到DR寄存器后,硬件把RXNE置1,前面RXNEIE置1,所以产生接受中,进入中断服务函数。我们把几个需要分析的函数列到下面。

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 */
}

void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
  uint32_t tmp_flag = 0, tmp_it_source = 0;


  tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_PE);
  tmp_it_source = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_PE);  
  /* UART parity error interrupt occurred ------------------------------------*/
  if((tmp_flag != RESET) && (tmp_it_source != RESET))
  { 
    huart->ErrorCode |= HAL_UART_ERROR_PE;
  }
  
  tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_FE);
  tmp_it_source = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);
  /* UART frame error interrupt occurred -------------------------------------*/
  if((tmp_flag != RESET) && (tmp_it_source != RESET))
  { 
    huart->ErrorCode |= HAL_UART_ERROR_FE;
  }
  
  tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_NE);
  /* UART noise error interrupt occurred -------------------------------------*/
  if((tmp_flag != RESET) && (tmp_it_source != RESET))
  { 
    huart->ErrorCode |= HAL_UART_ERROR_NE;
  }
  
  tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_ORE);
  /* UART Over-Run interrupt occurred ----------------------------------------*/
  if((tmp_flag != RESET) && (tmp_it_source != RESET))
  { 
    huart->ErrorCode |= HAL_UART_ERROR_ORE;
  }
  
  tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE);
  tmp_it_source = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_RXNE);
  /* UART in mode Receiver ---------------------------------------------------*/
  if((tmp_flag != RESET) && (tmp_it_source != RESET))
  { 
    UART_Receive_IT(huart);
  }
  
  tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_TXE);
  tmp_it_source = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_TXE);
  /* UART in mode Transmitter ------------------------------------------------*/
  if((tmp_flag != RESET) && (tmp_it_source != RESET))
  {
    UART_Transmit_IT(huart);
  }


  tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_TC);
  tmp_it_source = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_TC);
  /* UART in mode Transmitter end --------------------------------------------*/
  if((tmp_flag != RESET) && (tmp_it_source != RESET))
  {
    UART_EndTransmit_IT(huart);
  }  


  if(huart->ErrorCode != HAL_UART_ERROR_NONE)
  {
    /* Clear all the error flag at once */
    __HAL_UART_CLEAR_PEFLAG(huart);
    
    /* Set the UART state ready to be able to start again the process */
    huart->State = HAL_UART_STATE_READY;
    
    HAL_UART_ErrorCallback(huart);
  }  
}

产生接受中断后,进入中断服务函数,中断服务函数调用了一个HAL自己编写的中断处理函数,这个函数根据判断发生的中断类型,进行对应的操作。这里我们的中断是接受中断,所以判断后满足接受中断的条件后调用UART_Receive_IT(huart),下面我们把被调函数的关键内容列出。

*huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);


    if(--huart->RxXferCount == 0)
    {
      __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);


      /* Check if a transmit process is ongoing or not */
      if(huart->State == HAL_UART_STATE_BUSY_TX_RX) 
      {
        huart->State = HAL_UART_STATE_BUSY_TX;
      }
      else
      {
        /* 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);


        huart->State = HAL_UART_STATE_READY;
      }
      HAL_UART_RxCpltCallback(huart);


      return HAL_OK;
    }

此函数首先是从DR寄存器读出一字节内容,并且将这字节内容储存到我们之前传入的地址(每次地址会自增),根据寄存器RXNE我们得知,读取DR寄存器,此时RXNE位变成0。清除了接受中断标志位。接下来判断计数自减是否为0,不等于0重复上述过程,等于0表示需要接受特点的长度字节接受储存完毕,此时我们失能之前使能的中断。然后调用一个接受中断回调函数,这个中断回调函数需要我们再用户文件中重定向,目的是接受完指定操作去执行某些动作。

理解玩接受中断,发送中断就好理解多了,

HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)


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

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

这和上面接受中断是一样的,赋值一些变量后使能发送中断。我们根据手册寄存器得知,复位后,TXE,TC缺省值为1。前面使能了发送中断,所以进入中断函数,之后调用HAL中断处理,判断类型后执行下面的函数

static HAL_StatusTypeDef UART_Transmit_IT(UART_HandleTypeDef *huart)

我们把这个函数的关键内容列出来分析。

huart->Instance->DR = (uint8_t)(*huart->pTxBuffPtr++ & (uint8_t)0x00FF);

    if(--huart->TxXferCount == 0)
    {
      /* 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);
    }

首先对DR寄存器有一个写操作,把数据从之前传入的地址取出写入DR寄存器。(指定的地址每次自增),根据寄存器可得对DR写操作,TXE置0,然后计数自减判断,不等于0,等待硬件把数据从DR寄存器专一到移位寄存器发出,此时TXE也被硬件置1触发了此次中断,重复几次,当计数自减为0后代表指定发送长度的数据发送完毕,此时失能发送中断,使能发送完成中断,由于在发送字节时,当数据转移到移位寄存器后TC置1,加上使能发送完成中断,此时触发中断,。。。根据判断执行static HAL_StatusTypeDef UART_EndTransmit_IT(UART_HandleTypeDef *huart),我们还是只看关键部分。

  __HAL_UART_DISABLE_IT(huart, UART_IT_TC);
  
  HAL_UART_TxCpltCallback(huart);

触发发送完成中断进入此函数后,失能发送完成中断,然后调用发送中断回调函数,这个函数也是需要用户重定向。目的也是执行特点的动作。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值