第34回 チャレンジ課題2

今まで習得した知識を使ってチャレンジ課題に挑戦してみましょう!

目次

チャレンジ課題

2つの課題を用意してみました。今までの知識を使ってチャレンジしてみてください!

チャレンジ課題2-1

前回の記事で作成したしたタイマーのスケッチは、残り時間が3分の2になるまで緑色のLEDのみ点灯、3分の2から3分の1までの間は黄色LEDのみ点灯、残りの3分の1の間は赤色LEDのみ点灯しています。

このLED制御を、次のように変更してみてください。

  1. スイッチが押されてタイマーが開始したら、緑色LED、黄色LED、赤色LEDを全て点灯する
  2. 残り時間が3分の2になったら、緑色LEDを消す。
    つまり黄色LEDと赤色LEDが点灯している状態になる
  3. 残り時間が3分の1になったら、黄色LEDを消す。
    つまり赤色LEDのみが点灯している状態になる

チャレンジ課題2-2

この課題は、前の課題のスケッチをさらに変更してみてください。(前回の記事のスケッチを変更しても構いません)

タイマー時間が残り5秒になったら、赤色LEDも青色LEDと同じように点滅させてください。

タイマーがカウントダウンしている間は、青色LEDが1秒間に1回「ピカッ」と光るようにしています。

この動作に加えて、残り時間が5秒以下になったら、青色LEDと同じタイミングで赤色LEDも「ピカッ」と光らせてください

このように赤色LEDを点滅して目立たせることにより、「もう時間ですよ」という表現をしたいと思います。

この課題について

この課題は今までの知識を使って実装することができますが、もう少しわかりやすい書き方があります。この課題と同じ内容のスケッチを、別の書き方にするミニチャレンジ課題を次回の記事に掲載してあります。ぜひ次回の記事も参考にしてみてください。

チャレンジ課題解答例

これが唯一の正解というわけではありません。動けばOKです!

チャレンジ課題2-1解答例

変更は次の3ヶ所です。

  • タイマー開始時に残り時間LEDをすべて点灯する
  • 残り時間が3分の2のタイミングで、緑色LEDのみ消す
  • 残り時間が3分の2のタイミングで、黄色LEDのみ消す

スケッチは次のよう変更してみました。

/*
  チャレンジ課題2-1解答例
  内容: 残り時間LEDの点灯制御を変更する
*/


// 秒を表現するLED関連の定義
#define BYOU_LED 12  // 秒を表現するLEDの接続端子
#define BYOU_ON  50 // 秒を表現するLEDを点灯している時間(単位:ミリ秒)
#define BYOU_OFF (1000 - BYOU_ON) // 秒を表現するLEDを消している時間(単位:ミリ秒)

// 残り時間を表現するLED関連(緑色、黄色、赤色LED)
#define LED_MIDORI 8 // 緑色LEDの端子番号
#define LED_KIIRO  6 // 黄色LEDの端子番号
#define LED_AKA    4 // 赤色LEDの端子番号

// タイマースタートスイッチ関連の定義
#define SWITCH A5 // スイッチを接続している端子名
#define SWITCH_OFF 1 // スイッチOFFの時のdigitalReadの値
#define SWITCH_ON  0 // スイッチONの時のdigitalReadの値

// タイマー時間設定(LEDの点滅回数)
#define TIMER_JIKAN 30

// 残り時間を表現するLEDの制御時間
#define KIIRO_JIKAN 10  // 残り時間3分の2
#define AKA_JIKAN   20  // 残り時間3分の1

// アラーム音関連
#define SPEAKER A0  // スピーカーの端子番号
#define ALARM   880 // アラーム音の音程

void setup() {
  // 端子の設定
  // スピーカー接続端子はtoneの指示で自動的に出力設定になるので設定していません
  pinMode(BYOU_LED,   OUTPUT); // 秒表現のLED接続端子の出力設定
  pinMode(SWITCH,     INPUT_PULLUP); // スイッチ接続端子をプルアップ設定
  pinMode(LED_MIDORI, OUTPUT); // 緑色LED接続端子設定
  pinMode(LED_KIIRO,  OUTPUT); // 緑色LED接続端子設定
  pinMode(LED_AKA,    OUTPUT); // 緑色LED接続端子設定

  // 秒のLED(青色LED)を点灯する
  digitalWrite(BYOU_LED, HIGH);

  // スイッチが押されるまで何もしないで待つ
  while( digitalRead(SWITCH) == SWITCH_OFF ) {
  }

  // タイマー開始時に残り時間LEDを全て点灯する
  digitalWrite(LED_MIDORI, HIGH);
  digitalWrite(LED_KIIRO,  HIGH);
  digitalWrite(LED_AKA,    HIGH);
}

