修改 Timebase Source 轻松重新定义HAL_InitTick:武侠大侠的进阶秘籍 ⚡️

修改 滴答时钟源Timebase Source 轻松重新定义HAL_InitTick函数:武侠大侠的进阶秘籍 ⚡️

在这里插入图片描述

亲爱的朋友们,今天我们将走进 STM32 的江湖,学习如何通过修改 Timebase Source,重新定义 HAL_InitTick 这个弱函数。让我们像武林高手一样,轻松自如地掌控时基,决胜千里之外!😎

在 STM32 中,HAL_InitTick 是一个 弱函数__weak),意味着你可以在代码中重定义它。这一招就像是一个绝世武功的秘籍,能够让你根据不同的需求,自定义时基源,从而实现更精细的控制。今天,我会带你一步步揭开这门绝技的神秘面纱。


什么是 Timebase Source?

在 STM32 这片浩瀚的江湖中,Timebase Source 就像是一名神秘的大宗师,掌控着所有的时间滴答。你可能没怎么注意过它,但它的力量却时刻影响着你。它负责提供系统的滴答定时器(SysTick),也就是你在使用 HAL_Delay()HAL_GetTick() 时最依赖的武器。

每当你调用 HAL_Delay(),你的程序就像被大宗师点了穴道,定时开始计算出时间延迟。而在 STM32 中,默认的 Timebase Source 就是SysTick,不过如果你想要像武侠小说中的江湖大佬一样,不拘一格、自由掌控,那你完全可以选择其他定时器,来改变时基来源。Timebase Source 就是那把随时可以切换的“武器”。🗡️


Timebase Source 的作用:一键解锁系统滴答秘籍 🕰️

你问:“那 Timebase Source 到底能帮我做什么呢?”别着急,听我细细道来!😏

1. 提供精准的时间滴答:让你可以控制延迟、等待、时间流转 🕐

这招就像是掌门人指点迷津,让你轻松掌控程序中的时间流转。当你用 HAL_Delay() 来控制延时时,实际上是依赖 Timebase Source 提供的滴答信号。这不就像是某位大侠一剑穿心,每一滴血、每一秒钟都掌控得精准无误?

2. 任务调度:让 RTOS 和系统更快更稳

如果你在江湖中混得久了,肯定知道FreeRTOS这位大侠。它需要时间基准来管理任务调度,而默认的 SysTick 为其提供了必要的时间滴答。如果你切换到 其他定时器,比如 TIM6,就能为 FreeRTOS 提供更高精度的时基,做到任务调度更灵活、速度更快,如同大侠拔剑出鞘,快如闪电!

3. 低功耗模式:江湖也需要休养生息 🛌

武侠江湖中,谁不喜欢悠闲时光?但系统可不能总是忙碌不休,得学会休息和恢复。当 STM32 进入低功耗模式时,SysTick 不再工作,但你可以通过选择 TIM6TIM7 等定时器,使其依旧为你提供时基信号,让你在休眠时依然能够维持精确的时间管理。这招就像金庸大侠笔下的隐士高人,虽深居简出,但一旦出手,便是风云变化!


什么是 HAL_InitTick 🕰️

HAL_InitTick 是 STM32 HAL 库中用于初始化系统时基的函数。它的作用是配置一个定时器(通常是 SysTick)来生成系统时钟的滴答信号。这些滴答信号是 HAL 库(比如 HAL_Delay())等功能所依赖的基准。

然而,这个函数是弱函数__weak),意味着你可以在应用程序中对它进行重定义,从而实现定制化的时基源。

__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
  /* Configure the SysTick to have interrupt in 1ms time basis*/
  if (HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq)) > 0U)
  {
    return HAL_ERROR;
  }

  /* Configure the SysTick IRQ priority */
  if (TickPriority < (1UL << __NVIC_PRIO_BITS))
  {
    HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority, 0U);
    uwTickPrio = TickPriority;
  }
  else
  {
    return HAL_ERROR;
  }

  /* Return function status */
  return HAL_OK;
}

如上所示,HAL_InitTick 配置了系统时基源,通常是 SysTick,并设置了中断优先级。在 CubeMX 中修改 Timebase Source 后,你将能够定制时基来源,选择 SysTick 以外的定时器(比如 TIM6),实现更高精度或低功耗的控制。

**如何通过修改 Timebase Source 轻松重新定义 HAL_InitTick

1. 打开 CubeMX,切换时基来源 🔧

首先,大家得进入 CubeMX,这就像是你开启了武林秘籍,进入了更深的江湖。

  • 打开 CubeMX,进入 System Core 部分的 Timebase Source 配置。
  • 你会看到一个默认选项——SysTick,不过如果你想学更高深的武技,可以选择 TIM6TIM7 或其他定时器,带来更强大的控制力。

2. 生成代码,加入初始化配置 💻

一旦你选择了新的 Timebase Source,点击 Project 生成代码,就像是你从武馆里拿到了新武器,准备出招了!

