对STM32 HAL库的一些思考(二)__weak关键字和systick

本文探讨了STM32 HAL库中__weak关键字的作用,它允许函数重定义并实现了类似C++的函数重载特性。同时,详细介绍了Systick定时器作为内核的心跳定时器,如何为系统提供时基信号,并在HAL库中如何应用。通过理解这两个概念,可以更好地自定义延时函数,同时避免直接修改库文件带来的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

__weak关键字

有时候我们阅读HAL源码的时候会发现,很多函数前会有一个__weak的前缀,一开始我对这个前缀很好奇,想知道这到底是什么意思。在IAR for ARM中使用“go to defination”查看该关键字的时候会提示__weak defined on the command line,即在命令行中定义,得,这又回到原点了……

不过一次偶然的机会,在查找C语言相关资料时,我看到它的真实含义,该关键字用于函数前,编译器在链接函数时会优先链接没有该关键字前缀的函数,即变相的,而且是不完全的实现了C++的函数重载特性,示例:

//HAL库微秒延时函数,有__weak关键字即代表可以重载该函数
__weak HAL_Delay(__IO uint32_t delay);
//用户函数
HAL_Delay(__IO uint32_t delay);

以上两个函数,编译器会优先链接下面的函数,即为我们重定义延时函数提供了较大的便利性。


Systick定时器

了解ARM的人对Systick定时器一定不陌生,这是内核自带的定时器,不过我更喜欢称它为心跳定时器,一般在裸机开发时,由它提供整个内核的时基信号,当然也可以替换为外围的定时器,这一点可以在STM32CubeMX中得到验证,此处不赘述。

不过为什么要把systick和__weak关键字扯在一起呢?这当然是有原因的。

如果有阅读过HAL库中关于cortex部分的源码,你会发现关于心跳定时器的每一个函数前都有__weak关键字,以STM32F407为例,这部分源码在stm32f4xx_hal.h/.c和stm32f4xx_hal_cortex.h/.c中,之前网上有很多修改Tick的初始化以达到使HAL_Delay()函数可以进行微秒级延时的例子,这里不多说这种方法,只是阐述一下HAL_Delay()的延时原理。

  1. Tick的默认初始化

    __weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
    {
      /*Configure the SysTick to have interrupt in 1ms time basis*/
      HAL_SYSTICK_Config(SystemCoreClock/1000U);
    
      /*Configure the SysTick IRQ priority */
      HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority, 0U);
    
      /* Return function status */
      return HAL_OK;
    }

    经过此函数,心跳定时器被初始化为1ms的时基单元,即每毫秒进入一次Systick中断

  2. Systick中断及其回调函数

        /**
         * stm32f4_it.c
        **/
    
    void SysTick_Handler(void)
    {
          /* USER CODE BEGIN SysTick_IRQn 0 */
    
          /* USER CODE END SysTick_IRQn 0 */
          HAL_IncTick();
          HAL_SYSTICK_IRQHandler();
          /* USER CODE BEGIN SysTick_IRQn 1 */
    
          /* USER CODE END SysTick_IRQn 1 */
    }
    
    /**
     * stm32f4xx_hal.c
     * uwTick是一个全局变量,在该文件中定义
    **/
    __weak void HAL_IncTick(void)
    {
        uwTick++;
    }

    即每毫秒uwTick加一,用于计算Systick产生的节拍数

  3. 获取当前节拍

    /**
     * stm32f4xx_hal.c
     * uwTick是一个全局变量,在该文件中定义
    **/
    
    __weak uint32_t HAL_GetTick(void)
    {
        return uwTick;
    }

    返回当前节拍,如果内核正常运行,则uwTick的值即为已经经过的ms数(不考虑精确度)

  4. 延时函数

    /**
     * stm32f4xx_hal.c
     * uwTick是一个全局变量,在该文件中定义
    **/
    
    __weak void HAL_Delay(__IO uint32_t Delay)
    {
        uint32_t tickstart = HAL_GetTick();
        uint32_t wait = Delay;
    
        /* Add a period to guarantee minimum wait */
        if (wait < HAL_MAX_DELAY)
        {
            wait++;
        }
    
        while((HAL_GetTick() - tickstart) < wait)
        {
        }
    }

    我想这个函数不需要多解释,就是数节拍以确定延时。


既然了解了HAL的延时函数是如何延时的,则我们完全可以重写这些函数以实现花样延时,但是不建议直接修改库文件,有__weak在,就可以在其他文件中书写自己的函数而不是破坏库函数原有结构了。另外,修改了库函数,在使用CubeMX重新生成的时候,所做的修改会消失,这一点要慎重。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值