重温STM32基础:定时器(3)
文章目录使用定时器做定时中断的基本流程TIM_TimeBaseInitTIM_ClockDivisionTIM_RepetitionCounterTIM_Prescaler 和 TIM_Period中断函数实验问题数字从1开始增加最后一行代码作用对解决方案的疑问事件、Flag和中断验证遇到了问题。。。结论摘要本文记录了 STM32 定时器定时中断的配置流程重点剖析了TIM_TimeBaseInit中几个容易被忽略的参数TIM_ClockDivision、TIM_RepetitionCounter、TIM_Prescaler与TIM_Period的作用。随后围绕“屏幕数字从 1 开始增加”的实验现象展开深入排查澄清了事件、Flag 与中断三者的区别并解释了TIMx-EGR TIM_PSCReloadMode_Immediate这行代码引发问题的原因及正确清标志位的操作。使用定时器做定时中断的基本流程使能RCC RCC_APB1PeriphClockCmd配置定时器时钟源 TIM_InternalClockConfig配置定时器 TIM_TimeBaseInit配置中断输出控制允许更新中断输出到NVICTIM_ITConfig配置NVIC在NVIC中打开定时器中断通道并且分配优先级时基单元的运行控制使能计数器写定时器中断函数配置的时候跟着老师的表述和PPT的框图流程来就行。这里主要记录一下配置过程中发现的一些之前没有注意过的配置和它们的作用。TIM_TimeBaseInitTIM_ClockDivision配置定时器的时候需要给TIM_TimeBaseInit提供一个结构体。结构体中包含这个元素TIM_ClockDivision。这个参数在定时器框图中看不到而实际上它影响的是框图中的Input Filter模块下面红框。而TIM_ClockDivision的值实际影响的是CKD这个域。在RM中对这个域有解释。所以TIM_ClockDivision决定的是滤波器采样频率和CK_INT的关系而滤波器都是在外部时钟或者输入捕获等路线上。虽然从框图中看起来CK_INT和滤波器通路没有关系但实际上应该是框图中没有表现出来。一个例子假设使用外部时钟TIMx_ETR提供的外部时钟为8MHz并且设置它的prescalar为1设置TIM_ClockDivision为2那么这个filter就是以72/236MHz来采样这个8MHz的输入输出ETRF。另外有一个限制之前以为和Nyquist采样定理有关但是后来查了一下其实并不是。Nyquitst采样定理是建立模拟信号和数字信号之间的桥梁解决的是模拟信号能否被无失真地重建而这里采样地就是数字量对采样频率也有要求目标是正确捕获一个边沿事件。滤波器的采样和外部时钟生成脉冲显然是异步的。对两个异步的设备A采样和B产生数字信号A要捕获B的脉冲边沿就要求B相对于A足够慢慢到A在它的每个采样周期都能采到足够的点。这里的1/4限制是数字电路同步的“建立和保持”的要求至少要让滤波器有2个cycle捕获到外部时钟是高才能认为外部时钟处于高电平至少要让滤波器有2个cycle捕获到外部时钟是低才能认为外部时钟处于低电平这个限制下ETRP的最高频率就也和TIM_ClockDivision有关了如果这里的TIM_ClockDivision为1那么ETRP的最高频率可以是18MHz如果这里的TIM_ClockDivision为2那么ETRP的最高频率可以是9MHz有的时候由于系统的原因外部时钟的频率并不能和我们期望的一样比如它可能是32MHz。这个时候就违反了这个规定。当然ST也给出了解决方案可以用Prescalar先给ETR的输入降频到16MHz甚至8MHz作为ETRP输入filter。而总体而言这个TIM_ClockDivision参数只有当我们用外部定时器、输入捕获等情况时才会有影响如果我们用内部时钟作为定时器时钟源这个参数没有影响。TIM_RepetitionCounter这是高级定时器上的一个配置。看了一下RM里面的描述如果没有这个repitition counter RCR是计数到了ARR就产生事件如果设置了这个RCR每次计数到了ARRrepetition counter也会减1然后repetition counter到了0才会报一个event感觉就是ARR的又一次套壳。。。做了一些查询然后结合RM中的描述“This can be useful when generating PWM signals”所以看起来ARR和RCR还是有点区别的并且特别在PWM的应用中很有用ARR主要管PWM的周期RCR管多少个PWM周期后产生一个真正的寄存器更新/事件TIM_Prescaler 和 TIM_Period要让定时器以某个频率报中断就是用这两个参数用这个公式C K _ C N T _ O V f ( C K _ C N T ) A R R 1 C K _ P S C ( 1 P S C ) ( A R R 1 ) CK\_CNT\_OV \frac{f(CK\_CNT)}{ARR 1} \frac{CK\_PSC}{(1 PSC)(ARR 1)}CK_CNT_OVARR1f(CK_CNT)​(1PSC)(ARR1)CK_PSC​如果我们希望定时器1s报一次中断/事件则凑一个1即可CK_PSC是72000000可以凑一个组合prescalar设置为7200自动加载设置成1000但实际参数应该设置为TIM_Prescaler为7200 -1设置TIM_Period 为10000 - 1。还是有几个注意点设置的组合不唯一。除了上面的组合也可以设置Prescalar 为3600 自动重载为2000只要范围在0~65535 (uint16的取值范围)确定了prescalar和自动重载值之后真正赋给struct里面参数的值要减去1。这样可以从公式角度理解公式里面PSC和ARR都是加1运算的那么ARR和PSC需要减1带入才能得到我们想要的等式。中断函数进入中断函数先检查中断源必须在退出中断函数之前清除中断标志位实验问题数字从1开始增加课程中老师发现了一个现象照理屏幕数值是从0开始增加的但是它上来就是1。他立刻猜测到是不是一上来就进了一次中断导致运行了一次Num。他说这是由于定时器初始化函数TIM_TimeBaseInit的最后一行“TIMx-EGR TIM_PSCReloadMode_Immediate; ”导致的结果。解决方法是在初始化之后调用TIM_ClearFlag。对此本人还是有点疑问“TIMx-EGR TIM_PSCReloadMode_Immediate” 是什么意思疑问老师怎么直到是用clearFlag而不是clearIT另外看起来这起来的一下是进入了中断只有ISR里面Num才会加1那这个应该是属于产生了中断而不是事件啊所以看起来应该用clearIT验证如果真的是这一行产生的问题那么如果我注释掉这一行现象是不是会变成从0开始最后一行代码作用这一行代码是把EGR寄存器的bit1设置成1也就是初始化counter的值并且通过软件来触发一个更新事件。之所以要做这一步除了初始化counter的值是个正常操作另一个原因涉及之前提到过电路使用“影子寄存器”的机制我们往PSC和ARR寄存器里写入值不一定是立刻生效的因为电路读取的是它们的影子寄存器的值而只有在更新事件发生之后我们写入的值才会给到影子寄存器从而在电路中开始生效。这一步操作就是用软件触发这么一个更新事件在初始化完成之后让我们的配置立刻生效。对解决方案的疑问对于老师提供的解决方案为什么是调用TIM_ClearFlag而不是TIM_ClearITPendingBit因为看现象是跑到了TIM2的ISR应该是调用ClearIT才对其实如果看它们的实现代码会发现这两个functions几乎一模一样说是“几乎”是因为它们的入参范围不一样但是它们写的是同一个寄存器在当前代码这个场景下看底层对寄存器的操作这两个function是一样的。但是为了可读性还是要用TIM_ClearFlag因为从这两个这两个function的命名、定义以及入参来看这两个function的语义是不一样的。事件、Flag和中断这几个名词一直有点模糊。之前几乎把“事件的产生”和Flag的产生认为是一个东西但其实不是。结合定时器区分一下事件一个功能层面的定义它指的是某个功能模块产生一个脉冲信号它可以触发其他外设或者CPU动作。它可能置标志位也可能不置。Flag是事件在寄存器层面的可见形式。产生Flag肯定表示有事件但是有事件不一定体现在Flag上。中断可以理解为“事件通知CPU”。结合这个定时器的代码就是UIFUpdate Interrupt Flag和UIEUpdate Interrupt Enable同时为1时就是一个中断。当然最终要调用到对应ISR必须配置好NVIC使能相关IRQ通道。对比TIM_GetFlagStatus和TIM_GetITStatus也可以发现前者只是检查了SR寄存器的相应位后者除了这个之外还检查了IT是否被使能了(DIER寄存器的UIE位由TIM_ITConfig置1)验证遇到了问题。。。事实证明注释掉这一行还是会从1开始。下面对比了一下由这行和没这行的区别如果有这一行在执行初始化代码之后分别用TIM_GetFLAGStatus和TIM_GetITStatus读取状态FLAG是1而IT是0这个其实正常因为IT还没有被使能。。。如果没有这一行上面两个读出来都是0。也就是说确实是这一行造成了FLAG被置1。但是删掉这一行之后OLED还是会从1开始。尝试debug开启debug模式并在如下内容处打断点进入ISR时OLED_WriteNum的结束不是OLED_WriteNum这个函数调用的那一行断点停在某一行其实这行还没有被执行可以发现程序一上来会进入TIM2的ISR让Num。然后才执行OLED的显示操作导致第一次显示的还是1。猜测可能是由于一开始电路使用的是shadow ARR和shadow PSR默认值造成的而不是我们设置的值这个默认值导致报中断的间隔非常小所以上来就进入中断。这种情况下即使我们在TIM_TimeBaseInit之后执行clearIT或者clearFlag也都是没有用的。因为这个中断是配置完IT并且TIM2使能之后产生的。注但是我们读不到这两个shadow的值对于这个猜测不能很好的验证。另外不能说老师说的问题的原因不对而是注释掉这一行之后会有其他问题出现导致Num还是会在最开始被1。“TIMx-EGR TIM_PSCReloadMode_Immediate”的原因也是为了让shadow值立刻变成我们设置的值但是也带来一些“副作用”初始化之后TIM_GetFLAGStatus就是1如下流程图说明了执行和不执行TIM_PSCReloadMode_Immediate导致“错误”现象的原因以及执行clearFlag之后为什么可以解决问题对于初始化中执行EGRTIM_PSCReloadMode_Immediate而TIM使能之后立刻调用ISR的情况这看起来是“已经有了Flag使能了TIM2 ITUIE1)之后Flag‘变成了’中断”看上去像是这样但更准确的说法应该是UIE置1之后事件被接到了中断通路上并且由于NVIC已经配置它看到了这个事件于是进入TIM2的ISR。所以也结合上面“区分事件、Flag和中断”的部分事件不会“变成中断”事件一直都在只是UIE和NVIC配置之后NVIC看到了它。结论老师说出现这个现象的原因是由于“TIMx-EGR TIM_PSCReloadMode_Immediate” 这行代码。其实应该说是对的。因为确实是这一行代码导致了Flag被置1。我之前认为如果是这一行造成的问题那么注释掉它那这个现象应该消失。这个推断看起来是不对的。因为没有了这一行会产生其他问题造成类似的现象。总之这里有一个正确的操作初始化一个外设之后执行清Flag或者清中断的操作防止一开始出现不期望看到的状态。库函数封装很好但是确实藏了很多我们不知道的东西啊。。。

