ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

STM32定时器时间基准:从时钟树到PSC/ARR的完整计算指南

STM32定时器时间基准:从时钟树到PSC/ARR的完整计算指南 1. 从定时器到底在数什么这个问题说起很多人第一次接触 STM32 的定时器脑子里冒出来的第一个念头就是配置个 PSC 和 ARR然后就能定时了。代码能跑灯能闪串口能按周期发数据看起来一切正常。但如果你被问到一句你这个定时器到底在数什么它数一个数代表多长时间——不少人会卡壳。我自己当年也是这样。用 CubeMX 勾勾选选PSC 填 7199ARR 填 9999然后告诉自己这是 1 秒定时至于为什么是 1 秒心里其实没底。后来做电机控制、做输入捕获测频率、做 PWM 死区配置的时候才发现如果对时间基准从哪来这件事没有彻底想清楚后面所有的计算都是空中楼阁。这篇内容就围绕一个核心问题展开STM32 的定时器本质上是在对什么计数这个计数的节拍又是从哪里来的。我会把时钟树、PSC、ARR、计数模式、更新事件这几件事串成一条线讲清楚并且给出可以直接抄的计算方法和几个我实际踩过的坑。适合已经会点灯、会配置基本定时器但想把底层逻辑彻底理顺的嵌入式开发者也适合正在做电机控制、频率测量、PWM 输出这类对时间精度敏感的项目的人。关键词里出现的 STM32、TIM1、PSC、ARR基本就是这条主线上的四个关键角色。下面我们一个一个拆。2. 定时器的心跳时钟源是怎么一路送到计数器上的2.1 计数器数的不是时间是时钟脉冲先把一个最容易被忽略的认知摆正定时器里的计数器CNT数的不是秒也不是毫秒它数的是时钟脉冲的个数。每来一个有效的时钟边沿CNT 就加一或减一。所以定时这件事本质上是数够多少个脉冲。这就引出了两个必须回答的问题这个脉冲的频率是多少数到多少个脉冲算一轮第一个问题由时钟源 预分频器 PSC决定第二个问题由自动重装载寄存器 ARR决定。把这两个问题回答清楚定时时间就是一道乘法题。2.2 时钟从哪来从系统时钟到定时器时钟以最常见的 STM32F103 为例定时器的时钟并不是凭空产生的它来自系统时钟树。典型路径是这样的外部晶振常见 8MHz经过 PLL 倍频得到SYSCLK常见 72MHz。SYSCLK 经过 AHB 预分频器得到HCLK常见 72MHz。HCLK 再经过 APB 预分频器得到PCLK1 / PCLK2。这里有一个非常关键的规则很多人第一次看时钟树会看漏当 APB 预分频系数为 1 时定时器时钟 PCLK当 APB 预分频系数不为 1即 2、4、8、16时定时器时钟 PCLK × 2。也就是说APB 分频器在给外设降速的同时会额外给定时器时钟做一次倍频补偿。以 F103 为例APB1 通常分频为 2PCLK1 36MHz那么挂在 APB1 上的定时器TIM2~TIM7实际时钟是72MHzAPB2 分频为 1PCLK2 72MHz挂在 APB2 上的 TIM1、TIM8 时钟也是72MHz。所以你在算定时时间之前第一件事是确认我这个定时器挂在哪个总线上它的输入时钟到底是多少。这一步搞错后面全错。2.3 一张表看清常见型号的定时器时钟定时器挂载总线常见 APB 分频定时器时钟F103 72MHzTIM1 / TIM8APB2172 MHzTIM2~TIM7APB1272 MHzTIM6 / TIM7基本定时器APB1272 MHz注意 TIM6/TIM7 是基本定时器只能向上计数、没有捕获比较通道但时钟来源规则和通用定时器一致。做纯定时中断时它们其实很好用资源占用少。2.4 为什么 TIM1 经常被单独拿出来说TIM1 是高级定时器除了通用定时器的功能外还带互补输出、死区插入、刹车输入等常用于电机控制和 PWM 场景。它的时钟挂在 APB2 上通常就是系统主频所以在做高精度 PWM 或者高频捕获时TIM1 的时钟余量更大。热搜词里出现TIM1 update 中断 中心对齐说的就是 TIM1 在中心对齐模式下更新事件的产生时机问题这个后面会专门讲。3. PSC 和 ARR把时钟减速再数满的两级齿轮3.1 PSC 是预分频器不是分频系数本身很多人把 PSC 直接当成分频系数严格说不够准确。PSC 寄存器里存的值实际分频系数是PSC 1。原因很简单计数器从 0 开始计。你写 PSC 0就是 1 分频时钟直接进计数器写 PSC 1就是 2 分频。所以定时器的计数频率公式是计数频率 定时器时钟 / (PSC 1)以 72MHz 时钟、PSC 71 为例计数频率 72,000,000 / (71 1) 1,000,000 Hz 1 MHz也就是每 1 微秒CNT 加一。这个 1MHz 的节拍就是很多人做微秒级延时或者捕获时的基准尺。3.2 ARR 决定数到多少算一轮ARR 是自动重装载寄存器。计数器数到 ARR 的值后会产生溢出更新事件然后自动回到 0 重新开始向上计数模式。同样地实际计数的周期数是ARR 1。所以一轮定时的总时间定时时间 (PSC 1) × (ARR 1) / 定时器时钟反过来如果我要一个 1ms 的定时中断时钟 72MHz先定 PSC比如让计数频率为 1MHz则 PSC 71。1ms 需要数 1000 个脉冲所以 ARR 1 1000ARR 999。这就是PSC 填 7199、ARR 填 9999 得到 1 秒的由来72MHz / 7200 10kHz10kHz 数 10000 个 1 秒。理解了公式就不用死记硬背这些数字了。3.3 PSC 和 ARR 的分配策略为什么不是随便填既然 PSC 和 ARR 都能调为什么还要讲究怎么分配因为两者各有约束PSC 是 16 位寄存器最大值 65535所以单级分频最多 65536。ARR 也是 16 位部分型号如 F4/F7 的某些定时器是 32 位最大值同样受限。如果需要的定时时间很长单靠一级分频不够就要 PSC 和 ARR 配合。举个实际例子72MHz 时钟要 10 秒定时。若 PSC 719910kHz则 ARR 1 100000超过 65536不行。若 PSC 7199 不够那就加大 PSCPSC 65535分频 65536计数频率约 1098.6HzARR 1 10986可行。我的经验是优先让计数频率落在一个好算的整数上比如 1MHz、10kHz这样 ARR 的值直观调试时心里有数。只有在定时时间特别长、或者需要极高分辨率时才去精细分配。3.4 一个容易忽略的细节影子寄存器PSC 和 ARR 都有影子寄存器shadow register。你写入的新值不会立刻生效而是在下一个更新事件时才被真正加载。这个机制的好处是避免计数过程中参数突变导致输出异常但在动态改频率时容易让人困惑——我明明改了 ARR怎么这轮还是老周期解决办法是改完之后手动触发一次更新事件置位 UG 位让新值立即生效。这个技巧在做可变频率 PWM 或者动态调速时非常有用。4. 计数模式与更新事件定时器数满一圈之后发生什么4.1 三种计数模式的区别STM32 通用/高级定时器支持三种计数模式向上计数CNT 从 0 数到 ARR溢出后回 0。向下计数CNT 从 ARR 数到 0下溢后回 ARR。中心对齐向上/向下CNT 先向上数到 ARR再向下数到 0如此往复。中心对齐模式在电机控制里非常常见因为它产生的 PWM 波形是对称的谐波特性更好也更适合配合死区控制。但它的更新事件产生时机和向上计数不一样——中心对齐模式下更新事件在 CNT 到达 0 和到达 ARR 时都可能产生具体取决于配置。这就是热搜里TIM1 update 中断 中心对齐这个问题的来源很多人按向上计数的经验去算中断频率结果发现中心对齐下中断频率翻倍或者对不上。4.2 更新事件到底触发了什么更新事件Update Event是一个一圈结束的信号它会触发以下几件事把 PSC 和 ARR 的影子寄存器加载新值。如果使能了更新中断UIE产生中断。如果使能了更新 DMA 请求UDE产生 DMA 请求。在中心对齐模式下更新事件的产生点需要特别注意。所以定时中断的本质就是利用更新事件产生中断。你配置的定时周期就是更新事件的产生周期。4.3 中心对齐模式下中断频率的计算假设时钟 72MHzPSC 0不分频ARR 999中心对齐模式。向上数0 → 999共 1000 个计数。向下数999 → 0共 1000 个计数。一个完整周期 2000 个计数。如果更新事件在每个完整周期产生一次那么中断频率 72MHz / 2000 36kHz。但如果配置成上下溢都产生更新事件频率就翻倍。这就是为什么同样参数中心对齐下中断频率和向上计数不一样。提示做中心对齐 PWM 时建议先用示波器或者翻转 IO 的方式实测中断频率不要纯靠公式推因为更新事件的产生点还受重复计数器RCR高级定时器才有影响。4.4 重复计数器 RCR高级定时器的额外一层TIM1、TIM8 这类高级定时器有一个重复计数器 RCR。它的作用是每经过 (RCR 1) 个计数周期才产生一次更新事件。这相当于在 PSC 和 ARR 之外又加了一层降频。在中心对齐 PWM 场景下RCR 常被用来让更新中断只在每个完整 PWM 周期的特定点产生一次避免中断过于频繁。这个寄存器在通用定时器上是没有的所以从 TIM2 换到 TIM1 时行为可能不一样需要留意。5. 把公式用起来几个真实场景的完整计算5.1 场景一1kHz 定时中断需求每 1ms 进一次中断做任务调度。时钟 72MHz。取 PSC 71计数频率 1MHz。1ms 1000 个计数ARR 999。配置PSC 71, ARR 999向上计数使能更新中断。5.2 场景二输入捕获测频率需求测量外部方波频率范围 1Hz ~ 100kHz。思路用输入捕获在捕获中断里读取两次捕获值差值就是周期内的计数个数。时钟 72MHzPSC 71计数频率 1MHz每计数 1 微秒。若两次捕获差值为 N则信号周期 N 微秒频率 1,000,000 / N Hz。这里 PSC 的选择很关键如果被测频率很高比如 100kHz周期 10 微秒N 只有 10分辨率太低误差大。这时应该减小 PSC提高计数频率比如 PSC 0计数频率 72MHzN 720分辨率就上来了。测频时计数频率要远高于被测频率这是基本原则。5.3 场景三PWM 输出控制电机需求输出 20kHz PWM占空比可调。时钟 72MHz。20kHz 周期 50 微秒。取 PSC 0计数频率 72MHzARR 1 72,000,000 / 20,000 3600ARR 3599。占空比由 CCR 决定CCR / (ARR 1) 占空比。比如要 50% 占空比CCR 1800。这里有个经验PWM 频率和分辨率是一对矛盾。频率越高ARR 越小可调的占空比档位越少。20kHz 下 ARR 3599有 3600 档够用但如果做到 100kHzARR 只有 719分辨率就粗糙了。选型时要根据实际需求平衡。5.4 场景四长延时比如 60 秒时钟 72MHz。PSC 65535分频 65536计数频率 ≈ 1098.6Hz。60 秒需要计数 65918 个ARR 65917超过 65535还是不行。这时要么用 32 位定时器如 F4 的 TIM2/TIM5要么在中断里再软件计数。16 位定时器做超长定时软件累加是常规做法但要注意累加变量的类型和中断优先级避免计数丢失。6. 那些年我在时间基准上踩过的坑6.1 坑一忘了 APB 分频的倍频规则第一次用 F103 配 TIM3我以为 PCLK1 36MHz就按 36MHz 算 PSC结果定时时间差了一倍。后来才想起来 APB1 分频不为 1 时定时器时钟是 PCLK1 × 2 72MHz。这个规则在时钟树图上写得很清楚但很容易被忽略。避坑方法配置前先确认 APB 预分频系数再套用倍频规则或者直接用 CubeMX 生成的时钟树界面看定时器时钟。6.2 坑二动态改 ARR 不生效做可变频率输出时我在运行中改 ARR发现要等一个周期才生效导致频率切换有延迟。原因是影子寄存器机制。解决办法是改完 ARR 后置位 UG 位强制更新。TIM3-ARR new_value; TIM3-EGR | TIM_EGR_UG; // 立即加载影子寄存器注意置位 UG 也会产生一次更新事件如果使能了中断会立刻进一次中断要处理好这个额外的中断。6.3 坑三中心对齐下中断频率算错前面提过中心对齐模式下更新事件的产生点和向上计数不同。我一开始按向上计数算中断频率对不上任务调度节奏全乱。后来用 IO 翻转配合示波器实测才把频率确认下来。经验涉及中心对齐、RCR 的场景公式只能给个大概实测最靠谱。6.4 坑四PSC 和 ARR 都取最大值仍不够做超长定时时我一度以为 PSC 和 ARR 都拉满就能覆盖所有需求结果发现 16 位定时器的极限也就那么多。后来改用软件累加或者换 32 位定时器。经验选型阶段就要估算最长定时需求别等到写代码时才发现寄存器不够用。6.5 坑五中断优先级和计数丢失在软件累加做长定时时如果这个定时器中断被更高优先级中断长时间阻塞累加就会丢。解决方法是合理设置中断优先级或者用硬件定时器直接产生长周期32 位定时器。7. 把时间基准这件事彻底内化的几个建议7.1 养成先算时钟再配参数的习惯不要一上来就抄别人的 PSC、ARR。先问自己三个问题这个定时器挂在哪条总线上它的输入时钟是多少我要的定时时间/频率是多少把这三个问题回答清楚PSC 和 ARR 自然就出来了。7.2 用表格管理你的定时器配置项目里定时器一多很容易乱。我习惯用一个表格记录每个定时器的用途、时钟、PSC、ARR、中断频率调试时一目了然。定时器用途时钟PSCARR中断频率TIM2系统滴答72MHz719991kHzTIM3PWM 输出72MHz0359920kHzTIM4输入捕获72MHz7165535—7.3 善用 CubeMX 的时钟树视图CubeMX 的时钟树界面会直接显示每个定时器的输入时钟配置时对照着看能避免很多计算错误。但要注意CubeMX 只帮你算时钟PSC 和 ARR 还是要自己根据需求填。7.4 调试时先翻转 IO 验证不确定定时器配置对不对时最直接的办法是在中断里翻转一个 IO用示波器或者逻辑分析仪看波形。频率对不对一眼就知道。这比盯着代码算半天靠谱得多。7.5 理解时间基准是很多功能的地基输入捕获测频率、PWM 输出、电机换相、编码器接口、DMA 触发……这些功能全都建立在定时器数什么、数多快这个基础之上。把这个地基打牢后面学什么定时器应用都会快很多。我在实际项目里最深的一个体会是定时器用得好不好不取决于你会不会调库函数而取决于你对时钟和计数这两件事的理解有多深。库函数只是把寄存器操作包装了一下底层逻辑没变。当你哪天能不看手册就大致说出这个定时器现在数一个数代表多少时间那才算真正把定时器用明白了。最后分享一个小技巧如果你手头有示波器不妨拿一个定时器做实验把 PSC 和 ARR 改几组值实测中断频率和公式对一对。这种动手验证的过程比看十遍手册都管用。
返回列表