[其他ST产品] 什么是HAL(Hardware Abstraction Layer)?

[复制链接]
2176|54
 楼主| 雨果喝水 发表于 2023-8-27 17:27 | 显示全部楼层
回调函数

回调函数
回调函数是一个通过指针调用的函数。如果把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就将该函数称之为回调函数。
回调函数不是由该函数的实现方法直接调用的,而是在特定的事件或条件发生时由另外一方调用的,用于对该事件或条件进行的响应。
 楼主| 雨果喝水 发表于 2023-8-27 17:27 | 显示全部楼层
这里我们以串口中断为例介绍HAL库对中断的封装(关于中断的详细介绍查看:STM32 NVIC 调试心得)
  1. 第一个重要函数,存放在stm32fxxx.it.c文件中
  2. void USART2_IRQHandler(void)
  3. {
  4.   /* USER CODE BEGIN USART2_IRQn 0 */

  5.   /* USER CODE END USART2_IRQn 0 */
  6.   HAL_UART_IRQHandler(&huart2);
  7.   /* USER CODE BEGIN USART2_IRQn 1 */


  8.   /* USER CODE END USART2_IRQn 1 */
  9. }
 楼主| 雨果喝水 发表于 2023-8-27 17:28 | 显示全部楼层
用过中断的同学都知道这个函数,但大部分都将注意力集中在HAL_UART_IRQHandler(&huart2);这个HAL库的中断接口函数上,于是有了第一个问题——>是谁调用了USART2_IRQHandler()这个函数呢?这就需要了解MCU对中断的响应机制(详细说明见STM32 NVIC 调试心得),当中断发生时,微控制器暂停当前运行的程序,由内部的硬件机制跳转执行USART2_IRQHandler(),下面我们再看HAL_UART_IRQHandler(&huart2);中的相关代码
 楼主| 雨果喝水 发表于 2023-8-27 17:28 | 显示全部楼层
  1. void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
  2. {
  3.   uint32_t isrflags   = READ_REG(huart->Instance->SR);
  4.   uint32_t cr1its     = READ_REG(huart->Instance->CR1);
  5.   uint32_t cr3its     = READ_REG(huart->Instance->CR3);
  6.   uint32_t errorflags = 0x00U;
  7.   uint32_t dmarequest = 0x00U;

  8.   /* If no error occurs */
  9.   errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
  10.   if (errorflags == RESET)
  11.   {
  12.     /* UART in mode Receiver -------------------------------------------------*/
  13.     if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
  14.     {
  15.       UART_Receive_IT(huart);
  16.       return;
  17.     }
  18.   }

  19.   /* If some errors occur */
  20.   if ((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))
  21.   {
  22.     /* UART parity error interrupt occurred ----------------------------------*/
  23.     if (((isrflags & USART_SR_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET))
  24.     {
  25.       huart->ErrorCode |= HAL_UART_ERROR_PE;
  26.     }

  27.     /* UART noise error interrupt occurred -----------------------------------*/
  28.     if (((isrflags & USART_SR_NE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
  29.     {
  30.       huart->ErrorCode |= HAL_UART_ERROR_NE;
  31.     }

  32.     /* UART frame error interrupt occurred -----------------------------------*/
  33.     if (((isrflags & USART_SR_FE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
  34.     {
  35.       huart->ErrorCode |= HAL_UART_ERROR_FE;
  36.     }

  37.     /* UART Over-Run interrupt occurred --------------------------------------*/
  38.     if (((isrflags & USART_SR_ORE) != RESET) && (((cr1its & USART_CR1_RXNEIE) != RESET) || ((cr3its & USART_CR3_EIE) != RESET)))
  39.     {
  40.       huart->ErrorCode |= HAL_UART_ERROR_ORE;
  41.     }

  42.     /* Call UART Error Call back function if need be --------------------------*/
  43.     if (huart->ErrorCode != HAL_UART_ERROR_NONE)
  44.     {
  45.       /* UART in mode Receiver -----------------------------------------------*/
  46.       if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
  47.       {
  48.         UART_Receive_IT(huart);
  49.       }

  50.       /* If Overrun error occurs, or if any error occurs in DMA mode reception,
  51.          consider error as blocking */
  52.       dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR);
  53.       if (((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) || dmarequest)
  54.       {
  55.         /* Blocking error : transfer is aborted
  56.            Set the UART state ready to be able to start again the process,
  57.            Disable Rx Interrupts, and disable Rx DMA request, if ongoing */
  58.         UART_EndRxTransfer(huart);

  59.         /* Disable the UART DMA Rx request if enabled */
  60.         if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
  61.         {
  62.           CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);

  63.           /* Abort the UART DMA Rx channel */
  64.           if (huart->hdmarx != NULL)
  65.           {
  66.             /* Set the UART DMA Abort callback :
  67.                will lead to call HAL_UART_ErrorCallback() at end of DMA abort procedure */
  68.             huart->hdmarx->XferAbortCallback = UART_DMAAbortOnError;
  69.             if (HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK)
  70.             {
  71.               /* Call Directly XferAbortCallback function in case of error */
  72.               huart->hdmarx->XferAbortCallback(huart->hdmarx);
  73.             }
  74.           }
  75.           else
  76.           {
  77.             /* Call user error callback */
  78. #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
  79.             /*Call registered error callback*/
  80.             huart->ErrorCallback(huart);
  81. #else
  82.             /*Call legacy weak error callback*/
  83.             HAL_UART_ErrorCallback(huart);
  84. #endif /* USE_HAL_UART_REGISTER_CALLBACKS */
  85.           }
  86.         }
  87.         else
  88.         {
  89.           /* Call user error callback */
  90. #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
  91.           /*Call registered error callback*/
  92.           huart->ErrorCallback(huart);
  93. #else
  94.           /*Call legacy weak error callback*/
  95.           HAL_UART_ErrorCallback(huart);
  96. #endif /* USE_HAL_UART_REGISTER_CALLBACKS */
  97.         }
  98.       }
  99.       else
  100.       {
  101.         /* Non Blocking error : transfer could go on.
  102.            Error is notified to user through user error callback */
  103. #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
  104.         /*Call registered error callback*/
  105.         huart->ErrorCallback(huart);
  106. #else
  107.         /*Call legacy weak error callback*/
  108.         HAL_UART_ErrorCallback(huart);
  109. #endif /* USE_HAL_UART_REGISTER_CALLBACKS */

  110.         huart->ErrorCode = HAL_UART_ERROR_NONE;
  111.       }
  112.     }
  113.     return;
  114.   } /* End if some error occurs */

  115.   /* Check current reception Mode :
  116.      If Reception till IDLE event has been selected : */
  117.   if (  (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
  118.       &&((isrflags & USART_SR_IDLE) != 0U)
  119.       &&((cr1its & USART_SR_IDLE) != 0U))
  120.   {
  121.     __HAL_UART_CLEAR_IDLEFLAG(huart);

  122.     /* Check if DMA mode is enabled in UART */
  123.     if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
  124.     {
  125.       /* DMA mode enabled */
  126.       /* Check received length : If all expected data are received, do nothing,
  127.          (DMA cplt callback will be called).
  128.          Otherwise, if at least one data has already been received, IDLE event is to be notified to user */
  129.       uint16_t nb_remaining_rx_data = (uint16_t) __HAL_DMA_GET_COUNTER(huart->hdmarx);
  130.       if (  (nb_remaining_rx_data > 0U)
  131.           &&(nb_remaining_rx_data < huart->RxXferSize))
  132.       {
  133.         /* Reception is not complete */
  134.         huart->RxXferCount = nb_remaining_rx_data;

  135.         /* In Normal mode, end DMA xfer and HAL UART Rx process*/
  136.         if (huart->hdmarx->Init.Mode != DMA_CIRCULAR)
  137.         {
  138.           /* Disable PE and ERR (Frame error, noise error, overrun error) interrupts */
  139.           CLEAR_BIT(huart->Instance->CR1, USART_CR1_PEIE);
  140.           CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);

  141.           /* Disable the DMA transfer for the receiver request by resetting the DMAR bit
  142.              in the UART CR3 register */
  143.           CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);

  144.           /* At end of Rx process, restore huart->RxState to Ready */
  145.           huart->RxState = HAL_UART_STATE_READY;
  146.           huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;

  147.           CLEAR_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);

  148.           /* Last bytes received, so no need as the abort is immediate */
  149.           (void)HAL_DMA_Abort(huart->hdmarx);
  150.         }
  151. #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
  152.         /*Call registered Rx Event callback*/
  153.         huart->RxEventCallback(huart, (huart->RxXferSize - huart->RxXferCount));
  154. #else
  155.         /*Call legacy weak Rx Event callback*/
  156.         HAL_UARTEx_RxEventCallback(huart, (huart->RxXferSize - huart->RxXferCount));
  157. #endif
  158.       }
  159.       return;
  160.     }
  161.     else
  162.     {
  163.       /* DMA mode not enabled */
  164.       /* Check received length : If all expected data are received, do nothing.
  165.          Otherwise, if at least one data has already been received, IDLE event is to be notified to user */
  166.       uint16_t nb_rx_data = huart->RxXferSize - huart->RxXferCount;
  167.       if (  (huart->RxXferCount > 0U)
  168.           &&(nb_rx_data > 0U) )
  169.       {
  170.         /* Disable the UART Parity Error Interrupt and RXNE interrupts */
  171.         CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));

  172.         /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */
  173.         CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);

  174.         /* Rx process is completed, restore huart->RxState to Ready */
  175.         huart->RxState = HAL_UART_STATE_READY;
  176.         huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;

  177.         CLEAR_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);
  178. #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
  179.         /*Call registered Rx complete callback*/
  180.         huart->RxEventCallback(huart, nb_rx_data);
  181. #else
  182.         /*Call legacy weak Rx Event callback*/
  183.         HAL_UARTEx_RxEventCallback(huart, nb_rx_data);
  184. #endif
  185.       }
  186.       return;
  187.     }
  188.   }

  189.   /* UART in mode Transmitter ------------------------------------------------*/
  190.   if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
  191.   {
  192.     UART_Transmit_IT(huart);
  193.     return;
  194.   }

  195.   /* UART in mode Transmitter end --------------------------------------------*/
  196.   if (((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
  197.   {
  198.     UART_EndTransmit_IT(huart);
  199.     return;
  200.   }
  201. }
 楼主| 雨果喝水 发表于 2023-8-27 17:28 | 显示全部楼层
仔细阅读这部分代码,这部分代码其实就是接收中断、发送中断、异常中断、DMA中断等的再次封装,其实是中断类型判定与跳转执行回调函数的过程,在看HAL库代码时一定要注意ST官方对HAL库函数的解释与说明,以下ST公司是对HAL_UART_IRQHandler()的解释与说明
 楼主| 雨果喝水 发表于 2023-8-27 17:28 | 显示全部楼层
  1. [url=home.php?mod=space&uid=247401]@brief[/url]  This function handles UART interrupt request.
  2. @param  huart  Pointer to a UART_HandleTypeDef structure that contains
  3.          the configuration information for the specified UART module.
  4. @retval None

  5. @简要说明:该函数处理串口中断请求
  6. @参数:    指向UART\U HandleTypeDef结构的param huart指针,该结构包含指定UART模块的配置信息。
  7. @返回值:  无返回值
 楼主| 雨果喝水 发表于 2023-8-27 17:29 | 显示全部楼层
仔细阅读完代码后,我们不难发现HAL_UART_IRQHandler()中还调用了 HAL_UARTEx_RxEventCallback(huart, nb_rx_data); HAL_UART_ErrorCallback(huart)等回调函数,在keil中右键点击go to Defination,我们发现这些函数前均有weak关键字
 楼主| 雨果喝水 发表于 2023-8-27 17:29 | 显示全部楼层
  1. /**
  2.   * @brief  Rx Transfer completed callbacks.
  3.   * @param  huart  Pointer to a UART_HandleTypeDef structure that contains
  4.   *                the configuration information for the specified UART module.
  5.   * @retval None
  6.   */
  7. __weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
  8. {
  9.   /* Prevent unused argument(s) compilation warning */
  10.   UNUSED(huart);
  11.   /* NOTE: This function should not be modified, when the callback is needed,
  12.            the HAL_UART_RxCpltCallback could be implemented in the user file
  13.    */
  14. }

  15. /**
  16.   * @brief  Rx Half Transfer completed callbacks.
  17.   * @param  huart  Pointer to a UART_HandleTypeDef structure that contains
  18.   *                the configuration information for the specified UART module.
  19.   * @retval None
  20.   */
  21. __weak void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart)
  22. {
  23.   /* Prevent unused argument(s) compilation warning */
  24.   UNUSED(huart);
  25.   /* NOTE: This function should not be modified, when the callback is needed,
  26.            the HAL_UART_RxHalfCpltCallback could be implemented in the user file
  27.    */
  28. }
 楼主| 雨果喝水 发表于 2023-8-27 17:29 | 显示全部楼层
什么是weak关键字呢?其实函数名称前面加上__weak 修饰符,我们一般称这个函数为“弱函数”。
加上了__weak 修饰符的函数,用户可以在用户文件中重新定义一个同名函数,最终编译器编译的时候,会选择用户定义的函数,如果用户没有重新定义这个函数,那么编译器就会执行__weak 声明的函数,并且编译器不会报错。所以我们可以在别的地方定义一个相同名字的函数,而不必也尽量不要修改原始函数,于是这便实现了回调,回调给用户,使中断服务程序最终由用户设计,这种方式增强了代码的逻辑性:中断发生后先由内部硬件托管给HAL,HAL调用用户自己编写的回调函数实现功能,增加了文件的嵌套程度
 楼主| 雨果喝水 发表于 2023-8-27 17:29 | 显示全部楼层
(四)HAL库编程方式

HAL库提供了三种编程方式,分别是轮询模式、中断模式、DMA模式。
具体三种方式的编程案例详见STM32 ppp调试经验
Bowclad 发表于 2024-5-12 23:03 | 显示全部楼层
hal库移植起来确实是很方便
Clyde011 发表于 2024-9-16 07:24 | 显示全部楼层

它们之间的间距应至少为0.5mm。
公羊子丹 发表于 2024-9-16 08:17 | 显示全部楼层

会占用PCB的空间,成本也会更高。
万图 发表于 2024-9-16 09:20 | 显示全部楼层

对于信号回路的峰值电压防护电路不应动作,通常在信号回路中,防护电路的动作电压是信号回路的峰值电压的1.3~1.6倍。
Uriah 发表于 2024-9-16 10:23 | 显示全部楼层

它们通常用于分线板或小模块。
帛灿灿 发表于 2024-9-16 12:19 | 显示全部楼层

开关管T交替工作于通/断两种状态,当开关管关断时,脉冲变压器处于“空载”状态,其中储存的磁能将被积累到下一个周期
Bblythe 发表于 2024-9-16 13:22 | 显示全部楼层

在印刷电路板制造中
周半梅 发表于 2024-9-16 15:18 | 显示全部楼层

选择测试方法和测试参数是检测过程中的重要步骤
Pulitzer 发表于 2024-9-16 16:21 | 显示全部楼层

它产生的噪声是对地噪声
童雨竹 发表于 2024-9-16 18:17 | 显示全部楼层

对于环氧树脂而言,一般把导热系数为0.5W/M·K的导热性能已经被定义为高导热
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部