今回の仕様にスイッチを使ってLEDのOn/OffとLEDの色を変える、それと長押しで最大光量で光らせる機能を予定している。
スイッチはプッシュスイッチを考えていて、物理スイッチを使うとスイッチの接点やバネが有るため厄介な現象「チャタリング」が発生してしまう、スイッチの状態が変わったときに短い時間で接点の接触・非接触でOn/Offを繰り返した後にOnやOffに安定するのだが、On/Offを繰り返す不安定な時に状態を読み出すと間違った入力判断を得ることになってしまう。
この図のような読出しをしてしまうと3回スイッチを押したと判断してしまいその後の動作に問題発生と。
回避するには
1、スイッチとPICの間に回路を付け加える
2、プログラムを工夫する
ハードを付け加えればプログラムは簡単になるだろう、けれど部品点数が増えてしまいせっかくの小型化に貢献してくれない、んでプログラムでチャタリングを回避する。
プログラムでチャタリング除去
スイッチの状態が変わった時をトリガーにして
1.一時待って次の状態で判断する
2.何度か読み取って同じ状態が続くかで判断する
今回はスイッチ長押しの状態も考えているから、2番の方法の何度か読み取って状態判断をすることにした。
スイッチ押下で長短の判断は一定時間の中でスイッチがOffになってしまったら短いと判断をすることに、短いOnの場合はスイッチがオフとなってから判断するのでいっときの時間がかかることになるんだけど気にすることはないだろう。
何度か読み取るときにどの位の間隔が必要になるのだろう?、ゲームの連射とかを作るわけじゃないからちょっと長めでもかまわないだろう、で...10mSec間隔で読み取ることにする。
kOn = kOff = 0; // スイッチ状態カウンタ swStat = 0; // スイッチ状態ステータス while (1) { __delay_ms(10); // 10mSecのウェイト(10mSec間隔で読み取り) if (SwitchPORT == 0) // スイッチ状態が0ならOnとする(負論理) ++kOn; // On状態のカウント if (kOn >= 50) { // 連続50をカウントなら長押しと判断 swStat = LONG_PUSH; // 長押し判断 kOn = 50; // オーバーフローしないよう固定値 } } else { // スイッチ状態が1ならOffとする if (kOn >= 50) { // 長押しOff swStat = SWICH_OFF; kOn = 0; } else if (kOn >= 3) { // 短いOnと判断 swStat = SHORT_PUSH; kOn = 0; } else if (++kOff >= 3) { // Off判定 swStat = SWITCH_OFF; kOff = 0; } } if (kOn > 0 && kOff > 0) { // 両方カウントはチャタリングとする kOn = kOff = 0; } switch (swStat) { case 0: // スイッチOffの処理 break; case 1: // 短いスイッチOn処理 break; case 2: // 長いスイッチOn処理 break; } }
SwitchPortが「0(ゼロ)」のときにOnとしているのはPIC12F683の4番ピンをプルアップしGNDにプッシュスイッチを付けたので負論理となっている。
スイッチカウンタで3回同じ状態が続けばスイッチはOnまたはOffと判断する、ただしOnカウンタが50以上の場合は長押しと判断。