サーチ…


構文

  • 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ます。一見するとこれは驚くべきことではないかもしれませんが、時間のかかることが起こっていると効果があります:

ledTimePERIOD比較が750ミリ秒後に行われる状況を考えてみましょう。次に、 ledTimeを0に設定すると、以降のトグル操作はすべて250ミリ秒遅れることになります。対照的に、 PERIODledTimeから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
}


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow