首页 > 代码库 > cc2530的pwm实现
cc2530的pwm实现
本文记录如何利用cc2530的timer1产生pwm输出。在此之前,先看看timer1的一些特性。
先看timer1的操作模式,分别是Free-Running, Modulo, Up-and-Down。
具体的讲,Free-Running就是在每个时钟沿到来是计数器加1,从0x0000一直加到0xFFFF(如果设置了溢出中断,则发生中断,默认开启中断,在TIMIF.T1OVFIM可以失能中断),计数范围固定不变,可以通过预分频来控制计数频率。
Modulo则是通过设置T1CC0H,T1CC0L两个寄存器来改变timer1的计数上限。但是,如果timer1启动时,计数值大于T1CC0H,T1CC0L,则timer1会继续向上计数到0xFFFF,然后产生溢出中断。如果timer1启动时,计数值小于T1CC0H,T1CC0L,则当计数值等于T1CC0H,T1CC0L,计数值重置。
另外有一点需要注意,在配置T1CC0H,T1CC0L确保定时器暂停,先写低位在写高位
Up-and-Down,并不是pwm模式,我看网蜂pdf的定时器章节里,在T1CTL的描述中,把Up-and-Down写成了pwm。实际上,这并不是PWM模式。可以理解是,Modulo模式中加多一个到达计数最大值时,往回计数到0x0000时产生溢出中断。适用于中心对称PWM。
其实,datasheet里面的图已经很清晰了。
接下来是比较输出,设置T1CC0H,T1CC0L,当计数值与T1CC0H,T1CC0L相等时,相关通道产生输出。timer1总共有5个通道(0~4)。比较输出总共有9钟模式,但是要注意4~5,6~7这两对是对应着不同操作模式,通过T1CCTLn.CMP来设置。datasheet是这样描述的,还是挺好理解的。
使用PWM的话,一般应该是选择后6种吧。前2种,如果不软件改变输出状态,那么状态就只改变一次,第3种则没有PWM效果,但是可以实现时间大于0xFFFF的输出翻转。还有就是不是每一个通道都有上述9种模式。比如通道0就没有最后两个模式。
最后就是设置IO了,将对应的IO口设置为外设IO就可以了。先来看看外设IO分布情况
可以看出来,timer1的对应的IO口和串口0,1重合,这里为了方便,可以通过PERCFG.U1CFG和PERCFG.U0CFG把IO设置到Alternative 2 location,也就是P1口。否则timer将不会有比较输出。
弄清楚这些之后就是配置寄存器的问题了。给出我自己的代码(代码仅供参考,具体请根据datasheet配置相关寄存器)。先看定时器部分。
1 #include "Timer.h" 2 #include "led.h" 3 4 void Timer1_Init(unsigned char mode, unsigned char div) 5 { 6 unsigned char temp; 7 8 T1CCTL0 = 0x24; 9 T1CC0L = 0x00; //设置低位,在运行中修改,仅当计数值为0时生效10 T1CC0H = 0xF0; //写入高位时,低位会从buffer中写入11 12 //配置工作模式和分频系数13 temp = div << 2;14 temp |= mode;15 T1CTL = temp;16 17 //使能Timer1中断18 T1IE = 1;19 20 }21 22 #pragma vector = T1_VECTOR23 __interrupt void T1_ISR(void)24 {25 26 D0 = ~D0;27 T1STAT &= ~(1 << 5);28 T1IF = 0; //清除T1中断标志29 }
1 #ifndef __TIMER_H 2 #define __TIMER_H 3 4 #include <ioCC2530.h> 5 6 //T1CTL 7 //预分频设置 Free_Running_time 8 #define DIV_1 0 //0.004096 9 #define DIV_8 1 //0.03276810 #define DIV_32 2 //0.13107211 #define DIV_128 3 //0.524288s12 //定时器工作模式13 #define Suspended 014 #define Free_Running 115 #define Modulo 216 #define Up_And_Down 317 18 //Timer speed19 #define T_32M 020 #define T_16M 121 #define T_8M 222 #define T_4M 323 #define T_2M 424 #define T_1M 525 #define T_500K 626 #define T_250K 727 28 29 //T1STAT30 31 //function32 void Timer1_Init(unsigned char mode, unsigned char div);33 34 #endif
再看LED部分
1 #include "led.h" 2 3 /* P1.1 | P1.3 | P1.5 | P1.7 | P2.1 | P2.3 | GND 4 * D2 | S2 | | | | | 5 * P1.0 | P1.2 | P1.4 | P1.6 | P2.0 | P2.2 | P2.4 6 * D1 | S3 | D3 | | S0 | | 7 *----------------------------------------------- 8 * P0.6 | P0.4 | P0.2 | P0.0 | RESET | GND 9 * | | L_R | | S4 |10 * P0.7 | P0.5 | P0.3 | P0.1 | VDD | VDD11 * | | L_T | D4 S1 | |12 *-----------------------------------------------13 */14 15 // D1~D316 17 void LED_Init(void)18 {19 P1SEL &= ~0x13; //设置为GPIO20 P1DIR |= 0x13; //设置为输出21 P1INP &= ~0x13; //22 23 P0SEL |= 0x04; //设置为外设IO24 P0DIR |= 0x04;25 P0INP &= ~0x04;26 27 PERCFG |= 0x03; //设置串口映射到P128 29 D0 = LED_OFF;30 D1 = LED_OFF;31 D2 = LED_OFF;32 }
1 #ifndef __LED_H 2 #define __LED_H 3 4 #include <ioCC2530.h> 5 6 #define LED_ON 0 7 #define LED_OFF 1 8 9 #define D0 P1_010 #define D1 P1_111 #define D2 P1_412 13 #define D0_NUM 114 #define D1_NUM 215 #define D2_NUM 316 17 void LED_Init(void);18 19 #endif
建议仿真文件选择ioCC2530F256.ddf,可以看更多的寄存器情况,方便调试
最后附上TI E2E社区一个帖子 点我