16.【NXP 号令者RT1052】开发------实战-FlexPWM 输出
我们之前介绍了如何使用 RT1052 的四定时器 QTMR4 的通道 3 来产生 PWM 输出。RT1052 内部有一个非常牛逼的 PWM 模块:eFlexPWM(也叫 FlexPWM),其功能非常多,本章我们将向大家介绍如何使用 FlexPWM2 的模块 3 来产生 PWM 输出。在本章中,我们将使用 FlexPWM2 的模块 3 产生 PWM 来控制 DS1 的亮度。
16.1 FlexPWM 简介
FlexPWM 全称是:Enhanced Flex Pulse Width Modulator,也叫 eFlexPWM,即增强型灵活的脉宽调制器。RT1052 内部有 4 个这种脉宽调制器(FlexPWM)模块,每个脉宽调制器模块有有 4 个子模块,每个子模块可以用于控制单个半桥功率计,且提供故障保护通道。脉宽调制器(FlexPWM)模块可以组成多种开关组合方式,可生成高度复杂的波形,它可以用于控制各种类型的电机,也是各种开关电源(SMPS)拓扑模型的理想控制器。
FlexPWM 脉宽调制器的主要特点如下:
- 每个脉宽调制器(FlexPWM)有 4 个子模块;
- 16 位精度,支持中央对齐、边沿对齐和非对称 PWM 输出;
- 分数 PWM 时钟生成器可生成高精度 PWM 周期和占空比;
- 可工作在互补输出模式或独立工作模式;
- 每个 PWM 输出双沿(上升沿/下降沿)可独立控制;
- 可与外部硬件或其他 PWM 子模块同步;
- 双缓冲 PWM 寄存器,可设置 1~16 的整数重载率或半周期重载;
- 支持 PWM 输出的双切换(周期和占空比);
- 故障输入可以指定连接控制多个 PWM 输出
- 独立的可编程 PWM 输出极性设置;
- 独立的死区时间设置;
- 增强 型双沿(上升沿/下降沿)捕获功能;

由图可知,FlexPWM 的每个子模块由 1 个预分频器、1 个 16 位计数器和 6 个 16 位比较器等部分组成,主要有 3 个输出信号:PWM_X、PWM_A 和 PWM_B,其中 PWM_A 和 PWM_B可以用来输出 PWM/做输入捕获,而 PWM_X 是一个辅助输出,可以独立的用作 PWM 信号,也可以用作输入捕获,我们一般使用 PWM_A 或 PWM_B 来输出 PWM 波形。
图中①处,是故障信号输入,来自模块总线,由 XBAR1 的输出通道来控制,要想正常输出 PWM,必须设置合适的故障状态,或者禁止故障检测功能,否则将无法正常输出 PWM!下图是 FlexPWM 子模块的输出逻辑:

图中 PWM23 和 PWM45 分别由 VAL2/VAL3 和 VAL4/VAL5 控制占空比,来自经过死区处理后的信号,本例程没用到死区控制,所以在这里对死区不做介绍。由图可知,PWM23和PWM45的输出处理路径是一样的,只是控制信号不同而已,我们以 PWM23 为例,介绍其具体的输出过程:
① ,用于选择输出到下一级的是 PWM23 还是 PWMAFS[0]的值,由 Disable PWM_A 信号控制,当该信号为 0 的时候,PWM23 输出到下一级,否则 PWMAFS[0]的值输出到下一级。很明显,要正常输出 PWM,必须 Disable PWM_A 信号必须为 0。PWMAFS[0]来自 SMx_OCTRL(x=0~3)寄存器。
② ,用于设置是否屏蔽 PWM 输出,当 MASKA=0 时,可以正常输出;当 MASKA=1 时,屏蔽 PWM 输出。MASKA 来自 PWMx_MASK(x=0~3)寄存器。
③ ,用于设置输出有效信号极性。当 POLA=0 时,输出信号不反相;当 POLA=1 时,输出信号反相;POLA 来自 SMx_OCTRL(x=0~3)寄存器。
④ ,用于控制 PWM 最终是否输出到 PWM_A,由 PWM_A_EN、PWMAFS[1]和 Disable PWM_A 三个信号共同控制。PWM_A_EN 由 PWMx_OUTEN(x=0~3)寄存器设置,PWMAFS[1]来自 SMx_OCTRL(x=0~3)寄存器。
⑤ ,Disable PWM_A 来自故障保护单元,它由 FAULT0~3 和 Wait Mode、Debug Mode 和Stop Mode 等信号控制。我们待会重点介绍。
因此可知,PWM_A 要像正常输出来自 PWM23 的 PWM 信号,就必须设置好相应的控制位/信号:Disable PWM_A 必须为 0,MASKA 必须为 1,PWM_A_EN 必须为 1。对于 PWM_B的输出,同样也要设置类似的位/信号。
Disable PWM_A 信号来源如图:

由图可知 Disable PWM_A 主要来自两个方向:
1,故障输出(FAULT0~3);
2,MCU 工作模式(Wait/Debug/Stop)。正常工作时,我们只需要考虑故障输出,因此我们重点介绍下图中标注的①~⑥。
①,二或门,只要故障输出或 MCU 工作模式输出有效,则 Disable PWM_A 有效(=1)。
②,四或门,来自四个故障信号:FAULT0~FAULT3,只要任意一个故障信号有效(=1),则输出有效。
③,故障 0(FAULT0)屏蔽位(DISA0),用于设置是否屏蔽来自故障 0(FAULT0)的信号,如果我们不想让故障 0 控制我们的 PWM 输出,则可以设置该位为 0。DISA0 来自 SMx_DISMAP0(x=0~3),同样的 DISA1~DISA3 也是由该寄存器控制,分别控制 FAULT1~FAULT3 的屏蔽。注意:这些位默认都是 1 的!
④,故障输入 0 到 Disable PWM_A 输出组合路径屏蔽位,当 NOCOMB0 为 0 时,FAULT0 有两条路径可以输出到 Disable PMW_A:1,通过 NOCOMB0 与门;2,通过 FILT 过滤器;当 NOCOMB0 为1 时,则只能通过 FLIT 这条路径输出到 Disable PWM_A。NOCOMB0 来自 PWMx_FCTRL2(x=03)寄存器。同样的,NOCOMB13 也是来自该寄存器。
⑤,故障信号 0(FAULT0),来自 XBAR1 的输出。这些故障信号可以通过 XBAR1 映射到相关外部 IO 口,从而实现故障检测。具体的映射关系,详见《RT1050 参考手册》第 246 页,Table 3-6。
本章,我们通过 PWM2 的子模块 3 来产生 PWM 控制 DS1 的亮度,并不需要用到故障检测功能,所以,我们需要屏蔽故障(通过 SMx_DISMAP0 或 PWMx_FCTRL20 寄存器设置),或者设置故障值为正常(通过 XBAR1 设置)。一般我们通过设置 SMx_DISMAP0 寄存器(全 0)来屏蔽故障检测功能。
接下来,我们介绍一下 FlexPWM 子模块的时钟部分

此图比较简单,我们重点介绍图中标注的①~③,这三个部分。
①,时钟源选择器,由 CLK_SEL[1:0]位设置,我们一般选择 IPBus 时钟作为时钟源,IPBus时钟来自 IPG_CLK_ROOT(150Mhz)。CLK_SEL[1:0]来自 SMx_CTRL2(x=0~3)寄存器。
②,时钟预分频器,这是 8 位预分频器,但是只能设置固定的几个分频值,不能随意设置!其分频值可以是:1/2/4/8/16/32/64/128 等 7 个值,通过 PSRC[2:0]设置。PSRC[2:0]来自SMx_CTRL(x=0~3)寄存器。
③,时钟使能开关,由 RUN 位控制,如果 RUN 位为 1,则可以正常输出时钟;如果 RUN 位
为 0,则禁止输出时钟;RUN 位来自 PWMx_MCTRL(x=0~3)寄存器。
通过图中的①~③,我们就可以自由设置和选择子模块时钟,具体的设置,需要根据实际使用需求来确定。
经过以上学习,我们了解了 FlexPWM 的时钟设置、输出逻辑、故障管理和整体组成等,接下来,我们看看 FlexPWM 子模块产生 PWM 的具体过程,如图所示:

FlexPWM 子模块的计数器(CNT),只能工作在向上计数模式(图中类似三角波的波形),上图是 FlexPWM 子模块生成中央对齐 PWM 的时序图,因为计数方向是不可改变的,只能修改图中的③~⑨来实现中央对齐 PWM 的输出。事实上中央对齐、边沿对齐和非对称 PWM 的输出,都是通过修改这几个寄存器来实现的。注意:FlexPWM 是支持有符号操作的,如果 INIT 的值刚好和 VAL1 的值相反(值相同,符号相反),则表示是有符号模式,否则表示是无符号模式。
我们重点分析下图 17.1.5 的实现原理,为了方便说明,我们在图中标注了①~⑨。
①,PWM_A 波形,其波形是以 VAL0 的值中心对称的。PWM_A 波形由 VAL2 控制上升沿,由VAL3 控制下降沿,只要 VAL0-VAL2=VAL3-VAL0,则是中心对称模式。
②,PWM_B 波形,其波形也是以 VAL0 的值中心对称的。PWM_B 波形由 VAL4 控制上升沿,由VAL5 控制下降沿,只要 VAL0-VAL4=VAL5-VAL0,则是中心对称模式。
③,INIT 寄存器,用于设置 CNT 的初始值。这是一个有符号 16 位寄存器,它可以设置成负数或者正数,图 17.1.5 种设置的 INIT 值为 0XFF00,即-256,是负数。该寄存器用于在每个PWM 周期的启动时初始化 CNT 值(也就是 CNT 达到 VAL1 溢出后,都会将 INIT 的值重新赋值到CNT)。该寄存器和 VAL1 共同决定是否工作在有符号模式,只要这两个寄存器的值不刚好相反,则是工作在无符号模式,一般建议用无符号模式。
④,VAL0 寄存器,用于设置 CNT 的中间值。这是一个有符号 16 位寄存器,该寄存器的值介于 INIT 和 VAL1 之间,一般等于(VAL1-INIT)/2。
⑤,VAL1 寄存器,用于设置 CNT 计数器的最大值。这是一个有符号 16 位寄存器,该寄存器和 INIT 寄存器共同决定是否工作在有符号模式。
⑥,VAL2 寄存器,用于控制 PWM_A 的上升沿。这是一个有符号 16 位寄存器,通过它可以决定 PWM_A 波形高电平的起始时间。
⑦,VAL3 寄存器,用于控制 PWM_A 的下降沿。这是一个有符号 16 位寄存器,通过它可以决定PWM_A 波形高电平的结束时间。INIT、VAL1、VAL2 和 VAL3 共同决定了 PWM_A 的波形。
⑧,VAL4 寄存器,用于控制 PWM_B 的上升沿。这是一个有符号 16 位寄存器,通过它可以决定 PWM_B 波形高电平的起始时间。
⑨,VAL5 寄存器,用于控制 PWM_B 的下降沿。这是一个有符号 16 位寄存器,通过它可以决定 PWM_B 波形高电平的结束时间。INIT、VAL1、VAL4 和 VAL5 共同决定了 PWM_B 的波形。注意:INIT、VAL0~VAL5 等七个寄存器都是有缓冲的,我们写入这些寄存器的值并不会立即生效,必须设置 PWMx_MCTRL(x=0~3)寄存器的 LDOK 位,然后在下一个 PWM 周期开始的时候,会将写入这些寄存器的值加载到缓冲寄存器里面,然后设置的值才会生效。
上图 中是中央对齐模式的设置,如果我们调整 INIT 和 VAL0~VAL5 的值,则可以实现很多种不同模式的 PMW 波形输出。详见《RT1050 参考手册》第 1425 页 28.5.1 节。
本章,我们将使用 PWM2 子模块 3 的 PWM_B 输出来控制 DS1 的亮度,实现类似第 15 章的控制效果,即:DS1 不停的由暗变到亮,然后又从亮变到暗。
好的,我来帮你把这部分内容整理成 Markdown 格式,保持代码原样不动,仅仅排版清晰:
RT1052 FlexPWM2 配置步骤
1. 设置 GPIO3_IO03 复用功能
c
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_03_FLEXPWM2_PWMB03,0);
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_03_FLEXPWM2_PWMB03,0x10B0);
2. 使能 FlexPWM2 时钟
c
CLOCK_EnableClock(kCLOCK_Pwm2)
此函数会被
PWM_Init调用,无需显式调用。
3. 初始化 FlexPWM2
c
status_t PWM_Init(PWM_Type *base,
pwm_submodule_t subModule,
const pwm_config_t *config)
- base :指定 PWM,本例为
PWM2 - subModule :子模块选择,本例为
kPWM_Module_3 - config :配置结构体
pwm_config_t
示例配置
c
pwm_config_t pwm2sm3_config; //PWM2 模块 3 配置结构体
//初始化 PWM2 模块 3 的通道 B
PWM_GetDefaultConfig(&pwm2sm3_config); //先初始化为默认配置
pwm2sm3_config.clockSource = kPWM_BusClock; //时钟源为 IP BUS=150MHz
pwm2sm3_config.prescale = kPWM_Prescale_Divide_128; //设置 128 分频
pwm2sm3_config.reloadLogic = kPWM_ReloadPwmFullCycle; //全周期更新
pwm2sm3_config.pairOperation = kPWM_Independent; //PMWA PWMB 独立模式
PWM_Init(PWM2, kPWM_Module_3, &pwm2sm3_config); //初始化 PWM2 模块 3
4. 关闭故障检测功能
c
PWM2->SM[3].DISMAP[0] = 0;
5. 配置 PWM2 的 PWMB 通道
c
status_t PWM_SetupPwm(PWM_Type * base,
pwm_submodule_t subModule,
const pwm_signal_param_t * chnlParams,
uint8_t numOfChnls,
pwm_mode_t mode,
uint32_t pwmFreq_Hz,
uint32_t srcClock_Hz)
示例配置:10KHz,50% 占空比
c
u32 sourceclock;
//设置 PWM2_PWMB 通道
sourceclock = CLOCK_GetFreq(kCLOCK_IpgClk);
//PWMB
pwm_ignal.pwmChannel = kPWM_PwmB; //PWM 通道 B
pwm_ignal.level = kPWM_HighTrue; //高电平有效
pwm_ignal.dutyCyclePercent = 50; //50%占空比
//设置 PWM2,中央对齐模式
PWM_SetupPwm(PWM2, //PWM2
kPWM_Module_3, //PWM2 的子模块 3
&pwm_ignal, //PWM 通道配置参数结构体
1, //配置一个 PWM 通道
kPWM_CenterAligned, //无符号中央对齐模式
10000, //PWM 频率为 10KHz
sourceclock); //PWM 时钟源为 150MHz
PWM_SetPwmLdok(PWM2, kPWM_Control_Module_3, true); //设置 PWM 的 load ok 位
6. 开启 PWM2
c
PWM_StartTimer(PWM2, kPWM_Control_Module_3); //开启 PWM
7. 动态更新占空比
c
void PWM_UpdatePwmDutycycle(PWM_Type * base,
pwm_submodule_t subModule,
pwm_channels_t pwmSignal,
pwm_mode_t currPwmMode,
uint8_t dutyCyclePercent)
- pwmSignal:选择通道 (kPWM_PwmB / kPWM_PwmA / kPWM_PwmX)
- currPwmMode:当前 PWM 对齐模式
- dutyCyclePercent:占空比百分比 (0~100)
16.2 硬件设计
本实验用到的硬件资源有:
- 指示灯 DS1
本章将通过 PWM2 子模块 3 的 PWM_B 来控制 DS1 的亮度,DS1 是连接到 GPIO3_IO03(P303)上的,这个前面已经有介绍了。而 PWM2 子模块 3 的 PWM_B 的输出是可以连接在GPIO3_IO03(P303)上的,刚好和 DS1 是同一个脚,所以硬件不需要做任何变化,直接写代码即可。
16.3 软件设计
本章,我们依旧是在前一章的基础上修改代码,先打开之前的工程,在 HARDWARE 文件夹下新建 FLEXPWM 文件夹。然后打开 USER 文件夹下的工程,新建一个 flexpwm.c 的文件和flexpwm.h 的头文件,保存在 FLEXPWM 文件夹下,并将 FLEXPWM 文件夹加入头文件包含路径。
flexpwm.c
c
#include "flexpwm.h"
#include "lpuart.h"
pwm_config_t pwm2sm3_config; //PWM2模块3配置结构体
//初始化FLEXPWM,PWM2的模块3的通道A和B
//通过PWM2的模块3在通道A和B上面产生2路PWM输出.
//即在GPIO3_IO02和GPIO3_IO03上面输出PWM.
//psc : 预分频器,0~7,表示2^psc分频.
//fre : 频率
//duty:占空比
void PWM2_SM3_PWMAB_Init(u16 psc,u32 fre,u8 duty)
{
u32 sourceclock;
pwm_signal_param_t pwm_ignal;
pwm_clock_prescale_t pwm_prescale=(pwm_clock_prescale_t)psc; //分频
//IO功能设置
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_03_FLEXPWM2_PWMB03,0);
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_02_FLEXPWM2_PWMA03,1);
//配置IO引脚GPIO_SD_B1_02和GPIO_SD_B1_03的功能
//低转换速度,驱动能力为R0/6,速度为100Mhz,关闭开路功能,使能pull/keepr
//选择keeper功能,下拉100K Ohm,关闭Hyst
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_03_FLEXPWM2_PWMB03,0x10B0);
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_02_FLEXPWM2_PWMA03,0x10B0);
//初始化PWM2 模块3的通道B
PWM_GetDefaultConfig(&pwm2sm3_config); //先初始化为默认配置
pwm2sm3_config.clockSource=kPWM_BusClock; //时钟源为IP BUS=IPG_CLK_ROOT=150MHz
pwm2sm3_config.prescale=pwm_prescale; //设置分频
pwm2sm3_config.reloadLogic=kPWM_ReloadPwmFullCycle; //全周期更新
pwm2sm3_config.pairOperation=kPWM_Independent; //PMWA PWMB独立模式
PWM_Init(PWM2,kPWM_Module_3,&pwm2sm3_config); //初始化PWM2模块3
//屏蔽故障检测功能
PWM2->SM[3].DISMAP[0]=0;
//设置PWM2B通道
sourceclock=CLOCK_GetFreq(kCLOCK_IpgClk);
//PWMB
pwm_ignal.pwmChannel=kPWM_PwmB; //PWM通道B
pwm_ignal.pwmChannel=kPWM_PwmA; //PWM通道A
pwm_ignal.level=kPWM_HighTrue; //高电平有效
pwm_ignal.dutyCyclePercent=duty; //占空比
//设置PWM2,中央对齐模式
PWM_SetupPwm(PWM2,kPWM_Module_3,&pwm_ignal,2,kPWM_CenterAligned,fre,sourceclock);//使用了两个通道
PWM_SetPwmLdok(PWM2,kPWM_Control_Module_3,true); //设置PWM的load ok位
PWM_StartTimer(PWM2,kPWM_Control_Module_3); //开启定时器
}
//更新PWM2占空比
//duty:占空比
void PWM2_SM3_DutySet(u8 duty)
{
PWM_UpdatePwmDutycycle(PWM2,kPWM_Module_3,kPWM_PwmA,kPWM_CenterAligned,duty); //更新PWMB占空比
PWM_UpdatePwmDutycycle(PWM2,kPWM_Module_3,kPWM_PwmB,kPWM_CenterAligned,duty); //更新PWMB占空比
PWM_SetPwmLdok(PWM2,kPWM_Control_Module_3,true); //设置PWM的load ok位
}
此部分代码就二个函数:PWM2_SM3_PWMAB_Init 和 PWM2_SM3_DutySet,先来看一下函数 PWM2_SM3_PWMAB_Init,此函数有 3 个参数:
psc :用于设置预分频系数,取值范围:0~7,代表 1~128 分频。
fre :PWM 的频率,单位为 Hz,如要设置频率为 10KHz 的 PWM,此参数就设置为 10000。
duty:要设置的占空比(百分比),0~100 表示 0%~100%。函数 PWM2_SM3_DutySet 用来修改 PWM2 子模块 3 的 PWMB 通道的占空比,所以此函数只有一个参数:duty,此参数就是要设置的占空比(百分比),0~100 表示占空比 0%~100%。
flexpwm.h
c
#ifndef _FLEXPWM_H
#define _FLEXPWM_H
#include "sys.h"
void PWM2_SM3_PWMAB_Init(u16 psc,u32 fre,u8 duty); //PWM2 SM3 PWM输出初始化函数
void PWM2_SM3_DutySet(u8 duty); //设置PWM2_SM3两个通道的占空比
#endif
main.c
c
#include "sys.h"
#include "lpuart.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "exti.h"
#include "wdog.h"
#include "rtwdog.h"
#include "gptimer.h"
#include "pitimer.h"
#include "qtimer.h"
#include "pwm.h"
#include "xbar.h"
#include "flexpwm.h"
int main(void)
{
u8 key=0;
MPU_Memory_Protection(); //初始化MPU
RT1052_Clock_Init(); //配置系统时钟
DELAY_Init(600); //延时函数初始化
LPUART1_Init(115200); //初始化串口1
RT1052_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);//优先级分组4
#ifdef LED_DEBUG
u8 led0sta=1,led1sta=1; //LED0,LED1的当前状态
LED_Init(); //初始化LED
#endif
#ifdef KEY_DEBUG
KEY_Init(); //初始化KEY
#endif
#ifdef LPUART_DEBUG
u8 len; //接收数据长度
u16 times=0; //延时计数器
LED0(0); //先点亮红灯
#endif
#ifdef EXTIX_DEBUG
EXTIX_Init(); //初始化外部中断
#endif
#ifdef WDOG_DEBUG
WDOG1_Init(3,2); //初始化看门狗1,2秒溢出,提前1秒进入中断,方便喂狗
LED0(0); //先点亮LED灯
delay_ms(300); //延时300ms再初始化看门狗,LED0的变化"可见"
#endif
#ifdef RTWDOG_DEBUG
LED_Init(); //初始化LED
KEY_Init(); //初始化KEY
delay_ms(100); //延时100ms再初始化看门狗,LED0的变化"可见"
MYRTWDOG_Init(1,0,32768,0); //初始化RT看门狗,1秒溢出,非窗口模式
LED0(0); //先点亮LED灯
#endif
#ifdef GPT1_DEBUG
LED_Init(); //初始化LED
KEY_Init(); //初始化按键
GPT1_Int_Init(3750-1,10000); //设置GPT1 0.5秒钟产生一次中断
#endif
#ifdef PIT_DEBUG
LED_Init(); //初始化LED
PIT_CH0_Int_Init(75000000/2); //设置PIT 0.5秒钟产生一次中断
#endif
#ifdef QTMR_DEBUG
KEY_Init(); //初始化按键
LED_Init(); //初始化LED
QTMR1_CH0_Int_Init(15,46875); //设置QTMR1 0.04秒钟产生一次中断
#endif
#ifdef QTMR_PWM_DEBUG
u8 dir=1;
u16 led1pwmval=0;
gpio_pin_config_t led_config;
LED_Init(); //初始化LED
KEY_Init(); //初始化按键
//初始化PWM,定时器时钟为:150/64=2.34375Mhz,设置频率为5Khz,50%占空比
QTMR4_CH3_PWM_Init(14,5000,0);
//设置P103为输入模式,防止干扰PWM
led_config.direction=kGPIO_DigitalInput; //输出
led_config.interruptMode=kGPIO_NoIntmode; //不使用中断功能
led_config.outputLogic=0; //默认高电平,LED灯关闭
GPIO_PinInit(GPIO1,3,&led_config); //初始化GPIO1_3
#endif
#ifdef XBAR_DEBUG
u8 dir=1;
u16 led1pwmval=0;
//初始化PWM,定时器时钟为:150/64=2.34375Mhz,设置频率为5Khz,50%占空比
QTMR4_CH3_PWM_Init(14,5000,50);
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_03_XBAR1_INOUT17,0); //GPIO_AD_B0_03配置为ALT1,即XBAR1_INOUT17
XBARA1_Signal_Set(kXBARA1_InputQtimer4Tmr3Output,kXBARA1_OutputIomuxXbarInout17); //QTMR4_CH3输出到XBARA1_INOUT17上面.
//即:通过GPIO_AD_B0_03(GPIO1_IO03)输出QMR4_CH3的波形.
#endif
u8 dir=1;
u16 led1pwmval=0;
LED_Init(); //初始化LED
KEY_Init(); //初始化按键
PWM2_SM3_PWMAB_Init(7,1000,50); //初始化PWM2,128分频,1K频率,50%占空比
while(1)
{
delay_ms(10);
if(dir)led1pwmval++;
else led1pwmval--;
if(led1pwmval>=100)dir=0;
if(led1pwmval==0)dir=1;
PWM2_SM3_DutySet(led1pwmval);
#ifdef XBAR_DEBUG
delay_ms(10);
if(dir)led1pwmval++;
else led1pwmval--;
if(led1pwmval>=100)dir=0;
if(led1pwmval==0)dir=1;
QTMER4CH3_PWM_DutySet(14,5000,led1pwmval);
#endif
#ifdef QTMR_PWM_DEBUG
delay_ms(10);
if(dir)led1pwmval++;
else led1pwmval--;
if(led1pwmval>=100)dir=0;
if(led1pwmval==0)dir=1;
QTMER4CH3_PWM_DutySet(14,5000,led1pwmval);
#endif
#ifdef QTMR_DEBUG
LED0_Toggle;
delay_ms(1000);
#endif
#ifdef PIT_DEBUG
LED0_Toggle;
delay_ms(1000);
#endif
#ifdef GPT1_DEBUG
LED0_Toggle;
delay_ms(1000);
#endif
#ifdef RTWDOG_DEBUG
key=KEY_Scan(0);
if(key==WKUP_PRES) //如果按键按下,则喂狗.
{
RTWDOG_Feed();
}
delay_ms(10);
#endif
#ifdef WDOG_DEBUG
LED0(1); //关闭DS0,如不复位,DS0将一直处于关闭状态.
delay_ms(100);
#endif
#ifdef EXTIX_DEBUG
printf("Int example driver!\r\n");
delay_ms(1000);
#endif
#ifdef KEY_DEBUG
key=KEY_Scan(0); //得到键值
if(key)
{
switch(key)
{
case WKUP_PRES: //控制LED0,LED1互斥点亮
led1sta=!led1sta;
led0sta=!led1sta;
break;
case KEY2_PRES: //控制LED0翻转
led0sta=!led0sta;
break;
case KEY1_PRES: //控制LED1翻转
led1sta=!led1sta;
break;
case KEY0_PRES: //同时控制LED0,LED1翻转
led0sta=!led0sta;
led1sta=!led1sta;
break;
}
LED0(led0sta); //控制LED0状态
LED1(led1sta); //控制LED1状态
}else delay_ms(10);
#endif // KEY_DEBUG
#ifdef LPUART_DEBUG
if(LPUART_RX_STA&0x8000)
{
len=LPUART_RX_STA&0x3fff;//得到此次接收到的数据长度
printf("\r\n发送的消息为:\r\n");
LPUART_WriteBlocking(LPUART1,LPUART_RX_BUF,len);//发送接收到的数据
printf("\r\n\r\n");//插入换行
LPUART_RX_STA=0;
}else
{
times++;
if(times%5000==0)
{
printf("\r\nALIENTEK RT1052开发板 串口实验\r\n");
}
if(times%200==0)printf("请输入数据,以回车键结束\r\n");
if(times%30==0)LED0_Toggle;//闪烁LED,提示系统正在运行.
delay_ms(10);
}
#endif // LPUART_DEBUG
}
}
main 函数和之前的代码类似,通过 PWM2_SM3_PWMAB_Init 设置 PWM2 子模块 3 的相关参数,完成初始化设置,这里我们设置 PWM 频率为 1KHz,占空比为 50%。在死循环里面,我们通过 led1pwmval 的值来控制 DS1 的亮度。led1pwmval 的值从 0 变到300,然后又从 300 变到 0,如此循环,因此 DS1 的亮度也会跟着从暗变到亮,然后又从亮变到暗。至此,我们的软件设计就完成了。


总结
FlexPWM(eFlexPWM)是 RT1052 内部增强型的脉宽调制器模块,专门用于产生高精度、灵活的 PWM 波形。它支持中央对齐、边沿对齐和非对称输出,具备故障保护、死区控制、双缓冲寄存器、独立或互补输出等功能,可用于电机控制、开关电源等复杂应用场景。本章通过配置 FlexPWM2 子模块 3 的 PWMB 通道输出 PWM,动态调整占空比来控制 DS1 的亮度,实现 LED 从暗到亮再从亮到暗的循环变化。
OK!谢谢大家!