最近调AI8051U的三相SPWM变频驱动例程,算是把这个“3相互补PWM,相位差120度”的需求彻底跑通了。这块网上讨论不少,但完整的例程和调试心得比较散,我把自己从零配置PWMA、算SPWM占空比、到示波器验证波形的全过程整理出来,给后面做变频驱动、电机控制的兄弟省点时间。
这个例程的核心点是:AI8051U的PWMA模块输出3对互补PWM,也就是CH1/CH1N、CH2/CH2N、CH3/CH3N,每对的占空比按正弦规律变化,三对之间相位差120度,合成出来就是三相SPWM,可以直接驱动三相全桥逆变器去带电机。适合正在入门电机驱动、搞变频器、或者单纯想把STC系列高级PWM玩明白的人参考。我会把寄存器配置、参数计算、代码框架、实测验收一起说清楚,踩过的坑也会标出来。
1. 为什么用AI8051U的PWMA做三相SPWM
1.1 AI8051U这颗芯片到底好在哪
先说说选型。做三相SPWM变频,核心需求有三个:一是要有足够高的PWM频率和分辨率;二是必须有互补输出和死区控制,否则上下桥臂直通瞬间就能把功率管烧掉;三是生成三路相位准确的正弦占空比,CPU要有余量去实时算。
AI8051U这几个条件都满足。PWMA是它的高级PWM模块,专门干这个活的:每通道都带互补输出,死区时间可配,还能设置刹车输入做故障保护。这颗芯片主频最高能跑到40MHz往上(具体看型号和配置,以手册为准),即便用实时计算SPWM,每50微秒更新一次占空比也毫无压力。更舒服的是,AI8051U的指令集是增强型8051,代码不用像STM32那样建一堆工程文件,一个裸机工程就能搞定,适合快速验证算法。
用普通定时器软件翻转IO去模拟三相PWM,理论上也能转起来,但我劝你碰都别碰。三个通道的相位对齐靠软件中断去卡,中断一抖动,相位就歪了;死区更是麻烦,软件插入的死区不仅延迟不准,负载变化时还容易出短路风险。PWMA这种硬件外设的价值就在这里:你只要把寄存器配好,它自己保证互补、死区、相位关系,CPU只负责喂占空比数据。
1.2 SPWM生成方案:查表还是实时算
生成SPWM波形,业内常见两条路:查正弦表和实时计算。
查表法就是把一个周期的正弦值预先算好存到数组里,运行时按索引查。好处是CPU开销极小,老51也能跑,代码简单。缺点是想连续调频率比较麻烦,要么换不同点数的大表,要么用插值,不然频率一变,载波比就乱了。
实时计算就是用数学函数现场算正弦值。传统51受限于指令集,算一次sin要几十上百微秒,根本没法用。但AI8051U不一样,它带了硬件三角函数单元(TFPU),sin这类指令是硬件算的,速度快到可以忽略不计。这样我就能做到每载波周期都重新计算三相占空比,输出频率想怎么变就怎么变,完全连续平滑。
我的例程最终选了实时计算方式,配合TFPU算sin。如果你用的是没有TFPU的老8051,那就老老实实查表,128点或者256点正弦表足够,思路不变,只是把实时算换成查表取数。
2. 三相SPWM的参数怎么定
2.1 三相占空比公式,一句话讲清楚
SPWM的原理不复杂,就是拿一个正弦波和三角载波比较,正弦值高于载波就输出高电平,低于就输出低电平。把正弦波的瞬时值归一化到0到100%占空比,就是这样一个公式:
Da = 0.5 + 0.5 * M * sin(θ) Db = 0.5 + 0.5 * M * sin(θ - 2π/3) Dc = 0.5 + 0.5 * M * sin(θ + 2π/3)M是调制度,范围0到1,代表正弦波的峰值幅度。θ是当前相位,从0累加到2π再清零。0.5这个偏置是因为占空比只能是正的,把正弦波整体抬高到0~1之间,这样PWM的平均电压才能等效出正负变化的正弦电压。三相之间人为加上±120度的相位偏置,出来的三相占空比天然差120度,对应电机三相绕组的相位关系。
调制度M直接决定输出相电压幅值。M=1时输出最大,M减小相当于降压,电机转速就下来。实际变频器调压调频是一起做的,也就是常说的V/F比恒定,保证低速时磁通不饱和。
2.2 载波频率、输出频率、死区时间怎么搭配
这里三组参数要一起定,互相牵制。载波频率就是PWM本身的开关频率,决定功率管的开关损耗和电机噪音。输出频率是电机需要的正弦频率,比如5Hz到50Hz。载波比是载波频率除以输出频率,代表一个正弦周期里有多少个PWM周期。
我例程里用的默认参数是这样:
| 参数 | 数值 | 说明 |
|---|---|---|
| PWM频率(载波) | 20kHz | 高于人耳听感范围,噪音小,MOS管开关损耗可接受 |
| 输出频率范围 | 5Hz ~ 50Hz | 覆盖一般异步电机调速需求 |
| 最小载波比 | 400 | 20kHz / 50Hz,正弦波形平滑 |
| 死区时间 | 1μs | 适合MOS管桥臂,IGBT建议2~5μs |
| 调制度M | 0 ~ 1.0 | 对应V/F控制或开环调速 |
ARR值(自动重装载值)的计算公式是:ARR = 主频 / 预分频 / 载波频率 - 1。假设主频40MHz,不分频,ARR = 40000000 / 1 / 20000 - 1 = 1999。这个值代表一个PWM周期内计数器的最大值,CCR寄存器里写多少,就决定占空比多少。分辨率是1/2000,差不多0.05%的占空比精度,完全够用。
死区时间这个参数经常被人忽略,但它是三相桥能不能安全工作的命根子。上下桥臂如果同时导通,直流母线直接短路,瞬间几十安培电流就能炸管。死区就是让上下桥臂都关断一小段时间再开通,先关断、延迟、再开通,避免直通。死区大小取决于功率管的关断延迟和开通延迟。MOS管一般0.5~2μs,IGBT要2~5μs,宁大勿小,代价是略微增加谐波,但换取了安全性。
2.3 线电压利用率86.6%是怎么回事
经常看到资料说SPWM利用率最高只有86.6%,很多人不理解,我说下我的理解。SPWM的相电压基波幅值,在调制度等于1的时候,最大就是Vdc/2,也就是母线电压的一半。线电压等于两相相电压相减,幅值要乘√3,所以线电压基波最大幅值 = √3 × Vdc/2 ≈ 0.866 × Vdc。这个0.866就是SPWM的理论上限。
也就是说,直流母线电压100V,SPWM最多能输出86.6V(峰值)的线电压基波。想再往上榨电压,就要换SVPWM或者注入三次谐波,这两种方式可以把利用率推到接近1。我的例程做的是基础SPWM,先把原理跑通,后续要提升电压利用率,可以在这个框架上直接升级SVPWM算法,占空比计算那里换一下就行。
3. AI8051U的PWMA配置与代码实现
3.1 PWMA关键寄存器,先有个整体印象
AI8051U的PWMA是一个高级PWM外设,寄存器配置逻辑和STM32的高级定时器有相似之处。核心寄存器按功能分成几组:
- ARR寄存器:控制PWM周期,也就是载波频率。
- CCR1/2/3寄存器:控制各通道占空比,就是正弦瞬时值要映射的地方。
- CCER寄存器:使能各通道的主输出和互补输出,漏配这里会只有单端波形。
- BDTR寄存器:死区配置和主输出使能(MOE位),这是最容易忘的一步。
- CR1寄存器:PWM模式、对齐模式等基本配置。
如果你的目标芯片型号和我手里这颗寄存器的位定义有出入,一定以数据手册为准,我下面给的代码是按STC系列PWMA通用命名习惯写的,思路完全一样。
3.2 初始化流程,照着配就行
初始化PWMA,按顺序做这四步:时钟和引脚、周期结构、输出配置、使能输出。
// PWMA初始化示例(以AI8051U系列寄存器风格为例) void PWMA_Init(void) { // 1. 开启引脚复用,把PWM输出引脚切换到PWMA通道 // 不同型号引脚映射不同,查手册配P_SW或GPIO复用寄存器 // 2. 配置PWM周期:20kHz,主频40MHz // ARR = 40MHz / 20000 - 1 = 1999 PWMA_ARRH = 0x07; // (1999 >> 8) PWMA_ARRL = 0xCF; // (1999 & 0xFF) // 3. 配置CR1:边沿对齐模式,向上计数 // 如果芯片支持中心对齐,建议开启,谐波特性更好 PWMA_CR1 = 0x01; // CEN=1,使能计数器 // 4. 配置BDTR:死区时间约1us,使能主输出 // 具体分频和死区位,按数据手册公式换算 PWMA_BDTR = 0x80 | (死区配置值); // 5. 配置CCER:三路主输出+互补输出全部使能 PWMA_CCER1 = 0x55; // 通道1、2、3的CCxE和CCxNE置1 PWMA_CCER2 = 0x05; // 通道3的互补使能位根据通道分布调整 // 6. 初始占空比全设为0,避免上电瞬间输出异常 PWMA_CCR1H = 0; PWMA_CCR1L = 0; PWMA_CCR2H = 0; PWMA_CCR2L = 0; PWMA_CCR3H = 0; PWMA_CCR3L = 0; }提三个坑。第一个,BDTR的MOE位不置1,PWM引脚不会有输出,这是百分之百会踩的坑,排查第一件事就看它。第二个,CCER如果漏配了互补使能位,你会发现只有CH引脚有波形,CHN那个引脚纹丝不动。第三个,上电瞬间把占空比清零很重要,不然初始化那几十微秒里输出一个接近100%的占空比,碰到功率管没准备好,就可能出事故。
3.3 三相互补输出和120度相位差怎么实现
互补输出是硬件自动的,CH和CHN在同一时刻电平相反,中间插入死区。你只需要在CCR里写占空比,互补引脚自动跟着走,这比软件反相可靠得多。
三路之间120度相位差,我是这样做的:维护一个统一的相位变量θ,每次进PWM周期中断,用同一个θ分别计算三个通道的占空比,θ + 0度给A相,θ + 120度给B相,θ + 240度给C相。这样三相天然差120度,不会出现A、B两相误差零点几度的问题。
#define PI 3.14159265f #define TWO_PI 6.28318530f #define PWM_ARR 1999.0f // 对应20kHz载波,用于占空比换算 float phase_theta = 0.0f; // 当前相位,弧度制 // 在PWM周期中断里调用,更新三路CCR void Update_3_Phase_SPWM(float output_freq, float modulation) { float step = TWO_PI * output_freq / 20000.0f; // 每载波周期相位增量 float da, db, dc; unsigned int ccr_a, ccr_b, ccr_c; // 三相占空比,单位映射到ARR范围 da = (0.5f + 0.5f * modulation * sin(phase_theta)) * PWM_ARR; db = (0.5f + 0.5f * modulation * sin(phase_theta + TWO_PI / 3.0f)) * PWM_ARR; dc = (0.5f + 0.5f * modulation * sin(phase_theta + TWO_PI * 2.0f / 3.0f)) * PWM_ARR; // 写入CCR寄存器 pwma_write_ccr(1, (unsigned int)da); pwma_write_ccr(2, (unsigned int)db); pwma_write_ccr(3, (unsigned int)dc); // 相位累加,超过2π回卷 phase_theta += step; if(phase_theta >= TWO_PI) { phase_theta -= TWO_PI; } }这里注意B、C两相的相位偏置,我用的是加120度和加240度,相当于减120度。公式换成加240度之后,与前面文档里的正负120度写法等价,代码里尽量用同一个方向,减少绕脑子的概率。
还有一个细节:sin函数如果直接用不包一层转换,相位累加和回卷那里会有浮点精度问题。我习惯在相位超过2π后直接减掉一个2π,而不是用取余运算,避免浮点取余在边界上出现意外的负值或异常跳变。
3.4 中断频率和实时性怎么保证
三相SPWM的占空比更新必须和PWM周期同步,不然载波和调制波不同步,波形会乱。我的做法是PWMA配置成更新事件触发中断,也就是每20kHz一次中断,在中断里调Update_3_Phase_SPWM函数。20kHz中断意味着50微秒进一次中断,AI8051U在40MHz主频下处理这个开销非常轻松,中断占用时间占比只有几个百分点。
如果你用老51跑实时sin,这个方案就会很吃力,因为软件算sin一次几十微秒,三个就是上百微秒,中断还没结束下一个周期就来了。这种情况建议改成查表,把正弦表分成400份或者800份,每进一次中断查一下索引值,中断处理时间压到十微秒以内。
void PWMA_ISR(void) __interrupt { if(PWMA_SR1 & 0x01) // 更新事件标志 { Update_3_Phase_SPWM(current_freq, current_modulation); PWMA_SR1 = 0x01; // 清标志位 } }实际跑起来会发现,中断里除了更新CCR,其他事情尽量少做。调试时我试过在中断里塞串口打印,结果占空比更新被拉长,输出的正弦波形上有毛刺,明显看出来调制被破坏了。串口这类慢速操作放到主循环里,中断里只做最核心的算术和寄存器写入。
4. 调试过程与实测波形记录
4.1 分阶段跑通,不要一上来就接电机
三相逆变器最危险的调试方式,就是程序写完直接带电机上电。我调试这套例程分了三个阶段,每阶段都验证通过才进下一步。
第一阶段:不使能互补输出,只让三个CH引脚输出占空比固定的普通PWM,比如20%、50%、80%,用示波器确认三路PWM频率正确、占空比和CCR值对应准确。这个阶段主要验证GPIO复用、ARR逻辑、计数模式是否正确。
第二阶段:使能互补输出,不跑SPWM,只输出恒定的50%占空比,用示波器同时看CH1和CH1N,确认两路电平反向、死区时间正确。这个阶段把死区和互补关系验证掉,这是整块最危险的部分,单独验证安全可控。
第三阶段:跑SPWM实时计算,用示波器看单通道占空比是否按正弦变化,再看三路之间的相位差。全阶段都通过了再考虑接功率板、接电机。
4.2 波形怎么看,怎么算对不对
用示波器验证三相SPWM,先看单通道的占空比变化规律。占空比应该呈现一个低频正弦包络,这个低频频率就是输出频率。在50Hz输出时,示波器能明显看到占空比以50Hz的周期在拉高和拉低,整体包络形状光滑。
再看三路之间的关系。A、B、C三相的占空比包络波形形状完全一样,但在时间轴上互相错开三分之一周期。50Hz对应20ms周期,三相互差约6.67ms。示波器上如果相位偏移不对,大概率是相位偏置加错了,比如正负120度搞反,这时相序就反了,电机反转。
看互补输出带死区,要把示波器时间轴调到微秒级,观察CH1上升沿和CH1N下降沿之间的空隙。正常情况应该是先看到一个沿,间隔死区时间后另一个沿才动作,电平呈“先都关断,再一个导通”的状态。如果你看到两个引脚有瞬间同时为高的时刻,死区没生效,立刻断电查配置。
4.3 带电机跑起来之后的细节现象
波形没问题之后,我把输出接到三相全桥和一台小功率异步电机上。空载启动后,从10Hz慢慢往上调,电机转速平稳上升,电流声很安静,没有明显的“嗡嗡”共振声,说明载波20kHz选得合适。之前试过8kHz载波,电机带载时噪音明显偏大,调整到20kHz后基本听不到高频啸叫。
另一个观察点是母线电流。输出电压提高时母线电流随之上升,这是正常的,但要注意调制度M达到1.0之后再往上加,输出波形就会出现削顶,占空比跑到边界后正弦的顶部被切平,电流波形反而变差。这正好对应前面说的86.6%利用率问题,想继续提压就得换算法,不能硬超调制度。
5. 常见问题与排查技巧实录
5.1 上电就出短路,先查死区
三相桥炸管的大概率原因,按频率排:死区没配、互补输出极性写反、BDTR的MOE没置1导致引脚乱输出、调试时直接带负载没接保护。排查顺序一定是从安全到功能,先取掉母线供电,用万用表测上下桥臂的GS极之间有没有直通短路,确认控制板波形没问题再恢复供电。
死区检查有个快速办法:把占空比固定到50%,用示波器调出CH1和CH1N两条线,放大到每格几百纳秒,看两路电平切换之间有没有时间缝隙。缝隙存在说明死区生效了,没有缝隙,立刻查BDTR的死区配置位。
5.2 波形有正弦包络但三相互差不对
三相对了但相位关系乱掉,常见两种情况。第一种是B、C相偏置填错,输出不是120度而是240度或者反方向,表现是电机反转或者带载时剧烈抖动。解决办法是在代码里把偏置方向统一,每次只改一处,上电后用示波器对比A、B相第一个波峰的位置关系。
第二种是相序反转,这其实是正常现象,只要换任意两相输出,电机转向就会反过来。如果硬件走线不好换,改代码里B、C两相偏置对调也能实现。
5.3 电机低速抖动、高速啸叫
低速几下抖动,多数是启动瞬间调制度给得太大,电机定子电流冲击导致转矩脉动。我处理办法是启动时把输出频率从0开始缓慢增加,同时调制度跟着频率按V/F曲线爬升,避免直接给50Hz满幅。软件里面做一个斜坡函数,让频率和调制系数按一定斜率上升,几百毫秒内完成。
高速啸叫,优先怀疑载波频率过低,谐波分量进入音频范围。把载波频率提到16kHz以上,人耳基本听不见。要是还叫,检查是不是死区时间设置过大,导致电流波形畸变加重,试着把死区从3μs降到1μs看效果。
5.4 调试工具和测量注意事项
示波器测三相PWM,最容易被忽略的是探头地线。普通探头的地线夹子都接在示波器大地,测桥臂中点这种高压浮动点位时,地线夹子一夹就可能短路。测三相桥下管可以不隔离,测上管必须用差分探头或者隔离通道,没有隔离设备就只测PWM控制信号,不要直接去测功率侧。
以下是这次调试总结的问题排查速查表,收藏一下能省不少时间:
| 现象 | 优先排查方向 | 检查要点 |
|---|---|---|
| 引脚无输出 | BDTR主输出使能 | MOE位是否置1 |
| 只有主输出没有互补 | CCER互补使能 | CCxNE位是否配置 |
| 两路同时导通 | 死区配置 | BDTR死区值是否为0 |
| 三相互差不对 | 相位偏置代码 | 偏置角是否120/240 |
| 频率调不了 | 相位步长计算 | 输出频率是否映射到step |
| 波形包络有毛刺 | 中断负载 | 中断里是否有慢速IO操作 |
| 电机抖动 | 启动调制度 | V/F斜坡是否平滑 |
我个人在实际操作里最大的体会是:三相SPWM这件事,算法原理不难,难的是氛围和安全意识。每改一次死区或者相位参数,就默念一遍“先看波形再接功率、先断母线再动代码”,养成这习惯,能让你少买好几十个功率管。这个例程后续还可以直接往SVPWM、电流采样闭环同步、过流刹车保护这几个方向扩展,PWMA的刹车输入引脚就是为最后那个准备的,改天有空了我再写一篇专门聊刹车保护怎么和这例程接起来。