MC9S12XE PWM模块配置详解:从寄存器到波形生成实战
1. MC9S12XE PWM模块深度解析:从寄存器到波形生成
在嵌入式系统,尤其是汽车电子和工业控制领域,精准的硬件信号生成是核心需求。无论是驱动无刷电机的三相PWM波,还是调节LED背光的亮度,亦或是为开关电源提供控制信号,脉冲宽度调制(PWM)技术都扮演着至关重要的角色。Freescale(现NXP)的MC9S12XE系列微控制器,凭借其高度集成和可靠的性能,在这些领域有着广泛的应用。其内置的S12PWM8B8CV1模块,提供了8个独立且高度可配置的PWM通道,功能强大但配置也相对复杂。很多工程师在初次接触其数据手册时,面对数十个寄存器位域和多种工作模式,往往会感到无从下手。本文将从一个资深嵌入式开发者的视角,彻底拆解MC9S12XE的PWM模块,不仅告诉你每个寄存器该怎么设置,更会深入解释其背后的硬件工作原理、配置时的“潜规则”以及我在实际项目中踩过的坑,目标是让你看完后能独立、自信地驾驭这个模块。
PWM的本质,是用数字方法获得模拟效果。一个周期固定的方波,通过改变其高电平时间(脉宽)占整个周期的比例(占空比),其平均电压就会发生变化。MC9S12XE的PWM模块就是硬件上帮你完成“计数-比较-输出”这一循环的专用外设,解放CPU,实现精准、实时的控制。它的8个通道可以独立工作,也可以两两组队形成4个16位高精度通道,时钟源灵活,支持左对齐和中心对齐两种输出模式,双缓冲机制确保波形切换平滑无毛刺。理解并掌握它,是玩转MC9S12XE进行硬件控制的必修课。
2. 核心架构与工作模式全览
2.1 模块整体架构与信号流
MC9S12XE的PWM模块(S12PWM8B8CV1)并非一个简单的定时器加比较器,它是一个拥有独立时钟网络和灵活路由的完整信号生成引擎。其核心架构可以理解为8个并行的“波形发生器”,但它们共享上层的时钟预处理资源。
模块的时钟输入是系统的总线时钟(Bus Clock)。这个时钟首先进入一个预分频器(Prescaler),该预分频器可以生成两路独立的派生时钟:Clock A和Clock B。通过PWMPRCLK寄存器的PCKA[2:0]和PCKB[2:0]位,可以分别将总线时钟进行1、2、4、8、16、32、64、128分频,得到Clock A和Clock B。这是第一级频率粗调。
接下来,Clock A和Clock B可以分别再经过一个可编程的缩放器(Scaler),生成Clock SA和Clock SB。缩放公式为:Clock Sx = Clock x / (2 * PWMSCLx)。这里PWMSCLx是一个8位寄存器,当其值为0时,按256处理,即除以512。这是第二级频率细调,提供了更灵活的时钟选择,尤其适合产生特定频率的PWM波,例如用于音频或特定通信协议。
最终,每个PWM通道(0-7)可以从两对时钟(A/SA 或 B/SB)中选择其一作为自己的计数时钟源。通道0、1、4、5在A/SA中选择(通过PWMCLK寄存器的PCLKx位),通道2、3、6、7在B/SB中选择。每个通道都拥有自己独立的8位计数器(PWMCNTx)、周期寄存器(PWMPERx)和占空比寄存器(PWMDTYx)。计数器根据所选时钟递增(或先增后减),并与这两个寄存器的值进行比较,从而在对应的PWMx引脚上输出设定好的波形。
关键理解:这种两级时钟架构(预分频+缩放)的设计非常巧妙。预分频器(Prescaler)用较少的控制位(3位)实现了大的分频比变化,适合大幅调整频率范围。缩放器(Scaler)则提供了更精细的、以1为步进的调节能力(1-256),两者结合可以几乎覆盖从几十Hz到几MHz的PWM频率需求,而不需要CPU频繁干预计算。
2.2 左对齐与中心对齐模式详解
这是PWM模块的两个核心输出模式,由PWMCAE寄存器的CAEx位控制。选择哪种模式,绝不仅仅是波形看起来不同,它直接影响着频率计算、谐波成分以及在某些应用中的性能。
左对齐模式(CAEx = 0):这是最直观的模式。计数器从0开始向上计数,一直计到(PWMPERx - 1)。当计数值等于PWMDTYx时,输出电平根据极性设置发生翻转;当计数值达到PWMPERx - 1后,在下一个时钟周期计数器归零,输出电平复位,开始一个新的周期。波形在时间轴上是“左对齐”的,每个周期的起点是固定的。
- 周期计算:
PWM_Period = (PWMPERx) * T_clk。其中T_clk是所选通道时钟源的周期。 - 特点:实现简单,占空比分辨率是
1/PWMPERx。但其输出的谐波频谱中偶次谐波分量可能较大,在某些对电磁兼容性(EMC)要求高的场合(如电机驱动)可能不是最佳选择。
中心对齐模式(CAEx = 1):也称为“边沿对齐”或“对称PWM”。计数器从0开始向上计数到PWMPERx,然后立即向下计数回0,如此往复。在向上计数过程中,当计数值等于PWMDTYx时,输出电平发生一次翻转;在向下计数过程中,当计数值再次等于PWMDTYx时,输出电平再次翻转。这样,一个完整的周期是上计和下计的总和,波形以周期中心为对称轴。
- 周期计算:
PWM_Period = (2 * PWMPERx) * T_clk。注意,这里周期寄存器值需要乘以2。 - 特点:生成的PWM波形对称,其谐波频谱中主要以奇次谐波为主,且幅值相对左对齐模式更小,电磁干扰(EMI)性能通常更好。在电机控制(如正弦波驱动)和音频应用中更为常见。但需要注意的是,在中心对齐模式下,占空比调节的步进是
2/PWMPERx,因为一次完整的电平翻转需要上、下计数过程中各匹配一次。
实操心得:模式选择依据:在一般的LED调光、风扇调速等场合,左对齐模式完全够用,且计算直观。但在涉及电机控制(尤其是变频驱动)、需要生成正弦波或对噪声敏感的车载电子系统中,务必优先选择中心对齐模式。我曾在一个车载水泵控制器项目中,起初使用左对齐PWM驱动电机,电机运行时总伴有高频啸叫,频谱分析发现是特定谐波引起。切换到中心对齐模式后,啸叫明显减弱,系统通过EMC测试也更为顺利。
2.3 16位通道级联模式
对于需要更高精度PWM的应用(例如高精度数控电源、精密位置伺服),8位分辨率(256级)可能不够。MC9S12XE的PWM模块允许将两个8位通道级联成一个16位通道,分辨率提升至65536级。这是通过PWMCTL寄存器中的CON01、CON23、CON45、CON67位控制的。
当CON67=1时,通道6和7级联。此时:
- 主从关系:通道6成为高字节(High Byte),通道7成为低字节(Low Byte)。所有配置均以通道7为准。
- 控制寄存器:使能(
PWME7)、时钟选择(PCLK7)、极性(PPOL7)、对齐模式(CAE7)均使用通道7的配置位。通道6对应的这些控制位失效。 - 数据寄存器:16位的周期值 =
(PWMPER6 << 8) | PWMPER7;16位的占空比值 =(PWMDTY6 << 8) | PWMDTY7。写入时需要分别写入高8位和低8位。 - 输出引脚:仅使用通道7对应的
PWM7引脚输出波形,通道6的PWM6引脚被禁用。 - 计数器:形成一个16位的上下计数器,行为模式(左对齐/中心对齐)与单通道类似,但计数范围是0-65535。
注意事项:级联操作有一个严格的“锁步”要求。在修改
CONxx位(即进行级联或解级联操作)时,必须确保所涉及的两个通道都已被禁用(PWME6和PWME7都为0)。如果在通道使能状态下修改级联控制位,会导致不可预测的输出行为,甚至可能损坏外部硬件。同样,在级联模式下,对高字节寄存器(如PWMPER6)的写入也需要谨慎,最好在通道禁用时进行批量配置。
3. 寄存器配置实战与参数计算
理解了架构和模式,接下来就是动手配置。数据手册的寄存器描述是字典,但我们需要的是“菜谱”。下面我将以一个具体的实例贯穿始终:使用通道0产生一个频率为1kHz,占空比为30%的左对齐PWM波,系统总线时钟为8MHz。
3.1 时钟树配置与频率计算
这是最关键的一步,决定了PWM波的基准频率。我们的目标是1kHz。首先需要为通道0选择时钟源。通道0只能选择Clock A或Clock SA。
选择预分频器:先尝试只用预分频器(Clock A)。PWM周期公式(左对齐):
T_pwm = PWMPER0 * T_clkA,其中T_clkA = (预分频系数) / F_bus。 假设我们设置PWMPER0 = 100。那么所需T_clkA = T_pwm / PWMPER0 = (1/1000) / 100 = 10 us。对应的F_clkA = 100 kHz。 因此,预分频系数 =F_bus / F_clkA = 8MHz / 100kHz = 80。查看PWMPRCLK寄存器分频选项(1,2,4,8,16,32,64,128),没有80这个值。最接近的是64或128。若选64,F_clkA=125kHz,则PWMPER0 = F_clkA / F_pwm = 125,这是一个有效值(在0-255范围内)。若选128,F_clkA=62.5kHz,PWMPER0=62.5,不是整数,不可行。 所以,我们选择预分频系数64,即设置PCKA[2:0] = 110b(对应/64)。此时F_clkA = 8MHz / 64 = 125kHz。计算周期寄存器值:
PWMPER0 = F_clkA / F_pwm = 125kHz / 1kHz = 125。换算成十六进制是0x7D。检查是否超出255,没有,可行。考虑使用缩放器:如果我们希望
PWMPER0为一个更整的数(比如100),或者预分频器无法得到精确频率,就需要启用缩放器SA。公式变为:F_pwm = F_clkA / (2 * PWMSCLA * PWMPER0)。 如果我们想固定PWMPER0=100,则PWMSCLA = F_clkA / (2 * F_pwm * PWMPER0)。但这里F_clkA本身由预分频决定。我们需要联立方程。一个更简单的方法是:先确定一个合适的PWMPER0和PWMSCLA组合。例如,设PWMPER0=100,PWMSCLA=1,则F_clkA = 2 * 1 * 100 * 1kHz = 200kHz。那么预分频系数 =8MHz / 200kHz = 40,同样不在可选列表中。 尝试PWMPER0=125,PWMSCLA=1,则F_clkA=250kHz,预分频系数=32(可选)。PCKA[2:0]=101b(/32)。这个方案也可以。对比:方案一(仅预分频):PCKA=/64,PWMPER0=125。方案二(预分频+缩放):PCKA=/32,PWMSCLA=1,PWMPER0=125。两者结果一样,但方案二用了缩放器。通常,为了简化,如果仅用预分频就能得到整数周期值,就优先不用缩放器,减少一个配置变量。
我们选择方案一:仅使用预分频器。因此:
PWMPRCLK寄存器:PCKA[2:0] = 110b(0x06),PCKB暂时不用,设为默认000b。所以PWMPRCLK = 0x06。PWMSCLA寄存器:不使用缩放,可以写0x00或0x01,写0x00时按256处理,分频极大,实际上时钟SA会非常慢,只要我们不选择它作为时钟源就没影响。通常写0x00或0x01均可,这里写PWMSCLA = 0x00。PWMCLK寄存器:通道0选择Clock A,所以PCLK0 = 0。
3.2 周期、占空比与极性配置
- 周期寄存器:根据计算,
PWMPER0 = 125 = 0x7D。 - 占空比寄存器:占空比30%。在左对齐模式下,无论极性如何,高电平时间(或低电平时间)对应的计数值 =
占空比 * PWMPER0。- 如果设置极性为高电平有效(
PPOL0=1),输出起始为高,那么PWMDTY0存储的就是高电平计数值。PWMDTY0 = 0.3 * 125 = 37.5,取整为38(0x26)。实际占空比 =38/125 = 30.4%,存在量化误差,这是数字PWM的固有特性,分辨率越高误差越小。 - 如果设置极性为低电平有效(
PPOL0=0),输出起始为低,那么PWMDTY0存储的是低电平计数值。高电平计数值 =PWMPER0 - PWMDTY0。要得到30%高电平,需设置低电平占70%,即PWMDTY0 = 0.7 * 125 = 87.5,取整88(0x58)。高电平时间对应计数125-88=37,占空比=37/125=29.6%。如何选择极性?这通常由驱动电路决定。例如,使用N-MOSFET做高端开关时,常需要低电平有效信号再经过反相器驱动;而直接驱动LED阳极,可能高电平有效更简单。我们假设为高电平有效,即PPOL0=1,则PWMDTY0 = 0x26。
- 如果设置极性为高电平有效(
- 对齐模式:要求左对齐,所以
CAE0 = 0。 - 极性寄存器:
PWMPOL寄存器,设置PPOL0=1。 - 对齐使能寄存器:
PWMCAE寄存器,设置CAE0=0。
3.3 使能输出与完整初始化流程
配置PWM有一个严格的顺序,乱序可能导致第一周期波形异常或产生毛刺。
- 禁用通道:在配置任何参数前,先确保通道是关闭的。
PWME寄存器PWME0位清0。 - 配置静态参数:这些是通道使能后不应频繁更改的参数,特别是对齐模式
CAEx和级联控制CONxx。必须在通道禁用时设置。本例中,设置PWMCAE和PWMCTL(我们未使用级联,CONxx全0)。 - 配置时钟与波形参数:设置
PWMPRCLK,PWMSCLA,PWMCLK,PWMPER0,PWMDTY0,PWMPOL。这些参数在通道使能后虽然可以改(有双缓冲),但初始配置应在禁用状态下完成以保证确定性。 - 使能通道:最后,将
PWME寄存器的PWME0位置1。输出波形会在所选时钟的下一个上升沿开始生效。
避坑指南:双缓冲机制的理解:
PWMPERx和PWMDTYx寄存器都是双缓冲的。你写入的值首先进入一个缓冲区(Buffer),而真正驱动比较器的是另一个锁存器(Latch)。只有在“更新事件”发生时,缓冲区的值才会被拷贝到锁存器。更新事件包括:一个PWM周期结束、向计数器PWMCNTx写入任何值、通道被禁用。这个机制保证了你在PWM输出过程中修改参数,不会在一个周期中间产生畸变的波形,新的参数会在下一个完整周期开始时生效。这对于需要平滑改变占空比(如电机软启动)的应用至关重要。切记:如果你在运行时想改变频率或占空比,写入新值后,需要触发一个更新事件(例如,向PWMCNT0写一个值)来立即生效,否则会等到当前周期结束。
根据以上分析,完整的C语言初始化代码示例如下(假设寄存器已通过宏映射到内存地址):
void PWM_Channel0_Init(void) { /* Step 1: 禁用通道0 */ PWME &= ~(1 << 0); // PWME0 = 0 /* Step 2: 配置对齐模式 (左对齐) */ PWMCAE &= ~(1 << 0); // CAE0 = 0 // PWMCTL 默认全0,不级联 /* Step 3: 配置时钟源 */ // 设置Clock A预分频为64 (110b), Clock B不分频(默认000b) PWMPRCLK = 0x06; // PCKA=110b, PCKB=000b // 缩放寄存器A,不使用则写0 PWMSCLA = 0x00; // 通道0选择Clock A PWMCLK &= ~(1 << 0); // PCLK0 = 0 /* Step 4: 配置周期和占空比 */ PWMPER0 = 125; // 周期值,对应1kHz @ ClkA=125kHz PWMDTY0 = 38; // 占空比高电平计数,~30.4% /* Step 5: 配置极性 (高电平有效) */ PWMPOL |= (1 << 0); // PPOL0 = 1 /* Step 6: 使能通道0输出 */ PWME |= (1 << 0); // PWME0 = 1 }4. 高级应用与故障排查实录
4.1 同步触发与中断联动
MC9S12XE的PWM模块本身不直接产生中断,但它可以与周期中断定时器(PIT)模块联动,实现复杂的定时控制序列。这在数据手册PIT章节的“硬件触发”部分有提及。PIT模块可以产生周期性的硬件触发信号PITTRIG[x],这个信号可以连接到PWM模块(具体映射需查芯片数据手册的交叉开关部分),用于在特定时刻同步启动或重置PWM计数器。
例如,在一个多相电机控制中,可能需要三个相位差120度的PWM波。我们可以配置一个PIT定时器,产生三倍于PWM频率的触发信号。在每个PIT触发中断中,依次更新三个PWM通道的占空比寄存器,并写入其计数器(PWMCNTx)以触发双缓冲更新。这样,三个PWM通道就能实现严格的同步相位关系,避免了因软件执行时间不确定导致的相位抖动。
// 伪代码示例:利用PIT触发同步更新多路PWM interrupt void PIT_Channel0_ISR(void) { static uint8_t phase = 0; PITTF = 0x01; // 清除PIT标志位 switch(phase) { case 0: PWMDTY0 = duty_A; // 更新A相占空比 PWMCNT0 = 0; // 写入计数器,立即更新(左对齐模式) break; case 1: PWMDTY1 = duty_B; // 更新B相占空比 PWMCNT1 = 0; break; case 2: PWMDTY2 = duty_C; // 更新C相占空比 PWMCNT2 = 0; phase = -1; // 重置相位 break; } phase++; }4.2 常见问题排查与调试技巧
在实际开发中,PWM输出不正常是常事。下面是一些典型问题及排查思路:
问题1:无输出或输出恒定高/低电平。
- 检查引脚复用:首先确认
PWMx引脚是否已正确配置为PWM功能,而非普通的GPIO。这通常在系统集成模块(SIU)或端口控制寄存器中设置。 - 检查使能位:确认
PWME寄存器中对应通道的PWME位已设置为1。 - 检查时钟源:确认
PWMCLK选择正确,且上游的PWMPRCLK和PWMSCLA/B已配置。可以用示波器测量一下其他使用相同时钟源(如Clock A)的通道是否有输出,来验证时钟树是否工作。 - 检查周期和占空比:确认
PWMPERx和PWMDTYx的值是合理的。一个常见的错误是PWMPERx设置为0。根据数据手册,对于左对齐模式,如果PWMPERx=0x00,则计数器会一直计数到0xFF再溢出,周期是256个时钟。如果PWMDTYx也为0,则输出可能恒为高或恒为低(取决于极性)。 - 验证极性:如果
PPOLx=1且PWMDTYx >= PWMPERx,则输出恒高;如果PPOLx=0且PWMDTYx=0,则输出恒低。检查你的占空比计算是否正确。
问题2:输出频率或占空比与计算值不符。
- 总线时钟确认:所有计算的基础是准确的
F_bus。检查你的系统时钟配置(PLL、晶振分频等),确保CPU运行在预期的频率下。一个快速验证方法是:用PIT模块产生一个1秒的定时中断,翻转一个LED,看是否准确。 - 对齐模式混淆:这是最常见的错误之一。务必牢记:中心对齐模式的周期是
2 * PWMPERx * T_clk,而左对齐是PWMPERx * T_clk。如果你在中心对齐模式下用左对齐公式计算PWMPERx,得到的频率会是预期的一半。同样,占空比计算也会出错。 - 双缓冲更新时机:如果你在运行时修改了
PWMPERx或PWMDTYx,但没有触发更新事件(周期结束、写计数器、禁用通道),那么输出仍然是旧的波形。确保你的更新逻辑正确。
问题3:输出波形有毛刺或第一个周期异常。
- 遵循初始化顺序:数据手册明确警告:“使能通道后的第一个PWM周期可能是不规则的”。因此,标准的做法是:先完成所有配置,最后再置位使能位。避免在使能后短时间内频繁修改配置寄存器。
- 注意寄存器写入顺序:虽然手册说配置寄存器在使能前可以任意顺序写入,但良好的习惯是先配置时钟、周期、占空比、极性,最后配置对齐模式和使能。对于级联通道,一定要在两者都禁用的情况下配置
CONxx位。 - 电源与负载:如果驱动的是感性负载(如电机),PWM引脚上可能会感应出电压毛刺。确保硬件上有适当的缓冲电路(如栅极驱动器)、续流二极管和滤波电容。
调试技巧:
- 软件仿真:在IDE(如CodeWarrior)的调试器中,实时监控PWM相关寄存器的值,特别是计数器
PWMCNTx,看它是否在按预期递增/递减。 - 硬件测量:示波器是关键。测量输出波形的频率、占空比、上升/下降沿,并与计算值对比。观察使能瞬间的波形。
- 简化测试:开始时,使用最简配置:左对齐、最大分频(低频)、50%占空比。这样波形容易观察。成功后再逐步增加复杂度。
- 利用保留寄存器:
PWMTST和PWMPRSC是工厂测试寄存器,用户模式读为0。如果你意外写到了这些地址(通常不会),可能会导致模块行为异常。检查你的地址映射宏定义是否正确。
5. 低功耗模式与紧急关断
在电池供电或对功耗敏感的应用中,需要关注PWM模块在低功耗模式下的行为。
- 等待模式(Wait Mode):通过设置
PWMCTL寄存器中的PSWAI位,可以在MCU进入等待模式时,停止向PWM预分频器提供时钟。这会关闭整个PWM模块的时钟树,所有PWM输出停止,并显著降低功耗。当MCU退出等待模式时,时钟恢复,PWM从停止的状态继续运行。注意:这可能导致PWM输出相位不连续。 - 冻结模式(Freeze Mode):在调试或仿真时常用。设置
PWMCTL寄存器的PFRZ位,可以在MCU进入冻结模式(通常由调试器触发)时停止PWM时钟,方便观察系统状态。功能与PSWAI类似,但目的不同。
紧急关断(Shutdown):这是一个安全特性。PWM模块的通道7(PWM7)引脚复用为紧急关断输入(PWM7IN)。当PWMSDN寄存器中的PWM7ENA位使能此功能,且PWM7IN引脚检测到有效电平(可通过PWM7INL位选择高或低有效)时,所有PWM输出会立即被强制到一个安全状态(高电平、低电平或高阻态,由PWMLVL位决定)。同时,PWMIF标志位会被置起,如果PWMIE中断使能,还会产生中断。这个功能用于在系统故障(如过流、过热)时快速关闭功率输出,保护硬件。在电机驱动、电源设计中务必考虑并正确配置此功能。
配置紧急关断的步骤:
- 配置
PWM7引脚为输入功能(用于关断信号)或复用功能(具体看数据手册)。 - 在
PWMSDN寄存器中,设置PWMLVL决定关断时输出电平(例如,对于驱动桥臂,通常设为全低,防止上下管直通)。 - 设置
PWM7INL选择关断信号的有效电平(例如,低电平有效)。 - 使能关断功能:
PWM7ENA=1。 - (可选)使能关断中断
PWMIE=1,并在中断服务例程中处理故障。
6. 从8位到16位:高精度PWM配置实战
当我们需要高于8位(1/256 ≈ 0.4%)的分辨率时,就需要使用通道级联。假设我们需要一个16位PWM来控制一个精密电压基准,要求分辨率优于0.01%。我们将通道6和7级联。
目标:产生一个约100Hz的中心对齐PWM,占空比50%,系统总线时钟8MHz。
- 禁用通道:首先,确保
PWME6和PWME7都为0。 - 配置级联:设置
PWMCTL寄存器,CON67 = 1。此时,通道7成为主控通道。 - 配置通道7参数:
- 对齐模式:中心对齐,
CAE7 = 1。 - 时钟选择:选择Clock B或SB。为了获得更低的频率,我们选择Clock B并分频。设
PCLK7=0选择Clock B。 - 预分频:设置
PWMPRCLK的PCKB字段。目标频率很低,需要大分频。假设我们选PCKB=111b,即128分频。Clock B = 8MHz / 128 = 62.5kHz。 - 计算周期值:中心对齐周期公式
T_pwm = 2 * PWMPER67 * T_clkB。T_pwm = 1/100Hz = 10ms。T_clkB = 1/62.5kHz = 16us。 所以PWMPER67 = T_pwm / (2 * T_clkB) = 10ms / (2 * 16us) = 312.5。取整312(0x138)。实际频率F_pwm = 62.5kHz / (2 * 312) ≈ 100.16Hz。 - 16位周期值
PWMPER67 = 312 = 0x0138。因此,PWMPER6 = 0x01(高字节),PWMPER7 = 0x38(低字节)。 - 占空比:50%,所以
PWMDTY67 = PWMPER67 / 2 = 156 = 0x009C。PWMDTY6 = 0x00,PWMDTY7 = 0x9C。 - 极性:假设高电平有效,
PPOL7 = 1。
- 对齐模式:中心对齐,
- 写入寄存器:依次写入
PWMPER6,PWMPER7,PWMDTY6,PWMDTY7,PWMPOL,PWMCAE,PWMPRCLK,PWMCLK。 - 使能通道:最后,设置
PWME7 = 1。注意,PWME6在级联模式下无效,保持为0即可。
void PWM_16Bit_Init(void) { // 1. 禁用相关通道 PWME &= ~((1 << 6) | (1 << 7)); // PWME6=0, PWME7=0 // 2. 配置为16位中心对齐模式 (以通道7为主) PWMCTL |= (1 << 7); // CON67 = 1 PWMCAE |= (1 << 7); // CAE7 = 1, 中心对齐 PWMPOL |= (1 << 7); // PPOL7 = 1, 高电平有效 // 3. 配置时钟:Clock B, 128分频 PWMPRCLK = (0x07 << 4); // PCKB=111b (0x07), PCKA默认0 PWMCLK &= ~(1 << 7); // PCLK7=0, 选择Clock B (SB未用) // 4. 配置16位周期和占空比 // 周期 = 312 = 0x0138 PWMPER6 = 0x01; // 高字节 PWMPER7 = 0x38; // 低字节 // 占空比 = 156 = 0x009C PWMDTY6 = 0x00; // 高字节 PWMDTY7 = 0x9C; // 低字节 // 5. 使能通道7 (级联后仅通道7使能有效) PWME |= (1 << 7); // PWME7 = 1 }级联模式下的重要细节:在级联模式下,对16位数据的读写需要特别注意数据一致性。虽然你可以分别写入高、低字节寄存器,但在计数器运行期间,如果高、低字节写入操作之间被中断打断,可能会产生一个中间状态的错误周期值。对于要求严格的应用,建议在写入前禁用中断,完成两次写入后再开启中断。或者,更稳妥的方法是,在需要更新占空比/周期时,先禁用PWM通道(
PWME7=0),更新所有缓冲寄存器,然后重新使能。双缓冲机制会保证新值在下一个周期开始生效。
