manvaのエンジニアリング魂

エンジニアリング・ものづくり・DIYをもっと身近にするためのブログ。インスピレーションを刺激します。

デジタル入力が足りない場合の対処 ~ キーマトリクス

デジタル入力(DI)ピンが足りない場合、キーマトリクスを使う。検索すれば既に情報がいっぱいあるが、めっちゃ丁寧に説明してみる。

Pro MicroなどのArduinoマイコンでは、プルアップ抵抗が内蔵されており(内部プルアップ),それを使えばスイッチをGNDに繋ぐだけでDIができる。
f:id:manva:20210117234713p:plain

この時点で既にピンとこない人のために、もっとデジタル入出力(DIO)の基礎的な話も別記事に書いておいた。
デジタル入力の基礎的な話 - プルアップとかそんなん - manvaのエンジニアリング魂

では,上記の内部プルアップを用いたアクティブローの回路で,GNDではなく、デジタル出力(DO)に繋いだらどうなるか。DOをスイッチのイメージで描くと,↓のようになる。
f:id:manva:20210117235119p:plain
DOにLowを出力した時にはGNDに繋いだのと同じだが、DOにHighを出力した時、スイッチがオンでもオフでもHighであり、スイッチの操作が無効になる。スイッチ1つだと、無効とか要らんわ、と思うだろうが、この後のキーマトリクスで使う。
キーマトリクス回路とは,↓のようなものである。
f:id:manva:20210120064653p:plain
図は,3行3列の例である。とりあえずダイオードは無視して考えると,それぞれのスイッチが、上記のようなアクティブローの回路になっていて、DOで無効化できるようにしていると見なせる。
この例では、3行x3列で9個のスイッチを入力できる。単純にスイッチを1つずつDIに入力したら9ピン必要だが,この回路ならピンの数はDO3本,DI3本の計6本で済む。同様の配線で、行や列を増やすこともでき、行や列の数が多いほどピン数の節約効果は大きくなる。
わかりやすいように電圧がVccになっている線を赤にする↓。
f:id:manva:20210120064706p:plain
スイッチが全てオフならDOはどれもDIにつながっていないので,DOの状態に関係なくDIは全てHとなる。
また、DOが全てHなら、スイッチが全て「無効」の状態となり,スイッチの状態に関係なくDIは全てHとなる。DOで行ごとに無効化できるため、まず1行目のみを有効にしてDIを読み取り、次に2行目のみを有効にしてDIを読み取り、ということを高速に切替えれば全てのスイッチを読み取れる、という仕組みである。
その時の回路の電圧の状態を詳しく見てみる。DO1のみをLow(有効)にした時、回路の状態は↓のようになる。
f:id:manva:20210120064715p:plain
一番上の行のスイッチのみが有効となる。
ここで、SW1-1をオンにすると↓
f:id:manva:20210120064726p:plain
のようになり、DI1がローとなり、SW1-1が押されたことをマイコンで検出できる。
この図を見てみると、このときに、もしSW2-1やSW3-1も同時におされると、ショートすることがわかる(ダイオードが無ければ)。そうならないためにダイオードを入れている。

Arduino IDEで自作キーボードのプログラムをするなら↓こんな感じ。

void loop() {
    int CurrentKeyState;
    int i, j;

    for( i=0; i<NUM_ROW; i++ ){
        digitalWrite( rowPin[i], LOW );
        for( j=0; j<NUM_COL; j++ ){
            CurrentKeyState = digitalRead( colPin[j] );
            if( CurrentKeyState==LOW && PreviousKeyState[i][j]==HIGH ){
                Keyboard.press( keyMap[i][j] );
            }else if( CurrentKeyState==HIGH && PreviousKeyState[i][j]==LOW ){
                Keyboard.release( keyMap[i][j] );
            }
            PreviousKeyState[i][j] = CurrentKeyState;
        }
        digitalWrite( rowPin[i], HIGH );
    }
}