以前學了好幾次單片機,都是半途而廢,這次要把基礎打好點才行。
話說定時器還是很重要的。。。
對51單片機來說,其實定時器和計數器是一樣的東西,下面把它們統稱為定時器了。
51單片機有兩個定時器,它們的核心是兩個16位的加1計數器T0和T1,它們又被分為兩個8位的計數器TH0,TL0,TH1,TL1。
當作為計數器使用時,計數脈沖來自外部引腳P3.4(T0)和P3.5(T1)。當該腳的輸入信號發生由高到低的負跳變時,讀數器TH、TL的值就加1。
定時器其實也是計數,只不過計數的脈沖來源的內部時鐘。
程序是怎樣知道定時器的時間到了呢?用中斷啦。。。
定時器使用的是加法計數,而且只在計數溢出時才申請中斷,因此,要實現自定義定時或計數,需要自己計算計數的起點,并將它們填到TH、TL中。
也就是說,如果我要記1000個時鐘脈沖,我就將TH和TL的值設到距離最大值還差1000的位置。
假設計數的最大值是MAX(工作模式不同,這個值不同),則起點X的計算方法如下:
在計數方式下,X=MAX-計數值
在定時方式下,X=MAX-定時值/T,其中T為單片機的機器周期。如當機器周期=0.5us時,如果定時器工作于模式0,MAX = 2^13 * 0.5us = 4.096ms;如果工作于模式1,則最大定時值為MAX = 2 ^ 16 * 0.5us = 32.768ms。
在注意的是,在溢出后,除了模式2之外,程序都要重新裝入初值!
使用定時器的步驟:
1. 指定工作模式,即TMOD寄存器;
2. 裝入初始值,即對TH和TL賦值;
3. 啟動定時器中斷,通過賦值IE和優先級寄存器IP來實現,如果不使用中斷,則忽略此步驟;
4. 啟動定時器,即置位TR0或TR1。
模式0:
此模式為13位計數器,使用TH及TL中的低5位組成,此模式主要是為了向前兼容而設計的;在此模式下,當TL的低5位溢出時,向TH進位,當TH溢出時,計數器清零,同時TF置1,另外發出中斷請求。
模式1:
此模式為16位計數器,使用TH和TL中的所有位,此模式方便計算初值,而模式0中要由TH和TL中的5位組成一個13位的數,麻煩。
模式2:
此模式是8位自動重新裝入的計數器,其中TH作為計數初值寄存器,初值在程序中設置,程序初始化時,TL=TH,當TL溢出時,自動設置TL=TH,重新計數,TF標志置1,TH中的數不受影響。溢出信號還將送到串行通信系統,產生串口通訊的波特率。
模式3:
此模式是將TL和TH分成兩個獨立的計數器。T1沒有模式3,只有T0有模式3。如果T0工作在方式3下,那么T1就只能工作在0、1、2方式下,因為TR1及TF1已經被T0借用。
可以通過TMOD和TCON兩個寄存器控制它們。
TMOD
---------------------------------------------------------
用于T1 | 用于T0
---------------------------------------------------------
GATE | C/T | M1 | M0 | GATE | C/T | M1 | M0 |
TCON
------------------------------------------------------------
用于定時/讀數器 | 用于中斷
------------------------------------------------------------
TF1 | TR1 | TF0 | TR0 | IE1 | IT1 | IE0 | IT0 |
------------------------------------------------------------
TF是溢出的標志,TR是運行控制位,當置TR0=1時,定時器1即啟動。
IT是外部中斷觸發方式選擇位,0是低電平觸發,1是負跳變觸發。
IE是外部中斷請求位。
定時/計數器有四種工作方式,TMOD中的M1和M0即為指定工作方式;
C/T決定是工作于定時還是計數方式;
GATE可控制定時器的啟動,當GATE=0時,定時器僅由TR控制,當GATE=1時,除TR置1外,還必須等待外部脈沖輸入端P3.4或P3.5有個高電平,定時器才能啟動。若外部輸入低電平,則定時器關閉,這樣可由外部控制定時器的啟停。
初值計算舉例(以T0為例):
模式0, 6MHz的晶振,單片機的機器周期為12/6MHz=2us=0.002ms,如果要定時1ms,則有算式:1ms = (2^13-X)*0.002,解出X=7692=0x1E0C,轉化為2進制為1111000001100,這里面低5位要放到TL中,即TL0=01100=0xC,其余放到TH中,即TH0=11110000=0xF0;
模式1, 12MHz的晶振,單片機的機器周期為12/12MHz=1us=0.001ms,如果要定時10ms,則有算式: 10ms=(2^16-X)*0.001,解出X=55536=0xD8F0,則TH0=0xD8,TL0=0xF0;
模式3, 6MHz的晶振,機器周期為2us=0.002ms,如果要定時200us,則有200=(2^8-X)*2,解出X = 156 = 0x9C, 則TL0 = 0x9C
程序舉例:
T0工作于方式1,定時時間50ms,輸出周期為1000ms的方波,晶振為11.0592MHz
機器周期為12/11.0592us,最大值為2^16=65536,X=0x4C00
程序如下:
#include "reg51.h"
sbit P0_1 = P0^1;
char i = 0;
void main()
{
TMOD = 0x01; //T0方式1
TL0 = 0x00; //TL0的初值
TH0 = 0x4C; //TH0的初值
ET0 = 1; //打開定時器0的中斷允許開關
EA = 1; //開中斷
TF0 = 0;
TR0 = 1;
while(1);
}
void Int_T0() interrupt 1 using 2
{
TL0 = 0x00; //重新裝入初值
TH0 = 0x4C;
i++;
if (i==10)
{
P0_1 = !P0_1;
i = 0;
}
}
下面這段中斷的程序還須進一步研究,呵呵
|