RTOS systick 小baby问题

请问一下下面的168000/168M=0.001S=1MS部分是在哪部分的代码体现的呢


#if ( configOVERRIDE_DEFAULT_TICK_CONFIGURATION == 0 ) /*条件编译*/
 
    __weak void vPortSetupTimerInterrupt( void )
 
    {
        /* Calculate the constants required to configure the tick interrupt. */
 
        #if ( configUSE_TICKLESS_IDLE == 1 ) /*条件编译,这段不编译*/
            {
                ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
                xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
                ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ );
            }
        #endif /* configUSE_TICKLESS_IDLE */
 
        portNVIC_SYSTICK_CTRL_REG = 0UL;            /*清空控制及状态寄存器*/
        portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;   /*清空当前值寄存器*/
 
        /*设置重装载数值寄存器数值*/
        /*168000000/1000=  168000重装载值,168000/168M=0.001S=1MS*/
        portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
        /*设置控制及状态寄存器*/                    
        portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT );
                            /*( 1UL << 2UL ) | ( 1UL << 1UL ) | ( 1UL << 0UL ) */
                            /*选择处理器时钟、开定时器中断、使能定时器*/
 
    }
 
#endif /* configOVERRIDE_DEFAULT_TICK_CONFIGURATION */

在这段代码中,计算所需的重装载值和设置控制及状态寄存器(portNVIC_SYSTICK_CTRL_REG)的代码是计算和设置系统时钟中断的周期(即操作系统中的 Tick 计时器周期)。

通过下面的代码片段:

portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;

确定了重装载值,计算出了系统时钟中断的周期。其中,configSYSTICK_CLOCK_HZ 表示 Systick 计数器的时钟频率,单位为 Hz。configTICK_RATE_HZ 表示 Tick 计时器的周期,即每秒钟 Tick 计时器发出的中断次数。

本段代码的计算结果为 1ms,即每隔 1ms 会发出一次系统时钟中断,用来更新操作系统中的 Tick 计时器。

因此,代码中的 168000/168M=0.001S=1MS 部分不是代码体现的,而是源于 Systick 计时器和 Tick 计时器的参数配置。

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 以下回答来自chatgpt:

    回答:

    在RTOS系统中,systick计时器一般是由硬件定时器或者内核定时器定时中断实现的。在代码中出现的这段计算,其实是为了确定定时器的定时周期,从而实现需要的定时周期。以ARM Cortex-M系列MCU为例,systick计时器的计时周期可以通过SysTick_Config函数设置。

    下面是一个使用内核定时器实现systick计时器的示例代码,在该代码中,定时周期为1ms:

    #include "stm32f4xx_hal.h"
    
    /* 定义内核定时器句柄 */
    TIM_HandleTypeDef htim;
    
    /* systick计数器 */
    volatile uint32_t systick_count = 0;
    
    /* 定时器配置函数 */
    static void MX_TIM_Init(void)
    {
      TIM_MasterConfigTypeDef sMasterConfig = {0};
      htim.Instance = TIM2;
      htim.Init.Prescaler = 84-1;   /* 每10us计数一次 */
      htim.Init.CounterMode = TIM_COUNTERMODE_UP;
      htim.Init.Period = 10000-1;   /* 10*10us=100us周期 */
      htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
      if (HAL_TIM_Base_Init(&htim) != HAL_OK)
      {
        Error_Handler();
      }
      sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
      sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
      if (HAL_TIMEx_MasterConfigSynchronization(&htim, &sMasterConfig) != HAL_OK)
      {
        Error_Handler();
      }
    }
    
    /* 定时器中断处理函数 */
    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    {
      /* 若为systick定时器,计数器加1 */
      if(htim == &htim)
      {
        systick_count++;
      }
    }
    
    /* systick延时函数 */
    void delay_ms(uint32_t ms)
    {
      uint32_t start = systick_count;
      while(systick_count - start < ms);
    }
    
    void init()
    {
      /* 初始化定时器 */
      MX_TIM_Init();
      /* 使能定时器中断 */
      HAL_TIM_Base_Start_IT(&htim);
    }
    
    int main()
    {
      init();
    
      while (1)
      {
        /* 等待1s */
        delay_ms(1000);
      }
    }
    

    在以上代码中,通过配置定时器的预分频和周期,使得定时器的计数器1ms中断一次。在定时器中断处理函数中,判断是否为systick定时器,然后执行systick计数器变量的加1操作。在需要进行延时操作时,调用delay_ms函数,等待指定的ms数即可。

    若需要实现更高精度的systick计时器,可以考虑使用更高分辨率的硬件定时器或者在系统时钟配置时选择更高频率的时钟源。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^