SysTick:STM32F103C8T6的精准延时与多任务调度核心

SysTick介绍

什么是SysTick?

SysTick(System Tick Timer)是ARM Cortex-M内核内置的一个24位系统定时器,用于提供精确的时间基准。在STM32中,SysTick常用于实现延时函数、RTOS(实时操作系统)的时基,甚至简单的多任务调度。它的核心优势在于其与内核紧密集成,无需依赖外部外设即可实现高精度定时。

SysTick工作原理

SysTick是一个递减计数器,工作流程如下:

初始化:设定重装载值(LOAD寄存器),计数器从该值开始递减。

计数:每个时钟周期计数器减1。

中断触发:当计数器减至0时,触发SysTick中断(若使能),并自动重载初始值,循环往复。

时钟源:默认使用内核时钟(HCLK,STM32F103C8T6通常为72MHz),也可配置为HCLK的1/8(需修改CTRL寄存器)。

SysTick寄存器介绍

SysTick通过4个寄存器控制:

寄存器 地址 功能描述
CTRL 0xE000E010 控制寄存器:使能计数器、中断、选择时钟源等。
LOAD 0xE000E014 重装载值寄存器:设定计数器的初始值(最大值0xFFFFFF)。
VAL 0xE000E018 当前值寄存器:读取当前计数值,写入任意值会清零计数器。
CALIB 0xE000E01C 校准值寄存器:包含出厂预定义的校准值(STM32中通常无需手动配置)。

关键位说明(CTRL寄存器):
Bit 0:使能计数器(1=启动,0=关闭)
Bit 1:中断使能(1=计数到0时触发中断)
Bit 2:时钟源选择(1=HCLK,0=HCLK/8)

延时函数代码实现

HAL库提供了HAL_Delay(),但若需更高精度或非阻塞延时,可自定义实现:

  1. 初始化SysTick(HAL库已默认配置)
// HAL库启动时已初始化SysTick,用户无需重复配置
// 时钟源为HCLK(72MHz),中断频率1kHz(LOAD=72000-1)
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */
  1. 微秒级延时(操作系统中可用)
/**
  * @brief  微秒级延时
  * @param  nus 延时时长,范围:0~233015
  * @retval 无
  */
void delay_us(uint32_t nus)
{
    uint32_t ticks;
    uint32_t tcnt = 0, told, tnow;
    uint32_t reload = SysTick->LOAD;                //重装载值
    
    ticks = nus * 72;                               //需要计的节拍数
    told = SysTick->VAL;                            //刚进入while循环时计数器的值
    
    while(1)
    {
        tnow = SysTick->VAL;
        if(tnow != told)
        {
            if(tnow < told)
                tcnt += told - tnow;
            else
                tcnt += reload - (tnow -told);
            
            told = tnow;                            //下次进入while循环时,当前VAL的值作为told
            
            if(tcnt >= ticks)                       //已计的数超过/等于需要计的数时,退出循环
                break;
        }
    }
}
  1. 毫秒级延时

/**
  * @brief  毫秒级延时
  * @param  nms 延时时长,范围:0~4294967295
  * @retval 无
  */
void delay_ms(uint32_t nms)
{
    while(nms--)
        delay_us(1000);
}
 
/**
  * @brief  秒级延时
  * @param  ns 延时时长,范围:0~4294967295
  * @retval 无
  */
void delay_s(uint32_t ns)
{
    while(ns--)
        delay_ms(1000);
}

/**
  * @brief  重写HAL_Delay函数
  * @param  nms 延时时长,范围:0~4294967295
  * @retval 无
  */
void HAL_Delay(uint32_t nms)
{
    delay_ms(nms);
}

Systick模拟多线程

通过SysTick中断实现时间片轮转调度,模拟多线程任务切换:
由于Systick的中断在初始化时,HAL_Init()函数中,已经打开,我们只需要在中断处理函数中,添加一个我们的函数。

void SysTick_Handler(void)
{
  HAL_IncTick();
  systick_isr();
}

该中断函数可在.s文件中可找到。
添加的函数
由此,Systick会每一毫秒进入该函数一次。在该函数中,在该函数中,我们只做简单的计数任务,然后达到计数值则将flag值置1。在主函数中一直调用任务函数。

void systick_isr(void)
{
    if (task1_cnt < 1000)
        task1_cnt++;
    else
    {
        task1_flag = 1;
        task1_cnt = 0;
    }

    if (task2_cnt < 500)
        task2_cnt++;
    else
    {
        task2_flag = 1;
        task2_cnt = 0;
    }
}

任务函数

void task1(void)
{
    if(task1_flag == 0)
        return;
    
    task1_flag = 0;
    
    led1_toggle();
}

void task2(void)
{
    if(task2_flag == 0)
        return;
    
    task2_flag = 0;
    
    led2_toggle();
}

总结

SysTick作为Cortex-M内核的核心定时器,为STM32提供了精准的时间管理能力。通过灵活配置寄存器,开发者可实现从微秒级延时至多任务调度的复杂功能。在实际项目中,结合HAL库的封装和自定义逻辑,SysTick能够显著提升系统的实时性和效率。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