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がないと、ボタンを押した後も永遠に待ち続けることがあります。
チャレンジ
簡単このスケッチは、ボタンが押されるまで待ってから、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);
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
delayを使わないタイミング制御のすべてのレッスン
自分で練習してみよう: Arduinoプレイグラウンド