☰
STM32六路互补PWM验证实验:TIM1死区配置与示波器实测
2026/10/27 9:10:39 网站建设 项目流程

1. 为什么六路互补PWM值得单独做一次验证实验

如果你手上有STM32G431这类带高级定时器的芯片,又恰好要驱动三相无刷电机或者做数字电源,那六路互补PWM几乎是绕不开的一道坎。所谓六路互补,指的是三对通道,每对包含一个主输出和一个互补输出,比如TIM1的CH1/CH1N、CH2/CH2N、CH3/CH3N,一共六路信号。它们两两成对,主通道和互补通道在理想情况下永远处于相反的电平状态,中间还夹着一段谁都不导通的时间,也就是死区。

很多人第一次配完CubeMX,烧进板子,用示波器一测,发现波形要么缺一路,要么死区没出来,要么上下桥臂直接同时导通。问题往往不在代码逻辑,而在于对高级定时器的互补输出机制、死区发生器、刹车功能这几块理解得不够透。我见过太多人把TIM1当成普通定时器来配,结果CH1N死活不出波形,最后卡了一整天。

这篇内容就是围绕"验证六路互补PWM"这个实验展开的。我会把整个验证链路拆开讲:从CubeMX里TIM1的模式选择、通道配置、死区参数计算,到代码里怎么启动互补输出、怎么用示波器判断波形对不对,再到实测中容易踩的坑。适合正在做电机驱动、数字电源、逆变器这类项目的朋友,也适合刚接触STM32高级定时器、想搞明白互补输出到底怎么回事的初学者。看完你应该能独立完成一次完整的六路互补PWM验证,并且知道每一路波形为什么长那样。

2. TIM1的互补输出到底靠什么机制实现

2.1 主通道与互补通道的硬件关联

STM32的高级定时器(TIM1、TIM8这类)和通用定时器最大的区别之一,就是每个通道都配了一个互补输出。以TIM1为例,CH1对应PA8,CH1N对应PB13(具体引脚随封装和复用不同会有变化,G431上常见的是PA8/PA9/PA10做主通道,PB13/PB14/PB15做互补通道)。这两个输出不是软件里手动取反得到的,而是由定时器内部的互补输出逻辑直接控制。

关键在于,互补通道的电平并不是简单地对主通道取反。它受到一组控制位的联合影响:CCxE(主通道输出使能)、CCxNE(互补通道输出使能)、CCxP和CCxNP(各自的极性选择)、以及MOE(主输出使能)。这几个位任何一个没配对,波形就不对。比如你只开了CCxE没开CCxNE,那CH1N就是死的;如果你把CCxNP设反了,互补通道的极性就跟着反,死区位置也会看起来很奇怪。

我一般建议在CubeMX里先把通道都设成PWM Generation CHx CHxN模式,这样CCxE和CCxNE会一起被使能,省得手动去补。但要注意,CubeMX生成的初始化代码里,MOE这个位不一定在MX_TIM1_Init里就打开,很多时候是在HAL_TIM_PWM_Start之后才由HAL库去置位。这一点后面讲启动流程时会细说。

2.2 死区发生器的工作原理

死区时间的存在,是为了防止同一桥臂的上下两个开关管同时导通造成直通短路。它的本质是在主通道关断和互补通道开通之间,插入一段延迟;反过来,互补通道关断和主通道开通之间也插入一段延迟。这段延迟由死区发生器根据你配置的DTG(Dead-Time Generator)位来产生。

死区时间的计算不是随便填一个数就行。它和定时器的时钟频率、DTG的编码方式都有关系。STM32的死区发生器把DTG分成几段,不同区间的计算公式不一样。以常见的参考手册描述为例,当DTG[7:5]=0xx时,死区时间 = DTG[7:0] × Tdtg,其中Tdtg = 1/fCK_INT(假设时钟分频为1);当DTG[7:5]=10x时,公式变成(64 + DTG[5:0]) × Tdtg × 2;再往后还有更大的倍数。这意味着你不能简单地用"死区时间 = 某个寄存器值 × 时钟周期"来算,得先确定落在哪个区间。

