Szukaj…


Składnia

  • niepodpisane długie millis ()

  • długie micros bez znaku ()

  • void delay (niepodpisane długie milisekundy)

  • void delayMicroseconds (niepodpisane długie mikrosekundy)

  • Zobacz nagłówek elapsedMillis dla konstruktorów i operatorów tej klasy. W skrócie:

    • elapsedMillis elapsedMillisObject; tworzy obiekt do śledzenia czasu od momentu jego utworzenia lub innego jawnie określonego punktu w czasie
    • elapsedMillisObject = 0; zresetuj czas śledzony przez obiekt na „od teraz”
    • unsigned long deltaT = elapsedMillisObject; pozwala nam spojrzeć na śledzony czas
    • elapsedMillisObject + = i - = działają one zgodnie z oczekiwaniami

Uwagi

Kod blokujący a nieblokujący

W przypadku bardzo prostych szkiców odpowiednie może być pisanie kodu blokującego za pomocą delay() i delayMicroseconds() . Gdy sprawy stają się bardziej złożone, korzystanie z tych funkcji może mieć pewne wady. Niektóre z nich to:

  • Marnowanie czasu procesora: bardziej złożone szkice mogą wymagać procesora do czegoś innego, czekając na zakończenie mrugania diody LED.
  • nieoczekiwane opóźnienia: gdy delay() jest wywoływane w podprogramach, które oczywiście nie są wywoływane, na przykład w bibliotekach, które dołączasz.
  • brakujące zdarzenia, które zdarzają się podczas opóźnienia i nie są obsługiwane przez moduł obsługi przerwania, na przykład odpytywane naciśnięcia przycisków: przycisk można nacisnąć przez 100 ms, ale może to być delay(500) .

Szczegóły dotyczące wdrożenia

millis() zwykle polega na sprzętowym zegarze, który działa z prędkością znacznie wyższą niż 1 kHz. Kiedy millis() jest millis() , implementacja zwraca pewną wartość, ale nie wiesz, ile ona faktycznie ma lat. Możliwe, że „bieżąca” milisekunda właśnie się rozpoczęła lub że zakończy się natychmiast po wywołaniu tej funkcji. Oznacza to, że obliczając różnicę między dwoma wynikami z millis() , możesz być wyłączony przez cokolwiek pomiędzy prawie zero a prawie jedną milisekundą. Użyj micros() jeśli wymagana jest większa precyzja.

elapsedMillis kodu źródłowego elapsedMillis ujawnia, że rzeczywiście używa wewnętrznie millis() do porównywania dwóch punktów w czasie, więc cierpi również na ten efekt. Znowu istnieje alternatywa, która elapsedMicros dla większej precyzji, z tej samej biblioteki.

blokowanie migania z opóźnieniem ()

Jednym z najprostszych sposobów na mrugnięcie diody LED jest: włącz ją, poczekaj chwilę, wyłącz, poczekaj ponownie i powtarzaj w nieskończoność:

// 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
}

Jednak czekanie, tak jak w powyższym przykładzie, marnuje cykle procesora, ponieważ po prostu siedzi tam w pętli i czeka na określony moment w przeszłości. Właśnie to robią sposoby nieblokujące, używając millis() lub elapsedMillis - w tym sensie, że nie elapsedMillis tyle możliwości sprzętu.

Nieblokujący blinky z biblioteką elapsedMillis (i klasą)

Biblioteka elapsedMillis udostępnia klasę o tej samej nazwie, która śledzi czas, który upłynął od momentu jej utworzenia lub ustawienia określonej wartości:

#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
}

W przykładzie widać, że obiekt ledTime ma przypisane zero, gdy pin LED był przełączany. Na pierwszy rzut oka nie jest to zaskakujące, ale ma wpływ, gdy dzieje się coś bardziej czasochłonnego:

Rozważ sytuację, w której porównanie między ledTime i PERIOD jest wykonywane po 750 milisekundach. Ustawienie wartości ledTime na zero oznacza, że wszystkie kolejne operacje przełączania będą opóźnione o 250 ms. Gdyby natomiast ledTime PERIOD od ledTime , dioda LED zobaczyłaby jeden krótki okres, a następnie kontynuowałaby miganie, jakby nic się nie wydarzyło.

Nieblokujący blinky z millis ()

Jest to bardzo zbliżone do przykładu z arduino docs :

// 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
}

Używanie millis() w ten sposób - do czasowego wykonywania operacji w sposób nieblokujący - jest czymś, co jest potrzebne dość często, więc rozważ użycie w tym elapsedMillis biblioteki elapsedMillis .

Zmierz, jak długo zajęło coś, używając elapsedMillis i 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() {
}

W tym przykładzie obiekt elapsedMillis i elapsedMicros są używane do mierzenia czasu, przez jaki coś trwało, tworząc je tuż przed wykonaniem wyrażenia, które chcemy zmierzyć, a następnie uzyskując ich wartości. Pokażą nieco inne wyniki, ale wynik w milisekundach nie zostanie wyłączony o więcej niż jedną milisekundę.

Więcej niż 1 zadanie bez opóźnień ()

Jeśli masz więcej niż 1 zadanie do wykonania wielokrotnie w różnych odstępach czasu, użyj tego przykładu jako punktu początkowego:

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()");
}

Aby dodać kolejne zadanie do wykonania co 15 sekund, rozszerzyć zmienne intervals i last :

unsigned long intervals[] = {250,2000,15000};
unsigned long last[] = {0,0,0};

Następnie dodaj instrukcję if , aby wykonać nowe zadanie. W tym przykładzie thirdTask mu nazwę thirdTask .

if(now-last[2]>=intervals[2]){ last[2]=now; thirdTask(); }

Na koniec zadeklaruj funkcję:

void thirdTask(){
  //your code here
}


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow