między zdarzeni

Sep 24, 2013 10 Replies

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ą?


Atlantis snipped-for-privacy@wp.pl napisał(a): [wycinam, bo tak naprawdę brak związku między pytaniem a AVR, Arduino :) ]

  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.

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

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ę.

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?

Atlantis snipped-for-privacy@wp.pl napisał(a):

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.

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

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.

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

W dniu 24.09.2013 23:14, Atlantis 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:

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

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

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

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

Atlantis snipped-for-privacy@wp.pl napisał(a):

Jak unsigned to skąd znak?

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

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? ;)

W dniu 25.09.2013 18:52, Atlantis pisze:

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

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

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required