定時器3和定時器4與定時器1功能類似,都有三種模式:自由運行模式、模模式、正計數/倒計數模式,都有輸入捕獲和輸出比較功能,不同的是定時器3和定時器4是8位計數器,而定時器1是16位的,另外定時器3和定時器4只有2個通道,定時器多了一個模式:倒計數模式。由於定時器3和定時器4相似,下面以定時器3為例說明。
定時器3和定時器4是兩個8位定時器,每個定時器有兩個獨立的捕獲/比較通道,每一通道使用一個I/O引腳。
定時器3/4有以下特點:
- 兩個捕獲/比較通道;
- 設置,清除或切換輸出比較;
- 每時鍾可以被以下分頻:1、2、4、8、16、32、64、128;
- 在每次捕獲/比較和最終計數事件發生時產生中斷請求;
- DMA觸發功能。
定時器3的計數器在時鍾的邊沿遞增或遞減,活動時鍾邊沿的周期由寄存器位CLKCONCMD.TICKSPD[2:0]定義,並且由T3CTL.DIV[2:0]設置分頻值。T3CTL寄存器定義如下:
我們可以看到,定時器3對比與定時器1多了一個倒計數模式:從T3CC0到0x00反復計數。
另外定時器3還有一個啟動定時器位,當TxCTL.START寫入1,則定時器計數器開始計數,當TxCTL.START寫入0,計數器暫停在當前值。
還有一個位TxCTL.CLR,當寫入1,計數器清0並且初始化相關通道的所有輸出引腳。
開始、暫停、清零功能都有了,是不是很像秒表,呵呵。
定時器3的計數器為寄存器T3CNT,展示的當前的計數值,是只讀的。
定時器3的四種模式:
自由運行模式:從0x00開始在每個時鍾沿遞增,直到0xff,再回到0x00,再遞增,周而復始,當計數值到達0xff時,溢出中斷標志位TIMIF.T3OVFIF置1。
倒計數模式:T3CNT計數值裝入初值T3CC0,從T3CC0開始在每個時鍾沿遞減,直到0x00,定時器發生溢出中斷,溢出中斷標志位TIMIF.T3OVFIF置1。
注意:倒計數模式是一次事件的定時,什么意思呢?當TxCTL.START寫入1時,從T3CC0開始在每個時鍾沿遞減,到達0x00時TxCTL.START位變為0,如果需要再定時就需要繼續啟動START,即TxCTL.START置1.
定時器3的倒計數模式初始化程序:
1 /****************************************************************************** 2 *函 數 名:InitT3 3 *功 能:定時器3初始化 4 *入口參數:無 5 *出口參數:無 6 ******************************************************************************/ 7 void InitT3(void) 8 { 9 T3CTL = 0xed; //定時器3 128分頻,倒計數模式,溢出中斷使能,計數器清0 10 T3CC0 = 0x80; //定時器3通道0捕獲/比較值 11 IEN1 |= (1<<3); //定時器3中斷使能 12 EA = 1; //開總中斷 13 T3CTL |= 0x10; //啟動定時器3 14 }
中斷服務程序:實現LED燈閃爍功能。注意第12行,再次啟動定時器3,沒有這句,中斷程序只執行一次。另外10行和11行可以不要,因為中斷標志位會自動硬件清0,但是如果通過查詢方式實現定時器的功能時必須要軟件清0,為了保持一致,每次寫程序時,都軟件清0!
1 /****************************************************************************** 2 *函 數 名:Timer3_ISR 3 *功 能:定時器3中斷服務程序 4 *入口參數:無 5 *出口參數:無 6 ******************************************************************************/ 7 #pragma vector = T3_VECTOR 8 __interrupt void Timer3_ISR(void) 9 { 10 IRCON &= ~0x08; //定時器3中斷標志位清0 11 TIMIF &= ~0x01; //定時器3溢出中斷標志位清0 12 T3CTL |= 0x10; //再次啟動定時器3 13 if(count++ > 250) 14 { 15 count = 0; 16 LED1 = ~LED1; 17 } 18 }
模計數模式:從0x00開始在每個時鍾沿遞增,直到T3CC0,再回到0x00,再遞增,周而復始,如果計數值初值大於T3CC0,則計數值遞增到0xff,計數器溢出,溢出中斷標志位TIMIF.T3OVFIF置1。與定時器1一樣,使用定時器3的模模式必須要開啟通道0的輸出比較功能,注意兩點
1) 模模式需要開啟通道0的輸出比較模式,否則計數器到了0xFF時,才會產生溢出中斷,也就是說如果沒有設置通道0的輸出比較模式,計數器的值到了T3CC0設置的比較值后也不會產生溢出中斷。
2) T3的模模式不是普通的溢出中斷,和連續計數模式不同,它必須設置通道0的輸出比較功能,使能中斷時,也是使能通道0的輸出比較中斷屏蔽位。產生中斷時的中斷標志也是通道0的輸出比較中斷標志,而不是計數溢出標志。
正計數/倒計數模式:從0X00遞增到TxCC0里設置的值,然后遞減到0X00,溢出中斷標志位TIMIF.T3OVFIF置1。
注意:TIMIF.TxOVFIF 和 TIMIF.TxCHnIF不管中斷使能位(屏蔽位)是否為1,當定時器計數值溢出或通道0、1發生中斷都會置1,也就是說,TIMIF.TxOVFIF 和 TIMIF.TxCHnIF位置1不受是否開中斷影響。
但是,IRCON.T3IF 和IRCON.T4IF位必須在中斷使能位為1的情況下,發生中斷才會置1.定時器3和定時器4中斷使能有三個地方需要設置:IEN1.TxIEN 、 IEN0.EA、通道中斷使能TxCCTLn.IM
定時器3和定時器4沒有寄存器T3STAT和T4STAT
定時器3和定時器4的程序與定時器1的程序相似,詳見我的博客關於定時器1的介紹,感覺倒計數模式沒什么用,和模模式實現的功能是一樣的,區別只是一個正計數,一個倒計數,建議用模計數代替倒計數模式。這里給出定時器3模模式的程序,和定時器1一樣,需要設置設置通道0的輸出比較功能。
定時器3的模模式初始化程序:
1 /****************************************************************************** 2 *函 數 名:InitT3 3 *功 能:定時器3初始化 4 *入口參數:無 5 *出口參數:無 6 ******************************************************************************/ 7 void InitT3(void) 8 { 9 T3CTL = 0xee; //定時器3 128分頻,模計數器模式,溢出中斷使能,計數器清0 10 T3CCTL0 = 0x44; //通道0比較功能,並且開通道0中斷 11 T3CC0 = 0xff; //定時器3通道0捕獲/比較值 12 IEN1 |= (1<<3); //定時器3中斷使能 13 EA = 1; //開總中斷 14 T3CTL |= 0x10; //啟動定時器3 15 }
整個程序如下,實現功能:LED燈定時閃爍。
1 /****************************************************************************** 2 *文 件 名:Timer3.c 3 *作 者:陳照 4 *時 間:2015-05-15 5 *版 本:1.0 6 *描 述:定時器3模模式中斷 7 ******************************************************************************/ 8 #include <iocc2541.h> 9 10 typedef unsigned char uchar; 11 typedef unsigned int uint; 12 13 #define LED1 P1_0 14 uint count = 0; //定時器計數溢出次數 15 16 /**************************************************************** 17 *函 數 名:SysStartXOSC 18 *功 能:系統時鍾初始化 19 *入口參數:無 20 *出口參數:無 21 *****************************************************************/ 22 void SysStartXOSC(void) 23 { 24 SLEEPCMD &= ~0x04; // 啟動所有晶振 25 while (!(SLEEPSTA & 0x40)); // 等待晶振穩定 26 27 CLKCONCMD = (CLKCONCMD & 0x80) | 0x49; // 使用16M晶振作為主時鍾 28 while ((CLKCONSTA & ~0x80) != 0x49 ); // 等待主時鍾切換到16M晶振 29 30 CLKCONCMD = (CLKCONCMD & ~0x80) ; // 使用外部32K晶振作為休眠時鍾 31 while ( (CLKCONSTA & 0x80) != 0 ); // 等待睡眠時鍾切換到外部32K晶振 32 33 CLKCONCMD = (CLKCONCMD & 0x80) ; // 使用32M晶振作為主時鍾 34 while ( (CLKCONSTA & ~0x80) != 0 ); // 等待主時鍾切換到32M晶振 35 36 SLEEPCMD |= 0x04; // 關閉未使用的晶振 37 } 38 39 /****************************************************************************** 40 *函 數 名:InitLED 41 *功 能:LED口功能初始化 42 *入口參數:無 43 *出口參數:無 44 ******************************************************************************/ 45 void InitLED(uchar On_Off) 46 { 47 P1SEL &= ~0x01; //P1.0設置為通用I/O口 48 P1DIR |= 0x01; //P1.0設置為輸出 49 LED1 = On_Off; //P1.0亮滅初始化 50 } 51 52 /****************************************************************************** 53 *函 數 名:InitT3 54 *功 能:定時器3初始化 55 *入口參數:無 56 *出口參數:無 57 ******************************************************************************/ 58 void InitT3(void) 59 { 60 T3CTL = 0xee; //定時器3 128分頻,模計數器模式,溢出中斷使能,計數器清0 61 T3CCTL0 = 0x44; //通道0比較功能,並且開通道0中斷 62 T3CC0 = 0xff; //定時器3通道0捕獲/比較值 63 IEN1 |= (1<<3); //定時器3中斷使能 64 EA = 1; //開總中斷 65 T3CTL |= 0x10; //啟動定時器3 66 } 67 68 /****************************************************************************** 69 *函 數 名:Timer3_ISR 70 *功 能:定時器3中斷服務程序 71 *入口參數:無 72 *出口參數:無 73 ******************************************************************************/ 74 #pragma vector = T3_VECTOR 75 __interrupt void Timer3_ISR(void) 76 { 77 IRCON &= ~0x08; 78 TIMIF &= ~0x11; 79 if(count++ > 250) 80 { 81 count = 0; 82 LED1 = ~ LED1; 83 } 84 } 85 86 /****************************************************************************** 87 *程序入口函數 88 ******************************************************************************/ 89 int main(void) 90 { 91 SysStartXOSC(); //配置主時鍾為32MHz,定時器時鍾32MHz 92 InitLED(0); //LED初始化,熄滅LED1 93 InitT3(); //定時器3初始化 94 95 while(1); 96 }
在中斷服務程序里,中斷標志位,可以不軟件清除,經過實驗,把這兩句去掉,程序運行正常,但是為了嚴謹性,還是加上吧,畢竟軟件清除中斷標志位也不會影響什么,即使中斷標志位可以自動硬件清零。
IRCON &= ~0x08; TIMIF &= ~0x11;