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

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

51單片機編程開發(fā)(六)之按鍵與外部中斷

2022-07-30 11:15 作者:落木青云  | 我要投稿

這是一段不用看的屁話??

很長一段時間沒更新單片機教程了,因為最近手頭上有些事需要處理,閑暇時間就不多了,今天抽空先把這篇內(nèi)容先推送出來。其實吧,做開發(fā)真的是一件“苦差事”,真的喲,一旦一個項目啟動,你的生活就會進入敲代碼-吃喝拉撒-睡覺-敲代碼兩點一線式單調(diào)循環(huán)模式,并且,還需要隨時準備著享受客戶,領(lǐng)導的指指點點。哈哈哈~所以在你選擇學習編程,準備走上程序員這條路時一定要從心里喜歡上編程這件事,而不是因為聽說這個行業(yè)高薪所以就要學。當然選擇其他行業(yè)時也是一樣的道理,只有自己喜歡做這件事才會收獲其中的快樂,即使過程曲折也會樂在其中。

曾幾何時,不少朋友大四時突然發(fā)現(xiàn)大學幾年好像沒學會啥專業(yè)知識,又馬上要踏入社會了,多少都會焦慮,這時候培訓機構(gòu)出來讓他們喝了杯專門販賣焦慮的雞湯,瞬間讓他們就像打了雞血一樣抱住培訓老師的大腿。在培訓機構(gòu)培訓三四個月到半年時間,出來后剛好畢業(yè),然后也恰好找到了一份對口的工作。但有些沒堅持一年半載估計當初貸款的學費剛還清就轉(zhuǎn)行了。我并不是說所有人都不值得參加培訓,也不是說所有培訓機構(gòu)都沒有存在的意義。而是說在你做出選擇的時候一定要考慮自身的實際情況,你是否愿意堅持下去,做出自己的判斷之后再結(jié)合自己的興趣選擇一個方向和一個靠譜的機構(gòu)參加培訓,這也不是一件壞事,畢竟在你學本領(lǐng)的同時培訓機構(gòu)也賺到了money,這種需求關(guān)系決定的市場,本身就沒有對錯之說,但市場上培訓質(zhì)量難免良莠不齊,做決定時就更需要結(jié)合自身實際情況考慮清楚了。

曾經(jīng)參加過培訓的朋友當中也有很多一直堅持到現(xiàn)在并且都做得不錯的,如果你基礎(chǔ)一般,那通過培訓快速提升能力也是一件好事。但話說回來,如果你不是科班出身想換行那還是風險非常大的,選擇培訓速成就一定要慎重,特別是已經(jīng)參加工作的朋友,因為專業(yè)歧視是一直都存在的,培訓班歧視就更不用說了。假如我要招人也同樣是優(yōu)先考慮招錄科班畢業(yè),專業(yè)基礎(chǔ)良好的。所以跨專業(yè)很多時候都非常難,特別是在前期零基礎(chǔ)階段,你一定要比其他人更努力,還要充分了解計算機原理。想想面試時你和一群科班生同臺競技,你贏的機會在于你比他們表現(xiàn)得更專業(yè),否則面試通知都可能收不了。

當然對于自己選擇這條道路的在校學生來說,不希望自己有畢業(yè)即面臨失業(yè)的焦慮,最好的辦法就是從錄取通知書確定你的專業(yè)那一刻起就要時刻提醒自己踏實學習。編程是真的需要基礎(chǔ),要有編程思維的,這些能力和思維怎么鍛煉?就在于你對計算機的理解和平時的一次次可能無足輕重的編程訓練再加上其他的一些拓展見識。大學階段是學習技能最快的年齡,一定要穩(wěn)穩(wěn)抓住這段寶貴時光,為你將來上有老,下有小的生活多積累一份技術(shù)資本。當然大學期間也不要變成了書呆子,其他必要的事情都可以大膽嘗試。

