DSP28335基础教程——EPWM实验(呼吸灯控制)

Posted Sk Electronics

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DSP28335基础教程——EPWM实验(呼吸灯控制)相关的知识,希望对你有一定的参考价值。

0 前言

EPWM的实验教程来了,大家久等了。这一节的学习是非常重要且常用的,比如说SPWM,SVPWM调制算法都要用到这个功能。但由于这些调制算法都是比较高阶的,目前不适合作为基础教程,我们在做完基础教程之后会写个关于“算法实现的高阶教程系列”

因此,在这节我们以呼吸灯控制作为实验目的,进行详细介绍EPWM的配置过程(代码注释)。以下将分为硬件部分、软件部分和实验展示三个方面进行介绍,不清楚的欢迎留言。

1 硬件部分

在硬件部分,可以采用核心板上自带的5个LED来测试。其中EPWM1模块的PWM1A和PWM1B端口分别控制LED0和LED1;EPWM2模块的PWM2A和PWM2B端口分别控制LED2和LED3;EPWM3模块的PWM1A端口则控制LED4。硬件连接如下图所示。
在这里插入图片描述
通过调整PWM端口的占空比,就可以实现LED灯呼吸效果。

2 软件部分

软件部分,ePWM频率都配置为1500Hz,通过在每次EPWM1中断内,修改CMPA比较值,从而可以调整PWM占空比。具体代码如下所示。(注意:查看代码时双击点进去看,否则会内容不全)。
bsp_pwm.c

/**
 *  ********************************************************************************************
 *  @file                 bsp_pwm.c
 *  @file                 SK Electronics
 *  @version           V1.0
 *  @date               2020-xx-xx
 *  @brief               PWM应用函数接口
 *  *******************************************************************************************
 *  @attention
 *  实验平台:SK-F28335Mini   核心板
 *  CSDN博客:https://blog.csdn.net/weixin_46556696
 *  淘宝:https://shop409670932.taobao.com
 */
//! \\b External \\b Connections \\n
//!  - EPWM1A is on GPIO0
//!  - EPWM1B is on GPIO1
//!  - EPWM2A is on GPIO2
//!  - EPWM2B is on GPIO3
//!  - EPWM3A is on GPIO4
//!  - EPWM3B is on GPIO5


#include "DSP28x_Project.h"
#include "bsp_pwm.h"


