今回は、Arduino標準で搭載されている割り込み(interrupts)の機能と、
それを使った時のチャタリングについてお話していきます。
実際チャタリングとはどんなイメージなのかはこちらをご覧ください。↓↓
イメージとしては、割り込みで反応しているものの、
1回ボタンを押しただけなのに、割り込みが複数回入ってしまう感じです。
割り込みの中でONとOFFを反転させるような仕組みになっていたので、
この場合、ONとOFFが一瞬で2回切り替わって、ONのままのように見える。
という仕組みですね。
一番手前の黒いボタンが調子が悪いのが何となくわかってもらえると思います。
【チャタリング起こしにくいスイッチにすればいいじゃん…】
というのは無しで、今回はソフト側からチャタリングを防止してみました。
Youtubeチャンネルにさまざまな動画を上げています。
↓↓↓こちらからYoutubeチャンネルにアクセス!! ↓↓↓
↓↓↓↓これまでのArduinoの記事についてはこちら↓↓↓↓
チャタリングとはなんなのか?実際の回路も紹介。
チャタリングとは何なのかについてですが、
マルツさんが詳細を説明してくれているので
こちらを参考にしてください。
簡単に説明すると、
1回の切り替えで接点がバウンドして超高速で2回信号が変わってしまったりする現象です。
機械的なスイッチを使う以上、避けられない現象で、
何かしらの対策を入れる必要がある。というのが一般的な流れです。
対策方法としては、メカ的なものと、ソフト的なものがありますが、
今回はソフト的なアプローチをしてみようと思います。
動画のようなチャタリングが起きる回路
まず、冒頭の動画のようにチャタリングが発生する状態をご紹介します。
配線はこちらです。スイッチ2個とLEDという構成です。
ArduinoNanoの互換機を動画では使用していますが、
ArduinoUNOでも同じことができますのでご安心ください。
スイッチはD2,D3,LEDはD12につなげています。
LEDの抵抗だけ忘れないように気を付けてくださいね。
割り込み(interrupts)を使用してチャタリングが起きる。
今回は割り込み処理を使用するのが目的だったので、
Interruptsを使用します。
ArduinoのモデルによってInterruptsを使用できるピンは決まっています。
詳しくは公式のこちらに掲載されています。↓↓
内容としては、UNOにしてもNanoにしても、
2番ピンと3番ピンのみが割り込み処理のトリガーにできるピンです。
というわけで実際のスケッチはこちらです。
const byte ledPin = 12;
const byte interruptPinB = 2;
const byte interruptPinG = 3;
volatile byte state = LOW;
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(interruptPinB, INPUT_PULLUP);
pinMode(interruptPinG, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPinB), blink, RISING);
attachInterrupt(digitalPinToInterrupt(interruptPinG), blink, FALLING);
}
void loop() {
}
void blink() {
state = !state;
digitalWrite(ledPin, state);
}
上記のスケッチをそのまま書き込むと、1回タクトスイッチを押すと、
何回かに1回消えるはずが消えなかったり、
点くはずが点かなかったりするはずです。
それがチャタリングです。
チャタリングを防ぐ方法(スケッチ紹介)
チャタリングの説明の時に、メカ的な対策とソフト的な対策があると紹介しましたが、
メカ的な対策としては、コンデンサやシュミット・トリガなどを使うのが一般的なようです。
コンデンサは手持ちでありますが、
どうせやるなら書き込むスケッチで何とかならないかチャレンジしてみました。
チャタリング対策したスケッチ。
それではここが知りたかったところだと思いますのでもったいぶらずにご紹介します。
const byte ledPin = 12;
const byte interruptPinB = 2;
const byte interruptPinG = 3;
byte ledState=LOW;
bool switchFlg=false;
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(interruptPinB, INPUT_PULLUP);
pinMode(interruptPinG, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPinB), blink, RISING);
attachInterrupt(digitalPinToInterrupt(interruptPinG), blink, RISING);
Serial.begin(9600);
}
void loop() {
if(switchFlg)
{
delay(300); // チャタリング発生時間だけ待つ。ここは個体差あり。
ledState=!ledState;
digitalWrite(ledPin,ledState);
switchFlg=false;
Serial.println("LEDblink");
}
}
void blink() {
switchFlg=true;
Serial.println("interrupt!");
}
先ほどに比べてloop関数の中にいろいろ入れているのがわかりますかね。
実は、チャタリングしていたスケッチに対して対策した内容としては、
割り込みで実行される関数の中でLEDのONOFFをさせないようにしています。
割り込み自体はタクトスイッチ=チャタリングが発生するもの。
という構図になるので、割り込み関数の中でLEDの処理の実行部分を入れておくのは危険です。
では、割り込み関数の中でやっていることはなんでしょうか?
void blink() {
switchFlg=true;
Serial.println("interrupt!");
}
実は、割り込みされましたよ。とフラグをTrueにしているだけです。
これなら、何度Trueになりましたよ。とloopの中に入ってきたとしても、
実際の処理を行うのはloop関数の中なので何度もLEDのONOFFは実行されないということになります。
もう一つ大事なのが、
loop関数内のdelay(300)つまり待ちですね。
void loop() {
if(switchFlg)
{
delay(300); // チャタリング発生時間だけ待つ。ここは個体差あり。
ledState=!ledState;
digitalWrite(ledPin,ledState);
switchFlg=false;
Serial.println("LEDblink");
}
}
この待ちは、チャタリングしている場合、
つぎの割り込みが入ってきたとしても無視するためのものです。
逆に考えると、300mmSec以上の長期間チャタリングを起こす場合は防げません。
300mmSecもdelayを入れると若干押してから反応するまでのタイミングにラグが発生するので、
なるべくなら短くしたいですよね。
ちなみにこの対策版のスケッチを書き込んで動作テストしたのがこちらの動画です。
タイムラグは人間が感じられるレベルですが、
チャタリングするよりはましかな…といった感じですね。
冒頭の動画は光ったり光らなかったりなのでそれよりは全然いいですね。
今回のまとめ。
メカ的なチャタリングの対策方法はネット上にも結構あるのですが、
ソフト的に解決するアプローチに対してもちょっと紹介してみました。
Arduino限定にはなってしまいますが、割り込み処理を入れようとしてチャタリングして
困っている…という場合には参考にしてみてください。
コメント