TMS320F28377D学习日志:day4基于ePWM的呼吸灯


前言

28377D具有24路PWM输出引脚,14路高分辨率的HRPWM。ePWM是对PWM的加强型。其中一个ePWM通道有2个PWM输出引脚EPWMxA、EPWMxB,可以用于配置两路独立单边沿PWM、两路对称双边沿PWM和一路双边沿PWM。每个ePWM具有1个16位的时基计数器,用于控制周期和频率。
该通过对ePWM0进行配置,复用GPIO0和GPIO1为epwm,输出两路周期相同,占空比不同的PWM波形。在引脚接上LED,通过循环语句改变PWM的占空比,从而实现LED由亮到灭再到亮。


一、TMS320F28377D的ePWM介绍

1.1 PWM的复用引脚

PWM模块的输出引脚见下表,其中每组EPWM都有2组不同的引脚,在实际应用中复用其中一组引脚即可。

EPWMGPIO
EPWM1A/BGPIO0/1或GPIO145/146
EPWM2A/BGPIO2/3或GPIO147/148
EPWM3A/BGPIO4/5或GPIO149/150
EPWM4A/BGPIO6/7或GPIO151/152
EPWM5A/BGPIO8/9或GPIO153/154
EPWM6A/BGPIO10/11或GPIO155/156
EPWM7A/BGPIO12/13或GPIO157/158
EPWM8A/BGPIO14/15或GPIO159/160
EPWM9A/BGPIO16/17或GPIO161/162
EPWM10A/BGPIO18/19或GPIO163/164
EPWM11A/BGPIO20/21或GPIO165/166
EPWM12A/BGPIO22/23或GPIO167/168

1.2 PWM模块的组成

一个ePWM模块由8个小模块组成,如下图。分别为时基模块(TB)、比较计数模块(CC)、动作模块(AQ)、死区模块(DB)、PWM斩波模块(PC)、时间触发模块(ET)、防联模块(TZ)和数字比较模块(DC)。
在这里插入图片描述
其中,配置PWM波形常用的是TB、CC、AQ、DB和ET等模块。接下来介绍TB、CC和AQ模块。

1.3 TB模块

在这里插入图片描述
在这里插入图片描述
TB模块可以用于设计PWM的周期大小。其中有三种计数方式:向上计数、向下计数和向上-向下计数。其中配置PWM的周期/频率与TBPRD和TBCTRL这两个寄存器有关。TBPRD为时基周期寄存器值,用于储存计数的最大值。TBCTRL为时基计数器的计数模式,其中可以设置以上的三种计数模式。
对于设置为向上-向下计数模式的情况
在这里插入图片描述
其中PWM周期等于2倍的TBPRD乘以单个计数的时间。
对于对于设置为向上计数模式或者向下计数模式的情况
在这里插入图片描述
其中PWM周期等于TBPRD加一的和,再乘以单个计数的时间。
其中上面两图中T(TBCLK)是经过分频之后,一次计数的时间。频率计算公式为TBCLK=EPWMCLK/(HSPCLKDTV*CLKDIV),再取倒数就是周期。

TB模块配置程序:

// Setup TBCLK
    EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // Count up
    EPwm1Regs.TBPRD = EPWM1_TIMER_TBPRD;       // Set timer period,这里设置为20k
    EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE;    // Disable phase loading
    EPwm1Regs.TBPHS.bit.TBPHS = 0x0000;       // Phase is 0
    EPwm1Regs.TBCTR = 0x0000;                  // Clear counter
    EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV2;   // Clock ratio to SYSCLKOUT,采用2分频
    EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV2;      //TBCLK=EPWMCLK/(HSPCLKDIV*CLKDIV)=200M/(2*2)=50M,所以PWM周期为(20k+1)/50M=400us

其中采用向上计数的模式;EPWM1_TIMER_TBPRD预先宏定义为20k;没有预先相位,相位为;HSPCLKDIV 和CLKDIV 都采用2分频,28377D的系统频率为200M Hz,所以TBCLK为50M Hz,周期为1/50M s;经过计数PWM周期为400us。

