最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

51單片機(jī)編程開發(fā)(七)之定時(shí)器與定時(shí)器中斷

2022-07-31 09:08 作者:落木青云  | 我要投稿

51單片機(jī)定時(shí)器概述

定時(shí)/計(jì)數(shù)器從電路上來講是一個(gè)脈沖計(jì)數(shù)器,當(dāng)計(jì)數(shù)脈沖來自于單片機(jī)內(nèi)部機(jī)器周期時(shí),我們習(xí)慣上稱其為定時(shí)器,而當(dāng)計(jì)數(shù)脈沖來自于單片機(jī)外部的輸入信號時(shí),則稱其為計(jì)數(shù)器。8051系列單片機(jī)在片內(nèi)集成了兩個(gè)可編程的定時(shí)/計(jì)數(shù)器,分別稱其為定時(shí)/計(jì)數(shù)器0(T0)和定時(shí)/計(jì)數(shù)器1(T1),二者都具有定時(shí)和計(jì)數(shù)的功能。

這兩個(gè)定時(shí)計(jì)數(shù)器可以獨(dú)立配置為定時(shí)器或計(jì)數(shù)器。當(dāng)被配置為定時(shí)器時(shí),將按照預(yù)先設(shè)置好的長度運(yùn)行一段時(shí)間后產(chǎn)生一個(gè)溢出中斷;當(dāng)被配置為計(jì)數(shù)器時(shí),如果單片機(jī)的外部中斷引腳上檢測到一個(gè)脈沖信號,該計(jì)數(shù)器加1,當(dāng)達(dá)到預(yù)先設(shè)置好事件數(shù)目時(shí),產(chǎn)生一個(gè)中斷事件。

51單片機(jī)的定時(shí)計(jì)數(shù)器由內(nèi)部寄存器和外部引腳組成,T0(P3.4)引腳和T1(P3.5)引腳用于接收外部的脈沖信號。

51單片機(jī)的52子系列還有一個(gè)和這兩個(gè)計(jì)數(shù)器功能差別較大的16位定時(shí)計(jì)數(shù)器T2,T2的最常用功能是用作串行口的波特率發(fā)生器,這部分內(nèi)容我們之后再進(jìn)行講解。

51單片機(jī)通過對相應(yīng)寄存器的操作來實(shí)現(xiàn)對定時(shí)計(jì)數(shù)器的控制,這些寄存器包括工作方式控制寄存器TMOD(Timer MODe register)和控制寄存器TCON(Timer CONtrol register),此外T0和T1還分別擁有兩個(gè)8位數(shù)據(jù)寄存器TH0、TL0和TH1、TL1。

定時(shí)器控制機(jī)制

TMOD是定時(shí)計(jì)數(shù)器的工作方式控制寄存器,通過對該寄存器的操作可以改變T0和T1的工作方式。該寄存器的內(nèi)部結(jié)構(gòu)和說明如下圖所示,該寄存器不支持位尋址,單片機(jī)復(fù)位后被清零。

TMOD寄存器

TCON是定時(shí)計(jì)數(shù)器控制寄存器,上一節(jié)講解外部中斷時(shí)中我們已經(jīng)介紹過了,其內(nèi)部結(jié)構(gòu)如表下圖所示,在51單片機(jī)復(fù)位后初始化值為所有位都清零。

TCON寄存器

TH0、TL0/TH1、TL1分別是T0/T1的數(shù)據(jù)高位/低位寄存器,均為8位。當(dāng)定時(shí)計(jì)數(shù)器收到一個(gè)驅(qū)動(dòng)事件(定時(shí)、計(jì)數(shù))后,對應(yīng)的數(shù)據(jù)寄存器的內(nèi)容加1,當(dāng)數(shù)據(jù)寄存器的值到達(dá)最大時(shí),將產(chǎn)生一個(gè)溢出中斷,在單片機(jī)復(fù)位后所有寄存器的值都被初始化為0x00,這些寄存器都不能位尋址。

51單片機(jī)定時(shí)器工作原理

