RTV forum PL | NewsGroups PL

Jak zabezpieczyć odliczanie czasu w Arduino przed przepełnieniem millis()?

AVR, Arduino - odmierzanie czasu między zdarzeni ami

NOWY TEMAT

elektroda NewsGroups Forum Index - Elektronika Polska - Jak zabezpieczyć odliczanie czasu w Arduino przed przepełnieniem millis()?

Atlantis
Guest

Tue Sep 24, 2013 9:14 pm   



Do tej pory nie potrzebowałem jednoczesnego odmierzania kilku różnych
wartości, w związku z czym timerów w Atmedze8 wystarczało do moich
zastosowań. Mogłem sobie pozwolić na zaangażowanie konkretnego licznika
do konkretnego zadania i resetowanie go wedle upodobań. Nie zawsze
jednak tak się da...

W Arduino jest taka funkcja jak millis(), która zwraca ilość milisekund
jakie upłynęły od uruchomienia układu. Wartość przechowywana w long int,
wystarczy na trochę mniej niż 50 dni. Gdy zachodzi konieczność podjęcia
jakiejś akcji w określonym czasie od jakiegoś zdarzenia wystarczy
przepisać aktualną wartość do zmiennej, a potem sprawdzać jak różnica
miedzy wartością aktualną a zapisaną ma się do żądanego interwału.

Zastanawia mnie tylko jedna kwestia. Jakie mogą być skutki ewentualnego
przepełnienia zmiennej i rozpoczęcia odliczania od nowa? Można sobie
wyobrazić, że urządzenie pracujące cały czas będzie miało taki uptime.
Można jakoś bronić się przed taką sytuacją?

Grzegorz Niemirowski
Guest

Tue Sep 24, 2013 9:26 pm   



Atlantis <marekw1986NOSPAM@wp.pl> napisał(a):
[wycinam, bo tak naprawdę brak związku między pytaniem a AVR, Arduino Smile ]
Quote:
Zastanawia mnie tylko jedna kwestia. Jakie mogą być skutki ewentualnego
przepełnienia zmiennej i rozpoczęcia odliczania od nowa? Można sobie
wyobrazić, że urządzenie pracujące cały czas będzie miało taki uptime.
Można jakoś bronić się przed taką sytuacją?

1. Miej jakieś zdarzenie generowane z częstotliwością większą niż
przepełnienia tego licznika. Zapamiętuj w nim wartość zwróconą przez
milis(). Jak będzie niższa niż ostatnio, będziesz wiedział, że upłynął okres
tego licznika.
2. Użyj RTC z podtrzymywaniem bateryjnym. Mała inwestycja a życie stanie się
prostsze a niezawodność większa.

--
Grzegorz Niemirowski
http://www.grzegorz.net/
OE PowerTool i Outlook Express: http://www.grzegorz.net/oe/
Uptime: 13 days, 0 hours, 51 minutes and 31 seconds

Atlantis
Guest

Tue Sep 24, 2013 9:34 pm   



W dniu 2013-09-24 23:26, Grzegorz Niemirowski pisze:

Quote:
1. Miej jakieś zdarzenie generowane z częstotliwością większą niż
przepełnienia tego licznika. Zapamiętuj w nim wartość zwróconą przez
milis(). Jak będzie niższa niż ostatnio, będziesz wiedział, że upłynął
okres tego licznika.

Hmm... Na dobrą sprawę przecież mogę to zrobić w przerwaniu
przepełnienia tego licznika. Tak czy inaczej będzie tam instrukcja
warunkowa sprawdzająca czy zmienna osiągnęła swoją maksymalną wartość i
resetująca ją. Równie dobrze można wtedy postawić flagę.

Atlantis
Guest

Tue Sep 24, 2013 10:29 pm   



Tak swoją drogą nie mogę się doszukać informacji na temat czasu, jaki
zajmuje takiej Atmedze8 wyjście z idle mode. Czy przy przerwaniu
wywoływanym co 1 ms (do tego dochodzą jeszcze przerwania od USART, INT0
albo INT1) usypianie MCU po każdej iteracji pętli głównej ma sens?

Grzegorz Niemirowski
Guest