void loop() {

  // TIMER_JIKAN分の回数を数える
  for(uint8_t count=0;  count<TIMER_JIKAN; count++) {

    // 残り時間が3分の2のとき、緑色をOFFにする(黄色と赤色LEDは変更しない)
    if( count == KIIRO_JIKAN ) {
      digitalWrite(LED_MIDORI, LOW);
    }

    // 残り時間が3分の1のとき、黄色をOFFにする(赤色LEDは変更しない)
    if( count == AKA_JIKAN ){
      digitalWrite(LED_KIIRO, LOW);
    }

    // 1秒に1回青色LEDを点滅する
    digitalWrite(BYOU_LED, HIGH);
    delay(BYOU_ON);
    digitalWrite(BYOU_LED, LOW);
    delay(BYOU_OFF);
  }

  // 時間になったので秒のLED(青色LED)を点灯する
  digitalWrite(BYOU_LED, HIGH);

  // アラーム音を3回鳴らす
  for(uint8_t count=0; count<3; count++) {
    // ピ
    tone(SPEAKER, ALARM);
    delay(60);
    noTone(SPEAKER);
    delay(60);

    // ピ
    tone(SPEAKER, ALARM);
    delay(60);
    noTone(SPEAKER);
    delay(60);

    // ピーッ
    tone(SPEAKER, ALARM);
    delay(100);
    noTone(SPEAKER);
    delay(600);

  }
  // 何もしないで待つ
  while( true ) {
  }

}

チャレンジ課題2-2解答例

タイマーの時間計測は変数countで行っています。このcount経過時間を意味しています

やりたいことは「残り時間が5秒以下になったら」赤色LEDも点滅処理をすることです。

スケッチでは変数countの値に応じて、赤色LEDを点滅するかしないか判断する必要があります。

判断したい条件は「残り時間」ですが、countは「経過時間」ですので、countと残り時間を直接比較することはできません。例えば「残り時間が5秒以下」という条件はcount <= 5ではありません。

ちょっとややこしいので具体例で考えてみます。(プログラミングでややこしい状況になったら、まずは具体例で考えてみると見通しが良くなることが多いです)

例えば30秒タイマーの場合、「残り時間が5秒以下になったら」というのは「経過時間が25秒以上なったら」ということになります。

「25秒」というのは、「タイマー時間30秒から5秒を引いた値」ですよね。

