Elemes kapcsolások alapjai

Egy kis elmélettel kezdünk. Az ATmega328P chip és az összes többi társa működés közben jelentősnek mondható, 10mA nagyságrendű áramot vesz fel. Megmértem, ha semmit nem kötök rá, akkor 12,5mA. Tegyük fel, hogy akkumulátorról akarjuk táplálni. Vegyünk pl. egy klasszikus 18650-es lítium aksit. Az egyik onkrét típus (HTCNR18650) adatlapja szerint feszültsége 3,6V, kapacitása 2200mAh. A feszültsége az adatlap alapján teljesen feltöltött állapotban kb. 4V, és merítéskor folyamatosan csökken kb. 3V-ig, ahol egy teljes lemerítés elleni védelem le fogja kapcsolni. Ez a teljes lemerítés elleni védelem azért kell, mert a lítium aksik túlmerítés hatására szeretnek kigyulladni. Ki ne emlékezne a Samsung eszközökre, amik maguktól elégtek. A lítium aksi ráadásul nem csak az éghető anyagot tartalmazza, van benne oxigén is, így hiába dobod be egy vödör vízbe, tovább ég vidáman.
De tegyük fel, hogy még nem ég, és teljesen feltöltöttük. Ez azt jelenti, hogy 12,5mA terheléssel 2200/12,5=176 órát, vagyis kb. egy hetet üzemelne az áramkör. Ez elég kevés. Ha pl. egy konyhai időzítőt szeretnénk üzemeltetni, hetente tölteni kellene, akkor is ha egyszer sem időzítünk vele. A chip csak várakozik arra, hogy megnyomjuk az start gombot, és közben sokat fogyaszt. Tegyük fel, hogy a konyhai időzítőnk miközben működik (visszaszámol egy kijelzővel) 100mA áramot fogyaszt. Ebbe az áramfelvételbe akár világító led kijelző használata is beleférhet. Ha egy időzítés 10perc, akkor hányszor használhatnánk? 2200/100=22óra. Ha tojásfőzéskor időzítünk vele, akkor egy időzítés 10 perc, tehát 132-szer használhatjuk. Ha minden nap főzünk tojást, ez akkor is legalább négy hónap, és ez kielégítő eredmény. Négy havonta fel kell tölteni az aksit!
Nincs más dolgunk, mint az időzítések közötti szünetekben valahogyan el kell érni, hogy ne vegyen fel a chip 12,5mA áramot. Ezek a szünetek akár napokig is tarthatnak (én pl. csak nagyon ritkán eszek főt tojást), Lehetne egy főkapcsoló is, amivel teljesen lekapcsoljuk az áramkört az időzítőn, de ez nem elegáns. Küldjük inkább a chip-et aludni.

Ha kikapcsoljuk a program végrehajtásra szolgáló áramköröket, az AD konvertert, és minden más alvás időben szükségtelen eszközt, akkor az áramfelvétel jelentősen csökkenni fog. Az ATmega328 adatlapja szerint egészen 4,2mikroA-ig lehet lemenni. Ekkor már csak egy belső oszcillátor időzítővel, valamint két bemenetet figyelő áramkör működik. Ha a belső időzítő elszámolt egy beállított értékig (maximum 8 másodperc), vagy a két bemenet valamelyikére jelet kapcsolunk, akkor a chip felébred, és csinálhat valamit. Aztán újra el lehet küldeni aludni, amikor csak akarjuk. A 4,2mikroA áram igen kicsi. Meddig is működik az akkumulátorról? 2200mA/4,2mikroA=~524000 óra, vagyis kb. 21000 nap, azaz 60 év. Ez persze csak elméleti érték, sok mindennel nem számoltam. Sajnos az akkumulátorok és ez elemek merülnek maguktól terhelés nélkül is, így nem számíthatunk 60 évre, esetleg akkumulátornál egy-két évre, de egy lítium gombelemnél ez 7 év is lehet. A drágább lítium elemekre a gyártók éveket garantálnak. Egy konkrét típusnál 20% kapacitáscsökkenés eléréséhez 7 évet adtak meg emlékeim szerint.

Na akkor nézzük végre hogyan is kell elaltatni a chip-et. Nyilvánvaló, hogy erre van kész könyvtár. Egy elalvásról szóló internetes leírásban ezt találtam meg: https://github.com/rocketscream/Low-Power
Nagyon fontos!!! Ez a könyvtár nem kezeli az ATmega8 chip-et. Nekem ebből több darab is van raktáron, és ez elszomorított, de ez van. Vannak más könyvtárak, melyek lényegesen több vezérlő típusra fel lettek készítve.
Használathoz le kell tölteni a github-on megtalálható állományt, átnevezni „LowPower.zip”-re, és a könyvtár kezelőben mint zip állományt beimportálni. Sajnos ez a könyvtár az Arduino Ide könyvtár kezelőjében nincs benne tapasztalatom szerint. De így is jó, nem túl bonyolult az importálás.

A példaprogramokat a fájl/példák menüben tudjuk elérni:

Nem igényel sok magyarázatot a használata, két mintapéldát próbáltam ki, ezeket kissé át is alakítottam. Direkt a kis áramú kísérletekhez vettem egy 50mA-es 4 tizedesjegyet mutató panelműszert. Biztosan nem egy labor műszer, de legalább értékes számjegyeket lehetett leolvasni, és nem 0-át mint a multiméteremről. Ennek a műszernek a felbontása 0,1mikroA. LED-et kötöttem a chip-re, és figyeltem az áramfelvétel alvó és működő állapotban is.