定時(shí)功能:定時(shí)功能是通過計(jì)數(shù)器的計(jì)數(shù)來實(shí)現(xiàn)的。計(jì)數(shù)脈沖來自單片機(jī)內(nèi)部,每個(gè)機(jī)器周期產(chǎn)生1個(gè)計(jì)數(shù)脈沖,即每個(gè)機(jī)器周期使計(jì)數(shù)器加1。由于1個(gè)機(jī)器周期等于12個(gè)振蕩脈沖周期,所以計(jì)數(shù)器的計(jì)數(shù)頻率為振蕩器頻率的1/12。假如晶振的頻率fosc =12MHz,則計(jì)數(shù)器的計(jì)數(shù)頻率 fcont =fosc ×1/12 為1MHz,即每微秒計(jì)數(shù)器加1。這樣,單片機(jī)的定時(shí)功能就是對單片機(jī)的機(jī)器周期數(shù)進(jìn)行計(jì)數(shù)。由此可知,計(jì)數(shù)器的計(jì)數(shù)脈沖周期為:

T=1/fcont =1/(fosc ×1/12)=12/fosc

式中,fosc 為單片機(jī)振蕩器的頻率;fcont 為計(jì)數(shù)脈沖的頻率,fcont =fosc /12。在實(shí)際應(yīng)用中,可以根據(jù)計(jì)數(shù)值計(jì)算出定時(shí)時(shí)間,也可以反過來按定時(shí)時(shí)間的要求計(jì)算出計(jì)數(shù)器的初值。

單片機(jī)的定時(shí)器用于定時(shí),其定時(shí)的時(shí)間由計(jì)數(shù)初值和選擇的計(jì)數(shù)器的長度(如8位、13位或16位)來確定。

計(jì)數(shù)功能:計(jì)數(shù)功能就是對外部事件進(jìn)行計(jì)數(shù)。外部事件的發(fā)生以輸入脈沖表示,因此計(jì)數(shù)功能實(shí)質(zhì)上就是對外部輸入脈沖進(jìn)行計(jì)數(shù)。STC89 系列單片機(jī)的T0(P3.4)、T1(P3.5)或T2(P1.0)信號引腳作為計(jì)數(shù)器的外部計(jì)數(shù)輸入端,當(dāng)外部輸入脈沖信號產(chǎn)生由1至0的負(fù)跳變時(shí),計(jì)數(shù)器的值加1。

在計(jì)數(shù)方式下,計(jì)數(shù)器在每個(gè)機(jī)器周期的S5P2期間,對外部脈沖輸入進(jìn)行1次采樣。如果在第1個(gè)機(jī)器周期中采樣到高電平“1”,而在第2個(gè)機(jī)器周期中采樣到1個(gè)有效負(fù)跳變脈沖,即低電平“0”,則在第3個(gè)機(jī)器周期的S3P1期間計(jì)數(shù)器加1。由此可見,采樣1次由“1”至“0”的負(fù)跳變計(jì)數(shù)脈沖需要花費(fèi)2個(gè)機(jī)器周期,即24個(gè)振蕩器周期,故計(jì)數(shù)器的最高計(jì)數(shù)頻率為fcont =fosc ×1/24。例如,單片機(jī)的工作頻率fosc 為12MHz,則最高的采樣頻率為0.5MHz。

對外部脈沖的占空比并沒有什么限制,但外部計(jì)數(shù)脈沖的高電平和低電平保持時(shí)間均必須在1個(gè)機(jī)器周期以上,方可確保某一給定的電平在變化前至少采樣1次。

51單片機(jī)定時(shí)器模式設(shè)置

51單片機(jī)T0和T1定時(shí)器都有4種模式,由TMOD寄存器中間的M1、M0這兩位的設(shè)置來控制。寄存器配置工作模式如下圖所示:

模式設(shè)置

接下來我們一起看看這些模式的設(shè)置與特點(diǎn)。

工作方式0:當(dāng)M1、M0設(shè)定為“00”時(shí),定時(shí)器工作于工作方式0,此時(shí)定時(shí)計(jì)數(shù)器的內(nèi)部結(jié)構(gòu)如圖所示。

模式0控制結(jié)構(gòu)

在工作方式0下,定時(shí)器內(nèi)部計(jì)數(shù)器計(jì)數(shù)值為13位,由TH0/TH1的8位和TL0/TL1的低5位組成;當(dāng)TL0/TL1溢出時(shí)將向TH0/TH1進(jìn)位,當(dāng)TH0/TH1溢出后則產(chǎn)生相應(yīng)的溢出中斷。工作方式下的驅(qū)動(dòng)事件來源則由GATE位、C/T#位來控制。

工作方式1:當(dāng)M1、M0設(shè)定為“01”時(shí),定時(shí)器工作于工作方式1,此時(shí)定時(shí)計(jì)數(shù)器的內(nèi)部結(jié)構(gòu)如圖所示。

模式1控制結(jié)構(gòu)

和工作方式0相比,工作方式1的唯一區(qū)別在于此時(shí)的內(nèi)部計(jì)數(shù)器寬度為16位,分別由TH0/TH1的8位和TL0/TL1的8位組成,其溢出方式和驅(qū)動(dòng)事件的來源和工作方式相同。51系列單片機(jī)的定時(shí)計(jì)數(shù)器采用加1計(jì)數(shù)的方式,即當(dāng)接收到一個(gè)驅(qū)動(dòng)事件時(shí)計(jì)數(shù)器加1,當(dāng)計(jì)數(shù)器溢出時(shí)則產(chǎn)生相應(yīng)的中斷請求,第一個(gè)驅(qū)動(dòng)事件到來時(shí)刻和中斷請求產(chǎn)生。

51單片機(jī)在接收到一個(gè)驅(qū)動(dòng)事件之后計(jì)數(shù)器加1,當(dāng)計(jì)數(shù)器溢出時(shí)則產(chǎn)生相應(yīng)的中斷請求。在定時(shí)的模式下,定時(shí)計(jì)數(shù)器的驅(qū)動(dòng)事件為單片機(jī)的機(jī)器周期,也就是外部時(shí)鐘頻率的1/12,可以根據(jù)定時(shí)器的工作原理計(jì)算出工作方式0和工作方式1下的最長定時(shí)長度T為:

通過對定時(shí)計(jì)數(shù)器的數(shù)據(jù)寄存器賦一個(gè)初始化值的方法可以讓定時(shí)計(jì)數(shù)器得到0到最大定時(shí)長度中任意選擇的定時(shí)長度,初始化值N的計(jì)算公式如下:


注意:定時(shí)計(jì)數(shù)器的工作方式0和工作方式1,不具備自動(dòng)重新裝入初始化值的功能,所以如果要想循環(huán)得到確定的定時(shí)長度就必須在每次啟動(dòng)定時(shí)器之前重新初始化數(shù)據(jù)寄存器,通常是在中斷服務(wù)程序里完成這樣的工作。

工作方式2:當(dāng)M1、M0設(shè)定為“10”時(shí),定時(shí)器工作于工作方式2,此時(shí)定時(shí)計(jì)數(shù)器的內(nèi)部結(jié)構(gòu)如圖所示。

模式2控制結(jié)構(gòu)


定時(shí)計(jì)數(shù)器的工作方式2和前兩種工作方式有很大的不同,工作方式2下的8位計(jì)數(shù)器的初始化數(shù)值可以被自動(dòng)重新裝入。在工作方式2下,TL0/TL1為一個(gè)獨(dú)立的8位計(jì)數(shù)器,而TH0/TH1用于存放時(shí)間常數(shù),當(dāng)T0/T1產(chǎn)生溢出中斷時(shí),TH0/TH1中的初始化數(shù)值被自動(dòng)裝入TL0/TL1中。這種方式可以大大減少程序的工作量,但是其定時(shí)長度也大大減少,應(yīng)用較多的場合是較短的重復(fù)定時(shí)或用作串行口的波特率發(fā)生器。

工作方式3:當(dāng)M1、M0設(shè)定為“11”時(shí),定時(shí)器工作于工作方式3,此時(shí)定時(shí)計(jì)數(shù)器的內(nèi)部結(jié)構(gòu)如圖所示。

模式3控制結(jié)構(gòu)

