找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 14822|回復(fù): 1
打印 上一主題 下一主題
收起左側(cè)

51單片機定時器的原理與使用(22頁詳細的word格式教程下載)

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:325686 發(fā)表于 2018-5-9 10:08 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
定時器是單片機的重要功能模塊之一,在檢測、控制領(lǐng)域有廣泛應(yīng)用。定時器常用作定時時鐘,以實現(xiàn)定時檢測,定時響應(yīng)、定時控制,并且可以產(chǎn)生ms寬的脈沖信號,驅(qū)動步進電機。定時和計數(shù)的最終功能都是通過計數(shù)實現(xiàn),若計數(shù)的事件源是周期固定的脈沖則可實現(xiàn)定時功能,否則只能實現(xiàn)計數(shù)功能。因此可以將定時和計數(shù)功能全由一個部件實現(xiàn)。通過下圖可以簡單分析定時器的結(jié)構(gòu)與工作原理。
一、定時器

1、51單片機計數(shù)器的脈沖輸入腳。主要的脈沖輸入腳有Px,y, 也指對應(yīng)T0的P3.4和對應(yīng)T1的P3.5,主要用來檢測片外來的脈沖。而引腳18和19則對應(yīng)著晶振的輸入脈沖,脈沖的頻率和周期為

F = f/12 = 11.0592M/12 = 0.9216MHZ      T = 1/F = 1.085us
2、定時器有兩種工作模式,分別為計數(shù)模式和定時模式。對Px,y的輸入脈沖進行計數(shù)為計數(shù)模式。定時模式,則是對MCU的主時鐘經(jīng)過12分頻后計數(shù)。因為主時鐘是相對穩(wěn)定的,所以可以通過計數(shù)值推算出計數(shù)所經(jīng)過的時間。
3、51計數(shù)器的計數(shù)值存放于特殊功能寄存器中。T0(TL0-0x8A, TH0-0x8C), T1(TL1-0x8B, TH1-0x8D)
4、TLx與THx之間的搭配關(guān)系
1)、TLx與THx之間32進制。即當(dāng)TLx計到32個脈沖時,TLx歸0同時THx進1。這也稱為方式0。
        2)、TLx與THx之間256進制。即當(dāng)TLx計到256個脈沖時,TLx歸0同時THx進1。這也稱為方式1。在方式1時,最多計65536個脈沖產(chǎn)生溢出。在主頻為11.0592M時,每計一個脈沖為1.085us,所以溢出一次的時間為1.085usx65536=71.1ms。
3)、THx用于存放TLx溢出后,TLx下次計數(shù)的起點。這也稱為方式2。
4)、THx與TLx分別獨立對自己的輸入脈沖計數(shù)。這也稱為方式3。
5、定時器初始化
1)、確定定時器的計數(shù)模式。
2)、確定TLx與THx之間的搭配關(guān)系。
3)、確定計數(shù)起點值。即TLx與THx的初值。
4)、是否開始計數(shù)。TRx
(1)和(2)可以由工作方式寄存器TMOD來設(shè)定,TMOD用于設(shè)置定時/計數(shù)器的工作方式,低四位用于T0,高四位用于T1。其格式如下:
GATE:門控位,用于設(shè)置計數(shù)器計數(shù)與否,是否受P3.2或P3.3電壓狀態(tài)的影響。GATE=0時,表示計數(shù)器計數(shù)與否與兩端口電壓狀態(tài)無關(guān);GATA=1時,計數(shù)器是否計數(shù)要參考引腳的狀態(tài),即P3.2為高時T0才計數(shù),P3.3為高時T1才計數(shù)。
C/T:定時/計數(shù)模式選擇位。      =0為定時模式;    =1為計數(shù)模式。
M1M0:工作方式設(shè)置位。定時/計數(shù)器有四種工作方式,由M1M0進行設(shè)置。
6、計數(shù)器的溢出
計數(shù)器溢出后,THx與TLx都歸0。并將特殊功能區(qū)中對應(yīng)的溢出標志位TFx寫為1。
好了,理論就講述到這。現(xiàn)在我們通過一些實驗來看看怎么使用定時器。
實驗一、P1口連接的8個LED燈以1秒鐘的頻率閃爍。
首先上代碼:
  1. #include "reg51.h"  
  2.        char c;  
  3.          
  4.        void Timer0_Init() //初始化定時器  
  5.        {  
  6.           TMOD = 0x01;     //  
  7.           TH0 = 0;  
  8.           TL0 = 0;   //定時器的計數(shù)起點為0  
  9.           TR0 = 1; //啟動定時器0  
  10.    }  
  11.      
  12.    void main()  
  13.    {  
  14.        Timer0_Init();  
  15.        while(1)  
  16.        {  
  17.            if(TF0 == 1) //檢測定時器0是否溢出,每到65535次  
  18.            {  
  19.                TF0=0;  
  20.                c++;  
  21.                if(c==14)    //71ms乘以14為1s  
  22.                {  
  23.                    c=0;  
  24.                    P1=~P1;  
  25.                }  
  26.            }  
  27.        }  
  28.    }  