void EPWMIO_GPIO0(void)
{
    EALLOW;
    GpioCtrlRegs.GPAMUX1.bit.GPIO0=1;//复用模式
    GpioCtrlRegs.GPAPUD.bit.GPIO0=0;//使能内部上拉
    GpioCtrlRegs.GPADIR.bit.GPIO0=1;//配置成输出
    EDIS;
}
void EPWMIO_GPIO1(void)
{
    EALLOW;
    GpioCtrlRegs.GPAMUX1.bit.GPIO1=1;//复用模式
    GpioCtrlRegs.GPAPUD.bit.GPIO1=0;//使能内部上拉
    GpioCtrlRegs.GPADIR.bit.GPIO1=1;//配置成输出
    EDIS;
}
void EPWMIO_GPIO2(void)
{
    EALLOW;
    GpioCtrlRegs.GPAMUX1.bit.GPIO2=1;//复用模式
    GpioCtrlRegs.GPAPUD.bit.GPIO2=0;//使能内部上拉
    GpioCtrlRegs.GPADIR.bit.GPIO2=1;//配置成输出
    EDIS;
}
void EPWMIO_GPIO3(void)
{
    EALLOW;
    GpioCtrlRegs.GPAMUX1.bit.GPIO3=1;//复用模式
    GpioCtrlRegs.GPAPUD.bit.GPIO3=0;//使能内部上拉
    GpioCtrlRegs.GPADIR.bit.GPIO3=1;//配置成输出
    EDIS;
}
void EPWMIO_GPIO4(void)
{
    EALLOW;
    GpioCtrlRegs.GPAMUX1.bit.GPIO4=1;//复用模式
    GpioCtrlRegs.GPAPUD.bit.GPIO4=0;//使能内部上拉
    GpioCtrlRegs.GPADIR.bit.GPIO4=1;//配置成输出
    EDIS;
}
void InitEPwm1Example()
{
    // 设置TBCLK寄存器功能
    EPwm1Regs.TBPRD = 50000;           // 设置周期值为50000
    EPwm1Regs.TBPHS.half.TBPHS = 0x0000;           // 设置相移值为0
    EPwm1Regs.TBCTR = 0x0000;                      // 清除计数器的值

    // 设置比较寄存器功能
    EPwm1Regs.CMPA.half.CMPA = 0;     // 设置CMPA比较寄存器A的值为0
    EPwm1Regs.CMPB = 0;               // 设置CMPB比较寄存器B的值为0

    // 设置计数模式功能
    EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // 上下计数模式
    EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE;        // 禁止相移值装载到计数器
    EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_CTR_ZERO;    // 计数器值为0的时候发出同步信号,使得ePWM2/3/4/5/6的计数与1同步,不会产生误差偏移累加
    EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;       // 高速时钟预分频为1    TBCLK=150MHz
    EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1;          // 时钟预分频为1, 最终时钟频率:TBCLK=SYSCKOUT/(HSPCLKDIV*CLKDIV)=150MHz/(1*1)=150MHz
                                                      // ePWM频率=TBCLK/(2*TBPRD)=150000000/(2*50000)=1500Hz
    // 设置装载模式功能
    EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;    // 设定CMPA为映射模式
    EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;    // 设定CMPB为映射模式
    EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;  // 设定在计数值CTR=ZERO时,装载CMPA比较值
    EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;  // 设定在计数值CTR=ZERO时,装载CMPB比较值

    // 设置动作功能
    EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR;           //当计数方向为向上,CTR=CMPA时,PWM1A口输出低电平
    EPwm1Regs.AQCTLA.bit.CAD = AQ_SET;             //当计数方向为向下,CTR=CMPA时,PWM1A口输出高电平

    EPwm1Regs.AQCTLB.bit.CAU = AQ_CLEAR;           //当计数方向为向上,CTR=CMPA时,PWM1B口输出低电平
    EPwm1Regs.AQCTLB.bit.CAD = AQ_SET  ;           //当计数方向为向下,CTR=CMPA时,PWM1B口输出高电平

    // 设置将要更改比较寄存器值的中断功能
    EPwm1Regs.ETSEL.bit.INTSEL = ET_CTR_PRD;       // 在CTR=TBPRD时,产生中断
    EPwm1Regs.ETSEL.bit.INTEN = 1;                 // 使能中断
    EPwm1Regs.ETPS.bit.INTPRD = ET_1ST;            // 每一次满足中断条件就产生一次中断
}


void InitEPwm2Example()
{
    // 设置TBCLK寄存器功能
    EPwm2Regs.TBPRD = 50000;                      // 设置周期值为50000
    EPwm2Regs.TBPHS.half.TBPHS = 50000;           // 设置相移值为0
    EPwm2Regs.TBCTR = 0x0000;                     // 清除计数器的值

    // 设置比较寄存器功能
    EPwm2Regs.CMPA.half.CMPA = 0;     // 设置CMPA比较寄存器A的值为0
    EPwm2Regs.CMPB = 0;               // 设置CMPB比较寄存器B的值为0

    // 设置计数模式功能
    EPwm2Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // 上下计数模式
    EPwm2Regs.TBCTL.bit.PHSEN = TB_ENABLE;         // 使能相移值装载到计数器
    EPwm2Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_IN;     // 接受来自EPWM1的同步信号
    EPwm2Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;
    EPwm2Regs.TBCTL.bit.CLKDIV = TB_DIV1;

    // 设置映射模式功能
    EPwm2Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
    EPwm2Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
    EPwm2Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
    EPwm2Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;


    // 设置动作功能
    EPwm2Regs.AQCTLA.bit.CAU = AQ_CLEAR;
    EPwm2Regs.AQCTLA.bit.CAD = AQ_SET;

    EPwm2Regs.AQCTLB.bit.CAU = AQ_CLEAR;
    EPwm2Regs.AQCTLB.bit.CAD = AQ_SET  ;

    // Interrupt where we will change the Compare Values
    /*    EPwm2Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO;     // Select INT on Zero event
          EPwm2Regs.ETSEL.bit.INTEN = 1;                // Enable INT
          EPwm2Regs.ETPS.bit.INTPRD = ET_3RD;           // Generate INT on 3rd event
   */
}

