定時(shí)器
定時(shí)器的介紹
51單片機(jī)上的定時(shí)器是一種硬件模塊,用于計(jì)時(shí)和生成特定的時(shí)間延遲。它的電路和運(yùn)轉(zhuǎn)都在單片機(jī)內(nèi)完成,它是嵌入在單片機(jī)內(nèi)部的一個(gè)功能模塊,具有多種工作模式和功能。
在51單片機(jī)中,通常有兩個(gè)定時(shí)器/計(jì)數(shù)器:定時(shí)器0(Timer 0)和定時(shí)器1(Timer 1)。每個(gè)定時(shí)器都有一個(gè)相應(yīng)的控制寄存器,用于設(shè)置相關(guān)參數(shù)和配置工作模式。在我們這款STC89C52上還多一個(gè)T2的定時(shí)器;
定時(shí)器的作用
1.用于計(jì)時(shí)系統(tǒng),可以實(shí)現(xiàn)軟件計(jì)時(shí),或者使程序每隔一定的時(shí)間就完成一項(xiàng)任務(wù);
2.替代長時(shí)間的Delay,提高CPU運(yùn)行效率和處理速度;
我們在前面學(xué)習(xí)了用Delay函數(shù)進(jìn)行延遲,但對于Delay函數(shù)來說,我們在完成一件任務(wù)時(shí),當(dāng)它開始延遲時(shí),我們需要停下我們CPU的手上所有的運(yùn)行,等他延遲之后我們才可以繼續(xù)操作,因?yàn)閷τ谒凶雍瘮?shù)來說,我們都需要在主函數(shù)(main)中完成,當(dāng)發(fā)生Delay時(shí),就沒有辦法完成其他操作,所以Delay無法實(shí)現(xiàn)多任務(wù)線程的工作,例如下面的一邊流水燈,一邊用按鍵控制;而對于定時(shí)器來說,恰好解決了這一難題。
定時(shí)器框圖
定時(shí)器在單片機(jī)內(nèi)部就像一個(gè)小鬧鐘一樣,根據(jù)時(shí)鐘的輸出信號(脈沖),每隔一段時(shí)間,那么計(jì)數(shù)單元的數(shù)值就會加一,當(dāng)計(jì)數(shù)單元達(dá)到最大值后,那么計(jì)數(shù)單元就會向中斷系統(tǒng)發(fā)出申請,讓他開始執(zhí)行中斷服務(wù)函數(shù)。
定時(shí)器的工作模式
對于定時(shí)器來說,是有多種模式可以選擇的,不只是會讓計(jì)數(shù)單元一直加一加一,也可以是加十加十,這就相當(dāng)于我們選擇了另外一種模式;
對于STC89C52的T0和T1來說,都有四種工作模式:
模式0:13位定時(shí)器/計(jì)數(shù)器
模式1:16位定時(shí)器/計(jì)數(shù)器(常用)
模式2:8位自動重裝模式
模式3:兩個(gè)8位計(jì)數(shù)器
在這里,對于我們來說,模式1是我們這篇文章要講的,其他的像模式0和模式3,一般情況我們是用不到的,而模式2:8位自動重裝模式,主要用于串口通信產(chǎn)生波特率進(jìn)行調(diào)節(jié);
在這里,我們按照上面的框圖分為時(shí)鐘系統(tǒng),計(jì)數(shù)系統(tǒng),中斷:
計(jì)數(shù)器原理圖:
時(shí)鐘系統(tǒng):
SYSclk:system clock系統(tǒng)時(shí)鐘,它具有晶振周期,在本開發(fā)板上晶振為11.0592MHz,是一個(gè)非常大的數(shù)字,換算成時(shí)間的話就約為9ns左右(T=1/f),可以產(chǎn)生脈沖,將脈沖傳入計(jì)數(shù)系統(tǒng),然后系統(tǒng)時(shí)鐘可以有兩種模式選擇分頻,也就是將頻率降低;在這里,我們選擇的是12T;T0 Pin是外接口引腳,可以由外接口連上一個(gè)計(jì)時(shí)器,每個(gè)一個(gè)周期脈沖就會加1,那么計(jì)時(shí)器也就可以變?yōu)橛?jì)數(shù)器,通過計(jì)算脈沖來達(dá)到計(jì)數(shù)效果;也就是將C/T=0;
計(jì)數(shù)系統(tǒng):
TR0,是計(jì)時(shí)器T0的運(yùn)行控制位,相當(dāng)于一個(gè)啟動器(按鈕),只有TR0啟動之后,那么技術(shù)系統(tǒng)才會開始計(jì)數(shù);TL0和TH0分別表示低位和高位,用來計(jì)算脈沖傳過來的次數(shù),每一次的脈沖過來就加一,這兩個(gè)加起來總共有16bit位,那么就表示計(jì)數(shù)系統(tǒng)可以計(jì)算0~65535(2^16-1)次,當(dāng)計(jì)數(shù)達(dá)到最大值時(shí),就會向中斷系統(tǒng)發(fā)出中斷請求;
中斷:
TF0也就是中斷溢出的標(biāo)志位,簡單的來說就是消息提醒,向CPU告知需要中斷了,中斷就需要進(jìn)入中斷系統(tǒng);
中斷系統(tǒng)
介紹:
單片機(jī)的中斷系統(tǒng)是指單片機(jī)處理外部事件或者內(nèi)部事件時(shí)的一種機(jī)制。在單片機(jī)執(zhí)行程序的過程中,可能會遇到一些特殊情況,比如定時(shí)時(shí)間到、有外部設(shè)備的輸入信號等。這時(shí),CPU需要臨時(shí)停止當(dāng)前的程序,轉(zhuǎn)去執(zhí)行相應(yīng)的中斷處理程序,待處理完該事件后再返回原先的程序繼續(xù)執(zhí)行。這個(gè)定義很好理解,就像睡覺一半被鬧鐘叫醒去讀書一樣,鬧鐘在你睡覺途中打斷你的睡覺,讓你該去讀書了,這個(gè)過程就是中斷;
組成部分:
中斷源:指引起中斷的事件或信號源,可以是外部設(shè)備產(chǎn)生的輸入信號,也可以是定時(shí)器的時(shí)間到達(dá)等。
中斷控制器:負(fù)責(zé)對各個(gè)中斷源的優(yōu)先級進(jìn)行管理和調(diào)度,確定哪個(gè)中斷請求能夠被CPU響應(yīng)。
中斷向量表:用于存儲每個(gè)中斷類型對應(yīng)的中斷處理程序的入口地址。
中斷處理程序:是指處理具體中斷事件的程序代碼,根據(jù)中斷類型執(zhí)行相應(yīng)的操作,處理完后返回到原先的程序繼續(xù)執(zhí)行.
作用:
實(shí)時(shí)性:中斷系統(tǒng)可以及時(shí)響應(yīng)外部事件,提高系統(tǒng)的實(shí)時(shí)性能。
節(jié)約CPU資源:通過使用中斷系統(tǒng),CPU不再需要不斷地輪詢外部設(shè)備狀 態(tài),而是在需要處理事件時(shí)才會被中斷,節(jié)約了CPU的資源。
提高系統(tǒng)效率:使用中斷系統(tǒng)可以使單片機(jī)在處理外部事件時(shí)不需要等待,減少了等待時(shí)間,提高了系統(tǒng)的效率。
靈活性:通過中斷系統(tǒng),可以方便地處理不同類型的事件,增加了系統(tǒng)的靈活性和擴(kuò)展性。
中斷程序流程
在我們的認(rèn)知里,一般都會在主函數(shù)中執(zhí)行程序,但如果有中斷函數(shù)存在的話,當(dāng)主程序發(fā)出中斷請求時(shí),程序就會停止主程序,優(yōu)先處理中斷函數(shù)中的程序,處理完再返回主程序,這就是中斷程序的流程,在下面的代碼中將會有進(jìn)一步加深印象;
STC89C52的中斷資源
在STC89C52中有8個(gè)中斷資源:外部中斷、定時(shí)器0中斷、外部中斷1、定時(shí)器1中斷、串口中斷、外部中斷2、外部中斷3;
中斷的優(yōu)先級個(gè)數(shù)有4個(gè);
在這里i,函數(shù)后面的nterrupt+序列號就是表示不同的中斷資源,當(dāng)中斷請求向CPU發(fā)出后中斷系統(tǒng)響應(yīng)后,那么就會執(zhí)行這個(gè)中斷程序;
定時(shí)器和中斷系統(tǒng)
這里的中斷系統(tǒng)實(shí)際上是簡化的了,但對于原理來說,其實(shí)是一致的,為了方便對初學(xué)者的了解,才使用該原理圖;
這個(gè)就是定時(shí)器連接著中斷系統(tǒng)了。當(dāng)我們計(jì)數(shù)系統(tǒng)滿的時(shí)候,就會向TF0標(biāo)志位告知,讓它發(fā)出中斷請求,接著就是ETO得閉合,允許T0中斷,然后就是PT0選擇0,選擇好定時(shí)器的優(yōu)先級;
定時(shí)器的相關(guān)寄存器
在前面幾篇文章,我們使用的寄存器相對來說是比較少的,對于定時(shí)器來說,它有以下的相關(guān)寄存器:
我們可以看到對于計(jì)時(shí)器和中斷系統(tǒng)的寄存器來說,還是相當(dāng)多的,對于中斷寄存器的,我們只挑出相關(guān)定時(shí)器的寄存器來講;
TCON
寄存器都會有相應(yīng)的地址,程序會通過指針指向的地址來找到對應(yīng)的寄存器位置,寄存器一般有8個(gè)bit位,這里的可位尋址,表示根據(jù)它的bit位來尋找對應(yīng)的地址;
首先T1和T0對應(yīng)的bit位功能基本相同,所以這里只對T0展開論述;
TF0:定時(shí)器T0溢出中斷標(biāo)志(Timer Flag)。 T0開始計(jì)數(shù)后,但計(jì)數(shù)達(dá)到最大值后,開始產(chǎn)生溢出,TF0會由硬件置“1”,向CPU發(fā)出請求中斷,CPU響應(yīng)后,TF0才由硬件置“0”。
TR0:定時(shí)器T0控制位(Timer Run); 當(dāng)GATE(一個(gè)開關(guān))=0,TR0=1 T0開始計(jì)數(shù),TR0=0禁止T0計(jì)數(shù);
IE0:外部中斷0請求源標(biāo)志(Interrupt Enable);IE0=1外部中斷0向CPU請求中斷,CPU響應(yīng)后,外部中斷0由硬件清‘0’IE0;
IT0:外部中斷0觸發(fā)方式控制位(Interrupt Trigger);IT0=0時(shí),外部中斷0為低電平觸發(fā)方式,輸入低電平時(shí),置位IE0。當(dāng)IT1=0時(shí),則外部中斷0端口由“1”->"0"下降沿跳變,激活中斷請求標(biāo)志位IE0,向主機(jī)請求中斷處理。
TMOD
這里不可位尋址就是不能利用TMOD的bit位來尋找對應(yīng)的地址,必須使用TMOD寄存器,直接對它賦值;
GATE與C/T這里不涉及就不再講,M1和M0時(shí)選擇定時(shí)器的模式:
這里由于是不可位尋址,我們用到了一種巧妙的方式——按位運(yùn)算,對于我們要實(shí)現(xiàn)定時(shí)器0模式1 那么我們可以先對TMOD按位與0xF0,使TMOD定時(shí)器0都保持為0,接著用按位或的按位運(yùn)算,將它或上0x01,這種做的目的是不用管TMOD的初始狀態(tài)是什么,與上1就是1;
TH與TL
TH與TL后面跟0就表示定時(shí)器0的計(jì)數(shù),后面跟1就表示定時(shí)器1的計(jì)數(shù)。
有關(guān)中斷的寄存器
在這里,我們跟著原理圖的走向,列出相關(guān)的寄存器;
==EA:CPU的中斷允許控制位(Interrupt All);==這是一個(gè)總的中斷控制,當(dāng)EA=0,CPU將會屏蔽所有的中斷申請;EA=1才允許申請。
ET0:T0的溢出中斷允許位;ET0=1,允許T0中斷;
PT0: 一個(gè)特殊位申請,當(dāng)PT0=0,為中斷優(yōu)先級;PT0=1時(shí)為高級優(yōu)先權(quán)。
按鍵控制流水燈模式
這里我們需要對定時(shí)器進(jìn)行初始化
Timer0.h
#ifndef __TIMER0_H__
#define __TIMER0_H__
void Timer0Init();
#endif
Timer0.c:
#include <REGX52.H>
void Timer0Init() //1毫秒@11.0592MHz
{
TMOD &= 0xF0;
TMOD |= 0x01; //設(shè)置定時(shí)器模式
TL0 = 0x66; //設(shè)置定時(shí)初值
TH0 = 0xFC; //設(shè)置定時(shí)初值
TF0 = 0; //清除TF0標(biāo)志
TR0 = 1; //定時(shí)器0開始計(jì)時(shí)
ET0=1; //允許T0中斷
EA=1; //CPU開放中斷
PT0=0; //定時(shí)器0中斷優(yōu)先級
}
這里初始化的是可以走1ms的定時(shí)器,首先需要對定時(shí)器0模式選擇為1,然后設(shè)置定時(shí)的初值,根據(jù)每一個(gè)計(jì)數(shù)到下一個(gè)計(jì)數(shù)的時(shí)間差,從65535向前推算需要多少個(gè)計(jì)數(shù),進(jìn)行對應(yīng)的高低位初始化;那么1ms后就會向TF0發(fā)出中斷請求;TF0初始化為0;TR0選擇1,讓計(jì)時(shí)器計(jì)時(shí),ET0選擇1允許T0中斷,EA為總中斷控制位,選擇1為打開,PT0選擇0為低級中斷優(yōu)先級;
接著我們寫一個(gè)按鍵選擇函數(shù):
Delay.h:
#ifndef __DELAY_H__
#define __DELAY_H__
void Delayms(unsigned int x);
#endif
Delay.c
oid Delayms(unsigned int x) //@11.0592MHz
{
unsigned char i, j;
while(x--)
{
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
}
Key.h
#ifndef __KEY_H__
#define __KEY_H__
unsigned char Key();
#endif
Key.c
include "Delay.h"
#include <REGX52.H>
/**
* @brief 獲取獨(dú)立按鍵鍵碼
* @param 無
* @reval 按下按鍵的鍵碼,范圍0~4,無按鍵按下時(shí)返回值為0
*/
unsigned char Key()
{
unsigned char KeyNumber=0;
if(P3_1==0){Delayms(20);while(P3_1==0);Delayms(20);KeyNumber=1;}
if(P3_0==0){Delayms(20);while(P3_0==0);Delayms(20);KeyNumber=2;}
if(P3_2==0){Delayms(20);while(P3_2==0);Delayms(20);KeyNumber=3;}
if(P3_3==0){Delayms(20);while(P3_3==0);Delayms(20);KeyNumber=4;}
return KeyNumber;
}
最后寫上主函數(shù):文章來源:http://www.zghlxwxcb.cn/news/detail-542509.html
#include <REGX52.H>
#include "Timer0.h"
#include "Key.h"
#include <INTRINS.H>
unsigned char KeyNum,LEDMode;
void main()
{
P2=0xFE;
Timer0Init();
while(1)
{
KeyNum=Key();
if(KeyNum==1)
{
LEDMode++;
LEDMode%=2;
}
}
}
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x66; //設(shè)置定時(shí)初值
TH0 = 0xFC; //設(shè)置定時(shí)初值
T0Count++;
if(T0Count>=500)
{
T0Count=0;
if(LEDMode==0)
P2=_crol_(P2,1);
if(LEDMode==1)
P2=_cror_(P2,1);
}
}
在主函數(shù)里,先對P2和定時(shí)器進(jìn)行初始化,然后在循環(huán)里面走獨(dú)立按鍵的程序,每當(dāng)按一次按鍵1,LEDCode就會在0和1依次循環(huán)選擇;
然后是中斷函數(shù),1表示是計(jì)時(shí)器的中斷程序,每當(dāng)計(jì)時(shí)器計(jì)數(shù)溢出時(shí),那么我們就開始中斷主程序,對中斷函數(shù)開始執(zhí)行,先重新對計(jì)時(shí)器初始化,便于下一次計(jì)時(shí),這里ToCount表示多少毫秒走一次LED燈,當(dāng)LEDMode為0時(shí),向左跑流水燈,LEDMode為1時(shí)向右跑流水燈;這里的 crol()是一個(gè)LED流水燈函數(shù),第二個(gè)參數(shù)表示每一次跨越的燈數(shù),1也就是表示跨越一個(gè)燈數(shù),就會形成我們的流水燈。文章來源地址http://www.zghlxwxcb.cn/news/detail-542509.html
到了這里,關(guān)于51單片機(jī)--定時(shí)器與按鍵控制流水燈模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!