GD32VF103に割り込みを掛けるのに単体スイッチなど使っておりましたが、ちょいと数字が入力できる程度の「スイッチ配列」が欲しいもんだな、と思い立ちました。しかし、自作して醜い配線が多数というのは嫌。ちょうど良い塩梅の「キット」が売られていました。AE-KIT45-KEYPAD4X3、これなら汚い配線にはならない筈。
※「鳥なき里のマイコン屋」投稿順Indexはこちら
これまたArduino用がメインで売られているキットのようです。以下の商品ページへ行けば、Arduino用のサンプルプログラムをダウンロードすることができます。
秋月通商: 4×3キーパッド作成キット用基板 AE-KIT45-KEYPAD4X3
当方は、Arduinoではなく、GigaDevice社のRISC-Vコア搭載MCU、GD32VF103を搭載したSeeed社の開発ボード(環境はGD32VF103-SDK)にこのキーパッドのキット接続しようとしているので、そのままという分けには行きませぬ。
まずは、「キット」の組み立てから。以下がキットの内容であります。タクトスイッチ12個を4ビットx3ワード構成にするボードです。「ビット線」A,B,C,Dには電源との間に1kΩのプルアップをそれぞれ接続。駆動側の「ワード線」X,Y,Zと各スイッチの間にはダイオードが挿入されます。表面実装部品などはまったくないので、簡単に半田付けできます。
なおキットには、ピンヘッダが付属しているのですが、当方の事情により、手持ちのピンソケットに換えて実装いたしました。
半田付けしたら、評価ボードのGPIOに接続するだけです。GD32VF103VBT6は、16ビットのGPIOポートが、A,B,C,D,Eと5個も使用可能なので、今回は、
-
- Port Dの8、9、10番を「ワード線」X,Y,Z
- PortEの12、13、14、15番を「ビット線」A,B,C,D
とし、電源は3.3Vといたしました。開発に使っているPlatformIO上では、同じGD32VF103でも48ピンバージョンを搭載している小型ボード Longan nanoと「たばかって」動作させていますが、Longan nanoではこの辺のポートは使えない筈。
接続したところは、こんな感じ。
単なるGPIO接続なので、初期化、コードについては特に難しいことはありません。以下とおり(などと言いながら、最初、まったく動作せず、慌てふためいて調べたところが、結局、最初にPORT DとEに rcu_periph_clock_enableするのを忘れていた、というオチでした。トホホ。)
void initializePeriph(void) { // Enable Peripheral clock ~途中略~ rcu_periph_clock_enable(RCU_GPIOD); // Keypad rcu_periph_clock_enable(RCU_GPIOE); // Keypad ~途中略~ // A .. PE12 // B .. PE13 // C .. PE14 // D .. PE15 // X .. PD8 // Y .. PD9 // Z .. PD10 gpio_init(GPIOD, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10); // KEYPAD drive gpio_init(GPIOE, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15); // KEYPAD inputs gpio_bit_set(GPIOD, GPIO_PIN_8); gpio_bit_set(GPIOD, GPIO_PIN_9); gpio_bit_set(GPIOD, GPIO_PIN_10); ~以下略~
キーの読み取りルーチンは以下のとおり、全12キーについてそれぞれキーがおされていたら0、キーが押されていなかったら1の1ビットの値を並べたステータス値を返してきます。同時に2つ以上のキーが押されていても当然分かります。
unsigned int keyStatus(void) { uint16_t xstat, ystat, zstat; gpio_bit_reset(GPIOD, GPIO_PIN_8); //X gpio_bit_set(GPIOD, GPIO_PIN_9); gpio_bit_set(GPIOD, GPIO_PIN_10); delay_1ms(1); //delayS(100); xstat = gpio_input_port_get(GPIOE) & 0xF000; gpio_bit_set(GPIOD, GPIO_PIN_8); gpio_bit_reset(GPIOD, GPIO_PIN_9); //Y gpio_bit_set(GPIOD, GPIO_PIN_10); delay_1ms(1); //delayS(100); ystat = gpio_input_port_get(GPIOE) & 0xF000; gpio_bit_set(GPIOD, GPIO_PIN_8); gpio_bit_set(GPIOD, GPIO_PIN_9); gpio_bit_reset(GPIOD, GPIO_PIN_10); //Z delay_1ms(1); //delayS(100); zstat = gpio_input_port_get(GPIOE) & 0xF000; gpio_bit_set(GPIOD, GPIO_PIN_10); return (unsigned int)((zstat >> 4) | (ystat >> 8) | (xstat >> 12)); }
単独キーのキースキャンは問題なかったのですが、ひとつ「トラブッた」のは、2つ以上のキー押しの場合です。同一のワード線上の複数キーについては問題ないのですが、複数のワード線にまたがる同じビット線のキーを2個押すと、押していない3本目のワード線のビットも押されているかに見えました。具体的に言うと、XのAとYのAを同時に押すと押していないZのAも押されているように見えます。
まあ予想はしていました。上のコードの//で潰してあるところが修正箇所。最初使った待ちの長さが短すぎると判断したので、タイマで確実に「長時間」待つ関数で「待ち」をとても長くしたところ正常に動作するようになりました。
ビット線の「1」はプルアップ抵抗で回復するようになっているので、ワード線のスキャンの切り替えがその「回復時間」より早ければ、1と認識されるレベルになる前に読み込んでしまう筈。回復時間は、抵抗1kΩと、浮遊容量(マイコンのポートからKEYPAD間の長いジャンパ線とスイッチ通ってダイオードにいたる経路の)で決まる筈。本当はちゃんと測った方がいいと思うのだけれど、ゆるゆるスキャンすれば、まあ動くので、許す。いい加減な。