news 2026/5/5 22:49:28

STM32——定时器中断

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32——定时器中断

一、STM32 通用定时器是什么?

STM32F103 内部的TIM2、TIM3、TIM4、TIM5都属于通用定时器。它们的核心功能:

  • 定时
  • 中断
  • PWM 输出
  • 输入捕获
  • 输出比较

本篇我们使用最基础、最常用的定时中断功能

二、通用定时器中断工作原理

  1. 定时器有一个计数器,从 0 开始向上数
  2. 系统时钟 72MHz 太快,需要分频(Prescaler)降速
  3. 计数器数到自动重装载值(Period)时,产生溢出
  4. 溢出后触发更新中断(Update Interrupt)
  5. CPU 立刻响应,进入中断服务函数执行任务
  6. 执行完后,计数器自动清零,重新开始计数

一句话总结:分频 + 重装载值 → 决定多少秒进一次中断。

三、定时时间计算公式

定时时间(秒)= [( 分频系数 + 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. 你的定时器配置:每 1 秒进一次中断
  2. 中断里只做一件事:翻转 LED(快进快出)
  3. 代码现在 100% 正确,烧录直接亮灯闪烁!

七、你现在烧录进去会看到的现象

LED (PA1) :亮 1 秒 → 灭 1 秒 → 亮 1 秒 → 灭 1 秒…… 无限循环

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/5 22:39:34

零基础入门stm32:用快马ai生成你的第一个cubemxled闪烁工程

作为一个刚接触STM32开发的新手,第一次看到那些复杂的寄存器配置和底层硬件操作确实有点懵。好在有STM32CubeMX这个图形化配置工具,让外设初始化变得直观多了。最近我在InsCode(快马)平台上尝试用AI生成我的第一个LED闪烁工程,整个过程比想象…

作者头像 李华
网站建设 2026/5/5 22:34:31

终极指南:3分钟用calibre-douban插件快速整理电子书元数据

终极指南:3分钟用calibre-douban插件快速整理电子书元数据 【免费下载链接】calibre-douban Calibre new douban metadata source plugin. Douban no longer provides book APIs to the public, so it can only use web crawling to obtain data. This is a calibre…

作者头像 李华