arduino
時間管理
サーチ…
構文
unsigned long millis()
符号なしlong micros()
void遅延(符号なしlongミリ秒)
void delayMicroseconds(符号なしlongマイクロ秒)
そのクラスのコンストラクタと演算子については、elapsedMillisヘッダを参照してください。要するに:
- elapsedMillis elapsedMillisObject; オブジェクトが作成されてから、または他の明示的に設定されたある時点からの経過を追跡するオブジェクトを作成します
- elapsedMillisObject = 0; オブジェクトによって追跡された時間を「今から」にリセットする
- 符号なしlong deltaT = elapsedMillisObject; 追跡された時間を見てみましょう
- elapsedMillisObject + =と - = これらは期待通りに機能する
備考
ブロッキングコードと非ブロッキングコード
非常に簡単なスケッチでは、 delay()
とdelayMicroseconds()
を使ってブロックコードを書くことが適切です。物事が複雑になると、これらの機能を使用するといくつかの欠点が生じる可能性があります。これらのいくつかは:
- CPU時間の浪費:より複雑なスケッチでは、LED点滅の期間が終了するのを待つ間に、何かのためにCPUが必要になることがあります。
- 予期しない遅延:
delay()
が明示的に呼び出されないサブルーチン、例えばあなたがインクルードするライブラリで呼び出されたとき。 - 遅延中に発生し、割り込みハンドラによって処理されないイベントが欠落している(ポーリングされたボタンが押されたなど):ボタンが100ミリ秒間押されている可能性がありますが、
delay(500)
秒)でシャドウイングされる可能性があります。
実装の詳細
millis()
は通常、1kHzよりはるかに高い速度で動作するハードウェアタイマーに依存しています。 millis()
が呼び出されると、実装は何らかの値を返しますが、実際にどれくらいの年齢であるかはわかりません。 「現在の」ミリ秒が始まったばかりか、その関数呼び出しの直後に終了する可能性があります。つまり、 millis()
2つの結果の差を計算すると、ほぼゼロからほぼ1ミリ秒の間に何かずれてしまうことがあります。より高い精度が必要な場合は、 micros()
使用します。
elapsedMillis
のソースコードをelapsedMillis
と、実際に内部で2つの時点を比較するためにmillis()
使用されていることがmillis()
ます。そのため、この影響もあります。ここでも同じライブラリから、より精度の高い代替elapsedMicros
があります。
delay()でblinkyをブロックする
LEDを点滅させる最も単純な方法の1つは、電源を入れて少し待ってからもう一度やり直して無限に繰り返すことです:
// set constants for blinking the built-in LED at 1 Hz
#define OUTPIN LED_BUILTIN
#define PERIOD 500
void setup()
{
pinMode(OUTPIN, OUTPUT); // sets the digital pin as output
}
void loop()
{
digitalWrite(OUTPIN, HIGH); // sets the pin on
delayMicroseconds(PERIOD); // pauses for 500 miliseconds
digitalWrite(OUTPIN, LOW); // sets the pin off
delayMicroseconds(PERIOD); // pauses for 500 milliseconds
// doing other time-consuming stuff here will skew the blinking
}
しかし、上記の例のように待機するとCPUサイクルが浪費されます。なぜなら、特定の時点を過ぎるのを待っているループ内に座っているだけなのでです。これは、 millis()
またはelapsedMillis
を使用したノンブロッキングの方法が、ハードウェアの能力の多くを燃やさないという意味で、より良くなります。
elapsedMillisライブラリ(およびクラス)でノンブロッキングblinky
elapsedMillisライブラリは、作成されてから経過した時間や特定の値に設定された時間を追跡する、同じ名前のクラスを提供します。
#include <elapsedMillis.h>
#define OUTPIN LED_BUILTIN
#define PERIOD 500
elapsedMillis ledTime;
bool ledState = false;
void setup()
{
// initialize the digital pin as an output.
pinMode(OUTPIN, OUTPUT);
}
void loop()
{
if (ledTime >= PERIOD)
{
ledState = !ledState;
digitalWrite(OUTPIN, ledState);
ledTime = 0;
}
// do other stuff here
}
この例では、LEDピンがトグルされたときにledTime
オブジェクトがゼロに割り当てられていることがledTime
ます。一見するとこれは驚くべきことではないかもしれませんが、時間のかかることが起こっていると効果があります:
ledTime
とPERIOD
比較が750ミリ秒後に行われる状況を考えてみましょう。次に、 ledTime
を0に設定すると、以降のトグル操作はすべて250ミリ秒遅れることになります。対照的に、 PERIOD
をledTime
からledTime
と、LEDは1つの短い期間を見て、何も起こらないかのように点滅を続けます。
ミリ秒で点滅しないノンブロッキング()
これはarduinoのドキュメントの例に非常に近いです:
// set constants for blinking the built-in LED at 1 Hz
#define OUTPIN LED_BUILTIN
#define PERIOD 500 // this is in milliseconds
int ledState = LOW;
// millis() returns an unsigned long so we'll use that to keep track of time
unsigned long lastTime = 0;
void setup() {
// set the digital pin as output:
pinMode(OUTPIN, OUTPUT);
}
void loop() {
unsigned long now = millis();
if (now - lastTime >= PERIOD) // this will be true every PERIOD milliseconds
{
lastTime = now;
if (ledState == LOW)
{
ledState = HIGH;
}
else
{
ledState = LOW;
}
digitalWrite(OUTPIN, ledState);
}
// now there's lots of time to do other stuff here
}
このようにmillis()
を使用すると、非ブロッキングの方法で操作を行うことが非常に頻繁に必要になるので、 elapsedMillis
ライブラリを使用することを検討してelapsedMillis
。
elapsedMillisとelapsedMicrosを使用して、何が起きたかを測定する
#include <elapsedMillis.h>
void setup() {
Serial.begin(115200);
elapsedMillis msTimer;
elapsedMicros usTimer;
long int dt = 500;
delay(dt);
long int us = usTimer;
long int ms = msTimer;
Serial.print("delay(");Serial.print(dt);Serial.println(") took");
Serial.print(us);Serial.println(" us, or");
Serial.print(ms);Serial.println(" ms");
}
void loop() {
}
この例では、 elapsedMillis
オブジェクトとelapsedMicros
オブジェクトを使用して、何かが実行された時間を測定します。時間をelapsedMicros
する式が実行される直前に作成し、その後に値を取得します。わずかに異なる結果が表示されますが、ミリ秒の結果は1ミリ秒以上ずれていません。
遅延なしの1つ以上のタスク()
異なる間隔で繰り返し実行するタスクが複数ある場合は、この例を開始点として使用します。
unsigned long intervals[] = {250,2000}; //this defines the interval for each task in milliseconds
unsigned long last[] = {0,0}; //this records the last executed time for each task
void setup() {
pinMode(LED_BUILTIN, OUTPUT); //set the built-it led pin as output
Serial.begin(115200); //initialize serial
}
void loop() {
unsigned long now = millis();
if(now-last[0]>=intervals[0]){ last[0]=now; firstTask(); }
if(now-last[1]>=intervals[1]){ last[1]=now; secondTask(); }
//do other things here
}
void firstTask(){
//let's toggle the built-in led
digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN)?0:1);
}
void secondTask(){
//say hello
Serial.println("hello from secondTask()");
}
別のタスクを追加して15秒ごとに実行するには、変数intervals
を延長し、 last
:
unsigned long intervals[] = {250,2000,15000};
unsigned long last[] = {0,0,0};
次に、 if
文を追加して新しいタスクを実行します。この例では、 thirdTask
という名前を付けthirdTask
。
if(now-last[2]>=intervals[2]){ last[2]=now; thirdTask(); }
最後に関数を宣言します:
void thirdTask(){
//your code here
}