中斷與數碼管動態顯示
中斷是單片機系統重點中的重點,因為有了中斷,單片機就具備了快速協調多模塊的工作能力,可以完成復雜的任務。
C語言數組
數組的基本概念
數組是具有相同數據類型的有序數據的組合,一般來講,數組定義后滿足以下三個條件:
- 具有相同的數據類型
- 具有相同的名字
- 在存儲器中是被連續存放的
unsigned char LedChar[] =
{
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
在這個數組中的每一個值都稱之為數組的一個元素,這些元素都具備相同的數據類型就是unsigned cahr型,它們有一個共同的名字LedChar,不管是放在RAM里面還是放在Flash里面,它們都是存放在一塊連續的存儲空間里面的。
數組的下標由0開始
數組的聲明
一維數組的聲明格式如下:
數據類型 數組名[數組長度];
數組的數據類型聲明的是該數組的每個元素的類型,即一個數組中的元素具有相同的數據類型
數組名的聲明要符合C語言固定的標識符的聲明要求,只能由字母、數字、下劃線這三種符號組成,且第一個字符只能是字母或者下劃線
方括號中的數組長度是一個常量或者常量表達式,并且必須是正整數
數組的初始化
數組在進行聲明的同時可以進行初始化操作,格式如下:
數據類型 數組名[數組長度] = {初值列表};
例如:
unsigned char LedChar[] =
{
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
初值列表里的數據之間要用逗號隔開
初值列表的初值的數量必須等于小于數組長度,當小于數組長度時,數組的后邊沒有賦初值的元素由系統自動賦值為0
若給數組的所有元素都賦初值,可以省略數組的長度
系統為數組分配連續的存儲單元的時候,數組元素的相對次序由下標來決定,就是說LedChar[0],LedChar[2],...,LedChar[15]是按照順序依次排下來的
數組的使用和賦值
在C語言程序中,是不能一次使用整個數組的,只能使用數組的單個元素。
一個數組元素相當于一個變量,使用數組元素的時候與使用相同數據類型的變量方法是一樣的。
由以下幾點要注意:
- 引用數組的時候,那個方括號里的數字代表的是數組元素的下標,而數組初始化的時候方括號里的數字代表的是這個數組中元素的總數
- 數組元素的方括號里的下標可以是整形常數、整形變量或者表達式,而數組初始化的時候方括號里的數字必須是常數而不能是變量
- 數組整體賦值只能在初始化的時候進行,在程序執行代碼中只能對單個元素賦值
if語句
if語句有兩個關鍵字:if和else,把這兩個關鍵字翻譯一下就是:“如果”和“或者”。if語句一共有三種格式
if語句的默認形式
if (條件表達式)
{
語句1;
}
執行過程:條件表達式為真,則執行語句1,否則不執行語句1
if...else語句
if (條件表達式)
{
語句1;
}
else
{
語句2;
}
執行過程:條件表達式為真,則執行語句1,否則執行語句2
if...else if語句
if (條件表達式1)
{
語句1;
}
else if (條件表達式2)
{
語句2;
}
else if (條件表達式3)
{
語句3;
}
else
{
語句4;
}
執行過程:條件表達式1為真,則執行語句1,否則判斷條件表達式2,若條件表達式2為真,則執行語句2,否則判斷條件表達式3,若條件表達式3為真,則執行語句3,否則執行語句4
switch語句
用if...else語句處理多分支的時候,分支太多就會顯得不方便,且容易出現if和else配對出現錯誤的情況,在C語言中提供了另外一種多分支選擇的語句--switch語句,基本語法如下:
switch (表達式)
{
case 常量表達式1:語句1;
case 常量表達式2:語句2;
case 常量表達式3:語句3;
default:語句4;
}
執行過程:首先計算“表達式”的值,然后從第一個case開始,與“常量表達式x”進行比較,如果與當前常量表達式的值不相等,那么就不執行冒號后邊的語句x,一旦發現和某個常量表達式的值相等了,那么它會執行之后所有的語句,如果直到最后一個常量都沒有找到相等的值,那么就會執行default后面的語句。
當找到一個相等的case分支后,會執行該分支以及之后所有的分支的語句,在C語言里面,有一條break語句,作用的跳出當前的循環語句,包括for循環和while循環,同時,它還能用來結束switch語句塊。
switch (表達式)
{
case 常量表達式1:語句1;break;
case 常量表達式2:語句2;break;
case 常量表達式3:語句3;break;
default:語句4;break;
}
這樣子在執行對應case后面分支之后會因為break語句而直接跳出了switch語句,繼續執行switch語句后面的語句了
數碼管的動態顯示
動態顯示的基本原理
多個數碼管顯示數字的時候,實際上是輪流點亮數碼管(一個時刻內只有一個數碼管是亮的),利用人眼的視覺暫留現象(也叫余暉效應),就可以做到看起來所有數碼管都同時亮了,這就是動態顯示,也叫動態掃描。
例如,有兩個數碼管,要顯示數字“12”,先讓高位的位選三極管導通,然后控制段選讓其顯示“1”,延時一定時間后,再讓低位的位選三極管導通,然后控制段選讓其顯示“2”。把這個流程以一定速度循環運行就可以讓數碼管顯示出“12”,由于交替速度非常快,人眼識別到的就是“12”這兩位數字同時亮了。
將時間控制在10s內就可以實現動態顯示了。
6段數碼管的動態顯示
數碼管顯示消隱
”鬼影“的出現,主要是在數碼管位選和段選產生的瞬態造成的。
舉個例子:在數碼管動態顯示的那部分程序中,實際上,每一個數碼管點亮的持續時間是1ms的時間,1ms后進行下一個數碼管的切換。在進行數碼管切換的時候,比如從case 5要切換到case 0的時候,case 5的位選用的是“ADDR0 = 1; ADDR1 = 0; ADDR2 = 1;”假如此刻case 5也就是最高位數碼管對應的值是0,要切換成的case 0的數碼管位選是“ADDR0 = 0; ADDR1 = 0; ADDR2 = 0;”而對應的數碼管的值假如是1。又因為C語言程序是一句一句順序往下執行的,每一條語句的執行都會占用一定的時間,即使這個時間很短。但是當把“ADDR0 = 1”改變成“ADDR0 = 0”時,這個瞬間存在了一個中間狀態“ADDR0 = 0; ADDR1 = 0; ADDR2 = 1;”在這個瞬間上,就給case 4對應的數碼管DS5瞬間賦值了0。當全部寫完“ADDR0 = 0; ADDR1 = 0; ADDR2 = 0;”后,P0還沒有正式賦值,而P0卻保持了前一次的值,也就是在這個瞬間,又給case 0對應的數碼管DS1賦值了一個0。直到把case 0后邊的語句全部完成后,刷新才正式完成。而在這個刷新過程中,有兩個瞬間給錯誤的數碼管賦了值,雖然很弱(因為亮的時間很短),但是還是能夠發現。
搞明白原理后,解決起來就簡單了,避免這兩次瞬間錯誤就可以了。不產生瞬間錯誤的方法是,在進行位選切換期間,避免一切數碼管的賦值即可。
方法有兩個:
- 刷新之前關閉所有段,改變好位選之后,再打開段
- 關閉數碼管的位,賦值過程做好之后,再打開
實施: - 關閉段:在switch語句之前,加上
P0 = 0xFF; - 關閉位:在switch語句之前,加上
ENLED = 1;
動態顯示的數碼管顯示消隱
單片機中斷系統
中斷的產生背景
在單片機的程序處理中會遇到以下情景:
當單片機正在專心致志的做一件事情的時候,總會有一件或者多件緊迫或者不緊迫的事情發生,需要去關注,有一些需要停下手頭的工作馬上去處理了,只有處理完了,才能回頭繼續完成剛才的工作。這種情況下單片機的中斷系統就該發揮它強大作用了,合理巧妙的利用中斷,不僅可以獲得處理突發狀況的能力,而且可以使單片機能夠“同時”完成多項任務。
定時器中斷的應用
定時器和中斷不是一回事,定時器是單片機模塊的一個資源,確確實實存在的一個模塊,而中斷,是單片機的一種運行機制。
標準51單片機中控制中斷的寄存器有兩個:
- 中斷使能寄存器
- 中斷優先級寄存器
中斷使能寄存器

上表為中斷使能寄存器的位分配,下表為中斷使能寄存器的位描述

中斷使能寄存器IE的0~5位控制了6個中斷使能,而第6位沒有用到,第7位是總開關。
總開關相當于總閘,也就是說,只要用到了中斷,就要寫 EA = 1這一句,打開中斷總開關,然后用到哪個分中斷,再打開相對應的控制位就可以了。
采用中斷的動態顯示
在該程序中,有兩個函數:
- 主函數main函數
- 中斷服務函數
中斷服務函數:
void InterruptTimer0() interrupt 1
{
;
}
函數前面 void表示函數返回值為空,即中斷服務函數無返回值,函數名是 InterruptTimer0,這個函數名在符合函數命名規則的前提下可以隨便取,取這個名字是為了方便區分和記憶,而后的 interrupt是關鍵字,一定不能錯,這是中斷特有的關鍵字,另外后邊還有一個數字1,是中斷查詢序列。

表中第二行的T0中斷,要使能這個中斷那么就要把它的中斷使能位ET0置為1,當它的中斷標志TF0變為1時,就會觸發T0中斷了,這時就應該來執行中斷函數了,單片機靠的就是中斷向量地址來找到這個中斷函數的,所以interrupt后面中斷函數編號的數字x就是中斷向量得出的,它的計算方法是x * 8 + 3 = 向量地址。該值x也就是表內的第一欄內容了,也就是中斷函數編號,要用的時候查表直接用就可。
中斷函數完成后,每當滿足中斷條件而觸發中斷后,系統就會自動來調用中斷函數。
中斷優先級寄存器
單片機程序有一般緊急的中斷,有特別緊急的中斷,這取決于具體的系統設計,這就涉及中斷優先級和中斷嵌套的概念。
中斷優先級有兩種:
- 搶占優先級
- 固有優先級
搶占優先級

上表為中斷優先寄存器的位分配,下表為中斷優先寄存器的位描述

IP這個寄存器的每一位,表示對應中斷的搶占優先級,每一位的復位值都是0,當把某一位設置為1的時候,這一位的優先級就比其他位的優先級高了。
比如,設置PT0位為1后,當單片機在主循環或者任何其他中斷程序中執行時,一旦定時器T0發生中斷,作為更高的優先級,程序馬上就會跑到T0的中斷程序來執行。
反過來,當單片機正在T0中斷程序中執行,如果有其他中斷發生了,還是會繼續執行T0中斷程序,直到把T0中的中斷程序執行完畢后,才會去執行其他中斷程序。
當進入低優先級中斷時,如又發生了高優先級中斷,則立刻進入高優先級中斷執行,處理完高優先級中斷后,再返回處理低優先級中斷,這個過程就稱為中斷嵌套,也稱為搶占。
搶占優先級:優先級高的中斷可以打斷優先級低的中斷的執行,,從而形成嵌套。當然反過來,優先級低的中斷是不能打斷優先級高的中斷的。
固有優先級

該表的最后一欄就是固有優先級。
在中斷優先級的編號中,一般都是數字越小,優先級越高。
從表中可以看出,一共有1~6共6級優先級,這里的優先級與搶占優先級的一個不同點就是,它不具有搶占性,也就是說,即使在低優先級中斷執行過程中又發生高優先級的中斷,那么高優先級的中斷也只能等到低優先級的中斷執行完成后才能得到響應。
搶占優先級和固有優先級的協同,可以使單片機中斷系統有條不紊的工作,既不會無休止的嵌套又可以保證必要時緊急任務得到優先處理。
本文來自博客園,作者:EricsT,轉載請注明原文鏈接:http://www.rzrgm.cn/EricsT/p/19001778

浙公網安備 33010602011771號