Arduino を使って、押しボタンスイッチの入力アクションの検出を行なってみました。
アクションは「シングル (一回押し) 」「ダブル (二回押し) 」「ホールド (長押し) 」の三種類で、これらを一つのタクトスイッチから検出し LED の点灯・点滅・消灯を制御します。
ググってみると、一定の時間内にスイッチの状態を確認して OFF/ON が変化する時間や回数を調べる方法がとられているようですので、その方法で自分なりに考えてみることにします。
ますはアクションの検出について。
スイッチに入力があったら、そこから 50ミリ秒毎に 10回チェックを行い、その間にあった変化の回数をカウントすることにします。「シングル」では変化は 1回だけです。「ホールド」では変化はありません。「ダブル」の場合は 2回目の変化があった時点で判断します。
次に回路図です。
難しいものではありません。タクトスイッチの入力と、出力で LED を駆動するだけです。
入力ピンの電流を確認してみると HIGH でも LOW でも 0.7mA 程度でしたので、プルアップでもプルダウンでもどちらでもよさそうです。今回は ON 時に HIGH となるようプルダウンとしました。
出力も HIGH 時に LED が点灯するようにしました。もちろん電流値をきちんと確認して Arduino で直接駆動してもかまいませんが、これぐらいの単純なスイッチング回路を作るぐらいは屁でもありませんから (^_^;)
大まかなフローチャートです。
グーグル先生たちはこういうのを書かないのか、あまり見ませんね (^_^;) 上手ではありませんが、考えを整理するためにも簡単に作ると具合がいいです。
「入力待ち」では、スイッチが押されたかどうかを検知します。待つためにここでプログラムを止めてしまうと LED の点滅の制御ができなくなるので、一度検知したら次の処理を行なってからまた戻ってくるようにします。
スイッチが押されたら「変化を調べる」処理をします。前述のように、一定の時間内にスイッチの状態が変化した回数を調べます。
変化した回数をもとに、「LED表示」で点灯・点滅・消灯の制御を行います。点滅は 150ミリ秒を経過することに点灯・消灯を切り替えます。
「入力待ち」はこんな感じです。
入力ピンの状態を読み込んでスイッチが押されたら state_of_button をセットします。押されなければ何もしません。
スイッチが押されたら「変化を調べる」を実行します。押されていないときは何もしません。
50ミリ秒待ってからスイッチの状態が変化 (ON から OFF、または OFF から ON) しているかを調べます。変化なければ、また50ミリ秒待って調べます。これを 10回、都合 500ミリ秒間行ないます。
スイッチの状態が変化していたら number_of_changes を加算します。変化の回数が 2 になれば「ダブル」が確定しますので、ループを抜けます。これで number_of_changes は「シングル」が 1 、「ダブル」が 2 、「ホールド」は 0 となります。
ちなみに、最後の elapsed_time リセットは LED 点滅周期タイマーのスタートです。
最後は「LED 表示」です。
number_of_changes 値に従って switch case で分岐します。点滅制御は millis() 関数を利用して経過時間を調べ、150ミリ秒を経過していれば light 値を反転させて点灯・消灯を繰り返すという方法をとります。L チカでよくある delay を使う方法では、プログラムがここで止まってしまうのでうまくありません。
ということでできたスケッチは以下です。
// button-status.ino 2019/05/31 meyon
int inputPin = 2;
int outputPin = 13;
boolean state_of_button = 0;
boolean state_of_currently = 0;
int number_of_changes = 0;
unsigned long elapsed_time;
boolean light = 0;void wait_input(){
state_of_currently = digitalRead(inputPin);
if(state_of_currently == 1){
state_of_button = 1;
number_of_changes = 0;
}
return;
}void detect_changes(){
if(state_of_button == 1){
for(int i=0; i<10; i++){
delay(50);
state_of_currently = digitalRead(inputPin);
if(state_of_currently != state_of_button){
number_of_changes ++;
if(number_of_changes >= 2){
break;
}
state_of_button = state_of_currently;
}
}
while(state_of_currently == 1){
state_of_currently = digitalRead(inputPin);
}
state_of_button = 0;
elapsed_time = millis();
}
return;
}void light_led(){
switch(number_of_changes){
case 0:
light = 0;
break;
case 1:
light = 1;
break;
case 2:
if(millis() – elapsed_time > 150){
light = !light;
elapsed_time = millis();
}
}
digitalWrite(outputPin, light);return;
}void setup() {
pinMode(outputPin, OUTPUT);
pinMode(inputPin, INPUT);// Serial.begin(9600);
}void loop() {
wait_input();
detect_changes();
light_led();// Serial.print(state_of_currently);
// Serial.print(state_of_button);
// Serial.println(number_of_changes);}
コメントアウトしてあるシリアル出力はデバック時に変数の値を確認していたものです。このように適当な位置に Serial.print を入れると、その場所で変数がどうなっているかが見えるようになります。うまく動かないときに重宝しますね。
ということで、スイッチアクションで制御を切り替えることができるようになりました。