另外,不管怎么說,學習從來也都是克服眾多負面情緒的有效的手段,即使參加工作了也不例外。所以,還是我之前一直強調(diào)的那句話,不要輕易相信“選擇比努力更重要”這樣的鬼話。這話都是說給已經(jīng)成功的人聽的,無論如何至少要有了選擇權(quán)之后你才有資格驗證選擇結(jié)果。誰不想高考考進清北呢,問題是沒有那能力,我們連選擇權(quán)都沒有,所以你曾經(jīng)的努力就是在為你行使選擇權(quán)時多一份可能,而不是它一直站在那里等待你的選擇。面對確定的“成”與“敗”,誰會選擇“敗”呢,但從宇宙規(guī)律來看,一切本來就是不確定的,所以非要把成敗歸功(咎)于幾個選擇上那未免也太扯了。一個對自身有清晰認識并有強大執(zhí)行力的人總會有所收獲,剩下的時間就交給運氣吧,畢竟人生總離不開驚喜和意外。

好端端的一篇技術(shù)文章又變成了一篇雞湯文,原諒我這該死的啰嗦。接來下我們進入正題吧。

按鍵

按鍵也是一種元器件,這時一種控制電路短暫啟停的一種器件,在生活中也是非常的常見,比如電梯按鈕,鍵盤按鍵,遙控器,計算器,電話,手機按鍵,等等,比比皆是具體長什么樣就不用舉例了吧,各種各樣的形狀都有。

鍵盤

我們在使用電腦時都需要通過鍵盤進行打字輸入,鍵盤上的所有按鍵構(gòu)成一個按鍵矩陣,當我們按下某一個按鍵時,鍵盤上的芯片將對鍵值進行解碼,然后將鍵值通過鍵盤驅(qū)動程序傳遞給CPU,CPU收到信號后就會顯示按鍵內(nèi)容或執(zhí)行該按鍵對應的功能。單片機當然也有這樣的功能,我們在產(chǎn)品開發(fā)時不可避免的都可能會用到按鍵進行相應的控制操作,簡單的應用中可能只需要少數(shù)幾個按鍵就可以實現(xiàn)產(chǎn)品功能,這時使用幾個I/O口分別連接一個按鍵來實現(xiàn)。如果是一些需要很多按鍵的產(chǎn)品,像鍵盤,電視遙控器,如果一個按鍵對應一個引腳就太浪費芯片資源了,這時就需要使用矩陣按鍵增強單片機引腳的使用率了。

按鍵是人機交互的重要工具,也是非常簡單又常見的一種工具,下面我們接著介紹它的使用方法。

51單片機使用獨立按鍵

我們使用51單片機時要怎么來檢查按鍵操作呢?下面先根據(jù)我們仿真電路中使用的電路圖來具體說明。

電路圖

圖中K1~K4是四個獨立按鍵,分別接在了P3.0~P3.3這4個端口上。那當按鍵按下時我們要怎么讓單片機內(nèi)部檢測出是哪個按鍵按下的呢?從圖中可以看出在默認情況下這四個按鍵的輸入電平都是高電平,當按鍵被按下時其對應引腳輸入電平被拉到地。這時我們在程序中就可以設(shè)置一個不斷掃碼端口輸入數(shù)據(jù)的代碼段,被按下的按鍵對應的引腳數(shù)據(jù)寄存器中為0,其他引腳對應位數(shù)據(jù)依舊為1,接下來我們通過電平對比是不是就可以得出是哪個按鍵被按下了?

但是當按鍵按這個動作并不像一個方波信號那樣干脆利落,就像我們平時拔插插頭時可能會出現(xiàn)火花一樣,按鍵過程中也會有雜波信號抖動干擾,按鍵過程電平變化波形如下圖所示:

按鍵過程

如果我們程序中一旦檢測到電平變化就進行后續(xù)操作,這時如果只是一個抖動干擾信號,那不是就誤判了?這就會造成程序功能錯誤,在某些應用中可能造成嚴重的后果,那怎么才能避免這個問題呢?這些抖動信號一般在幾個ms內(nèi)(這相對以秒計數(shù)的整個過程來說是非常的短暫的),所以在簡單應用中我們一般在檢測到第一次按鍵后隔幾個或十幾個ms之后再檢測引腳輸入電平。如果第二次確認電平變化了才認為按鍵按下了,否則就是干擾信號??梢园l(fā)現(xiàn)這么處理就避免了干擾信號引發(fā)的程序錯誤。下面我們來看一下程序的實現(xiàn)過程。

