Wątpliwość co do millis

Masz problem, z którym nie możesz sobie poradzić? Pisz śmiało!
ODPOWIEDZ
Merki
Młodszy majsterkowicz
Posty: 10
Rejestracja: 10 lut 2013, 10:32

Wątpliwość co do millis

Post autor: Merki » 10 lut 2015, 21:35

Witam,

mam pytanie co do kodu przedstawionego niżej:

Kod: Zaznacz cały

if ((unsigned long)(aktualnyMillis-poprzedniMillis) >=przerwa) //czy to będzie działać dobrze ze względu na unsigned long?
  {
    dt=clock.getDateTime(); //przechwyt daty i czasu do zmiennej dt
    sensors.requestTemperatures(); //polecenie odczytu temperatury
    temp = sensors.getTempCByIndex(0); //zapisanie temperatury do zmiennej temp
    poprzedniMillis=aktualnyMillis;
  }
Zmienna poprzedniMillis początkowo jest deklarowana jako 0, zmienna aktualnyMillis zadeklarowana i aktualizowana w pętli głównej loop wartością millis.

Nachodzi mnie pytanie: co jeśli aktualny millis zbliża się do swojej maksymalnej wartości i w końcu ją przekroczy ustawiając się na 0? Może zajść wtedy przypadek gdy aktualnyMillis ma np. wartość 100, a poprzedniMillis ma te 49 dni około. Wtedy z porównania wyjdzie ujemna wartość i program (teoretycznie) przestanie działać prawidłowo. Jednak nie daje mi spokoju to, że całość w warunku jest typu unsigned long czyli bez znaku.

Czy ktoś może potwierdzić, że powyższy kod działać będzie prawidłowo niezależnie od tego jak długo pracować będzie Arduino?

Co miesiąc do wygrania nagrody o wartości ponad 1600 zł!


razorxx100
Starszy majsterkowicz
Posty: 329
Rejestracja: 1 sie 2014, 22:57

Re: Wątpliwość co do millis

Post autor: razorxx100 » 10 lut 2015, 22:53

Pomysl oczywiscie dobry, ale troche zle jest to zrobione.
Z tego co wiem to chcesz zrobic odczytanie temperatury np co 10s?
W setup dajesz przykladowo
time = millis() + 5000;
void loop() {
if( millis() >= time) {
//co ma wykonac
time = millis() + 5000;
}
}

Nic nie trzeba odejmowac :)
Co do ostatniego pytanie. Funkcja millis to czas ile juz chodzi nasza atmega, odliczanie jest do 50 dni, a po 50 dniach odliczanie zaczyna sie na nowo. Nie zapomnij na poczatku skryptu dopisac long time;
Merki
Młodszy majsterkowicz
Posty: 10
Rejestracja: 10 lut 2013, 10:32

Re: Wątpliwość co do millis

Post autor: Merki » 12 lut 2015, 11:12

Ok, rozumiem Twoją ideę. Ale co się stanie, gdy zmienna time przekroczy wielkość przeznaczoną dla zmiennej typu long? Nie spowoduje to jakiegoś błędu aplikacji?

Rozumiem,że millis starczy na 50 dni,ale w kontekście tej jednej linijki:

Kod: Zaznacz cały

if ((unsigned long)(aktualnyMillis-poprzedniMillis) >=przerwa)
co stanie się, gdy wejdę w zakres wartości ujemnych? Czy wogóle wejdę w ten zakres?
razorxx100
Starszy majsterkowicz
Posty: 329
Rejestracja: 1 sie 2014, 22:57

Re: Wątpliwość co do millis

Post autor: razorxx100 » 12 lut 2015, 16:58

Poprostu program sie zawiesi i tyle. Millis starczy ci nawet na 100 lat poniewaz sie resetuje do 50 dni. Z tego co liczylem to w long zmiesci sie 24-25 dni, ale przezciez mozesz zrobic w kodzie ze jak minie np 1 dzien to atmega sie resetuje i po problemie.
Jak wejdziesz w zakres wartosci ujemnych to sie nic nie stanie, ale w tym kodzie to przeciez nie jest mozliwe.
stiven
Złota rączka
Posty: 1596
Rejestracja: 13 maja 2014, 08:47
Lokalizacja: Zielona Góra

Re: Wątpliwość co do millis

Post autor: stiven » 14 lut 2015, 18:31

Dopisanie w warunku ifa (unsigned long) powoduje, że wynik (aktualnyMillis-poprzedniMillis) będzie typu unsigned long, dodatni (to się nazywa rzutowanie typu). Więc tam nigdy nie będzie wartości ujemnej. Na pewno w niczym to nie przeszkadza, funkcja millis zwraca wartość właśnie w unsigned long. Ale tak na prawdę jest to nie potrzebne, wystarczy, że zmienne aktualnyMillis i poprzedniMillis będą typu unsigned long i wynik będzie właśnie takiego typu (czyli też zawsze dodatni). To rzutowanie byłoby potrzebne jeśli z jakiegoś powodu ktoś te zmienne musiał zadeklarować jako long.

Wartości zmiennych typu long to przedział od -2.147.483.648 do 2.147.483.647, a unsigned long od 0 do 4.294.967.295.

Kiedy będziemy mieć na przykład coś takiego:

Kod: Zaznacz cały

  unsigned long x;
  unsigned long y;

  x = 0;
  y = x - 1;
to w zmiennej y nie będzie wartości -1. Tam będzie wartość 4294967295. Jest to coś takiego jak przepełnienie arytmetyczne, przepełnienie zmiennej. Gdyby tam na przykład było x - 10, no to końcówka zamiast '295, byłaby '286.
Tak na prawdę na tym samym polega zerowanie millis() (jest to na pewno jakaś zmienna typy unsigned long inkrementowana co odpowiedni czas), po wartości 4294967295 nie może już być 4294967296, więc następuje przepełnienie i jest 0.
W przypadku zmiennych, które nie są unsigned, to przeskoczyłoby do wartości ujemnych.

Prawda jest jednak taka, że wyzerowanie millis dużego problemu tutaj nie spowoduje, jedynie jednorazowe nadmiarowe wykonanie tego ifa. Na pewno można temu przeciwdziałać programowo, ale w tym przypadku chyba nie ma potrzeby.
W momencie wyzerowania w aktualnyMillis będzie na przykład 0, a w poprzedniMillis na przykład 4294967163, to pamiętając o przepełnieniu wynikiem 0 - 4294967163, będzie 4294967162 i warunek zostanie spełniony choć niekoniecznie powinien.


Zastanawia mnie czemu razorxx100 napisał, że program się zawiesi. Niby czemu? W ifie warunek o wartości ujemnej zawiesza program? Program by się nie zawiesił, tylko warunek by nie działał.


EDIT

Bzdurę napisałem, 0 - 4294967163 to nie 4294967162, tylko tyle co 4294967295 - 4294967162, czyli tak na prawdę wyzerowanie millis nie wpłynie w żaden sposób, bo różnica dzięki przepełnieniu zawsze będzie dobrze liczona.
Merki
Młodszy majsterkowicz
Posty: 10
Rejestracja: 10 lut 2013, 10:32

Re: Wątpliwość co do millis

Post autor: Merki » 16 lut 2015, 21:11

Dziękuję bardzo za odpowiedzi, teraz już kumam o chodzi ;)
ODPOWIEDZ

Strony partnerskie: