微控制器學習(六)定時器的使用

CodeReaper發表於2021-08-19

參考資料:

一、定時器簡介

  • 定時器介紹:
    51微控制器的定時器屬於微控制器的內部資源,其電路的連線和運轉均在微控制器內部完成
  • 定時器作用:
    • (1) 用於計時系統,可實現軟體計時,或者使程式每隔一固定時間完成一項操作
    • (2)替代長時間的Delay, 提高CPU的執行效率和處理速度
    • ...

二、STC89C52定時器資源

  • 定時器個數: 3個 (T0T1T2),T0和T1與傳統的51微控制器相容
    T2是此型號微控制器增加的資源
  • 注意:定時器的資源和微控制器的型號是關聯在一起的,不同的型號可能會有不同的定時器個數和操作方式,但一般來說,T0和T1的操作方式是所有51微控制器所共有的

三、定時器工作原理

定時器在微控制器內部就像一個小鬧鐘一樣,根據時鐘的輸出訊號,每隔“一秒"(一個單位時間)計數單元的數值就增加一,當計數單元數值增加到“設定的鬧鐘提醒時間"時,計數單元就會向中斷系統發出中斷申請,產生"響鈴提醒",使程式跳轉到中斷服務函式中執行

image-20210819135139999

在實現細節上:時鐘部分每隔單位時間就會傳遞一個脈衝訊號到計數部分,而計數部分會對脈衝個數進行計數,當脈衝個數達到TH0,TL0能儲存的最大數量後(即發生溢位,這裡一共有16位,即只能表示0~65535這些數字,繼續接收訊號即溢位),TF0將會被置一,此時就會發出中斷申請,然後程式跳轉到中斷服務程式中執行。

1. 時鐘訊號的提供

可以看到,在時鐘部分有兩個輸入來源:

  1. 系統時鐘
  2. T0引腳

當我們使用T0引腳時往往是將這個模組作為計數器記錄脈衝的個數的,而不是用作定時器,故這裡我們一般只考慮系統時鐘的訊號輸入

SYSclk:系統時鐘,即晶振週期,本開發板上的晶振為12MHz

C/T=0 時選擇的是系統時鐘作為輸入,而 C/T=1 時選擇的是T0引腳作為輸入,故我們需要選擇第一種。

2. 中斷系統簡介

中斷系統是為使CPU具有對外界緊急事件實時處理能力而設定的。

中斷的概念

當中央處理機CPU正在處理某件事的時候外界發生了緊急事件請求,要求CPU暫停當前的工作,轉而去處理這個緊急事件,處理完以後,再回到原來被中斷的地方,繼續原來的工作,這樣的過程稱為中斷

中斷的優先順序

實現這種功能的部件稱為中斷系統,請示CPU中斷的請求源稱為中斷源。微型機的中斷系統一般允許多箇中斷源,當幾個中斷源同時向CPU請求中斷,要求為它服務的時候,這就存在CPU優先響應哪一個中斷源請求的問題。通常根據中斷源的輕重緩急排隊優先處理最緊急事件的中斷請求源,即規定每一箇中斷源有一個優先順序別。CPU總是先響應優先順序別最高的中斷請求

中斷的巢狀

當CPU正在處理一箇中斷源請求的時候( 執行相應的中斷服務程式),發生了另外一個優先順序比它還高的中斷源請求。如果CPU能夠

  1. 暫停對原來中斷源的服務程式
  2. 轉而去處理優先順序更高的中斷請求源,處理完該請求
  3. 回到原低階中斷服務程式

這樣的過程稱為中斷巢狀,這樣的中斷系統稱為多級中斷系統

沒有中斷巢狀功能的中斷系統稱為單級中斷系統

中斷流程圖

image-20210819141614525

STC89C52的中斷資源

  • 中斷源個數: 8個

    1. 外部中斷0
    2. 定時器0中斷
    3. 外部中斷1
    4. 定時器1中斷
    5. 串列埠中斷
    6. 定時器2中斷
    7. 外部中斷2
    8. 外部中斷3
  • 中斷優先順序個數: 4個

  • 中斷號

image-20210819142345557

3. 相關的暫存器

TCON暫存器

image-20210819144150739

TF和TR

image-20210819145610987

當計數器溢位時TF0會被置一TR0用於控制T0計時器是否計數。

TMOD暫存器

TMOD暫存器主要是用於配置我們的定時器的功能

image-20210819143240884

GATE

image-20210819143853409

C/T

image-20210819143534190

M1、M0

image-20210819143355849

總圖

image-20210819144643006

4. 定時器程式基本配置圖

image-20210819144422214

四、編碼實現

初始化程式碼

1. 配置TMOD暫存器

首先我們希望使用定時器0,我們需要配置:

  1. GATE = 0
  2. C/T = 0
  3. 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:

image-20210819160820456

配置如下:

image-20210819161239960

然後我們即可獲得相應的初始化程式碼了!

注意:在我們當前版本的微控制器中是沒有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.hTimer0.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(),我們即可在固定的時間內呼叫中斷程式了。

相關文章