Arduino Ultimate Keymatrix


(10/09/2009)
ตัวอย่างการ เขียนโปรแกรมแบบ Multitask เพื่อแก้ปัญหาการติด loop เมื่อใช้งาน Keymatrix หรือ Keypad

ปล. ขออภัยด้วยครับที่ code ไม่สวยเพราะเดิมทีไม่ตั้งใจจะ opensource (^_^!)


/***************************************************************************
 * Status          : Complete !!  (เสร็จเมื่อ 15/4/2552 (ป่วยการเมืองหลายวัน ไม่ได้กิน ไม่ได้หลับ ไม่ได้นอน))
 * Date Start     : 9/4/2552 8:34
 * Project          : Ultimate KeyMatrix (debounce without delay and multiple keypress support !!)
 * Project Code  : KMAT (สำหรับทุก function และ global variable)
 * Compiler        : Arduino - 0015

 * Board           : DuinoThumb V1, DuinoThumb V2, Pico
 * MCU             : ATMEGA168
 *                     : ATMEGA8 (Arduino SingleBoard àÅ×Í¡ Arduino NG or older w/ ATmega8)
 * Clock             : 12Mhz, 16Mhz
 * Programmer   : Ksemvis Vitoonrach
 * Email            : Manager@DuinoThumb.com
 * Objective      
 *    - keymatrix แบบไม่รอการหน่วงเวลา (delay) ใช้เป็น polling เพราะบางงานไม่สามารถ delay ได้
 *    - ใช้ internal r-pullup ไม่ต้องต่อภายนอก
 *    - ตั้งได้ว่าจะให้กดค้างได้ หรือจะให้กดได้ครั้งเดียว
 *    - ใช้กดแบบปุ่มเดียว หรือหลายคีย์พร้อมกันได้ (พร้อมลำดับการกดก่อนหลัง)
 *    - พัฒนาให้เหมาะแก่การ portable
 *
    - ง่ายต่อการ reuse ระดับ source code คือ copy ไปรวมกับ code งานเดิมที่มีอยู่ได้ทันที ไม่ต้องแก้ไข
 *
 *
 * หลักการ
 *    - ใช้วิธีตรวจสอบการกดปุ่ม ถ้ามีการกดปุ่มแล้ว จะเริ่มการนับเวลา และจะวนรอบนับเวลาไปเรื่อยๆ
 *    จนกว่าการนับเวลา จะเท่ากับเวลาที่ตั้งเป็น debounce (ใช้การนับเวลา ไม่ใช้ delay ในการตรวจสอบ) จึงจะถือว่ากดปุ่มจริง !
 *    จากนั้นจะนำค่าปุ่มที่ได้ ไปเก็บลง buffer การทำแบบนี้จึงไม่ติด loop จึงสามารถทำงานได้หลายๆ ปุ่มพร้อมๆ กัน และใช้งานควบคู่ไปกับ
 *     watch dog หรือ งานอื่นๆ ใน code โดยไม่ต้องกังวลว่าจะไปติดลูปตายที่ไหน
 *
 *
 * Update          : 10/4/2552 22:46
 *    - แก้ bug ที่ปุ่ม 1 กับ 24 มีช่วงเวลาไม่เท่ากัน (ใช้ตรวจก่อนว่าครบ 1ms หรือยัง ถ้าครบแล้วค่อยบวก เพราะ MCU ทำงานไวเกินไป)
 *    - ปรับปรุงเงื่อนไขการวนลูบให้ดีขึ้น ใช้บวก loop ที่บรรทัดสุดท้าย เพราะเมื่อหลุดจาก loop จะไม่ต้องเริ่มขาเดิมอีกครั้ง
 *    - รองรับการกดหลายปุ่มพร้อมกัน ในคนละ Rows ได้ แต่ columns เดียวกันไม่ได้ (ปัญหาวงจร ที่เป็นแบบ matrix แก้ไม่ได้)
 *
 *
 * สิ่งที่ต้องพัฒนาเพิ่ม
 *    x จำลองเป็น Slave I2C ได้ เพื่อสามารถสั่งจาก Master MCU 
 *      -> ยกเลิก เนื่องจากเห็นว่ามันนิ่งแล้ว ส่วนเรื่อง I2C จะแยกไปเขียนเป็นอีกไฟล์หนึ่งเป็น i2c Master & Slave implement
 *         เวลาใช้งาน จะใช้วิธี copy source (implement) แล้วแก้ไข จะได้ไม่สับสน
 *
 * แนะนำ
 *  - เวลาทดลองให้เปิดใน hyperterminal ถ้าเปิดใน Arduino Serialport ดูเหมือนว่าจะ ส่งข้อมูลผิดพลาดเยอะ
 *    แต่เปิดใน hyperterminal เปิดได้ 2 ชม. ไม่มี error
 *
 *
 * BUG
 *  - ยังไม่ค้นพบ
 *    
 **********************************************************************
 *
 * [วิธีการใช้งาน] (step by step)
 *
 **********************************************************************
 * 1. copy ตั้งแต่ต้น ไปจนสิ้นสุดเพื่อนำไปใช้ (เว้นส่วน setup() และ loop() ไว้)
 * 2. เปลี่ยนค่า KMAT_ALL_ROWS, KMAT_ALL_COLS ตามต้องการ
 * 3. กำหนดค่าขาให้ตรงแล้วเรียกใช้ KMAT_setup()
 *
 * [หมายเหตุการใช้งาน]
 *  - จงค้นหาคำว่า "(แก้ไข)"    หมายถึง ให้แก้ไขค่าให้ตรงกับความเป็นจริง
 *  - จงค้นหาคำว่า "(แก้ไขก็ได้)" หมายถึง ค่าที่สามารถ แก้ไข หรือจะปล่อยผ่านก็ได้
 *
 **********************************************************************

 *
 * [ข้อจำกัด]
 * - จอง array เป็นแบบตายตัวสำหรับ columns และ rows ถ้าอยากค่าอื่นต้องแก้ constant
 *
 * [รูปแบบการต่อลายวงจร]
 *
 *  Row N ----[B N]-----[B N]------[B N]-------[B N]----
 *                  |              |              |              |
 *                  |              |              |              | 
 *  Row 1 ----[B 5]-----[B 6]-------[B 7]-------[B 8]----
 *                  |              |              |              |
 *                  |              |              |              |
 *  Row 0 ----[B 1]-----[B 2]-------[B 3]-------[B 4]----
 *   ^              |              |              |              |
 *   |               |              |              |              |
 *  (0) - >   Col 0          Col 1          Col 2          Col N
 *
 * อธิบาย : 
 * - Row0 และ Col0 จะเริ่มที่มุมซ้าย B คือค่าที่จะ return กลับเป็น byte
 * - ค่า index ของ array ที่ใช้นับเวลา debounce สามารถคำนวนได้จากสูตร 
 *        (RowX * Column_size) + ColumnX
 * - ค่า return สามารถคำนวนได้จากสูตร 
 *        (RowX * Column_size) + ColumnX + 1 
 * - ถ้าไม่มีการกด key จะคืนค่า 0
 * - ขา Rows จะเป็น output , ขา Cols จะเป็น input
 */


/*************************** Define and Constant ***************************/ 
#define KMAT_DEBUG  true                                    // เปิด(true)/ปิด(false) ระบบ debug (แก้ไข)
                                                             // ถ้า true จะส่ง output มาที่ UART 19200
const byte KMAT_ALL_ROWS = 4;                                // จำนวน แถวทั้งหมด (แก้ไข)
const byte KMAT_ALL_COLS = 6;                                // จำนวน คอลัมน์ทั้งหมด (แก้ไข)
const byte KMAT_ALL_KEYS = KMAT_ALL_ROWS * KMAT_ALL_COLS;    // จำนวนคีย์ทั้งหมด
const byte KMAT_KEYBUFFER_MAX = 6;                           // กด key พร้อมกันได้สูงสุด 6 ปุ่ม เก็บลง buffer (แก้ไข)


/*************************** Global Define *********************************/
byte KMAT_leg_rows[KMAT_ALL_ROWS];       // เก็บขาที่ใช้เป็นแถว
byte KMAT_leg_cols[KMAT_ALL_COLS];       // เก็บขาที่ใช้เป็น columns
byte KMAT_timer_counter[KMAT_ALL_KEYS];  // ตัวนับเวลาที่ผ่านไปหลังการกด key (0=ไม่ได้กด, 1-250=เวลา debounce, >250=สงวนไว้สถานะอื่น
byte KMAT_debounce_ms;                   // เวลาที่จะใช้ตรวจการ debounce (milliseconds) มีค่าได้ 1-250
unsigned long KMAT_global_ms;            // เก็บค่าเวลาที่ผ่านไปของระบบ
byte KMAT_keybuffer[KMAT_KEYBUFFER_MAX]; // keyboard buffer
byte KMAT_keybuffer_index;               // บอกว่าตอนนี้มี key ในหน่วยความจำกี่ตัวแล้ว


