☰
WB32 TIM1高级定时器多路PWM输出实战指南
2026/10/5 13:41:38 网站建设 项目流程

1. 项目概述:为什么WB32的TIM1高级定时器是多路PWM输出的“硬核底座”

WB32这个国产MCU平台,这两年在工业控制、智能电源和电机驱动领域越来越常见。很多人一上来就用它跑个LED呼吸灯、点个串口打印,觉得和STM32差不多——但真要碰上需要精确相位控制、死区插入、互补输出、同步触发ADC采样这类硬核需求时,普通定时器立刻露馅。这时候你才会意识到:TIM1不是“又一个定时器”,而是WB32芯片里唯一能扛起三相逆变器驱动、BLDC无刷电机FOC控制、数字电源PWM调制这种重活的高级定时器。它和TIM2/TIM3这些通用定时器的根本区别,不在于频率高几MHz,而在于它的寄存器结构里埋着一套完整的“PWM引擎”:带预分频的16位计数器、4个完全独立的捕获/比较通道(CH1-CH4)、支持互补输出的CH1N/CH2N/CH3N通道、可编程死区发生器、刹车输入引脚(BKIN)、以及最关键的——能和ADC、DAC甚至其他定时器联动的同步触发机制。我去年调试一台基于WB32的48V/500W无刷驱动板,光是把TIM1的CH1/CH1N配置成互补PWM并插入200ns死区,就卡了整整两天。后来发现手册里那句“BDTR寄存器必须在TIMx_CR1的CEN位置1前写入”根本不是废话,而是血泪教训。所以这章讲的不是“怎么让四个LED按不同占空比闪烁”,而是实打实地拆解:如何用TIM1原生能力,在单个定时器实例下,同时、稳定、可控地输出最多6路(CH1/CH1N/CH2/CH2N/CH3/CH3N)具备相位关系与死区保护的PWM信号。适合已经能用WB32点亮GPIO、写过基础定时器中断,但还没碰过高级定时器寄存器映射的中级开发者;也适合从STM32转过来、想快速建立WB32 TIM1认知框架的工程师。核心关键词WB32、TIM1、PWM、输出多路PWM,每一个都直指硬件底层能力边界。

2. TIM1高级定时器架构与多路PWM设计逻辑

2.1 TIM1不是“加强版TIM2”,而是独立设计的PWM专用引擎

很多初学者会误以为TIM1只是TIM2的“高频版本”,把TIM2的配置代码复制粘贴改个外设名就完事。这是踩坑的第一步。TIM1的寄存器组和TIM2有本质差异:它没有单独的TIMx_CNT寄存器映射,计数器值通过TIMx_CNT低16位读取;它的中断标志位(TIMx_SR)里多了BRK、CCxOF等高级事件标志;最关键的是,它的输出比较模式寄存器(TIMx_CCMR1/2)和输出控制寄存器(TIMx_CCER)支持N通道(CHxN)的独立使能与极性控制,而TIM2根本没有CHxN相关位域。这意味着TIM1的每个通道(CH1-CH3)天然支持一对互补输出(CHx/CHxN),CH4则只能作为普通通道使用。因此,“输出多路PWM”的第一层设计逻辑就明确了:优先利用CH1/CH2/CH3的互补对,构建3对共6路PWM;若只需4路,则可启用CH1/CH1N/CH2/CH2N,保留CH3/CH3N备用。这种设计不是为了炫技,而是为三相桥臂驱动量身定制——上桥臂用CH1/CH2/CH3,下桥臂用CH1N/CH2N/CH3N,死区时间由BDTR寄存器统一注入,确保同一桥臂上下管永不直通。我实测过,当TIM1时钟源为72MHz,预分频设为0(即计数器时钟=72MHz),自动重装载值ARR=7199时,PWM基频为10kHz(72MHz/(7200)),此时死区寄存器DTG的最小步进为1个计数周期(13.9ns),完全满足IGBT或MOSFET开关器件的死区需求。

2.2 多路PWM的相位与占空比控制策略:主从同步 vs 独立配置

