找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 21809|回復(fù): 4
打印 上一主題 下一主題
收起左側(cè)

單片機(jī)定時(shí)器利用中斷實(shí)現(xiàn)延時(shí)原理解析

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主

  1. #define _1231_C_

  2. #include "reg51.h"

  3. //sbit OE=P2^3;

  4. unsigned int SystemTime;

  5. void timer0(void) interrupt 1 using 3 //中斷部分代碼,見(jiàn)下文的釋疑

  6. {

  7.     TH0 = 0xdb;

  8.     TL0 = 0xff;

  9. //    TF0 = 0;

  10.     SystemTime++;

  11. }

  12. void main()

  13. {

  14.     TMOD &= 0xF0;

  15.     TMOD |= 0x01; //TMOD的值表示定時(shí)器工作方式選擇

  16.     TH0 = 0xdb; //寫(xiě)入初始值,初始值可以決定定時(shí)多久

  17.     TL0 = 0xff;

  18. //根據(jù)下文的木桶比喻的話,如果TH0 = 0x00;TL0 = 0x00;則表示從桶底開(kāi)始裝水。

  19. //TH0 = 0xdb;TL0 = 0xff;可以這樣子理解相當(dāng)于木桶里已經(jīng)有部分液鉛在里面,

  20. //TH0和TL0這個(gè)兩個(gè)值表示木桶里液鉛的高度,即此時(shí)桶里只能從液鉛的高度以上開(kāi)始裝水,

  21. //TH0 = 0xff;TL0 = 0xff;即表示桶的最高位置.

  22.     TF0 = 0; //計(jì)數(shù)到時(shí)TF0為1,即當(dāng)TH0 = 0xff;TL0 = 0xff;再運(yùn)行一步TF0 = 1;

  23.     TR0 = 1; //開(kāi)始計(jì)數(shù),從這時(shí)起,每運(yùn)行一步TH0和TL0都會(huì)增加,直到TH0 = 0xff;TL0 = 0xff;

  24.                  //相當(dāng)于開(kāi)水龍頭,如TR0=0則TH0和TL0不變

  25.     ET0 = 1; //允許定時(shí)器0中斷

  26.     EA=1;   //開(kāi)總中斷

  27. //下面是個(gè)死循環(huán),程序里每運(yùn)行一步TH0和TL0都會(huì)增加,當(dāng)增加到TH0 = 0xff;TL0 = 0xff;

  28. //單片機(jī)會(huì)從死循環(huán)里退出,去執(zhí)行中斷部分的代碼,即開(kāi)始運(yùn)行void timer0(void) interrupt 1 using 3{}

  29. //運(yùn)行完中斷部分的代碼后,接著繼續(xù)執(zhí)行死循環(huán)里的代碼。

  30. //注意:當(dāng)TH0 = 0xff;TL0 = 0xff;再運(yùn)行,TF0并沒(méi)有從0變?yōu)?,個(gè)人猜測(cè)TF0=1;時(shí)觸發(fā)了中斷,并重新被置零。

  31. //如把ET0 = 1;和EA=1;注釋掉,當(dāng)TH0 = 0xff;TL0 = 0xff;再運(yùn)行,TF0會(huì)變?yōu)?,此時(shí)不會(huì)再執(zhí)行中斷部分代碼。

  32.     while(1)

  33.     {

  34.         if ((SystemTime%100)<50)       //SystemTime除以100,余數(shù)小于50為真

  35.         {

  36.           …………;

  37.         }

  38.         else

  39.         {

  40.              …………;

  41.         }

  42.     };

  43. }
復(fù)制代碼

釋疑:void Timer0() interrupt 1 using 1

Timer0   是函數(shù)名,隨便取的

interrupt   xx   using   y

跟在interrupt   后面的xx   值得是中斷號(hào),就是說(shuō)這個(gè)函數(shù)對(duì)應(yīng)第幾個(gè)中斷端口,一般在51中

0   外部中斷0   

1   定時(shí)器0

2   外部中斷1

3   定時(shí)器1