// เมื่อทำงานอีกครั้งจะเริ่มนับปุ่มต่อไป ใช้แก้ปัญหาว่าเมื่อได้ค่าแล้วเด้ง return ทันที จะทำให้กดได้ปุ่มเดียว กดหลายปุ่มพร้อมกันไม่ได้
// ที่เป็นเช่นนี้เพราะเราจะอ่านค่าที่ละ pin ไม่ได้อ่านทีละ port 
// ถ้าเป็น Global มันจะเริ่มตรวจที่ขาถัดไปในรอบใหม่ เมื่อครบทุก rows+cols แล้วจะเริ่มใหม่ เสมือนว่ากดหลายปุ่มพร้อมกันได้
byte KMAT_currentRows = 0;                // ใช้ใน KMAT_readkey();
byte KMAT_currentCols = 0;                // ใช้ใน KMAT_readkey();


/*************************** Global Function *******************************/


// อ่านค่า key ทีละปุ่ม ถ้ามีการกดก็ return, ไม่มีก็ 0
// ถ้า pressOnce = true  หมายถึง กดได้ครั้งเดียว จะติดอีกครั้งเมื่อปล่อยมือแล้วกดใหม่
// ถ้า pressOnce = false หมายถึง กดได้กดค้างได้ สถานะจะยังคงส่งออกมาต่อเนื่อง
byte KMAT_readkey(byte pressOnce = false)
{
  // ตรวจสอบว่าค่า KMAT_currentRows ครบจำนวน ขาที่มีหรือยัง ถ้าวนรอบครบแล้ว ก็เริ่มใหม่
  if (KMAT_currentRows >= KMAT_ALL_ROWS)
      KMAT_currentRows = 0;
  // เริ่มการอ่านค่า วนลูปส่งค่า 0      
  for ( ;KMAT_currentRows < KMAT_ALL_ROWS;  ) // บวก rows ไปไว้ล่างสุดของ loop
  {
    digitalWrite(KMAT_leg_rows[KMAT_currentRows], LOW);


    // ตรวจสอบว่าค่า KMAT_currentCols ครบจำนวน ขาที่มีหรือยัง ถ้าวนรอบครบแล้ว ก็เริ่มใหม่ (เหมือน KMAT_currentRows)
    if (KMAT_currentCols >= KMAT_ALL_COLS)
        KMAT_currentCols = 0;
    // เริ่มอ่านค่าการกดจากฝั่ง Cols
    for ( ;KMAT_currentCols < KMAT_ALL_COLS;  ) // บวก cols ไปไว้ล่างสุดของ loop
    {
      // ตำแหน่ง array index ที่จะใช้ตรวจสอบเก็บค่า debounce จากการกดปุ่ม
      byte index = (KMAT_currentRows * KMAT_ALL_COLS) + KMAT_currentCols;
      // ตรวจได้ว่ามีการกดปุ่ม
      if (digitalRead(KMAT_leg_cols[KMAT_currentCols]) == LOW)
      {
        //
        // จัดการส่วน debounce
        //
        // ตรวจว่าก่อนหน้านี้มีการเริ่มนับเวลาไปแล้ว(จนเสร็จแล้ว) และเป็นกรณี pressOnce 
        // คือได้มีการ debounce มาก่อนหน้านี้จนครบเวลาแล้ว แต่ยังไม่ยอมยกมือ
        if (KMAT_timer_counter[index] >= KMAT_debounce_ms && pressOnce)
        {
          // ไม่ต้องทำอะไร เมื่อยกมือจะเคลียร์ค่าเอง
        }
        // พบว่ามีการกดปุ่มแล้ว แต่ยังไม่ครบเวลา จึงตรวจว่าก่อนหน้านี้มีการเริ่มนับเวลาหรือยัง แบบปกติ
        else if (KMAT_timer_counter[index] > 0)
        {
          /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
          // ก่อนใช้เวลาระบบ ต้องตรวจ millis ว่าเกิน 49 วัน 9 ชม.หรือไม่ เพราะกรณีเกินกว่า มันจะเริ่ม 0 ใหม่ (ค่าจะน้อยกว่า KMAT_global_ms)
          if (KMAT_global_ms > millis())
              KMAT_global_ms = millis(); // ปรับเวลาใหม่        
          // สาเหตุที่นำมาไว้ตรงนี้ เพราะว่าถ้าไว้นอกลูปมันจะตรวจเกือบตลอดเวลา
          /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
          //
          // เอาเวลาที่ผ่านไป มาบวก , ถ้าเริ่มนับไปแล้ว ตรวจว่าเวลามากเท่า debounce หรือยัง
          // โดยเอาเวลาปัจจุบัน + กับเวลาที่กด = เวลาที่ผ่านไปมา
          if (millis() - KMAT_global_ms > 1)
          {
            KMAT_timer_counter[index] += (byte)(millis() - KMAT_global_ms);
            // บันทึกเวลาล่าสุดที่ทำงาน
            KMAT_global_ms = millis();
          }
          // ตรวจเวลาครบ debounce แล้ว มั่นใจว่ากดจริง ก็ให้ return ค่า
          if (KMAT_timer_counter[index] >= KMAT_debounce_ms)
          {
            // clear ค่าเวลา กรณี pressOnce = false จะกดค้างได้ การทำให้เป็น 0 เมื่อรอบหน้าจะเข้าloop เดิม จึงถือเป็นการกดค้าง
            // (*** หากไม่เคลียร์ค่า สามารถเอาไปตรวจการที่ยังไม่ยกมือขึ้นได้)
            if (!pressOnce)
                KMAT_timer_counter[index] = 0;
            // คืนค่า port มิเช่นนั้นจะ กดตลอดกาล
            digitalWrite(KMAT_leg_rows[KMAT_currentRows], HIGH); 
            // เพิ่ม cols อีก 1 (แต่ไม่ต้องไปเพิ่มตรง for..loop) มิเช่นนั้น ถ้าหลุดออกไปจะกลับมาซ้ำรอบเดิมอีกหนก่อนบวก  
            KMAT_currentCols++;
            return index + 1;
          }
        }
        else // ยังไม่ได้เริ่มนับ ก็สั่งให้เริ่มนับ
        {
          KMAT_timer_counter[index] = 1;
          // บันทึกเวลาล่าสุดที่ทำงาน
          KMAT_global_ms = millis();
        }        
      }
      else // ตรงนี้ตรวจแล้ว ไม่ใช่การกดปุ่ม (ถือว่าเป็นการ unpress)
      {
        KMAT_timer_counter[index] = 0;
      }
      // เพิ่ม cols อีก 1 (แต่ไม่ต้องไปเพิ่มตรง for..loop) มิเช่นนั้น ถ้าหลุดออกไปจะกลับมาซ้ำรอบเดิมอีกหนก่อนบวก  
      KMAT_currentCols++;
    }
    // ครบรอบ Row 1 แถว ก็ให้คืนค่า port Row มิเช่นนั้นจะ ถือว่า "กด" ตลอดกาล
    digitalWrite(KMAT_leg_rows[KMAT_currentRows], HIGH); 
    // เพิ่ม rows อีกแถว (แต่ไม่ต้องไปเพิ่มตรง for..loop) มิเช่นนั้น ถ้าหลุดออกไปจะกลับมาซ้ำรอบเดิมอีกหนก่อนบวก
    KMAT_currentRows++;
  }
  
  // ทำงานจนเสร็จครบทุกรอบ รอบนี้ถือว่าไม่มีการกดปุ่มใดๆ return 0 
  return 0;
}




