IchigoJamでポケモンキーボードを使ってみる(Bluetooth・PS/2変換)
前回調査したArduino pro mini+USB Hostシールドを使って、
IchigoJamで「ポケモンキーボード(Bluetoothキーボード)」を利用出来るようにしました。
IchigoJamからはPS/2キーボードと認識されて利用出来ます。
ポケモンキーボードの全てのキーが利用出来ます。
IchigoJamから電源供給しています。
キーボードからの入力情報はPS/2キーボード用の端子 KBD1、KBD2に接続しています。
arduino IchigoJam
D2 => KBD2
D3 => KBD1
VCC => VCC
GND => GND
動作の様子
システム構成的な図
※図のGND => VCCは記載ミスです GND => GND が正しいです
処理としては、図のようなハードウェア&ソフトウェア構成となっています。
Bluetooth HIDのキーボード入力データをPS/2キーボードデータと信号に変換して
IchigoJamのPS/2キーボードとして利用出来るようにしています。
起動後のキーボードのキーを押しまくっているとペアリングが行われます。
利用しているハードウェア
1)Arduino pro mini 3.3V版(上)とUSB Hostシールド
純正品は高いので2つともクローン製品を使っています。
合計で1000円くらいです。
2)USB Bluetoothドングル
BT-MicroEDR2X
Bluetooth Ver.2.1+EDR対応 Micro サイズ USBアダプタ (Class2/10m)
かなり前に買って放置していたものです。
これ以外にElecom製のLBT-UAN05C2でも動作しました。
スケッチ
スケッチを公開します。
スケッチのダウンロード btkbd2ps2.zip (3.2K)
※ 2016/11/18 追記 最新版はgithubにて公開しています。
https://github.com/Tamakichi/Arduino_USBToPS2
コンパイルはArduino IDE 1.6.12を利用しています。
本スケッチの他に別途、下記のライブラリが必要です。
http://playground.arduino.cc/ComponentLib/Ps2mouse
// // btkbd2ps2 Bluetoothキーボード PS/2キーボード変換 for IchigoJam // 作成者 たま吉さん // 作成日 2016/11/09 // // このスケッチの利用には以下のハードウェア(シールド)が必要です. // ・USB Host Shield // // このスケッチのコンパイルには以下のライブラリが必要です. // ・PS/2デバイス ps2dev(ps2dev.zip) - an interface library for ps2 host // PS2 mouse interface for Arduino(http://playground.arduino.cc/ComponentLib/Ps2mouse) // ・USB_Host_Shield_2.0 (https://github.com/felis/USB_Host_Shield_2.0) // #include <ps2dev.h> #include <BTHID.h> #include <usbhub.h> PS2dev keyboard(3,2); // PS/2デバイス // HID Usage ID (0x04 - 0x43) => PS/2 スキャンコード 変換テーブル const uint8_t keytable1[64] PROGMEM = { 0x1C,0x32,0x21,0x23,0x24,0x2B,0x34,0x33,0x43,0x3B,0x42,0x4B,0x3A,0x31,0x44,0x4D, 0x15,0x2D,0x1B,0x2C,0x3C,0x2A,0x1D,0x22,0x35,0x1A,0x16,0x1E,0x26,0x25,0x2E,0x36, 0x3D,0x3E,0x46,0x45,0x5A,0x76,0x66,0x0D,0x29,0x4E,0x55,0x54,0x5B,0x5D,0x5D,0x4C, 0x52,0x0E,0x41,0x49,0x4A,0x58,0x05,0x06,0x04,0x0C,0x03,0x0B,0x83,0x0A,0x01,0x09, }; // HID Usage ID (0x4A - 0x52) => PS/2 スキャンコード 変換テーブル const uint8_t keytable2[9] PROGMEM = { 0x6C,0x7D,0x71,0x69,0x7A,0x74,0x6B,0x72,0x75, }; // // HIDキーボード レポートパーサークラスの定義 // class KbdRptParser : public KeyboardReportParser { protected: virtual uint8_t HandleLockingKeys(USBHID *hid, uint8_t key); virtual void OnControlKeysChanged(uint8_t before, uint8_t after); virtual void OnKeyDown(uint8_t mod, uint8_t key); virtual void OnKeyUp(uint8_t mod, uint8_t key); virtual void OnKeyPressed(uint8_t key) {}; }; uint8_t KbdRptParser::HandleLockingKeys(USBHID *hid, uint8_t key) { uint8_t old_keys = kbdLockingKeys.bLeds; switch (key) { case UHS_HID_BOOT_KEY_NUM_LOCK: kbdLockingKeys.kbdLeds.bmNumLock = ~kbdLockingKeys.kbdLeds.bmNumLock; break; case UHS_HID_BOOT_KEY_CAPS_LOCK: kbdLockingKeys.kbdLeds.bmCapsLock = ~kbdLockingKeys.kbdLeds.bmCapsLock; break; case UHS_HID_BOOT_KEY_SCROLL_LOCK: kbdLockingKeys.kbdLeds.bmScrollLock = ~kbdLockingKeys.kbdLeds.bmScrollLock; break; } if (old_keys != kbdLockingKeys.bLeds && hid) { BTHID *pBTHID = reinterpret_cast<BTHID *> (hid); // A cast the other way around is done in BTHID.cpp pBTHID->setLeds(kbdLockingKeys.bLeds); // Update the LEDs on the keyboard } return 0; } // // キー押しハンドラ // 引数 // mod : コントロールキー状態 // key : HID Usage ID // void KbdRptParser::OnKeyDown(uint8_t mod, uint8_t key) { /* Serial.print(F("DN [")); Serial.print(F("mod=")); Serial.print(mod,HEX); Serial.print("F( key=")); Serial.print(key,HEX); Serial.println(F("]")); */ // HID Usage ID から PS/2 スキャンコード に変換 uint8_t code = 0; uint8_t pre = 0; if (key >= 0x04 && key <= 0x43) { code = pgm_read_byte(keytable1 + key - 0x04); } else if (key >= 0x4A && key <= 0x52) { code = pgm_read_byte(keytable2 + key - 0x4A); pre = 0xE0; } else if (key == 0x87) { code = 0x51; } else if (key == 0x89) { code = 0x6A; } // PS/2キーの発行 if (pre) keyboard.write(pre); keyboard.write(code); } // // コントロールキー変更ハンドラ // SHIFT、CTRL、ALT、GUI(Win)キーの処理を行う // 引数 before : 変化前のコード USB Keyboard Reportの1バイト目 // after : 変化後のコード USB Keyboard Reportの1バイト目 // void KbdRptParser::OnControlKeysChanged(uint8_t before, uint8_t after) { MODIFIERKEYS beforeMod; *((uint8_t*)&beforeMod) = before; MODIFIERKEYS afterMod; *((uint8_t*)&afterMod) = after; // 左Ctrlキー if (beforeMod.bmLeftCtrl != afterMod.bmLeftCtrl) { if (afterMod.bmLeftCtrl) { keyboard.write(0x14); // 左Ctrlキーを押した } else { keyboard.write(0xF0); // 左Ctrltキーを離した keyboard.write(0x14); } } // 左Shiftキー if (beforeMod.bmLeftShift != afterMod.bmLeftShift) { if (afterMod.bmLeftShift) { keyboard.write(0x12); // 左Shiftキーを押した } else { keyboard.write(0xF0); // 左Shiftキーを離した keyboard.write(0x12); // } } // 左Altキー if (beforeMod.bmLeftAlt != afterMod.bmLeftAlt) { if (afterMod.bmLeftAlt) { keyboard.write(0x11); // 左Altキーを押した } else { keyboard.write(0xF0); // 左Altキーを離した keyboard.write(0x11); // } } // 左GUIキー(Winキー) if (beforeMod.bmLeftGUI != afterMod.bmLeftGUI) { if (afterMod.bmLeftGUI) { keyboard.write(0xE0); // 左GUIキーを押した keyboard.write(0x1F); } else { keyboard.write(0xE0); // 左GUIキーを離した keyboard.write(0xF0); keyboard.write(0x1F); } } // 右Ctrlキー if (beforeMod.bmRightCtrl != afterMod.bmRightCtrl) { if (afterMod.bmRightCtrl) { keyboard.write(0xE0); // 右Ctrlキーを押した keyboard.write(0x14); } else { keyboard.write(0xE0); // 右Ctrlキーを離した keyboard.write(0xF0); keyboard.write(0x14); } } // 右Shiftキー if (beforeMod.bmRightShift != afterMod.bmRightShift) { if (afterMod.bmRightShift) { keyboard.write(0x59); // 右Shiftキーを押した } else { keyboard.write(0xF0); // 右Shiftキーを離した keyboard.write(0x59); } } // 右Altキー if (beforeMod.bmRightAlt != afterMod.bmRightAlt) { if (afterMod.bmRightAlt) { keyboard.write(0xE0); // 右Altキーを押した keyboard.write(0x11); } else { keyboard.write(0xE0); // 右Altキーを離した keyboard.write(0xF0); keyboard.write(0x11); } } // 右GUIキー if (beforeMod.bmRightGUI != afterMod.bmRightGUI) { if (afterMod.bmRightGUI) { keyboard.write(0xE0); // 右GUIキーを押した keyboard.write(0x27); } else { keyboard.write(0xE0); // 右GUIキーを離した keyboard.write(0xF0); keyboard.write(0x27); } } }; // // キー離し ハンドラ // 引数 // mod : コントロールキー状態 // key : HID Usage ID // void KbdRptParser::OnKeyUp(uint8_t mod, uint8_t key) { // HID Usage ID から PS/2 スキャンコード に変換 uint8_t code = 0; uint8_t pre = 0; if (key >= 0x04 && key <= 0x43) { // keytable1を使った変換 code = pgm_read_byte(keytable1 + key - 0x04); } else if (key >= 0x4A && key <= 0x52) { // keytable2を使った変換 code = pgm_read_byte(keytable2 + key - 0x4A); pre = 0xE0; } else if (key == 0x87) { code = 0x51; } else if (key == 0x89) { code = 0x6A; } // PS/2キーの発行 if (pre) keyboard.write(pre); keyboard.write(0xF0); keyboard.write(code); }; // HIDマウス レポートパーサークラスの定義 class MouseRptParser : public MouseReportParser { protected: virtual void OnMouseMove(MOUSEINFO *mi) {}; virtual void OnLeftButtonUp(MOUSEINFO *mi){}; virtual void OnLeftButtonDown(MOUSEINFO *mi){}; virtual void OnRightButtonUp(MOUSEINFO *mi) {}; virtual void OnRightButtonDown(MOUSEINFO *mi){}; virtual void OnMiddleButtonUp(MOUSEINFO *mi){}; virtual void OnMiddleButtonDown(MOUSEINFO *mi){}; }; USB Usb; BTD Btd(&Usb); BTHID bthid(&Btd, PAIR, "0000"); BTHID hid(&Btd); KbdRptParser keyboardPrs; MouseRptParser mousePrs; int enabled =0; void ack() { while(keyboard.write(0xFA)); } // ホストから送信されるコマンドの処理 int keyboardcommand(int command) { unsigned char val; switch (command) { case 0xFF: ack();// Reset: キーボードリセットコマンド。正しく受け取った場合ACKを返す。 while(keyboard.write(0xAA)!=0); break; case 0xFE: // 再送要求 ack(); break; case 0xF6: // 起動時の状態へ戻す //enter stream mode ack(); break; case 0xF5: //起動時の状態へ戻し、キースキャンを停止する //FM enabled = 0; ack(); break; case 0xF4: //キースキャンを開始する //FM enabled = 1; ack(); break; case 0xF3: //set typematic rate/delay : ack(); keyboard.read(&val); //do nothing with the rate ack(); break; case 0xF2: //get device id : ack(); keyboard.write(0xAB); keyboard.write(0x83); break; case 0xF0: //set scan code set ack(); keyboard.read(&val); //do nothing with the rate ack(); break; case 0xEE: //echo :キーボードが接続されている場合、キーボードはパソコンへ応答(ECHO Responce)を返す。 //ack(); keyboard.write(0xEE); break; case 0xED: //set/reset LEDs :キーボードのLEDの点灯/消灯要求。これに続くオプションバイトでLEDを指定する。 ack(); keyboard.read(&val); //do nothing with the rate ack(); break; } } void setup() { Serial.begin(115200); while(keyboard.write(0xAA)!=0); if (Usb.Init() == -1) { Serial.print(F("\r\nOSC did not start")); while (1); // Halt } bthid.SetReportParser(KEYBOARD_PARSER_ID, &keyboardPrs); bthid.SetReportParser(MOUSE_PARSER_ID, &mousePrs); bthid.setProtocolMode(USB_HID_BOOT_PROTOCOL); // Boot Protocol Mode bthid.setProtocolMode(HID_RPT_PROTOCOL); // Report Protocol Mode Serial.println(F("Start.")); } void loop() { unsigned char c; // ホストからの送信データ if( (digitalRead(3)==LOW) || (digitalRead(2) == LOW)) { while(keyboard.read(&c)) ; keyboardcommand(c); } Usb.Task(); }
ポケモンキーボード以外のBluetoothキーボードも利用出来ると思います。
ただし、現状はポケモンキーボードに無いキーは未対応です。
カタカナ/ひらがなキー、無変換、変換キー、テンキーは未対応です。
サイズ的に中央に配置出来そうです。
最終的にはこの形態で利用出来るよう、やってみます。
2016/11/10 追記
取りあえず、ブレッドボードを付かない形態に変更しました。
ちょっと使いやすくなりました。
参考文献
・USB HID to PS/2 Scan Code Translation Table
http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/translate.pdf
・USBキーボードのキーコード
http://www2d.biglobe.ne.jp/~msyk/keyboard/layout/usbkeycode.html
・Device Class Definition for Human Interface Devices (HID)
http://www.usb.org/developers/hidpage/HID1_11.pdf
・HID Usage Tables
http://www.usb.org/developers/hidpage/Hut1_12v2.pdf
・NXP USB and PS/2 Multimedia Keyboard Interface
http://www.nxp.com/files/microcontrollers/doc/ref_manual/DRM014.pdf
・Sazanami Online PS/2 インターフェイスの研究
http://hp.vector.co.jp/authors/VA037406/html/ps2interface.htm
・PS/2キーボードインターフェース
http://www.technoveins.co.jp/technical/keyboard/
・O-Family JIS配列 PS/2 キーボード スキャンコード表
http://www.ne.jp/asahi/shared/o-family/ElecRoom/AVRMCOM/PS2_RS232C/KeyCordList.pdf
関連記事
IchigoJamでポケモンキーボードを使ってみる (16/11/10) この記事
arduinoでPS/2キーボードのエミュレーションを行う その2 (15/04/23)
arduinoでPS/2キーボードのエミュレーションを行う (15/04/22)
« Arduino Pro mini Pro Mini用USB HOSTシールドの調査 | トップページ | IchigoJamでLogicool製ワイヤレスキーボードを利用する(USB・PS/2変換) »
「arduino」カテゴリの記事
- Arduino IDE+Arduino STM32環境で指定と異なるgccが使われてしまう(2025.01.23)
- Zorin OSでArduino Uno互換機(CH340)が認識しない(2025.01.19)
- Arduino IDE 2.3.4でArduino STM32を利用する(2025.01.12)
- Arduino用 SKK日本語変換ライブラリの開発 その1(2024.12.28)
- NeoPixel(WS2812B)の制御 その5(2024.09.15)
「IchigoJam」カテゴリの記事
- Ichigojam Rが届きました(2021.02.05)
- β版 IchigoJam Rを予約注文しました(2021.01.23)
- IchigoJamのファームウェア 1.4.1が正式に公開されました(2019.12.10)
- 「ichigoツール」をGithubにて公開しました(2019.11.09)
- ichigojamのファームウェアを1.4b13にアップデートしました(2019.11.06)
« Arduino Pro mini Pro Mini用USB HOSTシールドの調査 | トップページ | IchigoJamでLogicool製ワイヤレスキーボードを利用する(USB・PS/2変換) »
コメント