(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