Artykuł jest częścią cyklu: SmartPIP - Elektroniczny dręczyciel
W poprzednim artykule ustaliliśmy w jaki sposób SmartPIP będzie realizował funkcję odliczania czasu. Możemy więc opracować ten fragment programu i przetestować, jakie będzie faktyczne zużycie prądu baterii w czasie snu mikrokontrolera.
Schemat testowy + fusebit'y
Zaczniemy od przygotowania schematu testowego. Sygnalizatorem pracy naszego licznika czasu będzie dioda LED:
Podział zasilania
W celu poprawnego dokonania pomiaru prądu pobieranego przez mikrokontroler w czasie snu, musimy dokonać podziału zasilania, na część zasilającą mikrokontroler oraz część zasilającą diodę LED.
Na schemacie możesz zauważyć, że dioda LED jest podłączona do mikrokontrolera katodą (przez rezystor R2). To bardzo istotne!
Dlaczego? Ponieważ w ten sposób pin mikrokontrolera staruje diodą zwierając ją do masy dzięki czemu, prąd płynący przez diodę LED nie jest pobierany z mikrokontrolera, co oznacza, że nie płynie przez amperomierz.
Jeżeli natomiast podłączymy diodę anodą do pinu mikrokontrolera (przez rezystor R2) a katodą do masy, to w takim układzie prąd diody będzie płynął przez mikrokontroler oraz amperomierz. Takie podłączenie nie pozwoli nam dokonać poprawnych pomiarów prądu zużywanego przez mikrokontroler w czasie snu. Możemy oczywiście na czas pomiaru po prostu usunąć diodę LED.
Kwarc zegarkowy + częstotliwość generatora RC + fusebit'y
Kwarc podłączamy bez zewnętrznych kondensatorów, ponieważ włączymy za pomocą fusebit'ów opcję CKOPT, która w przypadku wykorzystania takiego kwarcu powinna być włączona.
Program przygotowany jest dla mikrokontrolera taktowanego przez wewnętrzny generator RC 1MHz.
Wartości (ustawienia) fusebit'ów:
- low: 0xE1
- high: 0xC9
Kondensator filtrujący
Układ testowy przygotowany jest w wersji totalne minimum, ze względu na to, by upływność kondensatorów nie wpływała na pomiar. Dlatego użyjemy tylko jednego kondensatora ceramicznego na pinach zasilania oraz nie podłączymy kondensatora do pinu AREF.
Rezystor pinu Reset
Na powyższym schemacie wartość rezystora pull-up pinu Reset jest znacznie większa niż standardowe 10kΩ. Użyjemy 47kΩ, czyli w okolicach największej możliwej wartości wewnętrznego rezystora pull-up:
Nie ma to jednak dla nas większego znaczenia, ponieważ nie mamy przycisku na tym pinie, więc nie będzie zwierany do masy, a prąd upływu pinu i tak jest tak znikomy, że nie ma dla niego różnicy, czy rezystor ma 10kΩ, czy 47kΩ. Gdyby dokonać pomiarów na poziomie nA, to może się okazać, że jednak warto dać większy rezystor. Niemniej jednak ograniczanie prądów zawsze powinno być naszym priorytetem.
Program testowy
Poniżej program testowy, przygotowany zgodnie z założeniem, że stosujemy podział poszczególnych funkcjonalności na osobne pliki. Dlatego też program ten jest tak "rozwleczony". Mógłby być krótki, ale zalety takiego pisania docenisz w kolejnych artykułach o SmartPIP.
W związku z tym, wszystko co dot. licznika czasu umieszczamy w plikach o nazwie dd_licznik_czasu, a resztę programu w plikach dd_main.
Zadania programu:
- zainicjować Timer2 w tryb pracy z kwarcem 32,768kHz i wybranym preskalerem,
- przygotować mikrokontroler do usypiania w trybie Power Save,
- odliczać czas budząc się ze snu co 8 sekund, w celu zmiany stanu diody LED,
- uśpić mikrokontroler natychmiast po wykonaniu przerwania,
- ... i tak w kółko punkty 3 i 4.
Poszczególne czynności opisałem w komentarzach poniżej, a całość możesz pobrać na końcu artykułu.
Pomiar prądu
W czasie testów dokonamy pomiarów zużycia prądu przez mikrokontroler uśpionym do trybu Power Save z pracującym Timer2.
W moim przypadku zasilając układ testowy z baterii CR2032 (bateria, którą wybraliśmy) o napięciu 3V, wynik jaki otrzymałem wynosił 7,8µA i jest zgodny z naszymi prognozami:
dd_licznik_czasu.c
dd_licznik_czasu.h
Pliki dot. licznika czasu zawierają funkcję inicjującą Timer2 w tryb pracy asynchronicznej oraz funkcję obsługi przerwania przepełnienia Timer2.
W funkcji dd_timer2_rtc_ini() zwrócić należy uwagę na pętlę while(), która oczekuje na potwierdzenie zakończenia ustawiania parametrów Timer2. Jest to bardzo istotne, ponieważ Timer2 pracuje w trybie asynchronicznym:
Plik dd_licznik_czasu.c:
/************************************************************************* * SmartPIP - Elektroniczny dręczyciel * * Data: kwiecień 2013 * Autor: Dondu * www: http://mikrokontrolery.blogspot.com/2011/04/SmartPIP-elektroniczny-dreczyciel-spis-tresci.html * * Plik: dd_licznik_czasu.c * Opis: Funkcjonalności dot. licznika czasu *************************************************************************/ #include <avr/io.h> #include <avr/interrupt.h> #include "dd_main.h" #include "dd_licznik_czasu.h" //------------------------------------------------------------------------- void dd_timer2_rtc_ini(void){ //Funkcja inicjująca timer2 w tryb asynchroniczny //wykorzystujący kwarc 32,768kHz //timer2 odpowiada za odliczanie czasu generuje przerwania 8 sekund //tryb asynchroniczny ASSR |= (1<<AS2); //preskaler //TCCR2 = (1<<CS22) | (1<<CS20); //128 (1sek) TCCR2 = (1<<CS22) | (1<<CS21) | (1<<CS20); //1024 (8sek) //zaczekaj, aż będzie można zmieniać ustawienia timera //pracującego w trybie asynchronicznym (patrz datasheet) while(ASSR & ((1<<TCN2UB) | (1<<OCR2UB) | (1<<TCR2UB))); //zeruj flagę przerwania Timer2 TIFR |= (1<<TOV2); //włącz przerwanie od przepełnienia timer2 TIMSK |= (1<<TOIE2); } //------------------------------------------------------------------------- ISR(TIMER2_OVF_vect){ //przerwanie przepełnienia Timer2 //jeżeli włączony tryb testowy (szczegóły w pliku dd_main.h) #ifdef TRYB_TEST LED_TEST_TOGGLE; //zmień stan diody LED na przeciwny #endif }
Aby móc skorzystać z funkcji dd_timer2_rtc_ini() w innych częściach programu, należy zdefiniować plik nagłówkowy i wskazać w nim, że funkcja dd_timer2_rtc_ini() jest funkcją zewnętrzną.
Plik nagłówkowy dd_licznik_czasu.h:
/************************************************************************* * SmartPIP - Elektroniczny dręczyciel * * Data: kwiecień 2013 * Autor: Dondu * www: http://mikrokontrolery.blogspot.com/2011/04/SmartPIP-elektroniczny-dreczyciel-spis-tresci.html * * Plik: dd_licznik_czasu.h * Opis: Plik nagłówkowy pliku dd_licznik_czasu.c *************************************************************************/ extern void dd_timer2_rtc_ini(void);
dd_main.c
dd_main.h
Pliki główne naszego projektu zawierają fragmenty dot. dobrych praktyk w celu oszczędzania energii i odporności na zakłócenia oraz główne elementy naszego testu, czyli przygotowanie mikrokontrolera do pracy oraz pętlę główną. W pętli głównej zgodnie z założeniami SmartPIP'a, znajduje się jedynie funkcja usypiająca mikrokontroler.
W pliku nagłówkowym znajdziesz definicje dot. diody LED. Nie wszystkie są wykorzystane, ale przydadzą się nam w dalszych artykułach. Zwróć uwagę na komentarz definicji TRYB_TEST. Ta definicja powoduje, że niektóre fragmenty naszego programu są brane pod uwagę lub nie. Dotyczy to fragmentów, które są nam potrzebne jedynie do testów.
Plik nagłówkowy dd_main.h:
/************************************************************************* * SmartPIP - Elektroniczny dręczyciel * * Data: kwiecień 2013 * Autor: Dondu * www: http://mikrokontrolery.blogspot.com/2011/04/SmartPIP-elektroniczny-dreczyciel-spis-tresci.html * * Plik: dd_main.h * Opis: Plik nagłówkowy pliku dd_main.c *************************************************************************/ //======= TESTOWE ===================== //Definicje do fragmentów programu wykorzystywanych do testów #define TRYB_TEST 1 //zakomentowanie tej linijki wyłącza tryb testowy #ifdef TRYB_TEST //definicje dot. testowej diody LED #define LED_TEST_DDR DDRB #define LED_TEST_PORT PORTB #define LED_TEST_PIN_NAZWA PB0 #define LED_TEST_ON LED_TEST_PORT &= ~(1<<LED_TEST_PIN_NAZWA) #define LED_TEST_OFF LED_TEST_PORT |= (1<<LED_TEST_PIN_NAZWA) #define LED_TEST_TOGGLE LED_TEST_PORT ^= (1<<LED_TEST_PIN_NAZWA) #endif
Plik dd_main.c:
/************************************************************************* * SmartPIP - Elektroniczny dręczyciel * * Data: kwiecień 2013 * Autor: Dondu * www: http://mikrokontrolery.blogspot.com/2011/04/SmartPIP-elektroniczny-dreczyciel-spis-tresci.html * * Plik: dd_main.c * Opis: Test licznika czasu opartego o Timer2 w trybie asynchronicznym * z kwarcem 32,768kHz (włączony fusebit CKOPT) i taktowaniem * mikrokontrolera wewnętrznym generatorem RC 1MHz * * Mikrokontroler: ATmega8A * Fusebity: low: 0xE1 * high: 0xC9 * Kompilator: GCC * * W opcjach projektu należy ustawić: zegar: 1000000Hz * optymalizację: -Os *************************************************************************/ #include <avr/io.h> #include <avr/interrupt.h> #include <avr/sleep.h> #include "dd_main.h" #include "dd_licznik_czasu.h" //------------------------------------------------------------------------- int main(void) { //--- Wyłącz zbędne moduły --- //w celu oszczędzania energii wyłączamy domyślnie włączony //moduł komparatora analogowego ACSR |= (1<<ACD); //wyłącz komparator analogowy //--- Dobre praktyki --- //Po resecie (włączeniu zasilania) piny ustawione są domyślnie jako //wejścia. Włączamy rezystory pull-up. To bardzo istotne w projektach //zasilanych z baterii! Dla ATmega8A włączamy wszystkie z wyjątkiem //pinu RESET ponieważ mamy tam podłączony zewnętrzny rezystor pull-up //szczegóły: http://mikrokontrolery.blogspot.com/2011/04/zakocenia-w-pracy-mikrokontrolerow.html PORTB = 0xff; //włącz wewnętrzne rezystory pull-up PORTC = 0xff; //włącz wewnętrzne rezystory pull-up PORTD = 0x3f; //włącz wewnętrzne rezystory pull-up //jeżeli włączony tryb testowy (szczegóły w pliku dd_main.h) #ifdef TRYB_TEST //Ustaw pin LED jako wyjście LED_TEST_DDR |= (1<<LED_TEST_PIN_NAZWA); LED_TEST_ON; #endif //włącz timer2 dd_timer2_rtc_ini(); //włącz przerwania globalne sei(); //ustaw tryb snu set_sleep_mode(SLEEP_MODE_PWR_SAVE); sleep_enable(); //pętla główna while(1){ //śpij koteczku :-) sleep_cpu(); } }
Pliki do pobrania
Projekt AVR Studio 4 (pliki projektu wraz z plikami .c, .h, .hex): DD_SmartPIP_Licznik_czasu.zip
Artykuł jest częścią cyklu: SmartPIP - Elektroniczny dręczyciel
Opublikowałem małą poprawkę do kodu. Pliki do pobrania także są poprawione.
OdpowiedzUsuńCześć. Czy na schemacie kwarc nie powinien być podłączony do masy przez dwa kondensatory?
OdpowiedzUsuńOk. Sorry nie docztałem. ;)
UsuńTak bywa :)
Usuń