這篇文章是談談關於1937的定時器的,剛開始被晶振頻率、時鍾頻率、振盪周期、振盪頻率、指令周期、指令頻率等等的名詞繞暈了。先來解決這個問題。
晶振頻率是代表振盪器的頻率,說的是晶振這個器件的頻率,因為一個單片機有內部外部晶振,比如你選擇了內部晶振,那么這個晶振的頻率就是你單片機的時鍾頻率,
振盪頻率和晶振頻率說的是一回事。振盪周期是1/(晶振頻率),T = 1/f 嘛。指令周期這個根據單片機的不同會不同,8位的PIC單片機(PIC10/12/16/18系列)是4個時鍾周期為一個指令周期。16位的PIC24單片機和dsPIC數字處理芯片和32位PIC32處理器是2個時鍾周期為一個指令周期。(以上關於指令周期的內容是百度到的,內容較可靠http://zhidao.baidu.com/link?url=uEnsn0C-bb-xdDNG_qEI0HmhIpoDNVc4d2lheztGKsQMpflMcpbnlWAGdXyeMz05fJAhXardxSrQDLHEdDrCx_)
理清上面的內容,就開始我們的正題。
TIMER0
/*
* TIMER0是一個8位定時器/計數器,有8位預分頻器(1:2-1:256),是所有定時器中預分頻最大的(可以這么說吧。。)
* 可編程的內外部時鍾源,可編程的外部時鍾邊沿選擇。
* 溢出時中斷
* TMR0可用於門控Timer1(還沒試過。。)
* 休眠模式中無法工作
* 此時選擇內部晶振8mhz,預分頻1:16,每2.04s燈狀態改變一次。TMR0從0計數到255
* 所以是255*16*1000/(Fosc(晶振頻率)/4) = 2.04
*/
這些是我寫在單片機程序開頭的內容,大致描述了TIMER0模塊,接下來告訴你們怎么使用它吧。(只寫關於初始化TIMER0的,CPU的初始化之類的略過)
1.先初始化時鍾源,在OSSCON寄存器中設置SCS位來選擇內部振盪模塊,IRCF設置內部頻率
2.現在初始化TIMER0,還是一樣,先選擇時鍾源,TMR0CS = 0;表示內部指令周期(注意是指令周期,fosc/4)
3.選擇預分頻,PSA位來選擇需不需要預分頻,PS<2:0>來設置預分頻
4.時鍾都和中斷有關,所以這里要允許有效中斷,GIE = 1;
5.然后允許TIM0IE中斷,TIM0IE = 1;
6.最后是溢出中斷標志位,TMR0IF = 0;表示未溢出,當定時器開啟的時候TMRO就會開始計數,一個指令周期加一,從0-255.當加到255后再加一使TMR0IF = 1;計數會跳到0繼續。
7.TMR0可以不用使能,自動計數,但因為執行時會延遲2個指令周期,所以TMR0的初值需要設置,來抵消這個延遲。
還是上代碼吧,哈哈嘞
1 void InitTime(); 2 void Init_fosc(); //設置內部振盪器,不過好像沒用。。 3 4 unsigned int count = 0; 5 6 int main(int argc, char** argv) 7 { 8 InitCPU(); 9 Init_fosc(); 10 InitTime(); 11 TRISC = 0x00; 12 // LATC = 0x00; 13 while(1); 14 return (EXIT_SUCCESS); 15 } 16 17 void InitTime() 18 { 19 // INTEDG = 0; //bit6 中斷邊沿選擇位,1 = 上升沿,0 = 下降沿 20 TMR0CS = 0; //bit5 Timer0時鍾源選擇位,0 = 內部指令周期時鍾(Fosc/4) 21 TMR0SE = 0; //bit4 Timer0時鍾源邊沿選擇位,1 = 在T0CKI引腳電平下降沿時遞增,0 = 上升沿時遞增 22 PSA = 0; //bit3 預分頻器分配位,1 = 不分給Timer0,0 = 預分頻器分給Timer0 23 PS0 = 1; 24 PS1 = 1; 25 PS2 = 0; //1:16 26 //PS<2:0>,預分頻器分頻比選擇位 27 GIE = 1; //允許所有有效中斷 28 PEIE = 0; //禁止所有外設中斷,有待考慮 29 TMR0IE = 1; //允許TMR0中斷 30 TMR0IF = 0; //溢出中斷標志位,未溢出 31 TMR0 = 1; 32 } 33 34 void Init_fosc() 35 { 36 // OSCCON = 0x6a; 下面的設置為設置內部振盪器頻率的 37 SCS0 = 1; 38 SCS1 = 0; //1x內部振盪器模塊 39 IRCF0 = 0; 40 IRCF1 = 1; 41 IRCF2 = 1; 42 IRCF3 = 0; //1101 = 250kHz 43 44 } 45 46 void interrupt ISR() 47 { 48 TMR0 = 1; 49 count++; 50 if(count ==10) 51 { 52 LATC = ~LATC; 53 count = 0; 54 } 55 TMR0IF = 0; 56 }
TMR0是不用使能的,其他的時候也許不用管他,就算它在計數,沒有允許它中斷(TMR0IE位),也是沒啥用的啊,殘念ね。。
接下來是TIMER1模塊,TIMER1模塊的特殊的地方是帶門控,是16位的定時計數器,有專用32kHz的振盪器電路。
這次先上代碼吧,感覺會更有條理些
1 void InitTime(); 2 void Init_fosc(); //設置內部振盪器,不過好像沒用。。 3 4 unsigned int count = 0; 5 6 int main(int argc, char** argv) 7 { 8 InitCPU(); 9 Init_fosc(); 10 InitTime(); 11 TRISC = 0x00; 12 // LATC = 0x00; 13 while(1); 14 return (EXIT_SUCCESS); 15 } 16 17 void InitTime() 18 { 19 // INTEDG = 0; //bit6 中斷邊沿選擇位,1 = 上升沿,0 = 下降沿 20 TMR0CS = 0; //bit5 Timer0時鍾源選擇位,0 = 內部指令周期時鍾(Fosc/4) 21 TMR0SE = 0; //bit4 Timer0時鍾源邊沿選擇位,1 = 在T0CKI引腳電平下降沿時遞增,0 = 上升沿時遞增 22 PSA = 0; //bit3 預分頻器分配位,1 = 不分給Timer0,0 = 預分頻器分給Timer0 23 PS0 = 1; 24 PS1 = 1; 25 PS2 = 0; //1:16 26 //PS<2:0>,預分頻器分頻比選擇位 27 GIE = 1; //允許所有有效中斷 28 PEIE = 0; //禁止所有外設中斷,有待考慮 29 TMR0IE = 1; //允許TMR0中斷 30 TMR0IF = 0; //溢出中斷標志位,未溢出 31 TMR0 = 1; 32 } 33 34 void Init_fosc() 35 { 36 // OSCCON = 0x6a; 下面的設置為設置內部振盪器頻率的 37 SCS0 = 1; 38 SCS1 = 0; //1x內部振盪器模塊 39 IRCF0 = 0; 40 IRCF1 = 1; 41 IRCF2 = 1; 42 IRCF3 = 0; //1101 = 250kHz 43 44 } 45 46 void interrupt ISR() 47 { 48 TMR0 = 1; 49 count++; 50 if(count ==10) 51 { 52 LATC = ~LATC; 53 count = 0; 54 } 55 TMR0IF = 0; 56 }
再來寫下總結的步驟
1.初始時鍾源
2.在Timer1的初始中先選擇時鍾源
3.設置預分頻
4.允許中斷和溢出位清零
5.使能Timer1
雖然看起來簡單,但是Timer1的功能比Timer0多,好些自己也沒有用到過,有一個注意的地方,TMR1H和TMR1L的初值設定最好剛剛把延時拿回來就行了。使能也應該放最后,剛好需要起振時間
最后最后,1937里面最多的定時器,數量超過我的想象,竟然多達,,竟然擁有3個!!何等的數量啊。。。。。好了,不裝怪了,他是TIMER2/4/6葫蘆三兄弟。
/*1937共含有3個相同的Timer2模塊,分別為Timer2、Timer4、Timer6
* 8位定時器和周期寄存器(TMRx和PRx)
* 可讀寫、預分頻(1:1:4:16:64)后分頻(1:1至1:16)
* TMRx與相應的PRx分別匹配時中斷、可選擇作為MSSP模塊的移位時鍾(僅Timer2)
*/
看到了嗎,這里是TMRx與相應的PRx分別匹配時中斷,不像前面兩個あほ(TIMER0與TIMER1)是溢出中斷
還是先上代碼吧,,,這里直接上初始化Timer2/4/6的程序了,
1 void Init_Timer2() //時鍾是系統指令時鍾 Fosc/4,沿邊沿遞增計數。 2 { 3 T2CON = 0x0d; //設置后分頻,使能Timer2,設置預分頻 4 TMR2 = 0; 5 PR2 = 100; //TMR2與PR2的值越相近,進入中斷越快 6 GIE = 1; //允許所有有效中斷,!!!!實驗無此語句能否運作 7 PEIE = 1; 8 TMR2IE = 1; //允許Timer2中斷 9 TMR2IF = 0; //溢出標志位,未溢出 10 }
TIMER2/4/6是無法自己選擇內外部時鍾的,系統選什么他就得選什么,作為對比,TIMER0和TIMER1是可以自己選的,素晴らしい!
所有的時鍾設置總結來說,必須考慮的要素有以下幾條
-
- 1.設置時鍾,系統時鍾和定時器要用的時鍾(TIMER0和TIMER1是可以選的)
- 2.預分頻及后分頻,所有時鍾里TIMER0的預分頻最大(1:2-1:256),TIMER2/4/6既有預分頻又有后分頻
- 3.TMRxIE、PEIE、GIE(允許TIMERx中斷、允許外設中斷、允許所有有效中斷),這三個的賦值。除PEIE在TIMER0中沒有也可以運作外,其他兩個在每個定時器中必須有
- 4.TMRxIF,溢出的標志位,一般會在中斷程序里面清零,所以在初始化里面可有可無。
- 5.計數的設置TIMER0中的TMRO(0-255),TIMER1中的TMR1H和TMR1L,TIMER2/4/6中的TMRx(0-PRx),PRx(0-255)