デバウンスはFAQです。あなたは見つけることができるはずです...トピックのほぼ無制限の数のウェブページ。Smith氏は、このトピックに関するJack Ganssleの広く読まれているPDFについてもコメントしました。そして、これらすべての答えにより、ハードウェアとソフトウェアの両方の方法を利用できます。
まだ十分にカバーされていないアイデアについて主に話すことで、この「文学」に少しだけ追加します。しかし、私がする前に、1つか2つのポイント:
- アナログハードウェアでのデバウンスは、ポーリングによって、またはハードウェアのピン変更イベントによってさえ、定期的にデジタルでのみ「観測」されるスイッチでは達成できない結果を達成できます。しかし、すべての意図と目的をデジタルで「十分に」行うことができます。最近では、外部アナログデバウンスソリューションを使用する人はほとんどいません。しかし、私はワンショット(74121)を使用したパルスストレッチングから、ここでジャックガンスルが言及したテクニックまで、すべてを使用しました。
- 組み込みプログラミングのみを行っており、電子機器の学習にまったく関心がない場合、スイッチのデバウンスは、おそらく必要な2つの基本的なスキルセットの1つです。動作しているLEDはおそらくもう1つです。これによって、これらのスキルが1つしかないという意味ではありません。さまざまな方法でそれを行うことができるということです。あなたが本当にやるジャックGanssleはスイッチに関して、より一層に関する書き込み、どのような完全に逮捕する必要があります。
74121を使用したパルスストレッチングについて説明したので、Jack Ganssleはまだ言及しておらず、まだ誰もここで説明していないため、74121または555をワンショットとして使用するための追加の推奨資料として、この追加リンクを提供することもできます。スイッチをデバウンスするためのタイマー。
さて、これをマイクロコントローラで観察することから始めましょう。
通常、ステートマシンを使用してデバウンスを処理します。これはほとんど常に、私が約に設定した通常の「ハートビート」タイマーによって駆動されます8MS、 可能であれば。(私は通常、いくつかの理由でエッジトリガー割り込みイベントを使用しません。)
ステートマシンは次のようになります。
この回路のシミュレーション – CircuitLabを使用して作成された回路図
スイッチのDEBOUNCEDの値は、「非アクティブ」、「アクティブ」、および「不明」の値をとることができます。このようにして、初期化後にスイッチの値が落ち着くまでソフトウェアを確実に待機させることができます。しかし、通常、私はそれを気にしません。「不明な」値をデフォルト値に置き換え、代わりにバイナリ値システムを使用します。
ステートマシンに入るには、最初にデバウンス値をデフォルトに設定してから、ステートマシンの「CHANGING」状態に入ります。各時間間隔(通常は8MS私がそれを回避できる場合は)、現在のスイッチ値を読み取り、現在の状態と、場合によってはデバウンスされた値の更新を実行します。次に、終了します。高レベルのコードは、デバウンスされた状態にのみアクセスします。
それが私にとって重要な場合、私は以前のデバウンス状態を保持することもあります。これらの場合、デバウンスされた状態自体を更新するとき、最初にその状態を「以前のデバウンスされた状態」にコピーします。次に、値のペアを使用して、デバウンスされた遷移があったかどうかを判断できます。時々、私はトランジションを気にしません。時々、そうします。したがって、状況によって異なります。しかし、すべての場合において、デバウンスされた遷移についてのみ知りたいです。私はラントトランジションを気にしません。したがって、高レベルのコードは、ステートマシンが自身の作業に使用する内部状態を決して使用しません。
この方法の良い点の1つは、スイッチのポート全体を一度にデバウンスできることです。そして、割り込みコードに単一の分岐がなくてもそれを行うことができます。これは、マイクロコントローラーのポート幅(通常は8ビット幅)までの非常に高速で短いデバウンスコードを意味します。AtmelAT90の例は、Timer0割り込みイベントを使用してこれを実現する方法を示しています。
.equ SWPORTPINS = PINB
.def SwRawCurr = r4
.def SwRawPrev = r5
.def SwState = r6
.def SwDebCurr = r7
.def SwDebPrev = r8
; Debounce the input switches.
mov SwRawPrev, SwRawCurr
in SwRawCurr, SWPORTPINS
mov Timer0Tmp1, SwRawCurr
eor Timer0Tmp1, SwRawPrev
mov Timer0Tmp0, Timer0Tmp1
or Timer0Tmp1, SwState
mov SwState, Timer0Tmp0
mov Timer0Tmp0, Timer0Tmp1
com Timer0Tmp0
and Timer0Tmp1, SwDebCurr
and Timer0Tmp0, SwRawCurr
or Timer0Tmp1, Timer0Tmp0
mov SwDebPrev, SwDebCurr
mov SwDebCurr, Timer0Tmp1
ここで、この例は、以前および現在のデバウンスされたスイッチ値を含む完全な取引を示しています。また、必要なすべての状態遷移も実行します。このコードの初期化は示していません。しかし、上記は、ステートマシンの操作がいかに簡単であり、そのために必要なコードがほとんどないということを説明しています。これは非常に高速でシンプルであり、分岐を必要としません(追加のサイクルと追加のコードスペースが必要になる場合があります)。
私は使うことを好む 8MS私が過去に取り組んだ機器を使用して、さまざまな異なる人々との長い、長いテストが私をそこに導いたので、タイミング。私はより長い期間を試しました、そしてそうするとき、私は人々に「反応性」が十分に「活発」ではないことを言われるようになります。(最近、子供たちがリアルタイムの「シュート・エム・アップ」ゲームに取り組んでいるので、私はそれをさらに短くするかもしれません。彼らは、現代のデジタルTVがフレームのセットアップと表示を行うことによって引き起こされるわずかな遅延についてさえ、苦情を言うでしょう。)
一部の人々は、システムがどれほど鮮明で応答性がよいかについて非常に明確な感情を持つでしょう。鮮明で反応がよいということは、サンプルをより頻繁ではなく、より頻繁にサンプリングすることを意味します。でも個人的には20MS許容できる観測期間。(私にとっても、それより長い時間は十分とは言えません。)
前述のステートマシンは、最初にSETTLED状態に入り、DEBOUNCEDの値が更新される前に、さらに1つのサンプル時間そこにとどまる必要があることに注意してください。したがって、ボタンを押してそれを保持するには、たとえ最良の状況であっても、次のような遷移が必要になります。
- SETTLEDからCHANGINGに変更します
- CHANGINGからSETTLEDに変更します
- SETTLEDにとどまり、DEBOUNCEDを更新する
したがって、新しいデバウンス状態を実現するには、最低3つのサンプル期間が必要です。
プッシュボタンは、非アクティブからアクティブになり、非アクティブに戻るには、少なくとも6サンプル時間が必要です。
上記の詳細については、サンプル時間が 8MS それはどこかの間にあることを意味します 16MS <T≤24MS非アクティブから認識されたアクティブなデバウンス結果に移動する。そして、それは別の時間がかかります24MS状態が非アクティブに戻る前。それは最小です40MS <T≤48MS プッシュボタンサイクル全体を実行します。
より長いサンプル時間を使用すると、それに応じてより長い期間が生じます。を使用して20MS 私は「受け入れられる」と私はすでに言及しました 100MS <T≤120MSプッシュボタンサイクル全体。そして、それは人々が気づきがちな領域に真っ直ぐ上っている。それより長くなると、私は確かに「感触」が好きではありません。
この方法を使用する場合は、サンプル時間を長くすることに無頓着にしないでください。必要な場合は、ユーザー/コンシューマーを使用して多くのテストも行う必要があると思います。
タイピングキーボード用のコードを開発している場合は、使用時間を短くしてください。タイピストの記録は、数十年前に217 wpmで設定されました。これにより、約1つのキーが45MS。そのようなタイピストは、制御された順序で複数のキーを押しています。水銀で濡らされたリードリレースイッチングシステムを使用している非常に速いタイピストに良いパフォーマンスを得るには、2MS うまくいきました。