在這種工作方式下T0被拆分成了兩個(gè)獨(dú)立的8位計(jì)數(shù)器TH0和TL0,TL0使用T0本身的控制和中斷資源,而TH0則占用了T1的TR1和TF1作為啟動(dòng)控制位和溢出標(biāo)志。在這種情況下,T1將停止運(yùn)行并且其數(shù)據(jù)寄存器將保持當(dāng)前數(shù)值,所以設(shè)置T0為工作方式3也可以代替復(fù)位TR1來關(guān)閉T1定時(shí)計(jì)數(shù)器。

51單片機(jī)定時(shí)器中斷

51系列單片機(jī)內(nèi)部集成了兩個(gè)定時(shí)器/計(jì)數(shù)器,分別提供了兩個(gè)定時(shí)中斷源:TF0和TF1。

TF0中斷,定時(shí)器/計(jì)數(shù)器0中斷請求,其中斷請求號為1。

TF1中斷,定時(shí)器/計(jì)數(shù)器1中斷請求,其中斷請求號為3。

51單片機(jī)的斷控制寄存器IE中的EA位和ET0/ET1都被置“1”時(shí),定時(shí)計(jì)數(shù)器0/1的中斷被使能,在這種狀態(tài)下,如果定時(shí)計(jì)數(shù)器0/1出現(xiàn)一個(gè)計(jì)數(shù)溢出事件,則會觸發(fā)定時(shí)計(jì)數(shù)器中斷事件??梢酝ㄟ^修改中斷優(yōu)先級寄存器IP中的PT0/PT1位來提高定時(shí)計(jì)數(shù)器的中斷優(yōu)先級,MCS-51單片機(jī)的定時(shí)計(jì)數(shù)器的中斷處理函數(shù)的結(jié)構(gòu)如下:

void 函數(shù)名(void) interrupt ?中斷向量號 (using 工作組寄存器)

{

????//中斷代碼

}

51單片機(jī)定時(shí)器計(jì)數(shù)功能應(yīng)用

現(xiàn)在我們設(shè)計(jì)一個(gè)簡單的電路來實(shí)踐一下定時(shí)器的使用方法。

電路示例

如圖所示的電路中我們將T0對應(yīng)的外部脈沖引腳連接一個(gè)按鍵K5,用來測試定時(shí)器的計(jì)數(shù)功能。

普通計(jì)數(shù)器:P3.4電平變化后計(jì)數(shù)器累加,如果將計(jì)數(shù)初值設(shè)置為0xff,則每按鍵一次后計(jì)數(shù)器都會溢出,標(biāo)志位就會置位,程序中通過掃描計(jì)數(shù)器標(biāo)志位狀態(tài)來切換數(shù)字。

/*

*這是一個(gè)定時(shí)器計(jì)數(shù)應(yīng)用程序

*目的是運(yùn)用定時(shí)器計(jì)數(shù)功能進(jìn)行捕獲計(jì)數(shù)

*/


#include <reg52.h>

#include <intrins.h>


typedef unsigned char u8;

typedef unsigned int ?u16;


u8 data_L,data_H;

u8 num = 0;


u8 code num_codelist[10] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};


void delay(u8 ms);

void count_func(void);

void data_init(void);

void T0_init(void);

void display(void);


void main(void)

{

T0_init();


while(1)

{

count_func();

data_init();

display();

}

}



void delay(u8 ms)

{

? ? u8 i,j;


? ? for(i=0; i<ms; i++)

? ? {

? ? ? ? for(j=0; j<110; j++)

? ? ? ? {

? ? ? ? ? ? ;

? ? ? ? }

? ? }

}


void data_init(void)

{

? ? data_L = num%10;

? ? data_H = num/10;

}



void display(void)

{

P2 = 0xfe;

P0 = num_codelist[data_H];

delay(1);


P2 = 0xfd;

P0 = num_codelist[data_L];

delay(1);

}



void count_func(void)

{

????//查詢標(biāo)志位

????if(1 == TF0) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

? ? {

? ? ? ? TH0 = 0xff; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? TL0 = 0xff;

? ? ? ? if(20 == num)

? ? ? ? {

? ? ? ? ? ? num = 0;

? ? ? ? }

? ? ? ? else

? ? ? ? {

? ? ? ? ? ? num++;

? ? ? ? }

? ? ? ? TF0 = 0;

? ? }

}



void T0_init(void)

{

//設(shè)置定時(shí)器0為模式2

TMOD = 0x05; ?

??????//設(shè)置計(jì)數(shù)初值(模式2具備自動(dòng)重裝)

TH0 = 0xff;

TL0 = 0xff;

? ? ? //中斷使用設(shè)置,這里只啟用定時(shí)器不使用中斷功能

? ? ? ET0=0;

TR0 = 1;

EA = 0;

}


中斷計(jì)數(shù)器:這里的操作原理與以上普通程序相似,只是啟用了中斷,就不用進(jìn)行循環(huán)掃描操作了,定時(shí)器中斷進(jìn)行計(jì)數(shù),捕獲P3.4電平變化后計(jì)數(shù)器加1,當(dāng)數(shù)據(jù)寄存器數(shù)值溢出后產(chǎn)生中斷,在中斷中處理程序功能即可。


/*

*這是一個(gè)定時(shí)器中斷計(jì)數(shù)應(yīng)用程序

*目的是運(yùn)用定時(shí)器中斷功能進(jìn)行計(jì)數(shù)

*/


#include <reg52.h>

#include <intrins.h>


typedef unsigned char u8;

typedef unsigned int ?u16;


u8 data_L,data_H;

u8 num = 0;


u8 code num_codelist[10] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};


void delay(u8 ms);

//void count_func(void);

void data_init(void);

void T0_init(void);

void display(void);


void main(void)

{

T0_init();


while(1)

{

data_init();

display();

}

}



void delay(u8 ms)

{

? ? u8 i,j;


? ? for(i=0; i<ms; i++)

? ? {

? ? ? ? for(j=0; j<110; j++)

? ? ? ? {

? ? ? ? ? ? ;

? ? ? ? }

? ? }

}



void data_init(void)

{

? ? data_L = num%10;

? ? data_H = num/10;

}



void display(void)

{

P2 = 0xfe;

P0 = num_codelist[data_H];

delay(1);


P2 = 0xfd;

P0 = num_codelist[data_L];

delay(1);

}



void T0_init(void)

{

//設(shè)置定時(shí)器0為模式2

TMOD = 0x05; ?

//設(shè)置計(jì)數(shù)初值

TH0 = 0xff;

TL0 = 0xff;

//中斷使用設(shè)置,啟用中斷

ET0 = 1;

TR0 = 1;

EA = 1;

}



//void count_func(void)

//{

// if(1 == TF0) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //查詢是否溢出

// ? ?{

// ? ? ? ?TH0 = 0xff; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//重新賦值

// ? ? ? ?TL0 = 0xff;

// ? ? ? ?if(99 == num)

// ? ? ? ?{

// ? ? ? ? ? ?num = 0;

// ? ? ? ?}

// ? ? ? ?else

// ? ? ? ?{

// ? ? ? ? ? ?num++;

// ? ? ? ?}

// ? ? ? ?TF0 = 0;

// ? ?}

//}



void count_func(void) interrupt 1

{

//重新賦值

TH0 = 0xff; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

TL0 = 0xff;

// //中斷中此位會硬件清零,這句可以不用寫

// TF0 = 0;

// ? ?//這里相當(dāng)于對按鍵進(jìn)行消抖,實(shí)際使用時(shí)酌情使用

// ? ?delay(15);

//查詢外部輸入脈沖變化

? ? if(0 == T0) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

? ? {

? ? ? ? if(20 == num)

? ? ? ? {

? ? ? ? ? ? num = 0;

? ? ? ? }

? ? ? ? else

? ? ? ? {

? ? ? ? ? ? num++;

? ? ? ? }

? ? }

}

