標(biāo)題: 求教一個(gè)單片機(jī)矩陣按鍵的程序調(diào)試問(wèn)題 [打印本頁(yè)]

作者: wifen    時(shí)間: 2022-7-21 08:40
標(biāo)題: 求教一個(gè)單片機(jī)矩陣按鍵的程序調(diào)試問(wèn)題
    這段程序是摘錄的51hei單片機(jī)論壇的教程,這里有個(gè)說(shuō)明中斷函數(shù)中掃描 KeyIn 輸入和切換 KeyOut 輸出的順序與前面提到的順序不同,程序中我首先對(duì)所有的 KeyIn 輸入做了掃描、消抖,然后才切換到了下一次的 KeyOut 輸出,也就是說(shuō)我們中斷每次掃描的實(shí)際是上一次輸出選擇的那行按鍵,這是為什么呢?因?yàn)槿魏涡盘?hào)從輸出到穩(wěn)定都需要一個(gè)時(shí)間,有時(shí)它足夠快而有時(shí)卻不夠快,這取決于具體的電路設(shè)計(jì),我們這里的輸入輸出順序的顛倒就是為了讓輸出信號(hào)有足夠的時(shí)間(一次中斷間隔)來(lái)穩(wěn)定,并有足夠的時(shí)間來(lái)完成它對(duì)輸入的影響,當(dāng)你的按鍵電路中還有硬件電容消抖時(shí),這樣處理就是絕對(duì)必要的了,雖然這樣使得程序理解起來(lái)有點(diǎn)繞,但它的適應(yīng)性是最好的,換個(gè)說(shuō)法就是,這段程序足夠“健壯”,足以應(yīng)對(duì)各種惡劣情況 。
    這里我不太明白,一開始進(jìn)入中斷的時(shí)候,keyout等于0,然后程序往下跑,keyout++,等于1了,case1,打開的是第二行。但是第二行并沒有被拉低為0啊,這里不知道是為什么?
        不過(guò)我查閱了別的一些51的教程,關(guān)于矩陣按鍵這塊,貌似沒看到這么操作的,很是納悶,有這個(gè)必要嗎?別的程序都沒這么寫,包括它處理按鍵去抖的這個(gè)方法,哪種才是最優(yōu)的呢?是這種還是別人直接寫個(gè)delay()多少毫秒那種呢?

單片機(jī)源程序如下:
void InterruptTimer0() interrupt 1
{
unsigned char i;
static unsigned char keyout = 0; //矩陣按鍵掃描輸出索引
static unsigned char keybuf[4][4] = { //矩陣按鍵掃描緩沖區(qū)
{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}
};
TH0 = 0xFC;
TL0 = 0x67;
//重新加載初值

//將一行的 4 個(gè)按鍵值移入緩沖區(qū)
keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN_1;
keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN_2;
keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN_3;
keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN_4;
//消抖后更新按鍵狀態(tài)
for (i=0; i<4; i++) //每行 4 個(gè)按鍵,所以循環(huán) 4 次
{
if ((keybuf[keyout][ i] & 0x0F) == 0x00)
{ //連續(xù) 4 次掃描值為 0,即 4*4ms 內(nèi)都是按下狀態(tài)時(shí),可認(rèn)為按鍵已穩(wěn)定的按下
KeySta[keyout]
[ i] = 0;
}
else if ((keybuf[keyout]
[ i] & 0x0F) == 0x0F)
{ //連續(xù) 4 次掃描值為 1,即 4*4ms 內(nèi)都是彈起狀態(tài)時(shí),可認(rèn)為按鍵已穩(wěn)定的彈起
KeySta[keyout]
[ i] = 1;
[ i]}
[ i]}
//執(zhí)行下一次的掃描輸出
keyout++; //輸出索引遞增
keyout = keyout & 0x03; //索引值加到 4 即歸零
switch (keyout) //根據(jù)索引,釋放當(dāng)前輸出引腳,拉低下次的輸出引腳
{
case 0: KEY_OUT_4 = 1; KEY_OUT_1 = 0; break;
case 1: KEY_OUT_1 = 1; KEY_OUT_2 = 0; break;
case 2: KEY_OUT_2 = 1; KEY_OUT_3 = 0; break;
case 3: KEY_OUT_3 = 1; KEY_OUT_4 = 0; break;
default: break;
}
}  


作者: hzxyy    時(shí)間: 2022-7-21 10:27
找版主的書,這個(gè)按鍵章節(jié)部分,你再仔細(xì)看看,對(duì)照實(shí)驗(yàn),理解它
作者: wifen    時(shí)間: 2022-7-21 13:56
hzxyy 發(fā)表于 2022-7-21 10:27
找版主的書,這個(gè)按鍵章節(jié)部分,你再仔細(xì)看看,對(duì)照實(shí)驗(yàn),理解它

