一、基本概念
1、89C51有兩個計數器T0和T1,89C52還有一個T2。每個計數器都是由兩個8位的RAM 單元組成的,即每個計數器都是16 位的計數器,最大的計數容量是216=65536,記住是從0-65535。
2、提供給定時器的計數源又是從哪里來的呢?就是由單片機的晶振經過12 分頻后獲得的一個脈沖源。一個12M 的晶振,它提供給計數器的脈沖時間間隔是就是1us。
3、預置數計數法。如果每個脈沖是1微秒,則計滿65536個脈沖需時65.536毫秒。但是如果只需要10毫秒就可以了,怎么辦?只要在計數器里預先放進55536,這樣只需要計數65536-55536=10000次,也就是10毫秒了。
二、相關寄存器
特殊功能寄存器TMOD(89H)
用于T1
用于T0
GATE C/T M1
M0 GATE
C/T M1 M0
GATE:0用于內部脈沖;1用于外部脈沖。
C/T:0用于定時器;1用于計數器。
M1M0:工作方式
M1,M0 范圍
特性
0,0工作方式0 13位,8192次
為了和51 的前輩48系列兼容。
0,1工作方式1 16位,65536次
16位,其他特性與工作方式0相同,比較常用。
1,0工作方式2 8位,256次
自動再裝入預置數,預置數放在T0(或T1)
的高8位中,只有低8 位參與計數,通常用于
波特率發生器。
1,1工作方式3 8位,256次
TH0只能作為定時器用,TL0可作定時器或計數
器。溢出標記:TL0 還是用原來的T0的標記,
而TH0則借用T1的標記,因此只有在T1 以工
作方式2 運行時,才讓T0 工作于方式3。
特殊功能寄存器TCON(88H)
用于定時/計數器
用于中斷
TF1 TR1
TF0 TR0
IE1
IT1 IE0
IT0
TR0/TR1:定時器的開關。
TF0/TF1:計數溢出后由0變為1
IT0/IT1:定時器/計數器中斷允許位。
在今天的分享中我們學習下單片機/計數器的使用,在前面的分享中我們接觸到了單片機時鐘周期、機器周期和指令周期的概念,我們再溫習下:
1時鐘周期 = 1/晶振頻率M
1機器周期 = 12(51系列為12時鐘周期,有的改進型單片機是1時鐘周期)×時鐘周期=12(1)×(1/晶振頻率M)=1us(1/12us,如采用12M晶體)。
如果12MHZ晶振工作在51單片機12T模式下,需要使用定時器進行50ms定時操作,定時器工作在方式1,那么我們該怎樣編寫程序呢?
我們知道:
12M的晶振每秒(s)可產生1M(106us)個機器周期。
50ms就需要50×1000us×1us(1機器周期)個機器周期=50000個機器周期。
如果定時器在方式1工作,是16位計數器,最大值為65536(216),也就是能進行最大65536次計數。而50ms定時操作需要50000個機器周期,1個機器周期=1us,所以需要50000次計數操作。
為了計數器定時器工作,需要預先填充定時器初值(初值=定時器計數最大計數次數-所需定時計數次數)。所以需設置定時器初值
15536=65536-50000,即3CB0H(10進制15536轉換成16進制數3CB0),所以TH0=0x3c,TL0=0xb0,高位就是
TH0的值,低位為TL0的值。
如果使用11.0592MHZ的晶振,其他條件不變,11.0592M的晶振每秒可產生0.9216M個機器周期,50ms就需要46080
個機器周期。定時器在方式1工作,是16位計數器,最大值為65536,所以需設置初值19456=65536-46080,即4C00H,所以
TH0=0x4c,TL0=0x00。
由上面的分析,我們可以得出推導16位定時器/計數器初值設定高8位TH0,低TL0的公式為:
TH0=(65536-所需計數次數)/256=初值/256;
TL0=(65536-所需技術次數)%6=初值%6;
公式中的256是什么意思呢?我們的計時器是兩個8位組成的,那么要把那些差值裝進這兩個8位,計數從低8位開始,那么低8位最多能裝256
個機器周期,那么256計滿了就用高8位的,就是說低8位滿一次高8位加1,那么高8位裝多少,低8位就滿了幾次,算法就是用差值除一下256取其整數,
剩下的,就是還剩了小于256次數的就放在低8位,就是差值的余數。
下面我們看個定時器/計數器0,產生定時中斷的例程。
晶振頻率12M,其程序如下:
#include<reg51.h>
void timer0_init()
{
TMOD =
0x01; //定時器在方式1工作,是16位計數器,最大值為65536
TL0 = 0xb0;
//給TL0賦計數初值0xb0
TH0 = 0x3c;
//給TH0賦計數初值0x3c
TR0 = 1;
//定時器開始計數
ET0 = 1;
//定時器中斷允許
EA = 1;
//開總中斷
}
void main()
{
timer0_init();
while(1);
}
void timer0() interrupt 1
{
TH0=(65536-50000)/256;
//在中斷處理函數中需要重新給TH0賦初值。
TL0=(65536-50000)%6;
//在中斷處理函數中需要重新給TL0賦初值。
加上我們希望的語句。
}
上面給大家看了一段例程,講的是如何用定時器/計數器0實現中斷。單片機一般還有一個定時器/計數器1,它的編程和定時器/計數器0差不多。
另外,單片機定時器/計數器的使用不單單體現在定時器中斷方面,但它們的使用都萬變不離其綜,大家掌握了一種用法,對于其它的應用也就不難掌握了。 |