Skocz do zawartości
Diabloo24

Używanie funkcji millis() do odmierzania czasu

Pomocna odpowiedź

W projekcie z ESP8266 potrzebuje odczytywać dane z czujników co określony czas np. 30 min. Do programowania ESP8266 wykorzystuje środowisko Arduino i znalazłem w dokumentacji funkcję millis(), która odlicza czas od uruchomienia programu/urządzenia. Przy wykorzystaniu tej funkcji można stworzyć proste odmierzanie czasu i wykonywanie pomiaru w określonych przeze mnie odstępach np. co 30min. Funkcja ta byłaby świetnym rozwiązaniem, ale doczytałem, że licznik przepełnia się po 50 dniach i resetuje, a także, że wykorzystanie tej funkcji (gdy już licznik jest w dużej mierze napełniony) może ona wprowadzać błędy w innych operacjach arytmetycznych wykonywanych w tym programie. Niestety martwi mnie to, że mogą się pojawić błędy w innych obliczeniach, ponieważ oprócz samego odmierzania czasu i dokonywaniu pomiarów, wykonuję również trochę operacji matematycznych, a później wysyłam dane na serwer. Tutaj moje pytanie czy stosowanie takiego rozwiązania do odmierzania będzie w ogóle poprawne skoro może ono generować błędy? Czy ta funkcja może działać lepiej w esp8266 skoro ma więcej pamięci niż Arduino? W jaki inny sposób można rozwiązać odmierzanie czasu i cykliczne pomiary przy projektach, w których wykonuje się więcej operacji i obliczeń (odliczanie 30 - 60 min)?

Udostępnij ten post


Link to post
Share on other sites

Nic się nie resetuje - licznik się przepełnia (to różnica), ale urok operacji na liczbach bez znaku polega na tym, że nie wpływa to na obliczenia (przynajmniej w zakresie odliczania czasów nie przekraczających połowy pojemności licznika, czyli w naszym przypadku 25 dni). Poza tym nie jest tu ważna ilość pamięci a długość samego licznika , która w obu przypadkach wynosi 4 bajty.

Zapoznaj się z kursem Arduino, konkretniej https://forbot.pl/blog/kurs-arduino-ii-wielozadaniowosc-opoznienia-z-millis-id18418. Nie jest to dokładnie Twój problem, ale tak przy okazji jest on wyjaśniony.

 

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites
52 minuty temu, ethanak napisał:

Nic się nie resetuje - licznik się przepełnia (to różnica),

Tak właśnie to miałem na myśli, lecz w pośpiechu użyłem nie odpowiedniego słowa.

54 minuty temu, ethanak napisał:

Zapoznaj się z kursem Arduino, konkretniej https://forbot.pl/blog/kurs-arduino-ii-wielozadaniowosc-opoznienia-z-millis-id18418. Nie jest to dokładnie Twój problem, ale tak przy okazji jest on wyjaśniony.

Tak, czytałem. W zasadzie użyłem tego w podobny sposób. Głównie zastanawia mnie wpływ takiego odliczania na poprawność innych operacji. Przykładowo czy przy 45 dniu odliczania czasu w programie nie zaczną występować błędy a urządzenie przestanie pracować stabilnie?

 

Martwię się o to, że w początkowych dniach pracy urządzenia gdy licznik (w którym jest zapisany czas pracy) nie będzie zapełniony nawet do połowy to wszystkie inne operacje, które wykonuje w programie będą działać prawidłowo itp. Natomiast, gdy będzie już blisko przepełnienia licznika to będzie on miał wpływ na inne operacje w programie i będą się pojawiać błędy przez co urządzenie będzie pracować niestabilnie..?

Udostępnij ten post


Link to post
Share on other sites

Licznik się nie "zapełnia" tylko przyjmuje jakąś tam określoną wartość (od 0 do 0xffffffff), która nie ma nic wspólnego z "jakością" (czymkolwiek by ona nie była) pracy, a szczególnie nie ma wpływu na "jakość" (czymkolwiek by ona nie była) innych operacji.

