欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  网络运营

DSP28335的SPWM波生成方法

程序员文章站 2022-07-10 16:04:08
DSP新手,研究了一下午,在这里做个总结,希望对其他刚接触DSP的新手也能有所帮助。首先要明白SPWM波是什么。SPWM波实际上就只有2种电平,而且其频率一般是你自己给定的,所以难点在于如何调节每个周期内的占空比,这里采用的是双极性调制法。先说总体思路:以TBCTR为载波,以CMPA为调制波,并且让CMPA的值不断更新(中断方式),就可以在ePWMxA产生SPWM波。看了一些资料的你(没看就去看吧),应该能了解到ePWM模块的TB寄存器是设置频率的,CMPA和CMPB是设置占空比的,AQ...

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

首先要明白SPWM波是什么。

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

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

DSP28335的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;
}

 

本文地址:https://blog.csdn.net/qq_39527251/article/details/107432945

相关标签: dsp