前回はデジタル入力の勉強をしました。
前回はこちら
スイッチを用いたプログラムを動かしていると、スイッチが押された回数を数えたり、一回押される度に動作を変えたりしたい場合があります。前回勉強した方法では思い通りの動作を行いません。
トリガーの検出とチャタリング対策が必要になります。
トリガーの検出
LEDが点灯しているときに押しボタンSWを1回押すとLEDが消灯し、LEDが消灯しているときに押しボタンSWを1回押すとLEDが点灯するような動作を実現させたいです。身の回りで言うとエアコンのリモコンなどに使われています。
シンプルに考えると以下のようなプログラムになります。
#define LED 13
#define SW 7
void setup() {
pinMode(LED, OUTPUT);
pinMode(SW, INPUT_PULLUP);
}
void loop() {
if (digitalRead(SW) == LOW) {
if (digitalRead(LED) == HIGH) {
digitalWrite(LED, LOW);
} else {
digitalWrite(LED, HIGH);
}
}
}
10行目:
10行目のif文でSWが押されているかどうかを判定しています。
SWはアクティブLで接続していることを仮定しているので、SWが押されていればdigitalReadの戻値はLOWになります(SWが押されていなければ戻値はHIGHとなる)。
digitalReadの戻値がHIGH(=SWが押されていない)
特に処理は行なわれずloop関数を抜けます。(そして、再びloop関数が呼び出される)
digitalReadの戻値がLOW(=SWが押されている)
11行目から15行目までの処理が行われます。具体的には、現在のLEDの状態を取得し、LEDが点灯していれば消灯し、そうでなければ(=LEDが消灯していれば)点灯さます。
しかし、実際に実行してみると意図した動作をしません。
意図した動作をしない要因としては、「SW押下時間」と「loop関数の呼出し間隔」に関係します。
一般にSWの押下時間は0.2秒~0.5秒程度と考えられますが、その時間はArduinoがloop関数を呼び出す間隔と比較すると極めて長いです。
そのため、SWを押下している間に、複数回のloop処理(プログラムex03_3の10~16行目)が実行されてしまいます。
そして、その結果、SWを押下してもLEDが反転しなかったり、反転したりという不安定な動作となります。
意図した動作を実現するためには、「現在のSW状態」だけではなく「1ターン前のSW状態(前回のSW状態)」の利用が必要となります。
⇒前回のSW状態がHIGHで、現在のSW状態がLOWならLEDを反転させます
⇒上記の場合以外は何もしません。
#define LED 13
#define SW 7
boolean PS = HIGH; // Previous State 前回のSW状態
boolean CS; // Current State現在のSW状態
void setup() {
pinMode(LED, OUTPUT);
pinMode(SW, INPUT_PULLUP);
}
void loop() {
CS = digitalRead(SW);
if (PS == HIGH && CS == LOW) {
if (digitalRead(LED) == HIGH) {
digitalWrite(LED, LOW);
} else {
digitalWrite(LED, HIGH);
}
}
PS = CS;
}
4行目:
PSは前回loop関数実行時のSW状態(初期状態をHIGHとする)、05行目のCSは現在のSW状態を格納する変数です。
14行目:
「前回のSW状態がHIGH なおかつ 現在のSW状態がLOW であれば…」という条件判断を行なっています。
if文では「&&」を使ってAND条件を与えることができます。OR条件は「||」で与えます。
21行目:
次回loop関数が呼ばれるときのために、現在のSW状態を「前回のSW状態」として保存しています。
動作実験をしてみてください。
大分安定しましたが、まだ不具合が起きる場合があります。
これはチャタリングが原因です。
チャタリングとは
チャタリングとは、スイッチの ON/OFF を切り替える際、板バネなどの機械的構造に起因して接点が振動を起こす現象です。この結果、数msec から 数十msec という短い時間で意図しない ON/OFF が繰り返され、回路の誤作動等の原因となります。
チャタリングは電気回路上とソフトウェア上で回避する事が出来ます。
ソフトウェア上では、SW押下の検出後、チャタリングが収まるまでdelay命令を実行することでチャタリングをキャンセルすることができます。20行目です。
#define LED 13
#define SW 7
boolean PS = HIGH; // Previous State 前回のSW状態
boolean CS; // Current State現在のSW状態
void setup() {
pinMode(LED, OUTPUT);
pinMode(SW, INPUT_PULLUP);
}
void loop() {
CS = digitalRead(SW);
if (PS == HIGH && CS == LOW) {
if (digitalRead(LED) == HIGH) {
digitalWrite(LED, LOW);
} else {
digitalWrite(LED, HIGH);
}
delay(200);
}
PS = CS;
}
適切なdelay時間は、SW操作やSWタイプにより大きく変化するために実験的に決定する必要があります。
Delay時間が短すぎると、チャタリングの対策にならず、Delay時間が長すぎると、その間プログラムが動かなくなるため、スイッチを連打した際に、数え落としが発生してしまいます。
プログラムのみで解決すると、上記のデメリットが発生する為、高速で連打を検出したい場合等には回路上でも工夫する必要が有ります。
回路ではCR回路やシュミットトリガ回路等を用いて解決できます。
Arduino 実験⑧
チャタリングの電気回路における対策方法を調べ、説明せよ。
次回はこちら