Arduino รับค่าจาก keyboard

หลังจากที่ผมได้อ่านตามเว็บต่างๆ พบมีการใช้ไมโครคอนโทรลเลอร์มารับค่าจาก keyboard แบบ PS/2 ที่ใช้ในคอมพิวเตอร์รุ่นเก่าๆ จึงอยากลองเขียนดูบ้าง ตัว keyboard ได้ของเก่าจากห้องเก็บของซึ่งก็เก่ามากยี่ห้อ Sony แต่ยังใช้งานได้ดีอยู่เลย

รูปที่ 1 Keyboard ที่นำมาทดลอง

ในการทดลองผมได้ทำตัวแปลงหัวพอร์ตของ Keyboard เป็นขาแบบ SIP จำนวน 6 ขา เพื่อความสะดวกในการต่อกับบอร์ด Arduino โดยออกแบบวงจรอย่างง่ายด้วยโปรแกรม Protel99se


รูปที่ 2 ตัวแปลงพอร์ต PS/2 มุมมองด้านล่าง

รูปที่ 3 ตัวแปลงพอร์ต PS/2 มุมมองด้านหน้า

บอร์ด Arduino ที่ใช้คือ Arudino Mega 2560 แต่ก็สามารถใช้ Arduino รุ่นอื่นได้เนื่องจาก Code ที่เขียนมีขนาดเล็ก

รูปที่ 4 บอร์ด Arduino Mega2560

จอแสดงผลผมใช้จอของ SILA รุ่น TLCD-164 เป็นบอร์ด Graphic LCD แบบสำเร็จรูปสามารถที่จะแสดงผลภาษาไทย อังกฤษ และรูปภาพต่างๆ ได้ โดยมี interface 3 แบบ คือ TTL Serial, RS-232 Serial, SPI ในการทดลองนี้ได้เลือกใช้ interface แบบ TTL Serial เนื่องจากสามารถต่อกับ Arduino ได้ตรงๆ และง่าย ในการทดลองนี้ได้ใช้งาน 4 คำสั่ง คือ

  • Set charactor Row & Column (:1RCC<CR>) 
  • Set Character (:2XX...X<CR>) 
  • Clear LCD (:5<CR>)
  • Backlight ON (:9<CR>)

รูปที่ 5 บอร์ดจอ SILA TLCD-164

หลักการรับค่าจาก Keyboard จะทำโดยผ่านทางสายสัญญาณ 2 เส้น และไฟเลี้ยง 2 เส้น ดังนี้

  • CLOCK (ขาที่ 5) 
  • DATA (ขาที่ 1) 
  • ไฟเลี้ยง +5V (ขาที่ 4) 
  • Ground (ขาที่ 3) 

รูปที่ 6 ขาของพอร์ต PS/2

ขาแต่ละขาของพอร์ต PS/2 มีหน้าที่ดังนี้

  1. Data
  2. ไม่ใช้งาน
  3. ไฟเลี้ยง +5V
  4. GND
  5. Clock
  6. ไม่ใช้งาน

บัสของ Keyboard จะเป็นมาตรฐาน TTL 5V โหมดของบัส PS/2 มี 3 โหมด ดังนี้

  1. Data = high, Clock = high:  Idle state. บัสว่าง ไม่มีการกดปุ่มที่ Keyboard
  2. Data = high, Clock = low:  Communication Inhibited. เป็นการสั่งหยุดการส่งข้อมูลจาก Keyboard เพื่อที่ทำการส่งคำสั่งควบคุมไปยัง Keyboard เช่น สั่งเปิด LED ปุ่ม Numlock
  3. Data = low, Clock = high:  Host Request-to-Send เป็นการร้องขอการส่งข้อมูลจาก Keyboard

โหมดหลักๆ ที่เราใช้จะเป็นโหมดที่ 3 เพื่อที่จะรอรับค่าที่ Keyboard ส่งมาหา Arduino เมื่อมีการกดปุ่มใดๆ โดย ทั้งสัญญาณ Data และ Clock จะถูกควบควบคุมโดย Keyboard ทั้งหมด เราทำแค่อ่านค่าบิตข้อมูลทุกๆ ขอบขาลงของสัญญาณ Clock