Időzített bekapcsolás:

#include "LowPower.h" // LowPower könyvtár használata

void setup()
{
  pinMode(2, OUTPUT); // led a 13-as kivezetésre kerül
}

void loop() 
{
    // az ATmega328P chip alvó bódba megy 4 másodpercre
    // kikapcsolja az  ADC és a BOD modulokat a chipben
    // áramfelvétel 6,2 mikroA (a műszerem 0,1 mikroA érzékenységű)
    LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_OFF); 
    // 4 másodperc után itt folytatódik a program
    // bakapcsolt led esetén kb 17,6 mA áramfelvétel (nálam ebből a led 7,5mA)
    // a chip áramfelvétele kb 12-13 mA
    digitalWrite(2, HIGH);   
    delay(10000);   
    // ha nem kapcsolom ki a LED-et, akkor elalváskor a chip kimenet magas értéken marad
    // és az áramfelvétel kb. 6,7 mA vagyis a LED továbbra is fogyaszt, miközben a chip alszik
    // a chip kimenetei továbbra is működnek, csal a belső program végrehajtó logika alszik                    
    digitalWrite(2, LOW);   
}

A következő eredmények születtek:

  • Alvó módban az áramfelvétel 6,2 mikroA
  • Amikor a LED világit (10sec), az áramfelvétel 17,6 mA
  • Lehúztam a LED-et, ekkor az áramfelvétel 12 mA, tehát a LED 5mA körüli áramot vesz fel.

Néhány hasznos tudnivaló a programhoz:

  • A lehetséges időzített alvási időtartamok 15ms, 30ms, 60ms, 120ms, 250ms, 500ms, 1s, 2s, 4s, 8s
  • Ha egy kimenetet magas állapotban hagyunk elalváskor, akkor az magas is marad, és a rá kötött áramkörök áramot vesznek fel. Pl. egy led világít alvó chip esetén is. Feltehetőleg ennek az az oka, hogy a chip alváskor a 16Mhz órajelet kapcsolja ki, és statikus állapotban befagy a végrehajtás, ott ahol tartott. Ilyenkor a chipet felépítő MOSFET áramkörök 0 teljesítményt vesznek fel, ennek köszönhető a kicsi fogyasztás. Azonban a chip tápfeszültsége be van kapcsolva, a kivezetések áramkörei működnek.
  • Az ADC az analóg digitális konvertert jelenti, azt külön ki kell kapcsolni, mert feltehetőleg nem a 16Mhz órajelről kapja az órajelet, és tovább működne. Ezért az ADC-OFF a powerDown függvényben.
  • A BOD áramkör a chip tápfeszültségét figyeli. Alapértelmezetten 2,7 voltnál kapcsolná ki teljesen a chip-et, így most erre sincs szükségünk., hisz az aksi védőáramköre nem sokkal 3V alatt magától kikapcsol. Feltételezem, hogy virtuális akkumulátorunkon van védő áramkör, nem akarjuk, hogy fejlesztő laborunk leégjen. Hagyományos cink elemeknél a BOD hiánya gondot okozhatna, mert azok 0V-ig merülnek, így bizonytalan lenne a helyzet 2,7V környékén. Azonban az elemekből túlmerítéskor kifolyó sav a nagyobb károkat okozna, mint a bizonytalan működés.

Bekapcsolás az egyik chip kivezetésre kapcsolt feszültséggel:

#include "LowPower.h" //LowPower könyvtár használata

void setup() {
  pinMode(2, INPUT);  //2-es kivezetés bemenet ez a 0-as megszakítás bemenete
  pinMode(13, OUTPUT);//13-as kivezetésre kötjük a LED-et
}

void loop() {
  // a 0-ás megszakítást használjuk, ami a 2-es láb
  // az esemény a megszakitas() függvényt hívja meg (és felébreszti a chip-et)
  // LOW, akkor hajtódik végre, a a láb logikai alacsony szinten van,
  // CHANGE, akkor halytódik végre, ha a láb logikai szintje megváltozik
  // RISING, akkor hajtódik végre, ha a láb logikai szintje alacsonyról magasra vált
  // FALLING, akkor hajtódik végre, ha a láb logikai szintje magasról alacsonyra vált 
  attachInterrupt(0, megszakitas, LOW);
    
  // elküldjük aludni a chip-et.
  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); 
    
  // tiltjuk a megszakítást, nehogy a következő programrészeket újra 
  // megszakítsa a nyomógomb ismételt lenyomása.
  detachInterrupt(0); 
   
  delay(4000);   //Ez nem müködne a megszakitas() függvényen belül  
  digitalWrite(13, LOW);   

}

void megszakitas()
{
  digitalWrite(13, HIGH); 
}

Fontos tudnivaló, hogy a megszakítással meghívott függvényekben nem működik a delay() függvény. Mivel a programban azt akartam, hogy a led 4 másodpercig világítson, a delay() csak a loop()-ba kerülhetett. Egyébként a led bekapcsolása kerülhetett volna oda is, csak így látható a programban, hogy a megszakitas() függvény is csinál valami!