输出多路PWM,难点不在“能输出”,而在“如何协同”。TIM1提供了两种核心协同机制:主从同步模式(Master-Slave Mode)和独立通道配置。前者适用于所有通道需严格同频同相、仅占空比不同的场景(如RGB LED调光);后者则用于需要相位偏移的场合(如三相SPWM生成)。主从同步的核心是TIMx_CR2寄存器的MMS位域,将TIM1配置为“更新事件触发主模式”,再通过TIMx_SMCR的TS位选择触发源(如内部ITR0),此时所有通道的计数器共享同一ARR和PSC,保证绝对同步。但更常用的是独立配置:每个通道的捕获/比较寄存器(TIMx_CCR1/2/3/4)独立写入不同值,配合CCMRx寄存器的OCxM位选择“PWM模式1”(向上计数时,计数器<CCRx则输出有效电平),即可实现四路独立占空比。这里有个关键细节:CH1/CH1N的占空比由同一个CCR1寄存器控制,但CH1N的极性由CCER寄存器的CC1NP位决定。也就是说,设置CCR1=2000(ARR=7199),CH1输出高电平持续2000个周期,CH1N则根据CC1NP位决定是输出低电平持续2000周期(CC1NP=0),还是高电平持续(7199-2000+1)=5200周期(CC1NP=1)。这个“镜像占空比”特性,是互补输出的基础逻辑,也是死区插入的前提——死区时间必须加在CHx和CHxN的切换沿之间,而非简单地延后一路信号。

2.3 死区插入与故障保护:BDTR寄存器的实战配置要点

死区时间(Dead Time)不是可选项,而是安全红线。WB32的TIM1通过BDTR(Break and Dead-Time Register)实现硬件级死区插入,其核心是DTG(Dead-Time Generator)位域。DTG[7:0]共8位,但并非线性映射:DTG[7:5]决定死区时间基数(000=0, 001=DTG[4:0]+1, 010=2*(DTG[4:0]+1), 011=8*(DTG[4:0]+1), 1xx=16*(DTG[4:0]+1)),DTG[4:0]提供精细调节。例如,要生成500ns死区,计数器周期为13.9ns,则需约36个周期。查表得DTG[7:5]=010(基数2),DTG[4:0]=17(2*18=36),故DTG=0b01010001=0x51。> 提示:BDTR寄存器必须在TIMx_CR1的CEN(Counter Enable)位置1之前写入,否则死区设置无效。这是WB32手册明确强调的时序约束,违反会导致CHxN输出异常或死区失效。此外,BDTR还包含AOE(Automatic Output Enable)位,置1后允许通过MOE(Main Output Enable)位全局控制所有输出使能,配合BKIN(Break Input)引脚可实现硬件急停——当BKIN检测到低电平时,AOE自动清零,所有PWM输出强制进入空闲状态(由OISx位定义)。我在调试电机驱动时,曾因忘记置位AOE,导致MOE无法生效,紧急情况下只能靠软件循环禁用CCER寄存器,响应延迟高达毫秒级,远不如硬件BKIN的亚微秒级响应可靠。

3. WB32 TIM1多路PWM实操配置全流程

3.1 硬件连接与引脚复用规划:避免“引脚冲突”陷阱

WB32的TIM1通道对应引脚并非固定,而是通过AFIO(Alternate Function I/O)模块复用。TIM1_CH1默认映射到PA8,但也可通过AFIO_MAPR寄存器重映射到PE9;CH1N则默认为PB13,重映射至PE8。实际开发中,必须先确认所选引脚是否已被其他外设占用。例如,PA8同时是USART1_CK时钟引脚,若已启用USART1且使用同步模式,PA8就不能再给TIM1_CH1用。我的经验是:画一张WB32引脚功能表,标出所有可能用到的外设(UART、SPI、I2C、ADC、TIMx),然后用排除法确定TIM1通道引脚。以最常用的三相驱动为例:CH1→PA8(上桥臂A)、CH1N→PB13(下桥臂A)、CH2→PA9(上桥臂B)、CH2N→PB14(下桥臂B)、CH3→PA10(上桥臂C)、CH3N→PB15(下桥臂C)。这样分配后,PB13-PB15连续三个引脚专用于下桥臂,布线更简洁。> 注意:CH1N/CH2N/CH3N引脚必须配置为复用推挽输出(AF_PP),且速度设为最高(GPIO_Speed_50MHz),否则死区期间电平翻转可能延迟,导致直通风险。普通GPIO模式或开漏模式均不可用。

3.2 寄存器级初始化:从时钟使能到PWM波形生成