生成代码后,你会发现会生成一个stm32f4xx_hal_timebase_tim.c,其中 HAL_InitTick() 函数里自动为你配置了你所选择的时基源。如果你选择了 TIM6,代码就会像这样:

HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) { 
    RCC_ClkInitTypeDef clkconfig; 
    uint32_t uwTimclock, uwAPB1Prescaler = 0U, uwPrescalerValue = 0U, pFLatency; 
    HAL_StatusTypeDef status; 

    __HAL_RCC_TIM6_CLK_ENABLE(); // 启用TIM6时钟 
    HAL_RCC_GetClockConfig(&clkconfig, &pFLatency); // 获取时钟配置 
    uwAPB1Prescaler = clkconfig.APB1CLKDivider; // 获取APB1分频系数 
    uwTimclock = (uwAPB1Prescaler == RCC_HCLK_DIV1) ? HAL_RCC_GetPCLK1Freq() : 2UL * HAL_RCC_GetPCLK1Freq(); // 计算TIM6时钟频率 
    uwPrescalerValue = (uint32_t)((uwTimclock / 1000000U) - 1U); // 计算预分频值 

    htim6.Instance = TIM6; // 设置TIM6实例 
    htim6.Init.Period = (1000000U / 1000U) - 1U; // 设置周期为1ms 
    htim6.Init.Prescaler = uwPrescalerValue; // 设置预分频值 
    htim6.Init.ClockDivision = 0; 
    htim6.Init.CounterMode = TIM_COUNTERMODE_UP; 
    htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; 
    status = HAL_TIM_Base_Init(&htim6); // 初始化TIM6 

    if (status == HAL_OK) { 
        status = HAL_TIM_Base_Start_IT(&htim6); // 启动TIM6并使能中断 
        if (status == HAL_OK) { 
            HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn); // 启用TIM6中断 
            if (TickPriority < (1UL << __NVIC_PRIO_BITS)) { 
                HAL_NVIC_SetPriority(TIM6_DAC_IRQn, TickPriority, 0U); // 配置中断优先级 
                uwTickPrio = TickPriority; 
            } else { 
                status = HAL_ERROR; // 如果优先级无效,返回错误 
            } 
        } 
    } 
    return status; // 返回函数状态 
}

这段代码就像是给你传授了定时器控制秘籍,让你能够根据需求灵活地使用它。

3. 修改中断处理函数 🛡️

这招可以比喻为你用一根暗器来打败对手!如果你选择了 TIM6SysTick_Handler() 这个经典的武技就会变成 TIM6_DAC_IRQHandler()。别担心,这只是换了一个名字,能力却依旧强大!

void TIM6_DAC_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&htim6);  // 处理中断
}

为什么要更改 Timebase Source?一切为了更强大的武力! 💥

你问:“大侠,我现在用 SysTick 也挺好的,改了有什么好处?” 哼!你不尝试怎么知道?一旦你掌握了这些招数,你将走得更远!

1. 低功耗模式:让你的 MCU 躲在暗处悄悄发力 💤

当 STM32 进入低功耗模式时,SysTick 停止工作,TIM6 仍能继续工作。就像是你在江湖上隐匿一段时间,别人以为你退隐了,结果你已经在背后悄悄做足了准备,等时机一到就能一鸣惊人!

2. 更灵活的定时控制:像大侠拔剑一样迅速 ⚔️

TIM6TIM7 能提供更灵活的时基控制,你可以自由设置它们的分频因子、时钟源。就像一位武林高手,手中的武器不仅威力无穷,且随时可以调整到最佳状态!

3. FreeRTOS 的任务调度:让你快人一步!

如果你正在使用 FreeRTOS,切换 Timebase Source 后,你可以获得更高精度的时基,避免了 SysTick 在某些高精度任务下的限制。就像一个身手敏捷的大侠,任务调度更精准,分秒必争!


正点原子的官方例程:双管齐下,兼顾 FreeRTOS 与 HAL 库基准时钟

在正点原子(STM32)官方例程中,常常会遇到如下操作:

void SysTick_Handler(void)
{
    HAL_IncTick();  // 增加 HAL 库的 Tick 值
    if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)  // 判断是否开始调度
    {
        xPortSysTickHandler();  // FreeRTOS 的滴答处理
    }
}

这段代码巧妙地将 FreeRTOS 和 HAL 库的时间基准结合在同一个 SysTick_Handler 中。我们来看看它是如何工作的:

  • HAL_IncTick():这段代码用来更新 HAL 库的 uwTick,即为 HAL 库提供时基。
  • xTaskGetSchedulerState():这一步判断 FreeRTOS 调度器是否已经启动,只有在启动后,才会调用 xPortSysTickHandler() 来处理 FreeRTOS 的任务调度。

通过这种方式,FreeRTOS 和 HAL 库共享一个系统滴答定时器,互不干扰,优雅地解决了两个系统对时基的需求。这就像是江湖中的两大门派,不仅能够和平共处,还能齐心协力,打下一片江山。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值