第2回

条件分岐・繰り返し

条件によって処理を変え、同じ処理を繰り返す。

if

if (condition) {
}

if / else

if (temperature >= 30) {
    // ...
} else {
    // ...
}

else if

if (temperature >= 40) {
} else if (temperature >= 30) {
} else {
}

switch

switch (mode) {
case 0:
    break;

case 1:
    break;

default:
    break;
}

for

for (int i = 0; i < 10; i++) {
}
for ( 初期化 ; 継続条件 ; 更新 )
        ↓         ↓        ↓
    int i = 0   i < 10     i++

while

while (condition) {
}

マイコンでの注意

無限ループはマイコンでは珍しくない。

while (true) {
}

ただしArduinoのloop()自体が繰り返し呼ばれるため、通常はloop()を利用する。loop()の中で長時間止まり続けると、他の処理が一切動かなくなる点に注意する。

動かして確かめる

演習に入る前に、まずこのサンプルを動かして結果を見る。追加の部品は要らない。光るのはボードに載っている内蔵LEDで、それ以外はシリアルモニタの出力で確かめられる。code/examples/02-control/を開き、pio run -t uploadで書き込んでからpio device monitorで出力を見る(手順と、外付けのLEDなどをつなぐ場合は開発環境にまとめてある)。

code/examples/02-control/src/main.cpp(抜粋)
/**
 * @brief 温度から警報の段階を決める
 * @details 上から順に評価されるため、条件の順番に意味がある。
 * @param temperature 温度(℃)
 * @return 0=normal, 1=warning, 2=danger
 */
int alarmLevel(float temperature) {
    if (temperature >= 40.0f) {
        return 2;
    } else if (temperature >= 30.0f) {
        return 1;
    } else {
        return 0;
    }
}

/**
 * @brief 警報の段階を文字列で表示する
 * @param level 警報の段階(0〜2)
 */
void printLevel(int level) {
    switch (level) {
    case 0:
        Serial.println("normal");
        break;

    case 1:
        Serial.println("warning");
        break;

    case 2:
        Serial.println("danger");
        break;

    default:
        Serial.println("unknown");
        break;
    }
}

/**
 * @brief 内蔵LEDを指定回数点滅させる
 * @param times 点滅回数
 */
void blink(int times) {
    for (int i = 0; i < times; i++) {
        digitalWrite(LED_BUILTIN, HIGH);
        delay(BLINK_MS);

        digitalWrite(LED_BUILTIN, LOW);
        delay(BLINK_MS);
    }
}
同じファイルの loop()
void loop() {
    // 温度を 25.0 から 5.0 ずつ上げていき、分岐が切り替わる点を見る
    static float temperature = 25.0f;

    int level = alarmLevel(temperature);

    Serial.print(temperature);
    Serial.print(" -> ");
    printLevel(level);

    // 段階と同じ回数だけ点滅させる(normal のときは光らない)
    blink(level);

    temperature += 5.0f;
    if (temperature > 45.0f) {
        temperature = 25.0f;
    }

    delay(1000);
}
シリアルモニタの出力
--- for ---
0 1 2 3 4 5 6 7 8 9
--- while ---
3
2
1
--- if / else if / switch ---
25.00 -> normal
30.00 -> warning
35.00 -> warning
40.00 -> danger
45.00 -> danger
25.00 -> normal

確かめること。

  • 25.00はnormal、30.00はwarning、40.00はdangerになっている
  • alarmLevel()の>= 40.0fと>= 30.0fを入れ替えると、dangerが一度も出なくなる。条件の順番に意味がある
  • printLevel()のbreakを1つ消すと、次のcaseへ流れ込む(フォールスルー)
  • LEDの点滅回数が段階と同じ回数になっている。normalのときは光らない

演習

  • 0〜9をシリアル出力する
  • LEDを一定回数点滅させる
  • ボタンが押されている間だけLEDを点灯する

3つ目はloop()とifの組み合わせで書ける。whileで待ち続けないほうがよい理由も一緒に考えるさせる。