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

来源:互联网 发布:中航工业津电 知乎 编辑:程序博客网 时间:2024/06/05 10:04

__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重新生成的时候,所做的修改会消失,这一点要慎重。

原创粉丝点击