[教學] 讀取 3x4 Keypad 的輸入

探討「內嵌」以及「腳本化」這兩個主題的技術-版主XO老師(熟悉的目前是 Tcl,討論內容也會環繞在 Tcl 四周,但是本版還是歡迎其他 Scripting 語言以及任何「內嵌」技術的討論。)

版主: b80203, ghost3401, XO, maa

分享到: Facebook

[教學] 讀取 3x4 Keypad 的輸入

文章maa » 週日 1月 30, 2011 9:12 pm

我已經學會使用 Keypad 了,請見我的筆記:

Arduino 筆記 - Lab18 讀取 3x4 Keypad 的輸入

原來 Keypad 的原理這麼簡單... :D
maa
版面管理員
 
文章: 631
註冊時間: 週一 9月 13, 2004 10:16 am
來自: 縱橫資通能源

Re:[教學] 讀取 3x4 Keypad 的輸入

文章XO » 週一 1月 31, 2011 10:59 am

真幸福... 現在都有 Library function 來幫你處理 Debouncing 的問題...
相當年西北研究所時,Microprocessor System Design 課程裡,也用 Intel 8080 寫過
Keypad Driver,試想一個硬物掉落地面,總要彈跳個幾下才會「停穩」靜止下來。

同樣的...

按下一個鍵也是一樣,按下後,鍵盤下方接觸點也是要「彈跳幾下子」才會停穩下來!

就像小馬這裡分享的文章圖片,按鍵被安排在 X-Y 垂直交叉、但又沒「接觸」在一起的線路上方處。
按下鍵後,會在該鍵下方讓這特定一組 X-Y 方向原來沒搭嘎的兩條線路「搭鐵」在一起,變成導通狀態。

Keypad 驅動程式,其實就是依序在 X 方向上每一條線路灌上電流,然後在 Y 方向上再依序
去 scan 哪一條線路被導通,正在灌的 X 與偵測到的 Y 兩線交叉處,就是被按下的鍵,就這麼回事兒!

可是如果按下的鍵會有這彈跳現象,在彈跳當下,你偵測不到並不意味該鍵沒按下,也許是已經按下,只
是你掃描那一會兒,正在「高空彈跳」中ㄇㄟ...

呵呵~~~ 好玩的技巧就在這兒哪... 挺懷念那些芝加哥的歲月。

剛剛翻出當年用書:John B. PeatMan的 "Microcomputer-Based Design", 1977 McGraw Hill, Inc.
最後由 XO 於 週一 1月 31, 2011 4:16 pm 編輯,總共編輯了 2 次。
eXtra Old 的是我「不是酒」哦!
제 이름은 오조휘 입니다

臉書裡依舊是 Extra.Old: http://www.facebook.com/extra.old
頭像
XO
資管系教師
 
文章: 5352
註冊時間: 週二 4月 27, 2004 12:20 pm
來自: CQ Inc.

Re:[教學] 讀取 3x4 Keypad 的輸入

文章maa » 週一 1月 31, 2011 11:41 am

Arduino Keypad Library 中負責處理「鍵盤掃瞄」和「debounce - 避免將機械彈跳誤判為輸入的處理」的
,就是底下這段 code:

代碼: 選擇全部
// Returns the keykode of the pressed key, or NO_KEY if no key is pressed
char Keypad::getKey(){
   char key = NO_KEY; // Assume that no key is pressed, this is the default return for getKey()
    for (byte c=0; c<size.columns; c++){
      digitalWrite(columnPins[c],LOW);   // Activate the current column.
      for (byte r=0; r<size.rows; r++){   // Scan all the rows for a key press.
         //  The user pressed a button for more then debounceTime microseconds.
         if (currentKey == keymap[c+(r*size.columns)]){
            // Button hold
            if (((millis()-lastUpdate) >= holdTime) && digitalRead(rowPins[r]) == LOW){
               transitionTo(HOLD);
            }
            // Button release
            if (((millis()-lastUpdate) >= debounceTime) && digitalRead(rowPins[r]) == HIGH){
               transitionTo(RELEASED);
               currentKey = NO_KEY;
            }
         }
         // Button pressed event.  The user pressed a button.
         else if (((millis()-lastUpdate) >= debounceTime) && digitalRead(rowPins[r]) == LOW){
            digitalWrite(columnPins[c],HIGH);   // De-activate the current column.
            key = keymap[c+(r*size.columns)];
            lastUpdate = millis();
            goto EVALUATE_KEY;          // Save resources and do not attempt to parse to keys at a time
         }
      }
      digitalWrite(columnPins[c],HIGH);   // De-activate the current column.
   }
   
   EVALUATE_KEY:
   if (key != NO_KEY && key != currentKey){
      currentKey = key;
      transitionTo(PRESSED);
      return currentKey;
   }
   else{
      return NO_KEY;
   }
}


這個 Keypad 驅動程式,掃瞄鍵盤的方向剛好跟老師講的相反,它是依序在 Y 方向上每一條線路灌上電流,
然後在 X 方向上再依序 去 scan 哪一條線路被導通,正在灌的 Y 與偵測到的 X 兩線交叉處,就是被按下的鍵。

就像在玩電子積木一樣,玩 Arduino 的好處就是,即使你不懂鍵盤掃瞄和 debounce 的原理,也可以很輕易的把東西組合起來。
當然,因為 Library 都是 Open Source 的,如果想要深入了解的話,也可以看個人興趣或需要往下挖掘。
maa
版面管理員
 
