基於單片機定時器/計數器的時鐘設計以及計數設計
第一部分 前言
本次單片機基礎實驗將會通過在Proteus軟件中畫原理圖,然後Keil軟件下編寫源程序並編譯形成可執行文件.hex,下載源程序,進行Protues和Keil的聯合仿真運行,最終對單片機仿真有初步的認識。 通過本篇文章定時器/計數器T0、T1的工作方式選擇和編程方法。學習Proteus瞭解定時器/計數器中斷服務程序的設計方法以下是本篇文章正文內容,所設計的案例可供參考
第二部分 定時器/計數器的原理
MCS-51定時器/計數器的結構
MCS-51單片機根據不同型號,其片內定時器/計數器數目不同。8051單片機有兩個16位定時器/計數器寄存器:Timer0(T0定時器)與Timer1(T1定時器1)。8052除這兩個定時器/計數器外還增加了1個Timer2(T2定時器),而這3個都可設置爲定時器或事件計數器。當其作爲“定時器”功能時,它是對標準時鍾計數,每個時鐘週期寄存器自動增1。由於MCS-51單片機的一個機器週期由12個振盪器週期組成,計數速率是振盪器頻率的1/12。作爲“計數器”功能,寄存器在響應相應的外部輸入引腳T0、T1或T2(在8052中)由1至0的轉變而增1。不論是“定時器”還是外部事件“計數器”,其工作原理是一樣的,即定時器/計數器電路中的內部計數器從某一預定值(此值是可編程的)開始計數,當累計到最大值時產生溢出,並同時會建立一個相應的溢出標誌(即中斷標誌位)。除了“定時器”或“計數器”選擇外,定時器0與定時器1有4種工作方式需要選擇。在8052單片機中的定時器T2有3種操作方式:“捕獲”、“自動重裝入”與“波特率生成器”。下面主要以AT89C51單片機爲例講解定時器/計數器的基本結構。
AT89C51單片機片內定時器/計數器的結構如圖1所示。定時器內部實質上是16位加法計數器,其控制電路受軟件控制。當用作定時器時,對機器週期計數,每過一個機器週期,計數器加1。由於每個機器週期包含12個振盪信號週期,所以加1計數器的計數頻率爲振盪器信號頻率的1/12。當用作計數器功能時,加1計數器的計數脈衝取自外部輸入端T0(P3.4)和T1(P3.5),只要這些引腳上有從“1”到“0”的負跳變,計數器就加1。CPU在每個機器週期的S5P2時刻對外部輸入狀態進行採樣,計數器加1的執行是在檢測到跳變後的下一個機器週期的S3P1時刻。由於需要兩個機器週期來識別一個從“1”到“0”的負跳變,所以最大計數頻率爲振盪信號頻率的1/24。而外部時鐘脈衝持續爲0和爲1的時間不能少於一個機器週期。
兩個可編程的16位定時器 /計數器T0 和 T1
- T0 = TH0(高8位) + TL0(低8位)
- T1 = TH1(高8位) + TL1(低8位)
定時器/計數器相關特殊功能寄存器
- TMOD:控制定時器/計數器的工作方式
- TCON:控制定時器/計數器的運行
- IE、IP:定時器/計數器的中斷控制
1. TMOD
TMOD用來選擇定時器/計數器的工作模式和工作方式,它的字節地址是89H,但該寄存器不能進行位尋址。
- GATE=0,運行控制位 TR0/TR1(=1) 控制 T0/T1 啓動;
- GATE=1,INT0/1 (=1) 及運行控制位TR0/TR1(=1)控制T0/T1啓動,可用於外部脈衝寬度測量
- C/T=0,用作定時器(定時功能通過計數實現,計數脈衝來自內部系統時鐘輸入,一個機器週期產生一個計數脈衝);
- C/T=1,用作計數器(對外部脈衝計數,外部輸入脈衝發送負跳
變時加1)
T0模式
M1 | M0 | 功能 |
---|---|---|
0 | 0 | 13 位定時器/ 計數器,TL1 低5 位 + TH1全8 位,最大值爲8192 |
0 | 1 | 16 位定時器/ 計數器,TL1、TH1 全用,最大值65.536ms; |
1 | 0 | 8 位自動重裝載定時器,當溢出時將TH1 存放的值自動重裝入TL1,最大值爲256; |
1 | 1 | 定時器/ 計數器1 此時無效(停止計數) |
T1模式
M1 | M0 | 功能 |
---|---|---|
0 | 0 | 13 位定時器/ 計數器,TL1 低5 位 + TH1全8 位,最大值爲8192 |
0 | 1 | 16 位定時器/ 計數器,TL1、TH1 全用,最大值65.536ms; |
1 | 0 | 8 位自動重裝載定時器,當溢出時將TH1 存放的值自動重裝入TL1,最大值爲256; |
1 | 1 | 定時器0 爲雙8 位定時器/ 計數器,TL0 作爲一個8 位定時器/ 計數器,通過標準定時器0 的控制位控制,TH0 僅作爲一個8 位定時器,由定時器1 的控制位控制。 |
2.TCON
TCON寄存器的字節地址爲88H,可進行位尋址。高4位分別爲定時器/計數器的啓動控制和溢出中斷標誌,低4位與外部中斷控制有關,
各標誌位的功能:
1. IT0—選擇外部中斷請求0爲跳沿觸發方式還是電平觸發方式:
IT0=0,爲電平觸發方式。
IT0=1,爲跳沿觸發方式。
可由軟件置“1”或清“0”。
2. IE0—外部中斷請求0的中斷請求標誌位。
IE0=0,無中斷請求。
IE0=1,外部中斷0有中斷請求。
當CPU響應該中斷,轉向中斷服務程序時,由硬件清“0”IE0
**3. IT1—外部中斷請求1爲跳沿觸發方式還是電平觸發方式,意義與IT0類似。
- IE1—外部中斷請求1的中斷請求標誌位,意義與IE0類似。
- TF0 —T0溢出中斷請求標誌位。**
T0計數後,當最高位產生溢出時,由硬件置“1”TF0,向CPU申請中斷,CPU響應TF0中斷時,清“0”TF0,TF0也可由軟件清0。
6. TF1—T1的溢出中斷請求標誌位,功能和TF0類似。
TR1、TR0 2個位與中斷無關,僅與定時器/計數器T1和T0有關。
3.IE
中斷允許寄存器:CPU對中斷源的開放或屏蔽,由片內的中斷允許寄存器IE控制。字節地址爲A8H,可位尋址。格式如下:
IE中各位的功能如下:
1. EA:中斷允許總控制位
EA=0:CPU屏蔽所有的中斷請求(CPU關中斷) ;
EA=1:CPU開放所有中斷(CPU開中斷) 。
五個中斷源的中斷請求是否允許,還要由IE中對應的5箇中斷請求允許控制位的狀態來決定。
2. ES:串行口中斷允許位
ES=0:禁止串行口中斷;
ES=1:允許串行口中斷。
3. ET1:定時器/計數器T1的溢出中斷允許位
ET1=0:禁止T1溢出中斷;
ET1=1:允許T1溢出中斷。
4. EX1:外部中斷1中斷允許位
EX1=0:禁止外部中斷1中斷;
EX1=1:允許外部中斷1中斷。
5. ET0:定時器/計數器T0的溢出中斷允許位
ET0=0:禁止T0溢出中斷;
ET0=1:允許T0溢出中斷。
6. EX0:外部中斷0中斷允許位。
EX0=0:禁止外部中斷0中斷;
EX0=1:允許外部中斷0中斷。
MCS-51復位後,IE清0,所有中斷請求被禁止。若使某一箇中斷源被允許中斷,除了IE相應的位被置“1” ,還必須使EA位=1。改變IE的內容,可由位操作指令或字節操作指令來實現。
定時器/計數器工作方式
在MCS-51系列單片機中,定時器/計數器(T0、T1)具有多種工作方式,當選擇工作方式不同,定時/計數器的使用方法差別很大。MCS-51單片機片內的定時器/計數器可以通過對特殊功能寄存器TMOD中的控制位 的設置來選擇定時器方式或計數器方式;通過對M1 M0兩位的設置來選擇定時器/計數器的四種工作方式,下面具體講解定時器/計數器的工作方式。
1. 工作方式0
定時器/計數器0、1在工作方式0時的電路邏輯結構見圖9-2。工作方式0(M1 M0 = 0 0)是13位計數結構的工作方式,其計數器由TH的全部8位和TL的低5位構成,TL的高3位不使用。當 =0時,定時器/計數器0、1處於定時工作方式,多路開關接通振盪脈衝的12分頻輸出,13位計數器依次進行計數。當 =1時,定時器/計數器0、1處於計數工作方式,多路開關接通計數引腳(T0),外部計數脈衝由腳T0輸入。當計數脈衝發生負跳變時,計數器加1。
當TL的低5位溢出時,都會向TH進位,而全部13位計數器溢出時,則會向計數器溢出標誌位TF0進位。同時,GATA位的狀態決定定時器運行控制取決於TR0一個條件還是TR0和/INT0引腳這兩個條件。當GATA=1時,由於GATA信號封鎖了與門,使引腳/INT0信號無效。而這時候如果TR0=1,則接通模擬開關,使計數器進行加法計數,即定時/計數器工作。而TR0=0,則斷開模擬開關,停止計數,定時器/計數器不能工作。當GATA=0時,與門的輸出端由TR0和INT0電平的狀態確定,此時如果TR0=1,INT0=1與門輸出爲1,允許定時器/計數器計數,在這種情況下,運行控制由TR0和INT0兩個條件共同控制,TR0是確定定時/計數器的運行控制位,由軟件置位或清“0”。
在工作方式0下,計數器的計數值X範圍爲1~8192(2131)。由於MCS-51單片機的T0和T1採用加計數,因此TH0(TH1),TL0(TL1)的初值N=8192-X。如當計數值X=1000,則計數初值N=7192=1C18H,那麼TH0(TH1),TL0(TL1)的值分別爲0E0H和18H。由於TL0(TL1)爲低5爲有效,所以該計數初值N不能簡單地分成高8位和低8位賦值給TH0(TH1),TL0(TL1)。當計數初值N=7192=1C18H,其二進制編碼如下
再將16位的二進制編碼去除最高的3位,保留後面13位,並取低5位寫入到TL0(TL1),高8位寫入到TH0(TH1),具體操作如下
其中,11000B是TL0(TL1)對應的低5位,其16進制編碼爲18H,而1110 0000這8位爲TH0(TH1)的內容,其16進制編碼爲0E0H。
當定時器/計數器工作於方式0且確定了定時時間T1後,其計數初值N的計算公式爲
式中,fosc爲系統時鐘振盪頻率。
假設單片機的晶振選爲12MHz,需要用T0進行2ms定時控制,則T0的初值N計算爲
則對應的13位二進制編碼爲1100 0001 1 0000則TH0=0C1H,TL0=10H
2. 工作方式1
定時器/計數器0、1工作於方式1時,其電路邏輯結構如圖所示。
工作方式1(M1 M0=0 1)是16位計數結構的工作方式。方式0和方式1的區別僅在於計數器的位數不同,方式0爲13位,而方式1則爲16位,由TH0作爲高8位,TL0爲低8位,有關控制狀態字(GATA、TF0、TR0)和方式0相同。
在工作方式1下,計數器的計數值X範圍是:1~65536
當定時器/計數器工作於方式1且確定了定時時間T1後,其計數初值N的計算公式爲:
則寫入到8位寄存器TH0(TH1),TL0(TL1)值分別爲
TH0(TH1)=N/256
TL0(TL1)=N%256
3. 工作方式2
當M1 M0=1 0時,定時器/計數器0、1處於工作方式2,此時其電路邏輯結構如圖9-4所示。以定時/計數器0爲例,定時/計數器1與之完全一致。
4. 工作方式3
當M1 M0 =1 1時,定時器/計數器工作於方式3下。方式3只適用於定時器T0,若將T1置爲方式3,則它將停止計數,其效果相當於置TR1=0,即關閉定時器T1。當T0工作在方式3時,TH0和TL0被分成兩個相互獨立的8位計數器,其電路邏輯結構如圖所示。
在工作方式3模式下,TL0既可以作爲計數器使用,也可以作爲定時器使用,定時器/計數器0的各控制位和引腳信號全歸它使用。其功能和操作與方式0或方式1完全相同。但TH0的功能受到限制,只能作爲簡單的定時器使用,而且由於定時器/計數器0的控制位已被TL0佔用,因此只能借用定時器/計數器1的控制位TR1和TF1,也就是以計數溢出去置位TF1,TR1則負責控制TH0定時器的啓動和停止。由於TL0既能作定時器也能作計數器使用,而TH0只能作定時器使用而不能作計數器使用,因此在方式3模式下,定時/計數器0可以構成兩個定時器或者一個定時器和一個計數器。
第三部分 定時器/計數器編程方法
定時器的初始化編程包括:
- 設置定時器工作模式(設置TMOD);
- 設置定時器計數初值(設置THx/TLx);
- 允許定時器中斷(IE);
- 啓動定時器(TCON)。
例如:
- 設置定時器工作模式(TMOD不能位尋址)
TMOD = 0x01; T0工作在模式 1下,16位定時器 - 設置定時器計數初值
計算初值公式 (T0定時模式2,8):
TH0=(28- 計數值) ; \ 8192 1s, 1us=110^6 ,50000,50ms
TL0=(28 -計數值);
計數值=定時時間/ 機器週期; 如果時鐘頻率fosc=12MHZ,則機
器週期=12
時鐘週期=12*1/fosc=1us。 6mhz,
PS:如果要求定時器按某固定時間間隔不斷觸發,需要在中斷服務程
序中再次設置定時器計數初值(模式2除外),否則,中斷服務程序以該模
式下的最大定時值工作。 - 允許定時器中斷(中斷號)
EA=1;ET0=1 - 啓動定時器
定時器T0:TCON=0x10 或者 TR0=1
第四部分 定時器/計數器仿真設計
設計案例一
基於上述原理可以設計一個60s計時的秒錶,完成秒錶電路的設計與編程調試。
原理圖
定時器T0或T1實現秒錶的計時功能,工作模式不限,計時60s後自動從0開始重新計時, INT0中斷方式實現秒錶的啓動和暫停計時; INT1中斷方式實現秒錶的計時重置。
動態仿真結果
代碼
Keil代碼如下:
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
sbit duan = P2^0;
sbit wei = P2^1;
sbit int0=P3^2;
sbit int1=P3^3;
uchar code LED_D[]={
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
uchar code LED_W[]={
0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
uchar count=0;
uchar Time=0;
void Delay(uint x);//延遲函數
void Display2(uchar W1, Time);//顯示函數
void QP();//清屏函數
//主函數
void main()
{
QP();
TMOD=0x01;//設置定時器工作方式
TH0=(65536-50000)/256;//計算初值,高8位
TL0=(65536-50000)%256;//計算初值,第8位
ET0=1;
EA=1; //開總中斷
while(1)
{
if(int0==0)
{
Delay(100);
if(int0==0){
TR0=!TR0;
while(int0==0);}}
if(int1==0){
Delay(100);
if(int1==0)
{
Time=0;
}}
Display2(6,Time);
}
}
void LED_Flash() interrupt 1//中斷函數
{
EA=0;//關總中斷
TH0=(65536-50000)/256;//重裝初值
TL0=(65536-50000)%256;//重裝初值
if(++count==20) //開始計數
{
count=0;
Time++;
if(Time==61)
Time=0;
}
EA=1;
}
void Int0() interrupt 0
{
if(int0==0)
{
Delay(100);
if(int0==0)
{
TR0=!TR0;
while(int0==0);
}
}
}
void Int1() interrupt 2//中斷函數
{
EA=1;
ET0=1;
if(int1==0){
Delay(10);
if(int1==0)
{
Time=0;
}
}
}
void Display2(uchar W1, Time)//顯示函數
{
uchar shi,ge;
shi = Time/10;
ge = Time%10;
P0 = LED_D[shi];
duan = 1; duan = 0;
P0 = LED_W[W1];
wei = 1;
wei = 0;
Delay(3);
QP();
P0 = LED_D[ge];
duan = 1;
duan = 0;
P0 = LED_W[W1+1];
wei = 1;
wei = 0;
Delay(3);
QP();
}
void QP()
{
P0=0x00;
duan = 1; duan = 0;
wei = 1; wei = 0;
}
void Delay(uint x) //延時
{
uchar t;
while(x--) for(t=0;t<110;t++);
}
設計案例二
利用T0、T1計數器功能,實現按鍵計數,計數值分別在2個4位數碼管上顯示。
原理圖
- 利用定時器T0工作模式2,中斷方式,計數初值爲0,數碼管顯示3位數
- T1工作模式不限,非中斷方式,計數初值爲256,數碼管顯示3位數
- INT0中斷方式實現T0、T1計數清零
動態仿真結果
通過不同的按鍵來實現對應的計數功能,利用定時器的計數功能可以使得單片機得到快速響應。
代碼
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
sbit duan = P2^0;
sbit wei = P2^1;
uchar code LED_D[]={
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
uchar code LED_W[]={
0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
uint count1,count2;
void Delay(uint x);
void Display2(uchar W1,uint count);
void QP();
void main()
{
QP();
EA=1; //開總中斷
TMOD=0x46; //設置定時器工作方式
TH0=TL0=0; //設定初值
TH1=1;TL1=0;
ET0=1;
EX0=1;
IT0=1;
TR0=1;
TR1=1;
while(1)
{
if(TF1==1) TF1=0;
count1 = TL0;
count2 = TH1*256+TL1;
Display2(1,count1);
Display2(5,count2);
}
}
void Flash() interrupt 1
{
EA=0;
TL1=0;
EA=1;
}
void Clear() interrupt 0
{
TL0=0;
TL1=0;
}
void Display2(uchar W1, uint count)
{
uchar bai,shi,ge;
bai = count%1000/100;
shi = count%100/10;
ge = count%10;
P0 = LED_D[bai];
duan = 1; duan = 0;
P0 = LED_W[W1];
wei = 1;
wei = 0;
Delay(3);
QP();
P0 = LED_D[shi];
duan = 1;
duan = 0;
P0 = LED_W[W1+1];
wei = 1;
wei = 0;
Delay(3);
QP();
P0 = LED_D[ge];
duan = 1;
duan = 0;
P0 = LED_W[W1+2];
wei = 1;
wei = 0;
Delay(3);
QP();
}
void QP()
{
P0=0x00;
duan = 1; duan = 0;
wei = 1; wei = 0;
}
void Delay(uint x)
{
uchar t;
while(x--) for(t=0;t<110;t++);
}
以上就是本次定時器/計數器的全部內容,希望通過本次的講解能夠加深大家對於定時器/計數器以及中斷的理解。文章的內容可能存在部分不足之處,如有錯誤,請在評論區指出,謝謝。如果大家覺得文章有用,麻煩點贊關注,感謝支持,後續將會推出單片機的進階設計文章。