news 2026/9/5 6:14:53

6路交错PWM实现:LAT1593中心对齐模式详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
6路交错PWM实现:LAT1593中心对齐模式详解

6路交错PWM这个需求,我是在做一台48V转12V/100A输出的大功率DC-DC时遇到的。输入电流纹波和输出电容的发热都压在面前,单路PWM怎么调都过不了温升,最后只能上交错方案。而在LAT1593上把Up Down计数模式玩明白之后,6路相位差60度发波这件事,其实比想象中要顺。这篇文章就把我整个从原理到代码再到实测的过程完整写出来,给同样要做多相交错电源或者电机控制的同行一个参考。

1. 为什么非要6路交错,单路PWM哪里不够用

1.1 单路PWM的纹波困境

单路Buck变换器在重载时的纹波问题是客观存在的。假设12V输出、100A负载,开关频率60kHz,电感选1μH,那么单相的电流纹波峰峰值大约在十几安培,这个脉动电流几乎全部要由输出电容来吸收。电容ESR只要有几毫欧,温升就会很难看,而且纹波电压也压不下来。

实际项目里我最初用单路方案,输出用了6个470μF的固态电容并联,ESR已经压到很低了,但满载时输入侧电流纹波依然大得离谱。输入线缆上的共模干扰还会影响到旁边一块控制板,最后查来查去,根源就是单路结构本身——所有能量都在一个开关周期内脉冲式地从输入端抽取,输入纹波电流等于输出电感纹波电流的一半加上负载电流的开关分量。

1.2 交错后的等效效果:纹波互消

交错PWM的思路很简单:把原来一路的大脉动拆成6路小脉动,每路承担约1/6的输出功率,而且在时间上让6路错开。6路均分一个360°载波周期,相邻两路之间相差60°,也就是1/6个开关周期。

这样做最大的收益在总电流上。6个电感的纹波电流不再是同相叠加,而是等相位差地相互错开。以60kHz、周期16.67μs为例,6路交错后,输出端总电流的纹波频率是360kHz,也就是开关频率的6倍,而纹波峰峰值在占空比不是极端值时,通常会降到单路的1/5到1/10。

有一个理想的极限情况特别能说明问题:当占空比D恰好等于1/6时,各路电感的脉动电流在时间轴上首尾相接,理论上总纹波电流为零。虽然实际中由于电感量差异和死区影响不可能完全为零,但那个数量级的差距已经足够让人满意了。

1.3 为什么载波要选Up Down计数模式

做交错PWM时,载波模式的选择直接影响纹波抵消效果。用递增计数模式也能做多路PWM,把各路的比较值依次延迟,但这里有个问题:边沿对齐的PWM脉冲是靠一边对齐的,各路脉冲的上升沿错开了,可是脉冲的中心位置并不均匀分布。在多相交错电源里,各路电流叠加后的总纹波会因为脉冲中心不齐而产生额外的低频分量,纹波抵消效果明显变差。

而Up Down计数模式,也就是中心对齐模式,计数器从0走到ARR再走回0,比较匹配产生的PWM脉冲天然关于计数周期中心对称。六路载波相位均匀错开后,各路脉冲的中心点也跟着均匀错开,电流叠加后纹波抵消的效果最干净。

中心对齐还有一个隐藏优势,对做数字电源的人尤其有用:可以在计数器下溢或上溢的时刻触发ADC采样,此时流过电感的电流正好等于平均电流,采样值不需要再做相位补偿。这在后面第6节我会详细展开。

2. Up Down计数模式下,PWM到底怎么生成

2.1 计数器运行轨迹

LAT1593的高级定时器在Up Down计数模式下,计数器从0开始向上计数,到达自动重装载值ARR后翻转方向,再向下计数到0,然后再翻转为向上,如此往复。一个完整的PWM周期算下来,计数器要走过 2 × ARR 个计数步。

这里有两个关键时间点:

  • 上溢事件:计数器到达ARR的那一刻。
  • 下溢事件:计数器到达0的那一刻。

在中心对齐模式下,通常上下溢事件都可以作为更新事件(Update Event)的来源,具体用哪一种可以在寄存器里配置。更新事件非常重要,它是PWM周期切换的标志,也是占空比影子寄存器同步装载的时刻,后面调试时遇到首脉冲异常的问题就和它有关。

2.2 比较匹配与输出翻转逻辑

PWM输出电平的翻转发生在计数器值与比较寄存器CCR匹配的时刻。以PWM模式1为例:

  • 向上计数过程中,计数器值等于CCR时,输出变为有效电平(默认高电平)。
  • 继续向上到达ARR后翻转方向,向下计数过程中再次等于CCR时,输出变为无效电平(默认低电平)。
  • 一直保持低电平到计数器回到0。

所以一个完整周期内,输出先是低电平,到达CCR后变高,随后又在下行段CCR处变低。高电平的中心正好落在计数器周期的中点(也就是ARR时刻),这就是中心对齐PWM的由来。

高电平持续时间由CCR与ARR的关系决定,占空比D = CCR / ARR(在CCR不超过ARR的前提下,0到100%均可实现,CCR大于ARR时恒为有效,等于0时恒为无效)。

2.3 实际频率计算

中心对齐模式下,PWM频率的计算公式是:

f_PWM = f_TCLK / ((PSC + 1) × 2 × ARR)

这个2倍是必须注意的,因为在Up Down计数模式下,计数器一个完整往返才是1个PWM周期,很多新手第一次配置时按递增模式算频率,结果实际输出频率少了一半。

我项目里的实际参数:LAT1593的定时器时钟为96MHz,预分频PSC取0,目标开关频率60kHz,代入公式:

60kHz = 96MHz / (2 × ARR)

解得ARR = 800。

这里有个经验之谈:做6路交错时,ARR的取值最好能被6整除或者接近整除,这样各路相位差对应的计数步长才容易取整。800虽然不能被6整除,但相位差是ARR × 2 / 6 = 266.67个计数步,取266或者267引入的误差在60kHz下只有约11纳秒,完全可接受。

3. 6路60°相位差:初值错相与同步启动

3.1 思路:多时基加相位初值

做6路交错PWM,很多人第一反应是:一个定时器有6个比较通道,用6个CCR不就行了吗?

实际工程中我不推荐这么做。用单一比较通道偏置去模拟不同载波相位,在中心对齐模式下很难做均匀,因为每个通道只有一个CCR,你很难同时表达“相位偏移后比较值超出ARR范围”的情况。就算用取模映射把比较值折回有效区间,PWM输出逻辑的正确性验证起来也相当麻烦。

我推荐的方案是:用LAT1593的多个独立时基(Timer单元),每个时基负责一路PWM。所有时基配置完全相同的PSC和ARR,也就是完全相同的载波频率和载波形状,但每个时基的计数器初始值不同,这样一路路在启动瞬间就处于载波周期的不同相位上,之后再以相同的速率增减计数,相位差自然保持不变。

3.2 相位初值表:ARR=800时的6路配置

在Up Down计数模式下,任意相位对应的瞬时计数值并不是线性递增的,而是一个三角波。以ARR=800为例,一个完整周期相位从0°到360°,计数器走过的路径是:

  • 0°时,计数器值为0,方向向上。
  • 90°时,计数器值为400,方向向上。
  • 180°时,计数器值为800,方向翻转。
  • 270°时,计数器值为400,方向向下。
  • 360°时,计数器值为0,方向再翻转。

如果6路相位分别是0°、60°、120°、180°、240°、300°,那么各路的初始配置如下表:

通道相位偏移计数器初值初始计数方向
CH00向上
CH160°266向上
CH2120°533向上
CH3180°800向下
CH4240°533向下
CH5300°266向下

这个方法对初值计算有两点要求。第一,60°对应的计数步长不是ARR/6,而是2×ARR/6 = ARR/3,因为一个完整360°周期对应的是计数器的往返全程。第二,对180°以后相位,瞬时值要按三角波的下降段映射,不能简单按ARR减去偏移量来算。我在第一次做时就直接套了个线性值,结果示波器上看CH3、CH4、CH5全挤在一起,相位关系完全不对。

3.3 同步启动:让6个计数器同时起步

初值写入正确只是第一步,更关键的是让6个时基在同一个时钟沿同时开始计数。如果不用同步机制,而是初始化完一个启动一个,第一个时基已经开始跑了,第六个才刚启动,相位差就完全不是预设的值了。

LAT1593的定时器同步方案有两种可选。第一种是硬件主从模式:把TIM0设为主机,产生触发输出;其余5个时基设为从机,接收到触发信号后启动。第二种是用软件触发:初始化完所有寄存器后,通过一条写操作同时启动多个时基。

我习惯用硬件主从模式,因为它有一个额外的好处——以后的启停都可以通过一个主定时器来控制,如果遇到故障需要同时封锁所有PWM输出,主从同步的逻辑会清晰很多。

有个初始化顺序的细节要提醒:必须先写入各时基的计数器初值,然后使能对应的自动重装载和预装载功能,最后才发送同步触发。如果顺序反了,先启动后写初值,计数器可能已经错过了初值装载窗口,首周期波形就会多出一个不正常的窄脉冲。

4. 初始化流程与代码骨架

4.1 核心初始化步骤

下面这段代码是通用化的C伪代码结构,具体寄存器名称以LAT1593的参考手册为准,但流程顺序是经过验证的。

// 第1步:使能6个时基的时钟 CLK_EnableTimerClock(TIM0); CLK_EnableTimerClock(TIM1); CLK_EnableTimerClock(TIM2); CLK_EnableTimerClock(TIM3); CLK_EnableTimerClock(TIM4); CLK_EnableTimerClock(TIM5); // 第2步:配置时基,全部使用Up Down计数模式 TIM_TimeBaseInitTypeDef tb; tb.Period = 800; // ARR tb.Prescaler = 0; // PSC tb.CountingMode = TIM_COUNTING_MODE_UPDOWN; tb.RepetitionCounter = 0; for (int i = 0; i < 6; i++) { TIM_TimeBaseInit(timBase[i], &tb); } // 第3步:配置输出比较,统一PWM模式1 TIM_OCInitTypeDef oc; oc.OCMode = TIM_OCMODE_PWM1; oc.Pulse = 400; // 50%占空比 oc.OCPolarity = TIM_OCPOLARITY_HIGH; for (int i = 0; i < 6; i++) { TIM_OCInit(timBase[i], TIM_CHANNEL_1, &oc); } // 第4步:写相位初值和方向(关键) uint16_t phaseInit[6] = {0, 266, 533, 800, 533, 266}; bool phaseDirUp[6] = {true, true, true, false, false, false}; for (int i = 0; i < 6; i++) { TIM_SetCounter(timBase[i], phaseInit[i]); TIM_SetCountingDirection(timBase[i], phaseDirUp[i] ? TIM_DIRECTION_UP : TIM_DIRECTION_DOWN); } // 第5步:配置主从同步 TIM_SelectMasterSlaveMode(TIM0, TIM_MASTER_TRIGGER_ENABLE); for (int i = 1; i < 6; i++) { TIM_SelectInputTrigger(timBase[i], TIM_TRIGGER_SOURCE_TIM0); TIM_SelectSlaveMode(timBase[i], TIM_SLAVE_MODE_TRIGGER); } // 第6步:发送同步触发,6路同时启动 TIM_GenerateTrigger(TIM0, TIM_TRIGGER_SOFTWARE);

这段代码里,第4步的相位初值表是整个方案的灵魂,必须放在启动触发之前执行完。我调试验证过,初值表和方向表只要错一位,最终的相位关系就会乱套。

4.2 占空比更新:预装载机制必须打开

运行中更新占空比时,要使用比较寄存器的预装载能力。比较寄存器CCR有两种工作方式:立即生效和预装载生效。预装载模式下,CCR的值先写入预装载寄存器,等到下一个更新事件(上溢或下溢)时才统一装载到实际比较寄存器。

这个机制在6路交错场景里极其重要。如果没有预装载,你在中断里依次更新6个通道的CCR,从第0路写到第5路有几十个时钟周期的时间差,这几路在同一个开关周期内的实际占空比就不一致,相电流就会瞬间不平衡。而开了预装载,6路会在同一个更新事件瞬间完成切换,相位关系和占空比关系始终保持一致。

4.3 三相全桥场景:3个时基加互补输出也能得到6路交错