Tue Sep 24, 2013 10:33 pm   



Atlantis <marekw1986NOSPAM@wp.pl> napisał(a):
Quote:
Tak swoją drogą nie mogę się doszukać informacji na temat czasu, jaki
zajmuje takiej Atmedze8 wyjście z idle mode. Czy przy przerwaniu
wywoływanym co 1 ms (do tego dochodzą jeszcze przerwania od USART, INT0
albo INT1) usypianie MCU po każdej iteracji pętli głównej ma sens?

Trudno powiedzieć, bo nie podałeś ile czasu MCU spędza w tych przerwaniach.
A po co usypiasz? Masz zasilanie bateryjne? Może po prostu zmierz pobór
prądu z usypianiem i bez.

--
Grzegorz Niemirowski
http://www.grzegorz.net/
OE PowerTool i Outlook Express: http://www.grzegorz.net/oe/
Uptime: 13 days, 2 hours, 0 minutes and 32 seconds

Atlantis
Guest

Wed Sep 25, 2013 4:27 am   



W dniu 2013-09-25 00:33, Grzegorz Niemirowski pisze:

Quote:
Trudno powiedzieć, bo nie podałeś ile czasu MCU spędza w tych
przerwaniach.

Trudno powiedzieć. Jednak staram się, żeby w przerwaniach nie było zbyt
rozbudowanych instrukcji, oczywiście nigdy nie używam funkcji
opóźniającej (ani niczego co ją wykorzystuje) w procedurze obsługi
przerwania.


Quote:
A po co usypiasz? Masz zasilanie bateryjne? Może po prostu
zmierz pobór prądu z usypianiem i bez.

Tak, chodzi o urządzenia zasilane z baterii/akumulatorka.

Zbych
Guest

Wed Sep 25, 2013 2:10 pm   



W dniu 24.09.2013 23:14, Atlantis pisze:
Quote:
Do tej pory nie potrzebowałem jednoczesnego odmierzania kilku różnych
wartości, w związku z czym timerów w Atmedze8 wystarczało do moich
zastosowań. Mogłem sobie pozwolić na zaangażowanie konkretnego licznika
do konkretnego zadania i resetowanie go wedle upodobań. Nie zawsze
jednak tak się da...

W Arduino jest taka funkcja jak millis(), która zwraca ilość milisekund
jakie upłynęły od uruchomienia układu. Wartość przechowywana w long int,
wystarczy na trochę mniej niż 50 dni. Gdy zachodzi konieczność podjęcia
jakiejś akcji w określonym czasie od jakiegoś zdarzenia wystarczy
przepisać aktualną wartość do zmiennej, a potem sprawdzać jak różnica
miedzy wartością aktualną a zapisaną ma się do żądanego interwału.

Zastanawia mnie tylko jedna kwestia. Jakie mogą być skutki ewentualnego
przepełnienia zmiennej i rozpoczęcia odliczania od nowa? Można sobie
wyobrazić, że urządzenie pracujące cały czas będzie miało taki uptime.
Można jakoś bronić się przed taką sytuacją?

Nie ma po co się bronić. Jeśli nie posługujesz się wartością bezwzględną
licznika, tylko różnicą wskazań to spokojnie możesz mierzyć przedziały
mniejsze niż te 50 dni (niezależnie czy licznik się w tym czasie
przekręci, czy nie). Wystarczy sprawdzić kilka przypadków na palcach:

- stan początkowy licznika: 00000000h, końcowy: 00000200h, różnica 200h
- stan początkowy licznika: FFFFFF00h, końcowy: 00000100h, różnica 200h

Atlantis
Guest

Wed Sep 25, 2013 4:52 pm   



W dniu 2013-09-25 16:10, Zbych pisze:

Quote:
Nie ma po co się bronić. Jeśli nie posługujesz się wartością bezwzględną
licznika, tylko różnicą wskazań to spokojnie możesz mierzyć przedziały
mniejsze niż te 50 dni (niezależnie czy licznik się w tym czasie
przekręci, czy nie). Wystarczy sprawdzić kilka przypadków na palcach:

Czekaj, coś mi tu nie pasuje...

Dla ułatwienia unsigned short int, wartości zapisane systemem dziesiętnym.

