アフィリエイト広告
アフィリエイト広告

Arduino のマルチタスク (2) 複数のステートマシン

Arduino のマルチタスクとクラスについて、勉強中です。

Multi-tasking the Arduino - Part 1
Once you have mastered the basic blinking leds, simple sensors and buzzing motors, it’s time to move on to bigger and be...

前回は「ステートマシン」の概念について学びました。

Arduino のマルチタスク (1) ステートマシン
これまでにやってみた 7 セグメント LED のダイナミック点灯でも、トライアックによる電力制御でも、Arduino で何かをやろうと思うと、いろいろな処理を同時に進行させないといけないわけです。スケッチを書きながら、ごく自然にそんなことを...

今回は、複数のステートマシンを組み合わせて、複数の L チカを同時に実行してみましょう。

同時に 2 つを実行する

Now it is time to do some multi-tasking! First wire up another LED as in the diagram below.

https://learn.adafruit.com/multi-tasking-the-arduino-part-1/now-for-two-at-once

Now for two at once

まずは回路図です。

何度も見たことのある L チカの基本的な回路ですが、LED は 2 つあります。

この 2 つの LED をサンプル例の Blink で L チカさせるのは、ちょっと難しいですね。片方を点滅させるときに delay() を使いますから、他方はその間、止まってしまいます。

そこで利用するのが、前回やったステートマシン。これを複数、組み合わせてみます。

独立した 2 つ目のステートマシンを作って、2 つの LED をそれぞれ異なる時間で点滅させるようにしたスケッチです。
今回も、コピーアンドペーストするだけじゃ身につかないので、自分なりに書き直しています。

  1. // Now for two at once
  2. const bool LED_ON = HIGH;
  3. const bool LED_OFF = LOW;
  4. const byte ledPin1 = 12;
  5. const unsigned long onTime1 = 250; // LED1 on time (ms)
  6. const unsigned long offTime1 = 750; // LED1 off time (ms)
  7. const byte ledPin2 = 13;
  8. const unsigned long onTime2 = 330; // LED2 on time (ms)
  9. const unsigned long offTime2 = 400; // LED2 off time (ms)
  10. void setup() {
  11.   pinMode(ledPin1, OUTPUT);
  12.   pinMode(ledPin2, OUTPUT);
  13. }
  14. void loop() {
  15.   static bool ledState1 = LED_OFF;
  16.   static unsigned long previousMillis1 = 0;
  17.   static bool ledState2 = LED_OFF;
  18.   static unsigned long previousMillis2 = 0;
  19.   unsigned long currentMillis = millis();
  20.   if ((LED_ON == ledState1) && (onTime1 <= currentMillis - previousMillis1)) {
  21.     ledState1 = LED_OFF;
  22.     previousMillis1 = currentMillis;
  23.     digitalWrite(ledPin1, ledState1);
  24.   }
  25.   else if ((LED_OFF == ledState1) && (offTime1 <= currentMillis - previousMillis1)) {
  26.     ledState1 = LED_ON;
  27.     previousMillis1 = currentMillis;
  28.     digitalWrite(ledPin1, ledState1);
  29.   }
  30.   if ((LED_ON == ledState2) && (onTime2 <= currentMillis - previousMillis2)) {
  31.     ledState2 = LED_OFF;
  32.     previousMillis2 = currentMillis;
  33.     digitalWrite(ledPin2, ledState2);
  34.   }
  35.   else if ((LED_OFF == ledState2) && (offTime2 <= currentMillis - previousMillis2)) {
  36.     ledState2 = LED_ON;
  37.     previousMillis2 = currentMillis;
  38.     digitalWrite(ledPin2, ledState2);
  39.   }
  40. }

簡単ですね。
前回作ったスケッチ Flash without delay のステートマシン部分をコピーアンドペーストして、変数を修正するだけ。それぞれが、それぞれの LED を点滅させています。

演習:3 番目のステートマシンを追加せよ

As an exercise, edit the code above to add a third state machine.

https://learn.adafruit.com/multi-tasking-the-arduino-part-1/now-for-two-at-once
Now for three at once

やってみましょう。

回路図です。
3 番目の LED を追加しました。

スケッチは、2 つ目のステートマシンを追加したときと同じ手順です。コピーアンドペーストして、変数名を修正して……

えーと、そんなねぇ、俺はもう、そこまで初心者じゃないかもしれない (^_^;)
ステートマシンを関数にしてしまえばいいじゃん。4 番目だって簡単に増やせるぞ。

  1. // Now for three at once
  2. const bool LED_ON = HIGH;
  3. const bool LED_OFF = LOW;
  4. const byte ledPin[] = {11, 12, 13};
  5. const byte numberOfLed = sizeof(ledPin) / sizeof(ledPin[0]);
  6. unsigned long onTime[numberOfLed];
  7. unsigned long offTime[numberOfLed];
  8. unsigned long previousMillis[numberOfLed] = {0};
  9. bool ledState[numberOfLed] = {LED_OFF};
  10. void setup() {
  11.   for (byte i = 0; i < numberOfLed; i++) {
  12.     pinMode(ledPin[i], OUTPUT);
  13.   }
  14.   onTime[0] = 250; // LED0 on time (ms)
  15.   offTime[0] = 750; // LED0 off time (ms)
  16.   onTime[1] = 330; // LED1 on time (ms)
  17.   offTime[1] = 400; // LED1 off time (ms)
  18.   onTime[2] = 550; // LED2 on time (ms)
  19.   offTime[2] = 270; // LED2 off time (ms)
  20. }
  21. void loop() {
  22.   static byte i = 0;
  23.   ledFlash(i);
  24.   if (numberOfLed <= ++i) i = 0;
  25. }
  26. void ledFlash(byte n) {
  27.   unsigned long currentMillis = millis();
  28.   if ((LED_ON == ledState[n]) && (onTime[n] <= currentMillis - previousMillis[n])) {
  29.     ledState[n] = LED_OFF;
  30.     previousMillis[n] = currentMillis;
  31.     digitalWrite(ledPin[n], ledState[n]);
  32.   }
  33.   else if ((LED_OFF == ledState[n]) && (offTime[n] <= currentMillis - previousMillis[n])) {
  34.     ledState[n] = LED_ON;
  35.     previousMillis[n] = currentMillis;
  36.     digitalWrite(ledPin[n], ledState[n]);
  37.   }
  38. }

これでどうよ? 意図したとおりに動いてくれるよ。

loop() の中は for() 文でもいいんだけど、for() 文を実行している間は他が止まってしまうから、こんなふうにした。マルチタスクでしょ (^_^;)

It’s not very difficult to do.  But it seems rather wasteful writing the same code over and over again.  There must be a more efficient way to do this!

https://learn.adafruit.com/multi-tasking-the-arduino-part-1/now-for-two-at-once

だよね。


ということで、今回は複数のステートマシンを使って、簡単なマルチタスクを実行してみました。
次は「より単純でより効率的なプログラミング手法」を学んでみましょう。

タイトルとURLをコピーしました