// ใช้แสดงผลข้อมูลใน buffer
// ถ้า KMAT_DEBUG == true  จะเปิดใช้ UART 
// ถ้า KMAT_DEBUG == false function นี้เอาออกไปได้เลย เพื่อประหยัด Flash
#ifdef KMAT_DEBUG
    #if KMAT_DEBUG
    void printkeybuff() // for test
    {
      for(byte count = 0; count < KMAT_KEYBUFFER_MAX; count++)
      {
        Serial.print( KMAT_keybuffer[count],HEX );
        Serial.print(",");
      }
      Serial.println();    
    }
    #endif
#endif


// ลบค่าใน keybuffer
void KMAT_clear_keybuffer()
{
  for(byte count = 0; count < KMAT_KEYBUFFER_MAX; count++)
    KMAT_keybuffer[count] = 0;
    
  // เริ่มตัวชี้ index ของ keyboard buffer
  KMAT_keybuffer_index = 0;
}


// ลบข้อมูล keybuffer array ตาม index ที่ระบุ แล้วเลื่อนลำดับต่อไปขึ้นมา
void KMAT_remove_keybuffer(byte index)
{
  for (byte count = index; count < KMAT_keybuffer_index; count++)
    KMAT_keybuffer[count] = KMAT_keybuffer[count+1];
    
  // เมื่อสลับจนสิ้นสุดแล้ว ข้อมูลสุดท้ายเป็น 0  และ ลดค่า index อีก 1
  KMAT_keybuffer[--KMAT_keybuffer_index] = 0;
}