這兩個(gè)程序很大一部分都是相同的,不同之處在于計(jì)數(shù)處理部分,第一個(gè)程序沒有使用中斷,我們定義了一個(gè)void count_func(void),第二個(gè)程序中我們使用了定時(shí)器中斷,中斷函數(shù)就是void count_func(void) interrupt 1。程序的主要區(qū)別就在于這兩個(gè)函數(shù)void count_func(void)是普通函數(shù)需要定義,說明,調(diào)用,而void count_func(void) interrupt 1是中斷函數(shù)它只需要定義就行。另外兩函數(shù)功能差異就是我們剛所講到的,一個(gè)是在主函數(shù)循環(huán)中不斷掃描寄存器標(biāo)志位,一個(gè)是中斷中查詢引腳狀態(tài)。其他程序段都是比較簡單易懂的吧,這里簡單說明一下:void data_init(void)這個(gè)函數(shù)是對顯示數(shù)據(jù)進(jìn)行個(gè)位與十位處理的。void display(void)這個(gè)函數(shù)是數(shù)碼管顯示處理函數(shù),前面講數(shù)碼管時(shí)是介紹過了,這里只是把它打包成一個(gè)函數(shù)了。void T0_init(void)這個(gè)函數(shù)是定時(shí)器T0的初始化函數(shù),里面包括定時(shí)器的模式,計(jì)數(shù)初值,中斷等設(shè)置內(nèi)容。以上程序不理解的可以留言或參考資料分析一下。最后再來看一下電路仿真情況。

仿真結(jié)果

兩個(gè)程序?qū)崿F(xiàn)的功能都是一樣的,現(xiàn)在想想定時(shí)器使用計(jì)數(shù)功能時(shí)中斷作用通過一些特殊處理(比如我們這里將計(jì)數(shù)初值設(shè)置為最大值0xff)是不是和前面講的外部引腳P3.3和P3.4的中斷就很相似了,按鍵按一下就會產(chǎn)生中斷。所以如果某些程序需要多個(gè)外部中斷而單片機(jī)沒有那么多中斷引腳時(shí)不妨可以使用這種方式來增加單片機(jī)功能。當(dāng)然這都是題外話,等你真正做開發(fā)時(shí)很大概率是不會用這款單片機(jī)的,現(xiàn)在的單片機(jī)功能強(qiáng)大著呢!但這是一種開發(fā)者應(yīng)該具有的思維,也不是說你想到了某個(gè)法子就能派上用場,但平時(shí)積累一些“奇巧淫技”是有必要的,萬一哪天就用上了呢!或許你的一個(gè)軟件優(yōu)化就幫公司產(chǎn)品省去了一筆費(fèi)用,如果是一個(gè)月產(chǎn)n千或n萬,甚至更高產(chǎn)量的產(chǎn)品,那老板不給你加薪還給誰加薪呢。對于有這樣思維的,像對待自己孩子一樣對待工作的人,無論什么崗位,我認(rèn)為如果遇到了都值得成為合伙人,可以直接給股份,共創(chuàng)未來。這就是你的個(gè)人,從某種意義上來說,工作能力是職場的信譽(yù)值,信譽(yù)是市場硬通貨,信譽(yù)也是真正的財(cái)富密碼。打工時(shí)拿到好的工資是因?yàn)槔习逭J(rèn)可你所做工作,產(chǎn)品找明星代言,當(dāng)我們選擇它時(shí)很大可能是因?yàn)樾湃文莻€(gè)明星。對于信譽(yù)值達(dá)到一定程度的產(chǎn)品,它本身就成了一種信譽(yù),就像在股市你之所以買某只股票,很大的原因就是因?yàn)槟阊芯窟^了這家公司后得出你的信任這家公司這個(gè)結(jié)論。以上為我個(gè)人分析,當(dāng)然并不一定所有人(老板)都會這么想,但我認(rèn)為若真正信任員工,那雇傭關(guān)系轉(zhuǎn)換為具有規(guī)則契約的合作關(guān)系能取得更好成就,這是一種互信機(jī)制。這都是本人回顧曾經(jīng)“滄海”的產(chǎn)生的真實(shí)理念,但往事“不堪回首”,故事就不說了,以后有機(jī)會再交流,5年或許10年后我還會再來看這段話,或許到時(shí)我也早已不是“光桿司令”了。

51單片機(jī)定時(shí)器定時(shí)功能應(yīng)用