4   串行中斷

實(shí)際上編譯的時(shí)候就是把你這個(gè)函數(shù)的入口地址方到這個(gè)對(duì)應(yīng)中斷的跳轉(zhuǎn)地址

using   y   這個(gè)y是說(shuō)這個(gè)中斷函數(shù)使用的那個(gè)寄存器組,51里面一般有4組   r0   --   r7寄存器,一共有32個(gè),如果你的終端函數(shù)和別的程序用的不是同一個(gè)寄存器組則進(jìn)入中斷的時(shí)候就不會(huì)將寄存器組壓入堆棧返回時(shí)也不會(huì)談出來(lái)節(jié)省代碼和時(shí)間

初始值算法:定時(shí)器是當(dāng)總數(shù)達(dá)到FFFFH后產(chǎn)生中斷吧!那你要讓它計(jì)數(shù)10000,是不是用FFFF(16進(jìn)制)減去10000(十進(jìn)制)的數(shù)當(dāng)計(jì)數(shù)初值 ?TH0=-(10000/256); TL0=-(10000%256)跟FFFF(16進(jìn)制)減去10000(十進(jìn)制)的數(shù)是一樣的。從TH0=-(10000/256); TL0=-(10000%256)開(kāi)始計(jì)數(shù),計(jì)數(shù)到10000剛好滿。跟用FFFF(16進(jìn)制)減去10000(十進(jìn)制)的數(shù)一樣。!寫(xiě)起來(lái)更簡(jiǎn)單,不 用算。!

看看原碼、補(bǔ)碼就知道。正數(shù)的補(bǔ)碼是對(duì)應(yīng)的二進(jìn)制數(shù),符號(hào)位為零,負(fù)數(shù)的補(bǔ)碼是它的絕對(duì)值對(duì)應(yīng)的二進(jìn)制數(shù)按位取反再加一,符號(hào)位為一。無(wú)符號(hào)數(shù)不考慮符號(hào),那么這個(gè)結(jié)果就跟用FFFF減去它的絕對(duì)值一樣

我們學(xué)習(xí)了用指令延時(shí)閃燈,但是用指令方式閃燈有cpu不能做其他工作的缺點(diǎn)。

這一課,我們將學(xué)習(xí)如何使用定時(shí)器方式使燈閃爍。

中斷的理解。

這里將涉及到單片機(jī)中斷的應(yīng)用,在cpu的一步步按照指令運(yùn)行的過(guò)程中(主程序),可能會(huì)有其它的更緊急的需要做的事情(中斷服務(wù)程序),需要cpu暫時(shí)停止當(dāng)前的程序(主程序),做完了(中斷服務(wù)程序)之后,又可以繼續(xù)去運(yùn)行先前的程序(主程序)。就像你正在吃飯,一邊又在給水桶里放水,吃著吃著,水滿了,你就得趕快去把水龍頭關(guān)掉或者換一個(gè)空的水桶,再回來(lái)吃飯。

單片機(jī)的定時(shí)器就像是一個(gè)水桶,你讓它啟動(dòng)了,也就是水龍頭打開(kāi)了;開(kāi)始裝水了;定時(shí)在每個(gè)機(jī)器周期不斷自動(dòng)加1,最后溢出了;水桶的水不斷增加,最也就滿出來(lái)了;定時(shí)器溢出時(shí),你就要去做處理了;水桶的水滿了,你也應(yīng)該處理一下了;處理完后,單片機(jī)又可以回到剛剛開(kāi)停止的地方繼續(xù)運(yùn)行;水桶處理了,先前你在做什么也可以繼續(xù)去做什么了。

單片機(jī)的主程序是從0x0000開(kāi)始運(yùn)行的,單片機(jī)服務(wù)程序從哪里開(kāi)始運(yùn)行呢?在51里,有多個(gè)中斷服務(wù)程序入口,0號(hào)入口是外中斷0,地址在0x0003;1號(hào)入口是定時(shí)器0,在 0x000B;2號(hào)入口是外中斷1;地址在0x0013,3號(hào)入口是定時(shí)器2;地址在0x001B,等等。當(dāng)中斷發(fā)生時(shí),程序就記下當(dāng)前運(yùn)行的位置,跳到對(duì)應(yīng)的中斷入口去運(yùn)行中斷服務(wù)程序,運(yùn)行完之后,又跳回到原來(lái)的位置繼續(xù)運(yùn)行。