復(fù)制代碼

上述代碼的思路是每計算14個溢出,則翻轉(zhuǎn)P1口狀態(tài)。產(chǎn)生一個溢出的時間是71.1ms,14個則約為1s。

  1. #include "reg51.h"  
  2.        sbit LD1 = P1^0;  
  3.          
  4.        void Timer0_Init() //初始化定時器  
  5.        {  
  6.           TMOD = 0x01;     //  
  7.           TH0 = 0;  
  8.           TL0 = 0;   //定時器的計數(shù)起點為0  
  9.           TR0 = 1; //啟動定時器0  
  10.    }  
  11.      
  12.    void Timer0_Overflow()  //處理定時器0的溢出事件  
  13.    {  
  14.        static char c;  
  15.        if(TF0 == 1) //檢測定時器0是否溢出,每到65535次  
  16.            {  
  17.                TF0=0;  
  18.                c++;  
  19.                if(c==14)    //71ms乘以14為1s  
  20.                {  
  21.                    c=0;  
  22.                    LD1=!LD1;  
  23.                }  
  24.            }     
  25.    }  
  26.      
  27.    void main()  
  28.    {  
  29.        Timer0_Init();    //初始化定時器0  
  30.        while(1)  
  31.        {  
  32.            Timer0_Overflow();  
  33.        }  
  34.    }  
復(fù)制代碼


相比于上個例子,這里有兩個區(qū)別,首先是將timer0的溢出事件作為子函數(shù)單獨出來,其次是注意翻轉(zhuǎn)一個led燈時候用的是“!”。

例子三、讓連接到P1口的LED1和LED8燈每1秒鐘閃爍。

  1. #include "reg51.h"  
  2.          
  3.        void Timer0_Init() //初始化定時器  
  4.          
  5.        {  
  6.           TMOD |= 0x01;        //定時器0方式1,計數(shù)與否不受P3.2的影響  
  7.           TH0 = 0;  
  8.           TL0 = 0;   //定時器的計數(shù)起點為0  
  9.           TR0 = 1; //啟動定時器0  
  10.    }  
  11.      
  12.    void Timer0_Overflow()  //´處理定時器0的溢出事件  
  13.    {  
  14.        static char c;  
  15.        if(TF0 == 1) //檢測定時器0是否溢出,每到65535次  
  16.            {  
  17.                TF0=0;  
  18.                c++;  
  19.                if(c==14)    //71ms乘以14為1s  
  20.                {  
  21.                    c=0;  
  22.                    P1 ^= (1<<0);//LD1=!LD1;  
  23.                }  
  24.            }     
  25.    }  
  26.      
  27.    void Timer1_Init()  
  28.    {  
  29.        TMOD|=0x10; //定時器1方式1,計數(shù)與否不受P3.3的影響  
  30.        TH1=0;  
  31.        TL1=0; //定時器1的計數(shù)起點為0  
  32.        TR1=1; //啟動定時器1  
  33.    }  
  34.      
  35.    void Timer1_Overflow()  //處理定時器1的溢出事件  
  36.    {  
  37.        static char c;  
  38.        if(TF1==1) //軟件查詢,主循環(huán)每跑完一圈才會到這里。  
  39.        {  
  40.            TF1=0;  
  41.            c++;  
  42.            if(c==14)  
  43.            {  
  44.                c=0;  
  45.                P1 ^= (1<<7);//LD8=!LD8;  
  46.            }  
  47.        }     
  48.    }  
  49.      
  50.    void main()  
  51.    {  
  52.        Timer0_Init();    //初始化定時器0  
  53.        Timer1_Init();     //初始化定時器1  
  54.        while(1)  
  55.        {  
  56.            Timer0_Overflow();  
  57.            Timer1_Overflow();  
  58.        }  
  59.    }  
