วันศุกร์ที่ 17 กุมภาพันธ์ พ.ศ. 2560

การใช้งานแป้นปุ่มกด (Keypad) แบบ 4x4 ปุ่ม


แป้นปุ่มกดหรือ Keypad เป็นอุปกรณ์สำหรับรับอินพุตจากผู้ใช้ มีลักษณะเป็นปุ่มกดหลายปุ่ม ถูกจัดเรียงกันในลักษณะเป็นอาร์เรย์ แบ่งเป็นแถวแนวนอน (Rows) และแถวแนวตั้ง (Columns) เช่น 3x4 (= 12 ปุ่ม) หรือ 4x4 (= 16 ปุ่ม) เป็นต้น แต่ละปุ่มก็จะมีสัญลักษณ์เขียนกำกับไว้ เช่น ตัวเลข 0-9, #, * เป็นต้น โดยปรกติ ถ้าต่อปุ่มกดแยกจำนวน 16 ตัว จะต้องใช้ขาสัญญาณทั้งหมด 16 ขา แต่ถ้าใช้การจัดเรียงแบบ 4x4 จะใช้ขาสัญญาณเพียง 8 ขา แต่ต้องมีเทคนิคในการตรวจดูว่า ปุ่มกดใดถูกกดบ้างในขณะนั้น วิธีการนี้เรียกว่า การสแกนปุ่มกด (key scan)
บทความนี้จะกล่าวถึงการใช้งาน 4x4 Keypad ร่วมกับบอร์ด Arduino เพื่อคอยตรวจดูว่า (การสแกนปุ่มกด) ผู้ใช้ได้กดปุ่มใดบ้าง อุปกรณ์ที่ใช้เป็น 4x4 Keypad มีสายเชื่อมต่อและคอนเนกเตอร์จำนวน 8 ขา แบบตัวเมีย (Female) ถ้าต้องการเสียบขาลงบนเบรดบอร์ด ก็สามารถใช้ Pin Header ตัวผู้ เป็นตัวเชื่อมต่อได้
 
ภาพแสดงอุปกรณ์ 4x4 Keypad สำหรับการทดลองใช้งาน

ขาทั้ง 8 นั้น ถ้ามองจากด้านหน้า (Front View) และนับจากซ้ายไปขวา จะเป็นขาหมายเลข 1-8 ตามลำดับ โดยที่ขา 1-4 จะเป็นขาสำหรับแถวแนวนอน (Rows) และขา 5-8 จะเป็นขาแนวตั้ง (Columns) ในการใช้งานร่วมกับบอร์ด Arduino จะต้องต่อตัวต้านทานแบบ Pull-up เช่น 1k ถึง 10k โอห์ม (เฉพาะ)ที่ขาแนวตั้งแต่ละขาด้วย รวมทั้งหมด 4 ตัว
 
ภาพแสดงการต่อขาอุปกรณ์ 4x4 Keypad และตัวต้านทานแบบ pull-up บนเบรดบอร์ด

ข้อมูลเพิ่มเติมเกี่ยวกับ 4x4 Membrane Keypads:

พฤติกรรมการทำงานของโค้ดตัวอย่าง


ในการตรวจสอบดูว่ามีการกดปุ่มใดบ้างในแต่ละเวลา จะเลือกใช้ไลบรารี่ที่มีชื่อว่า Keypad ของ Arduino ซึ่งทำให้สะดวกในการใช้งาน ในการต่อวงจร จะต้องต่อขา ROWS (ขาหมายเลข 1-4 นับจากซ้ายไปขวา) ของอุปกรณ์ 4x4 keypad ไปยังขา D2, D3, D4, D5 ตามลำดับ และขา COLUMNS (ขาหมายเลข 5-8 นับจากซ้ายไปขวา) ของอุปกรณ์ 4x4 keypad ไปยังขา D8, D9, D10, D11 ตามลำดับ
เมื่อมีการกดปุ่มแต่ละครั้ง ค่าหรือตัวอักษรที่ตรงกับปุ่มกดนั้น จะถูกส่งผ่าน Serial (ใช้ค่า Baudrate 115200) ไปแสดงผลในหน้าต่างของ Serial Monitor และมีเสียง "beep" สั้นๆ (ถ้าต่อเอาต์พุตไปยัง Buzzer)
  • ศึกษาการใช้งานไลบรารี่ของ Arduino สำหรับ Keypad ได้จาก http://playground.arduino.cc/Code/Keypad
  • เนื่องจาก Arduino IDE (version 1.0.5) ไม่ได้รวมไลบรารี่ Keypad เอาไว้ ดังนั้นจึงต้องดาวน์โหลดและติดตั้งเพิ่มเติมได้ ดาวน์โหลด Keypad Library ได้จาก http://playground.arduino.cc/uploads/Code/keypad.zipหรือ Keypad.zip(local copy) เมื่อดาวน์โหลดไฟล์ .ZIP แล้ว ให้ unzip ในไดเรคทรอรี่ <arduino>/libraries/ ของ Arduino Software
 
ภาพแสดงการติดตั้งไลบรารี่ Keypad โดยปรากฏเป็นไดเรคทรอรี่ใหม่ภายใต้ <arduino>/libraries/

Arduino Sketch

///////////////////////////////////////////////////////////////////////////////
// Author: RSP @KMUTNB
// Date: 23-Oct-2013
// Target Board: Arduino Uno (ATmega328P, 5V, 16MHz)
// Arduino IDE: version 1.0.5
// This sketch demonstrates how to do a keypad scan (a 4x4 keypad used)
// using the Arduino Keypad library.

#include <Keypad.h> // use the Arduino Keypad library