看過(guò)了,請(qǐng)問(wèn)有必要這么寫嗎?我看很多別 的書都不是這么寫的。
作者: hhh402    時(shí)間: 2022-7-22 10:13
樓主是做工控的吧對(duì)按鍵抗干擾有要求,樓主只是考慮了按下的情況,按鍵釋放沒有考慮,同時(shí)按鍵也沒有考慮,我寫有一個(gè)按鍵檢測(cè)程序,你參考一下。
這是按鍵檢測(cè)模塊函數(shù):要認(rèn)真看才能夠理解。
void key() //按鍵處理模塊,需要放在10ms中斷中運(yùn)行。!
/* 說(shuō)明:1、按鍵單擊,指按下100-1000ms內(nèi)釋放,加入時(shí)間限制是為了防止干擾。
             2、按鍵長(zhǎng)按,指按下3-10s內(nèi)釋放,加入時(shí)間限制是為了防止干擾。
             3、函數(shù)運(yùn)行后,按鍵值保存在key1、key2。用戶直接調(diào)用key1、key2即可。
*/
{
  u16 static kgr[4];    //必須要static,抗干擾時(shí)間數(shù)組
  u8  static kanggr[4]; //中間變量1
  u8  static anjtem[4]; //按鍵釋放中間變量。
  u8 i;
  u8 L_anj[4];
  L_anj[0]=k1;
  L_anj[1]=k2;
  L_anj[2]=k3;
  L_anj[3]=k4;
  for(i=0;i<3;i++)  //4個(gè)按鍵處理,key1,
   {
         if(L_anj[ i]==0)        //按鍵按下                                       
          { if(kanggr[ i]==0)        //中間變量1,與下面互鎖
             { kgr[ i]=0;                //抗干擾時(shí)間清零,每次按鍵只寫1次。
               kanggr[ i]=1;         //中間變量1
               anjtem[ i]=1;         //按鍵釋放中間變量。與下面互鎖
            }

           if(anjtem[ i]==1)
           {
                  kgr[ i]++;//10毫秒計(jì)時(shí)。
                  if(kgr[ i]>1000) //按鍵按下大于10秒,強(qiáng)制復(fù)位,防止誤按。
                   { anjtem[ i]=0; //按鍵釋放中間變量。與上面互鎖
                     kgr[ i]=0;
                   }
           }
         }

     else    //按鍵釋放
     { kanggr[ i]=0;           //中間變量1,與上面互鎖
           if(kgr[ i]>9 && kgr[ i]<99) //按鍵間隔100--1000毫秒才有效,防止電磁干擾。時(shí)間可以修改
                 key1=i+1;   //單擊,按鍵間隔100--1000毫秒,每次釋放只寫1次。一次只能夠按一個(gè)按鍵,不允許同時(shí)按鍵。
           else if(kgr[ i]>300 && kgr[ i]<1000) //按鍵間隔3000--10000毫秒才有效,防止電磁干擾。時(shí)間可以修改
                 key1=(i+1)*10;//長(zhǎng)按,按鍵間隔3--10秒,每次釋放只寫1次。
     }
  }

//下面是處理:key2是有按鍵按下就輸出鍵值。        
    for(i=0;i<3;i++)
         { if(L_anj[ i]==0)
           key2=i+1;//一次只能夠按一個(gè)按鍵,不允許同時(shí)按鍵。
         }
}

完整的程序參考:http://www.torrancerestoration.com/bbs/dpj-208253-1.html
作者: wifen    時(shí)間: 2022-7-22 16:35
hhh402 發(fā)表于 2022-7-22 10:13
樓主是做工控的吧對(duì)按鍵抗干擾有要求,樓主只是考慮了按下的情況,按鍵釋放沒有考慮,同時(shí)按鍵也沒有考慮, ...

哈,謝謝,不過(guò)你的變量全部都是漢語(yǔ)拼音,有點(diǎn)意思。
作者: hhh402    時(shí)間: 2022-7-23 13:54
本帖最后由 hhh402 于 2022-7-23 14:01 編輯
wifen 發(fā)表于 2022-7-22 16:35
哈,謝謝,不過(guò)你的變量全部都是漢語(yǔ)拼音,有點(diǎn)意思。

不會(huì)英語(yǔ),不過(guò)單片機(jī)C語(yǔ)言英文不多,編程核心還是算法,怎么通過(guò)已知的幾個(gè)變量計(jì)算出所需要的量。
作者: wifen    時(shí)間: 2022-7-25 07:53
hzxyy 發(fā)表于 2022-7-21 10:27
找版主的書,這個(gè)按鍵章節(jié)部分,你再仔細(xì)看看,對(duì)照實(shí)驗(yàn),理解它

看了也理解了,就是不知道這種寫法優(yōu)勢(shì)何在,實(shí)際工程中的寫法是怎樣的呢?
作者: bbxyliyang    時(shí)間: 2022-7-25 08:05
wifen 發(fā)表于 2022-7-21 13:56
看過(guò)了,請(qǐng)問(wèn)有必要這么寫嗎?我看很多別 的書都不是這么寫的。

