引言:PWM對於很多軟件工程師可能又熟悉又陌生,以PWM調節LED亮度為例,其本質是在每個周期都偷工減料一些,整體表現出LED欠壓亮度不同的效果。像大家看到的七色彩燈其原理也類似,只是用3路PWM分別控制紅、綠、藍三種顏色的燈輸出亮度,再結合混色原理表現出豐富多彩的炫光效果~
寫在前面:前十幾篇介紹了CC2530的一些外設的基本用法,接下來幾篇拿幾個例子回顧並加深一下之前的知識點,上面引言是普及、下面高能預警!
第一個例子:用定時器1產生PWM來控制LED亮度
我們在《[ZigBee] 5、ZigBee基礎實驗——圖文與代碼詳解定時器1(16位定時器)(長文)》中講過定時器1 是一個支持典型的定時/計數功能的獨立16 位定時器,支持輸入捕獲,輸出比較和PWM等功能。該工程就是利用定時計數器1產生1毫秒PWM,20%的占空比,用PWM來調節LED的亮度,如果led的亮度比較暗可調整pwm頻率和占空比來控制Led燈的亮度。
1 /**************************************************************************** 2 * 文 件 名: main.c 3 * 描 述: cc2530 定時計數器1產生1毫秒PWM,20%的占空比,led的亮度比較暗 4 * 可調整pwm頻率和占空比來控制Led燈的亮度 5 ****************************************************************************/ 6 #include <ioCC2530.h> 7 8 typedef unsigned char uchar; 9 typedef unsigned int uint; 10 11 #define LED1 P1_0 // P1.0口控制LED1 12 13 14 /**************************************************************************** 15 * 名 稱: InitLed() 16 * 功 能: 設置LED燈相應的IO口 17 * 入口參數: 無 18 * 出口參數: 無 19 ****************************************************************************/ 20 void InitLed(void) 21 { 22 P1DIR |= 0x01; //P1.0定義為輸出 23 LED1 = 1; //使LED1燈上電默認為熄滅 24 } 25 26 /**************************************************************************** 27 * 名 稱: InitT1() 28 * 功 能: 定時器初始化,TICKSPD 是16 MHz系統不配置時默認是2分頻,即16MHz 29 * 入口參數: 無 30 * 出口參數: 無 31 ****************************************************************************/ 32 void InitT1() 33 { 34 CLKCONCMD &= ~0x40; //設置系統時鍾源為32MHZ晶振 35 while(CLKCONSTA & 0x40); //等待晶振穩定為32M 36 CLKCONCMD &= ~0x07; //設置系統主時鍾頻率為32MHZ 37 CLKCONCMD |= 0x38; //時鍾速度32 MHz 定時器標記輸出設置[5:3]250kHz 38 39 PERCFG |= 0x40; //定時器1 的IO位置 1:備用位置2 40 P2SEL &= ~0x10; //定時器1優先 41 P2DIR |= 0xC0; //第1優先級:定時器1通道2-3 42 43 P1DIR |= 0xff; //端口1為輸出 44 P1SEL |= 0x01; //timer1 通道2映射口P1_0 45 46 T1CC2H = 0x00; //20%占空比為200us 47 T1CC2L = 0x32; //修改T1CC2L可調整led的亮度 48 T1CC0H = 0x00; //1ms的周期時鍾,頻率為976.516HZ 49 T1CC0L = 0xff; 50 T1CCTL2 = 0x1c; // 模式選擇 通道2比較模式 51 T1CTL = 0x02; //250KHz 1分頻 52 } 53 54 /**************************************************************************** 55 * 程序入口函數 56 ****************************************************************************/ 57 void main(void) 58 { 59 InitLed(); //調用初始化函數 60 InitT1(); //定時器初始化及pwm配置 61 while(1) 62 { 63 } 64 }
可見代碼中的核心在於39~51行:
39 PERCFG |= 0x40; //定時器1 的IO位置 1:備用位置2
40 P2SEL &= ~0x10; //定時器1優先
41 P2DIR |= 0xC0; //第1優先級:定時器1通道2-3
42
43 P1DIR |= 0xff; //端口1為輸出
44 P1SEL |= 0x01; //timer1 通道2映射口P1_0
45
46 T1CC2H = 0x00; //20%占空比為200us
47 T1CC2L = 0x32; //修改T1CC2L可調整led的亮度
48 T1CC0H = 0x00; //1ms的周期時鍾,頻率為976.516HZ
49 T1CC0L = 0xff; 50 T1CCTL2 = 0x1c; // 模式選擇 通道2比較模式 51 T1CTL = 0x02; //250KHz 1分頻
1.1、第一步:調用外設控制寄存器設置外設所映射IO引腳的方案
其中第39行令PERCFG |= 0x40,PERCFG是外設控制寄存器,如下圖該寄存器用來設置一些外設的I/O的位置。這里操作的是第六位T1CFG,選擇定時器1的IO為備用位置2。
這里所說的IO映射位置方案1和方案2需要在表《Peripheral I/O Pin Mapping》中查看,在第七節《[ZigBee] 7、ZigBee之UART剖析(ONLY串口發送)》中我已經用UART的例子詳細介紹如何看這個表:
以USART0為例,第一種映射關系是RT-P05\CT-P04\TX-P03\RX-P02;另一種映射關系是TX-P15\RX-P14\RT-P13\CT-P12。
那么在使用過程中,一種模式對應兩種映射肯定會出現矛盾!
那么外設控制寄存器就是用來設置選擇哪種方案的!這里設置為0x40即選用定時器1的引腳映射方案2:P07對應通道3、P06-通道4、P12-通道0、P11-通道1、P10-通道2~
1.2、第二步:調用Port2功能選擇和Port1設備優先級控制寄存器,設置timer1占Port1引腳的外設優先級為高
在第七節《[ZigBee] 7、ZigBee之UART剖析(ONLY串口發送)》中同樣有介紹,上面外設控制寄存器僅僅解決了同一個外設多個IO映射方案的沖突問題,但是並沒有解決不同外設IO映射沖突問題。P2SEL寄存器就是處理這個問題!
3、4、5、6位用於設置同一個IO上兩個設備當PERCFG賦值時的優先級,因此這里設置P2SEL &= ~0x10,將定時器設置為最優先。
1.3、第三步:調用Port2方向選擇和Port0設備優先級控制寄存器,設置timer1占Port0引腳的外設優先級為高
在第七節《[ZigBee] 7、ZigBee之UART剖析(ONLY串口發送)》中同樣有介紹,由於timer1引腳映射占了Port0和Port1,因此上面P2SEL寄存器用來設置port1部分timer所占引腳的優先級,這里調用P2DIR設置其占Port0引腳的優先級,代碼中P2DIR |= 0xC0,即設置7~6位為11使定時器1通道2-3最優先。
規律:不難發現這里timer的用法和第七篇中介紹的uart初始化很類似,前三行做端口映射、優先級選定,一般外設會涉及兩個端口,因此需要用P0SEL和P2DIR分別設置。接下來就是針對具體外設的參數設置了!
1.4、第四步:選擇PWM通道,並使能
在1.1中介紹定時器1的引腳映射方案選用是備用2方案:P07對應通道3、P06-通道4、P12-通道0、P11-通道1、P10-通道2~
在1.3中設置通道2、3優先級最高
從1.1~1.3為timer1的PWM的的初始化,也設置了通道的優先級,如果想使能通道還需要進一步設置:
43 P1DIR |= 0xff; //端口1為輸出 44 P1SEL |= 0x01; //timer1 通道2映射口P1_0
其中第43行設置端口1為全部輸出,第44行比較關鍵,用來將IO引腳設置為普通IO引腳還是設置成IO外設引腳,這里將P1_0設置為外設引腳。根據前面的設置,我們知道是將P10設置為了定時器1的通道2輸出口。
1.5、定時器1通道2輸出比較模式選擇&設置周期與占空比
關於輸出比較模式在《[ZigBee] 5、ZigBee基礎實驗——圖文與代碼詳解定時器1(16位定時器)(長文)》里的第9段介紹比較詳細:PWM 輸出可以通過選擇定時器正計數/倒計數模式生成。根據PWM 信號所需的極性選擇通道輸出比較模式4 或5(由T1CCTLn.CMP 位定義,其中n 是1 或2)。PWM 信號的周期由T1CC0 確定,通道輸出的占空比由T1CCn 確定,其中n 是PWM 通道1 或2。某些類型的電機驅動應用程序會需要中心對齊的PWM 模式,一般地這比邊沿對齊的PWM 模式產生的噪音更少,因為I/O 引腳傳輸不集中在同一個時鍾邊沿上。
46 T1CC2H = 0x00; //20%占空比為200us
47 T1CC2L = 0x32; //修改T1CC2L可調整led的亮度
48 T1CC0H = 0x00; //1ms的周期時鍾,頻率為976.516HZ
49 T1CC0L = 0xff;
50 T1CCTL2 = 0x1c; // 模式選擇 通道2比較模式
51 T1CTL = 0x02; //250KHz 1分頻
其中第50行用來設置定時器1通道2捕獲/比較控制寄存器為0x1C,[5:3]=011則選擇了輸出比較模式4,其PWM信號周期由T1CC0決定,占空比由T1CCn確定(正計數到計數模式生成PWM比邊沿模式生成PWM更適合這里,如果你聽不懂這句話請看第5篇)!因此,46~49行就是設置PWM的周期和占空比~
注意:這里0x0032/0x00ff不等於20%,為什么注釋中說占空比為20%呢?我們用一個簡單的例子解釋這個問題的特殊性(繪制定時器counter的值變化線如下):左邊的一個設T1CC0=4,T1CC2=2,顯然占空比不是2/4,也不是3/9,因為最后一個綠色框內的時期屬於下一個周期了,一個完整周期應該為0~4~1,因此占空比為3/8;同理右邊的占空比為3/6。這里T1CC2設置為0x0032,則低段有:0~0x0032,0x0032~1,總共(0x0032-0+1)+(0x0032-1+1)=0x0032*2+1=0x0065=101;總周期為0x00FF*2=0x01FE=510,占空比為0x65/0x01FE約等於5
其中最后一行T1CTL = 0x02,用來設置自由運行模式(關於模式也在第七篇介紹),采用1分頻,250KHz~
總結:這樣就能用PWM輸出通道2直接關聯到P10來控制LED的亮度,簡單有效~
Zigbee系列文章:
[ZigBee] 3、ZigBee基礎實驗——GPIO輸出控制實驗-控制Led亮滅
[ZigBee] 5、ZigBee基礎實驗——圖文與代碼詳解定時器1(16位定時器)(長文)
[ZigBee] 6、ZigBee基礎實驗——定時器3和定時器4(8 位定時器)
[ZigBee] 7、ZigBee之UART剖析(ONLY串口發送)
[ZigBee] 8、ZigBee之UART剖析·二(串口收發)
[ZigBee] 9、ZigBee之AD剖析——AD采集CC2530溫度串口顯示
[ZigBee] 12、ZigBee之看門狗定時器——餓了就咬人的GOOD DOG
PS:如果您覺得還不錯,點個贊,讓更多人受益~
@beautifulzzzz 2016-07-22 continue~
e-mail:beautifulzzzz@qq.com
sina:http://weibo.com/beautifulzzzz?is_all=1