HOME > 技術談話 > PIC® microcontroller > チャタリング除去

はじめに 高橋名人 認識時間 処理の負荷 周期と回数 気が付いたのはイツ 連打の回避 
処理の負荷を減らす 


■はじめに

 談話の初級編「スイッチ入力」でチャタリング除去について説明を行いましたが、気になる点を補足します。

■高橋名人

 「高橋名人」って覚えてますか?私自身リアルタイムで拝見したことは無いのですが…。
 なんでも任天堂ファミコンの16連射で有名との事。

 ゲームの中でスイッチを連打する。その連打が1秒間に16発であれば1発あたり62.5ms。
 けどスイッチはオフを経由しなければオンできないので、半分の31.25msでスイッチの状態を確定している?

 注意しなければならないのは、人間の操作に対してスイッチの状態を確定する作業が完全に同期していない事です。少なくとも倍以上の早さで状態を確定しないと非同期認識においては16連射を認識することは無理でしょう。

 まぁこれは相当早い操作条件ですが、世の中には組み込み機器を酷使する人がいるんですよね。画面スクロールのボタンを連打連打…「次!次!次!」って感じ。たいていの場合、画面の表示が追いつきません。 orz

 連打以外に困る操作があります。ボタンの「ちょい押し」。この場合はオン時間が短いです。「あれ?効かない?」ってこと、時々見かけます。誤操作を抑止するとも言いますが…。 orz


 そういえば連射機能を持つ外部装置をファミコンに取り付ける事もあった様です。どれ位の速度でスイッチを連打するのか?スイッチ処理を作る側からすると恐怖の仕様です。たぶん仕様が決められなくなります。

 2010.01.26 新規作成。

■認識時間

 チャタリング除去は非同期認識なので、処理タイミングとの絡みで認識できるまでの時間がばらつきます。例えばサンプリング周期10msで3回一致を考えた場合、以下のような時間幅を持つことになります。
 結果として認識時間は 、
  (サンプリング周期 × (チャタリング除去回数 - 1))ms < t < (サンプリング周期 × チャタリング除去回数)ms
になります。

 この考えに基づけばハードウェアによりチャタリング除去を行ったとしてもサンプリング周期1回分の範囲で認識時間のズレが生じます。ただ、部品定数や電圧変動、温度変化等でズレが更に変動する場合があります。

 2010.01.26 新規作成。

■処理の負荷

 チャタリング除去は定周期で行い、かつ、定周期時間のばらつきを抑えるために処理優先度は比較的高いです。

 これまで10ms周期の3回一致を例に取り上げましたが、認識時間を短くするために周期を短くしたらどうなるでしょう?
 もちろん、チャタリング除去という本来の目的が達成できる事が大前提です。

 チャタリング除去のための処理時間を20usと仮定します。
 ・
10ms周期の場合 … 占有率0.2%、1秒換算で100回分、2ms
 ・
5ms周期の場合 … 占有率0.4%、1秒換算で200回分、4ms

 1つの処理だけを見れば短時間ですが、積み重ねると大きな時間です。定周期実行で処理優先度が高く、チャタリング除去を行う分だけ低優先度の処理が遅延することになります。

 仮にチャタリング除去の処理時間を1usだけ短くしたとします。PICマイコンであれば1命令程度ですが…。
 ・10ms周期の場合 … 1秒換算で100回分、対策された時間は1秒あたり100us
 ・
5ms周期の場合 … 1秒換算で200回分、対策された時間は1秒あたり200us

 ささやかな対策でも繰り返し処理が行われる場合は積み重ねると大きな処理時間になります。

 この積み重ねは様々な場所で見られます。
 例えば、モニタディスプレイの表示更新時間の処理時間対策。VGAサイズであれば640*480ドット。全307,200ドットです。1画素あたりの処理時間を1us短縮できれば1画面に対して307.2msの処理時間を節約できます。

 処理能力を向上させたい場合は総ての処理の中から繰り返し実行される部位を抽出し、そこを集中的に対策します。時には関数呼び出しをマクロ呼び出しに変更するだけでも効果があります(反面プログラム容量は増えます)。場合によっては部分的な機能をC言語からアセンブラで記述し直すことで高速化を図る。これも常道手段です。

 たまにしか実行されない処理。これはスタックが許す限り関数呼び出しで問題ありません。できることなら高速化する処理のためにプログラム容量がコンパクトになる様に努めたいところです。


 理想を言えば、チャタリング除去の負荷があっても耐えられる処理時間の余裕が必要ですね。

 2010.01.27 新規作成。