通過以上兩個(gè)例程各位對定時(shí)器計(jì)數(shù)功能應(yīng)該都能掌握了吧,想驗(yàn)證是否掌握最快的方法就是自己親自敲一遍代碼運(yùn)行一下,看結(jié)果是否相符,如果自己敲代碼后仿真運(yùn)行或在實(shí)驗(yàn)板上沒結(jié)果時(shí)記得對照程序好好檢查一下,看是哪里出了問題。

接下來我們繼續(xù)介紹定時(shí)器的定時(shí)功能。我們想來看一段代碼,可以嘗試一下在不看后面解析的情況下試試自己能否讀出程序的結(jié)果。

/*

*這是一個(gè)定時(shí)器定時(shí)應(yīng)用程序

*目的是運(yùn)用定時(shí)器定時(shí)模式進(jìn)行控制數(shù)碼管和LED顯示

*/


#include <reg52.h>

#include <intrins.h>


typedef unsigned char u8;

typedef unsigned int ?u16;


u8 data_L,data_H;

u8 T0_cnt = 0;

u8 T0_s = 0;

u8 T1_cnt = 0;

u8 crol = 0xfe;


u8 code num_codelist[10] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};


void delay(u8 ms);

void data_init(void);

void Timer_init(void);

void display(void);


void main(void)

{

Timer_init();

P1 = crol;


while(1)

{

data_init();

display();

}

}


void delay(u8 ms)

{

? ? u8 i,j;


? ? for(i=0; i<ms; i++)

? ? {

? ? ? ? for(j=0; j<110; j++)

? ? ? ? {

? ? ? ? ? ? ;

? ? ? ? }

? ? }

}


void data_init(void)

{

? ? data_L = T0_s%10;

? ? data_H = T0_s/10;

}


void display(void)

{

P2 = 0xfe;

P0 = num_codelist[data_H];

delay(1);


P2 = 0xfd;

P0 = num_codelist[data_L];

delay(1);

}


void Timer_init(void)

{

//使能中斷總開關(guān)

EA = 1; ? ? ? ? ?

// 使能定時(shí)器中斷

ET0 = 1; ? ?

ET1 = 1; ? ? ? ? ? ? ? ? ? ? ? ? ?

// 設(shè)置工作方式1

TMOD = 0x11; ? ? ? ? ? ? ? ? ? ? ??

// 設(shè)置定時(shí)器0定時(shí)時(shí)間50ms

TH0 = (65536-50000)/256; ? ? ? ? ?

TL0 = (65536-50000)%256; ? ? ? ? ?

// 設(shè)置定時(shí)器1定時(shí)時(shí)間50ms

TH1 = (65536-50000)/256; ? ? ? ? ?

TH1 = (65536-50000)%256; ? ? ? ? ??

// 設(shè)置控制寄存器:啟動(dòng)定時(shí)器

TR0 = 1; ? ? ? ? ? ? ? ? ? ? ? ? ?

TR1 = 1; ? ? ? ? ? ? ? ? ? ? ? ? ?

}


void T0_func(void) interrupt 1

{

//重新賦值

TH0 = (65536-50000)/256;

TL0 = (65536-50000)%256;


//計(jì)時(shí)1s

T0_cnt++;

if(20 == T0_cnt)

{

T0_cnt = 0;

T0_s++;

if(60 == T0_s)

{

T0_s = 0;

}

}


}


void T1_func(void) interrupt 3

{

//重新賦值

TH1 = (65536-50000)/256;

TL1 = (65536-50000)%256;


//計(jì)時(shí)0.5s

T1_cnt++;

if(5 == T1_cnt)

{

T1_cnt = 0;

//燈移位

crol = _crol_(crol,1);

P1 = crol;

}

}

這個(gè)程序的功能是使用定時(shí)T0定時(shí)控制數(shù)碼管每秒變化數(shù)字,利用定時(shí)器T1控制LED每秒移位點(diǎn)亮4個(gè)燈。

先看程序運(yùn)行的結(jié)果。

仿真結(jié)果

現(xiàn)在來分析一下程序,程序整體來說是非?;A(chǔ)的,很多都是出現(xiàn)過多次的程序段了,我們主要介紹一下幾個(gè)新的函數(shù)。

