Cortex-M3 (NXP LPC1788)之PWM

        PWM即脉宽调制,可用于输出一定占空比的方波。LPC1788有两个PWM,每个PWM可以由6路的输出,PWM1~PWM6。下面介绍使用PWM0.1输出PWM波。

        1,PWM使用公共的PCLK,因此要配置系统时钟和外设时钟。之前的文章中有具体的时钟配置过程。

        2,使能PWM模块。配置外设功率配置寄存器PCONP,使能PWM0的时钟控制位。

        3,PWM0.1的输出管脚和P1_2管脚复用,因此要配置IOCON_P1_02寄存器,将其设置成PWM0.1的输出。

        4,设置PWM的脉冲宽度,基本的原理就是比较PWM定时器计数器TC和匹配寄存器MR中的值,如果匹配我们可以通过匹配控制寄存器MCR选择操作,如产生一个中断,复位TC,停止TC和预分频计数器PC且停止计数。匹配寄存器MR0通过在匹配是将计数器TC复位来控制PWM的周期频率。另一个匹配寄存器控制PWM沿的位置。如PWM0.1的输出,将使用MR0控制PWM的周期频率,MR1控制边沿的位置。

        5,最后是对于PWM的具体控制,配置PWM预分频寄存器PWMPR,该32位寄存器规定了PWM预分频计数的最大值,PWM预分频计数器寄存器PWMPC在每个PCLK上递增一次,当PWMPC和PWMPR值相等时,PWMTC的值会递增,而PWMPR在系一个PCLK周期被复位。这样,当PWMPR=0时,PWMTC会在每个PCLK上递增,而当PWMPR=1时,在每2个PCLK上递增。匹配寄存器PWMMR中的值和PWMTC的值比较,如果相等则触发在PWMMCR中配置的操作。当MR0和TC相等时,我们进行复位TC从新计数从而固定了PWM的周期频率。当定时器处于PWM模式时,软件对PWM匹配寄存器MR的写操作,写入值实际上被保存在一个映像寄存器中,不会被立即使用。所以在我们需要操作PWM锁存使能寄存器PWMLER,典型序列为:将新值写入MR,写PWMLER中相应的位,更改的MR值将在下一次定时器复位时生效。

        在下面的程序中,将给MR1中写入不同的匹配值,来控制PWM的占空比。为了方便使用LED灯进行示意。

#define CCLK		120000000
#define PCLK		 60000000

#define rFIO1DIR	(*(volatile unsigned*)(0x20098020))
#define rFIO1MASK 	(*(volatile unsigned*)(0x20098030))
#define rFIO1PIN	(*(volatile unsigned*)(0x20098034))
#define rFIO1SET	(*(volatile unsigned*)(0x20098038))
#define rFIO1CLR	(*(volatile unsigned*)(0x2009803c))

#define rCLKSRCSEL  (*(volatile unsigned *)(0x400FC10C))     //时钟源选择寄存器  
#define rPLL0CON    (*(volatile unsigned *)(0x400FC080))     //PLL0控制寄存器  
#define rPLL0CFG    (*(volatile unsigned *)(0x400FC084))     //PLL0配置寄存器  
#define rPLL0STAT   (*(volatile unsigned *)(0x400FC088))     //PLL0状态寄存器  
#define rPLL0FEED   (*(volatile unsigned *)(0x400FC08C))     //PLL0馈送寄存器  
#define rPLL1CON    (*(volatile unsigned *)(0x400FC0A0))       
#define rPLL1CFG    (*(volatile unsigned *)(0x400FC0A4))  
#define rPLL1STAT   (*(volatile unsigned *)(0x400FC0A8))  
#define rPLL1FEED   (*(volatile unsigned *)(0x400FC0AC))  
#define rCCLKSEL    (*(volatile unsigned *)(0x400FC104))     //CPU时钟选择寄存器  
#define rUSBCLKSEL  (*(volatile unsigned *)(0x400FC108))     //USB时钟选择寄存器  
#define rPCLKSEL    (*(volatile unsigned *)(0x400FC1A8))     //外设时钟寄存器  
#define rPCON       (*(volatile unsigned *)(0x400FC0C0))  
#define rPXCONP     (*(volatile unsigned *)(0x400FC0C4))  
#define rSCS        (*(volatile unsigned *)(0x400FC1A0))     //系统控制和状态寄存器  
#define rCLKOUTCFG  (*(volatile unsigned *)(0x400FC1C8))

#define rIOCON_P1_02	(*(volatile unsigned *)(0x4002C088))
#define rPCONP		(*(volatile unsigned *)(0x400FC0C4))

