zoukankan      html  css  js  c++  java
  • (转)CortexM3 (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灯进行示意。

    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的边沿。

  • 相关阅读:
    1034:计算三角形面积
    1033:计算线段长度
    1033:计算线段长度
    1033:计算线段长度
    1032:大象喝水查
    1032:大象喝水查
    1032:大象喝水查
    SQL Server 数据类型
    sql server 变量声明、设置、使用、输出
    sql server 变量声明、设置、使用、输出
  • 原文地址:https://www.cnblogs.com/tdyizhen1314/p/2704589.html
Copyright © 2011-2022 走看看