[023] O zasilaniu Arduino z baterii

[023] O zasilaniu Arduino z baterii

Czas na kolejną dawkę wiedzy związaną z bateryjnym zasilaniem Arduino. Zmodyfikujmy szkic, który był bohaterem poprzedniego artykułu.


#define SEND_PWM_BY_TIMER  // Definicja niezbędna dla Arduino Uno związana z obsługą nadajnika podczerwieni.
#include <IRremote.h>      // Biblioteka obsługi nadajnika podczerwieni.

const byte pstryczekPrzerwan = 2;  // Adres linii przerwań (Dla Uno 2 lub 3, ale 3 jest już zajęty).
const unsigned int adres = 64482;  // Adres urządzenia, którym będziemy sterować.
const byte kodWylacz = 38;         // Kod wysyłany podczerwienią.

void setup() {
  IrSender.begin(DISABLE_LED_FEEDBACK);      // Inicjacja biblioteki nadajnika podczerwieni.
  pinMode(pstryczekPrzerwan, INPUT_PULLUP);  // Deklaruj linie przerwań jako wejścia podciągnięte wewnętrznie do wysokiego stanu.
}

void loop() {
  if (digitalRead(pstryczekPrzerwan) == LOW) {          // Jeśli pstryczek został wciśnięty...
    IrSender.sendNEC(adres, kodWylacz, 0);              // Wyślij w standardzie NEC: adres, komendę i bit braku autorepetycji.
    delay(50);                                          // Czekaj 50 ms
    while ((digitalRead(pstryczekPrzerwan) == LOW)) {}  // Czekaj dopóki przyciski zostanie zwolniony.
    delay(50);                                          // Czekaj 50 ms
  }
}

Jedyną zmianą będzie przełączenie przycisku na port drugi. Zmieniłem mu także nazwę. Zaraz wyjaśni się, dlaczego tak. Program ten konsumuje 11 mA, bez względu czy wysyłany jest komunikat przez port podczerwieni, czy też nic się nie dzieje. I właśnie określenie nic się nie dzieje jest kluczem do oszczędności. Dlaczego prąd płynie także wtedy, gdy bezproduktywnie czekamy na przyciśnięcie przycisku? A gdyby układ jakoś uśpić na ten czas? Ależ proszę bardzo.

#define SEND_PWM_BY_TIMER  // Definicja niezbędna dla Arduino Uno związana z obsługą nadajnika podczerwieni.
#include <IRremote.h>      // Biblioteka obsługi nadajnika podczerwieni.
#include <avr/sleep.h>     // Biblioteka zarządzająca zasilaniem mikrokontrolera.

const byte pstryczekPrzerwan = 2;  // Adres linii przerwań (Dla Uno 2 lub 3, ale 3 jest już zajęty).
const unsigned int adres = 64482;  // Adres urządzenia, którym będziemy sterować.
const byte kodWylacz = 38;         // Kod wysyłany podczerwienią.

void setup() {
  IrSender.begin(DISABLE_LED_FEEDBACK);      // Inicjacja biblioteki nadajnika podczerwieni.
  pinMode(pstryczekPrzerwan, INPUT_PULLUP);  // Deklaruj linie przerwań jako wejścia podciągnięte wewnętrznie do wysokiego stanu.
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);       // Włącz pełne usypianie.
  sleep_enable();                            // Uśpij mikrokontroler.
}

void loop() {
  IrSender.sendNEC(adres, kodWylacz, 0);              // Wyślij w standardzie NEC: adres, komendę i bit braku autorepetycji.
  while ((digitalRead(pstryczekPrzerwan) == LOW)) {}  // Czekaj dopóki przyciski zostanie zwolniony.
  delay(50);                                          // Czekaj 50 ms
  attachInterrupt(0, przerwanie, LOW);                // Aktywuj przerwania na kanale 0 niskim poziomem.
  sleep_mode();                                       // Uśpij mikrokontroler.
}

void przerwanie() {    // Gdy poziom niski pojawi się na kanale 0 (czyli na wejściu "przerwania"), obudź mikrokontroler.
  detachInterrupt(0);  // Wyłącz obsługę przerwań.
  delay(5);            // Zaczekaj 5 ms na pobudkę.
}

