1. 项目概述从基础PWM到互补输出的跨越玩过STM8或者STM32的朋友对PWM脉冲宽度调制肯定不陌生点个灯、驱动个舵机、让电机转起来基本都离不开它。但当你需要驱动一个半桥或全桥电路比如无刷电机的三相逆变器、开关电源的推挽拓扑时单个引脚输出的PWM就力不从心了。这时候“互补输出”就成了必须掌握的核心技能。简单说互补输出就是让两个引脚输出完全相反的PWM波形一个高电平时另一个必然是低电平。这听起来简单但实际配置起来特别是涉及到“死区时间”这个关键保护机制时里面门道不少。最近在调试一个STM8S系列芯片驱动的小功率电机驱动板正好把定时器的高级功能——互补PWM输出——从头到尾踩了一遍坑也理顺了其中的配置逻辑。这篇笔记就记录下整个过程重点不是罗列寄存器而是厘清“为什么要这么配”以及“配置时最容易忽略的细节”。对于STM8来说其高级定时器TIM1和TIM2部分型号支持互补输出。我们常说的PWM模式1、模式2中心对齐还是边沿对齐在互补输出场景下理解会更深一层。更重要的是死区时间的插入是硬件完成的这既保证了安全又解放了CPU但它的计算和配置方式直接关系到电路能否可靠工作。我会结合IAR for STM8的开发环境从定时器的基础时钟配置开始到最终在示波器上观察到带死区时间的完美互补波形把每一步的原理和实操选择都讲清楚。无论你是刚开始接触电机驱动还是对STM8的定时器高级功能感到困惑希望这篇笔记都能提供一个清晰的、可复现的参考路径。2. 核心需求与硬件原理剖析2.1 为什么需要互补PWM输出想象一下控制一个H桥电路驱动直流电机正反转。桥臂的上管和下管比如Q1和Q2绝对不能同时导通否则电源就直接短路了瞬间烧毁MOS管。最安全的控制逻辑就是互补当Q1的栅极信号为高电平导通时Q2的栅极信号必须为低电平关断反之亦然。这就是互补PWM最根本的应用场景——驱动桥式电路。在STM8的高级定时器里对于同一个通道比如CH1它可以映射到两个物理引脚上一个是标准输出通道比如TIM1_CH1 PA2另一个是它的互补输出通道TIM1_CH1N PA3。控制器内部硬件保证了这两个输出的极性是反相的。你只需要配置好一个通道的PWM参数周期、占空比它的互补通道会自动生成反相波形无需软件干预。这种硬件级的互补关系确保了信号的严格同步和极高的可靠性软件延迟在这里几乎可以忽略不计。2.2 死区时间互补输出的“安全气囊”如果互补的两个信号是理想的、瞬间翻转的那么理论上不会发生上下管直通。但现实是骨感的MOS管有开启延迟Turn-on delay和关断延迟Turn-off delay。通常关断比开启更慢。假设我们给上管Q1发送关断信号的同时给下管Q2发送开启信号。由于Q1关断得慢而Q2开启得快在某个极短的时间内两个管子可能都处于半导通状态从而形成一个大电流通路这就是“直通”Shoot-through危害极大。死区时间就是为了解决这个问题而生的。它的原理很简单在互补的两个信号切换状态时插入一个两者都为低电平即都关断的短暂时间窗口。具体来说当信号要从“上管开、下管关”切换到“上管关、下管开”时先关闭上管然后插入一段死区时间此时上下管控制信号都为低之后再开启下管。反之亦然。这样就确保了一个管子完全关断后另一个管子才开启从根本上避免了直通。STM8的定时器硬件集成了死区时间发生器它通过一个可配置的寄存器位DTG来设置这个时间长度。这个时间是硬件自动插入到互补输出对中的对用户透明你只需要计算并设置好值即可极大地简化了软件设计并提高了系统安全性。2.3 STM8定时器资源选择STM8S系列中主要看TIM1和TIM2。TIM1 (Advanced Control Timer)这是功能最全的高级定时器16位支持互补输出、死区时间插入、刹车功能、编码器接口等。它是实现本项目功能的唯一选择。它的四个通道CH1, CH2, CH3, CH4都有对应的互补输出通道CH1N, CH2N, CH3N, CH4N。TIM2/TIM3 (General Purpose Timer)通用定时器通常不支持硬件互补输出和死区时间。虽然可以通过软件模拟反相但无法保证精确同步且无法插入硬件死区不适用于对可靠性要求高的功率驱动场景。因此我们的硬件设计必须将MOS管的驱动信号连接到TIM1的通道和互补通道引脚上。例如使用TIM1_CH1和TIM1_CH1N来控制一个H桥的上臂和下臂。3. 开发环境与工程配置要点3.1 IAR for STM8基础工程搭建我使用的是IAR Embedded Workbench for STM8。新建工程时选择对应的STM8S型号例如STM8S105K4。在工程选项中有两处关键配置Debugger: 选择你使用的仿真器如ST-LINK。Library Configuration: 通常选择“Full”或者根据需求选择。对于直接操作寄存器来学习底层原理的方式库的选择影响不大但保持默认即可。注意IAR for STM8的编译器对代码尺寸优化比较激进。在调试阶段特别是涉及精确时序时建议先在“Optimizations”选项中设置为“Low”或“None”避免编译器优化掉一些你认为有用的延时循环或变量操作导致现象和预期不符。等全部功能稳定后再尝试提高优化等级。3.2 时钟树配置PWM频率的基石PWM的频率和分辨率都依赖于定时器的时钟源。STM8的时钟源多样但最常用的是内部16MHz高速RC振荡器HSI。TIM1的时钟可以来自系统时钟fMASTER或者外部时钟。为了获得稳定且灵活的PWM频率我们通常将系统时钟配置为最高速例如HSI 16MHz经过分频或不分频然后通过TIM1的预分频器PSCR寄存器进行二次分频得到定时器的计数时钟fCK_CNT。计算公式fCK_CNT fMASTER / (PSCR 1)例如fMASTER 16MHz 设置PSCR 0则fCK_CNT 16MHz。这是定时器计数的“心跳”它决定了计数的快慢最终影响PWM的周期精度。配置心得在main函数最开始先通过CLK_HSIPrescalerConfig等函数如果使用标准外设库或直接配置CLK_CKDIVR寄存器将系统时钟设置到想要的频率。这是一个容易忽略的步骤如果系统时钟没配对后面怎么算PWM频率都是错的。4. TIM1互补PWM输出详细配置步骤这里我们以边沿对齐模式、PWM模式1、输出比较通道1CH1和CH1N为例展示从零开始的寄存器级配置流程。理解寄存器每一位的作用比单纯调用库函数更能帮你排查问题。4.1 第一步GPIO引脚模式配置TIM1的通道引脚需要配置为推挽输出模式并且最好是高速输出以确保PWM边沿陡峭。// 假设 CH1 - PA2, CH1N - PA3 PA_DDR | (1 2) | (1 3); // 设置PA2, PA3为输出方向 PA_CR1 | (1 2) | (1 3); // 配置为推挽输出模式 PA_CR2 | (1 2) | (1 3); // 配置为高速输出 (10MHz)关键点CR2寄存器配置输出速度很重要。对于几百kHz以上的PWM信号必须选择高速模式10MHz否则引脚上升/下降沿太缓可能导致MOS管在开关过程中长时间处于线性区发热严重甚至损坏。4.2 第二步定时器时基单元配置这是决定PWM周期频率的环节。涉及TIM1_PSCRH/L预分频器、TIM1_ARRH/L自动重装载值和TIM1_CR1控制寄存器1。设置预分频器PSCR降低计数时钟频率。// 设置预分频值为0即不分频f_CK_CNT f_MASTER 16MHz TIM1_PSCRH 0x00; TIM1_PSCRL 0x00;设置自动重装载值ARR这是PWM的周期值。// 假设我们要产生一个20kHz的PWM。计算公式PWM频率 f_CK_CNT / (ARR 1) // 所以 ARR f_CK_CNT / PWM_Freq - 1 16,000,000 / 20,000 - 1 799 TIM1_ARRH (799 8) 0xFF; // 高位字节 TIM1_ARRL 799 0xFF; // 低位字节PWM周期T (ARR 1) / f_CK_CNT。配置计数模式在TIM1_CR1寄存器中设置。// DIR0 向上计数 CMS00 边沿对齐模式 CEN0 先不开启计数器 TIM1_CR1 0x00;4.3 第三步输出比较与PWM模式配置这是决定PWM占空比和输出极性的环节。主要配置TIM1_CCMR1通道1模式寄存器和TIM1_CCER1捕获/比较使能寄存器。配置通道1为PWM模式1// OC1M 110 (PWM模式1) OC1PE 1 (预装载使能) // 在PWM模式1下当计数器CNT CCR1时参考信号OC1REF为有效电平取决于极性否则为无效电平。 TIM1_CCMR1 0x68; // 二进制 0110 1000OC1PE1非常关键。它允许你在PWM运行过程中修改CCR1值但新值要到下一个更新事件计数器溢出时才生效这避免了在一个PWM周期中间改变占空比可能产生的毛刺或窄脉冲。配置输出极性和使能// CC1P0 (CH1输出高电平有效) CC1NP0 (CH1N输出高电平有效) // CC1E1 (使能CH1输出) CC1NE1 (使能CH1N互补输出) TIM1_CCER1 0x03; // 二进制 0000 0011极性理解“有效电平”指的是PWM波形中我们认为是“导通”或“激活”状态的电平。例如驱动一个高电平导通的MOS管通常设置CCxP0高电平有效。此时占空比指的是有效电平高电平时间占总周期的比例。互补通道CCxNP可以独立设置通常设置成一样的这样CH和CHN才是真正的逻辑反相。4.4 第四步死区时间Dead Time配置这是互补输出的精髓所在通过TIM1_DTR死区时间寄存器和TIM1_BKR刹车寄存器配置。计算并设置死区时间 STM8的死区时间DT由DTG[7:0]这8位控制计算公式分段当DTG[7:5]0xx时DT DTG[6:0] * T_dtg其中T_dtg T_CK_CNT。当DTG[7:5]10x时DT (64 DTG[5:0]) * 2 * T_dtg。当DTG[7:5]110时DT (32 DTG[4:0]) * 8 * T_dtg。当DTG[7:5]111时DT (32 DTG[4:0]) * 16 * T_dtg。其中T_dtg 1 / f_CK_CNT。假设f_CK_CNT16MHz我们需要插入500ns的死区时间。T_dtg 1/16MHz 62.5ns。DT 500ns 需要的计数单位数N DT / T_dtg 500 / 62.5 8。8落在第一个区间0-127所以直接设置DTG 8即可。TIM1_DTR 0x08; // 设置死区时间约为500ns使能死区时间和互补输出 死区时间功能、互补输出以及刹车功能都由TIM1_BKR刹车寄存器的最高几位控制。// MOE1 (主输出使能必须置1才能输出PWM) OSSI1 (输出空闲状态1可选) // BKE0 (刹车功能禁用) AOE0 (自动输出使能可选) // 这里关键是MOE位。 TIM1_BKR 0x80; // 二进制 1000 0000核心要点MOE位是总开关。即使前面所有通道都配置正确如果MOE0那么所有输出包括互补和死区都会被禁止。这是一个常见的“坑”配置了半天没波形首先检查TIM1_BKR寄存器。4.5 第五步启动定时器最后使能计数器并产生一个更新事件以加载所有预装载寄存器ARR, CCR1等的值。// 产生一个软件更新事件将预装载寄存器的值传送到影子寄存器 TIM1_EGR 0x01; // UG1 // 使能计数器开始产生PWM TIM1_CR1 | 0x01; // CEN1至此理论上你应该能在PA2和PA3上测量到频率20kHz、带约500ns死区时间的互补PWM波形了。占空比可以通过修改TIM1_CCR1H/L的值来动态调整由于开启了预装载修改是安全的。5. 示波器实测与波形分析配置完成后最激动人心的就是上示波器验证。将探头分别连接到CH1PA2和CH1NPA3使用双通道模式并打开上升沿/下降沿延时测量功能。你应该观察到的现象反相关系两个通道的波形在大部分时间是严格反相的。一个为高时另一个为低。死区窗口在每次电平跳变无论是上升沿还是下降沿的时刻两个通道会同时出现一段都为低电平的区域。这段区域的宽度就是你设置的死区时间。用示波器的光标功能测量这个宽度应该接近你计算的500ns考虑到晶振误差和示波器精度。占空比控制修改TIM1_CCR1的值例如设置为ARR值的一半400你应该看到CH1的占空比变为50%同时CH1N的占空比也自动变为50%且保持互补和死区关系不变。实测心得探头接地要短测量高频PWM时一定要使用探头自带的接地弹簧针而不是长长的鳄鱼夹地线。长地线会引入振铃和噪声导致测量到的死区时间不准甚至看到虚假的直通现象。同步触发将示波器的触发源设置为CH1触发类型为上升沿。这样可以稳定波形便于观察死区。检查空闲状态在代码中尝试将MOE位清零观察输出引脚的电平。这个电平由OSSI和CCxE/CCxNE等位共同决定了解它在“刹车”或关闭状态下的行为对设计故障保护机制很重要。6. 常见问题排查与进阶技巧6.1 问题一完全没有波形输出检查顺序遵循“电源-时钟-GPIO-定时器使能-主输出使能”的路径。电源和复位芯片供电是否正常是否在复位状态系统时钟f_MASTER确认配置正确了吗可以用一个GPIO翻转来间接测试系统时钟频率。GPIO配置确认引脚复用功能是否正确开启STM8的引脚复用功能通常是默认的但也要查数据手册确认该引脚在复位后是否是定时器功能。定时器时钟TIM1_CR1.CEN1了吗终极开关TIM1_BKR.MOE位必须设为1这是最容易被遗忘的一点。6.2 问题二有波形但不是互补的或者没有死区检查互补使能TIM1_CCER1寄存器中的CC1NE位使能了吗检查极性CC1P和CC1NP设置是否一致如果设置相反两个通道会同相。死区未生效首先确认TIM1_DTR寄存器值是否已正确写入。其次死区时间只在互补输出使能且MOE1时才生效。如果只使能了CH1 (CC1E1)而没使能CH1N (CC1NE0)死区发生器是不工作的。6.3 问题三PWM频率或占空比不对频率不对检查f_MASTER和TIM1_PSCR、TIM1_ARR的计算。记住公式Fpwm f_CK_CNT / (ARR 1) 而f_CK_CNT f_MASTER / (PSCR 1)。使用示波器测量实际周期反算频率与理论值对比。占空比不对检查TIM1_CCR1的值。占空比 CCR1 / (ARR 1)。注意在边沿对齐模式下当CCR10时输出恒为无效电平当CCR1 ARR时输出恒为有效电平。6.4 进阶技巧中心对齐模式与移相PWM除了边沿对齐模式TIM1还支持中心对齐模式又称向上/向下计数模式。在此模式下计数器先向上计数到ARR再向下计数到0。PWM信号在计数器向上和向下计数时各比较一次这使得PWM波形关于中心对称。配置中心对齐模式TIM1_CR1 | 0x10; // CMS 01 (中心对齐模式1)中心对齐模式的优点是其产生的PWM谐波分量更小在某些电机驱动和电源应用中能降低电磁干扰EMI。它的频率计算也略有不同Fpwm f_CK_CNT / (2 * ARR)。移相PWM在一些复杂的拓扑如全桥移相软开关电源中需要多路PWM之间有一定的相位差。STM8的TIM1虽然不能直接硬件生成移相但可以通过多个定时器如TIM1和TIM2同步或者巧妙利用一个定时器的多个通道并软件调整其CCRx寄存器的初始值来模拟实现。例如让CH1和CH2使用相同的ARR周期但设置不同的CCR1和CCR2值并配合输出极性可以产生具有一定相位关系的PWM但这需要更精细的计算和控制。6.5 刹车功能简介TIM1的刹车Break功能是一个重要的安全特性。当外部刹车信号输入通常来自过流保护电路有效时硬件会自动将MOE位清零并按照预设将PWM输出引脚强制置为一个安全状态通常全部关断同时可能产生中断。这对于功率驱动电路的实时保护至关重要。配置刹车功能涉及TIM1_BKR和TIM1_CR2等寄存器需要根据具体的硬件保护电路来设计。整个配置过程从时钟到GPIO再到定时器的各个功能单元是一环扣一环的。最好的学习方法就是动手写一段代码用示波器一个个引脚、一个个寄存器位去验证。当你看到那对带死区的、干净利落的互补波形在屏幕上稳定显示时之前所有的疑惑和纠结都会豁然开朗。STM8的这个功能麻雀虽小五脏俱全理解了它再去看STM32更复杂的高级定时器就会发现很多概念是相通的。