ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

STM32定时器资源规划:8路同步PWM输出与4路反馈输入的最优方案

STM32定时器资源规划:8路同步PWM输出与4路反馈输入的最优方案 有人问了我一个很具体的资源规划问题How many STM32 timers/channels are required to generate 8 synchronized PWM outputs with 4 PWM feedback inputs? 这几乎是我见过最典型的多路PWM同步控制场景——多轴电机、多通道电源、机器人关节驱动背后全是这套资源账。很多人打开CubeMX往板子上拖定时器拖到一半发现引脚冲突、定时器不够用才开始回头算这笔账。先把结论放在前面8路同步PWM输出加4路PWM反馈输入最省资源的方案是3个定时器、12个通道。反过来如果反馈测量用PWM输入模式那种傻瓜精准方案就得4个定时器、16个通道。中间差了一个定时器差在哪就是这篇要拆开讲清楚的东西。1. 需求拆解8路输出和4路反馈背后真正的约束1.1 “同步”到底指哪几层含义很多初学者以为“同步”就是两个定时器用同一个时钟源觉得大家分频系数一样PWM频率自然一样应该就算同步了。用示波器一看就露馅频率确实一样但上升沿之间的相位完全随机每次上电都不一样。真正的同步至少包含三层意思同频所有PWM信号的频率一致这是基础。同相/固定相位关系各路PWM的边沿要么对齐要么维持一个确定的相位偏移。多路电机同步驱动时通常要求边沿对齐某些交错并联电源里反而要求固定相移。占空比同时更新改变占空比时所有通道必须在一个时刻统一生效而不是CPU一条条写寄存器、先写到的通道先变、后写到的通道后变。如果需求里只强调同频不同相那确实不需要定时器级同步各跑各的就行。但标题明确写的是“synchronized PWM outputs”那后面两层的语义基本默认包含在内这就把需求从“谁会配PWM”提升到了“谁会把多个定时器绑成一个整体”的层面。1.2 输出和反馈能不能复用同一套定时器一个定时器通道同一时间要么做输出比较产生PWM要么做输入捕获读取外部信号不能既当输出又当输入。这是STM32定时器硬件结构决定的不存在软件魔法能绕过。所以8路输出加4路反馈最优情况也是两套通道完全分开8个通道负责输出4个通道负责输入。你可以让同一个定时器一部分通道输出、一部分通道输入比如一个4通道定时器分出2路输出和2路输入但这样会让输出路数不够最终还是得再加定时器。工程上我基本都会让输出和输入分散到不同定时器逻辑清晰也方便后续单独调整中断优先级。1.3 先把STM32定时器的“家底”盘清楚做资源规划前先弄清楚手头芯片有多少定时器、每个定时器能出几路。常见系列大致如下定时器类型常见通道数特点高级定时器 TIM1/TIM84路 部分互补输出支持死区、刹车适合电机/逆变通用定时器 TIM2~TIM54路输出PWM和输入捕获都能做万金油双通道通用定时器 TIM9~TIM142路补充通道用基本定时器 TIM6/TIM7无IO只能做时基不能输出高分辨率定时器 HRTIMG4/H7多路CC单个外设可输出多路配置复杂F103C8T6这种经典片子一共就TIM1、TIM2、TIM3、TIM4四个能输出/捕获的定时器总数16个通道。F407VET6则充裕很多多了一堆双通道定时器和TIM8、TIM5。G474更夸张带HRTIM单独一个外设就能出十几路。但资源多归多同步机制的核心原理是一样的只是接线组合更灵活。2. 8路同步PWM输出最少需要几个定时器2.1 最直接的组合两个四通道定时器普通TIMx最多4个通道。8路PWM输出最简单粗暴的方案就是两个4通道定时器一个出4路另一个出4路。比如TIM2的CH1~CH4加上TIM3的CH1~CH4总共8路。这一步没什么争议。争议点在于很多人以为只要配置好两个定时器每路占空比往CCR里一塞任务就完成了。结果示波器一测8路频率都能对上相位关系却是乱的——原因是两个定时器虽然共用同一个时钟源但计数器从复位到启动的时机不一样你无法保证两个CNT在同一时刻从0开始。2.2 主从同步让两个计数器从同一个起点跑要解决相位随机问题就得让两个定时器建立主从关系。机制不复杂主定时器把更新事件输出到TRGO引脚对应的内部触发线上从定时器选择这条内部触发线作为自己的时钟源工作在外部时钟模式1。这样主定时器溢出一次从定时器就步进一次。两个CNT从同一起点开始每次走的步数完全一致相位天然对齐。再配合ARPE预装载占空比更新也在同一时刻生效。我见过一些项目嫌麻烦干脆用软件延时把两个定时器“凑”到同步。这个做法在低速、不要求相位精度的场合勉强能用但软件延时本身有抖动一旦开启中断、发生调度延迟相位差就开始漂。硬件主从同步是标配别省。2.3 为什么一个定时器出不了8路有朋友看到TIM1/TIM8有互补输出觉得CH1、CH1N、CH2、CH2N……一路数下来似乎能凑满8路。实际上常规F1/F4系列的高级定时器CH1~CH3有互补输出CH4没有互补单靠一个TIM1最多也只能输出7路PWMCH1、CH1N、CH2、CH2N、CH3、CH3N、CH4。所以常规系列里一个定时器出8路是不可能的。到了G4/H7的HRTIM一个外设能输出更多路但HRTIM属于另外一个维度配置复杂度比普通TIMx高不少而且也不是所有型号都有。3. 4路PWM反馈输入测量方案决定通道占用3.1 方案一PWM输入模式每路PWM吃掉2个通道STM32定时器里有个专门的PWM输入模式。选择一个信号接到某个定时器的TI1输入把通道1配成捕获上升沿、通道2配成捕获下降沿硬件就会自动把周期值存进CCR1、脉宽值存进CCR2。软件只需要去读两个寄存器就能算出频率和占空比。这个方案测量精准、软件逻辑最简单但代价是通道占用翻倍一个4通道定时器只能测2路PWM。4路反馈就得2个定时器一共8个通道。如果你的芯片定时器多、资源宽裕这个方案确实省心。但回到开头的题目8路输出已经吃掉了2个定时器反馈再吃掉2个一共就要4个定时器。对F103C8T6来说所有定时器全部占满系统里连个干杂活的定时器都不剩。3.2 方案二单通道双边沿捕获每路PWM只占1个通道每个输入捕获通道在上升沿触发中断时读一次CCR然后通过软件翻转CCER里的CCxP极性位让下一次捕获落在下降沿下降沿再读一次CCR再翻转极性。通过反复切换捕获边沿一个通道就能测出完整的周期和脉宽。这个方案的优势很明显4路反馈只需要1个4通道定时器。整个项目合计输出2个定时器、反馈1个定时器总共3个定时器、12个通道。F103C8T6能空出一个定时器做别的。代价是中断次数多。每路PWM每个周期产生2次中断4路就是每周期8次中断。PWM频率20kHz时每秒160万次中断CPU负载已经比较可观。这时会考虑用DMA循环模式让硬件捕获后直接通过DMA把CCR搬到内存用内存里的边沿时间戳序列软件计算占空比CPU几乎零负担。3.3 频率到多少就该换方案反馈PWM频率对方案选择的影响非常大我平时一般这么判断反馈PWM频率推荐方案理由1kHz以下单通道双边沿捕获中断中断量低代码最简单1kHz~20kHz单通道双边沿捕获DMA中断量可接受进一步省资源20kHz~100kHzPWM输入模式用通道换CPU硬件自动测量准确100kHz以上PWM输入模式硬件滤波/高分辨率定时器普通TIMx分辨率开始吃紧注意100kHz的PWM一个周期只有10微秒。如果用80MHz定时器时钟、预分频为1一个周期只有800个计数占空比分辨率大约0.125%。如果还要更细就得把计数时钟想办法提得更高或者接受一定误差。这个预算要在方案选择前就算好。4. 汇总核算最少3个定时器推荐4个定时器4.1 两种资源核算对照把输出和反馈连起来算总账方案输出定时器反馈定时器合计定时器合计通道适用场景单通道双边沿捕获TIM2 TIM3TIM43个12个反馈频率中等想留余量PWM输入模式TIM2 TIM3TIM4 TIM54个16个反馈精度优先软件求稳这里只是举例具体用哪几个定时器取决于引脚映射和芯片内部触发连接。4.2 结合具体芯片选型拿F103C8T6举例这个芯片就TIM1、TIM2、TIM3、TIM4四个能输出/捕获的定时器。如果按4定时器方案全部占满后续想加个编码器测速、做PWM DAC都没有定时器可用了。所以我至少会往F103RCT6这种资源更充裕的型号上走或者直接上F407/G4。G4系列的优势更明显TIM1/TIM8高级定时器带互补TIM2~TIM5全是4通道还有额外一组TIM15~TIM17总共十几个通道。而且G4的HRTIM可以做到单外设多路输出8路同步输出在一个外设内部就能解决同步精度比跨定时器主从同步更夸张。代价是HRTIM寄存器和配置复杂度高适合对时序有极致要求的项目。4.3 别忘了给其他功能留退路我见过太多人算定时器只盯着PWM和输入捕获算完发现刚刚好够用结果后面项目加了个编码器测速、加了个ADC采样定时触发发现一个定时器都不剩了。所以我做资源规划时默认都会留一个定时器做冗余。按这个原则上面3定时器方案在F103C8T6上其实是“刚够用但没余量”我会优先选择F407VET6这类定时器多的芯片哪怕成本高一点后期开发会舒服很多。5. 主从同步与输入捕获的寄存器级配置5.1 主定时器TRGO配置先让主定时器把更新事件输出到内部触发总线上。CubeMX里主定时器TIM2的Trigger Output (TRGO)选Update Event生成代码后对应配置TIM_MasterConfigTypeDef sMasterConfig {0}; sMasterConfig.MasterOutputTrigger TIM_TRGO_UPDATE; sMasterConfig.MasterSlaveMode TIM_MASTERSLAVEMODE_ENABLE; HAL_TIMEx_MasterConfigSynchronization(htim2, sMasterConfig);MasterSlaveMode这个字段值得多说一句。它主要作用是让主定时器在触发从定时器的同时自己也能响应某些同步事件保证主从链路双向握手。多数场景下打开它没有坏处配合从定时器使用更稳。5.2 从定时器ITR选择从定时器要选择内部触发源对应SMCR寄存器的TS位。不同芯片、不同定时器的ITR映射完全不同这是最容易翻车的地方。以F407为例TIM3的ITR0来自TIM4ITR1来自TIM2ITR2来自TIM3ITR3来自TIM8。那TIM2做主、TIM3做从时TIM3就要选ITR1。配置代码TIM_SlaveConfigTypeDef sSlaveConfig {0}; sSlaveConfig.SlaveMode TIM_SLAVEMODE_EXTERNAL1; sSlaveConfig.InputTrigger TIM_TS_ITR1; HAL_TIM_SlaveConfigSynchronization(htim3, sSlaveConfig);CubeMX里对应是Slave Mode选External Clock Mode 1Trigger Source选ITR1。写代码时一定去翻参考手册里“Timer internal trigger connection”那张表格别照抄网上其他芯片的配置。5.3 从定时器外部时钟模式1的注意点从定时器工作在外部时钟模式1时计数器时钟变成主定时器的更新事件相当于主定时器每溢出一次从定时器的CNT就加1。这种情况下从定时器的PSC一定要保持为0否则计数频率再被除一次主从比例就不是1:1了。同时启动顺序也有讲究先启动主定时器再启动从定时器。反过来的话从定时器一开始没有时钟源可能处于一个不可预期的状态。实测中从定时器PWM输出延迟一两个周期多半就是启动顺序反了。5.4 预装载与占空比同时更新配置每个PWM输出通道时把CCMR里的OCxPE位置1使能捕获比较预装载。再把TIMx_CR1的ARPE位置1使能自动重装载预装载。这样CPU写入CCR寄存器时新值不会立即生效而是等下一个更新事件统一加载。所以代码里可以放心地按顺序写8个CCR寄存器TIM2-CCR1 pwm[0]; TIM2-CCR2 pwm[1]; TIM2-CCR3 pwm[2]; TIM2-CCR4 pwm[3]; TIM3-CCR1 pwm[4]; TIM3-CCR2 pwm[5]; TIM3-CCR3 pwm[6]; TIM3-CCR4 pwm[7];写完之后主从定时器在下一个更新事件会同时加载新值8路占空比在同一时刻跳变肉眼和示波器都看不到先后顺序。5.5 输入捕获PWM模式下读CCR的顺序问题PWM输入模式里CCR1存周期、CCR2存脉宽。中断回调里如果先读CCR1再读CCR2中间刚好发生了新一轮捕获CCR1可能是新周期的值CCR2可能还是上一周期的值算出来的占空比就会错乱。我会直接在寄存器层连着读最大限度缩短两次读取之间的时间窗口void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { if (htim-Instance TIM4) { uint32_t period TIM4-CCR1; uint32_t pulse TIM4-CCR2; private_duty (pulse * 1000000UL) / period; } }如果对时效性要求更高就用DMA同时搬运CCR1和CCR2由DMA保证两次读取在同一周期内完成。6. 实测中最容易翻车的几个点6.1 高级定时器的MOE主输出使能TIM1、TIM8这类高级定时器多了一个主输出使能MOE位在BDTR寄存器里。只调用HAL_TIM_PWM_Start不一定能打开所有输出使用互补通道时尤其明显。如果用的是寄存器底层配置十有八九会遇到引脚死活不出波形的局面。解决方式是使能主输出HAL_TIM_PWM_Start(htim1, TIM_CHANNEL_1);HAL库的PWM Start函数一般会自动处理MOE但如果你手动用寄存器操作记得检查TIM1-BDTR的最高位是否置1。6.2 从定时器不计数多半是ITR选错主从同步配完从定时器波形完全不动这是最经典的故障。排查时先看从定时器的SMCR寄存器确认SMS位是外部时钟模式10b111TS位是否是期望的ITR源。再返回来查主定时器的CR2寄存器MMS位是不是010更新事件输出。有一次我在F407上调TIM3从TIM2同步代码是从STM32F1移植过来的F1上TIM3的ITR2是TIM2到了F407上映射就变了。查了一个多小时手册最后发现就是ITR编号不对。这种问题靠看寄存器配置能快速定位不建议在代码里盲试。6.3 占空比接近0%或100%时测量异常用PWM输入模式测量占空比接近0%或100%的PWM信号CCR2偶尔会捕获到0或者周期和脉宽不匹配。原因是窄脉宽情况下信号边沿抖动容易让下降沿捕获丢失或者极窄脉冲本身的建立时间不满足捕获时钟采样要求。处理办法是软件滤波连续多次采样偏差小于阈值才更新反馈值。尤其是闭环控制里一次错误占空比反馈就可能让PID输出抖一下滤波器是刚需。6.4 引脚复用冲突尤其是JTAG默认引脚PA15、PB3、PB4这些引脚默认被JTAG调试功能占用。如果PWM通道映射到这些引脚必须先把复用功能切换成SWD模式或AF模式否则电平根本出不来。CubeMX会自动处理这些约束但手写寄存器或者从旧工程移植代码时很容易漏掉。除此之外同类定时器通道在不同封装下的引脚映射也不一样画PCB前务必对着数据手册的AF
返回列表