機械式接点のあるキースイッチでは、キーのオンオフ時にチャタリングが発生する。100us~1msの間に激しくオンオフを繰り返すから、それをそのまま素直に捉えてしまうと、キーの多重打ちとして拾ってしまい、キーを1回しか押してないのに、画面に2〜3個文字が打たれてしまう。そこで通常はファームウェアで、キーが押された後に 1~5ms 程度、チャタリングが落ち着くまで待ってから再度キーをスキャンし、キーが本当に離されたかどうかを判定する。
でも、これだとバタバタバタッとした波形が回路内を伝わっていることには変わらない。よくよく考えてみたら、キーボードは回路というより、こういうバタバタスイッチの集まりで、回路として繋がっている感が少ないかもしれない。
何とかしたい。
と勝手に熱く思い始め、PCB を作っている途中で、チャタリング防止回路、デバウンス回路を付けることにした。以下のサイトを参考に、何となく作ってみる。
スイッチのチャタリングの概要
スイッチに並列コンデンサはダメ回路
なんちゃってデバウンス回路
最初に作ったのは、自作キーボードのお手本回路に、コンデンサと抵抗を付け加たもの。キースイッチにかかる電圧を平滑化する目的なら、各キースイッチに並列にコンデンサを入れるのがよいと思う。でも、それだとキーボードでは数が多くて大変だから、マイコンの入力端子にコンデンサを取り付け、端子電圧が平滑化されて、デバウンスになればよいことにした。回路図

arduino は入力端子の内蔵プルアップはあるけど、内蔵プルダウンはないので、キーマトリックスは反転論理で作られることが多いようだ。すなわち、この回路図で、
- 各 col 端子はマイコンの内蔵プルアップ(ここでは 30kΩ とみなす)された入力端子
- 各 row 端子はアクティブ・ローの出力端子
待機時の動作
0.033uF x 30kΩ = 1.0ms.
スキャン時の動作
もしキーが押されていなければ、スイッチは不導通で、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 倍ぐらい短くなってしまってアンバランスではあるけど、これは上の上限電圧の制限から、あまり差を縮められない部分。
ハードウェアデバウンスの効果?
ということで、とりあえず ProMicro + qmk で動かしてみた。
でも、キーを押しても何も反応がない・・・(焦)
う〜ん、と考えながら寝入る直前に思いついて翌朝確認して分かったのは、qmk では、デフォルトでは row 端子を Low にしてから 30us 待って col 端子を読み出しているので、上の回路だと、まだ全然コンデンサの放電が終わっていなかったようだ。
このウェイトを 30us から 1ms に長くしてみたら、キー押下がちゃんと入力された。でも、これだとキースキャンが遅くなるなぁ ・・・。
なるほど。ソフトウェアであっても、ハードウェアであっても、「デバウンスの肝は待つこと」なのだと理解。
あれ!?
あちゃ〜〜〜。
そもそもデバウンス回路のコンデンサと抵抗を col 線と row 線に分けて置こうとしたのは、そこそこ配線の終わっていた PCB に、後付けでデバウンス部品を付けようとしたので、「col と row に分ければ、場所的に無理なく置けそうじゃん!」という理由だった。
抵抗 R10, R11 がデバウンス用抵抗。配線の途中に直列に入れるだけだから、簡単だったんだよね・・・。
0 件のコメント:
コメントを投稿