/*

*這是一個按鍵測試程序

*目的是實現(xiàn)按鍵監(jiān)測功能

*/

#include <reg52.h>?

#include <intrins.h>?


sbit com1 = P2^0; //定義數(shù)碼管com1引腳

sbit com2 = P2^1; //定義數(shù)碼管com2引腳


sbit key1 = P3^0;?

sbit key2 = P3^1;?

sbit key3 = P3^2;?

sbit key4 = P3^3;?


typedef unsigned char u8;

typedef unsigned int ?u16;


u8 temp_key = 0; //定義一個變量用來存放臨時按鍵值


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


void delay(u8 ms);


void main()

{

//讀取P3端口,判斷是否有按鍵按下

if((P3&0x0f)^0x0f)

{

//保存當前按鍵值

temp_key = ((P3&0x0f)^0x0f); ?

//進行一個延時消抖

delay(15);

//再次讀取P3端口數(shù)據(jù),與temp_key對比,判斷按鍵值是否發(fā)生變化

if(temp_key == ((P3&0x0f)^0x0f))

{

//確定按鍵按下則不同按鍵顯示對應的數(shù)字

switch(temp_key)

{

case 0x01://按鍵1

com1 = 0;//將第一位的com端設(shè)置為低電平

com2 = 1;

P0 = num_codelist[1];

break;


case 0x02://按鍵2

com1 = 0;//將第一位的com端設(shè)置為低電平

com2 = 1;

P0 = num_codelist[2];

break;


case 0x04://按鍵3

com1 = 0;//將第一位的com端設(shè)置為低電平

com2 = 1;

P0 = num_codelist[3];

break;


case 0x08://按鍵4

com1 = 0;//將第一位的com端設(shè)置為低電平

com2 = 1;

P0 = num_codelist[4];

break;


default:

break;

}

}

}

}


void delay(u8 ms) ??

{

u8 i,j;

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

{

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

{

;

}

}

}

程序功能設(shè)置為檢測到按鍵按下后數(shù)碼管就顯示對應的按鍵數(shù)值,現(xiàn)在再來看一下仿真結(jié)果驗證一下。待會在進行代碼分析。

仿真現(xiàn)象

現(xiàn)在我們來分析程序的實現(xiàn)過程,一些以前說明過的程序就不做介紹了。主要講解關(guān)鍵程序段,如果有看不懂的可以留言。

u8 temp_key = 0; //定義一個變量用來存放臨時按鍵值。這里定義了一個變量來存放按鍵的臨時值,在第一次按鍵按下時用來存儲當前按鍵值,在第二次檢測時用它與第二次掃描的按鍵值進行對比判斷是否是真實按鍵操作。

if((P3&0x0f)^0x0f)這一行是讀取P3端口的數(shù)據(jù),&操作符時只獲取低4位數(shù)據(jù),^操作符是得到具體是哪個按鍵被按下。

temp_key = ((P3&0x0f)^0x0f); ?這行是將當前按鍵值暫存起來,后面使用時再調(diào)用。

delay(15);這一行是進行延時消抖處理,避免干擾信號引起的誤判。

if(if(temp_key == ((P3&0x0f)^0x0f))== ((P3&0x0f)^0x0f))這一行是消抖后再次進行鍵值判斷,如果當前讀取到的端口數(shù)據(jù)與temp_key?一致說明當前鍵值還是第一次檢測時的按鍵值,則說明確實有按鍵按下了,否則說明是干擾信號。

switch(temp_key)這里使用了switch語句,進行處理不同鍵值按下時數(shù)碼管顯示對應鍵值。

case?語句內(nèi)容就是依據(jù)對應的按鍵值進行相應的顯示處理。

當然這里也可以使用if判斷語句來處理,我這里使用switch語句是正好可以趁機會讓各位來溫習一下switch語句的用法。有興趣的朋友可以嘗試修改一下。