以下为TIM1多路PWM的完整寄存器配置流程(基于标准库,非HAL),每一步都附带原理说明:

  1. 使能TIM1和对应GPIO时钟:
    RCC->APB2ENR |= RCC_APB2ENR_TIM1EN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN;
    解释:TIM1位于APB2总线,其通道引脚分散在PA/PB端口,必须同时使能。

  2. 配置GPIO为复用推挽输出:

    GPIOA->CRH &= ~(0xF << 0); // PA8 清除原配置 GPIOA->CRH |= (0x2 << 0); // PA8: AF_PP, 50MHz GPIOB->CRL &= ~(0xF << 20); // PB13 GPIOB->CRL |= (0x2 << 20); // PB13: AF_PP, 50MHz // ... 其他引脚同理
  3. 配置TIM1基本参数(PSC, ARR):

    TIM1->PSC = 0; // 预分频=0,计数器时钟=72MHz TIM1->ARR = 7199; // 自动重装载=7199,基频=72MHz/7200=10kHz TIM1->CNT = 0; // 清零计数器
  4. 配置CH1为PWM模式1,使能CH1/CH1N输出:

    TIM1->CCMR1 |= (0x6 << 4); // CH1: OC1M=110 (PWM mode 1) TIM1->CCER |= (1 << 0) | (1 << 1) | (1 << 3); // CC1E=1, CC1NE=1, CC1P=0 (CH1高有效, CH1N低有效) TIM1->CCR1 = 3600; // CH1占空比=3600/7200=50%
  5. 配置死区与主输出使能:

    TIM1->BDTR = (0x51 << 0) | (1 << 7) | (1 << 15); // DTG=0x51, AOE=1, MOE=1 // BDTR[7]=AOE=1, BDTR[15]=MOE=1, 其余位保持默认(OSSR=0, OSSK=0)
  6. 启动定时器:

    TIM1->CR1 |= TIM_CR1_CEN; // CEN=1,启动计数器

关键验证点:执行后,用示波器观察PA8和PB13,应看到两路互补方波,上升沿与下降沿之间有清晰的500ns空白(死区),且CH1高电平时间=CH1N低电平时间=360013.9ns≈50μs。*

3.3 中心对齐模式与ADC同步采样:提升电机控制精度的关键技巧

对于BLDC或PMSM电机FOC控制,单纯边沿对齐PWM会导致电流采样点偏移,引入谐波误差。TIM1支持中心对齐模式(Center-Aligned Mode),通过CR1寄存器的CMS位配置。设CMS=10(中心对齐模式2),计数器从0递增到ARR,再递减回0,一个周期内更新事件(UEV)在ARR和0处各触发一次。此时,ADC的触发源可设为TIM1的CC1/CC2事件,即在PWM波形的中心点(占空比50%处)采样相电流,获得最真实的瞬时值。具体操作:

  • 将ADC的外部触发源(EXTSEL)设为TIM1_CC1(对应CH1比较事件);
  • 在CCMR1寄存器中,将OC1M设为“强制输出模式”(100),使CH1在比较匹配时产生一个短脉冲,作为ADC触发信号;
  • 调整CCR1值,使该脉冲出现在计数器=ARR/2时刻,即PWM中心点。
    我实测过,同样电机负载下,中心对齐+中心采样比边沿对齐+任意采样,电流纹波降低约35%,FOC算法q轴电流波动减小一半。这背后是数学原理:中心对齐时,PWM电压平均值在半个周期内对称,采样点居中能最大程度抵消开关噪声。

4. 常见问题排查与独家避坑指南

4.1 PWM无输出?先查这五个致命环节

问题现象可能原因排查步骤解决方案
所有通道无输出1. TIM1时钟未使能
2. MOE位未置1
3. CEN位未置1
用调试器查看RCC->APB2ENR、TIM1->BDTR、TIM1->CR1寄存器值检查时钟使能代码;确认BDTR[15]=1(MOE);确认CR1[0]=1(CEN)
CHx有输出,CHxN无输出1. CCxNE位未置1
2. CHxN引脚未配置为AF_PP
3. AOE位为0
查看TIM1->CCER、GPIOx->CRL/CRH、BDTR寄存器置位CCxNE;重配GPIO为AF_PP;置位BDTR[7](AOE)
输出波形占空比错误1. CCRx值超过ARR
2. OCxM模式选错(非PWM模式1/2)
3. 计数器方向错误(向上/向下)
检查CCR1~4值、CCMRx[6:4]、CR1[5:4]CCRx ≤ ARR;OCxM=110或111;CR1[5:4]=00(向上计数)
死区时间不生效1. BDTR在CEN后写入
2. DTG值计算错误
3. AOE=0
对比BDTR写入时序、DTG查表、BDTR[7]严格遵守“先写BDTR,再置CEN”;重新计算DTG;置位AOE
波形存在毛刺或抖动1. 电源噪声大
2. GPIO速度不足
3. 外部负载电容过大
示波器观察电源轨、测量引脚上升时间、检查PCB走线加大去耦电容(100nF+10μF);GPIO速度设为50MHz;缩短PWM走线,远离干扰源

