
简介本资源是面向嵌入式控制开发者的TMS320F28335 DSP实战代码包聚焦PWM波形生成与输入捕获CAP两大核心功能适用于电机驱动、电源管理及工业实时控制系统等应用场景特别适合具备C语言基础与DSP外设配置经验的中级开发者快速掌握28335的EPWM与ECAP模块协同应用。压缩包共74个文件含11个C源码如cap.c、Example_EPwmSetup.c、30个头文件覆盖EPwm.h、ECap.h、SysCtrl.h等关键驱动定义、14个编译目标文件及3个汇编启动/延时文件辅以CMD链接脚本、CCS工程文件.pjt/.paf2和完整调试符号映射.map/.out结构完整可直接导入Code Composer Studio编译运行。目前已有158人学习下载资源提供从寄存器级定时器配置、死区设置、占空比动态调节到边沿捕获中断处理的全流程实现包含初始化函数、中断服务例程及典型波形验证逻辑是理解28335 PWM-CAP硬件协同机制的高实用性参考工程。1. 项目概述从“PWM-CAP.zip”看28335的波形生成与捕获最近在整理一个老项目的资料库翻到了一个名为“PWM-CAP.zip”的压缩包。这个文件名对很多搞电机控制、电源管理或者数字信号处理的朋友来说应该不陌生尤其是当你看到“28335”这个型号时。没错这指的就是TI德州仪器那款经典的C2000系列DSP——TMS320F28335。这个压缩包的名字几乎就是这款芯片在实时控制领域核心能力的缩写PWM脉冲宽度调制波生成与CAP捕获。前者是发出精确控制命令的“嘴”后者是感知外部世界变化的“耳朵”。今天我就结合这个项目包以及这些年踩过的坑和积累的经验来深入聊聊在28335上玩转PWM和CAP的那些门道。无论你是刚接触28335的新手还是想优化现有设计的老鸟希望这些从实际项目中提炼出的细节能给你带来一些启发。2. 核心思路为什么是28335的EPwm模块在开始看代码之前我们得先搞清楚为什么在众多微控制器中28335的PWM和CAP功能如此受青睐。这背后是芯片架构与应用场景的深度匹配。2.1 应用场景驱动架构设计28335是一款专为实时控制而生的数字信号处理器DSP。它的主战场是变频器、伺服驱动器、不间断电源UPS、数字电源这些领域。这些应用有一个共同特点对时序的精密度和确定性要求极高。电机需要精确的换相信号电源需要稳定的开关频率任何微小的时序抖动都可能导致效率下降、噪音增大甚至系统不稳定。因此TI为28335设计了高度专业化、独立于CPU内核的增强型脉宽调制ePWM模块和增强型捕获eCAP模块。它们不是普通的定时器外设而是自带专用逻辑、可以自主运行的小型协处理器。这意味着一旦配置好产生PWM和测量外部信号周期/占空比这些耗时且要求精准的任务可以完全由硬件完成CPU只需在关键时刻比如周期中断进行干预极大地解放了CPU资源保证了系统的实时性。2.2 EPwm模块的核心优势解析一个28335芯片内部集成了多达6个独立的ePWM模块EPwm1-EPwm6每个模块都能产生两路互补或独立的PWM输出EPWMxA和EPWMxB。它的强大之处在于其精细化的结构时间基准TB子模块这是整个PWM模块的“心脏”决定PWM的周期和频率。它的计数器模式增计数、减计数、增减计数直接决定了PWM是对称的、不对称的还是中心对称的这对电机控制中的谐波抑制至关重要。计数比较CC子模块这是决定PWM占空比的“大脑”。它包含CMPA和CMPB两个比较寄存器。当时间基准计数器的值等于这两个寄存器的值时就会触发事件进而控制输出电平翻转。通过软件动态修改CMPA/CMPB的值就能实时、无毛刺地调整占空比。动作限定AQ子模块这是执行具体操作的“手”。它根据TB和CC子模块产生的事件如“周期匹配”、“比较匹配”来规定输出引脚应该执行什么动作置高、拉低、翻转。正是这个模块让我们能够灵活生成各种复杂的PWM波形。死区DB子模块这是电力电子应用的“安全阀”。在驱动H桥、半桥等电路时上下两个开关管绝对不能同时导通直通否则会瞬间烧毁。死区模块就是在互补的两路PWM信号中插入一个可控的延迟时间确保一路关断后另一路才开启。事件触发ET子模块这是连接PWM硬件与CPU软件的“信使”。它可以在PWM周期的特定点如周期开始、比较匹配时产生中断通知CPU进行下一步计算比如更新下一个周期的占空比实现闭环控制。这种模块化设计使得配置一个PWM输出就像搭积木你需要什么功能就使能哪个子模块非常清晰。3. 关键配置从零生成一对带死区的互补PWM光说不练假把式。我们直接来看如何配置EPwm1模块产生一对频率为10kHz占空比初始为30%带死区保护的互补PWM波EPwm1A和EPwm1B。这里会涉及大量寄存器操作我会尽量解释每一个配置背后的意图。3.1 时钟与引脚初始化任何外设工作的前提是时钟。28335的时钟树比较复杂但针对ePWM我们通常关注系统时钟SYSCLKOUT经过低速外设时钟预定标器LOSPCP后的分频。为了精度我们通常将ePWM的时钟EPWMCLK配置为与系统时钟同频或简单分频。// 假设系统时钟已配置为150MHz // 配置ePWM时钟不分频 SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC 0; // 先停止所有ePWM模块的时基时钟以便同步配置 SysCtrlRegs.PCLKCR1.bit.ENABLEEPWM1 1; // 使能EPWM1模块时钟 // ... 其他ePWM模块时钟使能 SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC 1; // 同步启动所有ePWM时基时钟保证它们同时开始计数接下来是引脚复用。28335的GPIO很多功能是复用的需要将特定引脚配置为ePWM功能。// 将GPIO0配置为EPWM1A输出GPIO1配置为EPWM1B输出 EALLOW; // 解除寄存器保护 GpioCtrlRegs.GPAMUX1.bit.GPIO0 1; // 01b 选择EPWM1A功能 GpioCtrlRegs.GPAMUX1.bit.GPIO1 1; // 01b 选择EPWM1B功能 // 通常PWM输出引脚驱动能力要强可以配置为高驱动电流 GpioCtrlRegs.GPADIR.bit.GPIO0 1; // 输出方向 GpioCtrlRegs.GPADIR.bit.GPIO1 1; EDIS; // 恢复寄存器保护3.2 时基TB子模块配置这是设定PWM频率周期的地方。我们的目标是10kHz。系统时钟150MHz如果时基计数器采用增减计数模式先增后减那么一个完整的PWM周期计数器会从0增加到某个值TBPRD再减少回0。计数器每个时钟节拍加1或减1。因此PWM周期T_pwm 2 * TBPRD * T_clk其中T_clk 1 / 150MHz。 为了得到10kHz (T_pwm 0.0001s)可以计算TBPRD (T_pwm / (2 * T_clk)) (0.0001 / (2 * (1/150e6))) 7500。EPwm1Regs.TBCTL.bit.CTRMODE 2; // 增减计数模式产生对称PWM谐波特性好 EPwm1Regs.TBPRD 7500; // 设置周期寄存器值 EPwm1Regs.TBPHS.half.TBPHS 0; // 相位寄存器清零如果需要多个PWM模块同步这里会设置偏移 EPwm1Regs.TBCTL.bit.PHSEN TB_DISABLE; // 禁止相位加载主模块模式 EPwm1Regs.TBCTL.bit.HSPCLKDIV TB_DIV1; // 高速时钟分频设为1 EPwm1Regs.TBCTL.bit.CLKDIV TB_DIV1; // 时基时钟分频设为1即EPWMCLK直接驱动计数器注意TBPRD寄存器的值决定了PWM频率。在增减计数模式下实际计数最大值就是TBPRD计数器范围为0 - TBPRD - 0。在增计数模式下计数器范围是0 - TBPRD此时T_pwm (TBPRD 1) * T_clk计算时要注意区分。3.3 计数比较CC子模块配置这里设置占空比。在增减计数模式下占空比的计算稍微复杂一点因为存在上升段和下降段。通常我们通过设置比较值CMPA来控制EPWM1A的占空比。当计数器在上升过程中小于CMPA时输出一种状态大于CMPA时输出另一种状态。下降段同理但可以通过动作限定器灵活配置。我们想要30%的占空比。对于对称PWM高电平时间T_high 2 * CMPA * T_clk(在一种常见的配置下)。占空比D T_high / T_pwm (2 * CMPA) / (2 * TBPRD) CMPA / TBPRD。 所以CMPA D * TBPRD 0.3 * 7500 2250。EPwm1Regs.CMPA.half.CMPA 2250; // 设置比较器A的值控制占空比 EPwm1Regs.CMPCTL.bit.SHDWAMODE CC_SHADOW; // 使用影子寄存器模式防止更新时产生毛刺 EPwm1Regs.CMPCTL.bit.LOADAMODE CC_CTR_ZERO; // 在计数器等于零时将影子寄存器的值加载到活动寄存器影子寄存器模式是关键技巧。直接修改活动比较寄存器CMPA可能在计数器运行到任何值时发生这会导致当前PWM周期宽度异常产生一个“毛刺”脉冲。而影子寄存器允许我们在一个安全的时刻如计数器为零时一次性更新确保PWM输出的平滑。3.4 动作限定AQ子模块配置这是定义输出行为的地方。我们希望EPWM1A在计数器小于CMPA时为高电平大于CMPA时为低电平。对于增减计数模式需要分别设置上升段和下降段的动作。// 当时间基准计数器等于CMPA且正在递增时上升沿匹配EPWM1A输出拉低 EPwm1Regs.AQCTLA.bit.CAU AQ_CLEAR; // 当时间基准计数器等于CMPA且正在递减时下降沿匹配EPWM1A输出置高 EPwm1Regs.AQCTLA.bit.CAD AQ_SET;对于互补输出EPWM1B我们通常希望它与EPWM1A反相。但注意直接配置反相逻辑可能和死区模块的功能重叠。更常见的做法是先配置EPWM1A为主信号然后通过死区模块生成互补对。3.5 死区DB子模块配置死区时间是硬件安全的关键。假设我们需要500ns的死区时间。系统时钟周期T_clk 6.67ns。死区模块有独立的预定标器但我们为了简单使用与时间基准相同的时钟。那么死区寄存器值DB T_dead / T_clk 500ns / 6.67ns ≈ 75。我们需要配置死区模块在EPWM1A的上升沿和下降沿都插入延迟来生成EPWM1B。EPwm1Regs.DBCTL.bit.OUT_MODE DB_FULL_ENABLE; // 使能上升沿和下降沿死区 EPwm1Regs.DBCTL.bit.POLSEL DB_ACTV_HIC; // 极性选择EPWM1A高有效EPWM1B低有效互补 EPwm1Regs.DBRED 75; // 上升沿延迟值从EPWM1A上升沿到EPWM1B下降沿的延迟 EPwm1Regs.DBFED 75; // 下降沿延迟值从EPWM1A下降沿到EPWM1B上升沿的延迟这个配置的含义是以EPWM1A为参考在其上升沿后延迟75个时钟周期才让EPWM1B变为低电平开通在其下降沿后延迟75个时钟周期才让EPWM1B变为高电平关断。这样就确保了任何时刻EPWM1A和EPWM1B不会同时有效这里是同时为低因为驱动桥可能低电平有效。3.6 事件触发与中断配置为了让CPU能够实时更新占空比比如实现PID控制我们需要在PWM周期的特定时刻产生中断。// 在时间基准计数器等于零时每个PWM周期开始产生中断 EPwm1Regs.ETSEL.bit.INTSEL ET_CTR_ZERO; // 选择中断事件源 EPwm1Regs.ETSEL.bit.INTEN 1; // 使能EPWM1中断 EPwm1Regs.ETPS.bit.INTPRD ET_1ST; // 每个事件都产生中断 // 还需要在PIE外设中断扩展控制器中配置EPWM1_INT对应的中断服务程序ISR在中断服务程序中你可以读取传感器数据运行控制算法然后更新EPwm1Regs.CMPA.half.CMPA的影子寄存器值新的占空比将在下一个PWM周期生效。4. 另一面使用eCAP模块精确捕获外部PWM生成PWM是控制捕获CAP则是感知。28335的eCAP模块主要用来高精度测量外部脉冲信号的频率、周期和占空比。这在测速、解码编码器信号、同步外部事件时非常有用。4.1 eCAP模块的工作模式eCAP模块有四种工作模式通过ECCTL1[CAP1-4LDEN]和ECCTL2[CONT/ONESHT]等位配置单次捕获模式捕获指定数量1-4个的事件时间戳后停止。连续捕获模式循环使用4个捕获寄存器连续记录事件时间戳适合测量周期信号。APWM模式将eCAP模块配置为简单的PWM发生器当ePWM模块不够用时可以备用。正交编码器QEP模式配合另一个eCAP模块可以解码增量式编码器信号。最常用的是连续捕获模式测量频率和占空比。4.2 配置eCAP1测量外部PWM频率与占空比假设外部PWM信号连接到CAP1引脚如GPIO24我们需要测量其频率和占空比。步骤1引脚与时钟初始化EALLOW; GpioCtrlRegs.GPBMUX2.bit.GPIO48 3; // 将GPIO48/CAP1配置为捕获功能 GpioCtrlRegs.GPBDIR.bit.GPIO48 0; // 输入方向 EDIS; // 使能eCAP1模块时钟 SysCtrlRegs.PCLKCR1.bit.ECAP1ENCLK 1;步骤2配置捕获模式我们计划用CAP1捕获上升沿和下降沿。使用连续捕获模式4个深度的时间戳寄存器CAP1-CAP4循环使用。ECap1Regs.ECCTL1.bit.CAP1POL 0; // CAP1捕获上升沿 ECap1Regs.ECCTL1.bit.CAP2POL 1; // CAP2捕获下降沿 ECap1Regs.ECCTL1.bit.CAP3POL 0; // CAP3捕获下一个上升沿 ECap1Regs.ECCTL1.bit.CAP4POL 1; // CAP4捕获下一个下降沿 ECap1Regs.ECCTL1.bit.CTRRST1 0; // 捕获事件1CAP1后不复位计数器 ECap1Regs.ECCTL1.bit.CTRRST2 0; // 捕获事件2CAP2后不复位计数器 ECap1Regs.ECCTL1.bit.CTRRST3 0; // 捕获事件3CAP3后不复位计数器 ECap1Regs.ECCTL1.bit.CTRRST4 1; // 捕获事件4CAP4后复位计数器完成一个测量周期 ECap1Regs.ECCTL2.bit.CONT_ONESHT 1; // 连续运行模式 ECap1Regs.ECCTL2.bit.STOP_WRAP 3; // 在捕获事件4后停止并产生中断 ECap1Regs.ECCTL2.bit.REARM 1; // 使能一次重载为下一次捕获序列做准备 ECap1Regs.ECCTL2.bit.TSCTRSTOP 1; // 启动时间戳计数器步骤3计算频率与占空比当捕获到4个事件上升、下降、上升、下降后会产生中断。在中断服务程序中我们可以读取四个捕获寄存器的值。CAP1第一个上升沿时间戳t_r1CAP2第一个下降沿时间戳t_f1CAP3第二个上升沿时间戳t_r2CAP4第二个下降沿时间戳t_f2那么信号周期T (t_r2 - t_r1)个计数器时钟周期。如果计数器时钟是SYSCLKOUT150MHz则实际周期T_sec T * (1/150e6)频率Freq 1 / T_sec。第一个脉冲的高电平时间T_high (t_f1 - t_r1)。占空比Duty T_high / T。// 在eCAP1中断服务程序中 volatile unsigned long t_r1, t_f1, t_r2, t_f2, period, high_time; float freq, duty; t_r1 ECap1Regs.CAP1; t_f1 ECap1Regs.CAP2; t_r2 ECap1Regs.CAP3; t_f2 ECap1Regs.CAP4; // 注意处理计数器溢出但eCAP是32位计数器在150MHz下约28秒溢出对于kHz级PWM可忽略 period t_r2 - t_r1; high_time t_f1 - t_r1; freq 150000000.0 / (float)period; // 单位 Hz duty (float)high_time / (float)period * 100.0; // 单位 % // 清除中断标志为下一次捕获做准备 ECap1Regs.ECCLR.bit.CEVT4 1; ECap1Regs.ECCLR.bit.INT 1;实操心得eCAP的计数器是自由运行的32位计数器测量两个边沿的时间差。这种方法测量占空比非常准确但前提是信号要稳定。对于噪声较大的信号需要在输入引脚前端添加施密特触发器或RC滤波进行整形。另外计算时使用float会消耗较多CPU时间在实时性要求高的场合可以考虑使用定点数运算或提前计算好比例因子。5. 高级应用与避坑指南掌握了基本生成与捕获我们可以看看一些更复杂的应用场景和常见问题。5.1 多模块同步与相位控制在三相逆变器中需要6路PWM上下桥臂并且它们之间需要有固定的相位关系如互差120度。28335的ePWM模块支持主从同步链。配置主模块将EPwm1Regs.TBCTL.bit.SYNCOSEL设置为TB_SYNC_DISABLE或输出同步脉冲并配置EPwm1Regs.TBCTL.bit.PHSEN TB_DISABLE。配置从模块例如EPwm2和EPwm3。将它们的EPwm2Regs.TBCTL.bit.SYNCOSEL设置为TB_SYNC_IN接收外部同步。将EPwm2Regs.TBCTL.bit.PHSEN设置为TB_ENABLE使能相位加载。设置相位偏移在从模块的TBPHS寄存器中写入相位值。如果主模块周期是7500对应180度电角度那么120度偏移对应的值就是(120/180)*7500 5000。触发同步通过软件强制主模块产生一个同步脉冲EPwm1Regs.TBCTL.bit.SWSYNC 1;或者配置为在特定事件如周期匹配时自动输出同步信号。所有从模块在接收到同步信号时会将其时基计数器TBCTR重置为TBPHS的值从而实现精确的相位对齐。5.2 故障保护Trip Zone的紧急关断在电力驱动中过流、过压等故障发生时必须在微秒级甚至纳秒级内关闭PWM输出否则会损坏设备。ePWM的故障保护TZ模块就是为此设计的硬件快速响应通道。配置故障输入引脚将某个GPIO如GPIO12配置为TZ1功能。配置故障条件在TZSEL寄存器中选择哪些故障源TZ1-TZ6能触发哪个ePWM模块。配置故障响应在TZCTL寄存器中设置当故障发生时PWM输出引脚强制变成什么状态。通常设置为高阻Hi-Z或强制高/低电平取决于你的功率器件驱动逻辑是低有效还是高有效。EALLOW; EPwm1Regs.TZSEL.bit.OSHT1 1; // 使能一次性OSHT故障源1TZ1 EPwm1Regs.TZCTL.bit.TZA TZ_FORCE_HI; // 故障时EPWM1A强制高 EPwm1Regs.TZCTL.bit.TZB TZ_FORCE_HI; // 故障时EPWM1B强制高假设高电平关断MOSFET EDIS;清除故障故障发生后需要软件在排除故障后手动清除故障标志EPwm1Regs.TZCLR.bit.OST 1;才能重新使能PWM输出。重要注意事项故障保护是最后的安全防线其响应路径应尽可能短避免经过复杂的逻辑。务必通过硬件比较器或专用驱动芯片的故障信号直接连接到TZ引脚而不是经过CPU查询再动作。软件清除故障标志前必须有明确的故障恢复确认逻辑防止误操作。5.3 高分辨率PWMHRPWM对于需要极高PWM分辨率如数字电源中的电压微调的应用28335的HRPWM模块可以将占空比或相位的控制精度从系统时钟周期级别如6.67ns提升到皮秒ps级别。其原理是利用一个微边沿定位器MEP在系统时钟的两个边沿之间进行插值。启用HRPWM通常涉及使能HRPWM时钟SysCtrlRegs.PCLKCR0.bit.HRPWMENCLK 1。配置HRCNFG寄存器选择高分辨率模式应用于占空比CMPA HR还是相位TBPHS HR。使用特定的HRMSTEP校准值这个值出厂时存储在特定的OTP内存中需要软件读取并配置。之后向CMPAHR寄存器CMPA的高分辨率扩展部分写入值即可实现精细调整。踩坑记录HRPWM的校准值HRMSTEP每个芯片都不同且受温度和电压影响。如果应用环境苛刻可能需要在线校准。TI提供了相关的校准库和算法。忽略校准直接使用会导致高分辨率控制的实际精度严重偏离预期。6. 调试技巧与常见问题排查在实际开发中PWM和CAP相关的问题层出不穷。下面是一个快速排查清单现象可能原因排查步骤无PWM输出1. 时钟未使能。2. 引脚复用配置错误。3. 时基计数器未启动TBCTL.CTRMODE0。4. 输出被强制AQSF寄存器被置位。1. 检查PCLKCR0/1寄存器对应位。2. 检查GPxMUX寄存器。3. 检查TBCTL.CTRMODE。4. 检查AQSF和TZ相关标志位。PWM频率不对1.TBPRD计算错误。2. 时钟分频CLKDIV,HSPCLKDIV配置错误。3. 计数模式增/减/增减理解错误。1. 根据系统时钟和计数模式重新计算。2. 核对TBCTL中的分频位。3. 用示波器测量结合计数器模式分析波形。占空比无法改变1.CMPA影子寄存器未启用直接写活动寄存器被忽略。2. 更新影子寄存器的时机LOADAMODE与中断更新不同步。3. 写入的值超出范围大于TBPRD。1. 确认CMPCTL.SHDWAMODE1。2. 确认在CTR0的中断里更新CMPA并检查中断是否正常进入。3. 增加数值边界检查。互补波形有重叠直通风险1. 死区时间DBRED/DBFED设置过小或为0。2. 死区模块未使能DBCTL.OUT_MODE。3. 输出极性POLSEL配置错误。1. 用示波器双通道测量确保死区时间存在。2. 检查DBCTL寄存器配置。3. 根据驱动电路的有效电平调整极性。eCAP捕获值始终为0或不变1. 捕获引脚功能未启用。2. 捕获边沿极性配置错误。3. 时间戳计数器未启动TSCTRSTOP0。4. 输入信号电平不匹配如3.3V CAP引脚输入5V信号。1. 检查GPxMUX。2. 检查ECCTL1.CAPxPOL。3. 检查ECCTL2.TSCTRSTOP。4. 使用电平转换电路或分压电阻。eCAP测量值跳动大1. 输入信号有噪声或振铃。2. 中断处理时间过长导致捕获事件丢失。3. 未处理计数器溢出对于极低频率信号。1. 在输入端增加RC滤波或施密特触发器。2. 优化中断服务程序或使用DMA传输捕获值。3. 在中断中检查ECAPx的溢出标志并进行补偿计算。调试时一定要善用CCSCode Composer Studio的寄存器查看器和实时变量监控功能。你可以暂停CPU查看所有ePWM/eCAP寄存器的值与你的配置预期进行比对。同时一台带数字解码功能的示波器是必不可少的它能直观地显示PWM的频率、占空比、死区、相位关系是验证硬件配置最直接的工具。最后关于那个“PWM-CAP.zip”项目包它很可能就是一个实现了上述功能的工程模板包含了初始化、配置、中断处理以及一些基本的控制逻辑。理解每个寄存器配置位的含义远比直接套用代码更重要。当你透彻理解了28335的ePWM和eCAP模块后无论是实现复杂的多轴电机同步控制还是构建高精度的数字电源都有了坚实的硬件基础。剩下的就是结合你的具体控制算法去发挥这颗经典DSP的全部潜力了。本文还有配套的精品资源点击获取