Do tego celu służy biblioteka avr/sleep. Nawet nie trzeba jej importować. Tutaj wybieramy sposób, w jaki mikrokontrloler będzie spać, bo może on to robić na wiele sposobów. Dziś jednak w szczegóły wchodzić nie będę.

set_sleep_mode(SLEEP_MODE_PWR_DOWN);       // Włącz pełne usypianie.

Tutaj układ zaśnie.

sleep_enable();                            // Uśpij mikrokontroler.

Byłoby po programie, gdyby nie dało się go jakoś obudzić. Do tego celu (i nie tylko do tego) służą przerwania. I znowu w uproszczony na dziś sposób wyjaśnię: przerwanie bezwzględnie przerywa procesy odbywające się na bieżąco, w szczególności tutaj – proces snu. Źródeł tych przerwań może być dużo, może to być wewnętrzny zegar albo nadejście komunikatu itd. Tutaj przerwanie zdarzy się na skutek zwarcia drugiego portu do masy. A że Arduino Uno i pochodne mogą nadać takie właściwości tylko portom 2 i 3, a trzeci jest już zajęty przez diodę, wyjaśniło się, dlaczego pstryczek trafił właśnie tutaj.

Po obudzeniu następuje wysłanie komunikatu, oczekiwanie na puszczenie przycisku, chwila oddechu, ponowna aktywacja wymienionego przerwania i sen.

IrSender.sendNEC(adres, kodWylacz, 0);              // Wyślij w standardzie NEC: adres, komendę i bit braku autorepetycji.
while ((digitalRead(pstryczekPrzerwan) == LOW)) {}  // Czekaj dopóki przyciski zostanie zwolniony.
delay(50);                                          // Czekaj 50 ms
attachInterrupt(0, przerwanie, LOW);                // Aktywuj przerwania na kanale 0 niskim poziomem.
sleep_mode();                                       // Uśpij mikrokontroler.

Spójrzmy na instrukcję attachInterrupt(0, przerwanie, LOW). Argument przerwanie informuje program, że po kolejnej pobudce procesor ma zaglądnąć w podprogram oznaczony tą etykietą.

void przerwanie() {    // Gdy poziom niski pojawi się na kanale 0 (czyli na wejściu "przerwania"), obudź mikrokontroler.
  detachInterrupt(0);  // Wyłącz obsługę przerwań.
  delay(5);            // Zaczekaj 5 ms na pobudkę.
}

Tutaj pierwszą instrukcją jest wyłączenie obsługi przerwań (bo właśnie nastąpiło), chwila oddechu na ustabilizowanie się prądów i powrót do pętli. A tam już, po wysłaniu komunikatu i puszczeniu przycisku znowu można będzie zasnąć. Zmierzmy sobie teraz prąd.

Czary jakieś, prąd przestał płynąć! No dobrze, nie jest aż tak idealnie, ale dużo lepiej. Układ konsumuje już tylko 120 mikroamperów, czyli 90 razy mniej. Ale to nie wszystko. Układ zawiera mnóstwo peryferiów i istnieje możliwość wyłączenia tych, których się nie używa. Dwie nowe instrukcje: ADCSRA = 0 oraz PRR = 0b00000111, wrzucone w sekcję setup wyłączą nam: przetwornik analogowo cyfrowy i porty szeregowe.

void setup() {
  IrSender.begin(DISABLE_LED_FEEDBACK);      // Inicjacja biblioteki nadajnika podczerwieni.
  pinMode(pstryczekPrzerwan, INPUT_PULLUP);  // Deklaruj linie przerwań jako wejścia podciągnięte wewnętrznie do wysokiego stanu.
  ADCSRA = 0;                                // Wyłącz przetwornik analogowo-cyfrowy.
  PRR = 0b00000111;                          // Wyłącz SPI, UART i ADC
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);       // Włącz pełne usypianie.
  sleep_enable();                            // Uśpij mikrokontroler.
}

Mierzymy i… teraz układ pobiera niecałe 19 mikroamperów, czyli prawie 600 razy mniej. Dwie bateryjki 2032 pozwolą na ciągłe działanie takiego układu przez ponad rok!

