PWM输出
本节介绍
📝本节您将了解PWM(脉冲宽度调制)的基本原理及其应用,掌握TMS320F28P550的增强型PWM(ePWM)模块功能,并通过图形化配置工具实现LED呼吸灯效果。
🏆本章目标
1️⃣理解PWM的工作原理及其在嵌入式系统中的应用。
2️⃣熟悉TMS320F28P550的ePWM模块架构与功能特性。
3️⃣掌握使用SysConfig工具配置ePWM外设的方法。
4️⃣实践应用:通过ePWM输出10kHz方波,动态调节占空比实现LED呼吸灯效果。
PWM介绍
PWM(Pulse Width Modulation 脉宽调制)是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。它是一种对模拟信号电平进行数字编码的方法。是指在一定时间内波形的高电平(即 1 状态)所占用的时间比例。类似于方波的信号,具有固定的频率
,但脉冲宽度(占空比)可以调整。在一定频率下,我们可以通过调整这个占空比来改变它的有效电压,在一定程度上可以实现D/A转换(数字量转模拟量)。
脉冲宽度调制说明(点击展开)
脉冲宽度调制(PWM)是一种通过改变脉冲的宽度(脉宽/占空比)来控制电信号平均功率的技术。在PWM中,脉冲的频率一般保持恒定,但脉冲的宽度(有效电平的时间)根据需要的模拟信号变化,从而实现对电机速度、LED调光和温度控制等的精确控制。
![]() |
---|
举个例子
想象你有一个LED和一个开关,你以肉眼看不清的速度,快速反复地开关一次,这样LED灯就会亮一半时间,暗一半时间。如果你快速地进行这个操作,对于观察者来说,LED就像是以半亮度持续亮着。这就是PWM的基本原理。
如果你把大部分时间保持开关为关闭状态,那么LED会显得更暗;相反,如果你把开关大部分时间保持为打开状态,LED会显得更亮。这就是PWM调节占空比来控制亮度的过程。
PWM基本参数
PWM 是脉冲宽度调制,具有两个非常重要的参数:频率和占空比。
- 频率:PWM 信号的周期长度,通常使用赫兹 (Hz) 表示,表示每秒钟有多少个脉冲。PWM 的频率是整个周期的倒数。指 1 秒钟内信号从高电平到低电平再回到高电平的次数(一个周期)
- 占空比:占空比是指一个周期内高电平所占的比例。占空比可以表示为百分比,比如50%的占空比意味着高电平持续一半的周期,然后低电平持续另外一半。
F28P550上的PWM
F28P550上的PWM叫ePWM,是一种增强型脉宽调制器, 一共有12个,每一个有两个通道,A通道和B通道。
在开发板上的支持ePWM的引脚见下方的开发板引脚示意图:(蓝色的EPWM)
![]() |
---|
![]() |
![]() |
ePWM具有两种工作模式,分别是基于时基Time Base的PWM模式,和比较器Compare的PWM模式。这两种工作模式都具有向上计数模式,向下计数模式,向上向下计数模式。
![]() |
---|
以向上向下计数模式为例,计数值一直向上加到最大,再从最大一直减到最小。计数变化的期间,如果计数值等于了设置的阈值(比较值),则输出的信号进行翻转。
这样向上计数的时候必定会遇到一次阈值,信号进行翻转;向下计数的时候也必定会遇到一次阈值,信号又进行一次翻转;最终实现的效果如下:
![]() |
---|
案例实验介绍
用PWM功能配置蓝色LED灯的引脚输出一个10KHz的方波,通过控制方波的占空比,实现控制蓝色LED灯实现呼吸灯的效果,逐渐亮再逐渐灭,如此反复。
工程创建
打开CCS,创建一个新的基于 F28P55X 的工程。
![]() | ![]() |
---|---|
工程配置
配置工程选项,将我们后面写好的代码烧录到 FLASH
中,并且使用的烧录模式是 cJTAG(1149.7)2-pin
模式。
![]() | ![]() |
---|---|
ePWM的配置
打开工程下的 .syscfg 文件。找到 EPWM 选项开始配置:
在 EPWM Time Base 中,设置时钟为默认的 1 分频,定时器周期 7500,使用向上向下计数模式;
在 EPWM Counter Compare 中,在 CMPA 的下拉选项下,设置比较值(阈值)Counter Compare A (CMPA) 为0,即占空比为0%;
在 EPWM Action Qualifier 中,在 ePWMxA Event Output Configuration 的下拉选项下,设置向上计数到COMPA值时输出为高,向下计数到COMPA值时输出为高。
配置PWM到LED的引脚
![]() | ![]() |
---|---|
![]() | ![]() |
---|---|
关于输出频率和占空比的设置说明
ePWM时钟频率 EPWMCLK 来源为 SYSCLK,其默认为 150MHz。
CLKDIV 为 EPWM 定时器的时钟预分频;
HSPCLKDIV 为 EPWM 定时器的时钟二次预分频;
实际PWM的输出频率TBCLK = EPWMCLK / (HSPCLKDIV * CLKDIV)
定时器的周期值 = ePWM频率 / (2 * 希望输出频率)
希望输出频率 = ePWM频率 / (2 * 定时器的周期值)
COMPx 对比值 = (期望占空比 / 100) * 定时器的周期值
ePWM常用选项说明(点击展开)
EPWM Time Base
Time Base Clock Divider
:EPWM 定时器的时钟预分频High Speed Clock Divider
:EPWM 定时器的时钟二次预分频Time Base Period
:EPWM 定时器的周期值Counter Mode
:计数模式,有向上、向下、向上向下、不计数
EPWM Count Compare
Counter Compare A (CMPA)
: COMPA对比值的初始值设置,该值必须小于定时器周期值,用于设定PWM的占空比。
EPWM Action Qualifier
ePWMxA Time base counter equals zero
: 定时器的计数值到 0 时要进行的操作ePWMxA Time base counter equals period
: 定时器的计数值到 设定的周期值 时要进行的操作ePWMxA Time base counter up equals COMPA
: 定时器的计数值向上计数到 COMPA比较值 时要进行的操作ePWMxA Time base counter down equals COMPA
: 定时器的计数值向下计数到 COMPA比较值 时要进行的操作ePWMxA Time base counter up equals COMPB
: 定时器的计数值向上计数到 COMPB比较值 时要进行的操作ePWMxA Time base counter down equals COMPB
: 定时器的计数值向下计数到 COMPB比较值 时要进行的操作
相关函数介绍
//*****************************************************************************
//
//! 设置计数器比较值。
//!
//! \param base 是 EPWM 模块的基地址。
//! \param compModule 是计数器比较值模块。
//! \param compCount 是计数器比较计数值。
//!
//! 此函数用于设置计数器比较寄存器的比较值。
//! compCount 的最大值为 0xFFFF。
//! compModule 的有效值为:
//! - EPWM_COUNTER_COMPARE_A - 计数器比较 A。
//! - EPWM_COUNTER_COMPARE_B - 计数器比较 B。
//! - EPWM_COUNTER_COMPARE_C - 计数器比较 C。
//! - EPWM_COUNTER_COMPARE_D - 计数器比较 D。
//!
//! \return 无。
//
//*****************************************************************************
static inline void EPWM_setCounterCompareValue(uint32_t base, EPWM_CounterCompareModule compModule, uint16_t compCount);
//*****************************************************************************
//
//! 设置 PWM 周期计数值。
//!
//! \param base 是 EPWM 模块的基地址。
//! \param periodCount 是周期计数值。
//!
//! 此函数用于设置 PWM 的周期计数值。periodCount 的值将直接写入寄存器。
//! 用户应根据所需的波形周期或频率映射到正确的 periodCount。
//! 调用函数 EPWM_selectPeriodLoadEvent() 并传入适当的参数以设置周期计数的加载模式。
//! periodCount 的最大有效值为 0xFFFF。
//!
//! \return 无。
//
//*****************************************************************************
static inline void EPWM_setTimeBasePeriod(uint32_t base, uint16_t periodCount);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
案例验证
更新主函数代码
更新工程的 empty_driverlib_main.c 文件为以下代码:
#include "driverlib.h"
#include "device.h"
#include "board.h"
#include "c2000ware_libraries.h"
// 定义呼吸灯参数
#define BREATH_STEP 10 // 每次占空比变化步长
uint16_t brightness = 0; // 当前亮度值(0~7500)
int8_t direction = 1; // 亮度变化方向(1=渐亮,-1=渐灭)
// 呼吸灯控制函数
void breath_led_update(void)
{
// 更新亮度值
brightness += direction * BREATH_STEP;
// 边界检测与方向反转
if (brightness >= 7500)
{
brightness = 7500;
direction = -1; // 达到峰值后开始递减
} else if (brightness <= 0)
{
brightness = 0;
direction = 1; // 达到谷值后开始递增
}
// 设置EPWM比较值
EPWM_setCounterCompareValue(myEPWM_BLUE_BASE, EPWM_COUNTER_COMPARE_A, brightness);
}
void main(void)
{
Device_init();
Device_initGPIO();
Interrupt_initModule();
Interrupt_initVectorTable();
Board_init();
C2000Ware_libraries_init();
EINT;
ERTM;
while(1)
{
//呼吸灯的更新
breath_led_update();
//1ms延时
DEVICE_DELAY_US(1000);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
下载器连接
XDS110下载器 | 开发板 |
---|---|
SWD | SWD/TMS |
CLK | CLK/TCK |
GND | GND |
5V | 5V |
代码烧录
GIF 动图
案例现象
板载的三色LED灯,从红色逐渐变成紫色,再从紫色变成红色,如此反复。
同时通过逻辑分析仪,采集GPIO20引脚的信号情况,其输出为10KHz的波形,占空比在不断变化。