如果你的6路PWM不是6相Buck,而是三相电机控制里的三相全桥驱动,那方案还可以简化:使用3个时基,每个时基输出2路互补PWM(PWMH和PWML),定时器内部自动插入死区。三个时基的初值分别设为0、266、533,方向都向上。

这时候看6个功率管的开关时刻:三个上管的相位分别是0°、120°、240°,三个下管因为与对应上管互补,相位分别是180°、300°、60°。汇总到所有6个开关器件上,刚好也是均匀交错60°。所以“6路交错”的语义在三相桥场景下依然成立,而且实现代码更少、死区更安全。

5. 实测相位精度与调试中踩过的坑

5.1 示波器验证相位的方法

代码下载之后,第一件事是用示波器验证相位关系。我用手上的四通道示波器加逻辑分析仪组合,一次看4路、分两批看完6路。测量方法很简单:触发源选CH0的上升沿,分别量CH1到CH5相对CH0上升沿的延迟时间。

在60kHz、占空比50%的条件下,各路上升沿的理论延迟为:

  • CH0:0μs
  • CH1:2.78μs
  • CH2:5.56μs
  • CH3:8.33μs
  • CH4:11.11μs
  • CH5:13.89μs

实际测出来的延迟和理论值相差在40纳秒以内,对于60kHz的载波来说,相位误差不到0.3°,这个精度来自计数器时基本身,足够满足电源交错控制的需求。

5.2 我踩过的三个坑

第一个坑是首周期窄脉冲。现象是启动后第一个开关周期内,某些通道会出现一个极窄的低电平毛刺。排查之后发现是计数器初值方向配置的问题,CH3初值是800,如果方向配成了向上,启动瞬间它会先尝试继续向上,但已经到顶了,会立刻触发上溢翻转,这个“立刻翻转”的动作在输出上就表现为一个异常窄的脉冲。把方向改成向下后问题消失。

第二个坑是更新占空比后相位漂移。现象比较隐蔽:稳态下相位差正常,但一旦负载变化、程序更新占空比,示波器上就能看到某些通道的相位发生了几十微秒的偏移,然后又慢慢回到正常。原因是第一版代码没开比较预装载,各通道CCR生效时刻不同,导致各路在一个“瞬间”处于不同相位。开了预装载后彻底解决。

第三个坑是修改开关频率时没有重算初值表。调试时我把ARR从800改成600,结果各路相位差不再是60°,而是乱七八糟的。因为相位初值表是严格按照ARR=800算出来的,修改ARR后必须重新计算。建议把初值表做成一个根据ARR运算的函数,而不是写死常量,这样后期调频率就方便了。

5.3 死区对相位测量的影响

在三相全桥场景中,插入死区后会有一点需要注意:互补通道PWML的上升沿会相对理论位置偏移一个死区时间。比如死区200ns,那么PWML相对于PWMH的下降沿会延迟200ns。如果你的应用对6路均分精度要求极高,测量时要把死区时间算进去。对于多相Buck的非互补输出场景,不存在这个问题,通道间只有正常的相位关系。

6. 扩展:从6路到更多相,以及与ADC联动

6.1 扩展到12路或更多路

多相交错的相数不是只能做6路。基于前面初值表的计算逻辑,我可以给出一个通用公式。

假设N路交错,ARR已知,相位偏移k×(360°/N),其中k=0,1,…,N-1。对应的瞬时计数初值:

  • 相位P = k × 2 × ARR / N
  • 将P对2×ARR做三角波映射(而不是简单的取余):
uint16_t P = (k * 2 * ARR) / N; uint16_t phaseInit, direction; uint16_t triPeriod = 2 * ARR; P = P % triPeriod; if (P <= ARR) { phaseInit = P; direction = TIM_DIRECTION_UP; } else { phaseInit = triPeriod - P; direction = TIM_DIRECTION_DOWN; }

用这个公式,12路交错只需要把N改成12,初值和方向会自动算出来。我在后续实验里试过12路,相邻相位差30°,总纹波频率等效到720kHz,输出端的电容压力进一步降低。

6.2 触发ADC采样:中心对齐模式的隐藏优势

中心对齐模式对数字电源最大的价值在于ADC同步采样。因为计数器在ARR或0位置时,电感电流恰好处于平均值附近,开关噪声也相对小,这是天然的采样点。