相关新闻

OpenCADStudio参数化设计:几何约束与尺寸约束的完整指南,告别手动修改图形

OpenCADStudio参数化设计:几何约束与尺寸约束的完整指南,告别手动修改图形

OpenCADStudio参数化设计:几何约束与尺寸约束的完整指南,告别手动修改图形 【免费下载链接】OpenCADStudio A CAD application built with Rust — 2D/3D drawing, DWG/DXF support, and GPU-accelerated rendering 项目地址: https://gitcode.com/gh_…

2026/10/4 19:33:31 阅读更多 →
ESP32实战:从Demo到AI硬件的8个工程坑

ESP32实战:从Demo到AI硬件的8个工程坑

前几天在群里看见一个演示视频:一块 ESP32 开发板,接上一个免费的云端大模型 API,有人对着板子喊了一句“今天室温多少”,几秒钟后小喇叭里传出了 AI 的回答。评论区一片“AI 硬件就这么成了”。说实话,我第一眼也心动…

2026/10/4 19:33:31 阅读更多 →
10.1--笔记和作业

10.1--笔记和作业

格式<!--注释--> 格式用来写注释ctrlz 撤销ctrl/ 快速注释<!DOCTYPE html> h5文档说明字符编码常用:lang学习网站标准结构快捷写法 输入&#xff1a;&#xff01;然后回车快速删除 行&#xff1a;ctrlshiftkshiftalt上下 快速复制一行作业