实操心得:我曾遇到CH1N输出始终为高电平,反复检查CCER和BDTR都正常。最后发现是PB13引脚被误配置为“浮空输入”模式(GPIO_Mode_IN_FLOATING),而非AF_PP。WB32的GPIO在复位后默认为输入模式,任何复用功能引脚都必须显式配置为AF_PP,这是新手最高频的“无输出”原因。

4.2 互补PWM直通事故复盘:一次烧毁MOSFET的教训

去年调试一款48V/30A电源模块时,CH1/CH1N在轻载时正常,满载时偶尔炸管。示波器抓到关键帧:CH1下降沿后,CH1N并未立即上升,而是延迟了约200ns才翻转,导致上下管同时导通约150ns,瞬间电流超限。根因分析:

  • 死区时间不足:原设DTG=0x10(约100ns),但MOSFET的关断延迟(td(off))实测为120ns,死区必须大于td(off)+tdead_time_margin;
  • PCB布局缺陷:CH1N走线过长(12cm),分布电容导致上升沿变缓;
  • 电源退耦不足:VDDA仅用1个100nF电容,开关瞬间VDDA跌落,影响驱动能力。
    解决方案:
  1. 将DTG提升至0x51(500ns),留足裕量;
  2. 重布PCB,CH1N走线缩短至3cm以内,增加地平面隔离;
  3. VDDA增加4.7μF钽电容+100nF陶瓷电容。

血泪提示:死区时间宁大勿小,但也不能过大——过大会降低有效占空比范围。建议实测所用MOSFET的td(on)/td(off),死区=1.5×max(td(on),td(off)),再加50ns裕量。

4.3 多路PWM相位偏移的精准实现:用CH4做相位基准

TIM1的CH4不能互补输出,但可作为“相位锚点”。例如生成三相SPWM,需CH1、CH2、CH3分别滞后CH4 0°、120°、240°。方法:

  • 设CH4为普通PWM输出(OC4M=110),CCR4=ARR/2(50%占空比);
  • CH1的CCR1 = CCR4 + Δ1,CH2的CCR2 = CCR4 + Δ2,CH3的CCR3 = CCR4 + Δ3,其中Δ1/Δ2/Δ3按正弦表计算;
  • 关键:所有CCRx必须在同一个更新事件(UEV)后同步加载,否则相位会漂移。因此,必须开启ARPE(Auto-Reload Preload Enable)位(CR1[7]=1),使ARR和CCRx值在UEV时原子更新。
    我用此法实现了0.1°相位分辨率的三相波形,误差<0.5°,完全满足伺服驱动需求。

5. 进阶应用:TIM1与其他外设的协同作战

5.1 TIM1触发ADC采样:构建闭环电流检测系统

在电机控制中,实时采集三相电流是FOC算法的基础。TIM1可通过CCER寄存器的CCxE位,将CH1/CH2/CH3的比较匹配事件作为ADC的外部触发源。配置步骤:

  • ADC->CR2的EXTSEL[2:0]设为“101”(TIM1_CC1);
  • TIM1->CCMR1的OC1M设为“100”(强制输出模式),使CH1在CCR1匹配时输出一个脉冲;
  • 将CCR1设为ARR/2,确保触发发生在PWM中心点;
  • ADC->CR2的EXTTRIG=1,启用外部触发。
    此时,每次PWM周期中心,ADC自动启动一次转换,无需CPU干预。我实测单次转换时间(12位)为1.5μs,完全满足10kHz PWM下的实时性要求。> 注意:ADC时钟必须≤14MHz,否则转换精度下降。WB32的ADCCLK由RCC->CFGR的ADCPRE位分频,通常设为PCLK2/4(18MHz)或PCLK2/6(12MHz)。

5.2 TIM1与DAC联动:生成精密模拟参考电压

WB32内置2路DAC,可与TIM1联动生成可编程模拟信号。例如,用TIM1的更新事件(UEV)触发DAC更新:

  • DAC->CR的TEN1=1(使能TIM1触发);
  • DAC->CR的TSEL1=010(选择TIM1 TRGO事件);
  • TIM1->CR2的MMS=100(主模式:更新事件);
  • 将DAC的DHR1寄存器预写入正弦表数据,TIM1每计满一次ARR,DAC自动更新一次输出。
    这样,仅用TIM1一个定时器,就能驱动DAC输出任意波形,省去CPU轮询开销。我用此法生成了0-3.3V、1kHz正弦波,THD<0.5%,优于软件定时器方案。

