概要
今回は以下のようなお話。
- Pro Microの +5V/16MHz版にPS/2キーボードを接続する。これは先日PRO MINIで作ったボードのマイコンをPro Microに載せ替えるだけで済む。
- Pro MicroをUSBケーブルでPCに接続し、HIDキーボードとして動作させるためのクラスを作る。大げさなPS/2-USB変換アダプタといったところ。
- JIS配列のPS/2キーボードを、ほぼNICOLA(親指シフト)キーボードとして使えるようにするためにhoboNicolaを修正し、PS/2キーボード用のクラスも含めてhoboNicolaLibrary1.11版として公開した。ライブラリに含まれるファイルの説明や、ダウンロードはこちらを参照。
USBキーボードを接続してほぼNICOLA配列にしたときの投稿はこちら。 - ちゃんと使えるようにするため、ユニバーサル基板にハンダ付けして頑丈にする。
Pro Micro 5V/16MHz版
日本のamazonに注文して約2週間で深センから到着。
さっそくUSBケーブルを差してPCに接続してみたところ、下図のようにWindows 10は Arduino Leonardo と認識した。
Windows10のデバイスとプリンターを開いて確認してみると、既にキーボードとマウスを備えたUSBコンポジットデバイスとなっていた。
Arduino Leonardoは使ったことがないのだが、同じブートローダーがフラッシュに書かれているのかもしれない。
SparkFun社のボード情報を追加済のArduino IDE (1.8.7)を開き、ツール/ボード情報を取得 を実行してみると、やはり Arduino Leonardo と表示された。
おそらく、ツール/ボードで SparkFun ProMicro (5V/16MHz)にし、何かのスケッチをビルドして書き込むと変わると思われる。
電源周り
前回、+3.3V/8MHz版を使ったときに電源周りの回路を調べてみたのだけど、今回購入した+5V版もジャンパJ1はオープンになっていた。
前にも書いたが、電源周りの回路は以下のようになっている。
写真で表面にS8QKと印字されているデバイスがLDOにあたり、LDOの入力がUSBのVBUS、出力がVCCとなっている。テスターで測ってみるとVBUSは+5.0V、VCC電圧は約+4.6Vだった。約0.4VがLDOのドロップアウトに相当する。
今回は+5V電源を必要とするPS/2キーボードを接続するので、VCCには5Vの±5%として4.75V以上は出て欲しい。そのための手段としては、以下の3つがある。
- RAWに外部から+6V以上与える。
- VCCに外部から+5Vちょうどを与える。
- J1を閉じて、VBUS とVCCを直結する。
せっかくのUSBデバイスなのに、別途電源が必要になるのは悲しい。今回はJ1にハンダを流して閉じ、VCCと直結することにした。
J1にハンダを流した。
オンボードLED
USBキーボード用に使ったPro Microの+3.3V版(8MHz発振器付き)のLEDは、電源インジケータが赤で送受信用が緑だった。
今回のものは、電源が緑で送受信が赤。おそらくLEDの直列抵抗は同じ値なので、緑はか細く、赤はまぶしい。もっともこの手の商品は、LEDが点灯するだけで儲けものくらいに思っている。
回路図
先日実験に使ったPROMINI + miniDINソケットの回路とほぼ同様。Pro MicroはUSBコネクタを備えておりPCと直結できるので、USB-シリアル変換モジュールが不要になる。
とりあえずブレッドボードに載せたところ。あっさりしている。
前回インタフェースを確認したブレッドボードからPRO MINIを抜き、代わりにPro Micro +5V/16MHz版を差しただけ。
D3端子とINT
PRO MINIとPro Microを同じ端子で結線した場合、いずれもD3端子にCLK信号を接続することになるのだが、ここに注意が必要。
PRO MINIでは、D3は ATmega328PのPD3/INT1ピンに接続されているが、Pro MicroのD3は、ATmega32u4のPD0/INT0ピンに接続されている。Arduinoの pinMode() や digitalWrite() で引数に3を指定しI/Oとして使う分には同じように扱えるが、attachInterrupt()で割込要因として使う場合、PRO MINIなら1、Pro Microなら0を指定する必要がある。
前回書いたテスト用のスケッチ(キーボードLEDをチカチカする)がなんで動かないか当初は戸惑ったのだけど、調べてみたらこういう理由でした。
スケッチ1(シリアルモニタでの確認用)
ps2_kbdクラスの作成
まずは、PS/2キーボードとのインタフェース機能をライブラリ(ps2_kbdクラス)にした。このライブラリは、PS/2キーボードから得られたスキャンコードをHID Usage IDとして返したり、キーボードのLEDをコントロールする機能を備えている。いちおう、PS/2キーボードのスキャンコードをそのまま返すこともできるようにした。
ps2_kbdクラスの実装については、Arduinoのライブラリの体裁にしたhoboNicolaプログラム(hoboNicolaLibrary1.11.zip)に含めたのでそちらを参照のこと。以下のスケッチはhoboNicolaLibrary1.11がライブラリとしてArduino IDEに導入されていないとビルドできない。USB版も含めたライブラリはこちらのページからダウンロードできる。
ライブラリ利用のスケッチ(スキャンコードの表示)
以下のスケッチは、ps2_kbdクラスの動作を確認するために作ったもので、hoboNicolaLibrary1.11のexamplesディレクトリに、ps2_kbd_test1.ino という名前で格納している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
#include "ps2_kbd.h" ps2_kbd* ps2; class ps2_event : public ps2_notify { public: virtual void raw_key_event(uint8_t scan) ;; virtual void key_pressed(uint8_t k, uint8_t mod); virtual void key_released(uint8_t k, uint8_t mod); virtual void modifier_changed(uint8_t before, uint8_t after); }; void ps2_event::raw_key_event(uint8_t scan) { char tmp[20]; sprintf(tmp, "%02X ", scan); Serial.print(tmp); } void ps2_event::modifier_changed(uint8_t before, uint8_t after) { char tmp[20]; sprintf(tmp, " [mod : %02X -> %02X]", before, after); Serial.println(tmp); } void ps2_event::key_pressed(uint8_t k, uint8_t mod) { char tmp[20]; sprintf(tmp, " [%02X, %02X is DOWN]", mod, k); Serial.println(tmp); if (k == 0x3a) ps2->toggle_numlock_led(); if (k == 0x3b) ps2->toggle_capslock_led(); if (k == 0x3c) ps2->toggle_scrlock_led(); } void ps2_event::key_released(uint8_t k, uint8_t mod) { char tmp[20]; sprintf(tmp, " [%02X, %02X is UP]", mod, k); Serial.println(tmp); } void setup() { ps2 = ps2_kbd::getInstance(); Serial.begin(115200); while (!Serial); Serial.println("Start."); ps2->begin(new ps2_event, LED_BUILTIN_TX); } void loop() { ps2->task(); } |
ps2_kbdにキーの押下やリリースを通知するためのクラス ps2_event のインスタンスをセットしてやることで、何かキー操作があるごとにそれが通知される。ps2_event クラスのメンバ関数は以下のように機能する。派生元のps2_notifyクラスは、ps2_kbd.h で定義している。
- raw_key_event() : 生のスキャンコードを1バイト得られたら通知する。
- key_pressed() : 押下されたキーのHID Usage IDが得られたら通知する。
- key_released() : リリースされたキーのHID Usage IDが得られたら通知する。
- modifier_changed() : 修飾キーの押下状態が変化したら通知する。
これらの通知は、メインループ(loop())から呼ぶ task() 内から行われる。task() 内ではps2_kbdクラス内の受信バッファからコードを取り出すたびに、raw_key_event() を呼び出すと共に、HID Usage IDへの変換処理や修飾キーの状況の通知を行う。
スキャンコードからHID Usage IDへの変換には、1つのキーについて最大8バイトのコードを評価する必要がある。
PS/2キーボードのスキャンコードについて
PS/2キーボードは3種類のスキャンコードセットを備えているようなのだが、今回は一般的なスキャンコードのセット2を使った。
古い話になるがIBM PCや互換機のBIOSを利用してキーボードのスキャンコードを得る場合、キーボードが出力したセット2のコードを、BIOSがセット1のコードに変換してくれていたので、わりとシンプルなコード系を扱えばよかった。しかしながら、今回はセット2を生で扱う必要があり、しょうしょうややこしかった。たとえば以下のようなスキャンコードが上がってくる。
Print Screen (0xE0, 0x7C)
- 押下: 0xE0, 0x12, 0xE0, 0x7C
- リリース: 0xE0, 0xF0, 0x7C, 0xE0, 0xF0, 0x12
Pause (0xE1, 0x14, 0x77)
- 押下: 0xE1, 0x14, 0x77, 0xE1, 0xF0, 0x14, 0xF0, 0x77
- リリース: (ナシ。MAKEコードに含まれる?)
Num Lock ON中にInsert (0xE0, 0x70)
- 押下: 0xE0, 0x12, 0xE0, 0x70
- リピート: 0xE0, 0x70
- リリース: 0xE0, 0xF0, 0x70, 0xE0, 0xF0, 0x12
左Shift押しながら上矢印 (0xE0, 0x75)
- 押下: 0xE0, 0xF0, 0x12, 0xE0, 0x75
- リピート: 0xE0, 0x75
- リリース: 0xE0, 0xF0, 0x75, 0xE0, 0x12
- リピート開始後のリリース: 0xE0, 0xF0, 0x75 (以下同じ)
右Shift押しながら上矢印
- 押下: 0xE0, 0xF0, 0x59, 0xE0, 0x75
- リピート: 0xE0, 0x75
- リリース: 0xE0, 0xF0, 0x75, 0xE0, 0x59
左Shiftと右Shift押しながら上矢印
- 押下: 0xE0, 0xF0, 0x12, 0xE0, 0xF0, 0x59, 0xE0, 0x75
- リピート: 0xE0, 0x75
- リリース: 0xE0, 0xF0, 0x75, 0xE0, 0x59, 0xE0, 0x12
参考:左Shiftは0x12、右Shiftは0x59。 0xF0はキーのリリースを表す。
こんな具合になっているのは、過去のBIOSとの互換性を維持するためなのだろう。0xE0, 0x12や0xE0, 0x59 というコードを出すキーは定義されていないので、その組み合わせを捨てながら評価していくことで、それらしくなった。詳しくはps2_kbd.cppを参照のこと。
シリアルモニタには上図のように表示される。[ ] で囲まれている値は key_pressed(), key_released(), modifier_changed() が出力しているもので、そうでないのが raw_key_event(); の出力を示している。
ps2_kbdの内部で、スキャンコード列からキーが確定した時点で通知しているので、上の説明とは若干違って見えている。
PS/2版のほぼNICOLAキーボード
ps2_kbdクラスはhoboNicolaプログラムの一部に組み込んだ。USBキーボード用をビルドするときには USB Host Shield Library 2.0を、PS/2キーボード用をビルドするときには ps2_kbdクラスを使うようにする。どちらを使うのかは、物理キーボードとNicolaKeyboardクラスの仲立ちをするスケッチ次第ということになる。
PS/2キーボードはHIDキーボードと違って、キーボード自体がタイパマチック動作してくる。HIDキーボードと同じように動いて欲しいので、 ps2_kbd::task(); の中で同じコードが連続した場合は捨ててしまってリピートを抑止した。
詳しくは、hoboNicolaのページをからダウンロードしてソースを見てください。
実用レベル?に仕上げる
前にも書いたのだけど、ブレッドボードに差したコネクタにキーボードケーブルをつなげると、ちょっとしたことでボードから外れてしまう。なので、ユニバーサル基板にはんだ付けすることにした。
ユニバーサル基板としては、秋月電子の小さな両面ユニバーサル基板 Dタイプ(47x36mm)を使った。もともとはATtinyのリモコン用に購入してあったもの。ここにPro MicroとMINI-DIN DIP化キット(ミニDINコネクタピッチ変換キット)を載せ、リセットスイッチとプルアップ抵抗を付けた。Pro Microに付属のリードが裏からはみ出すので、ミニブレッドボードに差し込んで対処。なかなかちょうどいい箱がないので、このまま使うことになるだろう。
せっかくなのでOM-Dのカメラ内深度合成を使って撮影してみた(レンズはMZD 30mm マクロ)。近接して深度合成する場合どうしても被写界深度の谷間に入るコマがでてくるので、8コマの合成では足りない。
キートップと並べてみると、その大きさ(小ささ)がよく分かる。PS/2版のhoboNiclaは、このRealforceを使い続けるために作ったようなものである。