SysTick:内核自带“心跳”,HAL_Delay和RTOS都靠它
短文标题:SysTick:内核自带“心跳”,HAL_Delay和RTOS都靠它

你有没有想过一个问题:HAL_Delay(1000)为什么能延时1秒?FreeRTOS的vTaskDelay(100)又是怎么知道100ms到了?答案:SysTick。 一个集成在Cortex-M内核里的24位递减定时器,在所有Cortex-M芯片上都有,地址固定。

SysTick的三个寄存器(CMSIS定义)
配置方法:
SysTick_Config(SystemCoreClock / 1000); // 每1ms中断一次
为HAL_Delay提供“心跳”
HAL_Delay的底层是uwTick变量,由SysTick中断每1ms加1。
__weak void HAL_Delay(uint32_t Delay)
{
uint32_t tickstart = HAL_GetTick();
uint32_t wait = Delay;
if (wait < HAL_MAX_DELAY) wait++; // 补偿一个tick
while ((HAL_GetTick() - tickstart) < wait);
}
SysTick停,HAL_Delay就停。 调试时在SysTick中断设断点会导致时间停滞。RTOS的心跳,FreeRTOS的configTICK_RATE_HZ(通常100或1000Hz)对应SysTick的中断频率。SysTick中断里调用xTaskIncrementTick(),检查任务延时、时间片轮转等。没有SysTick,RTOS就没有时间基准,任务无法切换。

时钟频率改变后必须重配SysTick,上电默认用HSI(8MHz)配置SysTick。执行SystemClock_Config切换到PLL(72MHz)后,SystemCoreClock更新为72000000,但SysTick的LOAD值仍是8000。72MHz下8000个时钟周期≈111μs,不是1ms。HAL_RCC_ClockConfig会自动调用HAL_InitTick重配SysTick,手动改时钟时别忘调用。
SysTick中断优先级,SysTick中断优先级通常设为最低(15),确保高优先级中断(串口接收、外部急停)能随时打断SysTick,不增加中断延迟。FreeRTOS的最低优先级可设为configLIBRARY_LOWEST_INTERRUPT_PRIORITY,SysTick设为此值。
微秒延时的替代方案,SysTick的1ms分辨率不适合微秒延时。方案:
- 硬件定时器(TIM2):微秒级PWM或单脉冲模式
- DWT外设(Cortex-M内核自带):DWT->CYCCNT 72MHz下1 tick≈13.9ns
void delay_us(uint32_t us) {
uint32_t start = DWT->CYCCNT;
uint32_t cycles = us * (SystemCoreClock / 1000000);
while ((DWT->CYCCNT - start) < cycles);
}

这个故事的启示,SysTick不是“又一个定时器”,它是系统软件的时间基石。HAL_Delay、RTOS、软件定时器都依赖它的心跳。没有SysTick,STM32的软件生态会塌掉一半。
写在最后,SysTick不起眼,但它是整个嵌入式软件的“脉搏”。HAL_Delay靠它,RTOS靠它,软件定时器靠它。一个1ms的心跳,撑起整个系统的时间线。
(本文灵感源于于振南《新概念ARM32单片机》教程第6.1节、第6.2节、第6.3节。)
觉得有用?点赞、转发,让更多人看懂SysTick的“心跳”智慧。

更多推荐

所有评论(0)