復(fù)制代碼


相較于例二,例子三有幾個點值得注意:

1、TMOD初始化為什么采用TMOD |= 0x01或0x10的形式?

      首先如果在定時器初始化函數(shù)中采用TMOD = 0x01和TMOD = 0x10,那么將造成LD1閃爍比LD8閃爍快8倍。分析一下,從main函數(shù)開始執(zhí)行,先是初始化timer0,這時候定時器1設(shè)置為工作方式1。接著程序執(zhí)行到Timer1_Init(),這時候TMOD=00010000,即選定了timer1在工作方式1,但同時timer0重新配置為工作方式0, 也就是32進制,所以產(chǎn)生快8倍現(xiàn)象。

     那為什么用|這個符號就可以做到互不影響呢?|是或運算符,即有1出1,全0出0。什么意思呢?舉個例子,a是11110000,b是10101010,那么a|b就是11111010。通過引入這個符號,可以實現(xiàn)tmod對兩個定時器的獨立操作。



2、為什么使用P1 ^= (1<<0)可以實現(xiàn)LD1的控制呢?

      首先解釋下^這個符號。^稱為異或運算符,相同出0,不同出1。舉個例子,a是11110000,b是10101010,那么a^b就是01011010。

      然后再來分析 x ^= (1<<i), 假設(shè)x為10101010,當(dāng)i為1時, (1<<i)為00000010,那么x^ (1<<i)=10101010^00000010=10101000。當(dāng)i為2時,(1<<i)為00000100,那么x^ (1<<i)=10101010^00000100=10101110,以此類推。我們發(fā)現(xiàn),x ^= (1<<i)是在將x的第i位翻轉(zhuǎn)而同時不影響其他位。

     因此P1 ^= (1<<0)實際是在翻轉(zhuǎn)P0口第一位的值,因此也就是在閃爍LD1燈。



上面三個例子實際都是采用了軟件查詢法。即main函數(shù)會每次進入到溢出事件函數(shù)里去判斷TF0或1是否等于1,這樣就浪費了大量CPU時間。同時,實時性差,假如在執(zhí)行Timer0_Overflow()的時候timer1也溢出了,這時候timer1的溢出事件就沒有及時處理。因此下面我們要引入中斷系統(tǒng)。



二、中斷系統(tǒng)

中斷系統(tǒng)是一套硬件電路,它可以在每個機器周期對所有的外設(shè)的標志位作查詢。相比于前面的軟件查詢(if(xx==1)),中斷系統(tǒng)也可以叫做硬件查詢。51的中斷系統(tǒng)可查詢以下6個標志位。

IE0(TCON.1),外部中斷0中斷請求標志位。

IT1(TCON.2),外部中斷1觸發(fā)方式控制位。

IE1(TCON.3),外部中斷1中斷請求標志位。

TF0(TCON.5),定時/計數(shù)器T0溢出中斷請求標志位。

TF1(TCON.7),定時/計數(shù)器T1溢出中斷請求標志位。      

RI(SCON.0)或TI(SCON.1),串行口中斷請求標志。當(dāng)串行口接收完一幀串行數(shù)據(jù)時置位RI或當(dāng)串行口發(fā)送完一幀串行數(shù)據(jù)時置位TI,向CPU申請中斷。

當(dāng)中斷系統(tǒng)查詢到外設(shè)的標志位變?yōu)?時,中斷系統(tǒng)可暫停當(dāng)前的主循環(huán),并且將程序跳轉(zhuǎn)到用戶預(yù)先指定的函數(shù)中執(zhí)行。要啟動中斷系統(tǒng),必須先進行中斷初始化,其流程如下:

a、是否要查詢外設(shè)標志(EA=0或EA=1,EA 也叫 CPU中斷允許(總允許)位)

b、查詢到標志1,是否要跳程序

c、跳轉(zhuǎn)的目標函數(shù),即中斷服務(wù)子函數(shù)

所以在使用定時器中斷時,我們只需要首先初始化中斷系統(tǒng),開啟總中斷(相當(dāng)于總開關(guān)),開啟定時器對應(yīng)的控制位(相當(dāng)于支路開關(guān)),再初始化定時器即可。中斷系統(tǒng)作為單片機的外設(shè),只有在某個中斷產(chǎn)生時才會打斷主循環(huán),并由相應(yīng)的中斷號引入到相應(yīng)的中斷服務(wù)子函數(shù)。下圖是6個中斷標志位的信息。