2026/10/4 19:33:31 阅读更多 →

最新新闻

前端静态资产去中心化自动化流水线:GitHub Actions 一键构建并 Pinning 至 IPFS

前端静态资产去中心化自动化流水线:GitHub Actions 一键构建并 Pinning 至 IPFS

前端静态资产去中心化自动化流水线&#xff1a;GitHub Actions 一键构建并 Pinning 至 IPFS在去中心化应用&#xff08;DApp&#xff09;的工程化演进中&#xff0c;前端运维往往是最容易被忽视的“阿喀琉斯之踵”。不少团队在底层智能合约上实现了自动化测试与多签部署流水线&…

2026/10/4 20:15:01 阅读更多 →
MyBatis Plus接入项目实战:从依赖配置到常见坑排查全流程

MyBatis Plus接入项目实战:从依赖配置到常见坑排查全流程

MyBatis Plus 接入项目实战&#xff1a;从零到一的全流程记录做后端开发这几年&#xff0c;我接手过不少老项目&#xff0c;也从头搭过好几个新服务。说到 ORM 框架选型&#xff0c;MyBatis 一直是国内团队的绝对主力&#xff0c;但有一个绕不开的痛点&#xff1a;单表 CRUD 你…

2026/10/4 20:15:01 阅读更多 →
搜索算法完整路线图:从二分查找到麻雀与原子搜索算法