按鍵基礎(chǔ)程序就講解完了,當然這里只是按鍵程序的最基礎(chǔ)例程,實際使用時根據(jù)具體需求做相應修改。

51單片機外部中斷

上面鍵的按鍵程序大家應該對著注釋和說明能夠看明白吧,但是如果讓程序一直掃描端口數(shù)據(jù)如果芯片還要處理其他事情那不就沒空處理了,這么使用是不是太浪費芯片資源了呢?確實,一般情況下我們做的產(chǎn)品不可能都是一直掃描按鍵吧,所以這時候我們就需要一些更好的辦法來解決這些資源浪費的問題吧。這就是中斷系統(tǒng),在這里的具體表現(xiàn)就是程序中不需要一種掃描端口數(shù)據(jù),你按鍵按下了中斷系統(tǒng)檢查出來就將結(jié)果通知CPU,CPU在發(fā)出信號,這時我們收到CPU的信號再進行后續(xù)相應的處理。如果沒按鍵按下CPU就去忙其他事情,有了這個中斷系統(tǒng)后CPU的工作效率就提高了吧!

前面介紹基礎(chǔ)內(nèi)容時簡單說明了單片機中斷相關(guān)的知識,但沒有講解中斷的具體使用方法,這節(jié)內(nèi)容我們一起來詳細了解一下51系列單片機的中斷控制器及其使用。

51系列單片機的中斷相關(guān)控制寄存器包括了中斷控制寄存器(Interrupt Enable register,IE)和中斷優(yōu)先級控制寄存器(Interrupt Priority register,IP),前者用于對單片機的中斷工作狀態(tài)進行控制,后者用于對51單片機的中斷優(yōu)先級進行控制。這兩寄存器具體的介紹請參考之前的文章:51單片機入門基礎(chǔ)知識(三)之中斷系統(tǒng)

以上兩個中斷寄存器是單片機所有中斷源的設(shè)置寄存器,當然單片機還有其他一些中斷控制寄存器,TCON和SCON。TCON是外部中斷和定時器中斷的控制寄存器,SCON是串口輸入和輸出中斷控制寄存器。簡單說這兩個寄存器就是使能這幾種中斷源的小開關(guān),開關(guān)打開之后各中斷事件才能被CPU獲取?,F(xiàn)在來認識一下這幾一節(jié)內(nèi)容我們需要用到的TCON寄存器:

TCON寄存器

IT0:INT0 觸發(fā)方式控制位。

可由軟件進行置位和復位,IT0=0,INT0 為低電平觸發(fā)方式,IT0=1,INT0 為下降沿觸發(fā)方式。

IE0:INT0 中斷請求標志位。

當有外部的中斷請求時,這位就會置1(這由硬件來完成),在CPU 響應中斷后,由硬件將IE0 清0,即不需要用指令來清0。

IT1:INT1 觸發(fā)方式控制位。

可由軟件進行置位和復位,IT1=0,INT1 為低電平觸發(fā)方式,IT1=1,INT1 為下降沿觸發(fā)方式。

IE1:INT1 中斷請求標志位。

當有外部的中斷請求時,這位就會置1(這由硬件來完成),在CPU 響應中斷后,由硬件將IE1 清0。

TR0:T0 啟動控制位。

TR0=1 時,啟動T0 工作;TR0=0 時,T0 停止工作。

TF0:定時器T0 的溢出中斷標志位。

當T0 計數(shù)產(chǎn)生溢出時,由硬件置位TF0。當CPU 響應中斷后,再由硬件將TF0清0。

TR1:T1 啟動控制位。

TR1=1 時,啟動T1 工作;TR1=0 時,T1 停止工作。

TF1:定時器T1 的溢出中斷標志位。

當T1 計數(shù)產(chǎn)生溢出時,由硬件置位TF1。當CPU 響應中斷后,再由硬件將TF1清0。

外部中斷控制需要使用的就是其中的IE0和IE1這兩位,剩下的是與定時器相關(guān)的位,這將是我們下一節(jié)要講解的內(nèi)容。