void InitEPwm3Example(void)
{
    EPwm3Regs.TBPRD = 50000;
    EPwm3Regs.TBPHS.half.TBPHS = 0x0000;
    EPwm3Regs.TBCTR = 0x0000;

    EPwm3Regs.CMPA.half.CMPA = 0;
    EPwm3Regs.CMPB = 0;

    EPwm3Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;
    EPwm3Regs.TBCTL.bit.PHSEN = TB_ENABLE;
    EPwm3Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_IN;
    EPwm3Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;
    EPwm3Regs.TBCTL.bit.CLKDIV = TB_DIV1;

    EPwm3Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
    EPwm3Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
    EPwm3Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
    EPwm3Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;

    EPwm3Regs.AQCTLA.bit.CAD = AQ_SET;
    EPwm3Regs.AQCTLA.bit.CAU = AQ_CLEAR;

    EPwm3Regs.AQCTLB.bit.CAU = AQ_CLEAR;
    EPwm3Regs.AQCTLB.bit.CAD = AQ_SET  ;

    // Interrupt where we will change the Compare Values
    /*      EPwm3Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO;     // Select INT on Zero event
          EPwm3Regs.ETSEL.bit.INTEN = 1;                // Enable INT
          EPwm3Regs.ETPS.bit.INTPRD = ET_3RD;           // Generate INT on 3rd event
   */
}

void InitEPwm4Example()
{
    EPwm4Regs.TBPRD = 50000;
    EPwm4Regs.TBPHS.half.TBPHS = 50000;
    EPwm4Regs.TBCTR = 0x0000;

    EPwm4Regs.CMPA.half.CMPA = 0;
    EPwm4Regs.CMPB = 0;

    EPwm4Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;
    EPwm4Regs.TBCTL.bit.PHSEN = TB_ENABLE;
    EPwm4Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_IN;
    EPwm4Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;
    EPwm4Regs.TBCTL.bit.CLKDIV = TB_DIV1;

    EPwm4Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
    EPwm4Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
    EPwm4Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
    EPwm4Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;

    EPwm4Regs.AQCTLA.bit.CAU = AQ_CLEAR;
    EPwm4Regs.AQCTLA.bit.CAD = AQ_SET;

    EPwm4Regs.AQCTLB.bit.CAU = AQ_SET;
    EPwm4Regs.AQCTLB.bit.CAD = AQ_CLEAR  ;

    // Interrupt where we will change the Compare Values
    /*      EPwm4Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO;     // Select INT on Zero event
          EPwm4Regs.ETSEL.bit.INTEN = 1;                // Enable INT
          EPwm4Regs.ETPS.bit.INTPRD = ET_3RD;           // Generate INT on 3rd event
   */
}

void InitEPwm5Example()
{
    EPwm5Regs.TBPRD = 50000;
    EPwm5Regs.TBPHS.half.TBPHS = 0x0000;
    EPwm5Regs.TBCTR = 0x0000;

    EPwm5Regs.CMPA.half.CMPA = 0;
    EPwm5Regs.CMPB = 0;

    EPwm5Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;
    EPwm5Regs.TBCTL.bit.PHSEN = TB_ENABLE;
    EPwm5Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_IN;
    EPwm5Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;
    EPwm5Regs.TBCTL.bit.CLKDIV = TB_DIV1;

    EPwm5Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
    EPwm5Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
    EPwm5Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
    EPwm5Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;

    EPwm5Regs.AQCTLA.bit.CAU = AQ_SET;
    EPwm5Regs.AQCTLA.bit.CAD = AQ_CLEAR;

    EPwm5Regs.AQCTLB.bit.CAU = AQ_SET;
    EPwm5Regs.AQCTLB.bit.CAD = AQ_CLEAR;

    // Interrupt where we will change the Compare Values
    /*      EPwm5Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO;     // Select INT on Zero event
          EPwm5Regs.ETSEL.bit.INTEN = 1;                // Enable INT
          EPwm5Regs.ETPS.bit.INTPRD = ET_3RD;           // Generate INT on 3rd event
   */
}