つまり、「残り時間が5秒以下になったら」というのは「経過時間が(タイマー時間 − 5秒以上になったら」ということになります。

これを変数countを使って考えると、「countが(タイマー時間 − 5秒)以上になったら」ということになります。


この考え方をもとに、スケッチの方針を考えてみます。

まず、スケッチの最初で「(タイマー時間 − 5秒)」を定義しておくことにします。タイマー時間はTIMER_JIKANで定義済みですので、次のように「(タイマー時間 − 5秒)」を新しく定義します。

// 赤色LEDを点滅する時間
#define TENMETSU_JIKAN (TIMER_JIKAN - 5)

次に、青色LEDを点灯するところで、countTENMETSU_JIKAN以上であれば赤色LEDも一緒に点灯します。

// 青色LEDを点灯するところで、
// もしcountがTENMETSU_JIKAN以上であれば赤色LEDも一緒に点灯する
if( count >= TENMETSU_JIKAN {
  digitalWrite(BYOU_LED, HIGH);
  if( count >= TENMETSU_JIKAN ) {
    digitalWrite(LED_AKA, HIGH);
  }
}

同様に、青色LEDを消すところで、countがTENMETSU_JIKAN以上であれば赤色LEDも一緒に消します。

// 青色LEDを消すところで、
// もしcountがTENMETSU_JIKAN以上であれば赤色LEDも一緒に消す
if( count >= TENMETSU_JIKAN {
  digitalWrite(BYOU_LED, LOW);
  if( count >= TENMETSU_JIKAN ) {
    digitalWrite(LED_AKA, LOW);
  }
}

この処理をスケッチに追加すれば大丈夫そうです。

次のスケッチは今までの内容をまとめたものです。

/*
  チャレンジ課題2-2解答例
  内容: 残り時間が一定時間以下になったら、赤色LEDも「ピカっ」と点滅する
*/


// 秒を表現するLED関連の定義
#define BYOU_LED 12  // 秒を表現するLEDの接続端子
#define BYOU_ON  50 // 秒を表現するLEDを点灯している時間(単位:ミリ秒)
#define BYOU_OFF (1000 - BYOU_ON) // 秒を表現するLEDを消している時間(単位:ミリ秒)

// 残り時間を表現するLED関連(緑色、黄色、赤色LED)
#define LED_MIDORI 8 // 緑色LEDの端子番号
#define LED_KIIRO  6 // 黄色LEDの端子番号
#define LED_AKA    4 // 赤色LEDの端子番号

// タイマースタートスイッチ関連の定義
#define SWITCH A5 // スイッチを接続している端子名
#define SWITCH_OFF 1 // スイッチOFFの時のdigitalReadの値
#define SWITCH_ON  0 // スイッチONの時のdigitalReadの値

// タイマー時間設定(LEDの点滅回数)
#define TIMER_JIKAN 30

// 残り時間を表現するLEDの制御時間
#define KIIRO_JIKAN 10  // 残り時間3分の2
#define AKA_JIKAN   20  // 残り時間3分の1

// 赤色LEDを点滅する時間
// 残り時間が5秒なので、経過時間は(TIMER_JIKAN-5)で計算する
// 赤色LEDは、この経過時間以上になったら点滅処理をすることにする
#define TENMETSU_JIKAN (TIMER_JIKAN - 5)

// アラーム音関連
#define SPEAKER A0  // スピーカーの端子番号
#define ALARM   880 // アラーム音の音程

void setup() {
  // 端子の設定
  // スピーカー接続端子はtoneの指示で自動的に出力設定になるので設定していません
  pinMode(BYOU_LED,   OUTPUT); // 秒表現のLED接続端子の出力設定
  pinMode(SWITCH,     INPUT_PULLUP); // スイッチ接続端子をプルアップ設定
  pinMode(LED_MIDORI, OUTPUT); // 緑色LED接続端子設定
  pinMode(LED_KIIRO,  OUTPUT); // 緑色LED接続端子設定
  pinMode(LED_AKA,    OUTPUT); // 緑色LED接続端子設定

  // 秒のLED(青色LED)を点灯する
  digitalWrite(BYOU_LED, HIGH);

  // スイッチが押されるまで何もしないで待つ
  while( digitalRead(SWITCH) == SWITCH_OFF ) {
  }

  // タイマー開始時に残り時間LEDを全て点灯する
  digitalWrite(LED_MIDORI, HIGH);
  digitalWrite(LED_KIIRO,  HIGH);
  digitalWrite(LED_AKA,    HIGH);
}

void loop() {

  // TIMER_JIKAN分の回数を数える
  for(uint8_t count=0;  count<TIMER_JIKAN; count++) {

    // 残り時間が3分の2のとき、緑色をOFFにする(黄色と赤色LEDは変更しない)
    if( count == KIIRO_JIKAN ) {
      digitalWrite(LED_MIDORI, LOW);
    }

    // 残り時間が3分の1のとき、黄色をOFFにする(赤色LEDは変更しない)
    if( count == AKA_JIKAN ){
      digitalWrite(LED_KIIRO, LOW);
    }

    // 1秒に1回青色LEDを点滅する
    // 残り時間が少なくなったら赤色LEDも青色LEDと同じように点滅する
    // 

    // 点灯する処理
    // 残り時間が少なくなったら赤色LEDも制御
    digitalWrite(BYOU_LED, HIGH);
    if( count >= TENMETSU_JIKAN ) {
      digitalWrite(LED_AKA, HIGH);
    }

    // 点灯する時間分待つ
    delay(BYOU_ON);

    // 消す処理
    // 残り時間が少なくなったら赤色LEDも制御
    digitalWrite(BYOU_LED, LOW);
    if( count >= TENMETSU_JIKAN ) {
      digitalWrite(LED_AKA, LOW);
    }

    // 消す時間分待つ
    delay(BYOU_OFF);
  }

  // 時間になったので秒のLED(青色LED)を点灯する
  digitalWrite(BYOU_LED, HIGH);

  // アラーム音を3回鳴らす
  for(uint8_t count=0; count<3; count++) {
    // ピ
    tone(SPEAKER, ALARM);
    delay(60);
    noTone(SPEAKER);
    delay(60);

    // ピ
    tone(SPEAKER, ALARM);
    delay(60);
    noTone(SPEAKER);
    delay(60);

    // ピーッ
    tone(SPEAKER, ALARM);
    delay(100);
    noTone(SPEAKER);
    delay(600);

  }
  // 何もしないで待つ
  while( true ) {
  }

}

更新履歴

日付内容
2019.10.13新規投稿
2021.8.27新サイトデザイン対応
2024.12.16課題内容変更
解答例追加
通知の設定
通知タイミング
guest
0 コメント
新しい準
古い順 一番投票が多い
本文中にフィードバック
全てのコメントを見る
目次