void Timer_init(void)這個(gè)函數(shù)是定時(shí)器T0和T1的初始化函數(shù),里面包含中斷控制位配置,數(shù)據(jù)寄存器初始化賦值以及定時(shí)器開關(guān)設(shè)置,這里將定時(shí)器T0和T1都設(shè)置為模式1,即16位定時(shí)器功能,這種模式下定時(shí)器數(shù)據(jù)寄存器沒有自動(dòng)重裝功能,所以在每次中斷之后要進(jìn)行賦初值操作,在定時(shí)器中斷中有這段代碼,計(jì)數(shù)通過前面內(nèi)容中的公式得出,這里是設(shè)置每50ms一次中斷。

計(jì)算初值這點(diǎn)肯定很多初學(xué)者不太理解,需要多看一下資料說明,原理其實(shí)很簡單,51單片機(jī)的計(jì)算器都是向上計(jì)數(shù)的,即從0~設(shè)置的定時(shí)器數(shù)據(jù)寄存器最大值,這里是16位所以就是0xffff(十進(jìn)制就是65535),當(dāng)計(jì)數(shù)到0xffff時(shí)再記一次這個(gè)數(shù)就溢出了,就產(chǎn)生了溢出中斷,這時(shí)在中斷函數(shù)中我們將數(shù)據(jù)寄存器程序重新賦值它又重頭開始進(jìn)行計(jì)數(shù),所以最大定時(shí)時(shí)間就是0xffff個(gè)機(jī)器周期,51單片機(jī)是一個(gè)機(jī)器周期為12個(gè)時(shí)鐘周期,如果使用12M晶振則剛好一個(gè)機(jī)器周期對應(yīng)為1us,如果我們只需定時(shí)1us數(shù)據(jù)寄存器中就賦值0xffff,即65536-1,,經(jīng)過一個(gè)機(jī)器周期就會產(chǎn)生中斷了,如果定時(shí)2us,則設(shè)置為65536-2,其他的數(shù)值以此類推。

void T0_func(void) interrupt 1這個(gè)函數(shù)是定時(shí)器0的中斷函數(shù),首先對定時(shí)器數(shù)據(jù)寄存器進(jìn)行賦初值然后設(shè)置一個(gè)1秒的累加技術(shù)操作,使得變量T0_s在每一秒計(jì)時(shí)之后加一,加到60s時(shí)進(jìn)行清零,之后再循環(huán)計(jì)數(shù),數(shù)碼管將顯示當(dāng)前秒數(shù)值。

void T1_func(void) interrupt 3這個(gè)函數(shù)是定時(shí)器T1中斷函數(shù),這里設(shè)置一個(gè)0.25s的時(shí)間進(jìn)行LED點(diǎn)亮移位操作。

這個(gè)程序的主要內(nèi)容就分享到這里,有不懂的朋友可以及時(shí)留言,這樣也可以和大家一起分析心中疑惑。

結(jié)語:

51單片機(jī)的定時(shí)器是一個(gè)很重要的內(nèi)容,對于其他單片機(jī)也一樣,定時(shí)器是項(xiàng)目開發(fā)中無可或缺的一部分,它的使用也是非常的靈活,所以一定要熟練使用。

上一節(jié)矩陣按鍵的參考測試代碼見推送的第二篇文章內(nèi)容。

加上代碼這又是一篇萬字長文,碼字不易,看過的朋友如果感覺有用歡迎轉(zhuǎn)發(fā),收藏或點(diǎn)贊,感謝支持!


51單片機(jī)編程開發(fā)(七)之定時(shí)器與定時(shí)器中斷的評論 (共 條)

分享到微博請遵守國家法律
木兰县| 海门市| 拉孜县| 南宫市| 大新县| 渝中区| 溆浦县| 南靖县| 岢岚县| 霍城县| 广安市| 鄂州市| 滨海县| 琼中| 景谷| 罗定市| 金寨县| 望都县| 长顺县| 临颍县| 马公市| 桓台县| 呼图壁县| 南漳县| 广安市| 麻江县| 五常市| 嵊州市| 保山市| 南皮县| 鹰潭市| 冕宁县| 中超| 安图县| 安陆市| 镇坪县| 泊头市| 闵行区| 宜丰县| 盐津县| 府谷县|