Wszyscy na całym świecie to stosują, większość ma obiekcje które nikną po dokładnym zapoznaniu się z zasadami arytmetyki liczb o stałej długości bez znaku.

Tak przy okazji - ESP8266 ma zegar czasu rzeczywistego który działa również w trybie uśpienia...

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites
(edytowany)

Jeśli ESP ma coś robić tylko co 30min to można go po prostu usypiać na ten czas (powerdown, potem robi reset i zaczyna program od nowa - trochę dziwne, ale dane można przechować w pamięci RTC), jeśli ma działać cały czas wystarczy wynik różnicy rzutować na UL i będzie działać dopóki nie zrobisz resetu lub nie braknie zasilania, na podstawie przykładu BlinkWithoutDelay:

const int ledPin =  LED_BUILTIN;// the number of the LED pin

 
int ledState = LOW;             // ledState used to set the LED
 
uint32_t previousMillis = 0;        // will store last time LED was updated
 
const uint32_t interval = 1000UL;           // interval at which to blink (milliseconds)

void setup() {
 
  pinMode(ledPin, OUTPUT);
}

void loop() {
  
  uint32_t currentMillis = millis();

  if ((uint32_t)(currentMillis - previousMillis) >= interval) {
 
    previousMillis = currentMillis;
 
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
      
    }
 
    digitalWrite(ledPin, ledState);
    
  }
}

Jak chcesz sprawdzić jak działa przepełnienie można wykorzystać mniejsze zmienne ze znakiem i bez:

Po edycji:

//Pretend "counter" is "millis"
unsigned char counter;
 unsigned char roznica;
unsigned char previousCounter = 0;
unsigned char interval=30;
const char interval2=30;
void setup() {
   Serial.begin(115200);
   delay(2000);  // give enough time to open the serial monitor after uploading
   Serial.println("Starting...");
}
void loop() {
   for (int x=0; x<1000; x++) { // run through uchar a few times
// ******* simulate millis()
       counter++; // simulate millis()
       Serial.println(counter);
// ******
       unsigned char currentCounter = counter;
     //  roznica=(currentCounter - previousCounter);
       if ((unsigned char)(currentCounter - previousCounter) >= interval) { // check for rollover
         Serial.println("Trigger Event!");
         previousCounter = currentCounter;
      }
   }
Serial.println("...stopping!");
Serial.println(roznica);
while(1) delay(1); // Stop the Serial monitor output
}

 

Edytowano przez kaczakat
Korekta dla ESP8266

Udostępnij ten post


Link to post
Share on other sites

Przy testowaniu drugiego programu wygląda to jakby ESP8266 się resetował (?)

 

obraz.thumb.png.d987c74d4cdab1cca669f8d2e19c5112.png

Udostępnij ten post


Link to post
Share on other sites

Owszem resetuje się - kolega @kaczakat zapomniał że to ESP a nie AVR i yield, delay albo powrót z loop zanim watchdog się wnerwi są wymagane 😉

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

Okej, ale wracając do mojej wątpliwości, rozumiem, że bez obaw mogę korzystać z funkcji millis() i powszechnie jest to też stosowane

Udostępnij ten post


Link to post
Share on other sites

Faktycznie przykład 2 testowałem na AVR, działa OK też z ESP32, ale WDT ESP8266 wkurza się w while(1), tu WDT jest automatycznie dołączony do kodu, wystarczy zmienić tę linijkę jak napisał @ethanak dodając delay(1) lub yield(): while(1) delay(1);. Dodałem we wcześniejszym kodzie, jakby ktoś tu jeszcze zajrzał.

Udostępnij ten post


Link to post
Share on other sites
1 godzinę temu, Diabloo24 napisał:

Okej, ale wracając do mojej wątpliwości, rozumiem, że bez obaw mogę korzystać z funkcji millis() i powszechnie jest to też stosowane

Dobrze rozumiesz.

@kaczakat- może być nawet delay(0) - to to samo co yield().

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »

×