新闻详情

新闻详情

首页 / 资讯中心 / 详情

STM32CubeMX实战:TIM1定时器1ms中断驱动LED闪烁

发布时间:2026/9/25 4:40:16来源:尧图网络
STM32CubeMX实战:TIM1定时器1ms中断驱动LED闪烁
先说我自己的体会STM32CubeMX 这种图形化配置工具带来的改变真的不是一星半点。以前用标准外设库配一个定时器中断要先翻数据手册查寄存器自己算预分频和重装载值再写启动代码折腾下来没个半小时真搞不定。现在通过 CubeMX 把引脚、时钟、外设都可视化配置好生成工程骨架再补几行用户逻辑TIM1 做 1ms 定时中断配合 LED 闪烁 Demo5 分钟绝对能跑起来。这篇文章我就拿 TIM1 定时器 1ms 中断作为例子把从 CubeMX 配置、代码编写到 Keil 烧录验证的完整流程拆开揉碎讲一遍适合刚接触 STM32 想搞懂定时器中断和 CubeMX 使用流程的读者已经会用标准库点灯但一直没摸过 CubeMX 的老朋友也可以对照看看两种开发方式的差别。1. 项目到底在做什么几个关键概念先理清在正式开始点鼠标配置之前我强烈建议先把几个基础概念想明白。否则就是照着截图点一遍下次换个定时器、换个周期还是不会。1.1 STM32CubeMX 到底帮你省了什么STM32CubeMX 是 ST 官方出的图形化初始化代码生成工具。它的核心逻辑很简单你用图形界面把芯片型号、引脚复用、时钟树、外设参数全部配置好它帮你生成一套完整的 HAL 库工程代码里面包括了时钟初始化、GPIO 初始化、外设初始化、中断向量配置这些底层逻辑。比如我们这个 Demo 里要做的 TIM1 初始化如果手写的话要操作 RCC 时钟使能、配置 PSC 预分频寄存器、配置 ARR 自动重装载寄存器、设置中断优先级、写中断服务函数每一步都要对着参考手册查寄存器地址和位定义。用 CubeMX 就是点几下鼠标的事配置完直接生成代码生成出来的初始化函数结构清晰逻辑都是验证过的。这里要说清楚CubeMX 生成的是项目骨架不是全部代码。它解决的是外设怎么初始化这个问题至于初始化之后要干什么比如我们要做的 LED 闪烁逻辑还是得自己写在用户代码区。这也是很多新手第一次用 CubeMX 时最容易困惑的地方以为代码生成完就能直接跑出效果其实不是你还需要主动去启动定时器、写中断回调函数。1.2 TIM1 是什么定时器为什么偏偏选它STM32 里的定时器资源很丰富基础定时器 TIM6/TIM7通用定时器 TIM2/3/4/5高级定时器 TIM1/TIM8还有一些更基础的看门狗定时器、系统滴答定时器。TIM1 属于高级定时器挂在 APB2 总线上它比通用定时器多了互补输出、刹车输入、重复计数这些功能常用于电机控制的 PWM 死区补偿场景。不过在我们这个 Demo 里用 TIM1 做基础定时中断和用通用定时器没有本质区别都是让计数器从 0 递增到自动重装载值触发更新事件进入中断回调函数。为什么我推荐在入门阶段用 TIM1一方面是因为高级定时器在学生板和入门教程里出现频率高你先把它玩明白了后面再用 TIM1 输出带死区的 PWM 驱动电机或者接霍尔传感器做输入捕获起点就不一样了另一方面是 TIM1 挂在 APB2 总线上在不少人用的 F103 系列里APB2 最大可以到 72MHz理解时钟路径之后计算中断频率会更顺手。1.3 1ms 中断是什么概念用来干什么1ms 中断说白了就是定时器每隔 1 毫秒触发一次中断也就是中断频率为 1kHz每秒触发 1000 次。这个时间粒度在嵌入式里非常常用很多实时性要求不高的系统都用它做时间基准比如按键消抖、LED 闪烁、传感器定时采样、任务调度心跳。为什么不用 delay 延时来实现闪烁因为 HAL_Delay 是阻塞式的程序在延时期间干不了别的事。而定时器中断是异步的主循环该干嘛干嘛到时间了硬件自动跳进中断服务函数处理一下处理完再回到主循环这种后台时间片的模式才是做嵌入式项目该有的思路。这里直接预告一个坑如果你让定时器每 1ms 中断一次然后在中断里直接翻转 LEDLED 会以 500Hz 的频率翻转人眼根本看不出闪烁看到的只是一个半亮状态的灯。所以这个 Demo 里我们不能每 1ms 翻转一次而是要在中断里做个计数累计到一定次数再翻转这样 LED 才能肉眼可见地闪起来。这个细节我后面写代码的时候会专门讲。2. 动手前的准备环境、接线与思路代码写起来其实不多但环境准备和思路理清是必须的一步。我把这部分放在前面省得你跟着教程走到一半发现工具链没配置好然后卡壳。2.1 软硬件清单硬件方面我用的是最常见的 STM32F103C8T6 最小系统板也就是大家常说的蓝板。这个板子性价比极高网上十几二十块就能买到引脚全部引出非常适合入门。调试器用一个 ST-Link V2十几块的国产货就够用。硬件清单如下STM32F103C8T6 最小系统板一块ST-Link V2 调试器一个面包板一块、杜邦线若干5mm LED 一个、220Ω 或 1kΩ 电阻一个数据线USB 转 micro USB给板子供电软件方面需要安装 STM32CubeMX、Keil MDK-ARM、ST-Link 驱动这三个东西。CubeMX 从 ST 官网下载安装就能用Java 环境新版已经内置了不用额外配置。这里顺便说一句网上很多人纠结 CubeMX 的汉化问题我的建议是没必要折腾界面就那么几个关键区域英文反而更容易和教程、手册对应起来而且汉化只是界面语言变了配置流程没有任何区别。2.2 开发板接线与原理LED 的接法很简单用杜邦线把 PA5 引脚接到面包板上串一个电阻再接到 LED 阳极LED 阴极接地。原理图就是下面这个逻辑。PA5 引脚电阻LED接地输出高电平时限流点亮低电平电阻用 220Ω 到 1kΩ 之间都行。以红色 LED 为例正向压降大概 1.8V工作在 5mA 左右如果供电是 3.3V电阻按 (3.3V - 1.8V) / 5mA ≈ 300Ω 选我习惯用 470Ω亮度适中稳定性也够。为什么不直接用板载的 PC13 LED因为很多最小系统板上 PC13 的 LED 是低电平点亮逻辑和常规推挽输出相反新手容易搞混用 PA5 外接一个 LED 可以避开这个坑。2.3 Demo 整体运行流程整个程序跑起来的流程是这样的系统上电后CubeMX 生成的 SystemClock_Config 先把系统时钟配到 72MHz然后 MX_GPIO_Init 把 PA5 初始化成推挽输出、初始电平为低接着 MX_TIM1_Init 把 TIM1 配成 1ms 中断周期NVIC 配好中断优先级。我们在 main 函数里调用 HAL_TIM_Base_Start_IT 启动定时器之后 TIM1 每 1ms 触发一次更新中断中断服务函数内部调用 HAL_TIM_IRQHandler再分发到 HAL_TIM_PeriodElapsedCallback 回调函数。在回调函数里用 static 变量做计数计到 500 次也就是 500ms翻转一次 PA5LED 就按 1Hz 频率闪烁。需要说明的是主循环 while(1) 里我们可以什么都不干或者只放一个空的循环。真实项目里主循环可以处理按键、通信、显示这些任务定时器中断负责时间相关的逻辑两者互不干扰。这就是中断带来的并行能力。3. 5分钟实战CubeMX 配置全流程这一节是整个教程的核心操作部分。我按照实际操作的顺序一步一步来每一步都会说明为什么这么配避免你只是机械地点鼠标。3.1 新建工程与芯片选型打开 CubeMX在主页选择 Access to MCU Selector进入芯片选型界面。在左侧搜索框输入 STM32F103C8在 MCU List 里找到 STM32F103C8Tx 这一项双击进入工程配置界面。选芯片的时候注意一个小细节F103C8T6 是 48 脚的 LQFP 封装Flash 容量是 64KB属于中等容量产品MCU List 里显示的型号是很具体的。如果你用的板子是 C6T6 或者 CBT6选型逻辑是一样的只要封装和 Flash 容量对应上就行。进入工程界面后右侧是芯片引脚图左侧是外设列表。这个界面里你先不用急着点引脚按照下面几个章节的顺序来配置就好。3.2 时钟树配置72MHz 这个参数为什么关键点开 System Core - RCC在右侧的 HSE 选项里选择 Crystal/Ceramic Resonator表示使用外部晶振作为高速时钟源。这是最常用也是精度最高的做法因为外部晶振比芯片内部 RC 振荡器稳定得多USB 通信、CAN 通信都依赖它。然后切到 Clock Configuration 标签页这就是时钟树配置界面。先看一眼HSE的值F103C8T6 最小系统板上一般焊接的是 8MHz 晶振如果你的板子是 12MHz 晶振这里要填 12不然后面所有时间参数全都会偏。确认 HSE 是 8MHz 后把PLL Source选为 HSEPLL Multiplier (x)设为 9这样 PLL 输出就是 72MHz在系统时钟源System Clock Mux里选择 PLLCLKSYSCLK 就变成 72MHz。最关键的一步来了看 APB1 和 APB2 的预分频器设置。APB1 最大只能跑 36MHz所以要设成 /2APB2 可以跑 72MHz设成 /1。这里有一个绝大多数人都会忽略的规则APB1 上的定时器时钟是 APB1 时钟的 2 倍也就是说 APB1 分频后是 36MHz但挂在 APB1 上的 TIM2/3/4/5 实际时钟是 72MHz。APB2 分频系数是 1所以挂在 APB2 上的 TIM1 时钟直接就是 72MHz。这个 72MHz 就是后面计算定时周期的关键参数。3.3 配置 TIM1 定时器PSC 和 ARR 的计算方法在左侧外设列表里找到 Timers - TIM1点进去。在 TIM1 Mode and Configuration 页面先看 Mode 标签把Clock Source设置为Internal Clock表示使用内部时钟源也就是刚才时钟树里确定的 72MHz。然后切到 Configuration - Parameter Settings这里有三个关键参数参数配置值说明Prescaler (PSC)71预分频系数Counter ModeUp向上计数模式Counter Period (ARR)999自动重装载值Auto-reload preloadEnable使能自动重装载预装载auto-reload preloadEnable使能自动重装载预装载为什么 PSC 取 71ARR 取 999这里有一个核心公式定时器中断频率 定时器时钟 / (PSC 1) / (ARR 1)代入数值72MHz / (71 1) / (999 1) 72MHz / 72 / 1000 1kHz也就是 1ms 触发一次中断。PSC 的作用是把 72MHz 分频到 1MHz也就是 1 微秒计数一次ARR 再计 1000 个数到溢出合起来就是 1 毫秒。这样理解起来就直观了先分频到你要的时间粒度再计多少个粒度到你要的周期。这个公式一定要吃透因为换任何定时器、任何周期都是这么算的。我整理了一个常用配置对照表同样在 72MHz 时钟下目标周期PSCARR计算过程1us71072MHz / 72 / 1 1MHz1ms7199972MHz / 72 / 1000 1kHz10ms71999972MHz / 72 / 10000 100Hz100ms719999972MHz / 720 / 10000 10Hz1s7199999972MHz / 7200 / 10000 1Hz注意这里的 ARR 和 PSC 在 16 位定时器里最大只能到 65535如果要配很长的周期优先加大 PSC让计数粒度粗一点而不是硬拉 ARR。在 NVIC Settings 标签页里勾选TIM1 update interrupt的 Enabled 复选框这步很容易漏掉。如果不勾CubeMX 不会生成 TIM1_UP_IRQHandler 中断服务函数后面定时器溢出时根本进不了中断。3.4 配置 LED 引脚 GPIO在左侧外设列表或者直接在右侧芯片引脚图上找到 PA5点击后选择 GPIO_Output。然后点开左侧 System Core - GPIO在 GPIO 配置页面里可以看到 PA5 的详细参数。参数配置值GPIO output levelLowGPIO modeOutput Push PullPull-up/Pull-downNo pull-up and no pull-downMaximum output speedLowGPIO output level 设成 Low 的意图很明确上电瞬间 PA5 是低电平LED 不亮等程序初始化完、中断开启、计数到 500 次时才第一次翻转变成高电平LED 点亮。这样可以避免上电瞬间乱闪。Maximum output speed 选 Low 就够LED 闪烁对翻转速率要求极低没必要开到 High 去增加功耗和噪声。这个参数主要是给高速通信引脚用的。这里也可以给 PA5 加一个 User Label比如填 LED这样生成的代码里会用宏定义替代硬编码的 GPIO_PIN_5代码可读性会好很多。3.5 生成代码与工程组织上面都配好后点菜单 Project - Generate Code第一次会让填工程名和路径。Project Name 填 LedTimerDemoToolchain 选 MDK-ARMToolchain version 选 V5其他保持默认点 Generate。生成后 CubeMX 会创建一个完整的工程目录核心文件有这么几个Core/Src/main.c主函数用户代码区Core/Src/tim.cTIM1 初始化函数 MX_TIM1_InitCore/Src/gpio.cGPIO 初始化函数 MX_GPIO_InitCore/Src/stm32f1xx_it.c中断服务函数Core/Inc/main.h头文件和用户标签宏定义用 Keil 打开项目里的.uvprojx工程文件前我先提醒一句CubeMX 生成的代码是可以反复再生成的但你手动修改过的代码只应该写在 USER CODE 注释区间内。main.c 里有各种USER CODE BEGIN和USER CODE END注释这些区域之间的内容是 CubeMX 下次生成时保留的区域而区间外的内容会被覆盖。所有自己写的逻辑启动代码、回调函数、自定义变量都要放在这些标记内。4. 核心代码解析真正跑起来的部分代码生成之后严格来说 Demo 还没跑起来因为你还没有启动定时器中断也没有写中断里要执行的逻辑。这一节专门说清楚代码要补在哪、为什么要这样补。4.1 启动定时器中断的几行代码打开Core/Src/main.c先看 main 函数里的结构。CubeMX 生成的 main 函数依次调用了 HAL_Init、SystemClock_Config、MX_GPIO_Init、MX_TIM1_Init 这些初始化函数。注意初始化函数只是配置了定时器的寄存器并没有启动定时器Timer 的计数器这时候还是静止状态。需要我们在USER CODE BEGIN 2区域添加一行/* USER CODE BEGIN 2 */ HAL_TIM_Base_Start_IT(htim1); /* USER CODE END 2 */这行代码的作用是启动 TIM1 的计数功能并使能更新中断。为什么必须加这行HAL 库把 初始化 和 启动 分成了两个阶段MX_TIM1_Init 只是设置寄存器参数相当于把闹钟调好了但还没上发条HAL_TIM_Base_Start_IT 才真正让闹钟走起来并且让闹钟响铃时能触发中断。和它对应的还有一个 HAL_TIM_Base_Start不带 IT 后缀这种模式只启动定时器但不开中断适用于查询溢位标志位的轮询方式。初学者最容易犯的错误是只调 HAL_TIM_Base_Start 或者干脆什么都不调结果程序跑起来毫无反应。4.2 __weak 回调函数机制定时器中断的脏活累活其实已经被 HAL 库做好了TIM1 溢出时硬件会触发 TIM1_UP_IRQHandler 中断服务函数这个函数在 stm32f1xx_it.c 里已经生成好内部调用HAL_TIM_IRQHandler(htim1)HAL 库在中断处理函数里判断确实是更新事件后会调用一个回调函数HAL_TIM_PeriodElapsedCallback。关键点来了HAL 库里给这个回调函数加了__weak修饰符也就是弱定义。库里面有一个默认的弱实现函数体是空的但允许你在自己的代码里重新定义一个同名同参的强定义函数链接时强定义会覆盖弱定义。这意味着你不用修改 HAL 库的任何源码只需要在自己的文件里写出完整版的 HAL_TIM_PeriodElapsedCallback这个回调就会被系统劫持。真正的用户逻辑就写在这里面。注意回调函数的命名不能写错Ben 的 B 字母大写是 Period 不是 Periodic很多人在这上面栽过跟头编译时报错找不到函数声明或者一直没反应。4.3 LED 闪烁逻辑每 1ms 做一次计数500ms 翻转一次现在就到了写核心逻辑的时候。理论上回调函数每 1ms 被调用一次如果你在回调里直接写HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin)LED 会以 500Hz 频率翻转人眼完全看不出来只会觉得灯变暗了。所以正确做法是加一个计数器变量累计到 500 次再翻转。在USER CODE BEGIN 4区域添加回调函数/* USER CODE BEGIN 4 */ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { static uint16_t ledCounter 0; if (htim-Instance TIM1) { ledCounter; if (ledCounter 500) { ledCounter 0; HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); } } } /* USER CODE END 4 */为什么用 static 变量因为 ledCounter 需要在多次中断调用之间保持值不变如果声明在函数内部且不加 static每次函数退出值就丢了如果放成全局变量会污染命名空间。static 局部变量在程序启动时只初始化一次而且只能在当前 .c 文件内部访问是最合适的方案。为什么要判断htim-Instance TIM1因为回调函数是全局的如果工程里同时使用了 TIM1、TIM2 等多个定时器它们的中断最终都会进到同一个回调函数。通过判断句柄里的 Instance 字段就可以区分当前中断来自哪个定时器做到互不干扰。在这个 Demo 里虽然只有一个定时器但这种写法是工程上必须养成的习惯。每次进回调 ledCounter 加 1加到 500 说明过了 500ms翻转一次 LED清计数器循环往复。最终 LED 亮 500ms、灭 500ms周期正好 1Hz肉眼看起来就是滴答滴答的呼吸感和闪烁感。如果想改成亮 1 秒、灭 1 秒把阈值从 500 改成 1000 就行。那段HAL_GPIO_TogglePin是直接翻转引脚电平的快捷函数比先读 ODR 寄存器再写 ODR 要简洁很多HAL 库在 GPIO 这层做了很好的封装直接用即可。4.4 编译烧录与验证用 Keil 打开工程后先把编译生成目标改成Use Linker Script或者直接默认在魔术棒Options for Target里Device 标签页确认芯片是 STM32F103C8Debug 标签页选择 ST-Link Debugger点 Settings确认能够识别到 SW DeviceFlash Download 标签页勾选 Reset and Run右上角编译按钮旁边的下拉框选 STM32F103C8 对应 Flash 大小一般是默认接线的时候ST-Link 和板子的 SWD 接口只需要接四根线SWDIO、SWCLK、GND、3.3V。接反或者松了都会导致找不到芯片这是下载问题里最高发的原因。烧录之后如果一切正常LED 会以大约 1Hz 的频率闪烁。如果没反应先别急着怀疑代码按顺序排查PA5 是否接对了杜邦线LED 极性有没有焊反ST-Link 驱动是否正常这些低级错误在嵌入式调试里发生的概率比想象中高得多。5. 踩坑实录与排查技巧这一节是我自己这些年做 STM32 项目过程中实实在在踩过的坑比代码逻辑本身更有价值。我按问题的发生频率从高到低整理了一遍每个问题都给出排查思路。5.1 定时器中断不触发该从哪查起这是新手遇到最多的问题。现象是程序跑起来主循环正常执行但 LED 不闪进了调试器打断点发现中断服务函数根本没到。排查顺序可以按下面这个来检查 HAL_TIM_Base_Start_IT 是否调用。这是第一位的。很多人初始化完定时器忘了启动或者用的 Hal_TIM_Base_Start 看不到效果因为查询模式下没有回调。检查 CubeMX 里 NVIC 是否正确勾选。如果只配了 TIM1 的 Mode 参数忘了在 NVIC Settings 里勾选 TIM1 update interruptCubeMX 生成代码时是不会生成 TIM1_UP_IRQHandler 的。检查回调函数是否真的被覆盖了。如果回调函数的拼写有误比如把 PeriodElapsed 写成 PeriodicElapsed编译器会认为你在定义一个新函数HAL 库里的弱回调函数仍然是空的中断进来了但什么都不干。检查回调函数里有没有死循环。比如在中断里调用了 printf而 printf 依赖串口且串口没初始化好程序会卡死在中断里表现就是 LED 不闪但程序也不死。5.2 周期不准时间不对如果 LED 闪烁的频率跟计算值对不上比如配 500ms 结果实际是 750ms问题八成出在时钟源上。最常见的是晶振频率配错。CubeMX 默认可能认为外部晶振是 25MHz 或者 8MHz但你的板子实际焊接的是 12MHz 或者 8MHz时钟树里 HSE 速度没改整个系统时钟就全偏了。有个小技巧用调试器查看 SystemClock_Config 函数里设置的 RCC_OscInitStruct 结构体看 HSEValue 字段是不是和你板子晶振一致。第二个常见原因是APB 预分频设置影响了定时器时钟。按照前面说的规则如果 APB1 设成 /2定时器时钟是 APB1 的 2 倍这个细节忘了的话你算出来的周期就会比自己预期的少一半或者慢一半。不同系列的规则不完全一样有的芯片没有定时器倍频逻辑所以拿一个例子套所有芯片是行不通的。第三个原因是 PSC 和 ARR 填反了。PSC 填了 999ARR 填了 71看似乘积一样但分频粒度和溢出计数的逻辑就完全反了虽然最终周期可能一样后期想做捕获比较时会非常别扭。5.3 下载失败与烧录问题Keil 报 No Target Connected 或者 RDDI-DAP Error 这类错误时硬件问题的权重比较大。ST-Link 的 SWDIO/SWCLK 是否接反这是最常见的低级错误。有的杜邦线颜色一样接的时候容易搞混最好用万用表量一下。ST-Link 的 3.3V 有没有输出ST-Link V2 从 USB 取电一般能输出 3.3V 给目标板供电但有的山寨版在功率不足时可能供电不稳。如果芯片之前烧过别的程序把 SWD 引脚复用成了普通 GPIO也会导致无法连接。这时候需要把 BOOT0 拉高进 ISP 模式重新上电后用 STM32CubeProgrammer 擦除整个 Flash再拉回 BOOT0 就能正常下载了。Keil 的 Debug 界面里ST-Link Debugger 的 Port 要选 SW而不是 JTAG速度尽量调低到 1MHz 左右会更稳。5.4 常见问题速查表症状可能原因快速处理LED 完全不闪没调 HAL_TIM_Base_Start_IT 或 NVIC 没勾补启动代码重新生成工程LED 常亮或半亮回调里直接翻转频率太高加计数器阈值不要每次中断都翻转LED 闪烁频率不对晶振频率设错或 APB 分频忘了定时器倍频核对时钟树参数用调试器看 RCC 配置进中断就卡死中断里调用 printf/delay 等阻塞函数中断里只做置标志位或简单操作编译报找不到回调函数声明函数名拼写错误对照 HAL 库函数名复制粘贴下载时报 No TargetST-Link 接线或驱动问题重新插拔、检测 SWD 线序还有一个我不太会写在纸上面但实际很重要的经验回调函数里尽量只做置标志位、计数、翻转 IO 这类极短的操作千万不要在里面调用 HAL_Delay 或者 printf。中断里面的时间非常宝贵执行时间过长会导致主循环饿死如果两个中断互相抢占还可能造成死锁。这个习惯越早建立越好。6. 后续还能怎么玩Demo 跑通之后这只是一个起点。TIM1 定时中断可以扩展出很多玩法我按从易到难的顺序给你列几个方向都是我在实际项目中验证过的思路。6.1 让闪烁时间随心变最简单的扩展是改周期。把 CubeMX 里 PSC 和 ARR 改一下重新生成代码闪烁节奏就变了。我这里推荐一个通用做法在改参数之前先用铅笔在纸上写一下公式定时器时钟 / (PSC1) / (ARR1) 期望频率再反推 PSC 和 ARR 的取值。算好再填不要凭感觉乱填。也可以不改定时器参数只改回调里的计数阈值。比如阈值 500 是 500ms改成 1000 就是 1 秒改成 50 就是 50ms这个灵活度比改定时器寄存器高得多适合在程序运行中动态调整闪烁频率。6.2 多个定时器协作的实用场景TIM1 做 1ms 时基TIM2 做 PWM 输出TIM3 做输入捕获解码编码器信号这是非常经典的组合。CubeMX 里配好几个定时器后回调函数里通过htim-Instance判断来源就可以分别处理不同定时器的事件。这种做法在项目里最常见的场景是一个定时器提供 1ms 系统时钟一个定时器输出呼吸灯 PWM一个定时器定时启动 ADC 采集传感器数据。代码结构清晰每个外设负责自己的一摊事互不干扰。6.3 中断优先级与资源协调虽然裸机 Demo 里中断优先级看起来不重要但如果你把系统从裸机往 FreeRTOS 上迁移或者同时开了串口、ADC、PWM 多个中断优先级设计就成了绕不开的问题。我的经验是需求明确前中断优先级可以先统一设成默认但工程结构上一定要保留 CubeMX 生成的 NVIC 配置入口别手动去寄存器里乱改。等系统复杂到一定程度再在 CubeMX 的 NVIC 界面里按时效性高、处理时间短的原则调整优先级让定时器这种时间敏感的中断优先级高一些而串口接收这种排队容忍度高的中断优先级低一些。这样动态调整能力就掌握了。多说一句把中断处理函数写短这个习惯越早养成越好。你自己想想看如果 1ms 中断一次回调函数里代码执行超过 1ms那下一个中断就来了要么丢中断要么嵌套混乱程序跑起来时好时坏排查起来极其痛苦。我个人的体会是CubeMX 最大的价值不是帮你省了敲代码的时间而是逼着你在图形界面里把外设配置、时钟树、引脚复用全部想清楚。以前我用标准库经常是抄一段定时器初始化代码就跑完全不理解为什么设置这个值。现在每配置一个外设都要在图形界面里面对所有选项逼着自己去弄懂每个参数的含义反而把基础打得扎实了。这个项目做完之后建议你在同一个 .ioc 文件上继续改把 PWM、输入捕获、编码器模式都试一遍你会发现 STM32 定时器这部分的底层逻辑是相通的一通百通。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