prevMillis = 65000 (czas zapisany przy rozpoczęciu pomiaru)
millis = 65200 (obecny czas)
millis-prevMillis = 200 (czas trwania mierzonego zjawiska, wszystko się
zgadza)

I w przypadku przekręcenia licznika:
prevMillis=65435 (czas zapisany na chwilę przed przekręceniem licznika)
millis=100 (obecny czas, już po przekręceniu licznika)
millis-prevMillis = -65335

Zdecydowanie nie jest to jedno i to samo. ;)

W przypadku signed short int:
prevMillis = 32667
millis = -32668
millis-prevMillis = -65335

Grzegorz Niemirowski
Guest

Wed Sep 25, 2013 6:42 pm   



Atlantis <marekw1986NOSPAM@wp.pl> napisał(a):
Quote:
Dla ułatwienia unsigned short int, wartości zapisane systemem dziesiętnym.
[ciach]
millis-prevMillis = -65335

Jak unsigned to skąd znak?

--
Grzegorz Niemirowski
http://www.grzegorz.net/
OE PowerTool i Outlook Express: http://www.grzegorz.net/oe/
Uptime: 13 days, 22 hours, 9 minutes and 9 seconds

Atlantis
Guest

Wed Sep 25, 2013 7:08 pm   



W dniu 2013-09-25 20:42, Grzegorz Niemirowski pisze:

Quote:
Jak unsigned to skąd znak?

Hmm... Tego nie wziąłem pod uwagę. Jak w takim razie zachowa się program
w poniższym przypadku?

unsigned int zmienna1 = 4000
unsigned int zmienna2 = 5000
unsigned int zmienna3 = 200

if (zmienna1-zmienna2 > zmienna3) {
//instrukcje do wykonania
}

Innymi słowy: do jakiego typu zmiennej zostanie podstawiony wynik
odejmowania i co nim będzie? Wink

Zbych
Guest

Wed Sep 25, 2013 7:09 pm   



W dniu 25.09.2013 18:52, Atlantis pisze:
Quote:
W dniu 2013-09-25 16:10, Zbych pisze:

Nie ma po co się bronić. Jeśli nie posługujesz się wartością bezwzględną
licznika, tylko różnicą wskazań to spokojnie możesz mierzyć przedziały
mniejsze niż te 50 dni (niezależnie czy licznik się w tym czasie
przekręci, czy nie). Wystarczy sprawdzić kilka przypadków na palcach:

Czekaj, coś mi tu nie pasuje...

Dla ułatwienia unsigned short int, wartości zapisane systemem dziesiętnym.

prevMillis = 65000 (czas zapisany przy rozpoczęciu pomiaru)
millis = 65200 (obecny czas)
millis-prevMillis = 200 (czas trwania mierzonego zjawiska, wszystko się
zgadza)

I w przypadku przekręcenia licznika:
prevMillis=65435 (czas zapisany na chwilę przed przekręceniem licznika)
millis=100 (obecny czas, już po przekręceniu licznika)
millis-prevMillis = -65335

Zdecydowanie nie jest to jedno i to samo. Wink

Masz braki w znajomości sposobów reprezentacji liczb w systemach
cyfrowych. Poczytaj sobie do poduszki na temat U2.

int main(int argc, const char *argv[])
{
unsigned short start = 65435;
unsigned short stop = 100;
printf("start: %u, stop %u, delta %u\n", start, stop, (unsigned
short)(stop-start));
return 0;
}

Wynik:
start: 65435, stop 100, delta 201

Quote:
W przypadku signed short int:
prevMillis = 32667
millis = -32668
millis-prevMillis = -65335

int main(int argc, const char *argv[])
{
short start = 32667;
short stop = -32668;
printf("start: %d, stop %d, delta %u", start, stop, (unsigned
short)(stop-start));
return 0;
}

Wynik:
start: 32667, stop -32668, delta 201

elektroda NewsGroups Forum Index - Elektronika Polska - Jak zabezpieczyć odliczanie czasu w Arduino przed przepełnieniem millis()?

NOWY TEMAT

Regulamin - Zasady uzytkowania Polityka prywatnosci Kontakt RTV map News map