參考資料:
一、定時器簡介
- 定時器介紹:
51微控制器的定時器屬於微控制器的內部資源,其電路的連線和運轉均在微控制器內部完成 - 定時器作用:
- (1) 用於計時系統,可實現軟體計時,或者使程式每隔一固定時間完成一項操作
- (2)替代長時間的Delay, 提高CPU的執行效率和處理速度
- ...
二、STC89C52定時器資源
- 定時器個數: 3個 (
T0
、T1
、T2
),T0和T1與傳統的51微控制器相容,
T2是此型號微控制器增加的資源 - 注意:定時器的資源和微控制器的型號是關聯在一起的,不同的型號可能會有不同的定時器個數和操作方式,但一般來說,T0和T1的操作方式是所有51微控制器所共有的
三、定時器工作原理
定時器在微控制器內部就像一個小鬧鐘一樣,根據時鐘的輸出訊號,每隔“一秒"(一個單位時間),計數單元的數值就增加一,當計數單元數值增加到“設定的鬧鐘提醒時間"時,計數單元就會向中斷系統發出中斷申請,產生"響鈴提醒",使程式跳轉到中斷服務函式中執行。
在實現細節上:時鐘部分每隔單位時間就會傳遞一個脈衝訊號到計數部分,而計數部分會對脈衝個數進行計數,當脈衝個數達到TH0,TL0
能儲存的最大數量後(即發生溢位,這裡一共有16位,即只能表示0~65535這些數字,繼續接收訊號即溢位),TF0
將會被置一,此時就會發出中斷申請,然後程式跳轉到中斷服務程式中執行。
1. 時鐘訊號的提供
可以看到,在時鐘部分有兩個輸入來源:
- 系統時鐘
T0
引腳
當我們使用T0
引腳時往往是將這個模組作為計數器記錄脈衝的個數的,而不是用作定時器,故這裡我們一般只考慮系統時鐘的訊號輸入。
SYSclk
:系統時鐘,即晶振週期,本開發板上的晶振為12MHz
當 C/T=0
時選擇的是系統時鐘作為輸入,而 C/T=1
時選擇的是T0
引腳作為輸入,故我們需要選擇第一種。
2. 中斷系統簡介
中斷系統是為使CPU具有對外界緊急事件的實時處理能力而設定的。
中斷的概念
當中央處理機CPU正在處理某件事的時候外界發生了緊急事件請求,要求CPU暫停當前的工作,轉而去處理這個緊急事件,處理完以後,再回到原來被中斷的地方,繼續原來的工作,這樣的過程稱為中斷。
中斷的優先順序
實現這種功能的部件稱為中斷系統,請示CPU中斷的請求源稱為中斷源。微型機的中斷系統一般允許多箇中斷源,當幾個中斷源同時向CPU請求中斷,要求為它服務的時候,這就存在CPU優先響應哪一個中斷源請求的問題。通常根據中斷源的輕重緩急排隊,優先處理最緊急事件的中斷請求源,即規定每一箇中斷源有一個優先順序別。CPU總是先響應優先順序別最高的中斷請求。
中斷的巢狀
當CPU正在處理一箇中斷源請求的時候( 執行相應的中斷服務程式),發生了另外一個優先順序比它還高的中斷源請求。如果CPU能夠
- 暫停對原來中斷源的服務程式
- 轉而去處理優先順序更高的中斷請求源,處理完該請求
- 再回到原低階中斷服務程式
這樣的過程稱為中斷巢狀,這樣的中斷系統稱為多級中斷系統
沒有中斷巢狀功能的中斷系統稱為單級中斷系統。
中斷流程圖
STC89C52的中斷資源
-
中斷源個數: 8個
- 外部中斷0
- 定時器0中斷
- 外部中斷1
- 定時器1中斷
- 串列埠中斷
- 定時器2中斷
- 外部中斷2
- 外部中斷3
-
中斷優先順序個數: 4個
-
中斷號
3. 相關的暫存器
TCON暫存器
TF和TR
當計數器溢位時TF0
會被置一,TR0
用於控制T0
計時器是否計數。
TMOD暫存器
TMOD暫存器主要是用於配置我們的定時器的功能。
GATE
C/T
M1、M0
總圖
4. 定時器程式基本配置圖
四、編碼實現
初始化程式碼
1. 配置TMOD暫存器
首先我們希望使用定時器0,我們需要配置:
GATE = 0
C/T = 0
M1,M0 = 01
所以我們可以使用與或賦值法進行賦值:
TMOD &= 0xF0; // 1111 0000
TMOD |= 0x01; // 0000 0001
tips:TMOD暫存器是不可位定址的,故我們只能通過整體賦值的方式進行配置
2. 配置TCON暫存器
我們需要啟用T0
計數器,並給它的溢位標誌位TF0
置零:
TF0 = 0;
TR0 = 1;
3. 配置計數暫存器的初始值
計數器的計數範圍:0~65535
大約每隔1us計數加一,故其總共定時時間為65535us
而我們希望計時1ms即發生中斷,則我們可以將計數暫存器初始值為64536,因為64536離計數器溢位差值1000,所以當計時時間為1ms時即可觸發中斷。
而計數暫存器由兩個暫存器拼接而成,則我們可以分高低位賦值:
TH0 = 64536 / 0x0100; // 高八位
TL0 = 64536 % 0x0100; // 低八位
4. 配置中斷通路
即按照上一部分的第4點的圖進行配置即可:
ET0 = 1;
EA = 1;
PT0 = 0;
5. 總的配置程式碼
void Timer0Init(void)
{
// 1.配置TMOD暫存器
TMOD &= 0xF0; // 1111 0000
TMOD |= 0x01; // 0000 0001
// 2.配置TCON暫存器
TF0 = 0;
TR0 = 1;
// 3.配置計數暫存器的初始值
TH0 = 64536 / 0x0100;
TL0 = 64536 % 0x0100;
// 4.配置中斷通路
ET0 = 1;
EA = 1;
PT0 = 0;
}
中斷程式程式碼
語法:相當於在函式後面加上 interrupt
關鍵字:
void 中斷程式名() interrupt 中斷號 {
...
}
其中中斷號需要和中斷源相對應。
使用STC-ISP自帶的定時器計算器
開啟STC-ISP燒錄工具,並點選【定時器計算器】的tab:
配置如下:
然後我們即可獲得相應的初始化程式碼了!
注意:在我們當前版本的微控制器中是沒有AUXR這個暫存器的,我們不需要配置此項(刪除即可),然後我們還需要加入中斷的配置,即【配置中斷通路】部分的三行程式碼。
使用自動生成的程式碼:
void Timer0Init(void) //1毫秒@12.000MHz
{
TMOD &= 0xF0; //設定定時器模式
TMOD |= 0x01; //設定定時器模式
TL0 = 0x18; //設定定時初值
TH0 = 0xFC; //設定定時初值
TF0 = 0; //清除TF0標誌
TR0 = 1; //定時器0開始計時
// 配置中斷通路
ET0 = 1;
EA = 1;
PT0 = 0;
}
unsigned int T0Count = 0;
void timer0_routine() interrupt 1 {
T0Count++;
TL0 = 0x18; //設定定時初值
TH0 = 0xFC; //設定定時初值
if (T0Count == 1000) {
T0Count = 0;
P2_0 =! P2_0;
}
}
五、將計時器封裝成模組
新建Timer0.h
和Timer0.c
檔案:
// Timer0.h
#ifndef __TIMER0_H__
#define __TIMER0_H__
void Timer0Init(void);
#endif // __TIMER0_H__
#include <Atmel/REGX52.H>
#include "Timer0.h"
void Timer0Init(void) //1毫秒@12.000MHz
{
TMOD &= 0xF0; //設定定時器模式
TMOD |= 0x01; //設定定時器模式
TL0 = 0x18; //設定定時初值
TH0 = 0xFC; //設定定時初值
TF0 = 0; //清除TF0標誌
TR0 = 1; //定時器0開始計時
// 配置中斷通路
ET0 = 1;
EA = 1;
PT0 = 0;
}
這樣我們只需要在主函式中使用Timer0Init()
,我們即可在固定的時間內呼叫中斷程式了。