日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當(dāng)前位置:首頁(yè) > 單片機(jī) > 單片機(jī)
[導(dǎo)讀]新型的按鍵掃描程序不過(guò)我在網(wǎng)上游逛了很久,也看過(guò)不少源程序了,沒(méi)有發(fā)現(xiàn)這種按鍵處理辦法的蹤跡,所以,我將他共享出來(lái),和廣大同僚們共勉。我非常堅(jiān)信這種按鍵處理辦法的便捷和高效,你可以移植到任何一種嵌入式

新型的按鍵掃描程序
不過(guò)我在網(wǎng)上游逛了很久,也看過(guò)不少源程序了,沒(méi)有發(fā)現(xiàn)這種按鍵處理辦法的蹤跡,所以,我將他共享出來(lái),和廣大同僚們共勉。我非常堅(jiān)信這種按鍵處理辦法的便捷和高效,你可以移植到任何一種嵌入式處理器上面,因?yàn)镃語(yǔ)言強(qiáng)大的可移植性。
同時(shí),這里面用到了一些分層的思想,在單片機(jī)當(dāng)中也是相當(dāng)有用的,也是本文的另外一個(gè)重點(diǎn)。
對(duì)于老鳥(niǎo),我建議直接看那兩個(gè)表達(dá)式,然后自己想想就會(huì)懂的了,也不需要聽(tīng)我后面的自吹自擂了,我可沒(méi)有班門(mén)弄斧的意思,hoho~~但是對(duì)于新手,我建議將全文看完。因?yàn)檫@是實(shí)際項(xiàng)目中總結(jié)出來(lái)的經(jīng)驗(yàn),學(xué)校里面學(xué)不到的東西。
以下假設(shè)你懂C語(yǔ)言,因?yàn)榧兇獾腃語(yǔ)言描述,所以和處理器平臺(tái)無(wú)關(guān),你可以在MCS-51,AVR,PIC,甚至是ARM平臺(tái)上面測(cè)試這個(gè)程序性能。當(dāng)然,我自己也是在多個(gè)項(xiàng)目用過(guò),效果非常好的。
好了,工程人員的習(xí)慣,廢話就應(yīng)該少說(shuō),開(kāi)始吧。以下我以AVR的MEGA8作為平臺(tái)講解,沒(méi)有其它原因,因?yàn)槲沂诸^上只有AVR的板子而已沒(méi)有51的。用51也可以,只是芯片初始化部分不同,還有寄存器名字不同而已。
核心算法:
unsigned char Trg;
unsigned char Cont;
void KeyRead( void )
{
unsigned char ReadData = PINB^0xff;// 1
Trg = ReadData & (ReadData ^ Cont);// 2
Cont = ReadData;// 3
}
完了。有沒(méi)有一種不可思議的感覺(jué)?當(dāng)然,沒(méi)有想懂之前會(huì)那樣,想懂之后就會(huì)驚嘆于這算法的精妙??!
下面是程序解釋:
Trg(triger) 代表的是觸發(fā),Cont(continue)代表的是連續(xù)按下。
1:讀PORTB的端口數(shù)據(jù),取反,然后送到ReadData 臨時(shí)變量里面保存起來(lái)。
2:算法1,用來(lái)計(jì)算觸發(fā)變量的。一個(gè)位與操作,一個(gè)異或操作,我想學(xué)過(guò)C語(yǔ)言都應(yīng)該懂吧?Trg為全局變量,其它程序可以直接引用。
3:算法2,用來(lái)計(jì)算連續(xù)變量。
看到這里,有種“知其然,不知其所以然”的感覺(jué)吧?代碼很簡(jiǎn)單,但是它到底是怎么樣實(shí)現(xiàn)我們的目的的呢?好,下面就讓我們繞開(kāi)云霧看青天吧。
我們最常用的按鍵接法如下:AVR是有內(nèi)部上拉功能的,但是為了說(shuō)明問(wèn)題,我是特意用外部上拉電阻。那么,按鍵沒(méi)有按下的時(shí)候,讀端口數(shù)據(jù)為1,如果按鍵按下,那么端口讀到0。下面就看看具體幾種情況之下,這算法是怎么一回事。
(1)沒(méi)有按鍵的時(shí)候
端口為0xff,ReadData讀端口并且取反,很顯然,就是 0x00 了。
Trg = ReadData & (ReadData ^ Cont); (初始狀態(tài)下,Cont也是為0的)很簡(jiǎn)單的數(shù)學(xué)計(jì)算,因?yàn)镽eadData為0,則它和任何數(shù)“相與”,結(jié)果也是為0的。
Cont = ReadData; 保存Cont 其實(shí)就是等于ReadData,為0;
結(jié)果就是:
ReadData = 0;
Trg = 0;
Cont = 0;
(2)第一次PB0按下的情況
端口數(shù)據(jù)為0xfe,ReadData讀端口并且取反,很顯然,就是 0x01 了。
Trg = ReadData & (ReadData ^ Cont); 因?yàn)檫@是第一次按下,所以Cont是上次的值,應(yīng)為為0。那么這個(gè)式子的值也不難算,也就是 Trg = 0x01 & (0x01^0x00) = 0x01
Cont = ReadData = 0x01;
結(jié)果就是:
ReadData = 0x01;
Trg = 0x01;Trg只會(huì)在這個(gè)時(shí)候?qū)?yīng)位的值為1,其它時(shí)候都為0
Cont = 0x01;
(3)PB0按著不松(長(zhǎng)按鍵)的情況
端口數(shù)據(jù)為0xfe,ReadData讀端口并且取反是 0x01 了。
Trg = ReadData & (ReadData ^ Cont); 因?yàn)檫@是連續(xù)按下,所以Cont是上次的值,應(yīng)為為0x01。那么這個(gè)式子就變成了 Trg = 0x01 & (0x01^0x01) = 0x00
Cont = ReadData = 0x01;
結(jié)果就是:
ReadData = 0x01;
Trg = 0x00;
Cont = 0x01;
因?yàn)楝F(xiàn)在按鍵是長(zhǎng)按著,所以MCU會(huì)每個(gè)一定時(shí)間(20ms左右)不斷的執(zhí)行這個(gè)函數(shù),那么下次執(zhí)行的時(shí)候情況會(huì)是怎么樣的呢?
ReadData = 0x01;這個(gè)不會(huì)變,因?yàn)榘存I沒(méi)有松開(kāi)
Trg = ReadData & (ReadData ^ Cont) = 0x01 & (0x01 ^ 0x01) = 0 ,只要按鍵沒(méi)有松開(kāi),這個(gè)Trg值永遠(yuǎn)為 0 ?。?!
Cont = 0x01;只要按鍵沒(méi)有松開(kāi),這個(gè)值永遠(yuǎn)是0x01?。?br/>(4)按鍵松開(kāi)的情況
端口數(shù)據(jù)為0xff,ReadData讀端口并且取反是 0x00 了。
Trg = ReadData & (ReadData ^ Cont) = 0x00 & (0x00^0x01) = 0x00
Cont = ReadData = 0x00;
結(jié)果就是:
ReadData = 0x00;
Trg = 0x00;
Cont = 0x00;
很顯然,這個(gè)回到了初始狀態(tài),也就是沒(méi)有按鍵按下的狀態(tài)。
總結(jié)一下,不知道想懂了沒(méi)有?其實(shí)很簡(jiǎn)單,答案如下:
Trg 表示的就是觸發(fā)的意思,也就是跳變,只要有按鍵按下(電平從1到0的跳變),那么Trg在對(duì)應(yīng)按鍵的位上面會(huì)置一,我們用了PB0則Trg的值為0x01,類似,如果我們PB7按下的話,Trg 的值就應(yīng)該為 0x80 ,這個(gè)很好理解,還有,最關(guān)鍵的地方,Trg 的值每次按下只會(huì)出現(xiàn)一次,然后立刻被清除,完全不需要人工去干預(yù)。所以按鍵功能處理程序不會(huì)重復(fù)執(zhí)行,省下了一大堆的條件判斷,這個(gè)可是精粹哦?。ont代表的是長(zhǎng)按鍵,如果PB0按著不放,那么Cont的值就為 0x01,相對(duì)應(yīng),PB7按著不放,那么Cont的值應(yīng)該為0x80,同樣很好理解。
如果還是想不懂的話,可以自己演算一下那兩個(gè)表達(dá)式,應(yīng)該不難理解的。
因?yàn)橛辛诉@個(gè)支持,那么按鍵處理就變得很爽了,下面看應(yīng)用:
應(yīng)用一:一次觸發(fā)的按鍵處理
假設(shè)PB0為蜂鳴器按鍵,按一下,蜂鳴器beep的響一聲。這個(gè)很簡(jiǎn)單,但是大家以前是怎么做的呢?對(duì)比一下看誰(shuí)的方便?
#define KEY_BEEP 0x01
void KeyProc(void)
{
if (Trg & KEY_BEEP) // 如果按下的是KEY_BEEP
{
Beep();// 執(zhí)行蜂鳴器處理函數(shù)
}
}
怎么樣?夠和諧不?記得前面解釋說(shuō)Trg的精粹是什么?精粹就是只會(huì)出現(xiàn)一次。所以你按下按鍵的話,Trg & KEY_BEEP 為“真”的情況只會(huì)出現(xiàn)一次,所以處理起來(lái)非常的方便,蜂鳴器也不會(huì)沒(méi)事亂叫,hoho~~~
或者你會(huì)認(rèn)為這個(gè)處理簡(jiǎn)單,沒(méi)有問(wèn)題,我們繼續(xù)。
應(yīng)用2:長(zhǎng)按鍵的處理
項(xiàng)目中經(jīng)常會(huì)遇到一些要求,例如:一個(gè)按鍵如果短按一下執(zhí)行功能A,如果長(zhǎng)按2秒不放的話會(huì)執(zhí)行功能B,又或者是要求3秒按著不放,計(jì)數(shù)連加什么什么的功能,很實(shí)際。不知道大家以前是怎么做的呢?我承認(rèn)以前做的很郁悶。
但是看我們這里怎么處理吧,或許你會(huì)大吃一驚,原來(lái)程序可以這么簡(jiǎn)單
這里具個(gè)簡(jiǎn)單例子,為了只是說(shuō)明原理,PB0是模式按鍵,短按則切換模式,PB1就是加,如果長(zhǎng)按的話則連加(玩過(guò)電子表吧?沒(méi)錯(cuò),就是那個(gè)?。?br/>#define KEY_MODE 0x01// 模式按鍵
#define KEY_PLUS 0x02// 加
void KeyProc(void)
{
if (Trg & KEY_MODE) // 如果按下的是KEY_MODE,而且你常按這按鍵也沒(méi)有用,
{//它是不會(huì)執(zhí)行第二次的哦 , 必須先松開(kāi)再按下
Mode++;// 模式寄存器加1,當(dāng)然,這里只是演示,你可以執(zhí)行你想
// 執(zhí)行的任何代碼
}
if (Cont & KEY_PLUS) // 如果“加”按鍵被按著不放
{
cnt_plus++;// 計(jì)時(shí)
if (cnt_plus > 100) // 20ms*100 = 2S 如果時(shí)間到
{
Func();// 你需要的執(zhí)行的程序
}
}
}
不知道各位感覺(jué)如何?我覺(jué)得還是挺簡(jiǎn)單的完成了任務(wù),當(dāng)然,作為演示用代碼。
應(yīng)用3:點(diǎn)觸型按鍵和開(kāi)關(guān)型按鍵的混合使用
點(diǎn)觸形按鍵估計(jì)用的最多,特別是單片機(jī)。開(kāi)關(guān)型其實(shí)也很常見(jiàn),例如家里的電燈,那些按下就不松開(kāi),除非關(guān)。這是兩種按鍵形式的處理原理也沒(méi)啥特別,但是你有沒(méi)有想過(guò),如果一個(gè)系統(tǒng)里面這兩種按鍵是怎么處理的?我想起了我以前的處理,分開(kāi)兩個(gè)非常類似的處理程序,現(xiàn)在看起來(lái)真的是笨的不行了,但是也沒(méi)有辦法啊,結(jié)構(gòu)決定了程序。不過(guò)現(xiàn)在好了,用上面介紹的辦法,很輕松就可以搞定。
原理么?可能你也會(huì)想到,對(duì)于點(diǎn)觸開(kāi)關(guān),按照上面的辦法處理一次按下和長(zhǎng)按,對(duì)于開(kāi)關(guān)型,我們只需要處理Cont就OK了,為什么?很簡(jiǎn)單嘛,把它當(dāng)成是一個(gè)長(zhǎng)按鍵,這樣就找到了共同點(diǎn),屏蔽了所有的細(xì)節(jié)。程序就不給了,完全就是應(yīng)用2的內(nèi)容,在這里提為了就是說(shuō)明原理~~
好了,這個(gè)好用的按鍵處理算是說(shuō)完了??赡軙?huì)有朋友會(huì)問(wèn),為什么不說(shuō)延時(shí)消抖問(wèn)題?哈哈,被看穿了。果然不能偷懶。下面談?wù)勥@個(gè)問(wèn)題,順便也就非常簡(jiǎn)單的談?wù)勎易约河脮r(shí)間片輪辦法,以及是如何消抖的。
延時(shí)消抖的辦法是非常傳統(tǒng),也就是 第一次判斷有按鍵,延時(shí)一定的時(shí)間(一般習(xí)慣是20ms)再讀端口,如果兩次讀到的數(shù)據(jù)一樣,說(shuō)明了是真正的按鍵,而不是抖動(dòng),則進(jìn)入按鍵處理程序。
當(dāng)然,不要跟我說(shuō)你delay(20)那樣去死循環(huán)去,真是那樣的話,我衷心的建議你先放下手上所有的東西,好好的去了解一下操作系統(tǒng)的分時(shí)工作原理,大概知道思想就可以,不需要詳細(xì)看原理,否則你永遠(yuǎn)逃不出“菜鳥(niǎo)”這個(gè)圈子。當(dāng)然我也是菜鳥(niǎo)。我的意思是,真正的單片機(jī)入門(mén),是從學(xué)會(huì)處理多任務(wù)開(kāi)始的,這個(gè)也是學(xué)校程序跟公司程序的最大差別。當(dāng)然,本文不是專門(mén)說(shuō)這個(gè)的,所以也不獻(xiàn)丑了。
我的主程序架構(gòu)是這樣的:
volatile unsigned char Intrcnt;
void InterruptHandle()// 中斷服務(wù)程序
{
Intrcnt++;// 1ms 中斷1次,可變
}
void main(void)
{
SysInit();
while(1)// 每20ms 執(zhí)行一次大循環(huán)
{
KeyRead();// 將每個(gè)子程序都掃描一遍
KeyProc();
Func1();
Funt2();


while(1)
{
if (Intrcnt>20)// 一直在等,直到20ms時(shí)間到
{
Intrcnt="0";
break;// 返回主循環(huán)
}
}
}
}
貌似扯遠(yuǎn)了,回到我們剛才的問(wèn)題,也就是怎么做按鍵消抖處理。我們將讀按鍵的程序放在了主循環(huán),也就是說(shuō),每20ms我們會(huì)執(zhí)行一次KeyRead()函數(shù)來(lái)得到新的Trg 和 Cont 值。好了,下面是我的消抖部分:很簡(jiǎn)單
基本架構(gòu)如上,我自己比較喜歡的,一直在用。當(dāng)然,和這個(gè)配合,每個(gè)子程序必須執(zhí)行時(shí)間不長(zhǎng),更加不能死循環(huán),一般采用有限狀態(tài)機(jī)的辦法來(lái)實(shí)現(xiàn),具體參考其它資料咯。
懂得基本原理之后,至于怎么用就大家慢慢思考了,我想也難不到聰明的工程師們。例如還有一些處理,
怎么判斷按鍵釋放?很簡(jiǎn)單,Trg 和Cont都為0 則肯定已經(jīng)釋放了。

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

