- マルチタスクとは何ですか?
- Arduinoでdelay()をスキップするのはなぜですか?
- なぜmillis()を使用するのですか?
- 必要なコンポーネント
- 回路図
- マルチタスク用のArduinoUNOのプログラミング
マルチタスクは、効率性、柔軟性、適応性と生産性を向上させる1つまたは複数のプログラムを同時に実行することができます革命にコンピュータをリードしてきました。組み込みシステムでは、マイクロコントローラーはマルチタスクを処理し、現在の命令を停止することなく2つ以上のタスクを同時に実行することもできます。
このチュートリアルでは、 ArduinoがArduinoミリ関数を使用してマルチタスクを実行する方法を学習します。一般に、 delay() 関数はLEDの点滅などの定期的なタスクのためにArduinoで使用されますが、このdelay()関数はプログラムを一定時間停止し、他の操作を実行できません。したがって、この記事では、delay()関数の使用を回避し、それをmillis()に置き換えて、複数のタスクを同時に実行し、Arduinoをマルチタスクコントローラーにする方法について説明します。詳細に入る前に、マルチタスクを控えめにすることから始めましょう。
マルチタスクとは何ですか?
マルチタスクとは、単に複数のタスクまたはプログラムを同時に実行することを意味します。ほとんどすべてのオペレーティングシステムはマルチタスクを備えています。この種のオペレーティングシステムは、MOS(マルチタスクオペレーティングシステム)として知られています。 MOSは、モバイルまたはデスクトップPCオペレーティングシステムにすることができます。コンピューターでのマルチタスクの良い例は、ユーザーが電子メールアプリケーション、インターネットブラウザー、メディアプレーヤー、ゲームを同時に実行し、ユーザーがアプリケーションを使用したくない場合は、閉じていない場合はバックグラウンドで実行することです。エンドユーザーはこれらすべてのアプリケーションを同時に使用しますが、OSはこの概念を少し異なります。 OSがマルチタスクを管理する方法について説明しましょう。
写真に見られるように、CPUは時間を3つの等しい部分に分割し、各部分を各タスク/アプリケーションに割り当てます。これは、ほとんどのシステムでマルチタスクが実行される方法です。概念は、時間分布が少し異なることを除いて、Arduinoマルチタスクでもほぼ同じです。Arduinoはラップトップ/モバイル/ PCと比較して低周波数とRAMで実行されるため、各タスクに与えられる時間も異なります。Arduinoには、広く使用されている delay() 関数もあります。しかし、始める前に、どのプロジェクトでも delay() 関数を使用すべきではない理由について説明しましょう。
Arduinoでdelay()をスキップするのはなぜですか?
Arduinoのリファレンスドキュメントを検討すると、2種類の遅延関数があります。1つ目はdelay()で、2つ目はdelayMicroseconds()です。両方の機能は、遅延の生成に関して同じです。唯一の違いは、delay()関数では、渡されるパラメーター整数がミリ秒単位であるということです。つまり、delay(1000)と書くと、遅延は1000ミリ秒、つまり1秒になります。同様に、delayMicroseconds()関数では、渡されるパラメーターはマイクロ秒単位です。つまり、delayMicroseconds(1000)と書くと、遅延は1000マイクロ秒(1ミリ秒)になります。
ここでポイントが来ます。両方の関数は、遅延関数で渡された時間の間、プログラムを一時停止します。したがって、1秒の遅延を与えると、プロセッサは1秒が経過するまで次の命令に進むことができません。同様に、遅延が10秒の場合、プログラムは10秒間停止し、プロセッサは10秒が経過するまで次の命令に進むことを許可しません。これは、速度と命令の実行に関してマイクロコントローラのパフォーマンスを妨げます。
遅延機能の欠点を説明する最良の例は、2つのプッシュボタンを使用することです。2つのプッシュボタンを使用して2つのLEDを切り替えたいとします。したがって、1つのプッシュボタンを押すと、対応するLEDが2秒間点灯します。同様に、2番目を押すと、LEDが4秒間点灯します。しかし、delay()を使用する場合、ユーザーが最初のボタンを押すとプログラムは2秒間停止し、ユーザーが2秒の遅延の前に2番目のボタンを押すと、マイクロコントローラーはプログラムのように入力を受け入れません。停止段階にあります。
Arduinoの公式ドキュメントでは、delay()関数の説明の注記と警告にこれが明確に記載されています。あなたはそれをより明確にするためにこれを通り抜けてチェックすることができます。
なぜmillis()を使用するのですか?
遅延の使用によって引き起こされる問題を克服するために、開発者は、習慣になったら使いやすく、命令の実行に遅延を発生させることなく100%のCPUパフォーマンスを使用する millis() 関数を使用する必要があります。mills()は、Arduinoボードがプログラムをフリーズせずに現在のプログラムの実行を開始してから経過したミリ秒数を返す関数です。この時間数は、約50日後にオーバーフローします(つまり、ゼロに戻ります)。
ArduinoにdelayMicroseconds()があるのと同じように、micros()としてmillis()のマイクロバージョンもあります。microsとmillisの違いは、micros()が50日であるのに対し、micros()は約70分後にオーバーフローすることです。したがって、アプリケーションに応じて、millis()またはmicros()を使用できます。
delay()の代わりにmillis()を使用する:
タイミングと遅延にmillis()を使用するには、アクションが発生した時間を記録して保存し、時間を開始してから、定義された時間が経過したかどうかを定期的に確認する必要があります。したがって、前述のように、現在の時刻を変数に格納します。
unsigned long currentMillis = millis();
必要な時間が経過したかどうかを確認するには、さらに2つの変数が必要です。現在の時刻を currentMillis 変数に格納しましたが、タイミング期間がいつ開始され、期間がどのくらいかを知る必要もあります。したがって、Intervalと previousMillis が宣言されます。間隔は時間遅延を示し、previosMillisはイベントが最後に発生した時間を保存します。
unsigned long previousMillis; unsigned long period = 1000;
これを理解するために、単純なLEDの点滅の例を見てみましょう。周期= 1000は、LEDが1秒間または1000ms点滅することを示します。
const int ledPin = 4; //接続されているLEDピン番号 intledState = LOW; // LEDの状態を unsignedlong previousMillis = 0 に設定するために使用されます。 // LEDが最後に点滅した時刻を保存しますconstlong period = 1000; //ミリ秒単位で点滅する期間 voidsetup(){ pinMode(ledPin、OUTPUT); // ledpinを出力として設定 } void loop(){ unsigned long currentMillis = mills(); //現在の時刻を保存します if(currentMillis --previousMillis> = period){// 1000msが previousMillis = currentMillisを 通過したかどうかを確認します; //最後にLEDを点滅させた時間を保存しますif(ledState == LOW){// LEDがオフの場合はオンにし、その逆の場合は ledState = HIGH; } else { ledState = LOW; } digitalWrite(ledPin、ledState); // ledStateでLEDを再び点滅するように設定 } }
ここで、ステートメント
Arduinoの割り込みは、他のマイクロコントローラーと同じように機能します。Arduino UNOボードには、GPIOピン2と3に割り込みを接続するための2つの別々のピンが あります。割り込みとその使用方法の詳細については、Arduino割り込みチュートリアルで詳しく説明しました。
ここでは、2つのタスクを同時に処理することによるArduinoマルチタスクを示します。タスクには、LEDのオン/オフ状態を制御するために使用されるプッシュボタンとともに、異なる時間遅延で2つのLEDを点滅させることが含まれます。したがって、3つのタスクが同時に実行されます。
必要なコンポーネント
- Arduino UNO
- 3つのLED(任意の色)
- 抵抗(470、10k)
- ジャンパー
- ブレッドボード
回路図
Arduino Millis()関数の使用法を示すための回路図 は非常に簡単で、以下に示すように接続するコンポーネントがあまりありません。
マルチタスク用のArduinoUNOのプログラミング
マルチタスク用にArduinoUNOをプログラミングするには、上記で説明したmillis()の動作の背後にあるロジックのみが必要です。マルチタスク用のArduinoUNOのプログラムを開始する前に、ロジックを明確にし、millis()に慣れるために、 ミリ秒 を使用してLEDの点滅を 何 度も練習することをお勧めし ます。このチュートリアルでは、割り込みはマルチタスクのためにmillis()と同時に使用されます。 ボタンは割り込みになります。したがって、割り込みが生成されると、つまりプッシュボタンが押されると、LEDはオンまたはオフの状態に切り替わります。プログラミングは、LEDとプッシュボタンが接続されているピン番号を宣言することから始まります。
int led1 = 6; int led2 = 7; int tokenLed = 5; int pushButton = 2;
次に、将来使用するためにLEDのステータスを格納する変数を記述します。
int ledState1 = LOW; int ledState2 = LOW;
上記のまばたきの例で説明したように、periodとpreviousmillisの変数は、LEDの遅延を比較して生成するように宣言されています。最初のLEDは1秒ごとに点滅し、別のLEDは200ms後に点滅します。
unsigned long previousMillis1 = 0; const long period1 = 1000; unsigned long previousMillis2 = 0; const long period2 = 200;
別のミリ関数を使用してデバウンス遅延を生成し、プッシュボタンが複数回押されるのを防ぎます。上記と同様のアプローチがあります。
int debouncePeriod = 20; int debounceMillis = 0;
三つの変数は、割り込みとして押しボタンの状態を格納するために使用されるLEDおよび押しボタンの状態トグル、。
bool buttonPushed = false; int ledChange = LOW; int lastState = HIGH;
どのピンがINPUTまたはOUTPUTとして機能するかというピンのアクションを定義します。
pinMode(led1、OUTPUT); pinMode(led2、OUTPUT); pinMode(toggleLed、OUTPUT); pinMode(pushButton、INPUT);
次に、ISRと割り込みモードの定義で割り込みをアタッチして割り込みピンを定義します。 attachInterrupt() 関数を宣言して実際のデジタルピンを特定の割り込み番号に変換する場合は、 digitalPinToInterrupt(pin_number) を使用することをお勧めします。
attachInterrupt(digitalPinToInterrupt(pushButton)、pushButton_ISR、CHANGE);
割り込みサブルーチンが作成され、buttonPushedフラグのみが変更されます。割り込みサブルーチンはできるだけ短くする必要があることに注意してください。そのため、割り込みサブルーチンを記述して、余分な命令を最小限に抑えるようにしてください。
void pushButton_ISR() { buttonPushed = true; }
ループは、ミリ秒の値をcurrentMillis変数に格納することから始まります。この変数は、ループが繰り返されるたびに経過した時間の値を格納します。
unsigned long currentMillis = millis();
マルチタスクには全部で3つの機能があります。1秒で1つのLEDを点滅させ、200msで2番目のLEDを点滅させ、押しボタンが押されたらオフ/オンLEDを切り替えます。したがって、このタスクを実行するために3つの部分を記述します。
最初は、経過ミリ秒を比較することにより、毎1秒後の状態をLEDのトグルです。
if(currentMillis-previousMillis1> = period1){ previousMillis1 = currentMillis; if(ledState1 == LOW){ ledState1 = HIGH; } else { ledState1 = LOW; } digitalWrite(led1、ledState1); }
同様に、2番目に、経過したミリ秒を比較することにより、200ミリ秒ごとにLEDを切り替えます。この説明は、この記事の前半ですでに説明されています。
if(currentMillis-previousMillis2> = period2){ previousMillis2 = currentMillis; if(ledState2 == LOW){ ledState2 = HIGH; } else { ledState2 = LOW; } digitalWrite(led2、ledState2); }
最後に、 buttonPushed フラグが監視され、 20ミリ秒の デバウンス遅延を生成した後、割り込みとして接続されたプッシュボタンに対応するLEDの状態を切り替えるだけです。
if(buttonPushed = true)// ISRが呼び出されているかどうかを確認します { if((currentMillis --debounceMillis)> debouncePeriod && buttonPushed)//複数回 押されないように20msのデバウンス遅延を生成します{ debounceMillis = currentMillis; //最後のデバウンス遅延時間を保存します if(digitalRead(pushButton)== LOW && lastState == HIGH)//プッシュボタンが押された後にLEDを変更します { ledChange =! ledChange; digitalWrite(toggleLed、ledChange); lastState = LOW; } else if(digitalRead(pushButton)== HIGH && lastState == LOW) { lastState = HIGH; } buttonPushed = false; } }
これでArduinoミリ秒()チュートリアルは終了です。 mills()を 習慣的に使用するには、他のいくつかのアプリケーションでこのロジックを実装する練習をするだけであることに注意してください。モーター、サーボモーター、センサー、その他の周辺機器を使用するように拡張することもできます。疑問がある場合は、フォーラムに書き込むか、以下にコメントしてください。
Arduinoでのミリ関数の使用法を示すための完全なコードとビデオを 以下に示します。