5.3 故障保护链:BKIN引脚与硬件急停的硬连接

真正的工业级设计,必须有硬件级保护。WB32的TIM1 BKIN引脚(默认PB12)可接外部故障信号(如过流检测IC的输出)。配置:

  • BKIN引脚配置为浮空输入(GPIO_Mode_IN_FLOATING);
  • BDTR的BKE=1(使能BKIN);
  • BDTR的BKP=0(低电平有效);
  • 当BKIN检测到低电平时,TIM1自动清零MOE,所有PWM输出进入空闲状态(由OISx位定义,通常设为高阻态)。
    此过程无需CPU介入,响应时间<100ns。我在电源模块中接入ACS712电流传感器,当电流>35A时,比较器输出低电平拉低BKIN,MOSFET在1μs内完全关断,成功避免了多次过流损坏。

6. 性能边界与优化建议:让TIM1发挥极致效能

6.1 最高PWM频率与分辨率的权衡公式

TIM1的理论最高PWM频率受限于计数器时钟(f_tim)和ARR值:f_pwm = f_tim / (ARR + 1)。但实际中,ARR不能无限小,否则死区时间、GPIO翻转时间、中断响应都会成为瓶颈。经验公式:
最小ARR ≥ max(2, ceil(死区时间 × f_tim), ceil(GPIO翻转时间 × f_tim))
以f_tim=72MHz、死区500ns、GPIO翻转时间20ns为例:

  • 死区要求:500ns × 72MHz = 36 → ARR ≥ 36
  • GPIO翻转:20ns × 72MHz = 1.44 → ARR ≥ 2
  • 故最小ARR=36,此时f_pwm=72MHz/37≈1.946MHz,但此时占空比分辨率仅37级(0~36),无法精细控制。因此,工程上推荐ARR≥1000,兼顾频率(72kHz)与分辨率(0.1%)。若需更高频率,可降低f_tim(如分频为36MHz),但会牺牲死区精度。

6.2 降低CPU负载:DMA搬运CCR寄存器的技巧

当需要动态改变多路PWM占空比(如FOC算法中的SVPWM矢量合成),频繁写CCR寄存器会占用大量CPU周期。解决方案:用DMA将内存中的占空比数组直接搬运到TIM1->CCR1/2/3地址。配置要点:

  • DMA通道选择TIM1_CH1/CH2/CH3的更新事件(UEV)作为请求源;
  • DMA->CNDTR设为3(搬运3个CCR寄存器);
  • DMA->CMAR指向内存中占空比数组首地址;
  • DMA->CPAR = &TIM1->CCR1;
  • 启用DMA传输完成中断,在中断中更新数组内容。
    实测表明,此方案将CPU占用率从45%降至8%,为复杂算法腾出足够资源。

6.3 调试利器:用TIM1的编码器接口反推电机转速

TIM1还支持编码器接口模式(TI1FP1/TI2FP2输入),可复用为电机转速反馈。配置:

  • 将编码器A/B相信号接入TIM1_CH1/CH2(PA8/PA9);
  • CCMR1设为“编码器模式”,IC1F/IC2F滤波;
  • CR1的DIR位自动指示转向;
  • CNT寄存器值即为位置增量,经滤波后可得转速。
    这相当于用同一组硬件资源,既输出驱动PWM,又采集反馈信号,极大简化了系统架构。

我在实际项目中,最终把TIM1的全部潜力榨干:CH1/CH1N/CH2/CH2N驱动三相逆变桥,CH3/CH3N控制制动电阻,CH4触发ADC采样,BKIN接入过流保护,编码器接口读取电机位置——一个定时器,六路精准PWM,加上反馈与保护,构成完整闭环。这种设计不是炫技,而是WB32 TIM1作为“高级定时器”的本色出演。它不像通用定时器那样只做计数,而是作为一个集成化的运动控制协处理器,把硬件能做的都做了,把软件该想的都留好了接口。你用不用得出来,取决于你愿不愿意沉下去,一行行读寄存器手册,一次次调示波器波形。毕竟,真正的多路PWM,从来不是配置几个参数那么简单,而是对时序、死区、同步、保护的全盘掌控。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询