เมื่อมีการกดปุ่มที่ Keyboard บัสของระบบจากที่อยู่สถานะ Idle จะเปลี่ยนเป็นสถานะ Host-Request-to_Send โดย Keyboard จะให้สัญญาณ Data เป็น LOW บ่งบอกถึงการเริ่มการส่งข้อมูล รูปแบบของข้อมูลที่ Keyboard ส่งไปจะมีขนาด 11 บิต ดังรูปที่ 7

รูปที่ 7 รูปแบบการส่งข้อมูลของ Keyboard

ข้อมูลทั้ง 11 บิต ประกอบด้วย

  • Start bit มีขนาด 1 บิต
  • Data bit มีขนาด 8 บิต
  • Parity bit มีขนาด 1 บิต (Odd Parity)
  • Stop bit มีขนาด 1 บิต

เมื่อ Data = 0 เป็นการเริ่มการส่งข้อมูล ให้รอจน Clock = 0 ต่อไปก็ให้รอขอบขาลงของ Clock ลูกถัดไป แล้วทำการอ่านค่าสัญญาณของ Data เก้บไว้ในตัวแปร เก็บจนครบ 8 บิตข้อมูล 2 บิตสุดท้ายคือ Parity และ Stop bit ไม่ต้องสนใจก็ได้

ข้อมูลที่ได้จะเป็นค่า Scan code ของแต่ละปุ่มซึ่งต้องนำมาแปลค่าอีกที

รูปที่ 8 รูปสัญญาณที่ได้จากการดักจับสัญญาณ

จากรูปที่ 8 เราค่าที่ส่งมาคือ 0x15 เมื่อเปิดตารางแปลจะมีความหมายเป็นตัว Q ส่วนค่าประจำตัวของตัวอื่นๆ สามารถดูได้จากลิงค์ต่อไปนี้

เมื่อมีการกดปุ่มจะมีค่าส่งออกมา 2 แบบ คือ ค่าเมื่อกดปุ่มลงไป เช่น ตัว Q คือ 0x15 อีกค่าที่ออกมาจะออกเมื่อปล่อยปุ่ม Q คือ 0xF0 0x15 ทำให้เราสามารถรู้ได้ว่าผู้ใช้ที่กดปุ่มได้ปล่อยปุ่มหรือยัง ตัวค่าที่ออกมาเมื่อปล่อยปุ่มส่วนใหญ่มีขนาด 2 byte โดย byte แรกจะเป็นค่า 0xF0 ตัวถัดมาเป็นค่าประจำตำแหน่งของปุ่มนั้นๆ

ในส่วนของ Sourcecode เขียนด้วย Arduino version 1.0 โดยต่อขา Data เข้ากับขา Digital 2, Clock เข้ากับขา Digital 3 ของ Arduino มีการแสดงผลออก 2 ทาง คือ จอแอลซีดี และทาง Serial Port รองรับการพิมพ์อักษรภาษาอังกฤษทั้งพิมฑ์เล็ก พิมพ์ใหญ่ อักขระพิเศษ ปุ่ม Tab, Caps lock, Shift 

