CH9329とATtiny202でUSBキーボード

2023/09/09に公開

はじめに

秋月電子の新商品を見ていたら、面白いものを見つけました。「CH9329」というICです。このICは、USBでPCにつなぐとキーボード(またはマウス)として振る舞います。マイコンとシリアルで通信し、キー押下情報をPCに送ることができます。秋月電子での取り扱いが始まった頃、正直あまり使わないかなと思っていました。キーボード作るならRaspberry Pi pico や Pro Micro があるしこっちのほうが高性能だし。
しかし、キーの数が少なくて良いならATtiny202等の格安マイコンから操作すれば小型で安価なキーボードが作れることに気が付きました。例えば、パワポリモコンとかなら、キーは右と左の2つで十分だからピン数も少なくて良い。

ということで、今回はCH9329とATtiny202を使用して格安パワポリモコンを作成します。

CH9329

秋月電子で購入できるUSB(HID)シリアル変換ICです。シリアル通信でコマンドを送るとキーボードのキー押下を再現させることが出来ます。秋月電子で150円。

データシートは英語か中国語ですが、なんと日本語に翻訳してくれた方がいました。ありがとうございます。
https://sites.google.com/site/ichiworkspace/ホーム/みんなのラボ/キーボードマウスエミュレータ

データシートを読むと、通信方法にいくつかのモードがあるようです。
ASCIIモードでは、受け取ったデータをASCIIの文字として認識して文字をそのままキー押下にするモードです。これが一番扱いやすそうです。しかし、このモードではASCII文字しか送信出来ず、矢印キー等の特殊キーの押下を送信することが出来ません。
特殊キーの押下を送信するには、「プロトコル送信モード」を使う必要がありそうです。このモードでは、決められた順番でコマンドを送信することで、キー押下を送信出来ます。各キーには、キーコードが割り当てられていて、その対応表がデータシートに記載されています。この、各キーとキーコードの対応をプログラムで書かないと行けないのかと思うと、やる気を失います。

ここでふと思いました。もしかしたら、Arduino公式のキーボードライブラリとキーコードは同じなのではないかと。調べてみると、同じではなかったのですが、Arduinoのライブラリでは、ASCII文字をそのまま受け付けるようになっていて、定数として定義してある特殊キーのキーコードは、ASCIIの範囲分ずらして定義してあり、送信時にずらした分を戻して送信しているようでした。つまり、最終的にUSBへ送信しているキーコードのデータは、CH9329と同じでした。 おそらく、USB規格に則ったキーコードなのでしょう。

CH9329 キーボードライブラリ

ということで、Arduino公式のキーボードライブラリをちょろっと変えるだけで、CH9329用ライブラリが作れそうなので、作りました。

https://github.com/shigobu/CH9329_Keyboard

ATtiny202

新しいtinyAVR 0シリーズマイコンです。そのシリーズの中で、フラシュが一番小さくて、ピン数が一番少なく、唯一秋月電子で取り扱いがあるものです。2023年6月現在、70円です。安い!

仕様 ATtiny202
フラッシュ(プログラムメモリ) 2048 bytes
RAM 128 bytes
EEPROM 64 bytes
GPIO Pins 6 (5 usable)

対応したボードパッケージをインストールすると、Arduno IDE で使うことが出来ます。

参考
https://elchika.com/article/679c4633-9424-4296-a3a6-03b34239d419/#h_ATtiny シリーズで小型化

回路

回路図

CH9329のデータシートにある回路図とほとんど同じです。
ヒューズは、手持ちのリセッタブルヒューズ0.4Aを使用しました。また、2番ピンをグランドに接続して、モード1にしています。モード1はキーボードのみのモードです。

プログラム

#include "CH9329_Keyboard.h"

// ボーレート設定値計算マクロ。最後の"+0.5"は、四捨五入させるため??
#define USART0_BAUD_RATE(BAUD_RATE) ((float)(F_CPU * 64 / (16 * (float)BAUD_RATE)) + 0.5)

#define SW_OFF HIGH
#define SW_ON LOW

const int LEFT_SW_PIN = PIN_PA1;
const int RIGHT_SW_PIN = PIN_PA2;
const int SW_ON_THRESHOLD = 10;
uint8_t reportData[KEY_REPORT_DATA_LENGTH] = {};

// USART初期化
void USART0_init(void) {
  PORTA.DIR &= ~PIN7_bm;
  PORTA.DIR |= PIN6_bm;
  USART0.BAUD = (uint16_t)USART0_BAUD_RATE(CH9329_DEFAULT_BAUDRATE);
  USART0.CTRLB |= USART_TXEN_bm;
}

