中斷是單片機系統(tǒng)的重點中的重點_第1頁
中斷是單片機系統(tǒng)的重點中的重點_第2頁
中斷是單片機系統(tǒng)的重點中的重點_第3頁
中斷是單片機系統(tǒng)的重點中的重點_第4頁
中斷是單片機系統(tǒng)的重點中的重點_第5頁
已閱讀5頁,還剩9頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、中斷是單片機系統(tǒng)的重點中的重點 , 因為有了中斷, 單片機C 語言的數(shù)組 6.1.1 數(shù)組的差不多概念我們第四章學(xué)過變量的差不多類型, 比如 char 、 int 等等。 這種類型描述的數(shù)據(jù)是比較有限的, 當(dāng)我們要處理特別大量數(shù)據(jù)的時候, 就能夠用到數(shù)組了, 比如我 們上節(jié)課的那個數(shù)碼管的真值表,我們就能夠用一個數(shù)組來表達。從概念上講, 數(shù)組是具有相同數(shù)據(jù)類型的有序數(shù)據(jù)的組合, 一般來講, 數(shù)組定義 后滿足以下三個條件。具有相同的數(shù)據(jù)類型;具有相同的名字;在存儲器中是被連續(xù)存放的。比如我們上節(jié)課定義的那個數(shù)碼管真值表, 假如我們把關(guān)鍵字code 去掉,數(shù)組元素將被保存在RAMfr,在程序中可讀

2、可寫,同時我們也能夠在中括號里邊 標(biāo)明那個數(shù)組元素的個數(shù),比如:unsigned char LedChar16 = 0 xC0,0 xF9,0 xA4,0 xB0,0 x99,0 x92,0 x82,0 xF8, 0 x80,0 x90,0 x88,0 x83,0 xC6,0 xA1,0 x86,0 x8e; 在那個數(shù)組中的每個值都稱之為數(shù)組的一個元素, 這些元素都具備相同的數(shù)據(jù)類 型確實是unsigned char型,他們有一個共同的名字 LedChar,不管放到RAMfr 依舊FLASHY,他們基本上存放在一塊連續(xù)的存儲空間里的。有一點要特別注意,那個數(shù)組一共有16中括號里面的數(shù)值個元素,

3、然而數(shù)組的元素的表達方式下標(biāo)是從0 開始,因此實際上上邊那個數(shù)組的首個元素LedChar0的值是0 xC0,而LedChar15的值是0 x8e,下標(biāo)從0至U 15一共是16 個元素。LedChar那個數(shù)組只有一個下標(biāo),我們稱之為一維數(shù)組,還有兩個下標(biāo)或者多個下標(biāo)的,我們稱之為多維數(shù)組。比如 unsigned char a23; 表示這是一個2行 3 列的二維數(shù)組。 在大多數(shù)情況下我們使用的是一維數(shù)組, 關(guān)于初學(xué)來說, 我 們先來研究一維數(shù)組,多維數(shù)組遇到了再了解。.2 數(shù)組的聲明一維數(shù)組的聲明格式如下:數(shù)據(jù)類型數(shù)組名 數(shù)組長度;(1) 數(shù)組的數(shù)據(jù)類型聲明的是該數(shù)組的每個元素的類型,即一個數(shù)組

4、中的元素具有相同的數(shù)據(jù)類型。數(shù)組名的聲明要符合C語言固定的標(biāo)識符的聲明要求,只能由字母、數(shù)字、 下劃線這三種符號組成,且第一個字符只能是字母或者下劃線。(3) 方括號中的數(shù)組長度是一個常量或常量表達式,同時必須是正整數(shù)。6.1.3 數(shù)組的初始化數(shù)組在進行聲明的同時能夠進行初始化操作,格式如下:數(shù)據(jù)類型數(shù)組名 數(shù)組長度 = 初值列表 ;依舊以上節(jié)課我們用的數(shù)碼管的真值表為例來講解考前須知。unsigned char LedChar16 = 0 xC0,0 xF9,0 xA4,0 xB0,0 x99,0 x92,0 x82,0 xF8, 0 x80,0 x90,0 x88,0 x83,0 xC6,

5、0 xA1,0 x86,0 x8e; (1) 初值列表里的數(shù)據(jù)之間要用逗號隔開。初值列表里的初值的數(shù)量必須小于或者等于數(shù)組長度,當(dāng)小于數(shù)組長度時,數(shù)組的后邊沒有賦初值的元素由系統(tǒng)自動賦值0。假設(shè)給數(shù)組的所有元素賦初值,能夠省略數(shù)組的長度,上節(jié)課的例子中我們實際上差不多省略了數(shù)組的長度。系統(tǒng)為數(shù)組分配連續(xù)的存儲單元的時候, 數(shù)組元素的相對次序由下標(biāo)來決定,確實是說 LedChar0 、 LedChar1LedChar15 是按照順序排下來的。6.1.4 數(shù)組的使用和賦值在 C 語言程序中,是不能一次使用整個數(shù)組的, 只能使用單個數(shù)組元素。 一個數(shù)組元素相當(dāng)于一個變量, 使用數(shù)組元素的時候與使用相

6、同數(shù)據(jù)類型的變量的方法一樣。比如那個LedChar那個數(shù)組,假如沒加code關(guān)鍵字,那么它可讀可寫,我們能夠?qū)懗蒩 = LedChar0 如此來把數(shù)組的一個元素的值送個a 那個變量,也能夠?qū)懗蒐edChar0 = a 如此把 a 那個變量的值送給數(shù)組的一個元素,以下* 1 、三點要注意:引用數(shù)組的時候,那個方括號里的數(shù)字代表的是數(shù)組元素的下標(biāo),而數(shù)組初始化的時候方括號里的數(shù)字代表的是那個數(shù)組元素的個數(shù)。數(shù)組元素的方括號里的下標(biāo)能夠是整型常數(shù),整型變量或者表達式,而數(shù)組初始化的時候方括號里的數(shù)字必須是常數(shù)不能是變量。數(shù)組整體賦值只能夠在初始化的時候操作,功能程序只能對單個元素賦值。if 語句if

7、 語句差不多不陌生了,前邊程序我們事實上差不多用過了,那個地方我們系統(tǒng)的介紹一下,方便后邊的深入學(xué)習(xí)。 if 語句有兩個關(guān)鍵字: if 和 else ,把這兩個關(guān)鍵字翻譯一下確實是:“假如”和“否那么”。 if 語句一共有三種格式,我們分別來看。f 語句的默認形式。if ( 條件表達式 ) 語句 1;其執(zhí)行過程是, if( 假如 ) 條件表達式的值為“真”,那么執(zhí)行語句 1;假如條件表達式的值為“假”,那么不執(zhí)行語句1。真和假的概念不再贅述,參考第五章。那個地方要提醒一句,C語言一個分號表示一句語句的結(jié)束,因此假如if后邊只有一條執(zhí)行語句的時候, 能夠省略大括號, 然而假如有多條執(zhí)行語句的話,

8、必須加上大括號。我們上節(jié)課的語句就很好理解了 if(16 =j) j = 0; ,假如 j 等于 16的時候,括號里的值才是“真”,那么就執(zhí)行j=0 這一句,假如 j 不等于16,那么里邊就為“假”,就不執(zhí)行這一句。f.else語句有些情況下,我們除了判斷一下if 括號里的是否滿足條件,執(zhí)行相應(yīng)的語句, 在不滿足條件的時候, 我們又要執(zhí)行另外相應(yīng)的語句, 那個時候就用到了if.else語句,它的差不多的語法形式是:if ( 條件表達式 )語句 1;else語句 2;比如上節(jié)課的后半段程序我們也能夠?qū)懗桑篜0 = LedCharj;/ 把數(shù)組里的對應(yīng)值送給P0if(15 = j)/ 當(dāng)顯示到 F

9、 后,歸0 重新開始j = 0; elsej+;那個程序大伙能夠改改下載進去試試,程序邏輯大伙自己動腦分析一下,我就不解釋了。f else if語句if.esle語句是一個二選一的語句,或者執(zhí)行if 條件下的語句,或者執(zhí)行 else 條件下的語句。 還有一種多項選擇一的用法確實是if.elseif 語句。他的差不多語法格式是:if ( 條件表達式 1) 語句 1;else if (條件表達式2)語句2; else if (條件表達式3)語句3; else語句 n;他的執(zhí)行過程是:依次判斷條件表達式的值,當(dāng)出現(xiàn)某個值為“真”時,那么執(zhí)行相對應(yīng)的語句,然后跳出整個if的語句塊,執(zhí)行“語句n”后邊的

10、程序;假 如所有的表達式都為“假”,那么執(zhí)行“語句 n”后,再執(zhí)行“語句n”后邊的 程序。if語句在C語言編程的過程中使用頻率很高,用法也簡單,因此必須要熟練學(xué)握。switch 語句用 ifelse 語句在處理多分支的時候,分支太多就會顯得不方便,且容易出現(xiàn)if和else配對出現(xiàn)錯誤的情況,在C語言中提供了另外一種多分支選擇的語句 switch 語句,它的差不多語法格式如下:switch ( 表達式 )case 常量表達式1:執(zhí)行語句1;case 常量表達式2:執(zhí)行語句2; case常量表達式n:執(zhí)行語句n;default:執(zhí)行語句 n+1;它的執(zhí)行過程是:首先計算“表達式”的值,然后從第一個

