资讯动态

定时器从模式复位:PWM周期与占空比测量方案详解

发布时间:2026/10/20 11:20:45 来源:尧图企业网站定制
做PWM测量这活儿很多做嵌入式开发的朋友迟早都会碰到。不管是电机调速信号、舵机PWM、还是传感器输出的占空比变化拿到一个脉冲波形第一件事就是想知道它的周期和占空比是多少。标题里这个从模式测量脉冲周期、占空比的做法是MCU定时器输入捕获里一个非常实用且高效的方案。用一句话概括它的核心思路利用定时器从模式里的复位功能让计数器在PWM每个周期开始时自动清零硬件自动帮你把周期和高电平时间分别存进两个捕获寄存器里CPU只需要在中断里读两个数再做一次除法就能算出频率和占空比。这篇文章会从原理拆到寄存器配置再到中断/DMA处理和实际踩过的坑按我平时调试的顺序来写。如果你正在用带输入捕获功能的MCU做信号测量或者被多通道采集搞得焦头烂额这篇文章应该能帮你少走不少弯路。1. 从模式测量方案的设计思路与底层原理1.1 传统输入捕获方案的痛点常规的输入捕获测量PWM大家第一反应都是开两个通道一个捕获上升沿一个捕获下降沿。比如通道1上升沿进中断记下计数器值CCR1通道2下降沿进中断记下CCR2下一次上升沿再进中断记下CCR3。然后周期等于CCR3减CCR1高电平时间等于CCR2减CCR1。逻辑上完全通但只要实际去写代码很快就发现几个问题。边沿和计数器清零不同步。传统方案里CNT计数器是自由运行的它不会因为你测到一个上升沿就自动归零。所以你每次处理中断都得自己保存上一次边沿的计数值然后用当前值减上次值来算差值。这个差值本身没问题问题在于如果中间有别的中断抢占或者你的处理函数执行时间长了点可能导致现场保存不完整。更麻烦的是不同边沿事件的先后关系需要软件自己维护稍微一个疏忽算出来的周期就可能是负值或者异常大的数字。中断次数多。两个通道都开中断的话一个PWM周期至少进两次中断。假设PWM频率是20kHz那一秒就是4万次中断每次中断还得判断是哪个通道触发的、分支处理、更新变量。CPU开销不小而且测量实时性完全依赖中断响应速度。还有一点容易被忽略传统的上升沿差值相减方案累计误差会随着信号频率提高而放大。因为CNT一直在跑你在中断里读到的CCR值和你实际边沿发生的时刻之间天然存在几个时钟周期的延迟两个差值一减误差可能叠加。1.2 从模式复位让计数器自己回到起点从模式复位方案能从根本上解决上面这些问题。它利用的是定时器的一个内部联动机制当外部输入的触发信号比如PWM上升沿到达时定时器自动把CNT计数器清零同时触发对应的捕获通道把当前CNT值锁存到CCR寄存器里。这里要重点理解两个动作是硬件同步完成的CNT被清零的时刻正是PWM上升沿发生的时刻同一个时刻CCR1锁存的是计数器清零前的旧值这个值恰好就是PWM一个完整周期内的计数个数。然后在PWM下降沿到达时CCR2锁存的是从上升沿到下降沿之间的计数个数也就是高电平脉宽。因为计数器只在每个PWM周期开始时复位所以后一个CCR1值就是当前最新周期前一个周期的CCR1就是上上个周期不需要软件做减法、不需要保存历史值。一次PWM周期硬件自动给出两个数据CCR1 周期计数值CCR2 高电平计数值频率和占空比的计算就变成了一个纯粹的算术问题。更妙的是这种方案只需要在读数据时开一个中断甚至可以用DMA把数据搬走CPU几乎不参与边沿处理。1.3 为什么从模式比双通道独立捕获更值得用有人会说我双通道方案也能测何必非要用从模式。我的看法是如果你只测一路信号、频率不高、对精度没有逼到极限用哪个确实差别不大。但从模式方案有三个优势是独立捕获方案很难替代的第一是相位一致性。旧方案里CCR1和CCR2来自不同的PWM周期严格说你的周期和新周期的高电平时间并不是同一条波形的数据。从模式复位方案里CCR1和CCR2在同一个周期内被锁存数据天然是配对的这对分析动态变化信号非常关键。第二是省时省心。从模式方案里上升沿触发复位后软件不需要每次中断都做差值计算读出来直接用省去的不仅仅是几条指令更省去了维护边沿状态机的逻辑复杂度。第三是误差更小。从模式复位在第0个计数值开始计时测量窗口是严格对齐波形边沿的不会像自由运行计数器那样周期起点是随机的。只要你预分频设置合理测量误差基本就是计数时钟的一个量化单位不会累加。不过它也有自己的局限性。比如占空比接近0%或100%时边沿缺失会导致数据不更新需要额外的超时机制。再比如触发信号经过内部同步电路会有几个时钟周期的延迟这些都会影响极限测量。后面在问题排查部分细说。2. 硬件资源规划与关键参数计算2.1 选择定时器和引脚时的几条硬性条件不是随便拿个定时器就能做这个方案的。使用从模式复位测量PWM硬件上至少要满足三个条件触发源必须来自定时器的通道1输入。以通用MCU的定时器为例定时器的触发输入TRGI可以映射到多种信号源但最常用、最容易配置成复位触发的是TI1FP1也就是通道1输入经过滤波和边沿检测后的信号。通道2的信号通常不能直接作为从模式触发源所以这个方案的硬件前提必然是PWM信号接到定时器的CH1引脚上。通道1和通道2必须同时能捕获。这意味着你需要一个拥有至少两个捕获通道的定时器而且两个通道的引脚最好都引出来。CH1用于上升沿触发周期捕获CH2用于下降沿捕获。如果你的板子上CH1引脚被别的功能占了这个方案就得改换定时器。引脚复用要查清楚。很多MCU同一个引脚可以复用成不同外设功能选定时器前先看数据手册的AFAlternate Function映射表。我自己的习惯是打开CubeMX或者参考手册的外设引脚图先把目标定时器的CH1/CH2对应的引脚号全部列出来再对照实际原理图做勾选避免焊好板子才发现引脚冲突。有一个经常踩的坑是有些定时器的CH1和CH2不能同时使用同一个输入源进行捕获映射。比如对于某些MCUCH2要么映射到自己的TI2输入线要么映射到TI1输入线它可以选择但你要保证CH1和CH2捕获的是同一个外部信号就必须让CH2的捕获映射指向TI1。这部分涉及的寄存器是CCMR1里的IC2SEL位段后面配置章节会写到。2.2 定时器时钟、预分频与计数频率搭配参数计算是整个方案里最考验经验的部分。核心变量有三个定时器输入时钟、预分频值PSC以及由此得到的计数频率。计数频率决定了测量的分辨率而分辨率会直接影响占空比和频率读取的精度。举个例子。假设定时器时钟是72MHz不分频的情况下计数频率就是72MHz每个计数脉冲对应的时间是13.9ns。这意味着你能分辨的最小脉宽变化就是13.9ns听起来很厉害。但问题来了16位计数器的最大值是65535用72MHz计数一个超过0.91ms的周期就会溢出。也就是说信号频率低于约1.1kHz时如果不启用32位计数器模式直接就爆表了。所以参数选择的原则应该是在保证不溢出的前提下尽量让周期计数值CCR1落在1000到10000这个区间。这样做的原因有三个CCR1太小比如小于100量化误差占比大测出来的占空比可能就是99%和100%这种粗糙跳变CCR1太大接近计数上限意味着计数频率太低软件读取时稍稍延迟一点就可能导致CCR1刚好等于上一次的值没来得及更新CCR1在1000以上占空比的分辨率能优于0.1%对绝大多数PWM控制类应用已经够了。计算思路可以这样走。先估一下被测信号的频率范围。比如要测1kHz的PWM方案A不分频计数频率72MHzCCR1约7200016位计数器会溢出必须开32位模式如果芯片支持或者用更大的预分频方案B预分频设为71计数频率变成1MHzCCR1约1000分辨率1us方案C预分频设为719计数频率100kHzCCR1100分辨率10us此时占空比分辨率只有0.1%略显粗糙。一般我选方案B。要测100kHz的高频PWM那就不分频或预分频设为7计数频率9MHzCCR190此时量化误差是11个百分点的最大误差精度确实不乐观。高频PWM用这种单定时器方案本身就有限制推荐用外部高速信号采样、比较器定时器门控等方法那就超出本文范围了。预分频值和计数频率的关系式是计数频率 定时器时钟频率 / (预分频值 1)周期测量分辨率 1 / 计数频率理论上CCR1最大能到2的计数位宽减1所以要保证被测信号频率 × (2^计数位宽 - 1) ≥ 计数频率比如16位计数器、计数频率1MHz则最高可测周期计数值65535对应最低频率约15.26Hz。低于这个频率的PWM就会溢出需要降低计数频率或改成32位模式。2.3 精度分析与极限情况从模式复位方案的精度主要由三部分构成计数量化误差。一次测量最多差一个计数脉冲折合成时间为一个计数周期。如果你的计数频率是1MHz那么周期误差最多1us占空比误差视周期长短而定。内部同步延迟误差。输入信号通过MCU的IO口进入定时器输入路径经过触发检测和同步电路最终产生复位和捕获动作这个路径上会有固定的几个时钟周期延迟。好在CCR1和CCR2的锁存发生在同一次触发信号链路上两者的相对关系不受影响所以占空比误差不受同步延迟影响只有周期的绝对测量值会带一点系统性偏移。滤波引起的边沿延迟。如果你开了输入滤波ICF字段滤波本身会引入滤波采样级数的延迟。从模式测量对滤波要求比较苛刻因为滤波器的延迟会导致CNT复位的时刻和CCR1捕获时刻之间的微小间隙虽然实际工程中通常可以忽略但高精度计量场景下要注意。我把工程上给的建议直接列成一张表被测频率范围建议计数频率16位模式可用性备注10Hz ~ 100Hz10kHz ~ 100kHz可用低频率CRC注意溢出100Hz ~ 1kHz100kHz ~ 1MHz可用CCR1控制在1000~50001kHz ~ 10kHz1MHz ~ 10MHz视CCR1值不一定够推荐32位计数器10kHz ~ 100kHz10MHz以上不够用必须32位或降低分辨率要求100kHz以上定时器最高时钟通常不够量化误差大慎用这张表是我拍脑袋定的大致区间实际要结合CCR1数值来看但方向和思路是对的宁可降低计数频率也不要让CNT轻易溢出同时保证占空比分辨率在可接受范围内。3. 从模式复位测量的配置与代码实现3.1 寄存器级配置步骤下面按我平时写底层驱动的习惯以通用定时器为例把从模式复位的完整配置过程过一遍。不依赖具体芯片厂商的库直接操作寄存器这样在哪个平台都能翻译过去。第一步配置GPIO复用。把定时器CH1和CH2对应的引脚设置为复用功能并选择正确的复用编号。这步在CubeMX里就是点几个下拉框的事但手写寄存器时要查AF映射表别填错。// 以某MCU为例假设CH1引脚在PA0CH2在PA1复用编号为AF1 GPIOA-MODER | (0x2 0) | (0x2 2); // PA0, PA1设置为复用模式 GPIOA-OSPEEDR | (0x3 0) | (0x3 2); // 高速模式适合高频输入 GPIOA-AFR[0] | (0x1 0) | (0x1 4); // AF1 - 定时器通道第二步配置时基。这里的关键是预分频值PSC按照前面算好的计数频率来填。还有一个容易忽略的地方无论你用不用定时器的自动重载功能ARR寄存器不能保持默认值不变应该设置成一个安全的大值防止计数器溢出时出问题。如果用16位计数器ARR直接设成0xFFFF用32位计数器可以设成0xFFFFFFFF。TIM2-PSC 71; // 72MHz输入时钟分频后计数频率1MHz TIM2-ARR 0xFFFFFFFF; // 根据定时器位宽调整给足余量第三步配置通道映射。这是这个方案的命门。CCMR1寄存器决定两个通道的输入源IC1要映射到TI1IC2也要映射到TI1。也就是说通道2捕获的必须是同一个外部信号经过内部输入线过来的版本而不是它自己的另一个引脚输入。TIM2-CCMR1 | (0x1 0); // IC1映射到TI1 TIM2-CCMR1 | (0x1 8); // IC2映射到TI1关键第四步配置边沿极性和滤波。CCER寄存器里CC1P位和CC2P位分别控制两个通道的有效边沿。在这个方案里CC1触发周期捕获必须配置为上升沿有效CC2脉宽捕获必须配置为下降沿有效。同时CCER里要把两个通道的输出使能位置1否则比较捕获不工作。TIM2-CCER | (0x1 0); // CC1E1使能通道1捕获 TIM2-CCER | (0x0 1); // CC1P0上升沿有效 TIM2-CCER | (0x1 4); // CC2E1使能通道2捕获 TIM2-CCER | (0x1 5); // CC2P1下降沿有效第五步配置从模式和触发源。SMCR寄存器里TS字段选择触发源为TI1FP1SMS字段选择复位模式。这里要注意TS和SMS的配置顺序没有强制要求但建议先写TS再写SMS因为有些芯片内部同步逻辑在从模式切换的瞬间可能出错。TIM2-SMCR | (0x5 4); // TS101选择TI1FP1作为触发源 TIM2-SMCR | (0x4 0); // SMS100复位模式第六步使能定时器。CR1的CEN位置1定时器开始运行。TIM2-CR1 | (0x1 0);3.2 中断、DMA与数据读取时机配置完成后测量已经由硬件自动完成了软件要做的只是把CCR1和CCR2读出来算结果。在这之前要把数据读取的通道选好。优先推荐在CC2中断下降沿里读取。原因是下降沿到来时CCR2刚完成对本次PWM高电平脉宽的锁存而CCR1在本次周期上升沿时也已经更新完毕。此时两个寄存器的值对应的是同一条PWM周期数据对最整齐。有人习惯在CC1中断上升沿里读理由是CC1事件同时包含了复位动作读CCR1肯定是最新鲜的。但CC1中断发生在周期开始时此刻CCR2还是上一个周期的脉宽值如果你想分析每个周期的独立变化这里的数据就错了半个周期。除非实际测试中发现PWM非常稳定否则还是推荐CC2中断。开启中断的配置很简单TIM2-DIER | (0x1 2); // CC2IE使能通道2捕获中断 NVIC_EnableIRQ(TIM2_IRQn);中断服务函数里顺序很重要。先关对应的中断标志位再读数据防止读的过程中又进来一次中断覆盖掉捕获寄存器。不过捕获寄存器是硬件锁存的就算再来一次新捕获也只是把值更新为新值你读的时候拿到的总是最新值所以严格说先读后清也问题不大但规范一点还是先清再读。void TIM2_IRQHandler(void) { if (TIM2-SR (0x1 2)) { TIM2-SR ~(0x1 2); // 清CC2中断标志 period TIM2-CCR1; pulse TIM2-CCR2; // 到这里period是当前周期计数pulse是当前高电平计数 // 占空比百分比 pulse * 100 / period // 频率 计数频率 / period } }如果你觉得中断太频繁尤其是测量频率超过几十kHz时可以改成DMA搬运方案。把DMA的源地址设为CCR2寄存器目标地址设为内存中的一个变量触发源选择定时器通道2捕获事件开启循环模式。每次下降沿到来硬件自动把CCR2值搬到内存完全不用CPU参与。同时需要再开一个DMA搬运CCR1或者用DMA的半传输/全传输中断定期处理一批数据。这个方案对高频PWM测量特别有用CPU占用几乎为零。DMA方式的缺点是占用两个DMA通道而且你要控制好DMA的传输时序避免两个通道的数据错位。所以在信号频率不高时我还是推荐用中断简单可靠出问题好排查。3.3 频率和占空比计算公式与溢出处理读取到CCR1和CCR2之后计算本身并不复杂。核心公式就两个周期 CCR1 / 计数频率高电平时间 CCR2 / 计数频率频率 计数频率 / CCR1占空比 CCR2 / CCR1 × 100%实际写代码时建议先判断CCR1是否为零。理论上CCR1最小是1但如果信号在触发的瞬间有毛刺硬件可能在半个计数周期内完成复位和捕获CCR1会被锁存为0或1这样的怪异值。所以加一个异常值过滤是必要的。还有一点CCR1和CCR2都是定点整数做占空比除法时如果先算百分比再取整小信号周期下误差会被放大。我常用的做法是先乘以10000再除保留两位小数。比如uint32_t duty_x10000 pulse * 10000 / period; // 结果duty_x10000 / 100就是百分比的整数部分%100就是小数部分频率计算上直接把计数频率除以CCR1即可。但如果信号频率极低CCR1非常大用一个除法可能损失精度。建议用浮点或者定点转换或者反过来直接显示周期时间。工程上我经常两个都算出来频率和周期都展示方便验证。溢出处理是一个经常被忽略的点。虽然ARR设成了大值但CNT不会无限增长到了ARR就会触发更新事件。在复位模式下每次有效上升沿都会把CNT清零所以正常情况下CNT不会到达ARR。除非输入信号频率太低等待上升沿的时间超过了ARR对应的最大计数值。这时你需要用一个更新中断UEV来做超时保护避免CCR1和CCR2很长时间不更新但占空比计算还在拿旧数据算。开启更新中断的方式很简单TIM2-DIER | (0x1 0); // UIE在更新中断里可以做一个标记如果CCR1很长时间没有变化说明信号可能丢失或者已经低于可测频率下限这时应该停止测量并给出告警。这个设计在实际项目里很重要尤其在产品上电自检阶段能帮你快速判断是否有外设没连接好。4. 常见问题与排查流程4.1 占空比固定为0%或100%时的表现这是从模式方案最典型的边界场景。假设PWM输出始终为高电平也就是100%占空比。那么信号的上升沿只会出现一次之后再也没有新的上升沿和下降沿。计数器CNT虽然在持续计数但因为没有新的触发边沿不会再复位CCR2一直保留的是上上个周期如果有的话的下降沿值。如果你只靠CC2中断去读取数据程序就会卡在读不到新数据的窘境里。解决思路是加超时机制。利用更新中断来判断如果CNT溢出且没有新的捕获事件发生可以认为输入信号要么是恒高、要么是恒低。然后通过读取GPIO的IDR寄存器判断当前电平读取为高电平占空比应为100%周期值沿用CCR1里保存的历史周期读取为低电平占空比应为0%周期值同样沿用历史值。这招是实测过比较好用的方法。有一点要注意GPIO的IDR读到的电平是经过施密特触发器整形后的电平对于弱上拉/弱下拉信号如果你GPIO没有配置上拉读出来的可能是随机值。所以用于检测电平的引脚应该配置为带上拉输入或者外部加一个确定电平的上下拉电阻。4.2 从模式触发不工作测量值一直为零这个问题十有八九出在SMCR寄存器配置或者CC2映射上。按照我的排查顺序来先看TS和SMS是不是都写对了。很多人只配了SMS复位模式忘了TS选TI1FP1。这种情况定时器根本不知道去哪里取触发信号复位永远不会发生。再看CCMR1的IC2SEL。如果在CubeMX里只是简单地把两个通道都选成输入捕获直接模式默认状态下IC2会映射到TI2也就是CH2的独立引脚。如果你的PWM信号只接了CH1引脚那CC2捕获到的永远是上一时刻CH2引脚的电平边沿数据完全是乱的。必须显式把IC2的映射源改成TI1。还要确认CCER的极性。有些芯片的CC1P/CC2P默认值是上升沿有效还是下降沿有效不同系列不一样。如果你用的是下降沿来捕获脉宽但寄存器里配成了上升沿那么下降沿到来时没有任何动作CCR2自然不更新。测一个小技巧在不接外部信号的情况下给CH1引脚接一个按键按下拉低、松开拉高然后用调试器观察CCR1是否在按键弹起的瞬间发生变化。如果CCR1有反应说明触发链路通了如果纹丝不动重点查SMCR和GPIO复用配置。4.3 测量结果整体偏大或偏小一个固定偏差如果你测出来的周期值比示波器读到的实际值固定偏大或者偏小先不要疑神疑鬼大概率是预分频和计数频率的关系没算对。PSC的写入值是分频系数减1这是个万年坑。比如你想分频到1MHz输入时钟72MHz要写的PSC是71不是72。写错成72实际计数频率是72 / 73 986.3kHz于是测量的周期计算值就会偏小约1.4%。这一步算错后面的公式全变。还有一个系统性偏差来源是内部同步延迟。对于72MHz定时器时钟的场景这个延迟一般在一个计数脉冲到几个计数脉冲之间换算成时间大概几十纳秒到一百多纳秒。你在高精度应用里可以做一个软件校准先用示波器测出一个精确的PWM信号频率用这套方案测一遍算出偏差值然后在代码里对这个偏差做补偿。这种校准思路在做仪表类项目时很有用。另一个可能导致固定偏差的原因是输入滤波器的延迟。ICF字段设置的值越大滤波采样点越多引入的边沿检测延迟也越大。在测量模式里周期测量通常用0到3级的滤波就够追求精确度就别把滤波器开到很深的级数。4.4 毛刺引起的计数异常PWM信号在长线上传输时反射和串扰会在边沿附近产生毛刺。毛刺一旦被输入捕获逻辑认为是一个有效边沿就会引发额外的复位和捕获动作导致CCR1和CCR2出现异常小值。对付毛刺有两个手段。硬件层面在定时器输入引脚上加RC滤波或者在软件里配置ICF数字滤波。数字滤波的原理是定时器输入信号经过分频后采样只有连续N个采样点都是有效电平才认为边沿有效。比如ICF3意味着连续8个采样周期采样周期等于输入时钟除以分频系数检测到同电平才确认边沿。这样窄于几个采样周期的毛刺会被直接滤掉。软件层面读到的CCR1和CCR2要做一个合理性校验。我自己常用的判断是如果CCR1比历史值的1/10还小或者CCR1/CCR2的比例超出0到100%范围就丢弃这次数据继续用上一帧有效数据。这不会提升单次测量的准确性但能防止异常值污染控制环路。毛刺导致的另一个隐蔽问题是毛刺可能出现在上升沿之后极短的时间内被CC2通道误判为下降沿导致CCR2捕获到一个几乎为零的值占空比瞬间跳变到0。这种问题用滤波阈值判断双管齐下基本能覆盖绝大多数场景。我把常见问题的排查要点整理成一个速查表方便现场排障现象可能原因排查动作CCR1始终为0触发源TS配置错误或边沿极性错检查SMCR的TS确认TI1FP1检查CC1P极性CCR2始终为0IC2映射到了TI2或极性配置错CCMR1的IC2SEL改为TI1确认CC2P为下降沿有效占空比一直是100%没有检测到下降沿检查信号是否为恒高检查CC2中断是否开启占空比一直是0%没有检测到任何边沿检查输入引脚焊接和GPIO复用配置频率值整体偏低几个百分点PSC分频比算错确认PSC分频系数-1偶尔出现极大/极小异常值毛刺触发或数据读取时机不对增加去毛刺判断改用CC2中断读取低频信号数据不更新ARR溢出导致更新事件干扰检查ARR是否够大考虑更小的计数频率信号正常但中断不触发NVIC优先级或中断标志位没清检查DIER、NVIC配置ISR里清理对应标志位4.5 一个实测案例的复现过程之前做一个电机测速的小项目输入信号来自编码器的PWM输出标称1kHz占空比约50%。我用这套从模式方案去测结果占空比一直跳变在49%到51%之间频率倒是稳定在999Hz附近。排查了很久没找到原因后来用示波器看了编码器输出波形发现输出信号存在约20us的振铃下降沿之后有个小台阶。这个台阶被CC2误判成了新的下降沿导致CCR2短暂地捕获到一个偏小的值占空比就出现跳变。解决方案是给编码器信号输出端加一个10k电阻到地做下拉同时在定时器输入通道配置ICF为3级数字滤波。增加滤波后20us宽度的毛刺直接就被滤掉了占空比读数稳定在50.0%左右波动降到了千分之一以内。这个案例说明PWM测量不准很多时候问题不在算法而在信号完整性上。5. 稍做总结与工程落地的扩展建议5.1 一路捕获成功后如何扩展到四路或更多单定时器的从模式方案一次只能测一路PWM因为一个定时器只有一个触发源能用。要测多路信号有三种思路。思路一是多定时器并行。每路PWM接一个定时器的CH1引脚每个定时器都配成从模式复位。这种方式代码复制粘贴即可每路测量相互独立可维护性也不错。问题是MCU的定时器资源有限同时要占用多个通道。思路二是用定时器的主从级联。比如把定时器1的通道1作为从复位触发源同时让定时器1输出一个分频后的时基信号给定时器2定时器2也做从模式复位。这种方式适合做频率相近、相位有要求的多路PWM测量但配置复杂度高一般项目用不上。思路三是ADC配合定时器采样不做输入捕获而是用定时器触发ADC在每个PWM周期内的固定相位点采集电压从电压波形反推占空比。这种方法适合输入信号不是标准方波、电压变化缓慢的场景但精度受ADC分辨率和采样延迟限制。对大多数应用来说我建议直接走多定时器并行。8位和32位MCU的中端型号一般都有两个以上带输入捕获的定时器双路、三路PWM测量完全够用。更高路数的就上可编程逻辑器件去扫描吧性价比更高。5.2 提高测量精度的几个额外手段前面讲到的主要是标准配置下的精度水平。如果你对精度有更高要求还有三招可以叠加使用。校准计数频率。定时器的时钟源来自系统时钟或PLL如果系统时钟本身有偏差测量结果也会有等比例的偏差。用一个高精度频率计测出实际系统时钟频率把校准后的值代入计算公式可以消除这一部分的固定误差。使用DMA的定时捕获。如果测量频率很高中断响应的延迟会导致数据读取滞后。DMA可以在硬件层面实现边沿到来时立即把CCR值搬走效果比中断更好。注意DMA的请求源要选对比如从模式下推荐用通道2捕获事件作为DMA请求源保证每次下降沿时都搬一次。使用双重缓冲区。有些定时器支持DMA的循环双缓冲搬数据到两个缓冲区交替进行一个缓冲在接收新数据另一个缓冲给软件处理。这样软件可以异步处理历史数据不会因为计算影响下一次捕获吞吐量更高。这些方法都属于锦上添花基础配置先搞对再谈精度优化。5.3 写代码时的一些个人习惯最后分享几个我写驱动时的习惯性做法谈不上权威但都是踩过坑换来的。中断服务函数里的代码尽量少。从模式方案的好处是ISR只做读寄存器和计算不做信号处理。如果你需要在占空比变化时做电机控制或反馈调节把控制逻辑放到主循环里执行不要在ISR里做PID运算否则高优先级中断会把你的捕获实时性拖垮。使用volatile修饰共享变量。ISR和主循环共享的数据比如period和pulse编译时一定要加volatile防止编译器优化后读到陈旧值。这个坑在开启O2优化后特别容易踩明明逻辑没错就是数据不更新。定期用示波器验证测量结果。软件再完善最后都要拿示波器做交叉验证。把所有测量值换算成实际时间和示波器读数对比如果偏差在预期范围内说明方案没问题如果偏差大到肉眼可见优先查硬件信号完整性和分频参数不要急着改软件。写这篇文章的时候我尽量把从模式测量的原理、配置、实操和排障都串起来讲了一遍。对我个人而言这套方案最大的价值在于它把测PWM这件事从频繁的中断处理里解放出来让硬件在底层完成边沿对齐和捕获锁存软件只做算术。如果你正在被PWM测量问题困扰不妨按这个思路试一遍配置通过后你会发现原来测周期和占空比可以这么清爽。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