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
まずは回路図です。
何度も見たことのある L チカの基本的な回路ですが、LED は 2 つあります。
この 2 つの LED をサンプル例の Blink で L チカさせるのは、ちょっと難しいですね。片方を点滅させるときに delay() を使いますから、他方はその間、止まってしまいます。
そこで利用するのが、前回やったステートマシン。これを複数、組み合わせてみます。
独立した 2 つ目のステートマシンを作って、2 つの LED をそれぞれ異なる時間で点滅させるようにしたスケッチです。
今回も、コピーアンドペーストするだけじゃ身につかないので、自分なりに書き直しています。
- // Now for two at once
- const bool LED_ON = HIGH;
- const bool LED_OFF = LOW;
- const byte ledPin1 = 12;
- const unsigned long onTime1 = 250; // LED1 on time (ms)
- const unsigned long offTime1 = 750; // LED1 off time (ms)
- const byte ledPin2 = 13;
- const unsigned long onTime2 = 330; // LED2 on time (ms)
- const unsigned long offTime2 = 400; // LED2 off time (ms)
- void setup() {
- pinMode(ledPin1, OUTPUT);
- pinMode(ledPin2, OUTPUT);
- }
- void loop() {
- static bool ledState1 = LED_OFF;
- static unsigned long previousMillis1 = 0;
- static bool ledState2 = LED_OFF;
- static unsigned long previousMillis2 = 0;
- unsigned long currentMillis = millis();
- if ((LED_ON == ledState1) && (onTime1 <= currentMillis - previousMillis1)) {
- ledState1 = LED_OFF;
- previousMillis1 = currentMillis;
- digitalWrite(ledPin1, ledState1);
- }
- else if ((LED_OFF == ledState1) && (offTime1 <= currentMillis - previousMillis1)) {
- ledState1 = LED_ON;
- previousMillis1 = currentMillis;
- digitalWrite(ledPin1, ledState1);
- }
- if ((LED_ON == ledState2) && (onTime2 <= currentMillis - previousMillis2)) {
- ledState2 = LED_OFF;
- previousMillis2 = currentMillis;
- digitalWrite(ledPin2, ledState2);
- }
- else if ((LED_OFF == ledState2) && (offTime2 <= currentMillis - previousMillis2)) {
- ledState2 = LED_ON;
- previousMillis2 = currentMillis;
- digitalWrite(ledPin2, ledState2);
- }
- }
簡単ですね。
前回作ったスケッチ 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
やってみましょう。
回路図です。
3 番目の LED を追加しました。
スケッチは、2 つ目のステートマシンを追加したときと同じ手順です。コピーアンドペーストして、変数名を修正して……
えーと、そんなねぇ、俺はもう、そこまで初心者じゃないかもしれない (^_^;)
ステートマシンを関数にしてしまえばいいじゃん。4 番目だって簡単に増やせるぞ。
- // Now for three at once
- const bool LED_ON = HIGH;
- const bool LED_OFF = LOW;
- const byte ledPin[] = {11, 12, 13};
- const byte numberOfLed = sizeof(ledPin) / sizeof(ledPin[0]);
- unsigned long onTime[numberOfLed];
- unsigned long offTime[numberOfLed];
- unsigned long previousMillis[numberOfLed] = {0};
- bool ledState[numberOfLed] = {LED_OFF};
- void setup() {
- for (byte i = 0; i < numberOfLed; i++) {
- pinMode(ledPin[i], OUTPUT);
- }
- onTime[0] = 250; // LED0 on time (ms)
- offTime[0] = 750; // LED0 off time (ms)
- onTime[1] = 330; // LED1 on time (ms)
- offTime[1] = 400; // LED1 off time (ms)
- onTime[2] = 550; // LED2 on time (ms)
- offTime[2] = 270; // LED2 off time (ms)
- }
- void loop() {
- static byte i = 0;
- ledFlash(i);
- if (numberOfLed <= ++i) i = 0;
- }
- void ledFlash(byte n) {
- unsigned long currentMillis = millis();
- if ((LED_ON == ledState[n]) && (onTime[n] <= currentMillis - previousMillis[n])) {
- ledState[n] = LED_OFF;
- previousMillis[n] = currentMillis;
- digitalWrite(ledPin[n], ledState[n]);
- }
- else if ((LED_OFF == ledState[n]) && (offTime[n] <= currentMillis - previousMillis[n])) {
- ledState[n] = LED_ON;
- previousMillis[n] = currentMillis;
- digitalWrite(ledPin[n], ledState[n]);
- }
- }
これでどうよ? 意図したとおりに動いてくれるよ。
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
だよね。
ということで、今回は複数のステートマシンを使って、簡単なマルチタスクを実行してみました。
次は「より単純でより効率的なプログラミング手法」を学んでみましょう。