8位單片機(jī)在嵌入式設(shè)計(jì)領(lǐng)域已經(jīng)成為半個(gè)多世紀(jì)以來(lái)的主流選擇。盡管嵌入式系統(tǒng)市場(chǎng)日益復(fù)雜,8位單片機(jī)依然不斷發(fā)展,積極應(yīng)對(duì)新的挑戰(zhàn)和系統(tǒng)需求。如今,Microchip推出的8位PIC?和AVR?單片機(jī)系列,配備了先進(jìn)的獨(dú)立...

關(guān)鍵字: 單片機(jī) 嵌入式 CPU

在嵌入式系統(tǒng)開(kāi)發(fā)中,程序燒錄是連接軟件設(shè)計(jì)與硬件實(shí)現(xiàn)的關(guān)鍵環(huán)節(jié)。當(dāng)前主流的單片機(jī)燒錄技術(shù)已形成ICP(在電路編程)、ISP(在系統(tǒng)編程)、IAP(在應(yīng)用編程)三大技術(shù)體系,分別對(duì)應(yīng)開(kāi)發(fā)調(diào)試、量產(chǎn)燒錄、遠(yuǎn)程升級(jí)等不同場(chǎng)景。...

關(guān)鍵字: 單片機(jī) ISP ICP IAP 嵌入式系統(tǒng)開(kāi)發(fā)

