本文記錄如何利用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,計數值重置。
在這個模式下如果使用比較輸出的話,T1CC0因為用做比較輸出的最大值,所以通道0沒有最后兩種輸出模式。在最后兩種模式中,狀態轉換是與T1CC0和T1CCn(n表示通道)比較得出的。通道0重疊了!!
另外有一點需要注意,在配置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_VECTOR 23 __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.032768 10 #define DIV_32 2 //0.131072 11 #define DIV_128 3 //0.524288s 12 //定時器工作模式 13 #define Suspended 0 14 #define Free_Running 1 15 #define Modulo 2 16 #define Up_And_Down 3 17 18 //Timer speed 19 #define T_32M 0 20 #define T_16M 1 21 #define T_8M 2 22 #define T_4M 3 23 #define T_2M 4 24 #define T_1M 5 25 #define T_500K 6 26 #define T_250K 7 27 28 29 //T1STAT 30 31 //function 32 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 | VDD 11 * | | L_T | D4 S1 | | 12 *----------------------------------------------- 13 */ 14 15 // D1~D3 16 17 void LED_Init(void) 18 { 19 P1SEL &= ~0x13; //設置為GPIO 20 P1DIR |= 0x13; //設置為輸出 21 P1INP &= ~0x13; // 22 23 P0SEL |= 0x04; //設置為外設IO 24 P0DIR |= 0x04; 25 P0INP &= ~0x04; 26 27 PERCFG |= 0x03; //設置串口映射到P1 28 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_0 10 #define D1 P1_1 11 #define D2 P1_4 12 13 #define D0_NUM 1 14 #define D1_NUM 2 15 #define D2_NUM 3 16 17 void LED_Init(void); 18 19 #endif
建議仿真文件選擇ioCC2530F256.ddf,可以看更多的寄存器情況,方便調試
最后附上TI E2E社區一個帖子 點我