3. 定时器中断与延时

定时器中断与延时 学习卡片

任务目标

本案例基于STM32标准外设库,配置TIM3产生周期性更新中断,在中断服务函数中翻转LED状态,实现主循环中不同延时时间的精确控制,最终使LED以两种不同频率交替闪烁。

硬件连接与前置条件

  • STM32F103系列开发板(以最小系统板为例)
  • LED接在PC13(板上自带)或PA5(外接,需串联220Ω电阻)
  • 使用标准外设库(STM32F10x_StdPeriph_Lib),已包含对应头文件路径

实现原理

TIM3时钟源为APB1(36MHz),通过预分频器PSC和自动重装载寄存器ARR设定中断频率。每次计数器溢出触发更新中断,在中断中翻转LED。主循环通过改变ARR值来切换闪烁频率,实现两种不同速率的延时控制。

关键完整代码

#include "stm32f10x.h"

volatile uint16_t delay_counter = 0;
volatile uint8_t  led_state = 0;

void TIM3_IRQHandler(void)
{
    if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
    {
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
        delay_counter++;
        if (delay_counter >= 10)   // 每10次中断翻转一次LED
        {
            delay_counter = 0;
            led_state = !led_state;
            GPIO_WriteBit(GPIOC, GPIO_Pin_13, led_state ? Bit_SET : Bit_RESET);
        }
    }
}

void TIM3_Init(uint16_t arr, uint16_t psc)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &GPIO_InitStructure);

    TIM_TimeBaseStructure.TIM_Period = arr - 1;
    TIM_TimeBaseStructure.TIM_Prescaler = psc - 1;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

    TIM_ITConfig(TIM3, TIM_IT_Update, 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);

    TIM_Cmd(TIM3, ENABLE);
}

void delay_ms(uint32_t ms)
{
    uint32_t i;
    for (i = 0; i < ms; i++)
    {
        // 利用TIM3中断计数实现1ms延时
        while (delay_counter < 1);
        delay_counter = 0;
    }
}

int main(void)
{
    TIM3_Init(1000, 72);  // 72MHz/72=1MHz, 计数1000次=1ms中断

    while (1)
    {
        // 快速闪烁:延时200ms
        delay_ms(200);
        // 慢速闪烁:延时500ms
        delay_ms(500);
    }
}

编译与下载

  1. 创建Keil MDK工程,选择对应STM32型号,添加标准外设库源文件
  2. 将上述代码保存为main.c并加入工程
  3. 在工程选项中定义STM32F10X_MD,包含标准库头文件路径
  4. 编译生成HEX文件,通过ST-Link或串口ISP下载到开发板

验证方法

下载程序后,观察LED闪烁节奏:应看到LED先快速闪烁(约200ms间隔翻转),随后变为慢速闪烁(约500ms间隔翻转),两种节奏交替循环。若LED不亮或频率异常,检查以下要点:

  • 确认TIM3中断已使能,NVIC优先级配置正确
  • 检查LED引脚是否与代码一致(PC13为板上LED,若用PA5需修改GPIO配置)
  • 用示波器或逻辑分析仪测量PC13引脚波形,验证高低电平持续时间是否符合预期

关键参数说明

定时器时钟频率计算:APB1=36MHz,定时器倍频后为72MHz。预分频72得到1MHz计数频率,ARR=1000时溢出周期为1ms。中断中每10次翻转一次LED,即LED状态每10ms改变一次。主循环中delay_ms(200)实际等待200个中断周期(200ms),delay_ms(500)等待500ms,实现两种闪烁频率的切换。