举个实际例子。假设TIM1的时钟是170MHz(G431常见主频),你想设1微秒的死区。1微秒对应170个时钟周期。查表可以知道,这个值落在DTG[7:5]=10x的区间,因为该区间覆盖(64+0)×2=128到(64+63)×2=254个周期。反推:170/2=85,85-64=21,所以DTG[5:0]=21,DTG[7:5]=100,合起来DTG=0b10010101,也就是0x95。这个计算过程在CubeMX里其实会自动帮你算,但你必须知道它算得对不对,否则示波器上看到的死区可能和你预期差很远。

2.3 中心对齐模式对互补波形的影响

六路互补PWM用在电机驱动时,通常会用中心对齐模式(Center-Aligned Mode),而不是边沿对齐。原因很直接:中心对齐模式下,PWM脉冲对称分布在计数器周期的中间,谐波特性更好,电机噪音更低,电流采样时机也更稳定。

但中心对齐模式会带来一个副作用:波形的更新时机和边沿对齐不同。在中心对齐下,计数器先向上数到ARR,再向下数回0,一个完整周期里比较匹配会发生两次。这意味着如果你在中断里改CCR值,改的时机不对,可能会出现脉冲宽度忽宽忽窄的情况。验证互补波形时,如果你用的是中心对齐,示波器上看到的死区位置在上升沿和下降沿两侧应该是对称的,这一点可以用来判断配置是否正确。

另外,中心对齐模式下还有个RCR(重复计数器)的概念。高级定时器的更新事件不是每个周期都产生,而是每(RCR+1)个周期产生一次。这个在单纯验证PWM波形时影响不大,但如果你后面要用更新中断做别的事,就得留意。

3. CubeMX里配置TIM1的完整操作链路

3.1 时钟树与TIM1时钟源确认

打开CubeMX之后,第一件事不是急着点TIM1,而是先把时钟树配好。G431的TIM1挂在APB2总线上,而APB2的时钟又来自系统时钟经过分频。很多人配完发现PWM频率不对,回头一查是APB2的分频没设对,或者系统时钟根本没跑到预期频率。

具体操作:在Clock Configuration页面,先确认HSE或HSI的输入,然后配PLL。G431最高能跑到170MHz,我一般会把SYSCLK设到170MHz,然后APB2不分频,这样TIM1的时钟就是170MHz。注意,如果APB2做了分频,定时器时钟可能会是APB2时钟的2倍(取决于具体分频系数和芯片手册规定),这个细节容易搞混。稳妥的做法是配完之后在CubeMX里直接看TIM1的时钟输入频率显示,确认它和你预期一致。

3.2 TIM1模式与通道参数设置

进入Timers → TIM1,把Clock Source设为Internal Clock。然后关键在下面的通道配置:

  • Channel1选PWM Generation CH1 CH1N
  • Channel2选PWM Generation CH2 CH2N
  • Channel3选PWM Generation CH3 CH3N

这样三对互补通道就都使能了。接着在Parameter Settings里设置:

  • Prescaler:先设0,方便计算
  • Counter Mode:Center Aligned Mode 1(或2、3,验证阶段用1即可)
  • Counter Period(ARR):决定PWM频率。假设170MHz时钟,想要20kHz的PWM,中心对齐下实际频率 = 170MHz / (2 × ARR),所以ARR = 170000000 / (2 × 20000) = 4250
  • Pulse(CCR):先设成ARR的一半左右,比如2125,这样占空比50%
  • Dead Time:根据你的开关管和驱动电路来定,验证阶段可以先设一个明显能看到的値,比如100(对应某个死区时间)

这里有个容易忽略的点:三个通道的Pulse值最好设成一样,验证时波形整齐,方便对比。如果后面要做SVPWM,再让它们按正弦规律变化。

3.3 死区时间与刹车功能的参数取舍

死区时间不是越大越好。设太大,输出电压畸变严重,电机效率下降;设太小,直通风险高。实际项目中,这个值要根据MOSFET的开关时间和驱动芯片的延迟来定。一般IGBT模块可能几百纳秒到1微秒,MOSFET可以小到几十纳秒。

