Potřeboval jsem aplikaci s rozumně malou spotřebou (tedy nebylo nutné jít do extrému) schopnou zobrazovat jednoduché textové a číslicové informace a schopnou běžet z dvojice tužkových baterií. Prakticky by stačil i klasický "sedmisegmentový" LCD displej. Ten ale potřebuje připojit velké množství vývodů (25 pinů 3 ciferný a 33 pinů 4 ciferný). Nebo, pokud má mít vývodů méně, tak vyžaduje použít MCU s LCD driverem (viz např. STM32 LCD a nebo AVR LCD). Protože jsem chtěl aplikaci rychle zbastlit z THT komponent rozhodl jsem se zjistit jak a s jakou spotřebou by šla realizovat s klasickým alfanumerickým LCD s driverem HD44780, resp. ST7066. Zjistil jsem, že není problém udržet spotřebu pod 500uA. A jako boční produkt jsem dal dohromady aplikaci, která si bez dalších integrovaných obvodů udržuje kontrast pro různá napájecí napětí z rozsahu 2.3V až 5.5V. Testy jsem provedl na AVR128DA28, ale práci zvládne v podstatě jakýkoli jiný mikrokontrolér. Pokud vám něco z toho připadá zajímavé, čtěte dále.
Než se pustíme do práce, shrneme si několik důležitých informací.
Protože má být aplikace napájená z dvojice tužkových baterií, bude potřebovat generátor záporného napětí. To lze snadno připravit nábojovou pumpou realizovanou dvojicí diod D1 a D2, dvojicí kondenzátorů C1 a C2 a časovačem v MCU (viz schema, kde jsem pro znázornil i odporový dělič na displeji). Obecně pro lepší účinnost nábojové pumpy se diody D1 a D2 volí schottkyho (s nízkým prahovým napětím). Velikostí C1 ovlivňujeme zvlnění nábojové pumpy. Velikostí C2 spolu s frekvencí obdélníkového signálu (SQW) rozhodujeme o tom jak bude naše nábojová pumpa "měkká" či "tvrdá" (zjednodušeně řečeno jaký proud z ní bude možné odebírat). Záměrně zatím neuvádím konkrétní hodnoty komponent, neboť pro různá řešení budou různé.
Uvažujme že budeme aplikaci napájet minimálním provozním napětím LCD driveru - tedy 2.7V (případně standardních 2.8V). V takovém případě je vhodné nábojovou pumpu sestavit z křemíkových diod namísto schottkyho. Nábojová pumpa se dvěma schottkyho diodami bude generovat na svém výstupu napětí 2.7V snížené o dva úbytky diod (řekněme o dvakrát 0.35V). Výstup pumpy tedy bude okolo -2.1V. Tím vznikne na děliči napětí okolo 4.8V (2.7+2.1). Výsledkem takové situace bude lehce "přepálený" kontrast, který bude kazit vzhled. Ale také tím vzroste spotřeba děliče na 4.8V/(5*4k7)=204uA. Větší úbytek na křemíkových diodách (řekněme dvakrát 0.6V) sníží výstupní napětí nábojové pumpy na -1.5V, čímž se napětí na děliči dostane na výhodnou hodnotu 4.2V. Kontrast bude optimální a spotřeba děličem bude přibližně 4.2V/23k5=179uA. Pro jistotu zopakuji že spotřeba děličem se musí do celkové spotřeby počítat dvakrát (kvůli nábojové pumpě). Celkově tím tedy ušetříme okolo 2*(204-179)=50uA.
Můžeme nedodržet minimální provozní napětí LCD driveru 2.7V a a napájet aplikaci například běžnějším napětím 2.5V (například nízkoodběrovým regulátorem MCP1700). V takovém případě se hodí zvolit jednu z diod jako schottkyho a druhou jako křemíkovou a nastavit tím kontrast (a spotřebu) do optima. Své opodstatnění má také kombinace kdy jsou obě diody schottkyho. Taková volba sice drobně zvýší spotřebu (kontrast 4.6V namísto optimálních 4.0V až 4.2V), ale umožní aplikaci udržet se v činnosti při nižším napětí (až do 2.2V).
Kontrast by měl být teoreticky závislý na teplotě, takže je potřeba všechny výše uvedené hodnoty brát s odpovídající rezervou. Platí jen pro pokojové teploty.
Test jsem realizoval na AVR128DA28. Displej byl připojen na piny PA1 až PA7. Výstup pro nábojovou pumpu na PC0. Knihovna pro ovládání displeje ke stažení. Napájení 2.5V, D1 (1N4148), D2 (noname schottky), C1,C2=22uF. Displej RC2004A-YHW-CSX (viz foto). Dále zběžně otestováno též na displeji DEM 16101 TGH/V (mimochodem displej má mizerný kontrast - i při běžném použití). Myšlenka je jednoduchá, takže příklad lze snadno přesnét na libovolný MCU, který má nějaký časovač a je schopen pracovat v nějakém rozumně úsporném režimu.
/* A) Jednoduchá varianta * Aplikace pomocí TCA0 generuje na PC0 obdélníkový průběh o frekvenci 8kHz sloužící jako signál pro nábojovou pumpu * Každou sekundu se aplikace probudí ze spánku (Standby) a pošle na displej "užitečnou informaci" * časovač je nastaven aby pracoval i v režimu spánku. Ze spánku se probouzíme pomocí PIT časovače. * Během nečinnosti jsou komunikační linky s displejem v neutrální úrovni (D4 až D7 jsou v HiZ a RS,RW v úrovni High) */ #include <avr/io.h> #include <avr/interrupt.h> #include "avr1_hd44780.h" // knihovna pro práci s LCD displejem, (F_CPU je definováno jako 32768) #include <avr/xmega.h> // kvůli makru _PROTECTED_WRITE #include <avr/sleep.h> // kvůli funkcím pro práci s režimem spánku #include "stdio.h" // kvůli snprintf() char text[18]; // ať máme kam formátovat text, který budeme zobrazovat na displeji uint16_t pocitadlo=0; // něco užitečného na práci void init_sqw(void); void init_pit(void); int main(void){ // přepni clock čipu na vnitřní 32kHz oscilátor _PROTECTED_WRITE(CLKCTRL.OSC32KCTRLA, CLKCTRL_RUNSTDBY_bm); // 32k oscilátor má běžet i ve STANDY BY režimu (potřebuje ho timer TCA0) _PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSC32K_gc); // volí 32kHz oscilátor jako zdroj clocku init_sqw(); // spustíme časovač TCA0 pro nábojovou pumpu lcd_init(); // inicializujeme LCD (4bit režim) lcd_bus_sleep(); // uvolníme komunikační linky (viz "pullupy" v textu) init_pit(); // inicializujeme "periodic interrupt timer" sei(); // povolíme přerušení aby nás PIT mohl budit set_sleep_mode(SLEEP_MODE_STANDBY); // volíme režim spánku sleep_enable(); // povolujeme uspávání while (1){ pocitadlo++; // děláme "užitečnou činnost" - počítáme sekundy snprintf(text,sizeof(text),"pocitadlo: %5u",pocitadlo); // zobrazujeme "užitečnou činnost" lcd_bus_wakeup(); // připravíme komunikační linky pro displej (viz "pullupy" v textu) lcd_gotoxy(0,0); // vypíšeme zprávu na displej lcd_puts(text); lcd_bus_sleep(); // uvolníme komunikační linky (viz "pullupy" v textu) sleep_cpu(); // není co dělat, jdeme spát... } } // rutina přerušení od PIT ISR(RTC_PIT_vect){ RTC.PITINTFLAGS = RTC_PI_bm; // mažeme vlajku přerušení // není co dělat ... jen se probudíme :) } // inicializace periodického probouzení void init_pit(void){ RTC.CLKSEL = RTC_CLKSEL_OSC32K_gc; // volíme 32k oscilátor jako zdroj clocku pro RTC/PIT RTC.PITINTCTRL = RTC_PI_bm; // povolujeme přerušení od PIT while(RTC.PITSTATUS & RTC_CTRLABUSY_bm){} // počkáme dokud neproběhne případný předchozí zápis do RTC.CTRLA RTC.PITCTRLA = RTC_PERIOD_CYC32768_gc | RTC_PITEN_bm; // volíme periodu 1s a povolujeme PIT } // inicializace časovače pro nábojovou pumpu void init_sqw(void){ PORTC.DIRSET = PIN0_bm; // PC0 jako výstup PORTMUX.TCAROUTEA = PORTMUX_TCA0_PORTC_gc; // remapujeme funkce TCA0 na PORTC (na piny PC0 a případně další) TCA0.SINGLE.CMP0 = 1; // nastavuji periodu 8kHz (možná by bylo vhodnější volit CMP0=0 => 16kHz) TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_WGMODE_FRQ_gc; // povoluji výstup na PC0 a volím režim Frequency Generation // volíme clock (32kHz), povolujeme chod časovače ve spánku, spouštíme časovač TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm | TCA_SINGLE_RUNSTDBY_bm; //TCA0.SINGLE.DBGCTRL = TCA_SINGLE_DBGRUN_bm; // povolujeme chod při debugu (není nutné pokud nedebugujeme) }
V této konfiguraci činila spotřeba celé aplikace přibližně 480uA. Testoval jsem provoz od 2.2V a displej (s ST7066U) pracoval správně. Netuším zda došlo k nějakému "zpomalení" v komunikaci atp. neboť MCU byl značně podtaktován (32kHz), takže nebyl schopen provádět komunikaci rychlostmi ani zdaleka se blížícími limitům driveru. Pokračování v podobě složitější varianty, která udržuje kontrast na konstantní hodnotě se dočkáte v příštím díle.
Home
| V1.10 6.7.2021 /
| By Michal Dudka (m.dudka@seznam.cz) /