Menu
CoddyTech

volatileによる共有

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

ISRではすばやく1つの処理を行うべきなので、通常はスケッチの残りの部分が読み取る変数を設定します。両方で使う変数はvolatileとして宣言する必要があります。

volatile bool started = false;

void onPress() {
  started = true;
}

時間を節約するため、コンパイラー(C++をチップの命令に変換するプログラム)は、メモリーを読み取る代わりに、変数のコピーをプロセッサー内に保持することがあります。割り込みによって変数が変更されることを認識できないため、スケッチは古いコピーをいつまでも使い続ける可能性があります。volatileを指定すると、毎回変数を読み直すようになります。

このスケッチは、whileループを使ってsetup()内で待機します。while (condition) { }は、条件が真である限り波かっこの中身を繰り返します。ここでの条件は!startedです。Inputsセクションで説明したように、!は「〜でない」という意味です。つまり、startedが偽である間、ループが繰り返されます。volatileがないと、ボタンを押した後も永遠に待ち続けることがあります。

challenge icon

チャレンジ

簡単

このスケッチは、ボタンが押されるまで待ってから、LEDを点滅させるはずです。現状ではいつまでも待ち続けます。修正してください:

  • onPress()内で、startedをtrueに設定する
  • startedをvolatileとして宣言する

Runを押し、ボタンを押してから、Checkを押してください。volatileを使わずに一度試して、ボードが動かなくなる様子を確認してください。

自分で試してみよう

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

bool started = false;   // 割り込みによって設定され、スケッチによって読み取られる

unsigned long previousMillis = 0;
int ledState = LOW;

void onPress() {
  // ここで started を true に設定する
}

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(buttonPin), onPress, FALLING);

  // ボタンが押されるまでここで待つ
  while (!started) {
  }
}

void loop() {
  // 250 ms ごとに点滅させる
  unsigned long now = millis();
  if (now - previousMillis >= 250) {
    previousMillis = now;
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }
    digitalWrite(ledPin, ledState);
  }
}
quiz icon腕試し

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

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

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