DSP28335的SPWM波生成方法

时光怂恿深爱的人放手 提交于 2020-07-27 08:58:35

DSP新手,研究了一下午,在这里做个总结,希望对其他刚接触DSP的新手也能有所帮助。

首先要明白SPWM波是什么。

SPWM波实际上就只有2种电平,而且其频率一般是你自己给定的,所以难点在于如何调节每个周期内的占空比,这里采用的是双极性调制法。

先说总体思路:以TBCTR为载波,以CMPA为调制波,并且让CMPA的值不断更新(中断方式),就可以在ePWMxA产生SPWM波。

看了一些资料的你(没看就去看吧),应该能了解到ePWM模块的TB寄存器是设置频率的,CMPA和CMPB是设置占空比的,AQ是设置触发方式的

如果设置好TB,那么就可以使得ePWM模块的计数器TBCTR从0上升到TBPRD然后下降到0,以此得到三角调制波,那就必须有

EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;

此外还要设置AQ,保证是调制波大于载波的时候,输出高电平

EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR; // Clear PWM1A on event A, up count
EPwm1Regs.AQCTLA.bit.CAD = AQ_SET;      // Set PWM1A on event A, down count
EPwm1Regs.AQCTLB.bit.CBU = AQ_CLEAR; // Clear PWM1B on event B, up count
EPwm1Regs.AQCTLB.bit.CBD = AQ_SET;      // Set PWM1B on event B, down count


而载波要怎么获得呢?Easy,写函数表即可。形式就是 sin(2π*i/N),i=0,1,...,N-1

float sina[256];

for(k=0;k<N;k++) {sina[k]= sin(2*3.1416*k/N);}

但是有没有发现,这里的载波并不是那种有正有负的、并且幅值为1的形式呢?我们能用的载波和图中的载波看起来就好像是标准载波加1并且乘以TBPRD/2得到的对吧?既然没法对载波进行变换,那就对调制波进行同样的变换,让调制波为TBPRD*(1+ M*sin(wt))/2,M为调制比,这样得到的调制结果也会是相同的,这里很关键。

当然最关键的地方就是中断了,这一段意思很明白,就是根据正弦表不断更新CMPA和CMPB的值,这就相当于一个阶梯状的调制波TBPRD*(1+ M*sin(wt))/2

interrupt void epwm1_isr(void){

    EPwm1Regs.CMPA.half.CMPA=EPwm1Regs.TBPRD*((1.0+M*sina[i])/2.0);
    EPwm1Regs.CMPB=EPwm1Regs.TBPRD*((1.0+M*sinb[i])/2.0);
    i++;

    if (i>=N){ i=0; }

    EPwm1Regs.ETCLR.bit.INT = 1; //写1对ETFLG[INT]状态标志位清零才能进行下一次中断
    PieCtrlRegs.PIEACK.all=PIEACK_GROUP3;
}

完整代码如下,烧录后,可以在PWM1引脚观察到SPWM波输出,关于频率的设置(TB的设置)这里就不多说了:

#include "DSP2833x_Project.h"
#include "math.h"

void InitEPwm1Example(void);
void Gpio_Setup(void);
interrupt void epwm1_isr(void);

int i,k=0;
float M=0.8;//调制比
int   N=256; //采样点数
float sina[256];
float sinb[256];

void main(void) {
        InitSysCtrl();  //初始化系统控制
        InitEPwm1Gpio();
        Gpio_Setup();   //子函数,Gpio口设置

        for(k=0;k<N;k++) {sina[k]= sin(2*3.1416*k/N); sinb[k]= sin(2*3.1416*k/N);}
        DINT;           //关闭中断
        InitPieCtrl();  //初始化中断控制
        IER = 0x0000;
        IFR = 0x0000;
        InitPieVectTable();//初始化中断矢量表

        EALLOW;  // This is needed to write to EALLOW protected registers
        PieVectTable.EPWM1_INT = &epwm1_isr;
        EDIS;

        EALLOW;
        SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0;  //先置0进行ePWM配置再置1
        EDIS;

        InitEPwm1Example();

        EALLOW;
        SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1;  //看上一个注释
        EDIS;

        IER |= M_INT3;

        // Enable EPWM INTn in the PIE: Group 3 interrupt 1-3
        PieCtrlRegs.PIEIER3.bit.INTx1 = 1;

        // Enable global Interrupts and higher priority real-time debug events:
        EINT;   // Enable Global interrupt INTM
        ERTM;   // Enable Global realtime interrupt DBGM

        for(;;){
            __asm("          NOP");
        }

}

void Gpio_Setup(void){
    EALLOW;
    GpioCtrlRegs.GPAMUX1.bit.GPIO0=1;   //GPIO0配置为ePWM1A功能
    GpioCtrlRegs.GPAMUX1.bit.GPIO1=1;   //GPIO1配置为ePWM1B功能
    EDIS;
}

void InitEPwm1Example(void){
       // Setup TBCLK
       EPwm1Regs.TBPRD = 25000;                  // 增减模式下为3KHz,自行计算
       EPwm1Regs.TBPHS.half.TBPHS = 0;           // Phase is 0
       EPwm1Regs.TBCTR = 0;                           // 时基计数器清零
       EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;
       EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE;   // Disable phase loading
       EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;  // Clock ratio to SYSCLKOUT
       EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1;

       // Setup shadowing
       EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
       EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
       EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; // CTR = Zero时CMPA从影子寄存器加载
       EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO; // CTR = Zero时CMPB从影子寄存器加载

       // Set actions
       EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR; // Clear PWM1A on event A, up count
       EPwm1Regs.AQCTLA.bit.CAD = AQ_SET;   // Set PWM1A on event A, down count
       EPwm1Regs.AQCTLB.bit.CBU = AQ_CLEAR; // Clear PWM1B on event B, up count
       EPwm1Regs.AQCTLB.bit.CBD = AQ_SET;   // Set PWM1B on event B, down count

       // Interrupt where we will change the Compare Values
       EPwm1Regs.ETSEL.bit.INTSEL= ET_CTR_PRD;      // Select INT on PRD event
       EPwm1Regs.ETSEL.bit.INTEN = 1;                   // Enable INT
       EPwm1Regs.ETPS.bit.INTPRD = ET_1ST;            // Generate INT on 1ST event

       EPwm1Regs.CMPA.half.CMPA = 0x0C35;//随便给的初始值,去掉也没问题吧
}

interrupt void epwm1_isr(void){

    EPwm1Regs.CMPA.half.CMPA=EPwm1Regs.TBPRD*((1.0+M*sina[i])/2.0);
    EPwm1Regs.CMPB=EPwm1Regs.TBPRD*((1.0+M*sinb[i])/2.0);
    i++;

    if (i>=N){ i=0; }

    EPwm1Regs.ETCLR.bit.INT = 1; //写1对ETFLG[INT]状态标志位清零才能进行下一次中断
    PieCtrlRegs.PIEACK.all=PIEACK_GROUP3;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!