實驗四、使用中斷系統(tǒng)實現(xiàn)LD1燈每1秒鐘閃爍。

  1. #include "reg51.h"  
  2.          
  3.        void Timer0_Init()  
  4.        {  
  5.            TMOD|=0x01;  
  6.            TH0=56320/256;   //計數(shù)起點為56320 ==10ms溢出一次  
  7.            TL0=56320%256;  
  8.            TR0=1;  
  9.        }  
  10.      
  11.    void Timer1_Init()  
  12.    {  
  13.          
  14.    }  
  15.      
  16.    void ISR_Init()    //初始化中斷系統(tǒng)  
  17.    {  
  18.        EA=1; //啟動中斷系統(tǒng)  
  19.        EX0=0; //-->IE0  
  20.        ET0=1; //-->TF0 控制位置1,表明當(dāng)TF0置1時,中斷系統(tǒng)將介入   
  21.        EX1=0; //-->IE1  
  22.        ET1=0; //-->TF1  
  23.        ES=0; //-->RI,TI  
  24.      
  25.    }  
  26.      
  27.    //以下中斷服務(wù)子程序,我們希望中斷系統(tǒng)來調(diào)用,而不是我們在main函數(shù)里面調(diào)用,因此使用interrupt. */  
  28.      
  29.    void IE0_isr() interrupt 0  
  30.    {  
  31.      
  32.    }  
  33.      
  34.    /*void TF0_isr()    interrupt 1  //71.1ms 進入一次,但如果要求10MS進來一次呢?
  35.    {
  36.        static char c;
  37.        c++;
  38.        if(c==14)
  39.        {
  40.            P1^=(1<<0);
  41.            c=0;
  42.        }
  43.    }
  44.    */  
  45.    void TF0_isr()  interrupt 1  //10ms 進入一次  
  46.    {  
  47.        static char c;  
  48.        TH0=56320/256;   //重裝初值  
  49.        TL0=56320%256;  
  50.        c++;  
  51.        if(c==100)  
  52.        {  
  53.            P1^=(1<<0);  
  54.            c=0;  
  55.        }  
  56.    }  
  57.      
  58.    void IE1_isr()  interrupt 2  
  59.    {  
  60.      
  61.    }  
  62.      
  63.    void TF1_isr() interrupt 3  
  64.    {  
  65.          
  66.    }  
  67.      
  68.    void RI_TI_isr() interrupt 4  
  69.    {  
  70.      
  71.    }  
  72.      
  73.    void main()  
  74.    {  
  75.         Timer0_Init();  
  76.         Timer1_Init();  
  77.         ISR_Init();  
  78.      
  79.         while(1)  
  80.         {  
  81.             //...  
  82.             //發(fā)現(xiàn)溢出后,中斷系統(tǒng)根據(jù)中斷號尋找中斷子服務(wù)函數(shù),并強行暫停主循環(huán)并進入子函數(shù)  
  83.             //...  
  84.         }  
  85.    }  
復(fù)制代碼

顯然使用中斷系統(tǒng)查詢得到的1s更為精確。因為中斷系統(tǒng)獨立于main函數(shù)運行。另外本程序還預(yù)裝了timer0的初值,這樣的話就可以實現(xiàn)比71ms更小的時間片,比如要求10ms就進入中斷。關(guān)于初值的設(shè)定,請參考下圖。

