ボタンを押してから一定時間Lチカ【マイコンLチカ道場 Arduino編 1-3】

スイッチを押してから一定時間LED点灯Arduino
スポンサーリンク

はじめに

このページは「マイコンLチカ道場 Arduino編」の「1-3:ボタンを押してから一定時間Lチカ」に対応するページです。ボタン(スイッチ)を押す度にLEDが一定時間点灯するような動作をさせてみます。長時間LEDを点灯させたい場合もあるので、今回はdelay関数を使わずに、millis関数を使う方法で試してみました。

回路図とブレッドボード接続図

今回の回路図・接続も前々回の「ボタンを押している間Lチカ」と同じです。楽ちんですね。
1個の青色LEDと、1個のタクトスイッチを使用します。プルアップ抵抗は内蔵ではなく、外付けとしています。

回路図
回路図
ブレッドボード接続図
ブレッドボード接続イメージ

プログラムを書いてみる

今回のプログラム(スケッチ)は下記になります。前回のプログラムを少し改造しました。
今回はdelay関数を使わない方法ということで、millis関数を使っています。

const int LED1 = 12; //LEDを接続するピン
const int SW1 = 2; //スイッチを接続するピン
int sw_state = HIGH; //スイッチの状態保存用の変数
int sw_latch = HIGH; //スイッチのラッチ用の変数

unsigned long led_on_time; // LED点灯時の時間を保存する変数
const long on_width = 500; // LED点灯時間の幅を決める定数(ms)

void setup() {
  pinMode(LED1, OUTPUT); //LED1ピンを出力にする
  pinMode(SW1, INPUT); //SW1を入力に設定
}

void loop() {
  sw_state = digitalRead(SW1); //SW1の状態を読み込み、sw_stateに代入
  if (sw_state == LOW){
      if (sw_latch == HIGH && sw_state == LOW){
        digitalWrite(LED1, HIGH); //LED1を点灯させる
        led_on_time = millis(); //LED1が点灯した時間をled_on_timeに代入
        sw_latch = LOW; //sw_latchをLOWとする
      }
  } else {
    sw_latch = HIGH; //SW1がOFFであればsw_latchをHIGHとする。
  }
  
  if (millis() - led_on_time >= on_width){ 
  //led_on_timeからon_widthの時間以上経過していれば、下記の処理を行う
    digitalWrite(LED1, LOW); //led_stateの状態で点灯・消灯切り替え
  }
}

主な動作の説明はコメント文に記載しています。スイッチをオンにしてから定数「on_width」で入力した時間分LEDが点灯して消える動作をします。今回のスケッチでは500msとしています。
スイッチを押しっぱなしにしても、LEDが点灯して消える時間は500msのままで、スイッチをもう一度離して再度押すまで、LEDは点灯しません。
led_on_time = millis()」で、LEDを点灯させた瞬間の時間を変数「led_on_time」に代入しています。
if (millis() – led_on_time >= on_width)」で、現在の時間と「led_on_time」の時間差が定数「on_width」の値以上になると、LEDを消灯させる処理を行います。
※「sw_latch」の部分が無いと、スイッチを押している間は点灯し続け、離すと500ms後にオフするという動作になると思います。

millis()関数について