KEIL5代码全黑怎么办?语法高亮失效的原因与修复指南 2026/9/25 7:01:19

KEIL5代码全黑怎么办?语法高亮失效的原因与修复指南

遇到过KEIL5里文件中的字全部变成黑色、看起来跟记事本一模一样的情况吗?先说结论:工程基本没坏,代码大概率也都还在,这属于KEIL5语法高亮(Syntax Coloring)渲染失效,在嵌入式开发群里出现的频率…

阅读更多 →
九联UNT403A/413A免拆刷机:晶晨S905L3安卓9.0重装实战 2026/9/25 7:01:19

九联UNT403A/413A免拆刷机:晶晨S905L3安卓9.0重装实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
柴油机颗粒物浓度预测:机器学习特征工程与模型选型实战 2026/9/25 7:01:12

柴油机颗粒物浓度预测:机器学习特征工程与模型选型实战

简介:本资源为《基于机器学习的柴油机颗粒物浓度预测》学术论文PDF,面向内燃机排放研究、环保监测及机器学习应用方向的高校师生与科研人员。论文以涡轮增压中冷重型柴油机在四个不同海拔地区的实际道路排放试验为基础,采用主成分分析提取气缸…

阅读更多 →
机器学习预测股票涨跌:代码每次结果不同的原因与避坑指南 2026/9/25 7:01:06