11、case 開始,與“常量表達式 x ”進行比較,假如與當(dāng)前常量表達式的值不相等,那么就不執(zhí)行冒號后邊的程序, 一旦發(fā)明和一個常量表達式的值相等了, 那么他會執(zhí)行之后所有的,注意是所有的“執(zhí)行語句”,顯然這不是我們想要的結(jié)果。在 C 語言中, 有一條 break 語句, 作用是跳出當(dāng)前循環(huán)語句, 不管是 for 和 while循環(huán), 依舊 switch 循環(huán), 都能夠用其搭配使用跳出循環(huán)。 switch 語句一共有n+1種可能, 而我們盼望要的是一條多項選擇一的語句, 只執(zhí)行其中一條然后直截了當(dāng)退出該循環(huán), 不再執(zhí)行下邊的任何語句,那個時候就需要用到 break 語句, 比如我們在 switch

12、 表達式上加上break 語句,如下:switch ( 表達式 )case 常量表達式1:執(zhí)行語句1; break ;case 常量表達式2:執(zhí)行語句2; break ;case 常量表達式 n:執(zhí)行語句 n; break;default: 語句 n+1;加了那個 break 語句后,一旦“常量表達式 x ”與“表達式”相等了,那就執(zhí)行“執(zhí)行語句x”,執(zhí)行完畢后,由于有了 break,直截了當(dāng)跳出switch語句,執(zhí) 行 switch 語句循環(huán)后邊的程序了,如此就能夠幸免執(zhí)行不必要的語句。了解了那個 switch 語句,我們將會在本章程序中使用鞏固。數(shù)碼管的動態(tài)顯示6.4.1 動態(tài)顯示的差不多

13、原理我們在上一章學(xué)習(xí)數(shù)碼管靜態(tài)顯示的時候說到,74HC138只能在同一時刻導(dǎo)通一個三極管, 而我們的數(shù)碼管是靠了 6 個三極管來操縱, 那我們?nèi)绾蝸碜寯?shù)碼管同時顯示呢?這就用到了我們這節(jié)課的動態(tài)顯示。多個數(shù)碼管顯示數(shù)字的時候, 我們實際上是輪流點亮數(shù)碼管 一個時刻內(nèi)只有一個數(shù)碼管是亮的,利用人眼的視覺暫留現(xiàn)象也叫余輝效應(yīng),就能夠做到看起來是所有數(shù)碼管都同時亮了,這確實是動態(tài)掃描顯示的含義。例如:我們有2 個數(shù)碼管,我們要顯示“ 12”那個數(shù)字,讓高位的位選三極管導(dǎo)通,然后給它賦值“1”,延時一定時間后讓低位的位選三極管導(dǎo)通,然后給它賦值“2”。把那個流程以一定的速度循環(huán)運行就能夠讓數(shù)碼管顯示出

14、“12”,由于交替速度特別快,人肉眼識別到的確實是“12”那個數(shù)字。那么一個數(shù)碼管需要點亮多長時間呢?也確實是說要多長時間完成一次全部數(shù)碼管的掃描呢 很明顯: 整體掃描時間=單個數(shù)碼管點亮?xí)r間*數(shù)碼管個數(shù)?答案是:10ms以內(nèi)。當(dāng)電視機和顯示器還處在 CRT電子顯像管時代時,有一句 很流行的廣告語一一“ 100Hz無閃爍,沒錯,只要刷新率大于100Hz,即刷新時間小于10ms就能夠做到無閃爍,這也確實是我們的動態(tài)掃描的硬性指標(biāo)。那么你也許會問, 有最小值的限制嗎?理論上沒有, 但實際上做到更快的刷新卻沒有任何進步的意義了, 因為差不多無閃爍了, 再快也依舊無閃爍, 只是徒然增加CPU勺負荷而已

15、因為1秒內(nèi)要執(zhí)行更多次的掃描程序。因此,通常我們設(shè)計程序的時候,基本上取一個接近10ms又比較規(guī)整的值就行了。我們板子上有 6 個數(shù)碼管,我們下面用程序來驗證一下數(shù)碼管動態(tài)顯示程序。#include / 包含寄存器的庫文件sbitADDR0= P1A0;sbitADDR1= P1A1;sbitADDR2= P1A2;sbitADDR3= P1A3;sbitENLED= P1A4;unsigned char code LedChar = /用數(shù)組來表示數(shù)碼管真值表0 xC0,0 xF9,0 xA4,0 xB0,0 x99,0 x92,0 x82,0 xF8,0 x80,0 x90,0 x88,0