在C51中,你不用理會(huì)中斷服務(wù)程序放在哪里,會(huì)怎么跳轉(zhuǎn)。你只要把某個(gè)函數(shù)標(biāo)識(shí)為幾號(hào)中斷服務(wù)函數(shù)就可以了。在發(fā)生了對(duì)應(yīng)的中斷時(shí),就會(huì)自動(dòng)的運(yùn)行這個(gè)函數(shù)。

請(qǐng)看一下相關(guān)的51的硬件的書(shū),對(duì)定時(shí)器工作的寄存器設(shè)置做進(jìn)一步的了解。也可以做完試驗(yàn)再了解,因?yàn)槔讨卸家呀?jīng)為您設(shè)置好了。

請(qǐng)看程序,主程序里的循環(huán)里是個(gè)死循環(huán),什么也沒(méi)有做,在實(shí)際應(yīng)用中這里是放的主程序。

在定時(shí)器服務(wù)函數(shù)里,需要重新置入定時(shí)器的值,這樣才能保證每次溢出時(shí),都是你指定的時(shí)間。這里置入的是0x0006,還需要走 0x10000-0x0006個(gè)機(jī)器周期才溢出。換成10進(jìn)制也就是每65530個(gè)機(jī)器周期中斷一次。我們仿真的晶振是22118400HZ,每12個(gè)時(shí)鐘一個(gè)機(jī)器周期。65530×12/22118400=0.036秒。也就是差不多28HZ的閃爍頻率。

因?yàn)?1的定時(shí)器最大只有0xffff,溢出的速度很快,無(wú)法做出更久的閃爍頻率來(lái),這一課就先觀察一下這個(gè)28HZ左右頻率。在下一課我們會(huì)用靜態(tài)變量的辦法,做一個(gè)長(zhǎng)達(dá)1秒鐘的LED閃爍頻率。

另外,由于51從中斷發(fā)生到進(jìn)入中斷的時(shí)間不定,是3至8個(gè)機(jī)器周期,我們?cè)谶M(jìn)入了中斷后才重新置新的定時(shí)器初始值,這樣就會(huì)存在定時(shí)誤差。也就是不是精確定時(shí),如果要精確定時(shí),需要使用定時(shí)器自動(dòng)裝載方式,也就是在定時(shí)器溢出的同時(shí),硬件邏輯就自動(dòng)把定時(shí)器初始值裝載進(jìn)去了,而不是在中斷服務(wù)程序里賦初始值,這樣就可以實(shí)現(xiàn)精確定時(shí),誤差只出現(xiàn)晶振的頻率上。現(xiàn)在請(qǐng)仔細(xì)研究一下程序,并編譯,進(jìn)入仿真,全速運(yùn)行,觀察運(yùn)行結(jié)果。我們可以看到P10上的LED在快速閃爍。


評(píng)分

參與人數(shù) 1黑幣 +2 收起 理由
qjzyx + 2 贊一個(gè)!

查看全部評(píng)分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享淘帖 頂2 踩

相關(guān)帖子

回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:233461 發(fā)表于 2017-9-16 11:31 | 只看該作者
多謝大神解析
回復(fù)

使用道具 舉報(bào)

板凳
ID:47634 發(fā)表于 2018-2-14 12:56 | 只看該作者
講的很好很通俗,很好理解,謝謝了
回復(fù)

使用道具 舉報(bào)

地板
ID:266116 發(fā)表于 2018-2-14 15:57 | 只看該作者
謝謝分享
回復(fù)

使用道具 舉報(bào)

5#
ID:382878 發(fā)表于 2019-1-12 15:25 | 只看該作者
很詳細(xì),感謝大神分享
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表