tags: [source-summary] type: source source: "尚硅谷嵌入式技术之STM32单片机(进阶篇)V1.0.1 — 第1章:定时器 + 配套代码16~19" author: "尚硅谷研究院" date: 2026-07-15
用生活理解:SysTick 就像秒表倒计时——设定一个时间(LOAD值),它倒数到 0 就提醒你(中断)。TIM通用定时器就像高级秒表,可以预分频(把太快的时间变成慢的)、自动重装(倒计时到0自动重新开始),适合精确控制 LED 闪烁频率。
SysTick 是 Cortex-M3 内核自带的24 位递减计数器,属于内核外设(不依赖具体芯片厂商)。
| 寄存器 | 地址偏移 | 功能 |
|---|---|---|
| CTRL | 0x00 | 控制与状态寄存器 |
| LOAD | 0x04 | 重装载数值寄存器 |
| VAL | 0x08 | 当前数值寄存器 |
| CALIB | 0x0C | 校准数值寄存器(很少用) |
CTRL 寄存器位说明: | 位 | 名称 | 说明 | |----|------|------| | 0 | ENABLE | 1=开启定时器,0=关闭 | | 1 | TICKINT | 1=计数到0时产生SysTick异常 | | 2 | CLKSOURCE | 1=AHB时钟(72MHz),0=AHB/8(9MHz) | | 16 | COUNTFLAG | 计数到0时硬件置1,读后自动清0 |
LOAD 寄存器:24 位有效(最大值 16,777,215)。
VAL 从 LOAD 值开始递减 → 到 0 时产生 COUNTFLAG → 自动重新装载 LOAD 值
// 微秒延时(AHB=72MHz)
void Delay_us(uint32_t us)
{
SysTick->LOAD = 72 * us; // 72MHz下,1us需72次计数
SysTick->VAL = 0; // 清当前值
SysTick->CTRL = 0x05; // ENABLE=1, CLKSOURCE=1(AHB)
while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG)) // 等待计数到0
{
}
SysTick->CTRL &= ~SysTick_CTRL_ENABLE; // 关闭定时器
}
注意:LOAD 最大 24 位(16,777,215),最大单次延时 = 16,777,215 / 72 ≈ 233ms
STM32F103ZET6 有多个定时器:
| 定时器 | 类型 | 位数 | 主要特性 |
|---|---|---|---|
| TIM1 | 高级 | 16 | 带互补输出、死区插入、刹车功能 |
| TIM2~5 | 通用 | 16 | 时基、PWM、捕获/比较 |
| TIM6~7 | 基本 | 16 | 仅时基(无PWM/捕获) |
预分频器(PSC) → 计数器(CNT) → 自动重装载(ARR) → 更新事件(UEV)
计数器时钟频率:CK_CNT = CK_PSC / (PSC + 1)
溢出时间:Tout = (ARR + 1) × (PSC + 1) / CK_PSC
示例:CK_PSC=72MHz, PSC=7199, ARR=9999
CK_CNT = 72MHz / 7200 = 10KHz
Tout = 10000 × 10KHz = 1s(1秒溢出一次)
| 寄存器 | 功能 |
|---|---|
| TIMx_PSC | 预分频器(16位,0~65535) |
| TIMx_CNT | 当前计数值 |
| TIMx_ARR | 自动重装载值 |
| TIMx_CR1 | 控制寄存器1(CEN使能、DIR方向、ARPE自动重装载预装载) |
| TIMx_DIER | 中断使能寄存器(UIE更新中断、CCxIE捕获比较中断) |
| TIMx_SR | 状态寄存器(UIF更新标志、CCxIF捕获比较标志) |
参考:参考手册 §14(通用定时器寄存器描述)
文件:stm32_base/16_systick_led_twinkle_register/Hardware/SysTick/systick.c
#include "systick.h"
// SysTick 初始化:配置1ms中断一次
void Systick_Init(void)
{
// 72MHz / 72000 = 1KHz = 1ms中断一次
// LOAD = 72000 - 1 = 71999
SysTick->LOAD = 72000 - 1;
SysTick->VAL = 0;
// CTRL: ENABLE=1, TICKINT=1(中断使能), CLKSOURCE=1(AHB)
SysTick->CTRL |= (SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_CLKSOURCE_Msk);
}
// SysTick 中断服务函数(在启动文件中注册)
void SysTick_Handler(void)
{
static uint16_t tick = 0;
tick++;
if (tick >= 1000) // 1000ms = 1s
{
LED_Toggle(LED_1); // 翻转LED
tick = 0;
}
}
文件:stm32_base/18_tim_led_twinkle_register/Hardware/TIM5/tim5.c
#include "tim5.h"
void TIM5_Init(void)
{
// 1. 开启TIM5时钟(APB1总线)
RCC->APB1ENR |= RCC_APB1ENR_TIM5EN;
// 2. 配置预分频器:72MHz / (7199+1) = 10KHz
TIM5->PSC = 7200 - 1;
// 3. 配置自动重装载值:10KHz / (10000+1) ≈ 1秒溢出一次
TIM5->ARR = 10000 - 1;
// 4. 清计数器
TIM5->CNT = 0;
// 5. 使能更新中断
TIM5->DIER |= TIM_DIER_UIE;
// 6. 使能TIM5中断(NVIC)
NVIC_EnableIRQ(TIM5_IRQn);
// 7. 使能计数器(CEN=1)
TIM5->CR1 |= TIM_CR1_CEN;
}
// TIM5 中断服务函数
void TIM5_IRQHandler(void)
{
if (TIM5->SR & TIM_SR_UIF) // 检查更新中断标志
{
LED_Toggle(LED_1); // 翻转LED
TIM5->SR &= ~TIM_SR_UIF; // 清标志(写0清除)
}
}
| 操作 | SysTick | TIM通用定时器 |
|---|---|---|
| 初始化 | SysTick->CTRL = 0x07 |
`TIMx->CR1 |
| 预分频 | 不可配(固定AHB或AHB/8) | TIMx->PSC = value |
| 重装载 | SysTick->LOAD = value |
TIMx->ARR = value |
| 中断使能 | CTRL.TICKINT=1 | DIER.UIE=1 + NVIC |
| 清标志 | 读CTRL自动清 | SR &= ~UIF |
| 停止 | CTRL &= ~ENABLE |
CR1 &= ~CEN |