4.1 delayを使わないLEDの点滅

delayを使うと、マイコンは待っている間は何もできなくなってしまうため
delayを使わずにLEDの点滅を行わせるには、どうすれば良いかを考えてみます。

そこで、プログラムを大幅に変えて
以下のようにしてみましょう

#define LED RED_LED

int LedState = LOW;
unsigned long preMillis = 0;  
unsigned long interval = 500;

void setup() {
  pinMode(LED, OUTPUT);      
}

void loop()
{
  unsigned long curMillis = millis();

  if(curMillis - preMillis > interval) {
    if (LedState == LOW) {
       digitalWrite(LED, HIGH);
       LedState = HIGH;
    }
    else {
       digitalWrite(LED, LOW);
       LedState = LOW;
    }
    preMillis = curMillis;   
  }

}

ここで、出てきた新しい関数や単語を順に見ていきます
unsigned long
という変数の型が出てきました、前回使っていたのはintだったわけですが
intは-32768~32767の値をとることができる変数型でした

longとは-2147483648~2147483647の値をとることができる変数型になります。
さらに、このlongの前に付けられたunsignedとは「符号無し」ということになり
マイナスを考えません、つまり扱える範囲が0~4294967295となります。

約43億までの数を数えられると言うことになります

次に出てきた新しい関数は
millis()
です。
この関数は、マイコンが動き出してから(電源が入ったorリセットされた瞬間から)
何ミリ秒経過したかを返す関数です。

unsigned long curMillis = millis()

と記述してありますので
curMillisという変数を宣言すると同時に、
マイコンが動き出してから現在までの経過時間をcurMillisに代入しています
(ちなみにcurはcurrentつまり”現在の”というつもりで名前を付けています)

では、次にif-else文をみてみると

  if(curMillis - preMillis > interval) {
    if (LedState == LOW) {
       digitalWrite(LED, HIGH);
       LedState = HIGH;
    }
    else {
       digitalWrite(LED, LOW);
       LedState = LOW;
    }
    preMillis = curMillis;   
  }

となっています。{ }が出てきました。
前回までのプログラムではifやelseの後に記述する命令が1つだけだったので
if(条件) 命令;
の形だったのですが、命令が複数ある場合は{ }でくくって記述することになります。

ちなみに、{ }でくくられるたびに、文字がインデント(2文字分右にずれて配置)されているのは、
{ }の中にくくられている範囲をわかりやすくするためです

さて、最初のifを見てみると
if(curMillis - preMillis > interval) {
となっています。
ここで出てきた、preMillisは前回の処理を行った時間を入れておくための変数として準備しています
(”以前の”という意味でpreviousの頭3文字次をとってpreと名前に付けています)

最初は0は代入されていますので
現在の時刻と0とを引き算して、interval(ここでは500が代入されている)より大きければ
{ }の中を実行します。

このif文の{ }が終わる前に
preMillis = curMillis;   
と記述してあります
これは、このif文の条件が真で{ }内が実行されたとき
最後にpreMillis(前回の処理を行った時刻)にcurMillis(現在の時刻)を代入しています。
つまり、前の処理から500[ms]経過しているときだけ{ }内を実行するわけです。
それ以外の場合はif文をスルーしますので、delayのように何もせずに待ち続けることはありません
if文の後ろに他の処理を記述すれば、そちらの処理を行わせることができます

それでは、このif文の中のif-else文を見ていきます

    if (LedState == LOW) {
       digitalWrite(LED, HIGH);
       LedState = HIGH;
    }
    else {
       digitalWrite(LED, LOW);
       LedState = LOW;
    }

となっており、ここでも{ }でくくることで複数の命令がifやelseの後に記述しています
ifの条件としてはLedstateという変数の中身がLOWなら真となります。
変数名はLed state(状態)ですので、読んで字のごとくLEDの状態を入れておく変数として準備しました
LEDはHIGH(光っている状態)とLOW(消えている状態)の2つの状態をとります。

もし、LEDがLOW(消えている状態)ならifの後の{ }を実行します
そうでなければelseの後の{ }を実行します

LEDが消えている状態であれば
       digitalWrite(LED, HIGH);
       LedState = HIGH;
として、LEDをHIGHにして、変数Ledstateの中に現在の状態(HIGH)を代入しています

LEDが光っている状態であれば
       digitalWrite(LED, LOW);
       LedState = LOW;
として、LEDをLOWにして、変数Ledstateの中に現在の状態(LOW)を代入しています

わざわざ、変数Ledstateの中に現在の状態を代入しているのは
マイコンで出力にしているポートの状態を読み取ることができないからです
なので、digitalWriteでHIGHを出力したら、HIGHと言う状態をどこかにメモしておかなくてはいけないわけです。

§3までと比べ、プログラムが複雑になってきましたが
マイコンの中で並列に複数のことを処理する場合に必要なテクニックの一つですので
プログラムがどんな動作をしているのか
もう一度自分でフォローしてみてください。

次は、同じ手法で緑色のLEDも点滅させたいと思います。

0 件のコメント:

コメントを投稿