首页->【玩CortexM0】

377 0

[Nuvoton M0516] 实验三 2路PWM输出控制

看寄存器配置手册的6.6 PWM发生器和捕捉定时器一章。M0具有4个独立时钟源的PWM,可以发生4组[对]最高为16位PWM,可以配置成8个PWM输出——就是说,可以有8个PWM输出,4个互补的PWM对输出,本例将配置2个PWM输出,有时间再配置一对互补的PWM输出。

本例设置PWM输出用到的寄存器函数名为:P2_MFP:IO输出和功能、P2_PMD:PWM工作模式、APBCLK:PWM时钟、CLKSELx:时钟选择、PPRA:预分频、SCRA:分频值、CNRxA:PWM周期、CMRxA:PWM占空比、POEA:输出使能、PCRA:PWM计数开始、以及中断使能、中断向量等,看似很多,而在实际编程中许多是一次配置终身受用,只有像周期等需要在输出的阶段改变。

看硬件手册,可以知道P2.x的8个口可以作为PWM输出,也可以从P4.0~3这4个口输出PWM0~3。本例采用P2.0~4口输出PWM信号,0,1为单路PWM信号,2,3为互补PWM信号,不设死区。

本例在自定义区增加两行:

#define DEAD_ZONE_INTERVAL 0xC8FF0000//死区

#define PWM_PRESCALAE      0x0000C763//预分频

变量定义区:

//Define Vsrisbles

long jsq;//计数器

int tt0,tt1,dt0=10,dt1;//PWM变量

IO初始化改为:

//IO Initial增加一行:

P2_PMD = 0x5555;//P2 DOUT

定义两个函数,1个设置固定不变的屏幕显示字符,程序不断改变的变量显示:

//Display BaseData

void dispBase(void){

  c2l(7,0,19);c2l(7,1,28);c2l(7,2,26);c2l(7,3,40);//JSQ:

  c2l(4,0,25);c2l(4,1,32);c2l(4,2,22);c2l(4,3,40);//PWM:

  c2l(4,9,25);c2l(4,10,32);c2l(4,11,22);c2l(4,12,40);//PWM:

}

//Display Test Data

void dispMes(void){

  c2l(7,4,(jsq/100000)%10);c2l(7,5,(jsq/10000)%10);c2l(7,6,(jsq/1000)%10);c2l(7,7,(jsq/100)%10);c2l(7,8,(jsq/10)%10);c2l(7,9,jsq%10);

  c2l(4,4,(CMR0A/1000)%10);c2l(4,5,(CMR0A/100)%10);c2l(4,6,(CMR0A/10)%10);c2l(4,7,(CMR0A)%10);

  c2l(4,13,(CMR2A/1000)%10);c2l(4,14,(CMR2A/100)%10);c2l(4,15,CMR2A/10)%10);c2l(4,16,(CMR2A)%10);

}

增加初始化PWM函数:

//WPM Initial

void pwmInit(){

  P2_MFP &= ~(P20_AD8_PWM0 | P21_AD9_PWM1 | P22_AD10_PWM2| P23_AD11_PWM3);//DEF PWM Output Port

  P2_MFP |= (PWM0 | PWM1 | PWM2 | PWM3);             //设置P0.2~P0.3位PWM0~3  

  P2_PMD  &= ~(Px0_PMD | Px1_PMD | Px2_PMD | Px3_PMD);

  P2_PMD  |= (Px0_OUT | Px1_OUT | Px2_OUT | Px3_OUT);//设置P2.0~3为输出PWM

  APBCLK  |= (PWM01_CLKEN | PWM23_CLKEN);            //是能PWM0,1和2,3时钟

  CLKSEL1  = CLKSEL1 & ((PWM01_CLK | PWM23_CLK)); 

  CLKSEL1 |= (PWM01_22M | PWM23_22M);                //选择22MH中內时钟为PWM01,23时钟

  //PPRA DZI23|31:24 DZI01|23:16 CP23|15:8 CP01|7:0;DZIxx 死区;CPxx 分频数

  PPRA  = 0x00000408 | DEAD_ZONE_INTERVAL;           //设定预分频和死区

  CSRA  = CSRA & (~(CSR0 | CSR1 | CSR2 | CSR3));

  CSRA |= (CSR0_CLK_2|CSR1_CLK_4|CSR2_CLK_16|CSR3_CLK_8);//设置PWM0~3的分频值

  PCRA |= (CH2INV_ON | DZEN23);                          //PWM23为互补输出,PWM2反向

  PCRA |= (CH0_AU_RL | CH1_AU_RL | CH2_AU_RL | CH3_AU_RL);//PWM0~3位系数自动重载

  CNR0A = CNR1A = CNR2A = CNR3A = 0x2710;         //PWM0~3的周期

  CMR0A = CMR1A = 0x1388;                         //PWM01占空比

  CMR2A = CMR3A = 0x09C4;                         //PWM23占空比

  PIERA |= (PWMIE0 | PWMIE1 | PWMIE2 | PWMIE3);   //PWM0~3中断使能

  NVIC_ISER = PWMA_INT;                           //中断向量

  POEA |= (PWM0_OE | PWM1_OE | PWM2_OE | PWM3_OE);//PWM0~3中断使能

  PCRA |= (CH0EN | CH1EN | CH2EN | CH3EN);        //PWM计数器使能开始

}

再在上述函数后增加一个PWM脉宽改变函数:

//Set PWM Period

void pwmP(){

 CMR0A=CMR1A=tt0;//PWM01 Plus

 CMR2A=CMR3A=tt1;//PWM23 Plus

}

主函数main前半部分增加:

ioInit();

pwmInit();

lcdInit();

lcdClear();

dispBase();

主函数循环部分增加:

led();

if(tt0>0x2500){dt0=-2;};if(tt0<10){dt0=2;};tt0=tt0+dt0;

if(tt1>0x2000){dt1=-10;};if(tt1<10){dt1=10;};tt1=tt1+dt1;

pwmP();

dispMes();

if(jsq>999999) jsq=0;else jsq++;

最后增加1个PWM中断函数:

//PWM Intrerupt handler

void PWMA_IRQHandler(void){

  PIIRA = PIIRA;//清除PWM中断标志,使中断继续

}

运行结果见图31,图32,图33


楼主可见