实现方法是在主定时器上配置下溢事件触发ADC触发源,每个PWM周期采样一次总输出电流。由于6路相位交错,各路电感电流的脉动并不整齐,但总输出电流在交错之后的纹波频率很高、幅值很小,在载波谷底采样得到的总电流值基本等于负载电流的直流分量,滤波计算量大大减小。

如果你希望采样到每一路的相电流,可以把ADC的触发源分别配置到对应时基的下溢事件上,这样每个时基都能在自己载波的谷底采样自己的电流,得到的就是该相电感的平均电流。这个配合在数字均流算法里非常实用。

6.3 最后分享一个小习惯

这个方案定型之后,我在实际项目里还养成了一个调试习惯:写上位机脚本把6路PWM的当前占空比、相位初值、ARR值一次性打印出来,检查配置和计算是否一致。做过多相交错的同行都知道,这种问题出在代码里往往不是算法难,而是初始化顺序、寄存器影子装载这类“小地方”最容易卡人。把状态可视化之后,排错速度快很多。

目前这套6路交错PWM已经在我的电源项目里跑了大半年,满载温升、输入纹波、输出电容发热都符合设计预期。如果你也在折腾多相交错、或者被MCU定时器的中心对齐模式绕晕了,希望这篇文章能帮你少走几步弯路。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/2 10:50:49

stop-slop快速检查12项清单:每篇AI文本发出前的必备自检

stop-slop快速检查12项清单&#xff1a;每篇AI文本发出前的必备自检 【免费下载链接】stop-slop A skill file for removing AI tells from prose 项目地址: https://gitcode.com/GitHub_Trending/st/stop-slop stop-slop 是一款开源的技能文件&#xff08;Skill&#x…

作者头像 李华
网站建设 2026/8/31 22:13:47

gh-aw交互式向导教程:TUI界面3步生成你的专属工作流

gh-aw交互式向导教程&#xff1a;TUI界面3步生成你的专属工作流 【免费下载链接】gh-aw GitHub Agentic Workflows 项目地址: https://gitcode.com/GitHub_Trending/gha/gh-aw gh-aw&#xff08;GitHub Agentic Workflows&#xff09; 让开发者用 Markdown 编写 AI 驱动…

作者头像 李华
网站建设 2026/9/1 7:17:14

人形机器人本体厂的生态卡位:透过对外投资看产业链布局

人形机器人本体的发布会越来越密集&#xff0c;但比发布会更值得琢磨的&#xff0c;是乐聚机器人这类“本体厂”近期的对外投资动静。在表面动作背后&#xff0c;暗含的是人形机器人赛道正在进行的“生态卡位”战。很多人的目光还停在整机demo、关节自由度、步行速度和价格上&a…

作者头像 李华
网站建设 2026/9/2 10:08:50

AI原生网络索引与搜索API实战:从RAG到Agent的接入指南

AI 应用最近卷到哪一步了&#xff1f;大家慢慢发现&#xff0c;真正难的不是让模型“说得好”&#xff0c;而是让模型“知道得新、知道得准”。本地知识库也好&#xff0c;Agent 工具链也罢&#xff0c;一旦需要实时外部信息&#xff0c;就得靠网络搜索。但传统搜索接口返回的是…

作者头像 李华
网站建设 2026/9/1 11:39:50

DeepSeek-Reasonix配置向导实战:reasonix setup三步完成DeepSeek接入

DeepSeek-Reasonix配置向导实战&#xff1a;reasonix setup三步完成DeepSeek接入 【免费下载链接】DeepSeek-Reasonix DeepSeek-native AI coding agent for your terminal. Engineered around prefix-cache stability — leave it running. 项目地址: https://gitcode.com/G…

作者头像 李华
网站建设 2026/9/1 0:03:58

FME自动化实战:1:1万DLG修测入库流程设计与避坑指南

1. 项目概述&#xff1a;当传统测绘遇上自动化利器 干了十几年测绘数据处理&#xff0c;最头疼的活儿是什么&#xff1f;十有八九的老师傅会告诉你&#xff1a; 1:1万比例尺DLG的修测入库 。这活儿就像给一张已经画得密密麻麻、线条错综复杂的城市地图做局部“微整形手术”&a…

作者头像 李华