現(xiàn)在市面上的51單片機擴展了更多中斷源,肯定就會有更多其他的中斷相關(guān)的寄存器,所以使用時一定要參考芯片手冊上的寄存器內(nèi)容,不可照搬!但是使用方法都是類似的,根據(jù)數(shù)據(jù)手冊上的操作說明逐步配置相關(guān)寄存器就好,包括以后如果使用更復雜的單片機也是一樣的道理。

在51系列單片機中P3.2和P3.3兩個端口的第二功能就是外部中斷輸入端口,現(xiàn)在我們來看一下單片機內(nèi)部中斷控制系統(tǒng)處理機制:

中斷控制機制

從上圖可以看出TCON和SCON寄存器里面相當于一個小開關(guān),直接決定各個中斷源的使用。IE寄存器中的前面幾位就像一個橋梁,決定現(xiàn)在你要接通哪些中斷源,而它的EA位就是一個總閘,決定是否把中斷信號發(fā)送給CPU。所以我們程序中配置中斷時這3個地方都有進行配置,缺一不可!至于IP寄存器是用來確定中斷信號優(yōu)先級的,本來單片機內(nèi)部是有默認的優(yōu)先級機制的,所以這個寄存器不設(shè)置也可以,它的作用就像皇帝身邊的小太監(jiān),大臣們上奏的奏折本來有規(guī)定的優(yōu)先順序,如果誰買通了它就可以給奏折換個順序。這么說這些寄存器之間的關(guān)系是不是就很好理解了?

現(xiàn)在再來了解一下CPU收到中斷之后的處理機制:

中斷流程

圖中硬件處理部分我們的程序是可以不用參與的,由CPU自動完成(前提是中斷寄存器都配置好了),CPU處理完就會跳轉(zhuǎn)到我們的代碼段中執(zhí)行。

這里一定要注意我們使用C語言編程時編寫中斷函數(shù)的格式:

void??your_fuction_name(void)?interrupt 0 //外部中斷0服務例程

{

//中斷處理語句段

}

其中函數(shù)名可以自行確定一個合法,易懂的。interrupt 0 代表這是外部中斷0中斷源入口,其他中斷源就不會跳轉(zhuǎn)到這里來,這件相當于各回各家,各找各媽。這是中斷函數(shù)中不可或缺的一部分,其他每種中斷源都有對應的數(shù)字號,可以自行查看中斷源入口地址表。另外值得注意的是,這些中斷函數(shù)不用聲明,也不可被調(diào)用,只要正確定義了編譯器編譯代碼時就能識別到它,這也是它與其他普通函數(shù)的區(qū)別。

現(xiàn)在再詳細了解一下我們的中斷程序中各部分的內(nèi)容。

關(guān)閉中斷與打開中斷:當中斷被正確響應后,如果中斷服務例程在執(zhí)行過程中,不想被更高級的中斷打斷。則可以在進入中斷服務例程后置EA=0,關(guān)閉所有中斷,或者關(guān)閉某些中斷,這樣可以保證中斷服務例程的順利執(zhí)行。在中斷服務例程結(jié)束時,可以將關(guān)閉的中斷開啟,以便于單片機能夠接收新的中斷請求。

現(xiàn)場保護與恢復現(xiàn)場:一般來說,在主程序和中斷服務程序中都會用到累加器和寄存器等。51單片機在中斷服務程序中使用這些寄存器的時候?qū)淖兤渲械膬?nèi)容,再返回主程序的時候容易引起錯誤。因此,在進入中斷服務程序后,應該首先將相應的寄存器保存起來,即保護現(xiàn)場;當中斷服務例程結(jié)束時,應該將這些寄存器的內(nèi)容恢復,即現(xiàn)場恢復。當然在C51語言程序中,這部分工作是由編譯器自動完成的。

中斷服務程序:這是我們需要在中斷中進行操作的內(nèi)容,根據(jù)程序功能確定。

現(xiàn)在你頭腦中對外部中斷使用應該有個大致的框架了吧?我們使用前面的仿真電路運用單片機外部中斷來做一個按鍵加減數(shù)字的程序,可以自己動手試試,下面參考一下我寫的測試程序:

