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

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 better projects. That usually involves com...

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

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をコピーしました