小宋老師的書寫的比較好的,他是利用狀態(tài)機(jī)的思想來(lái)寫的,釋放了單片機(jī),不是用延時(shí)函數(shù)完成的。每個(gè)人的程序?qū)懛ǘ际遣灰粯拥,沒必要糾結(jié),只要?jiǎng)e人的程序來(lái)過(guò)來(lái)會(huì)改加工完成自己的功能就OK了。
作者: bbxyliyang    時(shí)間: 2022-7-25 08:08
wifen 發(fā)表于 2022-7-25 07:53
看了也理解了,就是不知道這種寫法優(yōu)勢(shì)何在,實(shí)際工程中的寫法是怎樣的呢?

這種寫法就是釋放了單片機(jī),單片機(jī)有更多的時(shí)間去干別的事情,而不是在延時(shí)等待,啥事也不干,實(shí)際的工程,實(shí)時(shí)要求不要就用delay函數(shù)就行了,對(duì)系統(tǒng)實(shí)時(shí)要求比較高的,就需要用狀態(tài)機(jī)思想編程。
作者: wuwuwuwuwukk    時(shí)間: 2022-7-25 14:40
我只會(huì)按行按列掃描寫的這種,新手勿嘲請(qǐng)教一下大神們上述矩陣按鍵代碼是提高穩(wěn)定性而加的判斷嘛?#include <REGX52.H>
#include "Delay.h"
unsigned char MatrixKey()
{
        unsigned char KeyNumber=0;
        P1=0xFF;
        P1_3=0;
        if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=1;}
        if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=5;}
        if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=9;}
        if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=13;}
        P1_2=0;
        if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=2;}
        if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=6;}
        if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=10;}
        if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=14;}
        P1_1=0;
        if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=3;}
        if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=7;}
        if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=11;}
        if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=15;}
        P1_0=0;
        if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=4;}
        if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=8;}
        if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=12;}
        if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=16;}
        return KeyNumber;
}
       
作者: wifen    時(shí)間: 2022-7-25 19:22
wuwuwuwuwukk 發(fā)表于 2022-7-25 14:40
我只會(huì)按行按列掃描寫的這種,新手勿嘲請(qǐng)教一下大神們上述矩陣按鍵代碼是提高穩(wěn)定性而加的判斷嘛?#i ...

你這個(gè)寫法有點(diǎn)繁瑣啊
作者: wulin    時(shí)間: 2022-7-25 21:07
wifen 發(fā)表于 2022-7-25 19:22
你這個(gè)寫法有點(diǎn)繁瑣啊

給你一個(gè)簡(jiǎn)單、實(shí)用、可靠、易懂的4*4矩陣按鍵程序參考。
  1. void key_scan()                                        //4*4矩陣按鍵掃描程序
  2. {
  3.         static bit sign=0;                        //按鍵狀態(tài)標(biāo)志位變量
  4.         static unsigned int count=0;//計(jì)數(shù)變量
  5.         P3=0xf0;                                        //賦值P3 1111 0000
  6.         if(P3!=0xf0)                                //檢測(cè)有按鍵按下
  7.         {
  8.                 if(++count>=10 && sign==0)//消抖(根據(jù)實(shí)際應(yīng)用場(chǎng)景調(diào)整計(jì)數(shù)值,控制在10~20ms)
  9.                 {                       
  10.                         sign=1;                        //按鍵狀態(tài)標(biāo)志置1
  11.                         switch(P3)
  12.                         {
  13.                                 case(0Xe0):KeyValue = 1;break;
  14.                                 case(0Xd0):KeyValue = 2;break;
  15.                                 case(0Xb0):KeyValue = 3;break;
  16.                                 case(0X70):KeyValue = 4;break;
  17.                         }
  18.                         P3=0x0f;                        //賦值P3 0000 1111
  19.                         switch(P3)
  20.                         {
  21.                                 case(0X0e):KeyValue+= 0;break;
  22.                                 case(0X0d):KeyValue+= 4;break;
  23.                                 case(0X0b):KeyValue+= 8;break;
  24.                                 case(0X07):KeyValue+=12;break;
  25.                         }
  26.                 }
  27.         }
  28.         else                                                //鍵抬起
  29.         {
  30.                 sign=0;                                //按鍵狀態(tài)標(biāo)志清0
  31.                 count=0;                                //消抖計(jì)數(shù)清0
  32.         }
  33. }
復(fù)制代碼

作者: bbxyliyang    時(shí)間: 2022-7-25 21:45
wuwuwuwuwukk 發(fā)表于 2022-7-25 14:40
我只會(huì)按行按列掃描寫的這種,新手勿嘲請(qǐng)教一下大神們上述矩陣按鍵代碼是提高穩(wěn)定性而加的判斷嘛?#i ...

這種寫法,容易理解




歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1