millis()関数は、「Arduinoボードがプログラムの実行を開始した時から現在までの時間をミリ秒単位で返す」(約50日間でオーバーフローし、ゼロに戻る。)という関数です。(参考:Arduino 日本語リファレンス

この関数を使えば、Lチカやチャタリング対策もdelay関数を使わずに出来るようです。今回の動作ではチャタリング対策は不要そうだったので入れていません。動作時の波形が下記になります。

スイッチを短く押した時の動作時の波形
スイッチを短く押した時の動作時の波形

スイッチを長押ししても、正常に500msでオフしています。

スイッチを長押しした時の動作時の波形
スイッチを長押しした時の動作時の波形

※厳密にはチャタリングが有ると少し点灯時間が延びるかもしれません。というか500ms以下でスイッチを連打しても下記の様にLEDは点灯しっぱなしの動作となります。(最後に押してから500ms後に消灯します)

スイッチを連打した時の動作時の波形

これはこれで動作としてアリかと思ってましたが、絶対に決まった時間だけLチカさせる為には、もう少し工夫が必要そうですね。試しにスケッチを変更してみたものが下記になります。

const int LED1 = 12; //LEDを接続するピン
const int SW1 = 2; //スイッチを接続するピン
int sw_state = HIGH; //スイッチの状態保存用の変数
int sw_latch = HIGH; //スイッチのラッチ用の変数
int led_latch = HIGH; //LEDのラッチ用の変数
unsigned long led_on_time; // LED点灯時の時間を保存する変数
const long on_width = 1000; // LED点灯時間の幅を決める数値(ms)

void setup() {
  pinMode(LED1, OUTPUT); //LED1ピンを出力にする
  pinMode(SW1, INPUT); //SW1を入力に設定
}

void loop() {
  sw_state = digitalRead(SW1); //SW1の状態を読み込み、sw_stateに代入
  if (sw_state == LOW){
    if (sw_latch == HIGH && led_latch == HIGH && sw_state == LOW){
        digitalWrite(LED1, HIGH); //LED1を点灯させる
        led_on_time = millis(); //LED1が点灯した時間をled_on_timeに代入
        sw_latch = LOW; //sw_latchをLOWとする
        led_latch = LOW; //led_latchをLOWとする
     }
  } else {
  sw_latch = HIGH; //SW1がOFFであればsw_latchをHIGHとする。
  }
  
  if (millis() - led_on_time >= on_width){ 
  //led_on_timeからon_widthの時間以上経過していれば、下記の処理を行う
    digitalWrite(LED1, LOW); //led_stateの状態で点灯・消灯切り替え
    if (sw_latch == HIGH && sw_state == HIGH){ 
    //sw_latchとsw_stateがHIGHであれば下記の処理を行う
      led_latch = HIGH; //led_latchをHIGHとする
    }
  }
}

変数「led_latch」を新しく設けて、LED点灯時に「led_latch」をLOWとし、LED消灯後に「sw_latch」と「sw_state」がHIGHであれば「led_latch」をHIGHに戻してやるようにしました。
少しややこしくなりましたが、これによって、スイッチを連打しても点灯時間に影響なくLEDがOFFしてくれるようになりました。
※「sw_latch」だけでなく「sw_state」も判定に入れてあげないと、スイッチ連打後おしっぱなしにしていると、点灯時間が延びるような動作になりました。
動作時の波形が下記になります。(連打しやすくする為、点灯時間1秒としています)
スイッチを連打したり、連打後押しっぱなしにしても1秒間(1000ms)でLEDが消灯していることがわかります。

対策後の動作波形:スイッチを連打した時
対策後:スイッチを連打した時の動作時の波形
対策後の動作波形:スイッチを連打・長押しした時
対策後:スイッチを連打・長押しした時の動作時の波形

まとめ

ボタン(スイッチ)を押す度にLEDが一定時間点灯するような動作をさせることが出来ました。今回はdelay関数を使わずに、millis関数を使う方法で試してみました。この方法だとdelayでマイコンの処理が止まることが無さそうなので、長時間点灯させてもほかの処理に影響を与えずに済みますね。
引き続き難しいLチカに挑戦していきましょう。

このページの実験は下記の商品で試すことが出来ます。
Arduino Uno Rev3 アルドゥイーノ ウノ ATmega328P【正規代理店品】プログラミング ロボット 電子工作 アルデュイーノ 正規品 アルディーノ 電子パーツ 電子工作キット
Arduinoオフィシャルストア
初めての方は正規品か、互換品でもUSB-シリアル変換にAtmega16U2が使われているものがオススメです。安価な互換品はCH340G等が使われており、トラぶると面倒かもしれません。
Arduino電子工作
スポンサーリンク
このページをシェアする
のぶをフォローする
スポンサーリンク
スポンサーリンク
のぶらぼ
タイトルとURLをコピーしました