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实验(呼吸灯控制)的主要内容,如果未能解决你的问题,请参考以下文章