void InitEPwm6Example()
{

    EPwm6Regs.TBPRD = 50000;
    EPwm6Regs.TBPHS.half.TBPHS = 50000;
    EPwm6Regs.TBCTR = 0x0000;

    EPwm6Regs.CMPA.half.CMPA = 0;
    EPwm6Regs.CMPB = 0;

    EPwm6Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;
    EPwm6Regs.TBCTL.bit.PHSEN = TB_ENABLE;
    EPwm6Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_IN;
    EPwm6Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;
    EPwm6Regs.TBCTL.bit.CLKDIV = TB_DIV1;

    EPwm6Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
    EPwm6Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
    EPwm6Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
    EPwm6Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;

    EPwm6Regs.AQCTLA.bit.CAU = AQ_SET;
    EPwm6Regs.AQCTLA.bit.CAD = AQ_CLEAR;

    EPwm6Regs.AQCTLB.bit.CAU = AQ_SET;
    EPwm6Regs.AQCTLB.bit.CAD = AQ_CLEAR  ;

    // Interrupt where we will change the Compare Values
    /*      EPwm6Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO;     // Select INT on Zero event
          EPwm6Regs.ETSEL.bit.INTEN = 1;                // Enable INT
          EPwm6Regs.ETPS.bit.INTPRD = ET_3RD;           // Generate INT on 3rd event
   */
}

bsp.pwm.h

/**
 *  ********************************************************************************************
 *  @file                 bsp_pwm.h
 *  @file                 SK Electronics
 *  @version           V1.0
 *  @date               2020-xx-xx
 *  @brief               PWM应用函数接口头文件
 *  *******************************************************************************************
 *  @attention
 *  实验平台:SK-F28335Mini   核心板
 *  CSDN博客:https://blog.csdn.net/weixin_46556696
 *  淘宝:https://shop409670932.taobao.com
 */

#include "DSP28x_Project.h"

void InitEPwm1Example(void);
void InitEPwm2Example(void);
void InitEPwm3Example(void);
void InitEPwm4Example(void);
void InitEPwm5Example(void);
void InitEPwm6Example(void);

void EPWMIO_GPIO0(void);
void EPWMIO_GPIO1(void);
void EPWMIO_GPIO2(void);
void EPWMIO_GPIO3(void);
void EPWMIO_GPIO4(void);

main.c

/**
 *  ********************************************************************************************
 *  @file                 main.c
 *  @file                 SK Electronics
 *  @version           V1.0
 *  @date               2021-xx-xx
 *  @brief               EPWM测试
 *  *******************************************************************************************
 *  @attention
 *  实验平台:SK-F28335Mini   核心板
 *  CSDN博客:https://blog.csdn.net/weixin_46556696
 *  淘宝:https://shop409670932.taobao.com
 */
#include "DSP28x_Project.h"
#include "bsp_pwm.h"
#define FLASH_RUN 1
#define SRAM_RUN 2
#define RUN_TYPE FLASH_RUN
#if RUN_TYPE==FLASH_RUN
extern Uint16 RamfuncsLoadStart;
extern Uint16 RamfuncsLoadEnd;
extern Uint16 RamfuncsRunStart;
#endif
interrupt void epwm1_isr(void);
Uint16 PWM_count=0;
Uint16 PWM_direction=0;
void delay_1ms(Uint16 t);
/**
 *  @brief                           主函数
 *  @parameter                  无
 *  @return_value               无
 */
