LoginSignup
21
14

More than 1 year has passed since last update.

Arduino UNOを使った、キーボード機器製作法

Last updated at Posted at 2020-03-04

概要

皆さん、USB機器自作したいですよね!
そのためにはまず、Aruduinoをキーボードと認識させるつまり、

ArduinoをHID(Human interface device)として認識させる

必要があります。認識してもらえるようになったら、キーコードと呼ばれる数値(キー入力に該当する情報)をマイコン側からPCに送れるようにプログラムすることでキーボード機器を作ることができます。
本記事では、HIDに認識させる方法から、認識後のプログラム法について説明します。

(2023/1/16追記)
現在、dfu-programmer-winの配布サイトが更新され、exeファイルがなく、各自ソースをビルドする必要があり難易度が上がっています。

参考記事

  • ATmega16U2をDFUモードにし、HID機器と認識させるようにする方法

  • Arduino UnoでESCキー入力機器を作っている方(先にこちらを読むと良いと思います)

ただし、Aruduino ProやLeonardを使えば、Keyboardというライブラリがあり、簡単に実装できる上に悩むこともないので、こっちを使った方がいいと思います。

環境

  • Windows10
  • 純正のArduino IDE
  • Arduino UNO:Atmega328p(作業に入る前に、Arduino内のプログラムがSerialを使っていないものに書き換えてください)

重要な点として、
atmega16u2がUSBインターフェースのもの
を使ってください。
コンパチ品だとCH320等をUSBインターフェースに使っていますが、その場合は今回の方法は使えません。

12.png

赤丸の部品がないと今回の方法は使えません。

使用ソフトウェア(ソフトというよりコマンドプロンプト上で起動するもの)

dfu-programmer

windows用にコンパイラ済みの物があるので、ダウンロードと回答するだけでOKです。

(追記)久々に訪れたら、windowsのコンパイラ済みの物がなくなってました。

流れ

  1. ATmega16U2のファームウェアを書き換える
  2. ATmega16U2をHIDキーボードデバイスと認識させる
  3. ATmega328pから、USBキーコード(Serialデータ)をATmega16U2に送る
  4. 送られたキーコードがキーボード入力として認識される

ATmega16U2をHIDキーボードデバイスと認識させる方法

デバイスマネージャを起動 = ウィンドウズマーク右クリック

関係ない話ですけど、windowsの設定画面どこに何があるかわかりにくいですよね。
デバイスマネージャーとか昔からあるやつと、windows10から追加された設定項目で2分化された感じで
新しくできた設定画面からじゃデバイスマネージャーとか出せないし・・・

dfu-programmerをダウンロードする

前述のリンクからダウンロードしてわかりやすい所に保存してください。

Arduino Unoのリセットピン下のピンを2つをジャンパーピンを使ってショートさせる

ジャンパー.jpg

パソコンに繫ぐ

繫いでもPCには認識されません
認識されないことを確認した後(音が鳴らないので)、ジャンパーピンを外すと認識される(音が鳴る)
認識された時は「不明なデバイス」と表示されます。
->「プロパティ」を開き
->ドライバーのリボン
->ドライバーの更新
->コンピューターを参照してドライバーソフトウェアを検索
->dfu-programmerのファイル内の「dfu-programmer-win-0.7.2\dfu-prog-usb-1.2.2」を参照する
->ドライバーが当てられて、不明なデバイスから、「ATmega16U2」と認識されるようになります。

device.jpg

部門としては[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のファイル内に移動させます。

ファームウェアを書き込む

comand.jpg

dfu-programmer ATmega16U2 erase

とコマンドプロンプトに打ち込み、Enterで実行すると。
Atmega16u2に入っているたファームウェアを消します。

dfu-programmer.exe ATmega16U2 flash ./hex/Arduino-keyboard-0.3.hex

で新たにファームウェアを書き込みます。
flashの後の./hex/hexというファイルに自分が保存したためです。自分が保存した場所に合わせてください。

この段階ではまだ、キーボードとして認識されていませんが、一度USBを外して刺し直すと
「HIDキーボード」として認識されます。
keyborad.jpg
ここで、Atmega328pの方のプログラムがSerialデータを送信していた場合、Atmega16u2がキー入力と勘違いしてPCにデータを送ることになってしまうのでマイコン側のプログラムの初期化が重要だったというわけです。

Arduinoとして元に戻す場合は、ジャンパピンをさしてATmega16U2として再度認識させ、dfu-programmer

dfu-programmer ATmega16U2 erase
dfu-programmer.exe ATmega16U2 flash ./hex/Arduino-usbserial-uno.hex

comand2.jpg
と入力し直せば元に戻せます。

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ライブラリを使うことを強くお勧めします。

21
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
14