当前位置: 首页 > news >正文

定时器中断点灯

使用定时器 2 进行中断点灯,500ms LED 灯翻转一次

一、配置步骤(思路→落地)

  1. 系统时钟到 72 MHz(HSE+PLL x9)

    • 常见设置:AHB=72 MHzAPB1=36 MHz (分频2)APB2=72 MHz (分频1)

    • F1 定时器“×2 规则”:当 APB prescaler ≠ 1 时,定时器时钟 = 2 × PCLK

    • 所以在 APB1=36 MHz、分频2 时,TIM2CLK = 2 × 36 MHz = 72 MHz(与你的 Ft=72M 一致)。

  2. 定时参数计算

每 500 ms 产生一次更新中断

3.HAL 初始化 TIM2

  • 使能 TIM2 时钟,配置 Prescaler=7199Period=4999、向上计数。

  • 使能更新中断、配置 NVIC(TIM2_IRQn)。

  • HAL_TIM_Base_Start_IT(&htim2) 启动中断。

4.编写回调

HAL_TIM_PeriodElapsedCallback() 里判断 htim->Instance == TIM2,做你的事情(例如翻转 PC13 LED)。

5.中断向量

TIM2_IRQHandler() 中调用 HAL_TIM_IRQHandler(&htim2)

timer.c:

/******************** timer.c(HAL 版本,行级详细注释) ********************/
#include "timer.h"   // 定时器对外接口与 TIM_HandleTypeDef 声明
#include "led.h"     // LED 翻转函数(中断回调里用)/* 全局定时器句柄* 作用:承载 TIM2 的寄存器基址和初始化配置;HAL 的所有 TIM API 都围绕这个句柄工作*/
TIM_HandleTypeDef timer_handle = {0};/*** @brief  基本定时器初始化 + 启动更新中断* @param  arr 自动重装载值(ARR),计数到 arr 后产生更新事件;范围 0~65535(16 位定时器)* @param  psc 预分频值(PSC),计数时钟 = TIMxCLK / (psc + 1);范围 0~65535* @note   更新中断频率公式:*         f_update = TIMxCLK / ((psc + 1) * (arr + 1))*         对于 F103,若 APB 分频!=1,则 TIMxCLK = 2 * PCLKx(F1“×2”规则)*         例:72MHz、psc=7199、arr=4999 → f_update=2Hz(每500ms一次中断)*/
void timer_init(uint16_t arr, uint16_t psc)
{timer_handle.Instance = TIM2;                             // 绑定底层硬件实例:TIM2(F103C8 可用 TIM1~TIM4)timer_handle.Init.Prescaler = psc;                        // 设定预分频,影响计数时钟(越大越慢)timer_handle.Init.Period = arr;                           // 设定自动重装载值(计到此值产生更新事件)timer_handle.Init.CounterMode = TIM_COUNTERMODE_UP;       // 计数方向:向上计数timer_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; // ARR 立即生效(不缓存)HAL_TIM_Base_Init(&timer_handle);                         // 调 HAL 完成底层寄存器初始化(会回调 MSP)HAL_TIM_Base_Start_IT(&timer_handle);                     // 以“中断模式”启动定时器(开启更新中断)
}/*** @brief  HAL 的 MSP 初始化回调(由 HAL_TIM_Base_Init() 触发)* @param  htim 指向当前要初始化的定时器句柄* @note   这里完成与外设相关的“板级”初始化:开时钟、配置 NVIC 等*/
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM2)                                // 仅处理 TIM2,其他定时器可在此追加分支{__HAL_RCC_TIM2_CLK_ENABLE();                          // ① 打开 TIM2 外设时钟(APB1)HAL_NVIC_SetPriority(TIM2_IRQn, 2, 2);                // ② 配置 NVIC 优先级(抢占2,响应2,取值范围视分组而定)HAL_NVIC_EnableIRQ(TIM2_IRQn);                        // ③ 使能 TIM2 中断线}
}/*** @brief  TIM2 的中断服务函数(由启动文件向量表调用)* @note   在 HAL 中断框架下,需要把中断分发给 HAL_TIM_IRQHandler() 做标志判断和回调触发*/
void TIM2_IRQHandler(void)
{HAL_TIM_IRQHandler(&timer_handle);                        // 统一的 HAL 中断分发入口(会调用 PeriodElapsedCallback)
}/*** @brief  更新事件回调(UPD:计数溢出/重装载触发)* @param  htim 触发回调的定时器句柄* @note   推荐在回调里只做“快小活”(如置标志、翻转管脚),避免长阻塞影响中断响应*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM2)                                // 确认来源是 TIM2(工程里可能有多路 TIM){led1_toggle();                                        // 例:每次更新事件翻转 LED1(500ms 一次)}
}

main.c:

#include "sys.h"
#include "delay.h"
#include "led.h"
#include "timer.h"int main(void)
{HAL_Init();                         /* 初始化HAL库 */stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */led_init();                         /* 初始化LED灯 */timer_init(5000 - 1, 7200 - 1);while(1){ }
}