文章: 631
註冊時間: 週一 9月 13, 2004 10:16 am
來自: 縱橫資通能源

Re:[教學] 讀取 3x4 Keypad 的輸入

文章XO » 週一 1月 31, 2011 4:12 pm

試著幫樓上程式碼美編一下,看看在這 Phpbb 裡,會不會看起來好些:(如果...
再把下面那鍋 Code 標籤後面的 syntax off 給它 Click 一下,看起來又會更好些。)

代碼: 選擇全部
// Returns the keycode of the pressed key, or NO_KEY if no key is pressed

char Keypad::getKey() {
 
  // Assume that no key is pressed, this is the default return for getKey()
  char key = NO_KEY;

  for(byte c=0; c<size.columns; c++) {

    digitalWrite(columnPins[c],LOW);      // Activate the current column.

    for(byte r=0; r<size.rows; r++) {     // Scan all the rows for a key press.
      if(currentKey == keymap[c+(r*size.columns)]){
        //  The user pressed a button for more then debounceTime microseconds.

        // Button hold
        if(((millis()-lastUpdate) >= holdTime) &&
         digitalRead(rowPins[r]) == LOW) {
          transitionTo(HOLD);
        }
        // Button release
        if(((millis()-lastUpdate) >= debounceTime) &&
         digitalRead(rowPins[r]) == HIGH) {
          transitionTo(RELEASED);
          currentKey = NO_KEY;
        }
      } else if(((millis()-lastUpdate) >= debounceTime) &&
             digitalRead(rowPins[r]) == LOW) {
        // Button pressed event.  The user pressed a button.
          
        digitalWrite(columnPins[c],HIGH); // De-activate the current column.
        key = keymap[c+(r*size.columns)];
        lastUpdate = millis();
        goto EVALUATE_KEY;                // Save resources and do not attempt
                                          // to parse to keys at a time
      }
    } // end of inner for(...
    digitalWrite(columnPins[c],HIGH);     // De-activate the current column.

  } // end of outer for(...
   
  EVALUATE_KEY:
  if (key != NO_KEY && key != currentKey){
    currentKey = key;
    transitionTo(PRESSED);
    return currentKey;
  } else {
    return NO_KEY;
  }
}
eXtra Old 的是我「不是酒」哦!
제 이름은 오조휘 입니다

臉書裡依舊是 Extra.Old: http://www.facebook.com/extra.old
頭像
XO
資管系教師
 
文章: 5352
註冊時間: 週二 4月 27, 2004 12:20 pm
來自: CQ Inc.

Re:[教學] 讀取 3x4 Keypad 的輸入

文章maa » 週二 2月 01, 2011 11:52 am

程式碼經過整理之後,的確美觀多了。In case you don't know, Arduino Keypad Library 可以在底下的連結取得:

http://arduino.cc/playground/uploads/Code/Keypad.zip

圖檔

我現在用的是 3x4 的 Keypad,只有 0~9 和 *, # 共12 個數字。

圖檔

其實手機上也有 Keypad,而且功能更豐富,例如切換模式的功能,有數字模式、大小寫英文模式、
中文注音輸入模式等。我很好奇手機裏的 Keypad 驅動程式中的「模式的切換」功能是怎麼做的。
maa
版面管理員
 
文章: 631
註冊時間: 週一 9月 13, 2004 10:16 am
來自: 縱橫資通能源

Re: [教學] 讀取 3x4 Keypad 的輸入

文章chlove327 » 週一 5月 20, 2013 3:16 pm

您好,有問題想請教您。
我想讓鍵盤輸入的值來改變Delay時間,所以我設了一個n值,Delay(n),可是按了之後卻沒有反應,不曉得用怎麼樣的寫法才比較妥當,請您給我個方向,謝謝。



// 引用 Keypad library
#include <Keypad.h>

// 3x4 Keypad
const byte ROWS = 4; // 4 Rows
const byte COLS = 3; // 3 Columns
int PinLED = 11 ;

// 定義 Keypad 的按鍵
char keys[ROWS][COLS] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}
};


// 定義 Keypad 連到 Arduino 的接腳
byte rowPins[ROWS] = {11, 6, 7, 9}; // 連到 Keypad 的 4 個 Rows: Row0, Row1, Row2, Row3
byte colPins[COLS] = {10, 12, 8}; // 連到 Keypad 的 3 個 Columns: Column0, Column1, Column2

// 建立 Keypad 物件
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup(){
Serial.begin(9600);
}

void loop(){
digitalWrite(ledPin, HIGH);
delayMicroseconds(n);
digitalWrite(ledPin, LOW);
delayMicroseconds(n);

// 讀取 Keypad 的輸入
char key = keypad.getKey();
keypad.Read() = n ;


// NO_KEY 代表沒有按鍵被按下
if (key != NO_KEY){
// 假如有按鍵被按下,就印出按鍵對應的字元
Serial.println(key);
}
}
chlove327
剛學走路的小朋友
 
文章: 1
註冊時間: 週一 5月 20, 2013 3:10 pm


回到 內嵌與腳本化(Embedding & Scripting)

誰在線上

正在瀏覽這個版面的使用者:沒有註冊會員 和 2 位訪客

cron