16、 x83,0 xC6,0 xA1,0 x86,0 x8e,;void main() unsigned int counter = 0;unsigned char j = 0;unsigned long stopwatch = 0;unsigned char LedNumber6 = 0;ENLED = 0; ADDR3 = 1;P0 = 0XFF;74HC138和P0初始化部分TMOD = 0 x01; / 設(shè)置定時器0 為模式 1TH0= 0 xFC;TL0= 0 x67; / 定時值初值, 定時 1msTR0 = 1;/ 打開定時器0while(1) if(1 = TF0) TF0 = 0

17、;TH0 = 0 xFC;TL0 = 0 x67; counter+;if(1000 = counter) 達到 50 次counter = 0; stopwatch+;/ 秒表數(shù)值一秒加 1LedNumber0LedNumber1LedNumber2LedNumber3 管顯示值計算LedNumber4LedNumber5 if (0=j)/ 判斷定時器0 是否溢出/ 一旦溢出后,重新賦值/ 判斷定時器0 溢出是否/stopwatch%10;stopwatch/10%10;stopwatch/100%10;stopwatch/1000%10; / 數(shù)碼stopwatch/10000%10;s

18、topwatch/100000%10; ADDR0=0; ADDR1=0; ADDR2=0; j+;P0=LedCharLedNumber0; else if (1=j) ADDR0=1; ADDR1=0; ADDR2=0; j+;P0=LedCharLedNumber1; else if (2=j) ADDR0=0; ADDR1=1; ADDR2=0; j+;P0=LedCharLedNumber2; else if (3=j) ADDR0=1; ADDR1=1; ADDR2=0; j+;P0=LedCharLedNumber3; else if (4=j) ADDR0=0; ADDR1=0

19、; ADDR2=1; j+;P0=LedCharLedNumber4; else if (5=j) ADDR0=1; ADDR1=0; ADDR2=1; j=0;P0=LedCharLedNumber5; / 數(shù)碼管動態(tài)刷新部分這程序,大伙自己抄到 Keil 中,然后邊抄邊理解,最終下載到實驗板上實驗一下效果。其中下邊的if.else 語句確實是每1ms快速的刷新一個數(shù)碼管,如此 6個數(shù)碼管整體刷新一遍的時間確實是 6ms,視覺上確實是6個數(shù)碼管無閃爍的 同時亮起來了。另外一個簡單知識點那個地方也提一下, 事實上屬于小學(xué)三年級知識, 然而許多同學(xué)剛接觸C語言,可能遇到了也會發(fā)懵。確實是在數(shù)碼管

20、顯示值計算那個地方,相信小學(xué)我們沒學(xué)小數(shù)之前,除法運算里邊有“被除數(shù)”、“除數(shù)”、“商”、“余數(shù)”這四個概念年。而在我們 C語言中,“ / ”等同于數(shù)學(xué)里的除法運算,而“ %”等同于我們小學(xué)學(xué)的求余數(shù)運算。假如是123456 那個數(shù)字,我們要正常顯示在數(shù)碼管上, 個位顯示, 確實是直截了當(dāng)對10 取余數(shù), 那個“ 6” 就出來了,十位數(shù)字確實是先除以10,然后再對10 取余數(shù),以此類推,就把6 個數(shù)字全部顯示出來了。關(guān)于多項選擇一的動態(tài)刷新數(shù)碼管的方式, 我們假如用 switch 會有更好的效果,大伙來看一下我們用 switch 語句完成的情況。#include / 包含寄存器的庫文件sbit

21、ADDR0 = P1A0;sbitADDR1 = Pil;sbitADDR2 = P1A2;sbitADDR3 = P1A3;sbitENLED = P1A4;unsigned char code LedChar = /用數(shù)組來表示數(shù)碼管真值表0 xC0,0 xF9,0 xA4,0 xB0,0 x99,0 x92,0 x82,0 xF8,0 x80,0 x90,0 x88,0 x83,0 xC6,0 xA1,0 x86,0 x8e,;void main() unsigned int counter = 0;unsigned char j = 0;unsigned long stopwatch

22、=0;unsigned char LedNumber6=0;ENLED = 0; ADDR3 = 1;P0 = 0XFF; /74HC138 和 P0初始化部分TMOD = 0 x01; / 設(shè)置定時器0 為模式 1TH0= 0 xFC;TL0= 0 x67; / 定時值初值, 定時 1msTR0 = 1; / 打開定時器0 while(1)if(1 = TF0)TF0 = 0;TH0 = 0 xFC;TL0 = 0 x67;counter+;if(1000 = counter)達到 1000 次counter = 0;stopwatch+;/ 秒表數(shù)值一秒加 1LedNumber0LedNu