参数选择:

1)timer_handle.Instance = TIM2;

  • 可选实例(F103C8 常见)TIM1(高级定时器,APB2),TIM2TIM3TIM4(通用定时器,APB1)。

  • 含义:告诉 HAL 句柄要操作哪一个定时器外设。你也可以改为 TIM3/TIM4,其余代码保持一致,只需改 NVIC 的中断号。

2)timer_handle.Init.Prescaler = psc;uint16_t,0~65535)

  • 可选任意数值,影响计数时钟:CK_CNT = TIMxCLK / (PSC + 1)

  • 建议:选择能让 ARR 落在合适范围(不太大也不太小),以兼顾分辨率与溢出周期。

3)timer_handle.Init.Period = arr;uint16_t,0~65535)

  • 可选任意数值,影响更新事件周期:T_update = (ARR + 1) / CK_CNT

  • 注意:若需要更高计数范围,可用 32 位的 TIM(F1 上 TIM2/5 为 32 位,但 F103C8 没 TIM5;TIM2 在大多数包络是 32 位,Cube/HAL 会按芯片裁剪,通常仍当 32 位用,但保险起见按 16 位配置即可)。

4)timer_handle.Init.CounterMode = TIM_COUNTERMODE_UP;

  • 可选值

    • TIM_COUNTERMODE_UP(向上计数)

    • TIM_COUNTERMODE_DOWN(向下计数)

    • TIM_COUNTERMODE_CENTERALIGNED1/2/3(中心对齐模式 1/2/3,用于 PWM 等对称场景)

  • 含义:决定 CNT 的计数方式与更新事件时机(中心对齐模式会影响更新与比较事件的时序)。

5)timer_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

  • 可选值

    • TIM_AUTORELOAD_PRELOAD_DISABLE禁用预装载,写 ARR 立即生效)

    • TIM_AUTORELOAD_PRELOAD_ENABLE使能预装载,写 ARR 先进缓冲,待下次更新事件才生效)

  • 含义:是否把 ARR 放到缓冲寄存器,同步在更新事件时加载,常用于 PWM 周期更新避免“中途撕裂”。

说明:timer_handle.Init.ClockDivision 在你的代码里没设,默认 DIV1。如需要可加:

  • TIM_CLOCKDIVISION_DIV1 / DIV2 / DIV4
    含义:数字滤波分频(对死区/滤波有影响),基本定时用途通常保持 DIV1

6)HAL_TIM_Base_Start_IT(&timer_handle);

  • 含义:以“中断模式”启动定时器(使能更新中断并开始计数)。

  • 对应停止HAL_TIM_Base_Stop_IT(&timer_handle);

  • 非中断模式HAL_TIM_Base_Start() / HAL_TIM_Base_Stop()(不触发回调)。