// ค้นหาค่า key ว่ามีค่าที่กำหนดใน buffer หรือไม่ 
// (เริ่มต้นที่ 1..n)
// return เป็นตำแหน่ง index ของ array, ถ้าได้น้อยกว่า 0 คือไม่มี
char KMAT_findKeyInBuff(byte keyValue)
{
    for(byte index = 0; index < KMAT_KEYBUFFER_MAX; index++)
        if (KMAT_keybuffer[index] == keyValue) 
            return index;
    return -1;
}


// add ค่า key เก็บไว้ใน buffer (function ย่อยของ KMAT_multiple_readkey())
// keyadd = ค่าเลขปุ่มที่ต้องการเก็บ 1 เป็นค่าแรก (ถ้าจะใช้เป็น index ของ array ต้องลบ 1)
void KMAT_addkey_to_buffer( byte keyadd)
{
  // ถ้าปุ่มมากกว่า KMAT_ALL_KEYS หรือ น้อยกว่า หรือ = 0 ให้ return ไม่ต้อง save
  if ( (keyadd > KMAT_ALL_KEYS) || (keyadd <= 0) ) return;
  // ถ้าเกินกว่าจะรับได้
  if (KMAT_keybuffer_index >= KMAT_KEYBUFFER_MAX) return;
  // วนลูปตรวจว่ามีข้อมูลซ้ำหรือไม่ ถ้ามีก็ไม่ add
  for (byte loopChkExist = 0; loopChkExist < KMAT_KEYBUFFER_MAX; loopChkExist++)
    if (KMAT_keybuffer[loopChkExist] == keyadd) return;
  
  // ถ้าไม่ซ้ำเลย จึง add key
  KMAT_keybuffer[KMAT_keybuffer_index++] = keyadd;
}


