16.【NXP 号令者RT1052】开发——实战-FlexPWM 输出

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 脉宽调制器的主要特点如下:

  1. 每个脉宽调制器(FlexPWM)有 4 个子模块;
  2. 16 位精度,支持中央对齐、边沿对齐和非对称 PWM 输出;
  3. 分数 PWM 时钟生成器可生成高精度 PWM 周期和占空比;
  4. 可工作在互补输出模式或独立工作模式;
  5. 每个 PWM 输出双沿(上升沿/下降沿)可独立控制;
  6. 可与外部硬件或其他 PWM 子模块同步;
  7. 双缓冲 PWM 寄存器,可设置 1~16 的整数重载率或半周期重载;
  8. 支持 PWM 输出的双切换(周期和占空比);
  9. 故障输入可以指定连接控制多个 PWM 输出
  10. 独立的可编程 PWM 输出极性设置;
  11. 独立的死区时间设置;
  12. 增强 型双沿(上升沿/下降沿)捕获功能;

由图可知,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 硬件设计

本实验用到的硬件资源有:

  1. 指示灯 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!谢谢大家!

相关推荐
墨辰JC2 小时前
基于STM32标准库的FreeRTOS移植与任务创建
数据库·stm32·嵌入式硬件·freertos
时光の尘2 小时前
【STM32】DMA超详细解析·入门级教程
stm32·单片机·嵌入式硬件·mcu·串口·dma·usart
chao1898442 小时前
基于TMS320F28069 DSP开发板实现RS485通信
单片机·嵌入式硬件
朱嘉鼎3 小时前
消费级MCU如何管理内存
单片机·嵌入式硬件
R6bandito_4 小时前
STM32 HAL库原子操作编译问题解决指南
c语言·ide·经验分享·stm32·单片机·嵌入式硬件·mcu
Jerry丶Li4 小时前
三十、STM32的USART (串口发送+接收)
stm32·单片机·嵌入式硬件
从零点4 小时前
STM32连接以太网失败自动重新连接
stm32·单片机·嵌入式硬件
python百炼成钢5 小时前
13.RTC实时时钟
linux·stm32·单片机·嵌入式硬件·实时音视频
国科安芯5 小时前
FreeRTOS 在 AS32系列RISC-V 架构MCU电机驱动中的应用实践与优化
单片机·嵌入式硬件·安全·架构·压力测试·risc-v·安全性测试