在嵌入式系統(tǒng)開(kāi)發(fā)中,看門(mén)狗(Watchdog Timer, WDT)是保障系統(tǒng)可靠性的核心組件,其初始化時(shí)機(jī)的選擇直接影響系統(tǒng)抗干擾能力和穩(wěn)定性。本文從硬件架構(gòu)、軟件流程、安全規(guī)范三個(gè)維度,系統(tǒng)分析看門(mén)狗初始化的最佳實(shí)踐...

關(guān)鍵字: 單片機(jī) 看門(mén)狗 嵌入式系統(tǒng)

本文中,小編將對(duì)單片機(jī)予以介紹,如果你想對(duì)它的詳細(xì)情況有所認(rèn)識(shí),或者想要增進(jìn)對(duì)它的了解程度,不妨請(qǐng)看以下內(nèi)容哦。

關(guān)鍵字: 單片機(jī) 開(kāi)發(fā)板 Keil

隨著單片機(jī)系統(tǒng)越來(lái)越廣泛地應(yīng)用于消費(fèi)類電子、醫(yī)療、工業(yè)自動(dòng)化、智能化儀器儀表、航空航天等各領(lǐng)域,單片機(jī)系統(tǒng)面臨著電磁干擾(EMI)日益嚴(yán)重的威脅。電磁兼容性(EMC)包含系統(tǒng)的發(fā)射和敏感度兩方面的問(wèn)題。