23、mber1LedNumber2LedNumber3 管顯示值計算LedNumber4/ 判斷定時器0 是否溢出/ 一旦溢出后,重新賦值/ 判斷定時器0 溢出是否/stopwatch%10;stopwatch/10%10;stopwatch/100%10;stopwatch/1000%10; / 數(shù)碼stopwatch/10000%10;stopwatch/100000%10;LedNumber5 switch(j)case 0: ADDR0=0; ADDR1=0; ADDR2=0; j+;P0=LedCharLedNumber0;break;ADDR0=1; ADDR1=0; ADDR2=0;

24、 j+;P0=LedCharLedNumber1;break;ADDR0=0; ADDR1=1; ADDR2=0; j+;P0=LedCharLedNumber2;break;ADDR0=1; ADDR1=1; ADDR2=0; j+;P0=LedCharLedNumber3;break;ADDR0=0; ADDR1=0; ADDR2=1; j+;P0=LedCharLedNumber4;break;ADDR0=1; ADDR1=0; ADDR2=1; j=0;P0=LedCharLedNumber5;break;default: break;/ 數(shù)碼管動態(tài)刷新部分大伙是否能感受到 switc

25、h 語句比if.else語句顯得要整齊的多?6.4.2 數(shù)碼管消隱處理不明白細心的同學(xué)能否發(fā)明, 我們的兩次數(shù)碼管動態(tài)刷新顯示的時候大概并不是那么完美,第一個小問題,大伙認真看,數(shù)碼管的不應(yīng)該顯示的段,大概有微微的發(fā)亮,這種現(xiàn)象叫做“鬼影”,那個“鬼影”嚴峻妨礙了我們的視覺效果,我 們該如何解決呢? 同 學(xué)們今后可能會遇到各種各樣的問題,可能有許多我是沒有講過的問題,遇 到問題如何辦呢?大伙要相信, 你作為初學(xué)者, 遇到的問題確信不是第一個遇到 的, 確信 有前輩會遇到同類問題, 他們一般會在網(wǎng)上發(fā)表各種帖子, 各種討論, 因此大伙遇到問題, 首先解決方法就應(yīng)該形成一個到網(wǎng)上搜索的條件反射,

26、那個 問題大伙能夠 到網(wǎng)上搜:“數(shù)碼管消隱”或者“數(shù)碼管鬼影解決”,多找相關(guān) 關(guān)鍵詞搜索,會搜索也是一種能力。大伙在網(wǎng) 上搜了一下會發(fā)明, 解決這類問題的普遍兩個方法, 其中之一是延時,延時之后我們?nèi)庋劬涂赡芸床坏侥莻€ “鬼影” 了。 然而延時是一個特別拙劣的手段,且不說延 時多久能讓我們看不到“鬼影”,延時后,我們的數(shù)碼管亮度會普遍降低。我們解決問題呢,不能只知其然,不知其因此然,因此我們首先要弄懂什么原因會出現(xiàn)“鬼影”?!肮碛啊?的出現(xiàn), 要緊是因為我們數(shù)碼管位選和段選產(chǎn)生的瞬態(tài)所造成的。 舉個簡單例子, 我們在數(shù)碼管動態(tài)刷新的那部分程序中, 實際上每一個數(shù)碼管點亮的持續(xù)時間是1ms的時間

27、,1ms后進行下個數(shù)碼管的切換。在進行數(shù)碼管切換的時候,比如我們從case 5 要切換到 case 0 的時候, case 5 的位選用的是ADDR0=1;ADDR1=0; ADDR2如此刻case5也確實是最高位數(shù)碼管對應(yīng)的值是 0。我們 要切換成的case 0的數(shù)碼管位選是 ADDR0=0; ADDR1=0; ADDR2=0;對應(yīng)的數(shù)碼 管的值假如是1。因為我們的C語言程序是一句一句順序往下執(zhí)行的,每一條語句都會占用一定的時間, 即使那個時間特別特別短暫。 然而當(dāng)我們把“ ADDR0=” 1 改變成“ADDR0=”0的時候,那個瞬間存在了一個中間狀態(tài)ADDR0=0; ADDR1=0; AD

28、DR2=那個瞬問上,我們就給case 4對應(yīng)的數(shù)碼管DS5瞬間賦值了 0。當(dāng)我們?nèi)繉懲炅?ADDR0=0; ADDR1=0; ADDR2=0;,那個時候,我們的 P0還沒有正式賦值,而 P0 此刻卻保持了前一次的值,也確實是在那個瞬間,我們又給case 0 對應(yīng)的數(shù)碼管DS1賦值了一個00直到我們把case 0后邊的語句全部完成后,我們的刷新 才正式完成。 而在那個刷新過程中, 有 2 次瞬間我們給了錯誤的數(shù)碼管賦值, 盡 管很弱因為亮的時間很短,然而我們依舊能夠發(fā)明。那 弄懂了原理后,解決起來就不是困難的情況了,我們只要避開那個瞬態(tài)就能夠了。 不產(chǎn)生瞬態(tài)的方法是, 我們在進行刷新的賦值語句