■周期と回数

 普通の操作であれば10ms周期の3回一致で問題ありません。が、この「普通」という表現が悩ましいのが現実です。

 仕様書に記載されているからとサンプリング周期と一致回数をプログラムに反映しても、ユーザが使いづらいと言えばそれまでです。かといって、滅茶苦茶早いサンプリング周期を採用しても、チャタリング除去としての機能を失う可能性があるだけでなく、チャタリング除去処理の負荷が大きくなって本来行うべき処理の性能が低下します。

 これまでに作成されたシステムの後継機種を作るのであれば過去の仕様を参考にするのが良いと思います。少なくともユーザ認証は受けているわけで…。まずはチェックしてみましょう。無茶苦茶云々は抜きにして。

 高速に認識する場合はハードウェア担当者と話し合いましょう。前述の高橋名人ではありませんが、1秒間に20回の押下に対応するのであれば、
 ・チャタリングの発生しない(もしくは少ない)スイッチの採用を検討する。
 ・ハードウェアによるチャタリング除去を検討する。
といったところでしょうか。
 高橋名人の操作をソフトウェアだけで処理することはできますが処理の負荷増大を覚悟してください。増加分を他の処理で大いに対策する必要があります。

 低速で認識する場合はソフトウェアだけで対応できますが、1秒間に8回程度のオンを認識する性能は持ちたいところです。1秒間に4回の性能は…。プログラムを作っている本人ですら「イラッ」ってきます(笑

 時にはハイブリッド型を採用するケースもあります。スイッチの種類によりサンプリング周期と一致回数を使い分けます。高速に認識する種類を少なく、低速で認識する種類を多く。これであれば処理の負荷を幾分抑えることができます。また、高速認識する部分だけハードウェアにも救済してもらうのも手です。

 いずれにせよ、チャタリング除去した結果を利用する処理が目的とする時間内に行われること。これは大前提です。
 例えばテレビゲームの中で1秒間に20回の連射に対応するのであれば、1発あたり50ms以内に発射できなければチャタリング除去で頑張っても無意味です。敵にやられてしまいます orz

 2010.01.27 新規作成。

■気が付いたのはイツ

 スイッチが押下されてから30ms後に信号をオンする。どのように処理しますか?
 これまでと同様、サンプリング周期を10ms、3回一致で考えてみます。

その1:
確定した時を基準

その2:
兆しを基準

ただし確定ありき

 解釈の仕方で2通りが考えられますが、人の手でスイッチを操作している限りは曖昧な部分があるのでスイッチの状態が確定するまでの時間が短ければ問題は無いと思います。

 前者も後者も如何様にも正当性を示す理由が付けられます。が、火のないところに煙は立たず。スイッチのチャタリングはスイッチ操作の変化があって初めて発生するので、どちらかと言うと後者の方が理想的かもしれません。

 時としてチャタリング除去の時間を考慮した「XXms後」という仕様をユーザが指定する場合があるので、念のため確認しておいた方が良いでしょう。仕様を出す人、プログラムを作る人双方で補正を行うとマイナスの時間が生じる場合があります。
 例えば仕様を出す人がその2の方式を設定。けどプログラマがその1の方式で作っていることを予想し、20ms減じた10msで仕様を作成する。一方、プログラマはその2を想定し、仕様の時間から20msを減じる(概して自動計算させる事が多い)。その結果、出力信号のオンタイミングは-10ms。符号なし数値としてみた場合はとてつもなく大きな時間になります。

 今回の例題は人によるスイッチ操作、かつ出力信号の操作タイミングが短くて実運用ではありえないケースですが、モータで用紙送りを行い、センサーを通過してから出力信号を操作するようなケースではありそうです。

 さらに注意しなければならないのが、サンプリング周期1回分の範囲内で生じる認識時間のズレです(詳細は前述)。仕様として認識誤差±XXmsと記述があり、プログラムがその仕様を満足していれば問題ありませんが、仕様によってはチャタリングの生じない(少ない)ハードウェア構成、あるいは変化を割り込みで認識する等の工夫が必要です。

 2010.01.27 新規作成。

■連打の回避

 画面表示の行送りを繰り返すのは大変です。
 スイッチ押下で1行スクロール。カチカチ連打しても1秒に10行位のスクロールでしょうか。
 100行もスクロールした後は疲れますし、スイッチの音がうるさいです。

 これはデジタル時計の時間合わせでもありそうなシーンです。

 よくある対策としてはスイッチの長押しで高速スクロール。もしくはページスクロールする方法。

 この場合、スイッチのオン情報だけでは制御できないので、スイッチオンを時間監視し、ある時間を超えたら連続スクロールするような制御を行います。

 制御の一例を状態遷移図風に表現しました。
 ・赤線:事象で遷移(スイッチ操作、もしくは時間)
 ・黒線:無条件遷移

 最初のページスクロールを実行するまでは時間を要しますが、スイッチを押下継続した場合は短時間でページスクロールを繰り返すイメージです。


 時間監視の手法については工夫が必要です。

 マルチタスク構成であれば単に待機するだけで済みます。起床条件は時間とスイッチ操作でしょうか。

 シングルタスク構成の場合は単に待機したままでは他の処理が動作しません。この場合はステートを管理して分岐するようなプログラム構造が必要です。
 長押下の操作方法を知っている人が長押下に対応していない機器を取り扱う場合はすごく不便に感じるものです。

 2010.01.28 新規作成。

■処理の負荷を減らす

 多数のスイッチを処理する場合を考えます。動作条件は、
 ・8個のスイッチを10ms周期で個別にチャタリング除去を行う。
 ・1回あたりのチャタリング除去は0.2ms要する。
 ・チャタリング除去後のスイッチ処理は状態確定有無に関わらずスイッチ1個あたり0.5ms要する。
とします。

 この条件でプログラムを作ると以下の様になります(割り込みを利用しない極端な例)。

 この場所で10ms待機するのではなく、後続の処理を10ms周期で実行するためのタイミングを作り出します。

 スイッチに関する各処理は時間を基準に動作するので、単位時間当たりの中で常に処理(時間)が発生します。

 少なくともチャタリング除去を済ませた情報をスイッチ処理で扱う必要があります。

 この形式で処理を作成した場合、10ms経過の度に処理のピークが現れることになります。

 これはこれで問題ありません。スイッチしか処理しないのであればプログラムの負荷は約56%です。
 ですが、
プログラムのピークが集中してしまうこと、将来的な仕様変更に耐えられない可能性があります。


 例えば2ms周期で0.5msの処理を追加する場合、時間としては10msの中で合計2.5msの処理ですが、10ms周期の前半にスイッチに関する処理が占有しているので2ms周期を実現することができません。

 このような場合の対処法の1つとして、
追加の処理を割り込みで処理する方法があります。

 2ms周期の割り込みで追加された処理が動作します。メイン処理(割り込み処理以外を指す)は処理の途中で割り込みにより中断し、割り込み処理終了後に再開します。

 無難な作りであり、暇な時間は少なくなるもののプログラムの負荷は崩壊していません。まずは問題はないでしょう。ですが、
割り込みが行われることを前提としてメイン処理を作成する必要がありますし、スタックの消費量も注意しなければなりません。そして留意すべきは、プログラムのピーク集中は回避されていないことです。


 2つ目の対処法として、割り込みを使用せず、10ms周期を2ms周期に分割して処理を分散させます。

 ステップ番号を用意し、2ms毎にステップに応じた処理を行います。これにより追加処理は割り込み処理でなく、メイン処理に埋め込むことができます。同時にプログラムのピークを分散することができます。
 この手法であれば追加の定周期仕様が発生しても時間の隙間さえ見つければ対応することができます。

 この手法は時間を要する複数の乗除算や外部にある通信デバイスを利用する際にも利用できます。今回はスイッチ処理を分散させましたが、絶対定周期時間内(今回であれば10ms)で分散するのであれば制御上の問題はないはずです(一部例外はあると思いますが…)。


 割り込みを使う方法は間違いではありません。逆に割り込みで処理しなければならない事も多数あります。が、スタックの深さや変数の排他的使用等、注意しなければならない点が多くなります。注意さえ怠らなければ全く問題ありませんが、リスクが伴うことを忘れないでください。

 2010.02.14 新規作成。

■XXXXX

 。

 2010.XX.XX 新規作成。

Copyright 2010 PaletteSoft LLC. All rights reserved. 利用条件 | HOME | サイトマップ | お問合せ