關(guān)鍵字: 單片機(jī) 電磁兼容

以下內(nèi)容中,小編將對(duì)單片機(jī)的相關(guān)內(nèi)容進(jìn)行著重介紹和闡述,希望本文能幫您增進(jìn)對(duì)單片機(jī)的了解,和小編一起來(lái)看看吧。

關(guān)鍵字: 單片機(jī) 復(fù)位電路

在這篇文章中,小編將為大家?guī)?lái)單片機(jī)的相關(guān)報(bào)道。如果你對(duì)本文即將要講解的內(nèi)容存在一定興趣,不妨繼續(xù)往下閱讀哦。

關(guān)鍵字: 單片機(jī) 異常復(fù)位

今天,小編將在這篇文章中為大家?guī)?lái)單片機(jī)的有關(guān)報(bào)道,通過(guò)閱讀這篇文章,大家可以對(duì)它具備清晰的認(rèn)識(shí),主要內(nèi)容如下。

關(guān)鍵字: 單片機(jī) 仿真器

單片機(jī)將是下述內(nèi)容的主要介紹對(duì)象,通過(guò)這篇文章,小編希望大家可以對(duì)它的相關(guān)情況以及信息有所認(rèn)識(shí)和了解,詳細(xì)內(nèi)容如下。

關(guān)鍵字: 單片機(jī) 中斷 boot

一直以來(lái),單片機(jī)都是大家的關(guān)注焦點(diǎn)之一。因此針對(duì)大家的興趣點(diǎn)所在,小編將為大家?guī)?lái)單片機(jī)的相關(guān)介紹,詳細(xì)內(nèi)容請(qǐng)看下文。

關(guān)鍵字: 單片機(jī) 數(shù)字信號(hào) 模擬信號(hào)
關(guān)閉