29、期間, 幸免一切數(shù)碼管的賦值即 可。方法有兩個,一個方法是刷新之前關(guān)閉所有的段,改變好了位選后,再打開段即可;第二個方法是關(guān)閉數(shù)碼管的位,賦值過程都做好后,再重新打開即可。那個 不是很難,答案我都公布一下。關(guān)閉段:在switch(j)這句程序之前,加一句P0=0XFF如此就把數(shù)碼管所有的 段都關(guān)閉了,當(dāng)把“ ADDR的值全部搞定后,再給P0賦對應(yīng)的值即可。關(guān)閉位:在switch(j) 這句程序之前,加上一句ENLED=1等至IJ把“ADDR=0ADDR1=0;ADDR2=0;P0=LedCharLedNumber0; 這幾條刷新程序全部寫完后, 再加上一句ENLED=0然后再進行break操作

30、即可。那個地方略微有點邏輯思路在里邊, 大伙一定要理解深刻, 深刻理解, 完全弄明白, 把那個瞬態(tài)弄明白, 后邊許多牽扯到此類情況的問題, 我們都能夠一并搞定。上邊的數(shù)碼管程序還有第二個問題, 大伙認真看, 我們的數(shù)碼管上的數(shù)字每一秒變化一次, 變化的時候, 不參加變化的數(shù)碼管可能出現(xiàn)一次抖動, 那個抖動沒有什么專業(yè)的名字, 我們就稱之為數(shù)碼管抖動吧。 這種數(shù)碼管抖動是什么緣故造成的呢?為何在數(shù)據(jù)改變的時候才抖動呢?我們來看我們的程序。 我們的程序在定時到 1 秒的時候, 執(zhí)行了 “數(shù)碼管顯示值計算”那個過程,一個32 位的除法運算,實際上是比較耗費時間的,至于這一段程序占用了多少時間,大伙能

31、夠通過第四章講的Debug進入看看這段程序運行一共占據(jù)了多少時間。 由于達到 1 秒的時候, 程序多運行了這么一段, 導(dǎo)致了某個數(shù)碼管的點亮?xí)r間比其他情況下要長一些,時間是1ms程序消耗時間,于此同時,其它的數(shù)碼管就熄滅了5ms程序消耗時間,假如那個程序消耗時間特別短,那么能夠忽略不計,但很明顯,現(xiàn)在這段程序差不多比較長了,嚴峻妨礙我們的視覺效果了,因此我們要采取另外一種思路去解決那個問題。6.5 中斷的學(xué)習(xí) 6.5.1 中斷的產(chǎn)生背景比如此刻我正在廚房用煤氣燒一壺水,燒開一壺水剛好需要10 分鐘。我是一個主體,燒水是一個目的,而且我只能時 時刻刻在那個地方燒水,因為一旦水開了,溢出來澆滅煤氣

32、的話,有可能引發(fā)一場災(zāi)難。而那個時候呢,我聽到了電視里傳來天龍八部的主題歌,馬上就要開演了, 我真想奪門而出,去看我最喜愛的電視劇。然而,聽到那個水壺發(fā)出的“咕嘟”的聲音,我清晰:除非水開了,否那么我是無法享受我喜愛的電視劇的。那個地方邊主體只有我一個, 而我要做的有兩件情況, 一個是看電視, 一個是燒水,而電視和燒水是兩個獨立的客體,他們是同時進行的。其中燒水需要10 分鐘, 但不需要了解燒水的過程的, 只需要得到水燒開的如此一個結(jié)果就行了, 提下水壺和關(guān)閉煤氣只需要幾秒的時間而已。 因此我們采取的方法確實是: 燒水的時候,定上一個鬧鐘,定時10 分鐘,然后我就能夠安心看電視了。當(dāng) 10 分