// อ่านค่าแบบหลายปุ่ม output จะข้อมูลเก็บไว้ที่ KMAT_keybuffer[]
void KMAT_multiple_readkey()
{
  KMAT_readkey(true);    
  
  // เมื่อครบ 1 รอบก็วน loop จนครบทุกปุ่ม เพื่อจะดูว่ามีปุ่มใดยกมืออออกไปแล้วบ้าง
  for (byte index = 0; index < KMAT_ALL_KEYS; index++)
  {
    // ดูว่าปุ่มใดกดจน debounce เสร็จแล้ว ก็ให้ add key
    if (KMAT_timer_counter[index] >= KMAT_debounce_ms)
    {
      KMAT_addkey_to_buffer( index+1 );
    }
    // ดูว่าปุ่มใดยกมือออกมาแล้ว
    else if (KMAT_timer_counter[index] == 0)
    {
      // ดูว่ามีข้อมูลเก่าใน buffer หรือไม่ ถ้ามีก็เอาออกไป
      for (byte y = 0; y < KMAT_KEYBUFFER_MAX; y++)
      {
        // ค้นหาข้อมูลเก่าที่ไม่ได้กดปุ่มแล้ว ให้เอาข้อมูลออกไป
        if (KMAT_keybuffer[y] == index+1) // เพราะค่า index ของ array น้อยกว่าค่าปุ่มอยู่ 1
          KMAT_remove_keybuffer(y);
      }
    }        
  }      
}




// กำหนดค่าให้ keymatrix
// arrRows = array เก็บเลขขา rows แบบเรียงลำดับ
// arrCols = array เก็บเลขขา cols แบบเรียงลำดับ
// debounce_ms = ระยะเวลา (ms) สำหรับ debounce
void KMAT_setup(byte arrRows[], byte arrCols[], byte debounce_ms)
{
  byte count = 0;
  // กำหนดค่า ขา rows
  for (count = 0; count < KMAT_ALL_ROWS; count++)
  {
    KMAT_leg_rows[count] = arrRows[count];
    pinMode(arrRows[count],OUTPUT);
    digitalWrite(arrRows[count], HIGH);
  }
  // กำหนดค่า ขา columns
  for (count = 0; count < KMAT_ALL_COLS; count++)
  {
    KMAT_leg_cols[count] = arrCols[count];
    // เปิด internal r-pull up
    pinMode(arrCols[count],OUTPUT);
    digitalWrite(arrCols[count],HIGH);
    // เปลี่ยน mode
    pinMode(arrCols[count],INPUT);    
  }
  
  // init var
  KMAT_debounce_ms = debounce_ms > 250 ? 250 : debounce_ms;
  KMAT_global_ms = millis();
  
  // clear keybuffer
  KMAT_clear_keybuffer();
}


/*************************** End Keymatrix Part ****************************/




/*************************** Example ***************************************/
#ifdef KMAT_DEBUG
  #if KMAT_DEBUG == false
  void setup(){};
  void loop(){};

  #endif
#endif
  