在CubeMX的Dead Time栏里填的是一个整数,它会被映射到DTG寄存器。CubeMX会根据你填的值自动选择最接近的编码。但你要知道,它不一定能精确等于你想要的纳秒数,因为DTG是分段量化的。验证阶段我建议先填一个中间值,比如对应500ns左右,然后用示波器实测,再反过来调整。

刹车功能(Break)在纯验证阶段可以先不开。但如果你后面要接实际功率级,刹车输入必须配,否则一旦出现过流,硬件没有快速关断通路。CubeMX里Break配置有BRK极性、滤波、以及自动输出使能等选项,这些等实际联调时再细调。

4. 代码层面启动六路互补输出的正确姿势

4.1 MX_TIM1_Init之后还差什么

CubeMX生成的MX_TIM1_Init函数会把定时器基本参数、通道、死区、极性都配好,但它通常不会自动启动PWM输出。你需要在main函数里手动调用启动函数。对于互补通道,必须用HAL_TIM_PWM_Start的扩展形式,把主通道和互补通道都启动。

正确的调用方式是这样:

HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2); HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2); HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3); HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_3);

注意HAL_TIMEx_PWMN_Start是专门启动互补通道的,很多人只调了HAL_TIM_PWM_Start,结果CH1N没波形,就是漏了这一步。另外,MOE位会在第一次调用这些启动函数时被置位,所以顺序上先启动哪个通道问题不大,但建议成对启动,逻辑清晰。

4.2 主输出使能MOE的隐藏陷阱

MOE(Main Output Enable)是高级定时器的一个总开关。如果MOE没置位,所有输出通道都是死的,不管CCxE和CCxNE怎么设。HAL库在HAL_TIM_PWM_Start和HAL_TIMEx_PWMN_Start里会去操作MOE,但前提是刹车功能没有把MOE强制清零。

如果你开了刹车功能,并且刹车输入有效,MOE会被硬件自动清零,这时候你怎么调启动函数都没用。验证阶段如果发现六路全无输出,先检查刹车引脚的状态,或者干脆先把刹车功能关掉,排除干扰。

还有一个细节:有些HAL版本里,HAL_TIMEx_PWMN_Start内部会调用__HAL_TIM_MOE_ENABLE,但如果你在CubeMX里把Automatic Output Enable设成了Disable,那MOE可能不会被自动置位,需要你手动加一句__HAL_TIM_MOE_ENABLE(&htim1)。这个坑我在不同版本的HAL库里都遇到过,建议启动之后用调试器看一眼TIM1->BDTR寄存器的MOE位是不是1。

4.3 用调试器确认寄存器状态

代码跑起来之后,别急着上示波器。先用调试器连上,在启动函数之后打个断点,查看几个关键寄存器:

  • TIM1->BDTR:确认MOE=1,DTG字段是你设的值
  • TIM1->CCER:确认CC1E、CC1NE、CC2E、CC2NE、CC3E、CC3NE都是1
  • TIM1->CR1:确认CEN=1,CMS字段是中心对齐模式
  • TIM1->ARR和TIM1->CCR1/2/3:确认周期和占空比符合预期

这一步能帮你排除掉大部分配置问题。如果寄存器都对,波形还不对,那问题就在硬件连接或者示波器设置上了。

5. 示波器实测:六路波形该怎么看

5.1 探头接法与通道分配

六路信号,一般示波器只有2到4个通道,所以得分批看。我的做法是先用两个探头看一对互补通道,比如CH1和CH1N,确认死区、极性、频率都对,然后再换到CH2/CH2N、CH3/CH3N。如果示波器通道够,可以一次看三对,但要注意探头地线别接错,否则容易短路。

接探头时,地线夹要接板子的GND,探针接对应的MCU引脚。G431的引脚是3.3V电平,示波器探头设成10倍衰减或者1倍都行,但要注意带宽,20kHz的PWM用普通探头完全够。

5.2 死区时间的实测与计算核对

把示波器调到上升沿触发,时基设成几微秒一格,看CH1和CH1N的交叉点。理想情况下,CH1从高变低之后,CH1N要等一段死区时间才从低变高;反过来CH1N从高变低之后,CH1也要等一段死区才从低变高。这两段死区时间应该相等。

