博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
(转)Cortex-M3 (NXP LPC1788)之PWM
阅读量:5792 次
发布时间:2019-06-18

本文共 8350 字,大约阅读时间需要 27 分钟。

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灯进行示意。

 

[cpp]
  1. #define CCLK        120000000 
  2. #define PCLK         60000000 
  3.  
  4. #define rFIO1DIR    (*(volatile unsigned*)(0x20098020)) 
  5. #define rFIO1MASK   (*(volatile unsigned*)(0x20098030)) 
  6. #define rFIO1PIN    (*(volatile unsigned*)(0x20098034)) 
  7. #define rFIO1SET    (*(volatile unsigned*)(0x20098038)) 
  8. #define rFIO1CLR    (*(volatile unsigned*)(0x2009803c)) 
  9.  
  10. #define rCLKSRCSEL  (*(volatile unsigned *)(0x400FC10C))     //时钟源选择寄存器   
  11. #define rPLL0CON    (*(volatile unsigned *)(0x400FC080))     //PLL0控制寄存器   
  12. #define rPLL0CFG    (*(volatile unsigned *)(0x400FC084))     //PLL0配置寄存器   
  13. #define rPLL0STAT   (*(volatile unsigned *)(0x400FC088))     //PLL0状态寄存器   
  14. #define rPLL0FEED   (*(volatile unsigned *)(0x400FC08C))     //PLL0馈送寄存器   
  15. #define rPLL1CON    (*(volatile unsigned *)(0x400FC0A0))        
  16. #define rPLL1CFG    (*(volatile unsigned *)(0x400FC0A4))   
  17. #define rPLL1STAT   (*(volatile unsigned *)(0x400FC0A8))   
  18. #define rPLL1FEED   (*(volatile unsigned *)(0x400FC0AC))   
  19. #define rCCLKSEL    (*(volatile unsigned *)(0x400FC104))     //CPU时钟选择寄存器   
  20. #define rUSBCLKSEL  (*(volatile unsigned *)(0x400FC108))     //USB时钟选择寄存器   
  21. #define rPCLKSEL    (*(volatile unsigned *)(0x400FC1A8))     //外设时钟寄存器   
  22. #define rPCON       (*(volatile unsigned *)(0x400FC0C0))   
  23. #define rPXCONP     (*(volatile unsigned *)(0x400FC0C4))   
  24. #define rSCS        (*(volatile unsigned *)(0x400FC1A0))     //系统控制和状态寄存器   
  25. #define rCLKOUTCFG  (*(volatile unsigned *)(0x400FC1C8)) 
  26.  
  27. #define rIOCON_P1_02    (*(volatile unsigned *)(0x4002C088)) 
  28. #define rPCONP      (*(volatile unsigned *)(0x400FC0C4)) 
  29.  
  30. #define rPWM0IR     (*(volatile unsigned *)(0x40014000)) 
  31. #define rPWM0TCR    (*(volatile unsigned *)(0x40014004)) 
  32. #define rPWM0TC     (*(volatile unsigned *)(0x40014008)) 
  33. #define rPWM0PR     (*(volatile unsigned *)(0x4001400C)) 
  34. #define rPWM0CTCR   (*(volatile unsigned *)(0x40014070)) 
  35. #define rPWM0MCR    (*(volatile unsigned *)(0x40014014)) 
  36. #define rPWM0MR0    (*(volatile unsigned *)(0x40014018)) 
  37. #define rPWM0MR1    (*(volatile unsigned *)(0x4001401C)) 
  38. #define rPWM0CCR    (*(volatile unsigned *)(0x40014028)) 
  39. #define rPWM0PCR    (*(volatile unsigned *)(0x4001404C)) 
  40. #define rPWM0LER    (*(volatile unsigned *)(0x40014050)) 
  41.  
  42. #define rISER1      (*(volatile unsigned *)(0xE000E104)) 
  43. #define rCER1       (*(volatile unsigned *)(0xE000E184)) 
  44.  
  45. unsigned int duty = 10; 
  46. unsigned char match_cnt = 0; 
  47.  
  48. void PWM0_IRQHandler(void
  49.     if(rPWM0IR&0x1) 
  50.     { 
  51.         rFIO1PIN |= (1<<18); 
  52.         match_cnt++; 
  53.         rPWM0IR |= 0x1;     //MR0中断复位 
  54.     } 
  55.      
  56.     if(rPWM0IR&(0x1<<1)) 
  57.     { 
  58.         rFIO1PIN &= ~(1<<18); 
  59.         rPWM0IR |= 0x1<<1;  //MR1中断复位 
  60.     } 
  61.  
  62. void SystemInit()   
  63. {   
  64.     rSCS &= ~(0x1<<4);                //频率12M   
  65.     rSCS |= (0x1<<5);             //使能主振荡器   
  66.     while(0 == (rSCS & (0x1<<6)));//等待主振荡器稳定   
  67.        
  68.     rCLKSRCSEL = 0x1;   
  69.        
  70.     rPLL0CFG = 0x9;                 //配置CCLK = 120M   
  71.     rPLL0CON = 0x01;   
  72.     rPLL0FEED = 0xAA;   
  73.     rPLL0FEED =0x55;   
  74.     while( 0 == (rPLL0STAT & (0x1<<10)));    
  75.        
  76.     rCCLKSEL = (0x1 | (0x1<<8));   
  77.     rPCLKSEL = 0x2;                 //配置PCLK = 60M   
  78.        
  79.     rCLKOUTCFG = 0x0 | (0xb<<4) | (0x1<<8);   
  80. }  
  81.  
  82.  
  83. void PWMInit() 
  84.     rIOCON_P1_02 &= ~0x7; 
  85.     rIOCON_P1_02 |= 0x3;    //P1.02配置成PWM0[1] 
  86.      
  87.     rPCONP |= 0x1<<5;     //使能PWM0外设 
  88.      
  89.     rPWM0IR = 0x73F;    //初始化PWM相关控制寄存器 
  90.     rPWM0TCR = 0; 
  91.     rPWM0CTCR = 0; 
  92.     rPWM0MCR = 0; 
  93.     rPWM0CCR = 0; 
  94.     rPWM0PCR = 0; 
  95.     rPWM0LER = 0; 
  96.      
  97.     rPWM0PR = 0x1<<20;    //每0x1<<20+1个PLCK上升沿,TC递增 
  98.     rPWM0TCR |= 0x1<<1;   //复位TC和PC 
  99.     rPWM0TCR &= ~(0x1<<1); 
  100.      
  101.     rPWM0MR0 = 100; 
  102.     rPWM0LER |= 0x1; 
  103.     rPWM0MCR |= 0x1<<1 | 0x1;     //MR0和TC匹配时复位TC和PC.并且产生中断 
  104.      
  105.     rPWM0MR1 = duty; 
  106.     rPWM0LER |= 0x1<<1; 
  107.     rPWM0MCR |= 0x1<<3;   //MR1和TC匹配时产生中断 
  108.  
  109. int main () 
  110.     PWMInit(); 
  111.      
  112.     rFIO1DIR |= (0x1<<18); 
  113.     rISER1 |= 0x1<<7; //PWM0中断使能 
  114.      
  115.     rPWM0TCR |= 0x1<<1;   //复位TC和PC 
  116.     rPWM0TCR &= ~(0x1<<1); 
  117.      
  118.     rPWM0TCR |= 0x1;    //PC和TC计数使能 
  119.     rPWM0TCR |= 0x1<<3; //PWM模式使能 
  120.      
  121.     while(1) 
  122.     { 
  123.         if(match_cnt >= 1) 
  124.         { 
  125.             match_cnt = 0; 
  126.             duty = duty+10; 
  127.             if(duty >= 100) 
  128.             { 
  129.                 duty  = 0; 
  130.             } 
  131.             rPWM0MR1 = duty; 
  132.             rPWM0LER |= 0x1<<1; 
  133.             rPWM0MCR |= 0x1<<3; 
  134.         } 
  135.     } 
  136.     return 1; 
#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的边沿。

转载地址:http://zxgyx.baihongyu.com/

你可能感兴趣的文章
【转】php字符串加密解密
查看>>
22. linux 常用命令
查看>>
ASP.Net 使用GridView模板删除一行的用法
查看>>
(十六)字段表集合
查看>>
JPGraph
查看>>
实验二 Java面向对象程序设计
查看>>
------__________________________9余数定理-__________ 1163______________
查看>>
webapp返回上一页 处理
查看>>
新安装的WAMP中phpmyadmin的密码问题
查看>>
20172303 2017-2018-2 《程序设计与数据结构》第5周学习总结
查看>>
eclipse中将一个项目作为library导入另一个项目中
查看>>
Go语言学习(五)----- 数组
查看>>
Android源码学习之观察者模式应用
查看>>
Content Provider的权限
查看>>
416. Partition Equal Subset Sum
查看>>
centos7.0 64位系统安装 nginx
查看>>
数据库运维平台~自动化上线审核需求
查看>>
注解开发
查看>>
如何用 Robotframework 来编写优秀的测试用例
查看>>
Django之FBV与CBV
查看>>