概要
皆さん、USB機器自作したいですよね!
そのためにはまず、Aruduinoをキーボードと認識させるつまり、
ArduinoをHID(Human interface device)として認識させる
必要があります。認識してもらえるようになったら、キーコードと呼ばれる数値(キー入力に該当する情報)をマイコン側からPCに送れるようにプログラムすることでキーボード機器を作ることができます。
本記事では、HIDに認識させる方法から、認識後のプログラム法について説明します。
(2023/1/16追記)
現在、dfu-programmer-winの配布サイトが更新され、exeファイルがなく、各自ソースをビルドする必要があり難易度が上がっています。
(2024/7/19追記)
現在はこちらの[FLIP]というソフトを使ったほうがいい可能性が高いです(未検証)。
参考記事
- ATmega16U2をDFUモードにし、HID機器と認識させるようにする方法
- Arduino UnoでESCキー入力機器を作っている方(先にこちらを読むと良いと思います)
ただし、Aruduino ProやLeonardを使えば、Keyboardというライブラリがあり、簡単に実装できる上に悩むこともないので、こっちを使った方がいいと思います。
環境
- Windows10
- 純正のArduino IDE
- Arduino UNO:Atmega328p(作業に入る前に、Arduino内のプログラムがSerialを使っていないものに書き換えてください)
重要な点として、
atmega16u2がUSBインターフェースのもの
を使ってください。
コンパチ品だとCH320等をUSBインターフェースに使っていますが、その場合は今回の方法は使えません。
赤丸の部品がないと今回の方法は使えません。
使用ソフトウェア(ソフトというよりコマンドプロンプト上で起動するもの)
dfu-programmer
windows用にコンパイラ済みの物があるので、ダウンロードと回答するだけでOKです。
(追記)久々に訪れたら、windowsのコンパイラ済みの物がなくなってました。
流れ
- ATmega16U2のファームウェアを書き換える
- ATmega16U2をHIDキーボードデバイスと認識させる
- ATmega328pから、USBキーコード(Serialデータ)をATmega16U2に送る
- 送られたキーコードがキーボード入力として認識される
ATmega16U2をHIDキーボードデバイスと認識させる方法
デバイスマネージャを起動 = ウィンドウズマーク右クリック
関係ない話ですけど、windowsの設定画面どこに何があるかわかりにくいですよね。
デバイスマネージャーとか昔からあるやつと、windows10から追加された設定項目で2分化された感じで
新しくできた設定画面からじゃデバイスマネージャーとか出せないし・・・
dfu-programmerをダウンロードする
前述のリンクからダウンロードしてわかりやすい所に保存してください。
Arduino Unoのリセットピン下のピンを2つをジャンパーピンを使ってショートさせる
パソコンに繫ぐ
繫いでもPCには認識されません
認識されないことを確認した後(音が鳴らないので)、ジャンパーピンを外すと認識される(音が鳴る)
認識された時は「不明なデバイス」と表示されます。
->「プロパティ」を開き
->ドライバーのリボン
->ドライバーの更新
->コンピューターを参照してドライバーソフトウェアを検索
->dfu-programmerのファイル内の「dfu-programmer-win-0.7.2\dfu-prog-usb-1.2.2」を参照する
->ドライバーが当てられて、不明なデバイスから、「ATmega16U2」と認識されるようになります。
部門としては[Libusb-win32 devices]の中に[ATmega16U2]が有ります。
コマンドプロンプトで、dfu-programmer.exeを起動
cmd.exe
とWindowsマークのとなりの「ここに入力して検索」に打ち込み、コマンドプロンプトを起動します。
cd "ダウンロードしたdfu-programmerの保存場所"/dfu-programmer-win-0.7.2
でdfu-programmer.exeの有るファイルに移動(cdコマンドは人によって違います)
ファームウェアをダウンロードしてくる
キーボード機器として認識させるファームウェアは
->firmware
->Arduiono-keyboard-0.3.hex
です。
最初に入っている、Arduinoとしてのファームウェアは
->firmware
->Arduino-usbserial-uno.hex
です。
ダウンロードしたら、dfu-programmer
のファイル内に移動させます。
ファームウェアを書き込む
dfu-programmer ATmega16U2 erase
とコマンドプロンプトに打ち込み、Enterで実行すると。
Atmega16u2
に入っているたファームウェアを消します。
dfu-programmer.exe ATmega16U2 flash ./hex/Arduino-keyboard-0.3.hex
で新たにファームウェアを書き込みます。
flash
の後の./hex/
はhex
というファイルに自分が保存したためです。自分が保存した場所に合わせてください。
この段階ではまだ、キーボードとして認識されていませんが、一度USBを外して刺し直すと
「HIDキーボード」として認識されます。
ここで、Atmega328p
の方のプログラムがSerialデータを送信していた場合、Atmega16u2
がキー入力と勘違いしてPCにデータを送ることになってしまうのでマイコン側のプログラムの初期化が重要だったというわけです。
Arduino
として元に戻す場合は、ジャンパピンをさしてATmega16U2
として再度認識させ、dfu-programmer
で
dfu-programmer ATmega16U2 erase
dfu-programmer.exe ATmega16U2 flash ./hex/Arduino-usbserial-uno.hex
ATmega328p
から、USBキーコード(Serialデータ)をATmega16U2
に送る
次に、キー入力をする方法を説明します。
ATmega328p
から、ATmega16U2
にUSBキーコードをSerial.write
で送信すればキーボードとして入力したことになります。
送るUSBキーコードは次の表を参考にすると良いです。
まとめると
Usageの上位16ビットをUsage page下位16ビットをUsage IDと呼ぶ。
Usageは32ビットありこれをすべて送ると不経済であるため省略して送ることができる。
あるReportの集まりが共通のUsage Pageを持つUsageだった場合には、グループ化して表現でき、
下位16ビットのUsage IDだけを送信することができる。またUsage PageやUsage IDの上位ビットが0だった場合にはそれを省略できる。このためキーボードのUsageは、たとえば"A"キーは'0x00070004'ではなく'0x04'だけを送るようにできる。
サンプルとして、10秒おきに"hello world"と送信してくる機器にしてみましょう。
(実際にあったら超迷惑なBadUSBですが)
void setup() {
Serial.begin(9600);
delay(2000);
}
void loop() {
putChar(0x0B); // 一文字目大文字 できない
putChar(0x2A); //よってBackSpace
Sheft(0x0B); //H
putChar(0x08); //e
putChar(0x0F); //l
putChar(0x0F); //l
putChar(0x12); //o
Sheft(0x1A); //W
putChar(0x12); //o
putChar(0x15); //r
putChar(0x0F); //l
putChar(0x07); //d
putChar(0x28); //改行
delay(10000);
}
void putChar(byte data) {
for (byte j = 0; j <= 7; j++) {
if (j == 2) {
Serial.write(data);
} else {
Serial.write(0x00);
}
}
for (byte j = 0; j <= 7; j++) {
Serial.write(0x00);
}
}
void Sheft(byte data) {
for (byte j = 0; j <= 7; j++) {
if (j == 6) {
Serial.write(data);
} else if (j == 2) {
Serial.write(0xE5);
} else {
Serial.write(0x00);
}
}
for (byte j = 0; j <= 7; j++) {
Serial.write(0x00);
}
}
void Ender() {
for (byte j = 0; j <= 7; j++) {
if (j == 2) {
Serial.write(0x00);
} else {
Serial.write(0x00);
}
}
}
とりあえず、「HelloWorld」と送ってくるデバイスができました。
プログラムの書き込み
USBポートはキーボードとして認識してしまうためプログラムの書き込みはできなくなっています。
ArduinoISPという方法を使ってプログラムの書き込みは行ってください。
書き込み毎にファームウェアをもとに戻す方法もありますが、大変だと思います。
キーコードについて
HID
のスキャンコードはよくわかりません。難しいし、いい情報が見当たらない。
Usageのpageは省略できるっぽいが、keyboardなら0x07が最初からいらないことや、一度32bit送ったら、再度0で書き換えないとずっとそのキーを入力し続けている判定になることなど、難しい。
とりあえず、BackSpaceをやるなら上のプログラムで、
putChar(0x2A);
Enterなら
putChar(0x28);
でやれました。これで、巨大Enterも作れる。太鼓の達人コントローラも、アーケコンも作れるぞ!
ただ、遅延とかはまだよくわからない。
長々とご閲覧ありがとうございました。
追記
2023/1/16 dfu-programerのwindows版がなくなりました。自分でコンパイルする必要がありそうです。
Arduino ProでKeybord・Mouseライブラリを使うことを強くお勧めします。