实测值和你在CubeMX里填的值可能会有偏差,因为DTG是量化过的。比如你填的值对应480ns,实际测出来可能是470ns或500ns,这都正常。关键是这个值要满足你的功率级要求。如果实测死区明显偏小,比如只有几十纳秒,那可能是DTG编码落在了最小档,需要重新算一个更大的值。

5.3 中心对齐模式下波形的对称性检查

中心对齐模式下,PWM脉冲应该以计数器周期中心为对称轴。用示波器看的时候,把触发点设在CH1的上升沿,然后观察CH1的高电平时间是否在周期中间。如果发现脉冲偏向一侧,可能是Counter Mode设成了边沿对齐,或者ARR和CCR的计算有误。

另外,中心对齐模式下,CH1和CH1N的死区在上升沿和下降沿两侧应该是对称的。如果一侧死区大一侧死区小,那可能是极性配置有问题,或者死区发生器只在一侧生效。这种情况在实际调试中不常见,但一旦遇到,优先检查CCxP和CCxNP的设置。

6. 实测中容易翻车的几个典型问题

6.1 CH1N死活不出波形的排查顺序

这是最高频的问题。排查顺序我一般这样走:

  1. 先看CCER寄存器的CC1NE位是不是1。如果是0,说明互补通道没使能,检查CubeMX里通道模式是不是选成了PWM Generation CH1而不是CH1 CH1N。
  2. 如果CC1NE是1,再看BDTR的MOE位。MOE=0的话,所有输出都被关断,检查刹车配置或者手动置位MOE。
  3. 如果MOE也是1,看GPIO配置。CH1N对应的引脚(比如PB13)必须配成复用推挽输出,且复用功能要选对。CubeMX一般会自动配,但如果你手动改过引脚,可能就错了。
  4. 最后看硬件。用万用表量一下引脚对地有没有短路,或者换个引脚试试。

6.2 死区时间看起来不对的几种原因

死区实测和预期不符,常见原因有:

  • 时钟频率不是你以为的那个值。比如APB2分频导致TIM1时钟变成了85MHz而不是170MHz,死区时间就翻倍了。
  • DTG编码落在不同区间,计算公式变了,但你没重新算。
  • 示波器探头补偿没调好,导致边沿看起来变缓,死区被"吃掉"了一部分。
  • 互补通道的极性设反了,导致死区出现在错误的位置。

我一般会先用一个已知频率的方波校准示波器探头,然后再测死区,这样排除掉测量误差。

6.3 上下桥臂直通的紧急处理

如果在实测中发现同一桥臂的上下两个管子同时导通,也就是死区完全没起作用,必须立刻断电。这种情况多半是:

  • 死区时间设成了0
  • MOE虽然置位了,但CCxNE没使能,互补通道一直输出无效电平,导致驱动电路误判
  • 驱动芯片的输入极性接反了

处理完之后,重新检查CubeMX里的死区配置和通道极性,确保主通道和互补通道在静态时不会同时为高。

7. 从验证实验到实际电机驱动的延伸

六路互补PWM验证通过之后,下一步通常就是接三相逆变桥。这时候要注意,验证阶段用的固定占空比要换成按正弦规律变化的CCR值,也就是SVPWM或SPWM。中心对齐模式在这里依然适用,但更新CCR的时机要放在更新中断里,确保三个通道的占空比同步更新。

另外,实际驱动电机时,死区时间还要考虑MOSFET的体二极管续流和驱动电阻的影响。验证阶段测出来的死区值可以作为一个起点,但最终值要在带载测试中微调。我个人的经验是,先按数据手册算一个理论值,然后实测波形,再根据温升和效率做小范围调整,一般调两三轮就能稳定下来。

还有一点,如果你用的是G431这类带运放和比较器的芯片,可以把过流保护直接做到硬件刹车通路上,这样一旦过流,MOE被硬件清零,六路输出立刻关断,比软件响应快得多。这个在验证阶段可以先不接,但设计功率板的时候一定要预留。

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

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

立即咨询