参考文献:《Cortex-M3 权威指南》

https://picture.iczhiku.com/resource/upload/6820519db1f84e7faaf51c573c48e013.pdf

———————————————————————————————————————————

SysTick(System Tick Timer)是 Cortex-M系列内核内置的一个 24 位递减计数器

  • 捆绑在 NVIC(嵌套向量中断控制器)中,异常号 15。

  • 所有 Cortex-M3 芯片均包含此定时器,且SysTick的处理方式都是相同的

SysTick功能

        产生周期性的“滴答”(tick)中断,为操作系统(如 FreeRTOS、RT-Thread)或实时系统提供时间基准(时基)

SysTick作用

(1) 任务调度与时间片轮转

示例

  • 假设RTOS操作系统为任务 A 分配 3 个时间片(3ms),任务 B 分配 1 个时间片(1ms),SysTick 每 1ms 触发一次中断,RTOS 会在中断中检查是否需要切换任务,确保公平调度。

  • 如果没有 SysTick,某个任务可能长期占用 CPU,导致系统卡死。

(2)定时功能
  • 操作系统提供的延时函数(如 osDelay())、软件定时器、超时检测等均依赖 SysTick。

(3)维持系统“心跳”
  • SysTick 的寄存器通常由操作系统内核管理,用户程序无法直接修改,防止人为破坏系统节律。

SysTick 的时钟源

(1)内部时钟(FCLK):
  • Cortex-M3 的 自由运行时钟,频率与 CPU 主频相同(如 SystemCoreClock = 72MHz)。

(2)外部时钟(STCLK)
  • 由芯片厂商定义,可能来自分频后的系统时钟或外部低速时钟(如 32.768kHz)。

控制SysTick定时器的4个寄存器

1、控制及状态寄存器

(1)COUNTFLAG (位16):状态标志位
  • 功能:当SysTick计数器从1递减到0时,此位会自动置1。当程序读取这个位后,它会自动清零。

  • 用途:常用于检测定时器是否完成了计数周期。

(2)CLKSOURCE (位2):时钟源选择位

    功能:选择时钟源

  • 0 = 使用外部时钟源(STCLK,通常是AHB时钟的分频)
  • 1 = 使用处理器内核时钟(FCLK)
(3)TICKINT (位1):中断使能位

     功能:控制是否产生中断

  • 1 = 当计数器递减到0时产生SysTick异常请求(中断)
  • 0 = 计数器递减到0时不产生中断
(4)ENABLE (位0):定时器使能位

     功能:SysTick定时器的使能位

  • 1 = 启用SysTick定时器
  • 0 = 禁用SysTick定时器
2、重装载数值寄存器

RELOAD 寄存器用于设置 SysTick 定时器的重装载值

  • 这个值决定了定时器的计数周期,它是一个24位的值,最大可设置为0xFFFFFF(16,777,215)

  •  SysTick 定时器倒数计数从 RELOAD 值开始递减,直到0时会自动从这个寄存器重新加载数值

  • 定时周期 = (RELOAD + 1) × 时钟周期

示例:

如果要配置 SysTick 每1ms产生一次中断:(假设时钟频率为16MHz)

RELOAD = (16000000 / 1000) - 1 = 15999

3、当前数值寄存器

功能描述:

(1) 读取操作

        读取时会返回 SysTick 定时器当前的倒计数值

(2) 写入操作

        向这个寄存器写入任何值都会导致:

  • 当前计数值被清零

  • 同时会清除 SysTick 控制及状态寄存器中的 COUNTFLAG 标志

实际应用

  • 读取当前倒计数的剩余值

  • 通过写入操作手动重置计数器

  • 手动清除 COUNTFLAG 状态标志(当计数器从1减到0时,该标志会被置位)

4、校准数值寄存器

位段说明

(1)NOREF (位31):外部参考时钟信息
  • 1表示没有外部参考时钟(STCLK不可用)

  • 0表示外部参考时钟可用

(2)SKEW (位30):校准值信息
  • 1表示校准值不是准确的10ms

  • 0表示校准值是准确的10ms

(3)TENMS (位23:0):实现跨平台的恒定 SysTick 中断频率

        当 SysTick 定时器以 系统时钟(SYSCLK) 运行时,TENMS存储的是 10ms 内 SysTick 需要计数的 ticks(时钟周期数)。(芯片厂商会默认写入这个值)。

