STM32——定时器中断
·
一、STM32 通用定时器是什么?
STM32F103 内部的 TIM2、TIM3、TIM4、TIM5 都属于 通用定时器。它们的核心功能:
- 定时
- 中断
- PWM 输出
- 输入捕获
- 输出比较
本篇我们使用最基础、最常用的 定时中断功能。
二、通用定时器中断工作原理
- 定时器有一个 计数器,从 0 开始向上数
- 系统时钟 72MHz 太快,需要 分频(Prescaler) 降速
- 计数器数到 自动重装载值(Period) 时,产生 溢出
- 溢出后触发 更新中断(Update Interrupt)
- CPU 立刻响应,进入 中断服务函数 执行任务
- 执行完后,计数器自动清零,重新开始计数
一句话总结:分频 + 重装载值 → 决定多少秒进一次中断。
三、定时时间计算公式
定时时间(秒)= [( 分频系数 + 1 ) × ( 自动重装载值 + 1 )] / 定时器时钟
STM32F103 定时器时钟 = 72MHz
四、tim.c(定时器核心文件)
#include "tim.h"
#include "stm32f10x.h"
void Base_TIM_Init(void)
{
1. 定义结构体
TIM_TimeBaseInitTypeDef TIM_TimeInitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
TIM_TimeBaseInitTypeDef:定时器基本配置结构体NVIC_InitTypeDef:中断优先级配置结构体
2. 开定时器时钟(必须第一步)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
- TIM2 挂载在 APB1 总线上
- 任何外设必须先开时钟才能工作
- 不开时钟 → 定时器完全不工作
3. 配置定时器基本参数
TIM_TimeInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
- 时钟分频:不分频
- 一般默认写
TIM_CKD_DIV1即可
TIM_TimeInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
- 计数器模式:向上计数模式
- 从 0 → Period 往上数,数满溢出
TIM_TimeInitStruct.TIM_Prescaler = 10000;
分频系数
- 把 72MHz 时钟进行 10001 分频
- 分频后计数器时钟 = 72MHz / 10001 ≈ 7199Hz
TIM_TimeInitStruct.TIM_Period = 7200;
自动重装载值
- 计数器从 0 数到 7200 溢出
- 溢出触发中断
TIM_TimeInitStruct.TIM_RepetitionCounter = 0;
- 高级定时器用
- 通用定时器写 0
⭐ 本代码的定时时间计算
(10000 + 1) × (7200 + 1) / 72000000 ≈ 1 秒
结论:每 1 秒进入一次定时器中断。
4. 初始化定时器
TIM_TimeBaseInit(TIM2, &TIM_TimeInitStruct);
把参数写入 TIM2 寄存器。
5. 开启更新中断
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
- 开启定时器溢出中断
- 计数器数满 → 触发中断
6. 启动定时器
TIM_Cmd(TIM2, ENABLE);
- 启动后,定时器才真正开始计数
- 不写这句,定时器永远不工作
7. NVIC 中断优先级配置
NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn;
指定中断通道为 TIM2 中断。
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
使能中断。
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
设置优先级:
- 抢占优先级 0
- 子优先级 0
NVIC_Init(&NVIC_InitStruct);
将优先级配置写入寄存器。
四、逐行详细讲解:main.c
int main()
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
✅ 中断分组必须放在最前面
- 整个芯片中断规则
- 只能设置一次
LED_Init();
Base_TIM_Init();
初始化 LED 和定时器。
while(1)
{
}
}
主循环什么都不做,完全交给中断控制。
五、中断服务函数详细讲解
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
判断是否为定时器更新中断
- 防止进错中断
- 标准写法
GPIO_WriteBit(GPIOA, GPIO_Pin_1, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1)));
翻转 LED 电平
- 原来 0 → 变 1
- 原来 1 → 变 0
- 实现闪烁效果
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
清除中断标志位(必须写)
- 不清除 → 程序卡死在中断里
六、最终总结
- 你的定时器配置:每 1 秒进一次中断
- 中断里只做一件事:翻转 LED(快进快出)
- 代码现在 100% 正确,烧录直接亮灯闪烁!
七、你现在烧录进去会看到的现象
LED (PA1) :亮 1 秒 → 灭 1 秒 → 亮 1 秒 → 灭 1 秒…… 无限循环
更多推荐



所有评论(0)