1.4 CC模块

CC模块可以用于控制PWM的脉宽
在这里插入图片描述
对于向上计数模式或者向下计数模式,在一个PWM周期中,比较只能计数一次,就是单边沿触发;对于向上-向下计数模式,在一个PWM周期中,比较会计数两次,就是双边沿触发。

CC模块配置程序:

// Setup shadow register load on ZERO
    EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
    EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
    EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
    EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;

    // Set Compare values
    EPwm1Regs.CMPA.bit.CMPA = EPWM1_MIN_CMPA;    // Set compare A value
    EPwm1Regs.CMPB.bit.CMPB = EPWM1_MAX_CMPB;    // Set Compare B value

这里采用了影子寄存器的方式,给CC寄存器进行配置,当计数器为0时进行载入。同时设置CMPA和CMPB的比较值,当计数器到达这两个比较值时,会发出脉冲给AQ模块,进而调整输出电平。因此CMPA和CMPB的比较值将会影响PWM的脉宽大小。

1.5 AQ模块

AQ模块用于控制输出PWM的动作,当CC模块触发或者软件触发时,可以响应触发,选择对PWM波形进行置高、置底或者翻转等操作。
在这里插入图片描述

AQ模块配置程序:

// Set actions
    EPwm1Regs.AQCTLA.bit.ZRO = AQ_SET;            // Set PWM1A on Zero
    EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR;          // Clear PWM1A on event A, up count

    EPwm1Regs.AQCTLB.bit.ZRO = AQ_SET;            // Set PWM1B on Zero
    EPwm1Regs.AQCTLB.bit.CBU = AQ_CLEAR;          // Clear PWM1B on event B, up count

当计数器为0时,设置EPWM1A为高电平;当计数器等于CMPA的比较值时,设置EPWM1A为低电平。对于EPWM1B的设置也是同理。

// AQCTLA and AQCTLB (Action Qualifier Control)
//=============================================
// ZRO, PRD, CAU, CAD, CBU, CBD bits
#define	AQ_NO_ACTION	0x0
#define	AQ_CLEAR		0x1
#define	AQ_SET			0x2
#define	AQ_TOGGLE		0x3

在ti官方给的F2837xD_EPwm_defines.h中可以看到,AQ动作有4种方式。其中AQ_NO_ACTION为无事发生;AQ_CLEAR为置低;AQ_SET为置高;AQ_TOGGLE为翻转。AQ可以动作的时间也有很多,还包括计数器计满等情况。

二、程序介绍

#include "F28x_Project.h"

#define EPWM1_TIMER_TBPRD  20000
#define EPWM1_MAX_CMPA     19500
#define EPWM1_MIN_CMPA       500
#define EPWM1_MAX_CMPB     19500
#define EPWM1_MIN_CMPB       500

void InitEPwm1Example(void);

void main(void)
{
    //初始化系统时钟
    InitSysCtrl();

    //使能PWM1
    CpuSysRegs.PCLKCR2.bit.EPWM1=1;

    //初始化pwm1的gpio
    InitEPwm1Gpio();

    //Disable CPU interrupts
    DINT;

    //Initialize the PIE control registers to their default state.
    InitPieCtrl();

    // Disable CPU interrupts and clear all CPU interrupt flags:
    IER = 0x0000;
    IFR = 0x0000;

    //Initialize the PIE vector table with pointers to the shell Interrupt
    //Service Routines (ISR).
    InitPieVectTable();

    EALLOW;

    CpuSysRegs.PCLKCR0.bit.TBCLKSYNC =0;

    EDIS;

    //初始化EPWM
    InitEPwm1Example();

    EALLOW;

    CpuSysRegs.PCLKCR0.bit.TBCLKSYNC =1;

    EDIS;

    EINT;  // Enable Global interrupt INTM
    ERTM;  // Enable Global realtime interrupt DBGM

    int duty_cycle = 0; //用于控制pwm0的占空比
    int num = 0;  //用于记录duty_cycle是增加还是减少

    while(1)
    {
        if(num == 0)  //duty_cycle处于增长
        {
            duty_cycle++;

            if(duty_cycle == 100)
            {
                num = 1;
            }
        }
        else          //duty_cycle处于减少
        {
            duty_cycle--;
            if(duty_cycle == 0)
            {
                num = 0;
            }
        }

        EPwm1Regs.CMPA.bit.CMPA = (int) EPWM1_TIMER_TBPRD /100 * duty_cycle;          // Set compare A value
        EPwm1Regs.CMPB.bit.CMPB = (int) EPWM1_TIMER_TBPRD /100 * (100-duty_cycle);    // Set Compare B value

        DELAY_US(40 * 1000);  //延迟20ms
    }
}


void InitEPwm1Example(void)
{
    // Setup TBCLK
    EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // Count up
    EPwm1Regs.TBPRD = EPWM1_TIMER_TBPRD;       // Set timer period,这里设置为20k
    EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE;    // Disable phase loading
    EPwm1Regs.TBPHS.bit.TBPHS = 0x0000;       // Phase is 0
    EPwm1Regs.TBCTR = 0x0000;                  // Clear counter
    EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV2;   // Clock ratio to SYSCLKOUT,采用2分频
    EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV2;      //TBCLK=EPWMCLK/(HSPCLKDIV*CLKDIV)=200M/(2*2)=50M,所以PWM周期为(20k+1)/50M=400us

    // Setup shadow register load on ZERO
    EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
    EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
    EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
    EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;

    // Set Compare values
    EPwm1Regs.CMPA.bit.CMPA = EPWM1_MIN_CMPA;    // Set compare A value
    EPwm1Regs.CMPB.bit.CMPB = EPWM1_MAX_CMPB;    // Set Compare B value

    // Set actions
    EPwm1Regs.AQCTLA.bit.ZRO = AQ_SET;            // Set PWM1A on Zero
    EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR;          // Clear PWM1A on event A, up count

    EPwm1Regs.AQCTLB.bit.ZRO = AQ_SET;            // Set PWM1B on Zero
    EPwm1Regs.AQCTLB.bit.CBU = AQ_CLEAR;          // Clear PWM1B on event B, up count

}

呼吸灯的主程序,其中在while循环中每20ms改变PWM的占空比,由0逐渐增加1至100,再减一至0,另一路则相反。

void InitEPwm1Gpio(void)
{
    EALLOW;

    //
    // Disable internal pull-up for the selected output pins
    // for reduced power consumption
    // Pull-ups can be enabled or disabled by the user.
    // Comment out other unwanted lines.
    //
    GpioCtrlRegs.GPAPUD.bit.GPIO0 = 0;    // enable pull-up on GPIO0 (EPWM1A)
    GpioCtrlRegs.GPAPUD.bit.GPIO1 = 0;    // enable pull-up on GPIO1 (EPWM1B)
    // GpioCtrlRegs.GPEPUD.bit.GPIO145 = 1;    // Disable pull-up on GPIO145 (EPWM1A)
    // GpioCtrlRegs.GPEPUD.bit.GPIO146 = 1;    // Disable pull-up on GPIO146 (EPWM1B)

    //
    // Configure EPWM-1 pins using GPIO regs
    // This specifies which of the possible GPIO pins will be EPWM1 functional
    // pins.
    // Comment out other unwanted lines.
    //
    GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1;   // Configure GPIO0 as EPWM1A
    GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 1;   // Configure GPIO1 as EPWM1B
    // GpioCtrlRegs.GPEMUX2.bit.GPIO145 = 1;   // Configure GPIO145 as EPWM1A
    // GpioCtrlRegs.GPEMUX2.bit.GPIO146 = 1;   // Configure GPIO0146 as EPWM1B

    EDIS;
}

在配置GPIO的时候需要注意的是,GPIO的状态可以设置为上拉状态或者非上拉状态,二者都可以。一般来说为了避免功率浪费,默认为非上拉状态,但是这次实验要求GPIO作为输出引脚控制LED的亮灭,所以需要设置为上拉状态。将GpioCtrlRegs.GPAPUD.bit.GPIO0设置为0.

  • 34
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值