Žena potřebovala napájet fotopast z olověného akumulátoru. Potřeboval jsem tedy jednoduché zařízení, které fotopast (zátěž) odpojí kdžy napětí akumulátoru klesne pod jistou mez. A zase připojí zpět když je akumulátor nabitý. Tuto práci by hravě zvládnul komparátor s hysterezí, ale protože jsem neměl v šuplíkových zásobách žádný s rozumně nízkým odběrem (hrozí že baterie bude ve vybitém stavu dlouho čeká na výměnu), rozhodl jsem se zařízení zrealizovat mikropočítačem. Jednak proto že je vcelku snadné stáhnout spotřebu do oblasti uA a pak také proto že se mi tu roky válelo několik již nepotřebných Attiny13A a chtěl jsem jim dát šanci :)
Zapojení je přímočaré. Jako regulátor napětí (IC2) jsem zvolil MCP1703. V prvé řadě má velmi nízký odběr (typicky 2uA) a také má slušnou přesnost výstupního napětí (0.4%), což je velmi žádoucí protože díky tomu může zároveň posloužit jako reference AD převodníku v MCU k zajištění přesného měření napětí akumulátoru. Snese maximální napětí 16V, což by mělo stačit, protože provozní napětí olověných akumulátorů jsou pod 15V. Dělič napětí složený z R1 a R2 dělí v poměru přibližně 1:3.2, takže typické maximální napětí akumulátoru (14.4V) odpovídá napětí na vstupu MCU 4.5V. Přičemž klidový odběr děliče nepřekračuje typicky 4uA. Kondenzátor C4 slouží jako zásoba náboje aby AD převod nezatěžoval dělič. Ke spínání zátěže slouží nízkonapěťový MOSFET LGE2312 (Q1). Pulldown R3 má za úkol držet MOSFET zavřený v okamžiku kdy MCU startuje po zapojení napájení.
Program je přímočarý. Watchdog je nastaven do režimu časovače a každé 4s MCU probudí a nechá ho vykonat kód v hlavní smyčce. V ní změří napětí, porovná je se zvolenými limity a podle toho připojí nebo odpojí zátěž a zase usne. Aby program nereagoval na krátkodobé změny napětí akumulátoru způsobené například odběrem zátěže, je potřeba aby rozhodovací úroveň napětí byla překročena třikrát po sobě (tedy v trvání více jak 12s). Pro úsporu energie jsou vypnuty všechny nevyužité periferie, všechny nepoužité piny mají aktivovaný pullup rezistor aby na nich byla "legální" logická úroveň. A stejně tak je mimo dobu používání vypnutý i AD převodník. Rozhodovací úrovně jsou nastaveny na přibližně 11V (vypnutí zátěže) a 12V (zapnutí zátěže).
/* * Attiny13A Odpojovac * Created: 24.08.2024 10:15:50 * Author : mdudk */ // Clock 9.6MHz/8 = 1.2MHz // PB3 ADC input (divider from battery 2M2 + 1M || 100n) // PB4 MOSFET output #include <avr/io.h> #include <avr/interrupt.h> #include <avr/sleep.h> #include <avr/wdt.h> #define TURN_OFF_THR 695 // 11.0V #define TURN_ON_THR 755 // 12.0V #define DISABLE_LOAD PORTB &=~(1<<4) // vypnout MOSFET (zátěž) #define ENABLE_LOAD PORTB |= (1<<4) // zapnout MOSFET (zátěž) uint16_t get_volt(void); uint16_t volt; // změřené napětí uint8_t counter=0; // jednoduchý filtr // Rutina přerušení od "watchdog timeru" ISR(WDT_vect) { asm("nop"); // není co dělat, jde jen o to se probudit } int main(void){ PRR = (1<<PRTIM0) | (1<<PRADC); // vypnout clock periferiím ACSR = (1<<ACD); // vypnout komparátor DDRB = 1<<4; // nastavit PB4 jako výstup (MOSFET) PORTB = 0b100111; // zapnout pullup rezistory na nevyužitých pinech ADMUX = 0b11; // Zvolit VCC jako refrenci pro ADC a jako vstup pin PB3 (ADC3) DIDR0 = 0b111111; // Vypnout vstupní buffery na všech pinech WDTCR |= (1<<WDP3); // PErioda pro watchdog přibližně 4s WDTCR |= (1<<WDTIE); // spustit watchdog v režimu "časovače" sei(); // globální povolení přerušení set_sleep_mode(SLEEP_MODE_PWR_DOWN); // volím režim spánku Power Down (nejhlubší) while (1){ // kdykoli se čip probudí volt = get_volt(); // změří napětí if(volt < TURN_OFF_THR){ // pokud je menší jak "vypínací" napětí if(counter > 3){ // alespoň třikrát po sobě DISABLE_LOAD; // tak vypne zátěž }else{ // pokud ještě nebylo třikrát po sobě counter++; // započítá ho } }else if(volt > TURN_ON_THR){ // pokud je napětí větší jak "zapínací" if(counter > 3){ // alespoň třikrát po sobě ENABLE_LOAD; // zapne zátěž }else{ counter++; } }else{ // jinak nuluje počítadlo / filtr counter = 0; } sleep_mode(); // MCU jde spát asm("nop"); // to je tu asi zbytečně (možná jsem to tam měl kvůli debugu) asm("nop"); // to je tu asi zbytečně } } // funkce pro měření napětí uint16_t get_volt(void){ uint16_t tmp; PRR &=~(1<<PRADC); // nejprve zpět povolí clock pro ADC DIDR0 = 0b111111; // tohle je tu asi navíc ADMUX = 0b11; // Zvolit VCC jako refrenci pro ADC a jako vstup pin PB3 (ADC3) ADCSRA = (1<<ADEN) | (1<<ADPS1); // Zapne ADC s clokem 1.2MHz / 4 = 300kHz ADCSRA |= (1<<ADSC); // spustí převod while(ADCSRA & (1<<ADSC)){} // počká na jeho dokončení tmp = ADC; // vyčte výsledek ADCSRA = 0; // vypne ADC PRR = (1<<PRTIM0) | (1<<PRADC); // vypne clock všem periferiím (tedy i ADC, timer už ho má vypnutý) return tmp; // vrátí výsledek převodu }
Celkový odběr je přibližně 16uA při 12.8V. DPS má rozměry 26x29mm, k připojení k baterii slouží kabel s fastony. Na připojení k fotopasti pak kabel s "DC jack" konektorem. Programování mikropočítače je možné provést skrze ISP konektor na desce, nebo třeba v nepájivém poli ještě před osazením. DPS jsem nechával vyrábět v JLC PCB a vycházela na rovnou stokorunu i s poštovným (5ks DPS).
Home
| V1.00 07.12.2024 /
| By Michal Dudka (m.dudka@seznam.cz) /