實驗五、用定時器實現(xiàn)數(shù)碼管顯示1234。
  1. //數(shù)碼管的定時掃描,每5ms顯示一個數(shù)碼管,也就是說相同的數(shù)碼管,每20ms會被重新裝入同樣的數(shù)值,根據(jù)人眼的延遲效應(yīng),人眼觀測到的數(shù)碼管上的數(shù)值是靜態(tài)的。  
  2.         #include "reg51.h"  
  3.         unsigned int count;  
  4.         extern void load_smg();  
  5.         void Timer0_Init()  
  6.         {  
  7.            TMOD|=0X01;  
  8.            TH0=60928/256;  
  9.            TL0=60928%256;//每5ms進入一次中斷  
  10.        TR0=1;  
  11.     }  
  12.      
  13.    void isr_Init()  
  14.     {  
  15.        EA=1;  
  16.        ET0=1; //TF0 如果這個標志為1,進入中斷子函數(shù)  
  17.     }  
  18.      
  19.     void TF0_isr() interrupt 1  
  20.     {  
  21.        TH0=60928/256;  
  22.        TL0=60928%256;//重裝初值  
  23.        load_smg();  
  24.     }  
  25.      
  26.     void main()  
  27.     {  
  28.        Timer0_Init();  
  29.        isr_Init();  
  30.        while(1)  
  31.        {  
  32.          
  33.        }  
  34.      
  35.     }  
  36.      
  37.     #include "reg51.h"   
  38.      //char seg[10]={0xC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90};  
  39.     code char seg[10]={0xC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90};  
  40.     char smgbuf[4]={1,2,3,4}; //從RAM的smgbuf這個地址開始連續(xù)存放4個數(shù),并且每個數(shù)占一個單元。  
  41.     extern unsigned int count; //外部申明,表示并不在這里申明  
  42.      
  43.    void fill_smgbuf() //向LED緩沖區(qū)填充數(shù)據(jù)  
  44.    {  
  45.        smgbuf[0]=count/1000;  //千位  
  46.        smgbuf[1]=(count%1000)/100;  //百位  
  47.        smgbuf[2]=((count%1000)%100)/10;   //十位  
  48.        smgbuf[3]=((count%1000)%100)%10;   //個位  
  49.    }  
  50.      
  51.    void load_smg()   //將數(shù)碼管顯示緩沖區(qū)的數(shù)據(jù),顯示到數(shù)碼管上  
  52.     {  
  53.        static char i;  
  54.        fill_smgbuf();  
  55.        i++;  
  56.        if(i>=4)  
  57.        {  
  58.            i=0;  
  59.        }  
  60.        P0=0xFF;   //消除上一個循環(huán)的影子  
  61.        P2 = ~(1<<i);  
  62.        P0 = seg[smgbuf[i]];      
  63.     }  
復(fù)制代碼

實驗六、實現(xiàn)按鈕控制數(shù)碼管上的數(shù)值加1或減1,并且當(dāng)按住按鈕不放時,能實現(xiàn)快速的增減。

這里的關(guān)鍵點在于如何實現(xiàn)快速增減,具體請詳細分析代碼。代碼鏈接點擊打開鏈接

https://zhidao.baidu.com/question/561457023576622684.html

單片機中TCON和TMOD寄存器,無論是匯編程序還是C語言程序,都可以直接賦值。具體賦值多少,根據(jù)以上兩寄存器各位具體功能確定。

https://blog.csdn.net/zn2016/article/details/53353818

51定時器使用

2016年11月26日 18:56:03

閱讀數(shù):1020

1.設(shè)置特殊功能寄存器TMOD,配置好工作模式。
TMOD中M0/M1的配置決定定時器(0或1)的工作模式。
M1  = 0,M0 = 0,工作模式0,由THn的8位和TLn的5位組成一個13位的定時器。
M1 = 0,M0 = 1,工作模式1,由THn和TLn組成1個16位的定時器。
M1 = 1,M0 = 0,工作模式2,8位自動重裝模式,定時器溢出后由THn重裝的TLn中。
M1 = 1,M0 = 1,工作模式3,禁用定時器1,定時器0變成兩個8位的定時器。
2.設(shè)置計數(shù)寄存器TH0,TL0的初值。
3.設(shè)置TCON,通過TR0置1,來讓定時器開始計數(shù)。
4.判斷TCON寄存器的TF0位,檢測定時器是否溢出。
注意:定時器計數(shù)溢出后,TF0會置位,如果沒有開定時器中斷則需要軟件清零TF0位。如果開定時器中斷則TF0位由硬件清理。謹記:定時器溢出后給TH0,TL0 重裝載值。
定時器在每一個機器周期計數(shù)向上加1。


完整的Word格式文檔51黑下載地址:

51單片機定時器的原理與使用.docx (1.34 MB, 下載次數(shù): 52)



評分

參與人數(shù) 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享淘帖 頂2 踩
回復(fù)

使用道具 舉報

沙發(fā)
ID:128463 發(fā)表于 2019-3-30 17:16 | 只看該作者
xiexie!!!
回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復(fù) 返回頂部 返回列表