#define rPWM0IR 	(*(volatile unsigned *)(0x40014000))
#define rPWM0TCR	(*(volatile unsigned *)(0x40014004))
#define rPWM0TC		(*(volatile unsigned *)(0x40014008))
#define rPWM0PR 	(*(volatile unsigned *)(0x4001400C))
#define rPWM0CTCR	(*(volatile unsigned *)(0x40014070))
#define rPWM0MCR	(*(volatile unsigned *)(0x40014014))
#define rPWM0MR0	(*(volatile unsigned *)(0x40014018))
#define rPWM0MR1	(*(volatile unsigned *)(0x4001401C))
#define rPWM0CCR	(*(volatile unsigned *)(0x40014028))
#define rPWM0PCR	(*(volatile unsigned *)(0x4001404C))
#define rPWM0LER	(*(volatile unsigned *)(0x40014050))

#define rISER1  	(*(volatile unsigned *)(0xE000E104))
#define rCER1		(*(volatile unsigned *)(0xE000E184))

unsigned int duty = 10;
unsigned char match_cnt = 0;

void PWM0_IRQHandler(void)
{
	if(rPWM0IR&0x1)
	{
		rFIO1PIN |= (1<<18);
		match_cnt++;
		rPWM0IR |= 0x1; 	//MR0中断复位
	}
	
	if(rPWM0IR&(0x1<<1))
	{
		rFIO1PIN &= ~(1<<18);
		rPWM0IR |= 0x1<<1;  //MR1中断复位
	}
}

void SystemInit()  
{  
    rSCS &= ~(0x1<<4);                //频率12M  
    rSCS |= (0x1<<5);             //使能主振荡器  
    while(0 == (rSCS & (0x1<<6)));//等待主振荡器稳定  
      
    rCLKSRCSEL = 0x1;  
      
    rPLL0CFG = 0x9;                 //配置CCLK = 120M  
    rPLL0CON = 0x01;  
    rPLL0FEED = 0xAA;  
    rPLL0FEED =0x55;  
    while( 0 == (rPLL0STAT & (0x1<<10)));   
      
    rCCLKSEL = (0x1 | (0x1<<8));  
    rPCLKSEL = 0x2;                 //配置PCLK = 60M  
      
    rCLKOUTCFG = 0x0 | (0xb<<4) | (0x1<<8);  
} 


void PWMInit()
{
	rIOCON_P1_02 &= ~0x7;
	rIOCON_P1_02 |= 0x3;	//P1.02配置成PWM0[1]
	
	rPCONP |= 0x1<<5; 	//使能PWM0外设
	
	rPWM0IR = 0x73F;	//初始化PWM相关控制寄存器
	rPWM0TCR = 0;
	rPWM0CTCR = 0;
	rPWM0MCR = 0;
	rPWM0CCR = 0;
	rPWM0PCR = 0;
	rPWM0LER = 0;
	
	rPWM0PR = 0x1<<20;	//每0x1<<20+1个PLCK上升沿,TC递增
	rPWM0TCR |= 0x1<<1; 	//复位TC和PC
	rPWM0TCR &= ~(0x1<<1);
	
	rPWM0MR0 = 100;
	rPWM0LER |= 0x1;
	rPWM0MCR |= 0x1<<1 | 0x1; 	//MR0和TC匹配时复位TC和PC.并且产生中断
	
	rPWM0MR1 = duty;
	rPWM0LER |= 0x1<<1;
	rPWM0MCR |= 0x1<<3; 	//MR1和TC匹配时产生中断
}

int main ()
{
	PWMInit();
	
	rFIO1DIR |= (0x1<<18);
	rISER1 |= 0x1<<7;	//PWM0中断使能
	
	rPWM0TCR |= 0x1<<1; 	//复位TC和PC
	rPWM0TCR &= ~(0x1<<1);
	
	rPWM0TCR |= 0x1;	//PC和TC计数使能
	rPWM0TCR |= 0x1<<3; //PWM模式使能
	
	while(1)
	{
		if(match_cnt >= 1)
		{
			match_cnt = 0;
			duty = duty+10;
			if(duty >= 100)
			{
				duty  = 0;
			}
			rPWM0MR1 = duty;
			rPWM0LER |= 0x1<<1;
			rPWM0MCR |= 0x1<<3;
		}
	}
	return 1;
}
        程序在MR0匹配时复位TC,在MR1匹配时触发边沿。可以看到随着MR1匹配值的改变,LED灯的亮灭时间对应改变。(程序中的预分频寄存器PR设置为了让LED效果明显)

        LPC1788的PWM可以进行双边沿的控制。如PWM0.2可以用MR0控制PWM的周期频率,用MR1和MR2控制PWM0.2的边沿。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值