// constant values
const byte ROWS = 4; 
const byte COLS = 4; 
const byte BUZZER_PIN = 13;

char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};

byte rowPins[ROWS] = {2,3,4,5};   // connect D2,D3,D4,D5 to Rows 1-4 (the left four pins)
byte colPins[COLS] = {8,9,10,11}; // connect D8,D9,D10,D11 to Column 1-4 (the right four pins)

char key;
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup(){
  Serial.begin( 115200 );
  keypad.setDebounceTime( 20 ); // 20 msec
  pinMode( BUZZER_PIN, OUTPUT ); 
  digitalWrite( BUZZER_PIN, LOW );
}

void loop(){
  if ( (key = keypad.getKey()) != NO_KEY ) { // get key
    digitalWrite( BUZZER_PIN, HIGH ); // beep on
    Serial.println( key ); // show the key pressed
    delay(20);
    digitalWrite( BUZZER_PIN, LOW ); // beep off
  }
}
///////////////////////////////////////////////////////////////////////////////

 
ภาพแสดงการต่อวงจรโดยรวม
 
ภาพแสดงการสัญลักษณ์ของปุ่มกดที่ได้รับจาก Arduino ในหน้าต่างของ Serial Monitor

Arduino Sketch


โค้ดตัวอย่างนี้ แสดงวิธีการสแกนแป้นปุ่มกด โดยไม่ใช้ไลบรารี่ Keypad ของ Arduino หลักการทำงานโดยสังเขปมีดังนี้ กำหนดให้ขาที่ต่อกับ Rows 4 แถวแนวนอน เป็นเอาต์พุต และให้มีค่าเป็น HIGH ทั้งหมด (หรือ "1111") และกำหนดให้ขาที่ต่อกับ Columns 4 แถวแนวตั้ง เป็นอินพุต (มี pull-up) เริ่มต้นการสแกนด้วยการกำหนดค่าเอาต์พุตให้ Rows มีค่าเป็น "0111", "1011", "1101", "1110" ไปตามลำดับจนครบทั้ง 4 แถวนอน ถือว่าครบหนึ่งรอบของการสแกน ในแต่ละแถวนอนของการสแกน (เมื่อมีค่าเอาต์พุตสำหรับแถวแนวนอนเป็น LOW หรือ 0) ให้อ่านค่าอินพุตที่ต่อกับแถวแนวตั้ง หรือ Columns ถ้ามีปุ่มใดในแถวดังกล่าว ถูกกดในขณะนั้น จะได้ค่าอินพุตเป็น LOW ดังนั้น จะทราบพิกัดแนวนอนและแนวตั้งของปุ่มที่ถูกกด
///////////////////////////////////////////////////////////////////////////////
// Author: RSP @KMUTNB
// Date: 23-Oct-2013
// Target Board: Arduino Uno (ATmega328P, 5V, 16MHz)
// Arduino IDE: version 1.0.5
// This sketch demonstrates how to do a keypad scan (a 4x4 keypad used)
// (without use of the Keypad library).

// uncomment this line if you use Arduino Leonardo.
//#define USE_LEONARDO

// constant values
const byte BUZZER_PIN = 13;
const byte ROWS = 4; 
const byte COLS = 4; 

char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};

byte rowPins[ROWS] = {2,3,4,5};   // connect D2,D3,D4,D5 to Rows 1-4 (the left four pins)
byte colPins[COLS] = {8,9,10,11}; // connect D8,D9,D10,D11 to Column 1-4 (the right four pins)

void setup(){
  Serial.begin( 115200 );
  for (int i=0; i < ROWS; i++) {
     pinMode( rowPins[i], OUTPUT );
  }
  for (int i=0; i < COLS; i++) {
     pinMode( colPins[i], INPUT );
     digitalWrite( colPins[i], HIGH ); // enable internal pull-up
  }
  pinMode( BUZZER_PIN, OUTPUT ); 
  digitalWrite( BUZZER_PIN, LOW );

#ifdef USE_LEONARDO
  delay(1000);
  Keyboard.begin();
#endif
}

char getKey( ) {
  char key_pressed = 0;
  for (int j=0; j < ROWS; j++) { // scan the j-th row (j=0,1,2,3)
    for (int i=0; i < ROWS; i++) { 
      // output HIGH to all rows, except the j-th row
      digitalWrite( rowPins[i], (i==j) ? LOW : HIGH );
    }
    for (int i=0; i < COLS; i++) {
      if ( digitalRead( colPins[i] ) == LOW ) { // Button at (R,C)=(j,i) is pressed
         // wait until the button is released.
         while ( digitalRead( colPins[i] ) != HIGH ) ; // blocking
         key_pressed = keys[j][i]; // get the associated key for that button
         break;
      }
    }  
    digitalWrite( rowPins[j], HIGH );
    if ( key_pressed != 0 ) { 
      return key_pressed;
    }
  }
  return 0; // no key pressed
}

void loop(){
  char key = getKey();
  if ( key != 0 ) {
     digitalWrite( BUZZER_PIN, HIGH );

#ifdef USE_LEONARDO
     Keyboard.press( key );
     delayMicroseconds( 10 );
     Keyboard.releaseAll();
#endif

     Serial.println( key );
     delay(50);
     digitalWrite( BUZZER_PIN, LOW);
  }
  delay(10);
}

///////////////////////////////////////////////////////////////////////////////

 
ภาพแสดงการทดลองโดยใช้บอร์ด Leonardo 
ไม่ใช้ตัวต้านทาน Pull-up ภายนอก และใช้งานแบบ USB-HID (Keyboard)

ไม่มีความคิดเห็น:

แสดงความคิดเห็น