單片機學習(六)定時器的使用

參考資料:

一、定時器簡介

  • 定時器介紹:
    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(),我們即可在固定的時間內調用中斷程序了。

Tags: