ArduinoとCH9328でお手軽自作キーボード

CH9328とは

UARTを入力として受け取り USB HIDキーボードとして振舞うICのようです。

本来の用途としてはKVMスイッチなどでキーボードのエミュレーションを行うための物のようです。

今回はこのCH9328を搭載したモジュールボードを購入したので少し試食してみました。

f:id:inajob:20220405220253p:plain

自作キーボードとUSBデバイス

USB接続式の自作キーボードを設計するときに悩みの種となるのがUSBです。

まずUSBデバイス機能を搭載したマイコン、またはV-USBなどのソフトウェアエミュレーションに対応しているマイコンを用意する必要があります。

USBのプログラミングは煩雑で、メモリやCPUを結構消費します。

そして次の問題がVID/PIDです。作成したキーボードを個人で使う場合はそこまで問題となりませんが、販売するとなると正式には独自のVIP/PIDを取得しそれを利用するのが通常の流れです。

しかし、正規の方法でVIP/PIDを手に入れるためにはUSB-IFに申請し、結構多くのお金を納める必要があります。

同人ハードウェアなどの場合そこまでコストはかけられない、という事で、いくつかのベンダーがPIDのサブライセンスを行っているので、その仕組みに乗っかるなどしてPIDを取得している人もいるようです。

このあたりの事情は以下の記事が詳しいです。

qiita.com

CH9328とUSBのVID/PID

さて、今回扱うCH9328ですが、これはWCH社が販売しているICで、このICにはWHC社のVIDである0x1A86と、このIC固有の値であるPID 0xE026がデフォルト値として設定されています。 (この値は書き換えツールで変更できるようです)

この値をそのまま使う場合はWCH社のVID/PIDをそのまま使うことが出来ます(多分ライセンスとしてもこれでもないないはず、、USB Serial ICなどとやっていることは同じ)

Arduinoから使ってみる

ArduinoにはまさにCH9328を利用するためのライブラリである「CH9328-Keyboard」があります。

f:id:inajob:20220405212019p:plain

インストール出来たらHelloWorldのサンプルプログラムをArduino UNOに書き込んでさっそく実行してみます。

Arduino UNOで利用する際の罠

CH9328-Keyboardの内部で SERIAL_TX_ONLY という定数を使っていますが、どうもこれはESP8266などでのみ利用できる定数のようでArduino UNOではこのせいでコンパイルが実行できません。

インスール下ライブラリのCH9328Keyboard.cppの該当部分を削ることでコンパイルできるようになりました。

変更前
_Serial->begin(baud, SERIAL_8N1, SERIAL_TX_ONLY);

変更後
_Serial->begin(baud, SERIAL_8N1);

サンプルプログラムの実行

CH9328モジュールとArduino UNOはVCC,GND, TX, RXをそれぞれ接続します。

また動作モードを変更するジャンパのIO1,IO2をHIGHに設定します(このモジュールではジャンパをつけるとHIGHになるようです)

電力はCH9328モジュールからArduino UNOに送るのでArduino UNOはUSB接続する必要はありません。

Win+r押下の後 notepad + Enter を押下、その後Helloの文言が打ち込まれるというキーストロークのシミュレーションが行われ下記画像のようにメモ帳にメッセージが表示されました。

f:id:inajob:20220405212838p:plain

オリジナルキーボードの作成

ここまでくれば後は簡単です。

3キー搭載のマクロパッドを作ってみます。

自分のIDにちなんで「i」「n」「a」の3キーの存在するキーボードという事にします。

全く洗練されていませんがソースコードです。

#include <CH9328Keyboard.h>
#define PINRST 10
#define BAUDRATE 9600              //Default is 9600.
void setup()
{
  Keyboard.begin(&Serial, PINRST, BAUDRATE);
  delay(1000);
  Keyboard.releaseAll();

  pinMode(10, INPUT_PULLUP);
  pinMode(11, INPUT_PULLUP);
  pinMode(12, INPUT_PULLUP);
}

unsigned int trigger_b1 = 0;
unsigned int trigger_b2 = 0;
unsigned int trigger_b3 = 0;

void loop()
{
  int b1 = !digitalRead(10);
  int b2 = !digitalRead(11);
  int b3 = !digitalRead(12);

  if(b1){
    if(trigger_b1){
        Keyboard.press('i');
    }
    trigger_b1 ++;
  }else{
    Keyboard.release('i');
    trigger_b1 = 0;
  }
  if(b2){
    if(trigger_b2){
        Keyboard.press('n');
    }
    trigger_b2 ++;
  }else{
    Keyboard.release('n');
    trigger_b2 = 0;
  }
  if(b3){
    if(trigger_b3){
        Keyboard.press('a');
    }
    trigger_b3 ++;
  }else{
    Keyboard.release('a');
    trigger_b3 = 0;
  }

}

配線は Arduino UNOの10, 11, 12番ピンをタクトスイッチの片方にそれぞれ繋ぎ、タクトスイッチのもう片方はGNDに接続するだけです。

f:id:inajob:20220405220321p:plain

全体像はこんな感じです。

f:id:inajob:20220405220610p:plain

CH9328についてもう少し・・

値段やデータシートはLCSCが参考になります。

lcsc.com

モジュールは600円程しましたが、IC単品だと$1.5程度で買えそうです。AliExpressだともっと安いものも見つかると思います。 データシートは中国語の物しか見つかりませんでした。

しかし基本動作はシリアルから来たコードをHIDキーボードのコードに変換するだけなので、中国語が読めなくてもそこまで困ることはなさそうです。加えてCH9328-Keyboardライブラリがあるので、そもそも仕様を意識する必要もあまりありません。

AliExpressでCH9328で調べると様々なモジュールが販売されています。

私が今回利用したのは以下ですが、ほかにも様々なモジュールが存在します。

ja.aliexpress.com

よく似た型番の別のICや、ジャンパの設定が出来ないもの、水晶発振子が搭載されたもの、など様々な変種が存在するので、目的に応じて適切なものを購入してください。

(同じCH9328でも内部バージョンの違うものがあるようで、古いものは水晶発振子が外付けで必要のようです)

まとめ

CH9328を使うとUSB HID周りの煩わしい問題をすべて肩代わりしてくれるので、非常に簡単にUSBキーボードを自作できることがわかりました。

CH9328と低機能・低価格のマイコンを組み合わせる事で、部品は増えてしまいますが、多機能マイコン1つで作るよりも、安く、わかりやすい自作キーボードを設計することが出来ます。

チップの値段も安いので、新たな自作キーボードの材料として検討してみてはいかがでしょう?

最後に動作の様子の動画を貼っておきます。