#ifdef KMAT_DEBUG
    #if KMAT_DEBUG

    const byte PIN_JUMPER = 12;

    void setup()
    {
      // ตัวอย่างการกำหนดขาต่างๆ
      byte rowslegs[] = {2,3,4,5};           // กำหนดขา Rows 
      byte colslegs[] = {6,7,8,9,10,11};     // กำหนดขา Cols 
      KMAT_setup(rowslegs, colslegs, 30);    // เรียก setup   
     
      Serial.begin(19200);                   // เรียกใช้ Serial port ถ้าไม่ใช้ไม่ต้องใส่เพื่อประหยัด flash       
      //
      // ถ้า short ขา 12 กับ 13 เข้าด้วยกันจะเป็นการอนุญาติให้กดค้างได้
      //
      // เปิด r-pull up และทำหน้าที่แทน jumper
      pinMode(PIN_JUMPER, OUTPUT);
      digitalWrite(PIN_JUMPER, HIGH);
      pinMode(PIN_JUMPER,INPUT);
      // ทำ output
      pinMode(PIN_JUMPER+1, OUTPUT);
      digitalWrite(PIN_JUMPER+1, LOW);
    }

    void loop()
    {
      
      // example 1 : ทดสอบการทำงานของ function ต่างๆ 
      Serial.println("start...");
      printkeybuff(); // for test
      
      // ทดสอบการจำลองการส่งค่าปุ่มไปเก็บใน buffer
      KMAT_addkey_to_buffer(1);
      KMAT_addkey_to_buffer(3);
      KMAT_addkey_to_buffer(5);
      KMAT_addkey_to_buffer(7);
      Serial.println("add 1357");
      printkeybuff(); // for test
      
      // ทดสอบ clear buffer
      Serial.println("clear..");
      KMAT_clear_keybuffer();
      printkeybuff(); // for test

      KMAT_addkey_to_buffer(1);
      KMAT_addkey_to_buffer(3);
      KMAT_addkey_to_buffer(5);
      KMAT_addkey_to_buffer(7);
      Serial.println("add 1357 again");
      printkeybuff(); // for test
      
      // ลบ buffer บางตำแหน่ง
      KMAT_remove_keybuffer(2);
      Serial.println("remove index 2");
      printkeybuff(); // for test
      
      KMAT_remove_keybuffer(1);
      Serial.println("remove index 1");
      printkeybuff(); // for test
      
      KMAT_addkey_to_buffer(8);
      KMAT_addkey_to_buffer(9);
      KMAT_addkey_to_buffer(9);
      Serial.println("add 899 (add only first 9 becuase can't add exist key)");
      printkeybuff(); // for test
      
      KMAT_addkey_to_buffer(5);
      KMAT_addkey_to_buffer(5);
      KMAT_addkey_to_buffer(5);
      KMAT_addkey_to_buffer(5);
      KMAT_addkey_to_buffer(5);
      KMAT_addkey_to_buffer(5);
      Serial.println("add many more (555555)");
      printkeybuff(); // for test
      
      KMAT_addkey_to_buffer(99);
      Serial.println("add many more than max_key (99)");
      printkeybuff(); // for test
      
      KMAT_addkey_to_buffer(13);
      KMAT_addkey_to_buffer(14);
      KMAT_addkey_to_buffer(15);
      Serial.println("test add until max buffer by ad 13,14,15");
      printkeybuff(); // for test
      
      // ส่วนของการตรวจสอบการกด  
      byte readkey = 0;
      Serial.println("---------------------------------" );
      while(true)
      {
        KMAT_multiple_readkey();
        if(KMAT_keybuffer[0] > 0)
          printkeybuff();
      }


      ;
      
      /*
      
      // ----------------------------------------------------------------------------------------------------------------------
      // example 2 : ทดสอบการทำงานของปุ่มกด และเป็นตัวอย่างการเรียกใช้
      
      byte readkey = 0;


      Serial.println("KeyMatrix without debounce");
      Serial.println("--------------------------");
      while(true)
      {
        //
        // ถ้า short ขา 12 กับ 13 เข้าด้วยกันจะเป็นการอนุญาติให้กดค้างได้
        //
        if (digitalRead(PIN_JUMPER) == HIGH)
          readkey = KMAT_readkey(true);
        else
          readkey = KMAT_readkey(false);
        
        if (readkey != 0)
        {
          Serial.print(readkey + 0); // +0 เพื่อให้เปลี่ยนเป็นตัวอักษร
          Serial.print(",");
        }    
      }
      
      ;
      */
    }
    #endif
#endif
Comments