【單片機】【PIC16F1937】之定時器


這篇文章是談談關於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)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM