STM32CubeMX-HAL library-UART serial port receiving interrupt callback function code analysis

        The call of the HAL library function in CubeMx is different from the call of the library function. When learning CubeMx serial communication, I don’t understand how the callback function in the HAL library is called, so I check the definition of each, and refer to the blog written by others. Understand the difference between the HAL library interrupt call and the library function. Writing this blog is first to deepen my understanding, and second, I hope it will be helpful to friends who do not understand the callback function calling mechanism in the HAL library.

        Engineering code reference: 【STM32】-CubeMX-HAL library-UART-serial communication-STM32F103C8T6-transmitting test

        In the library function, when the UART serial port is interrupted, we directly write the business code in void USART1_IRQHandler(void), as shown in the figure below:

void USART1_IRQHandler(void)                	//串口1中断服务程序
	{
	u8 Res;

	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
		{
		Res =USART_ReceiveData(USART1);	//读取接收到的数据
		
		if((USART_RX_STA&0x8000)==0)//接收未完成
			{
			if(USART_RX_STA&0x4000)//接收到了0x0d
				{
				if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
				else USART_RX_STA|=0x8000;	//接收完成了 
				}
			else //还没收到0X0D
				{	
				if(Res==0x0d)USART_RX_STA|=0x4000;
				else
					{
					USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
					USART_RX_STA++;
					if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收	  
					}		 
				}
			}   		 
     } 

} 

        For the code generated by CubeMX, the USART1_IRQHandler(void) function uses a callback mechanism to improve interrupt efficiency. (The business code can be processed after the interrupt is closed, so that the interrupt processing will not take too much time and affect the execution efficiency of the program)

        Only HAL_UART_IRQHandler(&huart1) is called in the USART1_IRQHandler(void) function (can be found in STM32f1xx_it.c), the parameter is the handle huart1 of uart1, the handle can be understood as accessing various registers and data types of uart1 through huart1, if you don’t understand , you can see the definition of the UART_HandleTypeDef structure.

        UART_Receive_IT(huart); is called in the HAL_UART_IRQHandler(UART_HandleTypeDef *huart) function; (the callback function is called in this function) see the note to understand the function of this function

static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)
{
    //用这个指针指向我们用于接收数据的变量或数组,在收发测试例程中定义的是char Res
  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;//指向Res,相当于pdata16bits=&Res
        //具体原因参考HAL_UART_Receive_IT(&huart1, &Res, 1);
      *pdata16bits = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF);
      huart->pRxBuffPtr += 2U;
    }
    else
    {
      pdata8bits = (uint8_t *) huart->pRxBuffPtr;//指向Res,相当于pdata8bits=&Res
      pdata16bits  = NULL;

      if ((huart->Init.WordLength == UART_WORDLENGTH_9B) || ((huart->Init.WordLength == UART_WORDLENGTH_8B) && (huart->Init.Parity == UART_PARITY_NONE)))
      {
        //指针操作 相当于Res= (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
        *pdata8bits = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
      }
      else
      {
        //指针操作 相当于Res= (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
        *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;

      /* Check current reception Mode :
         If Reception till IDLE event has been selected : */
      if (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
      {
        /* Set reception type to Standard */
        huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;

        /* Disable IDLE interrupt */
        CLEAR_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);

        /* Check if IDLE flag is set */
        if (__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE))
        {
          /* Clear IDLE flag in ISR */
          __HAL_UART_CLEAR_IDLEFLAG(huart);
        }

#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
        /*Call registered Rx Event callback*/
        huart->RxEventCallback(huart, huart->RxXferSize);
#else
        /*Call legacy weak Rx Event callback*/
        HAL_UARTEx_RxEventCallback(huart, huart->RxXferSize);
#endif
      }
      else
      {
       /* Standard reception API called */
#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;
  }
}

Why are the operations on the left and right sides of the table equivalent?

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

The answer can be found from the UART_Start_Receive_IT function

(UART_Start_Receive_IT is called by HAL_UART_Receive_IT in the main function)

//函数参数相当于(&huart1, &Res, 1)
HAL_StatusTypeDef UART_Start_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
  //函数参数相当于(&huart1, &Res, 1)
  huart->pRxBuffPtr = pData;//pData==&Res 
  //在UART_Receive_IT函数中 pdata8bits = (uint8_t *) huart->pRxBuffPtr;
  //pdata8bits=&Res,其他都是同理,如果不理解,需要回顾一下指针操作。
  huart->RxXferSize = Size;//Size==1
  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;
}

Callback:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)//自定义回调函数 在UART_Receive_IT()中调用
{
	//判断是哪个串口触发的中断  huart1.Instance = USART1;定义在MX_USART1_UART_Init中
	if(huart==&huart1)//huart ->Instance == USART1两种判断条件等价
	{
		if((UART1_RX_STA & 0x8000)==0)//接收未完成&位运算符 &&短路与判断
		{
			if(UART1_RX_STA & 0x4000)//接收到 \r
			{
				if(Res==0x0a)//下一个必须是接收 \n
					UART1_RX_STA|=0x8000;
				else
					UART1_RX_STA=0;
			}
			else //未接收到\r
			{
				if(Res==0x0d)//Receive \r
				{
					UART1_RX_STA|=0x4000;
				}
				else
				{
					UART1_RX_Buffer[UART1_RX_STA&0X3FFF]=Res;
					UART1_RX_STA++;
					if(UART1_RX_STA>UART1_REC_LEN-1) UART1_RX_STA=0;//如果接收数据大于200Byte 重新开始接收
				}
			}
		}
		HAL_UART_Receive_IT(&huart1, &Res, 1);//完成一次接受,再此开启中断
	}
}

        If we do not define the callback function ourselves, the system will call the built-in callback function, and the function type is __weak, which means weak definition

        If the user defines the function himself, call the user-defined callback function first

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

        If it is helpful to you, please like it and leave, Respect!

Guess you like

Origin blog.csdn.net/weixin_44322104/article/details/125210812