Mikrokontrolery - Jak zacząć?

... czyli zbiór praktycznej wiedzy dot. mikrokontrolerów.

poniedziałek, 4 kwietnia 2011

SmartPIP - Licznik czasu - testowanie


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:
  1. zainicjować Timer2 w tryb pracy z kwarcem 32,768kHz i wybranym preskalerem,
  2. przygotować mikrokontroler do usypiania w trybie Power Save,
  3. odliczać czas budząc się ze snu co 8 sekund, w celu zmiany stanu diody LED,
  4. uśpić mikrokontroler natychmiast po wykonaniu przerwania,
  5. ... 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

Oceń artykuł.
Wasze opinie są dla nas ważne, gdyż pozwalają dopracować poszczególne artykuły.
Pozdrawiamy, Autorzy
Ten artykuł oceniam na:

4 komentarze:

  1. Opublikowałem małą poprawkę do kodu. Pliki do pobrania także są poprawione.

    OdpowiedzUsuń
  2. Cześć. Czy na schemacie kwarc nie powinien być podłączony do masy przez dwa kondensatory?

    OdpowiedzUsuń

Działy
Działy dodatkowe
Inne
O blogu




Dzisiaj
--> za darmo!!! <--
1. USBasp
2. microBOARD M8


Napisz artykuł
--> i wygraj nagrodę. <--


Co nowego na blogu?
Śledź naszego Facebook-a



Co nowego na blogu?
Śledź nas na Google+

/* 20140911 Wyłączona prawa kolumna */
  • 00

    dni

  • 00

    godzin

  • :
  • 00

    minut

  • :
  • 00

    sekund

Nie czekaj do ostatniego dnia!
Jakość opisu projektu także jest istotna (pkt 9.2 regulaminu).

Sponsorzy:

Zapamiętaj ten artykuł w moim prywatnym spisie treści.