1: #define dat 2 2: #define clk 3 3: #define led 13 4: #define clk_low() digitalWrite(clk,LOW) 5: #define clk_high() digitalWrite(clk,HIGH) 6: #define read_dat() digitalRead(dat) 7: #define read_clk() digitalRead(clk) 8: #define ps2_delay() delayMicroseconds(39) 9: unsigned char shift, caplock; 10: int idx=0; 11: unsigned char arr[10] = {0}; 12: unsigned long wait_time; 13: char in_transmit = 0,timeout=0; 14: void setup() 15: { 16: Serial.begin(9600); 17: Serial.print(":5\r"); 18: delay(100); 19: Serial.print(":9\r"); 20: delay(10); 21: Serial.print(":2PS2 Keyboard\r"); 22: delay(100); 23: Serial.print(":1100\r"); 24: delay(10); 25: pinMode(dat,INPUT); 26: pinMode(clk,INPUT); 27: pinMode(led,OUTPUT); 28: digitalWrite(clk,HIGH); 29: digitalWrite(dat,HIGH); 30: } 31: void print_arr(unsigned char *p,int len) 32: { 33: int i; 34: for(i=0;i < len;i++) 35: { 36: print_hex(p[i]); 37: Serial.write(' '); 38: } 39: } 40: void decode_key(char c) 41: { 42: Serial.print(":2"); 43: switch(c) 44: { 45: case 0x76: Serial.write(0x1b);break; //esc 46: case 0x05: Serial.write(0x1b);break; //f1 47: case 0x06: Serial.write(0x1b);break; //f2 48: case 0x04: Serial.write(0x1b);break; //f3 49: case 0x0c: Serial.write(0x1b);break; //f4 50: case 0x03: Serial.write(0x1b);break; //f5 51: case 0x0b: Serial.write(0x1b);break; //f6 52: case 0x83: Serial.write(0x1b);break; //f7 53: case 0x0a: Serial.write(0x1b);break; //f8 54: case 0x01: Serial.write(0x1b);break; //f9 55: case 0x09: Serial.write(0x1b);break; //f10 56: case 0x78: Serial.write(0x1b);break; //f11 57: case 0x07: Serial.write(0x1b);break; //f12 58: case 0x0e: 59: if(shift == 0)Serial.write('`'); 60: else Serial.write('~'); 61: break; 62: case 0x16: 63: if(shift == 0)Serial.write('1'); 64: else Serial.write('!'); 65: break; 66: case 0x1e: 67: if(shift == 0)Serial.write('2'); 68: else Serial.write('@'); 69: break; 70: case 0x26: 71: if(shift == 0)Serial.write('3'); 72: else Serial.write('#'); 73: break; 74: case 0x25: 75: if(shift == 0)Serial.write('4'); 76: else Serial.write('$'); 77: break; 78: case 0x2e: 79: if(shift == 0)Serial.write('5'); 80: else Serial.write('%'); 81: break; 82: case 0x36: 83: if(shift == 0)Serial.write('6'); 84: else Serial.write('^'); 85: break; 86: case 0x3d: 87: if(shift == 0)Serial.write('7'); 88: else Serial.write('&'); 89: break; 90: case 0x3e: 91: if(shift == 0)Serial.write('8'); 92: else Serial.write('*'); 93: break; 94: case 0x46: 95: if(shift == 0)Serial.write('9'); 96: else Serial.write('('); 97: break; 98: case 0x45: 99: if(shift == 0)Serial.write('0'); 100: else Serial.write(')'); 101: break; 102: case 0x4e: 103: if(shift == 0)Serial.write('-'); 104: else Serial.write('_'); 105: break; 106: case 0x55: 107: if(shift == 0)Serial.write('='); 108: else Serial.write('+'); 109: break; 110: case 0x66: 111: Serial.write(0x08); //backspace 112: Serial.write(' ' ); 113: Serial.write(0x08); 114: break; 115: case 0x0d: 116: if(shift == 0)Serial.write(0x09); //tab 117: break; 118: case 0x15: 119: if(shift == 0 && caplock == 0)Serial.write('q'); 120: else Serial.write('Q'); 121: break; 122: case 0x1d: 123: if(shift == 0 && caplock == 0)Serial.write('w'); 124: else Serial.write('W'); 125: break; 126: case 0x24: 127: if(shift == 0 && caplock == 0)Serial.write('e'); 128: else Serial.write('E'); 129: break; 130: case 0x2d: 131: if(shift == 0 && caplock == 0)Serial.write('r'); 132: else Serial.write('R'); 133: break; 134: case 0x2c: 135: if(shift == 0 && caplock == 0)Serial.write('t'); 136: else Serial.write('T'); 137: break; 138: case 0x35: 139: if(shift == 0 && caplock == 0)Serial.write('y'); 140: else Serial.write('Y'); 141: break; 142: case 0x3c: 143: if(shift == 0 && caplock == 0)Serial.write('u'); 144: else Serial.write('U'); 145: break; 146: case 0x43: 147: if(shift == 0 && caplock == 0)Serial.write('i'); 148: else Serial.write('I'); 149: break; 150: case 0x44: 151: if(shift == 0 && caplock == 0)Serial.write('o'); 152: else Serial.write('O'); 153: break; 154: case 0x4d: 155: if(shift == 0 && caplock == 0)Serial.write('p'); 156: else Serial.write('P'); 157: break; 158: case 0x54: 159: if(shift == 0)Serial.write('['); 160: else Serial.write('{'); 161: break; 162: case 0x5b: 163: if(shift == 0)Serial.write(']'); 164: else Serial.write('}'); 165: break; 166: case 0x5d: 167: if(shift == 0)Serial.write('\\'); 168: else Serial.write('|'); 169: break; 170: case 0x1c: 171: if(shift == 0 && caplock == 0)Serial.write('a'); 172: else Serial.write('A'); 173: break; 174: case 0x1b: 175: if(shift == 0 && caplock == 0)Serial.write('s'); 176: else Serial.write('S'); 177: break; 178: case 0x23: 179: if(shift == 0 && caplock == 0)Serial.write('d'); 180: else Serial.write('D'); 181: break; 182: case 0x2b: 183: if(shift == 0 && caplock == 0)Serial.write('f'); 184: else Serial.write('F'); 185: break; 186: case 0x34: 187: if(shift == 0 && caplock == 0)Serial.write('g'); 188: else Serial.write('G'); 189: break; 190: case 0x33: 191: if(shift == 0 && caplock == 0)Serial.write('h'); 192: else Serial.write('H'); 193: break; 194: case 0x3b: 195: if(shift == 0 && caplock == 0)Serial.write('j'); 196: else Serial.write('J'); 197: break; 198: case 0x42: 199: if(shift == 0 && caplock == 0)Serial.write('k'); 200: else Serial.write('K'); 201: break; 202: case 0x4b: 203: if(shift == 0 && caplock == 0)Serial.write('l'); 204: else Serial.write('L'); 205: break; 206: case 0x4c: 207: if(shift == 0)Serial.write(':'); 208: else Serial.write(';'); 209: break; 210: case 0x52: 211: if(shift == 0)Serial.write('\''); 212: else Serial.write('"'); 213: break; 214: case 0x5a: 215: Serial.println(""); 216: break; 217: case 0x1a: 218: if(shift == 0 && caplock == 0)Serial.write('z'); 219: else Serial.write('Z'); 220: break; 221: case 0x22: 222: if(shift == 0 && caplock == 0)Serial.write('x'); 223: else Serial.write('X'); 224: break; 225: case 0x21: 226: if(shift == 0 && caplock == 0)Serial.write('c'); 227: else Serial.write('C'); 228: break; 229: case 0x2a: 230: if(shift == 0 && caplock == 0)Serial.write('v'); 231: else Serial.write('V'); 232: break; 233: case 0x32: 234: if(shift == 0 && caplock == 0)Serial.write('b'); 235: else Serial.write('B'); 236: break; 237: case 0x31: 238: if(shift == 0 && caplock == 0)Serial.write('n'); 239: else Serial.write('N'); 240: break; 241: case 0x3a: 242: if(shift == 0 && caplock == 0)Serial.write('m'); 243: else Serial.write('M'); 244: break; 245: case 0x41: 246: if(shift == 0)Serial.write(','); 247: else Serial.write('<'); 248: break; 249: case 0x49: 250: if(shift == 0)Serial.write('.'); 251: else Serial.write('>'); 252: break; 253: case 0x4a: 254: if(shift == 0)Serial.write('/'); 255: else Serial.write('?'); 256: break; 257: case 0x29: 258: Serial.write(' '); //space 259: break; 260: //default: print_hex(c); 261: } 262: Serial.print("\r"); 263: } 264: void print_hex(unsigned char a) 265: { 266: unsigned char t; 267: t = (a >> 4) & 0x0f; 268: if(t <10)Serial.write(t + '0'); 269: else 270: { 271: t = t - 10; 272: Serial.write(t + 'A'); 273: } 274: t = a & 0x0f; 275: if(t <10)Serial.write(t + '0'); 276: else 277: { 278: t = t - 10; 279: Serial.write(t + 'A'); 280: } 281: //Serial.println(""); 282: } 283: void loop() 284: { 285: if((millis() - wait_time > 10) && in_transmit == 1) 286: { 287: in_transmit = 0; 288: timeout = 1; 289: } 290: if(timeout == 1) 291: { 292: timeout = 0; 293: if((idx == 1) && ((arr[0] == 0x12) || (arr[0] == 0x59))) 294: { 295: shift = 1; 296: //Serial.println("Shift key DOWN"); 297: } 298: if((idx == 2) && (arr[0] == 0xf0) && ((arr[1] == 0x12) || (arr[1] == 0x59))) 299: { 300: shift = 0; 301: //Serial.println("Shift key UP"); 302: } 303: if((idx == 1) && (arr[0] == 0x58)) 304: { 305: caplock = ~caplock; 306: } 307: if(idx == 1)decode_key(arr[0]); 308: else{ } 309: /*Serial.print(" ["); 310: print_arr(arr,idx); 311: Serial.print(", "); 312: Serial.print(idx); 313: Serial.print("] "); 314: */ 315: //Serial.print(arr[0],HEX); 316: idx = 0; 317: } 318: if(read_dat() == LOW) 319: { 320: in_transmit = 1; 321: //Start bit 322: while(read_clk() == HIGH); 323: while(read_clk() == LOW); 324: //Read 8 bit data 325: int i=0; 326: char mdat=0; 327: for(i = 0;i <= 7;i++) 328: { 329: while(read_clk() == HIGH); 330: if(read_dat() == HIGH)mdat = (mdat | (1 << i)); 331: while(read_clk() == LOW); 332: } 333: //Parity bit 334: while(read_clk() == HIGH); 335: while(read_clk() == LOW); 336: //Stop bit 337: while(read_clk() == HIGH); 338: while(read_clk() == LOW); 339: //print_hex(mdat); 340: arr[idx] = mdat; 341: idx++; 342: in_transmit = 1; 343: wait_time = millis(); 344: } 345: }