7)HAL_TIM_Base_MspInit()(HAL 的“MSP 回调”)

  • __HAL_RCC_TIM2_CLK_ENABLE();:打开 TIM2 外设时钟。

  • HAL_NVIC_SetPriority(TIM2_IRQn, 2, 2);

    • 第2个参数 = 抢占优先级,越小越高;

    • 第3个参数 = 子优先级,越小越高。

    • 可选范围取决于优先级分组(HAL_NVIC_SetPriorityGrouping() 或系统默认分组)。常见Group 2时两者范围均 0~3。

  • HAL_NVIC_EnableIRQ(TIM2_IRQn);:使能该中断线。

  • 可选中断号TIM1_UP_IRQn(TIM1 溢出/更新时间),TIM2_IRQnTIM3_IRQnTIM4_IRQn 等,视你使用的定时器而定。

8)TIM2_IRQHandler()

  • 固定写法:在具体的中断向量里调用 HAL_TIM_IRQHandler(&句柄),由 HAL 统一完成更新标志判断与回调触发。

  • 如果你改为 TIM3:向量函数要对应 void TIM3_IRQHandler(void),并调用 HAL_TIM_IRQHandler(&timer_handle)

9)HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

  • 回调来源判断if (htim->Instance == TIM2);多定时器共用一个回调时务必判断来源。

  • 可在此做的事:翻转 IO、投递事件标志、给队列/信号量(RTOS)等快小活;不要长期阻塞(例如长延时、长串口打印等)。


小注:500ms 的常用参数(72MHz、APB1÷2 → TIM2CLK=72MHz)

  • PSC = 7199ARR = 4999CK_CNT = 72MHz/(7199+1)=10kHzT = (4999+1)/10k = 0.5s

  • 若要 1ms 中断:PSC=71ARR=999(10kHz→此处应为 1kHz?更标准:PSC=71 得 1MHz,再 ARR=999 得 1kHz→1ms)

  • 若要 100us 中断:PSC=71ARR=99(1MHz/100 → 10kHz→100µs)

温馨提示:F1 的“×2 规则”很关键——若 APB1 分频不是 1,则 TIM2/3/4 的时钟 = 2 * PCLK1。确保系统时钟树配置与计算一致,否则节拍会偏。

http://www.dtcms.com/a/335895.html

相关文章:

  • Redux搭档Next.js的简明使用教程
  • 安卓开发中遇到Medium Phone API 36.0 is already running as process XXX.
  • 突破Python性能墙:关键模块C++化的爬虫优化指南
  • 【牛客刷题】字符串按索引二进制1个数奇偶性转换大小写
  • 编程算法实例-整数分解质因数
  • Vue3 + Element Plus 人员列表搜索功能实现
  • UE5多人MOBA+GAS 48、制作闪现技能
  • 第三十九天(WebPack构建打包Mode映射DevTool源码泄漏识别还原)
  • 软件开发 - foreground 与 background
  • 电容,三极管,场效应管
  • 光耦,发声器件,继电器,瞬态抑制二极管
  • 【102页PPT】新一代数字化转型信息化总体规划方案(附下载方式)
  • Coin与Token的区别解析
  • Python爬虫-解决爬取政务网站的附件,找不到附件链接的问题
  • 数学建模-评价类问题-优劣解距离法(TOPSIS)
  • 博士招生 | 新加坡国立大学 SWEET实验室 招收人机交互方向 博士/博士后
  • 13.web api 4
  • 实现用户输入打断大模型流式输出:基于Vue与FastAPI的方案
  • 基于DSP+ARM+FPGA架构的储能协调控制器解决方案,支持全国产化
  • Diamond基础2:开发流程之LedDemo
  • JavaScirpt高级程序设计第三版学习查漏补缺(1)
  • vba学习系列(12)--反射率通过率计算复杂度优化25/8/17
  • Nacos 注册中心学习笔记
  • Yolov模型的演变
  • 计算机毕业设计java的小天鹅酒店月子会所管理小天鹅酒店母婴护理中心管理系统设计小天鹅酒店产后护理会所信息化管理平台
  • ansible管理变量和事实
  • RAG学习(一)
  • 在职老D渗透日记day19:sqli-labs靶场通关(第26a关)get布尔盲注 过滤or和and基础上又过滤了空格和注释符 ‘)闭合
  • Google Earth Engine | (GEE)逐月下载的MODIS叶面积指数LAI
  • 好看的个人导航系统多模板带后台