2019年12月5日木曜日

キーボードのデバウンス回路を考える(前編)

とは言っても、初めて作った 2x4 キーボードのただの失敗談。


機械式接点のあるキースイッチでは、キーのオンオフ時にチャタリングが発生する。100us~1msの間に激しくオンオフを繰り返すから、それをそのまま素直に捉えてしまうと、キーの多重打ちとして拾ってしまい、キーを1回しか押してないのに、画面に2〜3個文字が打たれてしまう。そこで通常はファームウェアで、キーが押された後に 1~5ms 程度、チャタリングが落ち着くまで待ってから再度キーをスキャンし、キーが本当に離されたかどうかを判定する。

でも、これだとバタバタバタッとした波形が回路内を伝わっていることには変わらない。よくよく考えてみたら、キーボードは回路というより、こういうバタバタスイッチの集まりで、回路として繋がっている感が少ないかもしれない。


何とかしたい。


と勝手に熱く思い始め、PCB を作っている途中で、チャタリング防止回路、デバウンス回路を付けることにした。以下のサイトを参考に、何となく作ってみる。

スイッチのチャタリングの概要
スイッチに並列コンデンサはダメ回路

なんちゃってデバウンス回路

最初に作ったのは、自作キーボードのお手本回路に、コンデンサと抵抗を付け加たもの。キースイッチにかかる電圧を平滑化する目的なら、各キースイッチに並列にコンデンサを入れるのがよいと思う。でも、それだとキーボードでは数が多くて大変だから、マイコンの入力端子にコンデンサを取り付け、端子電圧が平滑化されて、デバウンスになればよいことにした。

回路図


要はコンデンサを充放電すればいいんだよね?と考え、各 col 端子に平滑化コンデンサ1つと、各 row 端子に放電用抵抗を1つずつ付けてみた。



arduino は入力端子の内蔵プルアップはあるけど、内蔵プルダウンはないので、キーマトリックスは反転論理で作られることが多いようだ。すなわち、この回路図で、
  • 各 col 端子はマイコンの内蔵プルアップ(ここでは 30kΩ とみなす)された入力端子
  • 各 row 端子はアクティブ・ローの出力端子
に設定する。

待機時の動作


各 row 出力は、普段は High レベルにする。すると、ダイオードは逆バイアスされてオフになる。この時、キーが押されていてもいなくても、col 端子はプルアップにより High レベルになる。コンデンサの充電は、内蔵プルアップ抵抗を通して col 線で行われ、その時定数は
0.033uF x 30kΩ = 1.0ms.

スキャン時の動作


ここで、ある row 出力を Low レベルに落とすと、その row 行にある各キーの状態が各 col で検出できる。

もしキーが押されていなければ、スイッチは不導通で、col は High レベルのまま。

また、キーが押されていれば、スイッチとダイオードが導通して、col 端子が Low レベルに落ちる。実際には、電源電圧が 5V の場合、ダイオードの電圧降下を 0.7V として、
(5 - 0.7) * 3.3k / (3.3k + 30k) + 0.7V = 1.1V
が col 端子の電圧となる。atmega328p の場合、入力が Low と見做されるための上限電圧は
0.3 Vdd = 1.5V
なので、まだ多少の余裕がある。

一方、コンデンサの放電は、(col 端子の内蔵プルアップは大きいとして無視して)row 端子直前の抵抗を通して行われ、その時定数は、
0.033uF x 3.3kΩ = 0.11ms.
これは充電時の時定数 1.0ms に比べると 10 倍ぐらい短くなってしまってアンバランスではあるけど、これは上の上限電圧の制限から、あまり差を縮められない部分。

ハードウェアデバウンスの効果?


肝心のデバウンス効果としては、このスキャン時の時定数 0.11ms が効いてくる。オシロスコープを持ってないので、妄想の世界でチャタリングを防止している格好になってしまっているけど、たぶんこの時間スケールのスイッチ時の過渡波形が滑らかになっているはずだ!?

ということで、とりあえず ProMicro + qmk で動かしてみた。

でも、キーを押しても何も反応がない・・・(焦)

う〜ん、と考えながら寝入る直前に思いついて翌朝確認して分かったのは、qmk では、デフォルトでは row 端子を Low にしてから 30us 待って col 端子を読み出しているので、上の回路だと、まだ全然コンデンサの放電が終わっていなかったようだ。

このウェイトを 30us から 1ms に長くしてみたら、キー押下がちゃんと入力された。でも、これだとキースキャンが遅くなるなぁ ・・・。

なるほど。ソフトウェアであっても、ハードウェアであっても、「デバウンスの肝は待つこと」なのだと理解。

あれ!?


全部作り終わった後で気づいたのだけど、上の回路だと、row 行のキーを同時押ししていると、スキャン時の放電時間が長くなる!2個押しなら、コンデンサが2個並列で2倍遅く、3個押しなら、3個並列で3倍遅い。同時押しの数だけ倍数かかって遅くなる!

あちゃ〜〜〜。

そもそもデバウンス回路のコンデンサと抵抗を col 線と row 線に分けて置こうとしたのは、そこそこ配線の終わっていた PCB に、後付けでデバウンス部品を付けようとしたので、「col と row に分ければ、場所的に無理なく置けそうじゃん!」という理由だった。

最初の写真のキーボードの裏面

抵抗 R10, R11 がデバウンス用抵抗。配線の途中に直列に入れるだけだから、簡単だったんだよね・・・。

まとめ

「放電抵抗は row 線ではなく、col 線にデバウンス回路として、ちゃんと一緒にまとめて付けないといけなかった」という教訓。あと、充放電の時定数が 10 倍違うのもどうなの?というのも何とかしたかった・・・。後編に続く。





0 件のコメント:

コメントを投稿