例如:

  • 如果 SYSCLK = 50MHz,则 TENMS = 50,000,000 × 0.01 = 500,000
  • 如果 SYSCLK = 8MHz,则 TENMS = 8,000,000 × 0.01 = 80,000

  TENMS寄存器提供了 10ms 对应的 ticks 数,直接写入RELOAD 寄存器即可在所有兼容 Cortex-M3 的芯片上实现 精确的 10ms 中断,无需关心具体时钟频率。

注意:如果看到TENMS = 0,表示 该芯片不支持自动校准功能

RX32程序示例

1、systick_init( )函数
/********************************************************************************************************
**函数信息 :systick_init()                 
**功能描述 :systick延时函数初始化
**输入参数 :无
**输出参数 :无
********************************************************************************************************/
void systick_init()
{
    // 配置 SysTick 定时器,设置中断频率为 4.2kHz
    if (SysTick_Config((SystemCoreClock) / 10000)) 
    { 
        /*  如果配置失败(SysTick_Config函数返回 1 ),则进入死循环(错误处理) */
        while (1);
    }
    // 设置 SysTick 中断优先级为 0x2(中等优先级)
    NVIC_SetPriority(SysTick_IRQn, 0x2); 
}

SysTick_Config()函数说明

  • SysTick_Config(uint32_t ticks)函数配置 SysTick 定时器,使其按照设定的时间间隔触发中断。
  • ticks表示滴答定时器运行多少步数后中断一次。
  •  ticks(中断步数) = SystemCoreClock(系统主频) / 中断频率
  • 已知系统主频是42MHz,这里配置滴答定时器的定时中断频率为4.2kHz,也就是约等于每 300us 触发一次中断

 2、SysTick_Config( )函数
#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U)

// ARM Cortex-M 的通用 SysTick 初始化模板
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
  if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) // 检查重载值是否超出最大允许范围
  {
    return (1UL);                                                   /* 重载值超出有效范围,设置失败 */
  }

  SysTick->LOAD  = (uint32_t)(ticks - 1UL);                         /* 设置重装载寄存器值(实际写入值为ticks-1) */
  NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* 设置SysTick中断优先级为最低优先级 */
  SysTick->VAL   = 0UL;                                             /* 清零SysTick计数器当前值(强制重装载) */
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |                    	/* 选择处理器时钟作为时钟源 */
                   SysTick_CTRL_TICKINT_Msk   |                     /* 使能SysTick中断 */
                   SysTick_CTRL_ENABLE_Msk;                         /* 启动SysTick计数器 */
  return (0UL);                                                    /* 返回无符号长整型0,表示函数执行成功 */
  }
}

#endif

条件编译说明:

  • 厂商自定义了SysTick初始化时,则令_Vendor_SysTickConfig为1

  • 厂商使用ARM自带的SysTick初始化模板,令_Vendor_SysTickConfig为0

这里的条件编译就是检查_Vendor_SysTickConfig的值,决定是否使用ARM自带的SysTick初始化模板。

 SysTick_Config()函数详解:

(1)函数输入ticks的值,也就是中断步数的值

__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)

(2)函数通过该语句判断重载值是否越界,越界则结束函数并返回1表示错误

  if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) 
  {
    return (1UL); 
  }

(3) 函数通过该语句设置重装载寄存器值,寄存器值应该是ticks - 1(因为数到0后才触发中断)

  SysTick->LOAD  = (uint32_t)(ticks - 1UL);

(4) 函数通过该语句设置SysTick中断优先级为最低优先级

NVIC_SetPriority (SysTick_IRQn , (1UL << __NVIC_PRIO_BITS) - 1UL); 

(5)  函数通过该语句设置强制重装载(给当前数值寄存器写0)

SysTick->VAL   = 0UL;

 (6)  函数通过该语句完成以下配置:(使用位掩码的方式给控制与状态寄存器写值)

  • 选择处理器内核时钟(FCLK)作为时钟源

  • 使能SysTick中断

  • 启动SysTick计数器

  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                   SysTick_CTRL_TICKINT_Msk   |
                   SysTick_CTRL_ENABLE_Msk;

 (7)  函数配置完成后,返回0表示SysTick配置成功

return (0UL);
Logo

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

更多推荐