Menu
CoddyTech

ボタンでモードを切り替える

CoddyのArduinoジャーニー「delayを使わないタイミング制御」セクションの一部。レッスン 11/18。

多くのガジェットには、押すたびにモードが切り替わるボタンが1つあります。自転車のライトなら、消灯、点灯、点滅、高速点滅、そして再び消灯と切り替わります。これは、時計ではなくボタンを押すことで次の状態に移る状態機械です。

切り替え処理を独立した関数にします。現在のモードに対するswitchで次のモードを設定し、最後のモードから最初のモードに戻します。

void nextMode() {
  switch (mode) {
    case OFF:
      mode = ON;
      Serial.println("ON");
      break;
    // ... 以下同様に続き、FAST から OFF に戻るまで
  }
}

スケッチはボタンを押すたびにnextMode()を1回呼び出します。ボタンのチャタリング除去は、Inputsセクションで学んだ方法で行います。読み取り値が変化したら処理し、その後、接点が安定するまで20 ms待ちます。modeに対する2つ目のswitchでLEDを設定します。

challenge icon

チャレンジ

中級

ボタンとLEDのコードは用意されています。ボタンを押すたびに次のモードに切り替わり、その名前を出力するようにnextMode()を作成してください。順番はOFF、ON、BLINK、FASTで、その後は再びOFFになります。

Runを押し、ボタンを数回押してから、Checkを押してください。

自分で試してみよう

const int ledPin = 13;
const int buttonPin = 2;

enum Mode { OFF, ON, BLINK, FAST };
Mode mode = OFF;

bool wasPressed = false;
unsigned long blinkPrevious = 0;
int ledState = LOW;

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
  Serial.begin(9600);
}

// 次のモードに切り替え、その名前を出力する。
void nextMode() {
  // 各モードに1つのcaseを設ける:次のモードを設定し、名前を出力して、breakする
}

// interval msごとにLEDの点灯状態を切り替える。
void blinkEvery(unsigned long interval) {
  unsigned long now = millis();
  if (now - blinkPrevious >= interval) {
    blinkPrevious = now;
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }
    digitalWrite(ledPin, ledState);
  }
}

void loop() {
  // 1. チャタリング対策済みのボタン押下でnextMode()を呼び出す
  bool pressed = digitalRead(buttonPin) == LOW;
  if (pressed != wasPressed) {
    if (pressed) {
      nextMode();
    }
    wasPressed = pressed;
    delay(20);   // 接点が安定するのを待つ
  }

  // 2. モードによってLEDの動作が決まる
  switch (mode) {
    case OFF:
      digitalWrite(ledPin, LOW);
      break;
    case ON:
      digitalWrite(ledPin, HIGH);
      break;
    case BLINK:
      blinkEvery(500);
      break;
    case FAST:
      blinkEvery(100);
      break;
  }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

delayを使わないタイミング制御のすべてのレッスン

自分で練習してみよう: Arduinoプレイグラウンド