搜索算法完整路线图:从二分查找到麻雀与原子搜索算法

SCAU算法设计与分析这门课&#xff0c;是我第一次系统接触“搜索算法”这个名字的起点。当时只觉得“搜”这个动作很日常——在数组里找个数、在地图里找条路&#xff0c;但后来才发现&#xff0c;搜索算法几乎是整个计算机底层逻辑的骨架&#xff1a;数据库查询、推荐系统召回…

2026/10/4 20:15:01 阅读更多 →
MySQL 8.0.43安装保姆级教程:三大平台一次搞定

MySQL 8.0.43安装保姆级教程:三大平台一次搞定

这篇保姆级教程不是心血来潮&#xff0c;而是我这些年被问得最多的问题之一。装 MySQL 这件事&#xff0c;教材里永远只讲"下一步下一步"&#xff0c;但现实中每个操作系统都有自己的脾气&#xff0c;从下载源到权限设置到服务启动&#xff0c;任何一步不对都能卡你半…

2026/10/4 20:15:01 阅读更多 →
Flask进销存系统实战:核心表结构、库存流水与并发控制

Flask进销存系统实战:核心表结构、库存流水与并发控制

作为一个常年折腾后端业务系统的人&#xff0c;我接到过不少类似的单子&#xff1a;Python Flask 进销存。这看起来是个老生常谈的组合&#xff0c;但真正动手做的时候&#xff0c;才发现坑全藏在细节里。这次分享的项目是一个给某精品品牌企业用的进销存系统&#xff0c;品牌…

2026/10/4 20:15:01 阅读更多 →
AI编程工具信创环境适配指南:Codex 到国产化部署的完整实践与 TaoToken 统一接入

AI编程工具信创环境适配指南:Codex 到国产化部署的完整实践与 TaoToken 统一接入

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

2026/10/4 20:14:01 阅读更多 →

日新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

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

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

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

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

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

2026/10/4 1:00:58 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

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

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

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

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

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

2026/10/4 1:00:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/4 11:40:45 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/4 9:43:54 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/4 20:14:29 阅读更多 →