void main(void)
{
/*第一步:初始化系统控制:*/
    InitSysCtrl();

/*第二步:初始化GPIO口*/
    InitGpio();
    EPWMIO_GPIO0();
    EPWMIO_GPIO1();
    EPWMIO_GPIO2();
    EPWMIO_GPIO3();
    EPWMIO_GPIO4();
/* 第三步:清除所有中断 和初始化 PIE 向量表:*/
    DINT;// 关闭全局中断
    InitPieCtrl();// 初始化 PIE 控制寄存器到默认状态,默认状态是全部 PIE 中断被禁用和标志位被清除
    IER = 0x0000;// 禁用 CPU 中断和清除所有 CPU 中断标志位:
    IFR = 0x0000;
    InitPieVectTable();// 初始化 PIE 中断向量表

    // 中断重映射,注册中断程序入口(用户按需求添加)
    EALLOW;
    PieVectTable.EPWM1_INT = &epwm1_isr;
    EDIS;
    
    /*程序烧录入28335(可选的)*/
#if RUN_TYPE==FLASH_RUN
    MemCopy(&RamfuncsLoadStart,&RamfuncsLoadEnd,&RamfuncsRunStart);
    InitFlash();
#endif
/* 第四步: 初始化片上外设*/
    // InitPeripherals();  //初始化所有外设(本例程不需要)
    EALLOW;
    SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0;//停止时基计时器
    EDIS;
    InitEPwm1Example();//配置EPWM1
    InitEPwm2Example();//配置EPWM2
    InitEPwm3Example();//配置EPWM3
   // InitEPwm4Example();
   // InitEPwm5Example();
   // InitEPwm6Example();
    EALLOW;
    SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1;//使能时基计时器
    EDIS;
    IER |= M_INT3;//使能INT3中断,(关于中断第几组,具体查看中断向量表)
    PieCtrlRegs.PIEIER3.bit.INTx1 = 1;//使能ePWM1中断
    //PieCtrlRegs.PIEIER3.bit.INTx2 = 1;
    //PieCtrlRegs.PIEIER3.bit.INTx3 = 1;
    //PieCtrlRegs.PIEIER3.bit.INTx4 = 1;
    //PieCtrlRegs.PIEIER3.bit.INTx5 = 1;
    //PieCtrlRegs.PIEIER3.bit.INTx6 = 1;
/* 第五步:添加用户功能具体代码*/
    EINT;
    ERTM;
    for(;;)
    {

    }
}


void delay_1ms(Uint16 t)
{
    while(t--)
    {
        DELAY_US(1000);
    }
}

/*epwm1中断函数*/
interrupt void epwm1_isr(void)
{
    if(PWM_direction==0)//当前PWM_count方向是否=0 (=0表示向上,=1表示向下)
    {
        PWM_count=PWM_count+50;//PWM_count是用于下面更新CMPA比较值。 增加PWM_count
    }
    else
    {
        PWM_count=PWM_count-50;//减少PWM_count
    }
    if(PWM_count==50000)//当前PWM_count是否=TBPRD值
    {
        PWM_direction=1;//PWM_count方向变为向下
    }
    if(PWM_count==0)//当前PWM_count是否=0
    {
        PWM_direction=0;//PWM_count方向变为向上
    }
    EPwm1Regs.CMPA.half.CMPA = PWM_count;//更新EPWM1的CMPA比较值
    EPwm2Regs.CMPA.half.CMPA = PWM_count;//更新EPWM2的CMPA比较值
    EPwm3Regs.CMPA.half.CMPA = PWM_count;//更新EPWM3的CMPA比较值
    EPwm4Regs.CMPA.half.CMPA = PWM_count;//更新EPWM4的CMPA比较值
    EPwm5Regs.CMPA.half.CMPA = PWM_count;//更新EPWM5的CMPA比较值
    EPwm6Regs.CMPA.half.CMPA = PWM_count;//更新EPWM6的CMPA比较值

   // 清除中断标志位,防止重复进入中断
   EPwm1Regs.ETCLR.bit.INT = 1;

   // 应答此中断,使得从第3组接收更多其他中断(关于中断第几组,具体查看中断向量表)
   PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;
}

3 实验展示

程序烧录进去后,大家可以看到这个呼吸灯动图效果。
在这里插入图片描述
大家可以参考代码尝试一下, 有疑问的欢迎留言!!

以上是关于DSP28335基础教程——EPWM实验(呼吸灯控制)的主要内容,如果未能解决你的问题,请参考以下文章

DSP28335基础教程——EPWM实验(呼吸灯控制)

dsp28335的epwm如何输出互补的脉冲

DSP28335基础教程——GPIO输出(流水灯实验)

DSP28335基础教程——ECAP实验(超声波测距)

DSP28335基础教程——ECAP实验(超声波测距)

DSP28335基础教程——ECAP实验(超声波测距)