33、鐘時間到了,鬧鐘響了,此刻水也燒開了,我就過去把煤氣滅掉,然后接著回來看電視就能夠了。那個場景和單片機有什么關(guān)系呢?在單片機的程序處理過程中也有許多類似的場景, 當(dāng)單片機正在用心致志的做一件情況的時候( 如看電視 ) , 總會有一件或者多件緊迫或者不緊迫的情況發(fā)生, 需要我們?nèi)リP(guān)注, 有一些需要我們停下手頭的工作去馬上完成( 比如水開了 ) , 只有處理完, 才能回頭接著完成剛才的工作( 看電視 ) 。 假如在那個地方用上了單片機的中斷機制, 不僅僅我擁有了處理意外情況的能力, 而且假如我能夠充分發(fā)揮那個機制的妙用,就能夠“同時”完成多個任務(wù)了。假如依舊一知半解關(guān)于中斷更6.5.2 定時器中斷

34、應(yīng)用方法在第五章我們學(xué)過定時器,而實際上定時器一般用法基本上采取中斷方式來做的,我是有意在第五章用查詢法,確實是使用 if(TR0 =0) 這 樣的語句先講定時器, 目的是明確告訴同學(xué)們, 定時器和中斷不是一回事, 定時器是單片機模塊的一個資源,確真的實存在的一個模塊,而中斷,是單片機的一種運行機制。尤其是初學(xué)者們, 許多人會誤以為定時器和中斷是一個東西, 只有定時器才會觸發(fā)中斷,但實際上許多事件都會觸發(fā)中斷的,除了“燒水”,還有“有人按門鈴”,“來標(biāo)準(zhǔn)51 中與中斷相關(guān)的寄存器,一共有2 個,其中 1 個是中斷使能寄存器, 另外 1 個是中斷優(yōu)先級寄存器, 那個地方先介紹中斷使能寄存器。 隨

35、著一些增強型51 單片機的問世,可能會有增加的寄存器,大伙這些理解了那個地 方所講的,其他的通過自己研讀數(shù)據(jù)手冊全部能夠理解明白同時使用起來??晌粚ぶ罚粡?fù)位值:0 x00;復(fù)位源:任何復(fù)位位76543210符號 EA - ET2 ES ET1 EX1 ET0 EX0表 6-2 IE- 中斷使能寄存器的位描述位 符號描述7 EA 總中斷使能位,相當(dāng)于總開關(guān)6-5ET24ES3ET12EX11ET00EX0定時器 2 中斷使能串口中斷使能定時器 1 溢出中斷使能外部中斷 1 使能 定時器 0 中斷使能外部中斷 0 使能中斷使能寄存器IE 操縱了 6 個中斷使能,其中第 6 位臨時不用,第七位是總開

36、關(guān), 相當(dāng)于我們家里或者學(xué)生宿舍里的那個電源總閘門。 而 0 到 5 位這 6 個相當(dāng)于每個分開關(guān)。那么也確實是說,我們只要用到中斷,就要寫 EA = 1 這一句,打開中斷總開關(guān),然后用到哪個分中斷,再打開相對應(yīng)的位就能夠了。我們現(xiàn)在就把第五章學(xué)的定時器的程序進行改寫, 使用中斷實現(xiàn)出來, 把數(shù)碼管 的抖動問題也同時一并處理掉。/ 用數(shù)組來表示數(shù)碼管真值表/ 包含寄存器的庫文#include 件sbitADDR0 = P1A0;sbitADDR1 = Pil;sbitADDR2 = P1A2;sbitADDR3 = P1A3;sbitENLED = P1A4;unsigned char cod

37、e LedChar = 0 xC0,0 xF9,0 xA4,0 xB0,0 x99,0 x92,0 x82,0 xF8,0 x80,0 x90,0 x88,0 x83,0 xC6,0 xA1,0 x86,0 x8e, ;unsigned char LedNumber6 = 0; / 定義全局變量unsigned char j = 0;unsigned int counter = 0;void main()unsigned long stopwatch =0;ENLED = 0; ADDR3 = 1; P0 = 0XFF;74HC138 和 P0初始化部分TMOD = 0 x01;/ 設(shè)置定時器

38、0 為模式 1TH0= 0 xFC;TL0= 0 x67;/ 定時值初值, 定時 1msTR0 = 1;/ 打開定時器0EA = 1;/ 打開中中斷ET0 = 1;/ 打開定時器0 中斷while(1)if(1000 = counter)/ 判斷定時器0 溢出是否達到1000次counter = 0;stopwatch+;LedNumber0 = stopwatch%10;LedNumber1 = stopwatch/10%10;LedNumber2 = stopwatch/100%10;LedNumber3 = stopwatch/1000%10;LedNumber4 = stopwatch

39、/10000%10;LedNumber5 = stopwatch/100000%10;void InterruptTimer0() interrupt 1/ 中斷函數(shù)的特別寫法,數(shù)字 1為中斷入口號 TH0 = 0 xFC; / 溢出后進入中斷重新賦值TL0 = 0 x67;counter+;/ 計數(shù)值counter 加 1P0 = 0 xFF;/ 消隱switch(j) case 0: ADDR0=0; ADDR1=0; ADDR2=0; j+;P0=LedCharLedNumber0; break;ADDR0=1; ADDR1=0; ADDR2=0; j+;P0=LedCharLedNum