Wciąż jednak podczas trzymania przycisku prąd sięga jedenastu miliamperów. Co prawda w skali użycia takiego pilota taki stan będzie marnym procentem całości, lecz Krakus nie lubi marnować niczego. Użyjemy kolejnej biblioteki o ładnej nazwie Narcoleptic. Oferuje ona między innymi zamiennik funkcji Delay. Różni się tym, że także nic nie robi przez określony czas, ale podczas tego nicnierobienia usypia procesor. Pętla sprawdzająca puszczenie przycisku jest zatem usypiana na 50 ms, po czym następuje wybudzenie, sprawdzenie czy przycisk nadal jest wciśnięty i tak aż do skutku. Tak wygląda szkic ze wszystkimi modyfikacjami.

#define SEND_PWM_BY_TIMER  // Definicja niezbędna dla Arduino Uno związana z obsługą nadajnika podczerwieni.
#include <IRremote.h>      // Biblioteka obsługi nadajnika podczerwieni.
#include <avr/sleep.h>     // Biblioteka zarządzająca zasilaniem mikrokontrolera.
#include <Narcoleptic.h>   // Biblioteka oferująca "śpiący" delay.

const byte pstryczekPrzerwan = 2;  // Adres linii przerwań (Dla Uno 2 lub 3, ale 3 jest już zajęty).
const unsigned int adres = 64482;  // Adres urządzenia, którym będziemy sterować.
const byte kodWylacz = 38;         // Kod wysyłany podczerwienią.

void setup() {
  IrSender.begin(DISABLE_LED_FEEDBACK);      // Inicjacja biblioteki nadajnika podczerwieni.
  pinMode(pstryczekPrzerwan, INPUT_PULLUP);  // Deklaruj linie przerwań jako wejścia podciągnięte wewnętrznie do wysokiego stanu.
  ADCSRA = 0;                                // Wyłącz przetwornik analogowo-cyfrowy.
  PRR = 0b00000111;                          // Wyłącz SPI, UART i ADC
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);       // Włącz pełne usypianie.
  sleep_enable();                            // Uśpij mikrokontroler.
}

void loop() {
  IrSender.sendNEC(adres, kodWylacz, 0);             // Wyślij w standardzie NEC: adres, komendę i bit braku autorepetycji.
  while ((digitalRead(pstryczekPrzerwan) == LOW)) {  // Czekaj dopóki przyciski zostanie zwolniony.
    Narcoleptic.delay(50);                           // Powtarzaj pętlę co 50 ms
  }
  attachInterrupt(0, przerwanie, LOW);  // Aktywuj przerwania na kanale 0 niskim poziomem.
  sleep_mode();                         // Uśpij mikrokontroler.
}

void przerwanie() {      // Gdy poziom niski pojawi się na kanale 0 (czyli na wejściu "przerwania"), obudź mikrokontroler.
  detachInterrupt(0);    // Wyłącz obsługę przerwań.
  Narcoleptic.delay(5);  // Zaczekaj 5 ms na pobudkę.
}

Teraz już pobór prądu będzie duży wyłącznie podczas wysyłania komunikatu diodą podczerwieni. Ale to jest tak krótki czas, że właściwie do pominięcia. Na koniec jeszcze dwa problemy. Rok czasu z użyciem bateryjek to niby dużo, ale fabryczne piloty potrafią działać kilka lat i to na jednej baterii litowej. Da się jeszcze jakoś zaoszczędzić? Da się, używając wolniejszych układów bądź oszczędniejszych. Ale o tym innym razem.

A co będzie, jeśli będziemy chcieli zbudować pilota z większą liczbą przycisków? Żaden problem, aczkolwiek troszkę nam się rozbuduje schemat. Oto pilot z dwoma przyciskami.

Diody, które tu widzimy, sumują zwarcia tak, by jednocześnie zwierany był port przerwań, czyli drugi i dowolny inny – w tym wypadku ósmy albo dziewiąty. W głównej pętli należy jeszcze sprawdzać, który dodatkowo port ma stan niski i w zależności od tego wysyłać stosowny komunikat. W ten sposób możemy wykorzystać wszystkie porty.

Powiązane tematy

Płytka edukacyjna TME-EDU-ARD-2Płytka edukacyjna TME-EDU-ARD-2Sprawdź tutaj

Przeczytaj również

Nasi partnerzy

TMETech Master EventTME EducationPoweredby
Copyright © 2024 arduino.pl