// // ATtiny13: Vylepseni baterioveho testeru BT-168D o LED, ktera meni barvy podle stavu baterie // ============================================================================================ // verze: 17.4.2018 // // Tester ma funkci Data-Hold, ktera zobrazuje hodnotu napeti baterie pri prvnim pripojeni baterie. // Kdyz ale napeti zatizene baterie zacne po chvili rychle klesat, na displeji sviti porad puvodni cislo. // Proto je jeden vystup ATtiny pouzit pro pravidelne resetovani merice (odpojeni napajeni zobrazovaciho obvodu pomoci P-FET tranzistoru). // Testovani poklesu napeti se provadi kazde 2 sekundy. // Kdyz merene napeti behem teto doby klesne asi o dve desetiny voltu od posledni zaznamenane hodnoty, provede se reset. // // Detaily: // http://www.astromik.org/raspi/battester/ //=============================================================================================== // Zapojeni: //============= // ATtiny13 // +--\__/--+ // (RESET) - PB5 1| |8 Vcc - napajeni // vstup 9V (pres delic) (ADC3) - PB3 2| |7 PB2 - ovladani P-FET tranzistoru (odpojovani napajeni zobrazovaciho obvodu) // vstup 1.5V (na primo) (ADC2) - PB4 3| |6 PB1 - (OC0B) zelena LED (Anoda) // GND 4| |5 PB0 - (OC0A) cervena LED (Anoda) // +--------+ //-------------------------------------------------------------------------------------------------------------- // prirazeni pinu #define pin_cervena_LED 0 // cervena LED na PB0 #define pin_zelena_LED 1 // zelena LED na PB1 #define pin_FET 2 // ovladani FETu na PB2 #define pin_analog15 2 // mereni napeti 1.5V na ADC2 (= PB4 = noha 3) #define pin_analog90 3 // mereni napeti 9V na ADC3 (= PB3 = noha 2) #define pocet_smycek 40 // po kolika pruchodech hlavni smyckou se rozepne FET (kdyz byl zaznamenan pokles mereneho napeti) (1 smycka = 48ms; 20 smycek jsou asi 2s) #define delka_resetu 4 // kolik smycek trva drzeni resetovaciho pinu v HIGH (odpojene napajeni pro zobrazovaci obvod) (4 smycky = asi 0.2 sekundy) #define zelenou 1 // parametry pro podprogram na rozsveceni LED .... napriklad: "rozsvit(zlutou);" #define zlutou 2 #define cervenou 3 //nastaveni napetovych hranic pro prepinani barvy LED a zmena napeti, pri ktere dochazi k resetu zobrazovaci jednotky // napajeci referencni napeti = 3.3V, tomu odpovida prevod na digitalni cislo 1023 // priklad vypoctu: (1V/3.3V) * 1023 = 310 #define GL15 310 // hranice pro Good/Low pro 1.5V (cislo 310 = 1.0V) #define LR15 297 // hranice pro Low/Replace pro 1.5V (cislo 297 = 0.9V) #define RESET15 62 // pri jake zmene napeti na 1.5V vstupu se provadi reset (cislo 62 = 0.2V) // na 9V vstupu je navic jeste delic napeti 51k + 10k (snizovaci pomer je 0.16393) // priklad vypoctu: (6.5V/3.3V) * 1023 * 0.16393 = 330 #define GL90 330 // hranice pro Good/Low pro 9V (cislo 330 = 6.5V) #define LR90 269 // hranice pro Low/Replace pro 9V (cislo 269 = 5.3V) #define RESET90 10 // pri jake zmene napeti na 9V vstupu se provadi reset (cislo 10 = 0.2V) //-------------------------------------------------------------------------------------------------------------- // globalni promenne unsigned int napeti; // zmerena hodnota na aktivnim analogovyem vstupu unsigned int minule_mereni; // zmerene napeti pri poslednim resetu (kdyz se aktualni napeti snizi asi o 0.2V, provede se dalsi reset) boolean baterie15; // znacka, jestli se meri 1.5V baterie (= true), nebo 9V baterie (= false) byte casovani = pocet_smycek; // odpocet smycek pred testem rozdilu napeti od posledniho resetu byte odpocet_resetu = delka_resetu; // odpocet smycek pri resetu boolean resetuj = false; // pomocna znacka, jestli se ma provest reset zobrazovaciho obvodu boolean blikbarva = false ; // zluta barva, ktera byla vytvorena rozsvicenim obou LED, byla nevyrazna. Proto se pri zlute jeste zaroven rychle blika. //-------------------------------------------------------------------------------------------------------------- void setup(void) { // nastaveni smeru pinu pinMode(pin_cervena_LED,OUTPUT); pinMode(pin_zelena_LED,OUTPUT); pinMode(pin_FET,OUTPUT); digitalWrite(pin_FET,LOW); // FET hned na zacatku otevrit a tim zapnout napajeni do mericiho obvodu delay(100); // pred dalsim postupem nechat trochu casu mericimu obvodu na pripojeni zateze (po tu dobu je barevna LED zhasnuta) napeti = prumeruj(pin_analog15); // zjisti hodnotu na 1.5V vstupu if (napeti > 200) // kdyz je na pinu pro mereni 1.5V baterie napeti vyssi nez 0.65V, znamena to, ze je tam pripojena 1.5V baterie { baterie15 = true; // meri se 1.5V baterie minule_mereni = napeti; // aktualni hodnota napeti pro porovnavani kvuli pripadnemu resetovani } else { baterie15 = false; // meri se 9V baterie minule_mereni = prumeruj(pin_analog90); // aktualni hodnota napeti pro porovnavani kvuli pripadnemu resetovani } } //-------------------------------------------------------------------------------------------------------------- // hlavni smycka void loop(void) { // ----------------------------------------------- // mereni (vcetne prumerovani 8 hodnot) napeti ze spravneho vstupu podle typu merene baterie if (baterie15 == true) // Kdyz se meri 1.5V baterie ... { napeti = prumeruj(pin_analog15); // ... zjisti hodnotu na 1.5V vstupu. // A podle hodnoty rozsvit patricnou LED if (napeti > GL15) rozsvit(zelenou); // pasmo GOOD pro 1.5V if (napeti > LR15 and napeti <= GL15) rozsvit(zlutou); // pasmo LOW pro 1.5V if (napeti <= LR15) rozsvit(cervenou); // pasmo REPLACE pro 1.5V } else { napeti = prumeruj(pin_analog90); // V opacnem pripade zjisti hodnotu na 9V vstupu. // A podle hodnoty rozsvit patricnou LED if (napeti > GL90) rozsvit(zelenou); // pasmo GOOD pro 9V if (napeti > LR90 and napeti <= GL90) rozsvit(zlutou); // pasmo LOW pro 9V if (napeti <= LR90) rozsvit(cervenou); // pasmo REPLACE pro 9V } // ----------------------------------------------- // cast, ktera zjistuje, jestli doslo od minule k poklesu napeti alespon o 0.2V (test se provadi, jen kdyz 'casovani' dojde do 0 - to je asi kazde 2 sekundy) casovani--; // V kazde smycce se od 'casovani' odecte 1 if (casovani == 0) // Kdyz dojde 'casovani' do 0, porovna se aktualni hodnota s hodnotou, ktera byla pri minulem resetu { if (baterie15 == true) // Pro 1.5V a pro 9V baterie jsou ruzne hodnoty odpovidajici zmene o 0.2V. { if (abs_rozdil(minule_mereni, napeti) > RESET15) // Pro 1.5V baterii: Kdyz je rozdil napeti pri poslednim resetu a aktualniho napeti vic nez 0.2V ... { resetuj = true; // ... provede se reset zobrazovaciho obvodu. } } else { if (abs_rozdil(minule_mereni, napeti) > RESET90) //Pro 9V baterii: Kdyz je rozdil napeti pri poslednim resetu a aktualniho napeti vic nez 0.2V ... { resetuj = true; // ... provede se reset zobrazovaciho obvodu. } } casovani = pocet_smycek; // Odpocet smycek se nastavi na preddefinovanou hodnotu. Reset se muze provest jen v pripade, ze tohle pocitadlo dojde do 0. } // ----------------------------------------------- // cast, ktera se stara o reset zobrazovaciho obvodu, ktery trva predem stanoveny pocet smycek if (resetuj == true) // kdyz se v teto smycce zjistilo, ze merene napeti pokleslo od minule o vic, nez 0.2V ... { digitalWrite(pin_FET,HIGH); // ... FET rozepnout (odpojit napajeni zobrazovaciho obvodu) if (odpocet_resetu > 0) // Kdyz je v pocitadle delky trvani resetu co odecitat, ... { odpocet_resetu --; // ... tak se odecte jednicka } else // Kdyz uz neni co odecitat ... { digitalWrite(pin_FET,LOW); // ... FET zase zpatky sepnout a tim pripojit zobrazovaci obvod na napajeni. minule_mereni = napeti; // Pro pristi porovnavani se bude pouzivat aktualni napeti. odpocet_resetu = delka_resetu; // A take se pro pristi reset nastavi delka trvani toho resetu. resetuj = false; // Znacku pro resetovani zrusit. Nahodit se muze az v okamziku, kdy poklesne napeti o alespon 0.2V a 'casovani' dobehne do 0 } } } //-------------------------------------------------------------------------------------------------------------- // podprogram pro rozsveceni LED void rozsvit (byte ledka) { switch (ledka) { case zelenou: // rozsviti zelenou, zhasne cervenou digitalWrite(pin_zelena_LED,true); digitalWrite(pin_cervena_LED,false); break; case zlutou: // zluta barva se dala od cervene spatne rozeznat, proto se pri zlute barve provadi jeste rychle blikani (10Hz) if (blikbarva == true) { digitalWrite(pin_zelena_LED,false); digitalWrite(pin_cervena_LED,false); blikbarva = false; } else { digitalWrite(pin_zelena_LED,true); digitalWrite(pin_cervena_LED,true); blikbarva = true; } break; case cervenou: // zhasne zelenou, rozsviti cervenou digitalWrite(pin_zelena_LED,false); digitalWrite(pin_cervena_LED,true); break; } } //-------------------------------------------------------------------------------------------------------------- // prumerovani 8 hodnot (cislo 8 bylo zvoleno kvuli jednoduchemu binarnimu deleni na konci vypoctu) unsigned int prumeruj(byte pin) { unsigned int suma = 0; for (byte i = 0; i < 8; i ++) // 8 vzorku { suma = suma + analogRead(pin); // poscitavat vsech 8 namerenych hodnot dohromady delay(6); // hlavni pauza, ktera urcuje rychlost blikani zlute LED a cas mezi testy napeti pro pripadny reset meridla // frekvence blikani zlute LED: f[Hz] = 1 / ( delay[s] * 16 ) pro delay(6) je frekvence 10Hz // cas testovani napeti pro reset: t[s] = pocet_smycek * delay[s] * 8 pro dealy(6) a 40 smycek je cas asi 2s } suma = suma >> 3; // na zaver soucet vydelit 8 return suma; } //-------------------------------------------------------------------------------------------------------------- // Vypocet rozdilu dvou napeti (v absolutni hodnote) unsigned int abs_rozdil(unsigned int A, unsigned int B) { if ( A > B) { return A - B; } else { return B - A; } }