6. 定时器

📌 本节学习目标
  • 了解 STM32 定时器分类与特性
  • 掌握 SysTick 滴答定时器的使用
  • 掌握通用定时器的定时中断配置
  • 理解输入捕获的基本原理

6.1 定时器分类

STM32F103 有 3 种类型的定时器:

类型数量计时器位数主要特性
高级定时器(TIM1)116 位PWM 互补输出、死区插入、刹车功能
通用定时器(TIM2/3/4)316 位定时、输入捕获、输出比较、PWM
基本定时器(TIM6/7)216 位基础定时、DAC 触发
SysTick124 位Cortex-M3 内核内置,常用作系统心跳

6.2 通用定时器原理

通用定时器内部包含:

  • 计数器 (CNT):向上/向下/中心对齐计数
  • 预分频器 (PSC):对时钟进行分频,分频范围 1~65536
  • 自动重装寄存器 (ARR):计数上限

定时时间计算公式:

T = (PSC + 1) × (ARR + 1) / 定时器时钟频率

例如:APB1 时钟 36MHz,TIM2 获得 72MHz(APB1 预分频≠1 时翻倍),PSC=7199,ARR=999:

T = (7200 × 1000) / 72,000,000 = 0.1s = 100ms

6.3 SysTick 定时器

C 代码(SysTick 延时)
#include "stm32f10x.h"

static uint32_t TimingDelay;

// SysTick 初始化:每 1ms 中断一次
void SysTick_Init(void)
{
    // SystemCoreClock = 72000000 (72MHz)
    // 计数值 = 72000000 / 1000 = 72000
    if (SysTick_Config(SystemCoreClock / 1000))
    {
        while (1);  // 配置失败
    }
}

// SysTick 中断服务函数
void SysTick_Handler(void)
{
    if (TimingDelay > 0)
        TimingDelay--;
}

// 毫秒延时函数
void delay_ms(uint32_t ms)
{
    TimingDelay = ms;
    while (TimingDelay != 0);
}

// 微秒延时(循环等待方式)
void delay_us(uint32_t us)
{
    uint32_t i;
    for (i = 0; i < us; i++)
    {
        // 约 1μs @72MHz(实际需微调)
        __NOP(); __NOP(); __NOP();
    }
}

6.4 通用定时器中断示例

C 代码(TIM3 定时中断)
#include "stm32f10x.h"

// TIM3 初始化:100ms 定时中断
void TIM3_Init(void)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

    // PSC=7199 -> 72MHz/(7199+1) = 10KHz = 0.1ms
    // ARR=999 -> 0.1ms × 1000 = 100ms
    TIM_TimeBaseStructure.TIM_Period = 999;
    TIM_TimeBaseStructure.TIM_Prescaler = 7199;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

    TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);  // 更新中断
    TIM_Cmd(TIM3, ENABLE);                      // 启动定时器

    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

// TIM3 中断服务函数
void TIM3_IRQHandler(void)
{
    if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
    {
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
        // 每 100ms 执行的任务
        GPIO_ToggleBits(GPIOB, GPIO_Pin_0);
    }
}
💡 这两段代码怎么用?
  1. SysTick 延时:设置 LOAD 后倒数到 0 自动重装,中断里递减计数,主程序忙等——这就是实验 14 的 delay_ms 原理
  2. 通用定时器中断:核心是 PSC(分频) + ARR(周期),配合 NVIC 产生周期性中断,实验 13 就是用它翻转 LED
  3. 定时时间公式 T = (PSC+1)×(ARR+1)/72MHz 务必背熟,实验题常考「给定时长反推 PSC/ARR」
📎 配套资料课件:6.定时器.pptx | 实验:实验13:定时器实验14:SysTick