Source code File ครับ

หวังบทความนี้คงพอช่วยให้ท่านสนุกกับการเล่นนะครับ

แหล่งข้อมูล

//en.wikipedia.org/wiki/PS/2_connector
//www.computer-engineering.org/ps2protocol/
//www.pyroelectro.com/tutorials/ps2_keyboard_interface/theory.html

Toplist

โพสต์ล่าสุด

แท็ก

แปลภาษาไทย ไทยแปลอังกฤษ โปรแกรม-แปล-ภาษา-อังกฤษ พร้อม-คำ-อ่าน lmyour แปลภาษา ห่อหมกฮวกไปฝากป้าmv แปลภาษาอาหรับ-ไทย แปลภาษาอังกฤษเป็นไทย pantip แอพแปลภาษาอาหรับเป็นไทย ค้นหา ประวัติ นามสกุล ห่อหมกฮวกไปฝากป้า หนังเต็มเรื่อง ไทยแปลอังกฤษ ประโยค Terjemahan เมอร์ซี่ อาร์สยาม ล่าสุด แปลภาษาจีน กรมส่งเสริมการปกครองท้องถิ่น ่้แปลภาษา Google Translate ข้อสอบคณิตศาสตร์ พร้อมเฉลย พร บ ระเบียบบริหารราชการแผ่นดิน ระเบียบกระทรวงการคลังว่าด้วยการจัดซื้อจัดจ้างและการบริหารพัสดุภาครัฐ พ.ศ. 2560 วิธีใช้มิเตอร์วัดไฟดิจิตอล สหกรณ์ออมทรัพย์กรมส่งเสริมการปกครอง ส่วนท้องถิ่น ห่อหมกฮวก แปลว่า Bahasa Thailand Thailand translate mu-x มือสอง รถบ้าน การวัดกระแสไฟฟ้า ด้วย แอมมิเตอร์ การ์ดแคปเตอร์ซากุระ ภาค 4 ก่อนจะนิ่งก็ต้องกลิ้งมาก่อน เนื้อเพลง ก่อนจะนิ่งก็ต้องกลิ้งมาก่อน แคปชั่น พจนานุกรมศัพท์ทหาร ภูมิอากาศ มีอะไรบ้าง สถาบันพัฒนาบุคลากรท้องถิ่น อาจารย์ ตจต อเวนเจอร์ส ทั้งหมด เขียน อาหรับ แปลไทย ใบรับรอง กรมพัฒนาฝีมือแรงงาน Google map Spirited Away 2 spirited away ดูได้ที่ไหน tor คือ จัดซื้อจัดจ้าง กินยาคุมกี่วัน ถึง ปล่อยในได้ ธาตุทองซาวด์เนื้อเพลง บช.สอท.ตำรวจไซเบอร์ ล่าสุด บบบย มิติวิญญาณมหัศจรรย์ ตอนจบ รหัสจังหวัด อําเภอ ตําบล ศัพท์ทางทหาร military words สอบ O หยน