欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136

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

QQ登錄

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

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

最為精辟和實(shí)用的按鍵處理程序

  [復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:98238 發(fā)表于 2015-12-11 00:39 來(lái)自觸屏版 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
5黑幣
    最為精辟和實(shí)用的按鍵處理程序;1.新型的按鍵掃描程序;不過(guò)我在網(wǎng)上游逛了很久,也看過(guò)不少源程序了,沒(méi)有;同時(shí),這里面用到了一些分層的思想,在單片機(jī)當(dāng)中也;以下假設(shè)你懂C語(yǔ)言,因?yàn)榧兇獾腃語(yǔ)言描述,所以和;核心算法:;unsignedcharTrg;;unsignedcharCont;;voidKeyRead(void);unsignedcharReadDat

      最為精辟和實(shí)用的按鍵處理程序

      1.新型的按鍵掃描程序

      不過(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ì)驚嘆于這算法的精妙!! 下面是程序解釋?zhuān)?br />
      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!!

      (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,類(lèi)似,如果我們PB7按下的話,Trg 的值就應(yīng)該為 0x80 ,這個(gè)很好理解,還有,最關(guān)鍵的地方,Trg 的值每次按下只會(huì)出現(xiàn)一次,然后立刻被清除,完全不需要人工去干預(yù)。所以按鍵功能處理程序不會(huì)重復(fù)執(zhí)行,省下了一大堆的條件判斷,這個(gè)可是精粹哦!!Cont代表的是長(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è)!)

      #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è)非常類(lèi)似的處理程序,現(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ō)明原理~~

評(píng)分

參與人數(shù) 3黑幣 +11 收起 理由
13956466557 + 5 很給力!
秋雨綿綿 + 1 j絕對(duì)的好貼
提刀書(shū)生 + 5 很給力!

查看全部評(píng)分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏7 分享淘帖 頂3 踩
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:134830 發(fā)表于 2017-12-29 17:15 | 只看該作者
必須贊一個(gè),哇,想法賊厲害
回復(fù)

使用道具 舉報(bào)

板凳
ID:269228 發(fā)表于 2017-12-30 16:05 來(lái)自觸屏版 | 只看該作者
666摩拜大神
回復(fù)

使用道具 舉報(bào)

地板
ID:157975 發(fā)表于 2017-12-31 09:33 | 只看該作者
人才啊,佩服
回復(fù)

使用道具 舉報(bào)

5#
ID:67356 發(fā)表于 2018-2-26 06:02 | 只看該作者
雖然沒(méi)看懂,還是再堅(jiān)持學(xué)習(xí)
回復(fù)

使用道具 舉報(bào)

6#
ID:293729 發(fā)表于 2018-3-18 20:35 | 只看該作者
不錯(cuò)
這個(gè)是自己先寫(xiě)的
unsigned char this_key1;
unsigned char this_key2;
unsigned char this_key3;
unsigned char fst_key;
unsigned char key_l1;
unsigned char key_l2;
/*******************************************************
*»ñè¡I/OμÄÖμ
*******************************************************/
unsigned char read_gpio(void)
{
        unsigned char ret;
       
        ret = 0;
        //Õaàïìí¼ó¶áè¡I/OμÄÖμμÃóï¾ä£¬
        //×¢òa£¬retÖDμÄêǰ′λμļùèô0λ¶Ôó|P0^0,μú7λ¶Ôó|P^7
        return ret;
}
/*******************************************************
*
*******************************************************/
void        key_read_io(void)
{
        unsigned char ret;
       
        ret = read_gpio();
        this_key2 = this_key1 & ret;
        this_key1 = ret;
        fst_key   = this_key3 & (~this_key2);
        this_key3 = this_key2;
        if((this_key2 & 0x01) > 0)
        {
                key_l1++;
        }
        else
        {
                key_l1 = 0;
        }
        if((this_key2 & 0x02) > 0)
        {
                key_l2++;               
        }
        else
        {
                key_l2 = 0;
        }       
}
回復(fù)

使用道具 舉報(bào)

7#
ID:293729 發(fā)表于 2018-3-18 20:43 | 只看該作者
這個(gè)程序的精元在于,在主程序中while(1)循環(huán)中會(huì)不斷的調(diào)用按鍵程序,好處,代碼太精簡(jiǎn),壞處是,對(duì)長(zhǎng)按鍵處理有點(diǎn)欠缺,當(dāng)主程序執(zhí)行的非常快是, 對(duì)cnt_plus的要求就大了,可能要unsigned long int,否則會(huì)將短按鍵(動(dòng)作相對(duì)遲緩一點(diǎn)的短按鍵)誤認(rèn)為是長(zhǎng)按鍵,所以,主程序在執(zhí)行一個(gè)循環(huán)得有一個(gè)估算,否則很難確定 cnt_plus設(shè)定為多少
回復(fù)

使用道具 舉報(bào)

8#
ID:312179 發(fā)表于 2018-4-20 09:26 | 只看該作者
好貼子,有很大幫助
回復(fù)

使用道具 舉報(bào)

9#
ID:312179 發(fā)表于 2018-4-25 10:19 | 只看該作者

吊炸天的感覺(jué),太牛了
回復(fù)

使用道具 舉報(bào)

10#
ID:312179 發(fā)表于 2018-4-25 14:31 | 只看該作者
liuqihui66 發(fā)表于 2018-3-18 20:43
這個(gè)程序的精元在于,在主程序中while(1)循環(huán)中會(huì)不斷的調(diào)用按鍵程序,好處,代碼太精簡(jiǎn),壞處是,對(duì)長(zhǎng)按鍵 ...

正解,長(zhǎng)按鍵確實(shí)有待研究
回復(fù)

使用道具 舉報(bào)

11#
ID:324844 發(fā)表于 2018-7-5 18:34 | 只看該作者
看不懂,但是很了不起,膜拜大神
回復(fù)

使用道具 舉報(bào)

12#
ID:366893 發(fā)表于 2018-7-7 21:47 | 只看該作者
很早就一直在用這個(gè)按鍵掃描了,的確很精辟!
回復(fù)

使用道具 舉報(bào)

13#
ID:379784 發(fā)表于 2018-7-27 11:28 | 只看該作者
很精辟的程序,說(shuō)得也很清楚,大贊。話說(shuō)不用消抖嗎?
回復(fù)

使用道具 舉報(bào)

14#
ID:281021 發(fā)表于 2018-10-9 09:34 | 只看該作者
路過(guò),看看
回復(fù)

使用道具 舉報(bào)

15#
ID:535834 發(fā)表于 2019-9-29 23:28 | 只看該作者
學(xué)渣與學(xué)霸 發(fā)表于 2018-7-27 11:28
很精辟的程序,說(shuō)得也很清楚,大贊。話說(shuō)不用消抖嗎?

看懂就知道不用啦
回復(fù)

使用道具 舉報(bào)

16#
ID:665950 發(fā)表于 2019-12-17 10:01 | 只看該作者
很好!!!!
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

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

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

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