/*

*這是一個按鍵的外部中斷處理程序

*目的是通過外部中斷監(jiān)測按鍵功能

*/


#include <reg52.h>?

#include <intrins.h>?


sbit com1 = P2^0; //定義數(shù)碼管com1引腳

sbit com2 = P2^1; //定義數(shù)碼管com2引腳


sbit key1 = P3^0;?

sbit key2 = P3^1;?

sbit key3 = P3^2;?

sbit key4 = P3^3;?


typedef unsigned char u8;

typedef unsigned int ?u16;


u8 temp_key = 0; //定義一個變量用來存放臨時按鍵值


u8 key_num = 0;//定義一個數(shù)字,用來顯示實時數(shù)值


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


void delay(u8 ms);


void main()

{

IT0=1; //外部中斷0為下降沿觸發(fā)

IT1=1; //外部中斷1為下降沿觸發(fā)

EX0=1; //開EX0中斷

EX1=1; //開EX1中斷

EA=1; //開總中斷


//有了中斷服務程序,在主循環(huán)中可以什么都不用做,當然你也可以讓它干一些事情

while(1)

{

//在循環(huán)中顯示當前數(shù)字

com1 = 0;//將第一位的com端設(shè)置為低電平

com2 = 1;

P0 = num_codelist[key_num];


}

}


void delay(u8 ms) ??

{

u8 i,j;


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

{

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

{

;

}

}

}


void P3_2_key_func(void) interrupt 0 //外部中斷0服務例程

{

//將外部中斷0對應的按鍵K3設(shè)置為按鍵加功能

if(0 == key3)

{

delay(15);

if(0 == key3)

{

if(key_num < 9)

{

key_num++;

}

else

{

key_num = 0;

}

}

}

}


void P3_3_key_func(void) interrupt 2 //外部中斷1服務例程

{

//將外部中斷0對應的按鍵K4設(shè)置為按鍵減功能

if(0 == key4)

{

delay(15);

if(0 == key4)

{

if(key_num > 0)

{

key_num--;

}

else

{

key_num = 9;

}

}

}

}

現(xiàn)在我們還是來看一下仿真結(jié)果:

有了前面的文字說明這個程序應該是很簡單的吧,下面來我們一起來分析一下代碼含義:

u8 key_num = 0;這一句是定義個變量來存放實時的按鍵值,在按鍵中斷程序中將對這個變量進行加減操作。

IT0=1;和IT1=1;這兩句是將兩外部中斷都設(shè)為下降沿觸發(fā)中斷。

EX0=1;和EX1=1;這兩句是使能兩外部中斷源。

EA=1;這一句是開啟總中斷。

中斷配置中需要將這3步都配置好才能生效。

while(1)這一句是就是主循環(huán)程序了,需要重復進行的程序都可以放在這里。

void P3_2_key_func(void) interrupt 0 和void P3_3_key_func(void) interrupt 2?這兩個函數(shù)就是我們定義的中斷處理函數(shù),在函數(shù)內(nèi)部我們確定對應的按鍵之后在if(){}else{}語句中對key_num 變量進行循環(huán)加減操作。這樣主函數(shù)中就可以顯示當前數(shù)值是多少了。

看完了整個程序是不是感覺非常簡單呢?平時可以把自己的想法寫下來通過程序?qū)崿F(xiàn),看是否可以正確運用。

矩陣按鍵

說完了按鍵和外部中斷內(nèi)容,我們的按鍵部分基礎(chǔ)知識就介紹完了,但是實際使用過程中我們還會碰到各種各樣的按鍵電路,這就需要我們運用所學基礎(chǔ)知識進行分析了。比如矩陣按鍵就是我們運用按鍵的擴展知識,它是怎么樣的呢?

矩陣按鍵