// 一つの値送信
void USART0_sendValue(uint8_t c) {
  while (!(USART0.STATUS & USART_DREIF_bm)) {
    ;
  }
  USART0.TXDATAL = c;
}

// 複数の値送信
void USART0_sendValue(uint8_t* c, size_t length) {
  for (size_t i = 0; i < length; i++ ) {
    USART0_sendValue(c[i]);
  }
}

// CH9329へキー押下情報送信
void CH9329_write(uint8_t c){
  size_t length = 0;
  CH9329_Keyboard.press(c);
  length = CH9329_Keyboard.getReportData(reportData, KEY_REPORT_DATA_LENGTH);
  USART0_sendValue(reportData, length);

  CH9329_Keyboard.release(c);
  length = CH9329_Keyboard.getReportData(reportData, KEY_REPORT_DATA_LENGTH);
  USART0_sendValue(reportData, length);
}

void setup() {
  USART0_init();
  CH9329_Keyboard.begin();

  pinMode(LEFT_SW_PIN, INPUT_PULLUP);
  pinMode(RIGHT_SW_PIN, INPUT_PULLUP);
  delay(5000);
}

void loop() {
  //チャタリング対策。SW_ON_THRESHOLDミリ秒ONが続いたものを採用する。
  int rightCount = 0;
  while (digitalRead(RIGHT_SW_PIN) == SW_ON){
    rightCount++;
    delay(1);
    if (rightCount > SW_ON_THRESHOLD){
      CH9329_write(KEY_RIGHT_ARROW);
      while (digitalRead(RIGHT_SW_PIN) == SW_ON);
      break;
    }
  }

  int leftCount = 0;
  while (digitalRead(LEFT_SW_PIN) == SW_ON){
    leftCount++;
    delay(1);
    if (leftCount > SW_ON_THRESHOLD){
      CH9329_write(KEY_LEFT_ARROW);
      while (digitalRead(LEFT_SW_PIN) == SW_ON);
      break;
    }
  }
}

上記の自作ライブラリを使用しています。
Serialオブジェクトを使うと、プログラムメモリを圧迫するので、直接レジスタを操作する方法でデータの送信を行いました。USARTの関数等は、マイクロチップ社が公開している資料(TB3216)のコードをほぼそのまま使いました。

制作

回路が簡単で部品数も少ないので、ユニバーサル基板に実装しようと思います。秋月のカテゴリとして存在してる基盤サイズの中で一番小さいD基盤を使いました。ユニバーサル基板の配線図は「marmelo」を使用し作成しました。角にあるピンヘッダは、基盤固定用の穴が空いてあるところで、部品と配線の配置ができないことを示しています。パスコンは、ICソケット(丸ピンソケット)の間に配置します。

ユニバーサル基板表
ユニバーサル基板裏

ここまで設計して、さて作るぞと部品を並べたところで、間違いに気づきました。配線図の横の穴数が一つ少なかったのです。幸いなことに、少ないものを多いものに実装する分には、穴が余るだけなので問題なく実装できました。逆だと設計やり直しでした。

完成写真

筐体には、百均のタッパーを使用したました。柔らかいプラスチックで加工し易いです。押しボタンは、オムロンの「A2A」を使いました。小さめですが、しっかりクリック感があって押し心地が良いです。USB端子は、秋月電子通商の「USB Type-Cコネクターパネル取付キット」をつかいました。Type-Cコネクタは、2つのCC端子を5.1kΩでプルダウンする必要があります。これは、Type-CコネクタはCC端子を見て電源端子の電圧を決めているためです。

主要部品

部品名 数量 購入場所
CH9329 1 秋月電子通商
ATtiny202 1 秋月電子通商
炭素皮膜抵抗 5.1kΩ 2 秋月電子通商
炭素皮膜抵抗 3.3kΩ 1 秋月電子通商
LED 1 秋月電子通商
ユニバーサル基板 Dタイプ 1 秋月電子通商
オムロン 超小形押ボタンスイッチ A2A 2(赤:1 青:1) モノタロウ
USB Type-Cコネクターパネル取付キット 1 秋月電子通商
タッパー 1 ダイソー

他、ピンヘッダやDIP化基盤を使いました。

まとめ

今回は、ch9329とATtiny202を使ってパワポリモコンを作りました。これで、パワポを使った発表が快適になります。
自作キーボードにはよくPro Microが使われますが、そこまで高性能である必要が無いパワポリモコンでは高価過ぎます。今回使用したch9329とATtiny202はとても安価でパワポリモコンに最適です。秋月電子通商では、両方合わせて220円です。とてもやすい。
みなさんも、お気に入りのスイッチでパワポリモコンを自作してみてはいかかでしょうか。

Discussion