机器学习预测股票涨跌:代码每次结果不同的原因与避坑指南

简介:2024年课程设计用机器学习股票预测算法源码项目,面向金融数据分析、人工智能、通信工程、自动化等相关专业的高校学生、教师和科研工作者,可作毕业设计、课程设计或项目初期演示的完整参考。压缩包共26个文件,整体仅2.57MB&a…

阅读更多 →
ChatGPT-Shortcut(AiShort)部署全指南:Vercel、Cloudflare、Docker 与离线内网方案 2026/9/25 7:00:53

ChatGPT-Shortcut(AiShort)部署全指南:Vercel、Cloudflare、Docker 与离线内网方案

AI 应用提示工程人工智能前端 【免费下载链接】ChatGPT-Shortcut Stop writing prompts from scratch — a searchable prompt library for ChatGPT, Claude, Gemini and Cursor Русский 한국어 العربية हिन्दी ไทย | 别再从头写提示词&…

阅读更多 →
Git GUI 图形界面使用与开发完全指南:Tcl/Tk 实现的 Git 可视化工作台 2026/9/25 7:00:46

Git GUI 图形界面使用与开发完全指南:Tcl/Tk 实现的 Git 可视化工作台

版本控制开发工具CLI 【免费下载链接】git A fork of Git containing Windows-specific patches. 项目地址: https://gitcode.com/gh_mirrors/git/git 点击查看 免费下载 Git GUI 是随标准 Git 发行版一同分发的官方图形化客户端,让你通过窗口界面完成暂…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