如圖所示的矩陣按鍵電路就是最常見的一種。你是不是想問它使用8個引腳是怎么實現(xiàn)的那么多按鍵檢測的呢?答案就是通過行列掃描,還記得前面講動態(tài)數(shù)碼管顯示的內(nèi)容中怎么實現(xiàn)兩位數(shù)碼管同時顯示的?那里是快速進行端口輸出數(shù)據(jù)及com引腳切換,這里也是差不多的道理,在程序中快速的進行段端口數(shù)據(jù)掃描按鍵掃描將每個按鍵按下時產(chǎn)生的鍵值存儲起來對結(jié)果進行對比就實現(xiàn)了。運用這個原理8個引腳甚至還可以接更多的按鍵,但這只是作為一個擴展知識,平時使用不多,有興趣的朋友可以查閱一下資料了解一下。那么矩陣鍵盤具體是怎么實現(xiàn)功能的呢?不妨自己先動手試試。

小結(jié)

這一節(jié)介紹了在單片機中這么使用按鍵依以及對單片機外部中斷的使用,這是做單片機開發(fā)時最常見的應用,所以需要好好消化這部分知識。多動手試試,又遇到問題即使解決。下一節(jié)我們將講解單片機的另一種中斷--定時器中斷。

附文:矩陣按鍵程序

/*

*這是一個矩陣按鍵處理程序

*目的是通過掃描的方式獲取矩陣按鍵鍵值并顯示

*/

#include <reg52.h>

#include <intrins.h>


sbit com1 = P2^0; //定義數(shù)碼管com1引腳

sbit com2 = P2^1; //定義數(shù)碼管com2引腳


sbit key1 = P3^0;

sbit key2 = P3^1;

sbit key3 = P3^2;

sbit key4 = P3^3;


typedef unsigned char u8;

typedef unsigned int ?u16;


u8 temp_key = 0; //定義一個變量用來存放臨時按鍵值


u8 key_num = 0;//定義一個數(shù)字,用來顯示

u8 value = 88,n,i,j,key_num;


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

u8 code keycodetable[]={0x7e,0x7d,0x7b,0x77,0xbe,0xbd,0xbb,0xb7,0xde,0xdd,0xdb,0xd7,0xee,0xed,0xeb,0xe7 };//鍵盤數(shù)組

void delay(u8 ms);

u8 check_key(void);

u8 key_scan(void);

void display(u8 dat);


void main()

{

?while(1)

?{

? display(key_scan());

?}

}


void delay(u8 ms)

{

? ? u8 i,j;


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

? ? {

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

? ? ? ? {

? ? ? ? ? ? ;

? ? ? ? }

? ? }

}


u8 check_key(void)

{

? ? u8 n;

? ? P3 = 0x0f; ?? ? ?? ?

? ? n = P3;

? ? if(n!=0x0f)

? ? return 1; //有,返回1

? ? else?

? ? return 0; //無則返回0

}


u8 key_scan(void)

{


if(check_key()==1)

{

delay(5);

if(check_key()==1)

{

P3=0x0f;

i=P3;

P3=0xf0; //列行掃描,尋找按鍵

j=P3;

i=i|j;

for(n=0;n<16;n++) //查詢鍵值

{

if(keycodetable[n]==i)

{

?? ?value=n;

}

}

// while(check_key()); //松手檢測

}

}

return(value); //返回鍵值

}


void display(u8 dat)

{

P2 = 0xfe;

P0 = num_codelist[dat/10];

delay(1);


P2 = 0xfd;

P0 = num_codelist[dat%10];

delay(1);

}

再看看程序仿真結(jié)果:

仿真結(jié)果


51單片機編程開發(fā)(六)之按鍵與外部中斷的評論 (共 條)

分享到微博請遵守國家法律
鄯善县| 罗田县| 乐安县| 德兴市| 曲阳县| 左权县| 靖边县| 南京市| 斗六市| 铁力市| 泌阳县| 比如县| 峨山| 阳西县| 霍城县| 临夏县| 曲阳县| 渭源县| 巴马| 漠河县| 阜新| 灵宝市| 惠州市| 安顺市| 开远市| 遵义县| 德格县| 晋宁县| 丹巴县| 建始县| 襄樊市| 鹿邑县| 临邑县| 赣榆县| 吕梁市| 迁安市| 堆龙德庆县| 嘉黎县| 民权县| 松阳县| 溧阳市|