40、ber1; break;ADDR0=0; ADDR1=1; ADDR2=0; j+;P0=LedCharLedNumber2; break;ADDR0=1; ADDR1=1; ADDR2=0; j+;P0=LedCharLedNumber3; break;ADDR0=0; ADDR1=0; ADDR2=1; j+;P0=LedCharLedNumber4; break;ADDR0=1; ADDR1=0; ADDR2=1; j=0;P0=LedCharLedNumber5; break;default: break;/ 動態(tài)刷新大伙能夠先把那個程序了解明白,下載到單片機里邊實驗一下,看看實際效果

41、。是否能夠看出來, 近乎完美的顯示效果通過我們的努力終于做成功了。 那下面我們還要來解析一下我們的那個程序。在我們那個程序中,有兩個函數(shù),一個是主函數(shù), 一個是中斷函數(shù)。 主函數(shù) main()我們就不用說了, 重點強調(diào)一下中斷函數(shù), 中斷函數(shù)的格式是固定的, 首先中斷函數(shù)前邊void 表示函數(shù)返回空,即中斷函數(shù)不返回任何值,函數(shù)名字是InterruptTimer0(),那個函數(shù)名字只要符合函數(shù)命名規(guī)那么的前提下我們就能夠隨便起, 我如此起名字是為了方便區(qū)分和經(jīng)歷, 而后是 interrupt 那個關(guān)鍵字不能錯,那個是中斷特有的關(guān)鍵字,另外后邊還有個數(shù)字1,那個數(shù)字1 如何來的呢?我們先來看一個

42、表格。表 6-3 中斷查詢序列描述中斷標(biāo)志中斷使能默認優(yōu)先級外部中斷0IE00003HEX01( 最高 )T0 中斷TF0000BHET02外部中斷1IE10013HEX13T1 中斷TF1001BHET14UART 斷TI/RI0023HES5T2 中斷TF2/EXF2002BHET26那個表格同樣不需要大伙記住, 需要的時候過來查就能夠了。 我們現(xiàn)在看第二行T0中斷,它的中斷標(biāo)志是TF0,也確實是當(dāng)TF0變成1的時候,就會觸發(fā)中斷。而在interrupt 后邊的數(shù)字x的計算方法是x*8+3=向量地址,T0的向量地址是 000BH那么我們能夠求得x的值是1。如此那個中斷函數(shù)名字我們就完全明白

43、 了。中斷函數(shù)和一般函數(shù)有個不一樣的地方, 一般函數(shù)一般是在程序中調(diào)用, 而中斷函數(shù)因為有了中斷入口, 達到中斷條件后, 他會自動進入程序執(zhí)行。 比如咱那個程序,平時一直在主程序 while(1) 的循環(huán)中運行,假如程序有100行,當(dāng)運行到了 50行的時候,定時器溢出了,那么CPLM會趕忙跑到中斷函數(shù)中執(zhí)行中斷程序, 中斷程序運行完畢后再自動返回到剛才的第 50 行處接著運行下面的程序,如此就保證了動態(tài)刷新是固定的1ms時間,可不能因為程序運行時間不一致的緣 故導(dǎo)致數(shù)碼管的抖動了。6.5.3 中斷的優(yōu)先級中斷優(yōu)先級的內(nèi)容, 大伙先通過我的介紹大概了解一下即可, 后邊真正實際應(yīng)用的時候我們再詳細

44、理解。在講中斷產(chǎn)生背景的時候, 我們僅僅講了看電視和燒水的例子, 然而實際生活話的“中斷” 程序當(dāng)中去, 就在接電話的同時, 聽到了水開的聲音, 水開的 “中斷”也發(fā)生了,我們要放下手上的電話,先把煤氣關(guān)掉,然后再回來聽電話,最后聽完了電話再看電視,那個地方就產(chǎn)生了一個優(yōu)先級的問題。還有一種情況, 我們在看電視的時候, 那個時候聽到水開的聲音, 水開的 “中斷”發(fā)生了,我們要進入關(guān)煤氣的“中斷”程序當(dāng)中,而在關(guān)煤氣的同時,電話聲音響了,而那個時候,我們的處理方式是先把煤氣關(guān)閉,再去接聽電話,最后再看電視。從這兩個過程中, 我們能夠得到一個結(jié)論, 確實是最最緊急的情況, 一旦發(fā)生后,我們不管當(dāng)時處在哪個“程序”當(dāng)中,我們必須先去解決最最

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論