1. PWM定时器核心机制:从计数器到脉冲边沿
要玩转PWM,尤其是像Tiva™这类微控制器里的高级PWM模块,不能只停留在“设置频率和占空比”的层面。你得先吃透它的心脏——定时器,以及它是如何一步步生成你最终看到的那个方波的。很多人调PWM波形不对,问题往往就出在对底层机制一知半解。
PWM生成器的核心是一个可编程的计数器(Timer)。这个计数器不像普通的定时器那样自由运行,它被限制在一个由LOAD值定义的范围内循环计数,从而形成一个固定的周期。根据计数方向的不同,它有两种基本工作模式,这直接决定了你输出PWM信号的对齐方式。
1.1 计数模式:左对齐、右对齐与中心对齐
递减模式(Count-Down)是最直观的一种。计数器从你设定的LOAD值开始,每个时钟周期减1,一直减到0。一旦到0,它不会停,而是立刻重新加载LOAD值,开始下一个周期的递减。你可以把它想象成一个倒计时的沙漏,漏完就立刻翻转。
在这种模式下,计数器只输出两个关键的内部事件脉冲:
zero脉冲:当计数器值等于0时,产生一个时钟周期宽的高电平脉冲。load脉冲:当计数器值等于LOAD值时,产生一个时钟周期宽的高电平脉冲。由于减到0后立刻重载,所以load脉冲紧跟着zero脉冲出现。dir方向信号:在递减模式下,这个信号恒为低电平,表示“向下”。
这种“从顶到底”的单向计数,天然地生成了边沿对齐的PWM信号。如果你在计数器递减过程中,在某个值(由比较器COMPA或COMPB定义)匹配时改变输出电平,得到的PWM脉冲其前沿(上升沿)是固定的(发生在重载时刻),后沿(下降沿)可变。这通常被称为右对齐(如果以时间轴从左到右来看,脉冲的右侧是固定的)。反之,如果设置成在匹配时拉高,在zero时拉低,就是左对齐。模式的选择完全取决于你对GENA/GENB寄存器的动作配置。
递增/递减模式(Count-Up/Down)则更复杂一些,也更强大。计数器从0开始递增,达到LOAD值后,转而递减回0,如此往复。这就好比一个弹簧在0和LOAD之间来回振动。
此时,计数器输出的信号就丰富了:
zero和load脉冲:分别在计数值为0和LOAD时产生。dir方向信号:在递增时为高电平,递减时为低电平。这是一个关键信号。cmpA和cmpB脉冲:当计数器值与COMPA或COMPB寄存器值匹配时产生。注意:在递增/递减模式下,匹配会在“上坡”和“下坡”时各发生一次。因此,cmpA脉冲需要与dir信号结合,才能区分是“匹配A上升”事件还是“匹配A下降”事件。
这种双向计数模式是生成中心对齐(或对称对齐)PWM的基石。中心对齐PWM的脉冲中心被固定在计时周期的中点,脉冲的前后沿对称地移动。这种波形在电机控制中尤其宝贵,因为它能显著降低谐波分量,减少电机噪音和铁损。想象一下,如果你让PWM在“匹配A上升”时拉高,在“匹配A下降”时拉低,那么高电平脉冲就会以LOAD/2时刻为中心对称展开。
实操心得:选择哪种模式?对于普通的LED调光、蜂鸣器驱动,递减模式简单够用。但一旦涉及到电机控制(尤其是BLDC、PMSM)、谐振式开关电源(如LLC),中心对齐PWM几乎是必选项,因为它能带来更好的电磁兼容性(EMC)性能和更高的效率。在Tiva中,通过配置
PWMnCTL寄存器的MODE位来选择模式。
1.2 比较器与事件:脉冲成形的雕刻刀
定时器提供了时间基准,而真正雕刻出PWM波形具体形状的,是两个比较器(Comparator A和B)以及它们产生的事件。
每个PWM发生器都有两个独立的比较器,分别对应CMPA和CMPB寄存器。它们持续对比计数器的当前值。当匹配发生时,会产生一个单时钟周期的cmpA或cmpB脉冲。这就是PWM边沿的“触发器”。
PWM信号发生器(Signal Generator)模块,就是根据这些事件(zero,load,cmpA up,cmpA down,cmpB up,cmpB down)来驱动最终的pwmA和pwmB原始信号。你需要通过PWMnGENA和PWMnGENB寄存器,为每一个可能的事件(在递减模式下是4个,在递增/递减模式下是6个)分别指定一个“动作”:
- 不动作:忽略该事件。
- 翻转:输出信号电平取反。
- 驱动为低:强制输出信号为低电平。
- 驱动为高:强制输出信号为高电平。
通过精心组合这些事件和动作,你几乎可以生成任意位置、任意占空比、甚至相互之间具有复杂相位关系的两路PWM信号。例如,要生成一个简单的中心对齐PWM,你可以这样配置PWMnGENA:
- 在“匹配A上升”事件时:驱动
pwmA为高。 - 在“匹配A下降”事件时:驱动
pwmA为低。 - 其他事件(
zero,load, 匹配B事件)均设置为“不动作”。
这样,在计数器从0增加到COMPA值的过程中,pwmA保持低电平;一旦匹配发生(cmpA脉冲且dir=1),pwmA变高;直到计数器从LOAD减回到COMPA值并再次匹配(cmpA脉冲且dir=0),pwmA才变低。占空比由COMPA值决定,周期由LOAD值决定。
注意事项:寄存器配置的“立即更新”与“同步更新”。如果你在计数器运行过程中直接修改
LOAD或CMPA/B值,可能会产生一个极短或极长的畸形脉冲,破坏输出波形。为了解决这个问题,Tiva PWM模块提供了“本地同步”和“全局同步”更新机制。简单说,你可以让新写入的寄存器值“挂起”,直到当前PWM周期结束(zero事件)时才真正生效,从而保证波形的连续性。这在需要动态调整频率或占空比的应用中至关重要,配置位于PWMnCTL寄存器的LOADUPD、CMPAUPD、CMPBUPD等位。
2. 死区生成:功率电路的安全卫士
当你用PWM驱动一个半桥或全桥电路(比如驱动电机的H桥)时,一个致命的危险是“直通”(Shoot-Through):同一桥臂的上管和下管在极短时间内同时导通,形成电源到地的低阻抗通路,产生巨大的瞬时电流,烧毁MOSFET或IGBT。死区(Dead Time)就是为了防止这种情况而引入的一段“全关断”时间。
2.1 死区生成器的工作原理
Tiva的死区生成器是一个独立的硬件模块,它接收来自PWM信号发生器的原始pwmA信号(注意,此时pwmB信号被忽略),并生成两路最终输出pwmA'和pwmB'。其核心操作是边沿延迟:
- 上升沿延迟:
pwmA'是pwmA信号的上升沿被延迟了一段时间(RISE值)后的结果。 - 下降沿延迟与反相:
pwmB'是pwmA信号取反后,其上升沿(对应原pwmA的下降沿)再被延迟一段时间(FALL值)后的结果。
最终效果是,pwmA'和pwmB'成为一对互补的、带有死区的信号。在pwmA原信号的跳变沿附近,pwmA'和pwmB'会同时保持一段时间的低电平,这个“同时为低”的窗口就是死区。对于上管驱动信号pwmA',其开通被延迟(上升沿延迟);对于下管驱动信号pwmB',其开通也被延迟(对应原pwmA下降沿后的延迟)。这就确保了在任何切换瞬间,总有一小段时间两个管子都是关闭的,彻底杜绝了直通。
2.2 寄存器配置与计算
死区时间由两个独立的寄存器控制:
PWMnDBRISE:控制pwmA'上升沿延迟的时钟周期数。PWMnDBFALL:控制pwmB'��升沿延迟(即pwmA下降沿延迟)的时钟周期数。
关键计算:死区时间 = 延迟周期数 × PWM时钟周期。
假设你的PWM时钟配置为系统时钟分频后得到10MHz(周期100ns),你需要插入500ns的死区时间。那么:
DBRISE=DBFALL= 500ns / 100ns = 5个时钟周期。
你需要将5写入PWMnDBRISE和PWMnDBFALL寄存器。同时,必须通过PWMnDBCTL寄存器使能死区生成器。
踩坑实录:死区时间不是随便设的。太短,起不到保护作用;太长,会显著降低有效电压输出,影响控制性能,尤其在高速开关场合。一般需要根据你所使用的功率器件的开关特性(特别是关断延迟时间)来确定。通常,死区时间应略大于器件的“关断延迟时间”减去“开通延迟时间”。务必查阅MOSFET/IGBT的数据手册。一个常见的起点值是200ns到1us。
3. 同步机制:多通道协同作战的艺术
单个PWM发生器只能输出两路有固定关系的信号。但在三相电机控制、交错式电源等应用中,我们需要多路(如6路)PWM,并且它们之间必须有精确、稳定的相位关系。这时,同步机制就派上用场了。
3.1 同步的层次与实现
Tiva的PWM模块提供了四个独立的PWM发生器(Generator 0-3),每个都能输出两路信号。同步机制的核心目标是让多个发生器的计数器保持相同的时基和相位。
1. 计数器同步(硬同步): 这是最基础的同步,通过PWMSYNC寄存器实现。向该寄存器的SYNC0、SYNC1等位写1,可以立即将对应发生器的计数器复位到0。如果你同时将SYNC0和SYNC1置位,那么Generator 0和1的计数器就会在同一时刻从0开始计数,实现了相位对齐的启动。这个操作是“立即生效”的。
2. 参数更新同步(软同步): 这是更精细、更常用的同步控制。它解决了“如何在运行时无毛刺地改变PWM参数”的问题。想象一下,你想同时改变三个相位的PWM占空比,如果直接写寄存器,由于软件执行有先后,会导致三个相位波形短暂失步,电机可能就会抖动。 Tiva提供了两种同步更新模式:
- 本地同步:当你在
PWMnCTL中为某个参数(如LOAD)设置了本地同步更新(LOADUPD=1),那么新写入PWMnLOAD寄存器的值不会立即生效,而是被缓存起来。直到该发生器自己的计数器回到0时,新值才被加载。这保证了参数在一个完整的PWM周期边界处改变。 - 全局同步:这是多发生器协同的关键。首先,你需要将各个发生器中需要同步更新的参数(如
CMPA)配置为全局同步更新模式(CMPAUPD对应位域设置为特定值)。然后,当你修改了所有发生器的CMPA值后,再向主控制寄存器PWMCTL中的GLOBALSYNC0等位写1。此时,所有被设置为全局同步的参数,都会在所有相关发生器的计数器都达到0的那个周期统一生效。这就实现了多通道参数的原子性更新。
3.2 同步应用实战:三相PWM生成
以生成相位互差120度的三相六步PWM(用于BLDC电机方波驱动)为例:
- 时基对齐:配置三个PWM发生器(如Gen0, Gen1, Gen2)为相同的计数模式(通常为中心对齐)和相同的
LOAD值(即相同频率)。通过PWMSYNC寄存器,一次性将SYNC0、SYNC1、SYNC2置位,让它们的计数器从同一起点开始。 - 相位设置:三相相位差120度。如果PWM周期对应电角度360度,那么120度相当于周期的1/3。你需要计算对应的比较器值。
- 假设
LOAD值为600(对应360度)。 - Gen0的
CMPA设为某值控制占空比,相位基准为0度。 - Gen1的
CMPA应产生滞后120度的效果。在中心对齐模式下,这通常意味着你需要计算一个偏移量,并可能通过调整“匹配上升”和“匹配下降”事件的动作组合来实现精确的相位移动,有时更直接的方法是使用不同的计数器初始偏移,但这需要更复杂的配置。一种常见方法是利用PWMnLOAD和PWMnCMP的同步更新,配合精心的时序计算。
- 假设
- 协同更新:当需要动态调整三相PWM的占空比(比如进行速度控制)时,将三个发生器的
CMPA更新模式都设置为全局同步。在软件中,依次更新PWM0CMPA、PWM1CMPA、PWM2CMPA寄存器(值已计算好),最后触发PWMCTL中的全局同步位。这样,三个新的占空比会在同一个PWM周期边界同时生效,电机运行会非常平滑,避免转矩脉动。
高级技巧:同步机制结合中断/ADC触发。你可以配置某个PWM事件(如计数器为零)来触发ADC采样。在多相系统中,你可以让主发生器(Gen0)的
zero事件触发ADC,采样所有相电流。由于计数器是同步的,这意味着ADC总是在每个PWM周期的同一精确时刻被触发,这对于电流环控制算法的稳定性和精度至关重要。配置在PWMnINTEN寄存器中完成。
4. 故障处理与输出控制:系统的安全网
工业控制中,安全永远是第一位的。PWM模块的故障处理功能就是最后的安全网。
4.1 故障源与安全状态
故障条件可以来自:
- 外部故障引脚(MnFAULTn):通常连接过流保护、过温保护等硬件保护电路的输出。
- 调试器触发的控制器停滞。
- ADC数字比较器触发:用于软件层面的过流、过压保护。
当故障发生时,你必须能够快速、确定地将PWM输出引脚驱动到一个安全的电平(通常是全关断,即所有桥臂下管导通或全部关断,取决于电机刹车方式),防止故障扩大。
4.2 故障处理流程配置
- 配置故障源:通过
PWMnFLTSRC0/1寄存器选择哪些信号能触发本发生器的故障。 - 配置故障引脚极性:通过
PWMnFLTSEN寄存器设置故障引脚是高电平有效还是低电平有效。 - 配置故障行为:这是核心,通过
PWMnCTL寄存器:LATCH位:决定故障是锁存的(一旦发生,即使故障信号消失也保持,直到软件清除)还是非锁存的(故障信号消失即自动恢复)。对于关键保护,建议设为锁存,防止抖动。MINFLTPER位:配合PWMnMINFLTPER寄存器,可以设置一个最小故障时间。即使故障输入是一个窄脉冲,PWM模块也会保证输出被抑制至少这么长时间,确保功率器件有足够时间关断。
- 定义安全输出值:当故障发生时,
pwmA'和pwmB'信号会被硬件强制替换为PWMFAULTVAL寄存器中预设的值。你可以为每一路PWM单独设置故障时输出高或低。 - 使能故障响应:通过
PWMFAULT寄存器,将对应的PWM输出通道与故障条件关联起来。
4.3 输出使能与极性控制
最终信号送到引脚前,还要经过输出控制块:
PWMENABLE寄存器:这是PWM输出的总开关。你可以单独使能或禁用任何一路PWM输出。这在电机换相时非常有用——通过简单地改写这一个寄存器,就能快速改变哪一对MOSFET被激活,而无需重新配置整个PWM发生器。PWMINVERT寄存器:控制输出极性。有些栅极驱动芯片是低电平有效,有些功率模块需要高电平使能。通过这个寄存器可以轻松翻转输出极性,无需改动硬件电路。重要:这个反转是在��障安全值PWMFAULTVAL生效之后应用的。也就是说,如果你设置了故障时输出高,同时又设置了输出反转,那么引脚最终输出的是低电平。
避坑指南:故障处理的配置顺序很重要。一个推荐的初始化顺序是:1) 配置故障安全值
PWMFAULTVAL;2) 配置并使能故障控制PWMFAULT;3) 配置PWM发生器参数;4) 最后使能PWM输出PWMENABLE。这样可以确保系统从上电开始,任何意外都不会导致危险的PWM输出。另外,一定要用示波器实测故障响应时间,确保从故障发生到PWM输出被拉至安全电平的时间满足你的系统安全要求。
5. 从理论到实践:一个完整的配置案例
让我们基于输入材料中的例子,但加入更多细节和解释,来配置一个中心对齐、带死区、并具备同步更新和故障保护功能的PWM,用于驱动一个半桥电路。
目标:使用PWM Generator 0,生成频率25kHz,占空比40%的中心对齐PWM。pwmA'驱动半桥上管,pwmB'驱动下管,插入500ns死区。系统时钟20MHz。
步骤分解与计算:
时钟与引脚配置:
- 使能PWM模块时钟(
RCGCPWM)和GPIO模块时钟(RCGCGPIO)。 - 配置对应GPIO引脚为PWM复用功能(
GPIOAFSEL),并通过GPIOPCTL映射到PWM外设。
- 使能PWM模块时钟(
PWM时钟分频:
- 目标PWM频率25kHz不算高,为了获得更精细的分辨率,我们可以对系统时钟进行分频。
- 配置
PWMCC寄存器:使能分频(USEPWMDIV=1),设置分频系数(PWMDIV)。例如,选择2分频,则PWM时钟 = 20MHz / 2 = 10MHz。周期为100ns。
计算周期与比较值:
- PWM周期:
T_pwm = 1 / 25kHz = 40us。 - PWM时钟计数周期数:
LOAD值决定了计数器的最大值。对于中心对齐模式(递增/递减),计数器从0到LOAD再到0,所以一个完整的PWM周期对应2 * LOAD个时钟周期。 - 因此,
2 * LOAD = T_pwm / T_clk = 40us / 100ns = 400。 - 解得:
LOAD = 200(0x00C8)。 - 占空比计算:占空比 = 高电平时间 / 周期时间。在中心对齐模式下,高电平时间对应于计数器值从 (
LOAD-CMPA) 到 (LOAD+CMPA) 的区间吗?不完全是。更准确地说,如果我们设置“匹配A上升”时拉高,“匹配A下降”时拉低,那么高电平时间对应计数器值在CMPA和LOAD*2 - CMPA之间的部分?这里容易混淆。实际上,在标准的中心对齐配置中,CMPA值定义了脉冲的起始点(从0开始递增到CMPA时拉高),而LOAD和CMPA共同决定了脉冲宽度。占空比 =CMPA / LOAD。对于40%占空比:CMPA = LOAD * 40% = 200 * 0.4 = 80(0x0050)。 - 死区计数:死区时间500ns,时钟周期100ns,需要5个时钟周期。设置
DBRISE = DBFALL = 5。
- PWM周期:
寄存器配置流程:
// 1. 配置PWM时钟 (假设寄存器地址已定义) PWMCC_R = (PWMCC_USEPWMDIV | PWMCC_PWMDIV_DIV_2); // 使用分频,2分频 // 2. 配置发生器0为递增/递减模式,并使能同步更新(防止毛刺) // PWM0CTL: MODE=1 (Up/Down), 其他位如LOADUPD, CMPAUPD可根据需要设置为同步更新 PWM0CTL_R = 0x00000000; // 先清零,MODE=0为递减,这里我们先按文档例子,后面改 // 文档例子是递减模式。我们要中心对齐,需设置为递增/递减: // PWM0CTL_R = (1 << 0); // 仅使能计数器,模式位?仔细看寄存器定义,MODE位可能在别处。 // 注意:Tiva PWMCTL寄存器可能没有直接的MODE位,计数模式可能在PWMnCTL的某个字段。需要查具体手册。 // 这里基于常见实践:假设配置为Up/Down模式。 // 3. 配置动作发生器GENA和GENB,以生成中心对齐PWM。 // 对于pwmA(上管信号):在“匹配A上升”时驱动为高,“匹配A下降”时驱动为低。 // 查找PWMnGENA寄存器位定义:ACTZERO, ACTLOAD, ACTCAU, ACTCAD, ACTCBU, ACTCBD。 // 假设ACTCAU=0x2 (驱动高), ACTCAD=0x1 (驱动低),其他动作忽略(0x0)。 // 寄存器值需要根据位域拼接。假设一个可能的配置值: PWM0GENA_R = 0x0000008C; // 文档中的值,需验证是否符合中心对齐。文档例是递减模式配置。 // 我们需要为Up/Down模式重新计算。例如: // ACTZERO=0, ACTLOAD=0, ACTCAU=2 (高), ACTCAD=1 (低), ACTCBU=0, ACTCBD=0 // 假设位域分布:[31:28] ACTZERO, [27:24] ACTLOAD, [23:20] ACTCAU, [19:16] ACTCAD, [15:12] ACTCBU, [11:8] ACTCBD... // 这需要精确的寄存器定义。这里出于演示,使用一个假设值: // PWM0GENA_R = (0x0 << 28) | (0x0 << 24) | (0x2 << 20) | (0x1 << 16) | ... ; // 对于pwmB(下管信号),我们将使用死区生成器从pwmA产生,所以GENB可以配置为不动作,或者生成一个初始信号再由死区模块处理。 // 简单起见,先按文档配置一个互补信号(但死区会使它失效)。 PWM0GENB_R = 0x0000080C; // 4. 配置周期和占空比 PWM0LOAD_R = 200 - 1; // 注意:文档中递减模式是 LOAD = 周期-1。对于Up/Down模式,LOAD值就是半周期计数。 // 根据前面计算,对于Up/Down模式,LOAD = 200 (0xC8)。但有些控制器定义LOAD为最大值,即200。 // 我们采用计算值200。 PWM0LOAD_R = 200; PWM0CMPA_R = 80; // 40% 占空比对应的比较值 // 5. 配置死区 PWM0DBCTL_R |= (1 << 0); // 使能死区生成器,假设第0位是ENABLE PWM0DBRISE_R = 5; // 上升沿延迟 PWM0DBFALL_R = 5; // 下降沿延迟 // 6. 配置故障保护(示例:故障时输出强制为低) PWMFAULTVAL_R &= ~((1 << 0) | (1 << 1)); // 清除PWM0和PWM1的故障值位,使其输出0 PWMFAULT_R |= (1 << 0) | (1 << 1); // 使能PWM0和PWM1通道的故障保护 // 7. 启动计数器 PWM0CTL_R |= (1 << 0); // 使能计数器,假设第0位是ENABLE // 8. 使能PWM输出 PWMENABLE_R |= (1 << 0) | (1 << 1); // 使能PWM0和PWM1引脚输出
调试心得:在最初调试时,先不要开启死区和故障保护。用示波器观察原始的
pwmA和pwmB信号,确认频率、占空比、中心对齐是否正确。然后再使能死区,观察pwmA'和pwmB'的边沿延迟是否出现,并用双通道示波器测量两个信号之间的死区时间是否与设定值相符。最后,模拟一个故障条件(如拉高故障引脚),验证输出是否立即被拉至安全电平。寄存器配置后,养成读取回显的习惯,确保写操作成功。