perjantai 1. toukokuuta 2020

AKKUTESTERI 56

Kuva 1. Testeri kotelossaan päältä nähtynä
Tämän projektin tähtäimenä oli rakentaa testeri, millä voi tutkia akun jäljellä olevan kapasiteetin. Käyttö on sellaisia olosuhteita varten, missä aurinkopaneeleilla tai / ja tuuligeneraattoreilla ladataan akkuja. Toisin sanoen tilanteessa, missä verkkosähköä ei ole käytettävissä akkujen lataamiseen.
Näissä olosuhteissa on tyypillisesti useita akkuja rinnan. Ne voivat hyvinkin olla eri ikäisiä, ja tavoitteena on akku kerrallaan tutkia, onko kyseinen akku vielä käyttöön riittävä, vai syytä vaihtaa uuteen. Tämä ei ole mikään tarkkuusmittalaite, vaan pyrkimyksenä on saada tietää mitatun akun käyttökelpoisuus.

Kuva 2. Lataus- ja purkuvirtojen reittien kytkentä.
Kuva 3. Laite alta. Ylhäällä kuormituslamput.


Vaatimuksena ja edellytyksenä on siis mahdollisuus ladata testattava akku muista akuista. Suositeltavaa onkin aloittaa testaus silloin, kun akut ovat mahdollisimman täynnä. Tällöin lataukseen kuluu aikaa mahdollisimman vähän.
Kuormaksi on mahdollista valita yhdestä kolmeen 20 W lamppua. Kun kaikki kolme ovat käytössä, on kuorman virta noin 5 A, mikä on suurin piirtein sama, minkä esim. tuollainen Peltier-elementillä toimiva pieni jääkaappi. Testi toisin sanoen testi kertoo suoraan, miten kauan testattava akku pystyisi syöttämään tuollaista jääkaappia.


Annoin yllä ymmärtää, että laitteen tarkkuus ei ole kovin hyvä. Virhetekijöitä on mm. seuraavia:
  1. Akku ladataan noin 7 A virralla 14,5 V:n jännitteeseen. Akku ei välttämättä ole täysin latautunut jännitteen käväistessä tuossa tasossa. Tilannetta parantaa tosin se seikka, että lataus pulssituksen kautta tapahtuu siten että 2 s latausta ja 1 s taukoa. Tähän suurin syy on kuitenkin jäähdytyslevynä toimivan alumiinisen U-palkin pienuus. Se taas johtuu siitä, että kotelo vaihtui kehityksen aikana suuremmaksi.
  2. Kuva 4. Aikamoinen sotku.
    Hall-generaattorin (LCB-050B) mittausalue on 50 A. Joten esim. 5 A kuormalla tarkkuus ei voi olla juurikaan 10 % parempi.
  3. Akku puretaan 11 V tasoon. Tällöin akku ei ole täysin tyhjä, vaan kapasiteettia on vielä jäljellä. Tämä taso säästää akkua. Syvemmästä purkauksesta ei tässä tapauksessa ole mitään hyötyä, sillä (testimittauksissa ilmennyt) noin 70 – 80 % tarkkuus kertoo kyllä mainiosti akun käyttökelpoisuuden jatkossa.
  Laitetta on rakennettu ja kokeiltu pienissä erissä. Sisäkuvasta näkee, että se ei sovi kenellekään malliksi ja ohjeeksi; korkeintaan varoittavaksi esimerkiksi.
Kuva 5. Hakkuriohjaimen kytkentä.
Kuva 6. Erillisten releiden kytkentä. Koskettimet näkyvät kuvassa 2.
Alussa ohjelma tuntui varsin yksinkertaiselta. Ladataan akku, puretaan se ja samalla mitataan kuorman virta sekunnin välein, jaetaan lopuksi luvulla 3600, ja saadaan näin akun kapasiteetti ampeeritunneissa. Lopuksi ladataan akku.
Periaatteessa kylläkin näin. Tuota ajatusta vastaan sotii tieto, että esim. alla oleva ohjelma on versio 14. Eri ohjelmia syntyi kaikkiaan 36 kappaletta. Jotain pieniä yksityiskohtia piti kehittää erikseen. Suurin syy tähän oli häiriöt. Tässä käsitellään kuitenkin melko suuria tehoja, mitkä aiheuttavat jännitepiikkejä. Yksi ongelma on myös minussa. En suunnittele etukäteen sopivia komponentteja, vaan pengon laatikoita ja valitsen siltä, mitä löytyy ja mitkä saattaisivat olla soveltavissa. Tässä toimii jälleen vana viisaus: ”Älä tee niin kuin minä teen, vaan tee niin kuin minä sanon!”
Alussa käytössä oli ”sopiva” ja laadukas induktanssi. Nyt hakkurin (mikä siirtää tehoa akusta toiseen) teho nousi yli 200 watin, joten käytössä ollut neljän releen yksikkö (4 Relay Module) otti nokkiinsa, totesi että nyt riitti, katkoi painitun piirin kalvoja ja ilmoitti mielipiteensä savumerkein.
Piti rakentaa uusi yksikkö tukevammin relein. Käytin siinä autojen varaosareleitä (12 V 20/30 A). Samalla pienensin hakkurin oskillaattorin pulssisuhdetta ja latausvirtaa.
Yksi iso ongelma pysyi kuitenkin melko tiukasti mukana. Se oli häiriö, mikä sotki LCD-näytön. Näytöllä pyöri ihan mitä sattuu juuri kun testi oli edennyt ja Ah-lukema pian luettavissa. Tähän oleellisin ratkaisu oli ottaa LCD-näytön 5 V:n syöttö Arduinon vastaavasta lähdöstä. Silti muutama suodatuskonkka releiden kytkimissä oli paikallaan.
Laitteessa on myös reset-painike, sillä kytkettäessä laite akkuun (A1, syöttävä), on hetkellinen virtapulssi melko suuri. Kun akut on kytketty, onkin hyvä painaa resettiä, jonka jälkeen ohjelma latautuu uudestaan, ja kuorma voidaan valita ja testi käynnistää.



LAITTEEN KÄYTTÖ:
 
Muutama sana ohjelmasta ja käytöstä: Ensin kytketään laitteen liittimet syöttävään akkuun (A1). Kun näyttöön ilmestyy kehotus valita purkausteho ja käynnistys, voidaan liittimet kytkeä testattavaan akkuun (A2). Käynnistyksen jälkeen ohjelma tutkiin, ettei akkujen jännite-ero ole liian suuri. Seuraavaksi tutkitaan, onko akussa A1 riittävä jännite (yli 13,5 V). Jos kaikki on tähän saakka kunnossa, alkaa latausvaihe. Aluksi lataus tapahtuu induktanssin ja diodin kautta akkuun A2. Hetken perästä kytkeytyy hakkuri kahdeksi sekunniksi ja ”pumppaa” virtaa akkuun A2. Samalla valvotaan, ettei akun A1 jännite putoa alle 12 V:n. Jos näin tapahtuu, palataan edelliseen askeleeseen ja odotetaan, että syöttävän jännite on taas yli 13,5 volttia. Näin jatketaan kunnes testattava akku on ”täynnä”. Sen jälkeen irrotetaan akku A1 testattavasta akusta, puretaan akku ja mitataan kapasiteetti. Lopuksi ladataan akku ilman virtapumppausta. Jos akkujen jännite-ero (A1 – A2 < 0,5 V) on riittävä pieni, kytketään akut suoraan yhteen. Nämä eri vaiheet tulostetaan LCD-näytölle.


 
Ohjelma 56

/* Nimi: A_Kapa56_v14
Luotu: 30.04.2020
Luoja: Antti Isännäinen

KUVAUS:
Pyrkimyksenä on tutkia akun jäljellä oleva kapasiteetti
ympäristössä, missä enenergiaa talletetaan useisiin
rinnakkain kytkettyihin akkuihin. Ja missä energia
tuotetaan arinkopaneeleilla ja tuuligeneraattoreilla.
*/

// MÄÄRITTELYT:
#include <LiquidCrystal.h>
LiquidCrystal lcd(3, 2, 7,6,5,4);
const byte api = B11100001;

// Kellon määrittely
unsigned long Ulo_MilliSek = 0;
unsigned long Ulo_UusiMilliSek = 0;
unsigned long Ulo_PulsMiSek = 0;
int Int_Viive = 100;
int Int_LCDvii = 300;
int Int_Sekunti = 0;
int Int_ViSek = 0;
boolean Bol_LCD_tulostus = false;
unsigned long Ulo_UusiLCD = 0;
boolean Bol_AskelViive = false;
// Tekstit
char tx1[] = "V";
char tx2[] = "A";
char tx3[] = "A1";
char tx4[] = "A2";
char tx5[] = "VAL. KUORMA => START";
char tx6[] = "Kuorma: 3 == 5.25 A";
char tx7[] = "Kuorma: 2 == 3.50 A";
char tx8[] = "Kuorma: 1 == 1.75 A";
char tx9[] = "VALMISTELUT:";
char tx10[] = "ODOTTAA: A1>13.5V";
char tx11[] = "A2 LATAUS";
char tx12[] = "A2 PURKAUS";
char tx13[] = "VALMIS";
char tx14[] = "AKUT KYTKETTY YHTEEN";
char tx15[] = "Ah";

// Analogiatulot
const int Con_A1V = 0;
const int Con_A2V = 1;
const int Con_Virta = 2;

// Muuttujat
int Int_A1raaka = 0;
float A1_Jannite = 0.00;
int Int_A2raaka = 0;
float A2_Jannite = 0.00;
int Int_VirtaPohja = 0;
int Int_Virta = 0;
float Flo_Virta = 0.00;
boolean Bol_Summaus = false;
int Int_Kapasi = 0;
float Flo_Kapasi = 0.00;
float Flo_U_Ero = 0.00;

// Kuormituksen ja käynnistyksen valinta
const int Con_Start = 18;
boolean Bol_Start = false;
const int Con_Kuorma = 19;
boolean Bol_Kuorma = false;
int Seq_Kuorma = 1;
const int Con_K1 = 8;
const int Con_K2 = 10;
const int Con_K3 = 9;
const int Con_K4 = 11;
const int Con_Pulssi = 13;
boolean Bol_Pulssi = false;
int Int_Lamput = 3;
int Seq_Mittaus = 0;

// ALIOHJELMAT
// Näytön aliohjelmat
// Tekstien päivitys
void Fun_Teksti(int kohta, int rivi, char teksti[]){
   lcd.setCursor(kohta, rivi);
   lcd.print(teksti);
}// Teksti_ali loppu

//Numeroiden päivitys
void Fun_Mittaus(int kohta, int rivi, float lukema){
   lcd.setCursor(kohta, rivi);
   lcd.print(lukema);
}// Mittaus_ali loppu

// Releyksikön aliohjelma
void Fun_Rele(int k1,int k2,int k3,int k4){
   delay(50);
     digitalWrite(Con_K1, k1);
     digitalWrite(Con_K2, k2);
     digitalWrite(Con_K3, k3);
     digitalWrite(Con_K4, k4);
   delay(100);
}// Rele aliohjelman loppu

// Kuormavalinnan aliohjelma
void Fun_Kuormitus(int valinta){
   switch (valinta) {
   case 1:
     Fun_Teksti(0, 1, tx8);
   break;
   case 2:
     Fun_Teksti(0, 1, tx7);
   break;
   case 3:
     Fun_Teksti(0, 1, tx6);
   break;
   }// Sekvenssi loppu
}// Kuormitusvalinnan aliohjelman loppu

// ASETUKSET:
void setup(){
   Serial.begin(9600);
   lcd.begin(20,2);
   Fun_Teksti(0, 0, tx5);
   Fun_Teksti(0, 1, tx6);
   pinMode(Con_Kuorma, INPUT_PULLUP);
   pinMode(Con_Start, INPUT_PULLUP);
   pinMode(Con_K1, OUTPUT);
   pinMode(Con_K2, OUTPUT);
   pinMode(Con_K3, OUTPUT);
   pinMode(Con_K4, OUTPUT);
   pinMode(Con_Pulssi, OUTPUT);
   Fun_Rele(1, 0, 0, 0); // Asetetaan releiden perusasetus
   delay(Int_Viive * 7);
   Int_VirtaPohja = analogRead(Con_Virta);
   Ulo_UusiMilliSek = millis();
}// Asetuksen loppu

// PÄÄLOOPPI
void loop(){
  Ulo_MilliSek = millis();
  if(Ulo_MilliSek > Ulo_UusiMilliSek + (Int_Viive * 10)){
     Bol_Summaus = true;
     Int_Sekunti += 1;
     Int_ViSek += 1;
     Ulo_UusiMilliSek = millis();
} // Tahdistus loppu

// LCD-näytön tahdistus
if(Seq_Mittaus > 0){
   if(Ulo_MilliSek > Ulo_UusiLCD + Int_LCDvii){
     Bol_LCD_tulostus = true;
     lcd.clear();
     Ulo_UusiLCD = millis();
}} // Näytön päivityksen loppu

//Mittaukset
Int_A1raaka = analogRead(Con_A1V);
A1_Jannite = Int_A1raaka / 60.176;
Int_A2raaka = analogRead(Con_A2V);
A2_Jannite = Int_A2raaka / 60.176;
Int_Virta = analogRead(Con_Virta);
Int_Virta = Int_Virta - Int_VirtaPohja;
Flo_Virta = Int_Virta * 0.11;

// Kytkimet
Bol_Kuorma = !digitalRead(Con_Kuorma);
Bol_Start = !digitalRead(Con_Start);
if(Bol_Start == true && Seq_Kuorma > 0){
   Seq_Mittaus = 1;
   Seq_Kuorma = 0;
   Int_ViSek = 0;
} // Kuormavalinta loppu

// Kuormavalinnan sekvenssi
switch (Seq_Kuorma) {
   case 1:
     if(Bol_Kuorma == true && Ulo_MilliSek - Ulo_UusiMilliSek > (Int_Viive * 2)){
       Ulo_UusiMilliSek = Ulo_MilliSek;
       Int_Lamput --;if(Int_Lamput == 0){Int_Lamput = 3;}
       Fun_Kuormitus(Int_Lamput);
       Seq_Kuorma = 2;
   }
   break;
   case 2:
     if(Bol_Kuorma == false){Seq_Kuorma = 1;}
   break;
  }// Sekvenssin loppu

// PÄÄSEKVENSSI
// Akun kapasiteetin mittaussekvenssi
switch (Seq_Mittaus) {
   case 1: // Valmistelut
     if(Bol_LCD_tulostus == true){
       Fun_Teksti(0, 0, tx9);
       Fun_Teksti(0, 1, tx3);
       Fun_Teksti(11, 1, tx4);
       Fun_Mittaus(3, 1, A1_Jannite);
       Fun_Teksti(8, 1, tx1);
       Fun_Mittaus(14, 1, A2_Jannite);
       Fun_Teksti(19, 1, tx1);
} // LCD-tulostus
// Tarkastetaan, ettei akkujen jännite-ero ole liian suuri
   if(A2_Jannite > (A1_Jannite - 2.0)){
     if(Int_ViSek > 3){
       Seq_Mittaus = 2;
       Int_ViSek = 0;
   }// Viiven loppu
}// Jännitetarkastuksen loppu
break;
case 2: // Odottaa, että A1 > 13.5 V
   if(Bol_LCD_tulostus == true){
       Fun_Mittaus(3, 1, A1_Jannite);
       Fun_Teksti(8, 1, tx1);
       Fun_Teksti(0, 0, tx10);
       Fun_Teksti(0, 1, tx3);
       Fun_Teksti(11, 1, tx4);
       Fun_Teksti(19, 1, tx1);
       Fun_Mittaus(3, 1, A1_Jannite);
       Fun_Mittaus(14, 1, A2_Jannite);
   } // LCD-tulostus loppu
   if(A1_Jannite > 13.5 && Int_ViSek > 3){
       Int_ViSek = 0;
       Ulo_PulsMiSek = Ulo_MilliSek;
       Bol_Pulssi = true;
       Seq_Mittaus = 3;
   } // Jännite ja viivetarkastus loppu
break;
case 3: // Latausaskel
   if(Bol_LCD_tulostus == true){
       Fun_Teksti(0, 0, tx11);
       Fun_Teksti(0, 1, tx3);
       Fun_Teksti(8, 1, tx1);
       Fun_Teksti(11, 1, tx4);
       Fun_Teksti(19, 1, tx1);
       Fun_Mittaus(3, 1, A1_Jannite);
       Fun_Mittaus(14, 1, A2_Jannite);
       Fun_Mittaus(11, 0, -1 * Flo_Virta);
       Fun_Teksti(15, 0, tx2);
   } // LCD-tulostus loppu
   Fun_Rele(0, 0, 0, 0);
   if(Bol_Pulssi == true && Ulo_MilliSek > Ulo_PulsMiSek + 2000){
       Ulo_PulsMiSek = Ulo_MilliSek;
       Bol_Pulssi = false;
   } // Pulssitus päällä
   if(Bol_Pulssi == false && Ulo_MilliSek > Ulo_PulsMiSek + 1000){
       Ulo_PulsMiSek = Ulo_MilliSek;
       Bol_Pulssi = true;
   } // Pulssitus pois päältä
   digitalWrite(Con_Pulssi, Bol_Pulssi);

// Tarkastetaan, onko ladattava akku täysi
   if(A2_Jannite > 14.5){
       Bol_Pulssi = false; digitalWrite(Con_Pulssi, Bol_Pulssi);
       Int_ViSek = 0;
       Seq_Mittaus = 4;
   } // Latausgeneraattorin pysäytys loppu
// Tarkastetaan, laskeeko syöttöjännite liikaa
   if(A1_Jannite < 12.0){
       Bol_Pulssi = false; digitalWrite(Con_Pulssi, Bol_Pulssi);
       Seq_Mittaus = 2;}
   break;
   case 4: // Akun purkaus
   if(Bol_Summaus == true){
       Flo_Kapasi = Flo_Kapasi + 1 * Flo_Virta;
}// Kapasiteetin keruun loppu
   if(Bol_LCD_tulostus == true){
       Fun_Teksti(0, 0, tx12);
       Fun_Teksti(0, 0, tx12);
       Fun_Teksti(15, 1, tx2);
       Fun_Mittaus(12, 0, Flo_Kapasi / 3600);
       Fun_Teksti(17, 0, tx15);
       Fun_Teksti(0, 1, tx4);
       Fun_Teksti(8, 1, tx1);
       Fun_Mittaus(3, 1, A2_Jannite);
       Fun_Mittaus(11, 1, 1 * Flo_Virta);
   } // LCD-tulostus loppu
// Valitaan asettettu kuorma
   if(Int_Lamput == 3){Fun_Rele(1,1,1,0);}
       else if(Int_Lamput == 2){Fun_Rele(1,0,1,0);}
       else {Fun_Rele(1,1,0,0);}
   if(Int_ViSek > 5 && A2_Jannite < 11.0){
       Seq_Mittaus = 5;
       Int_ViSek = 0;
   }// viiven loppu
   break;
   case 5: // Lataus
     if(Bol_LCD_tulostus == true){
       Fun_Teksti(0, 0, tx11);
       Fun_Mittaus(11, 0, Flo_Kapasi / 3600);
       Fun_Teksti(17, 0, tx15);
       Fun_Teksti(0, 1, tx3);
       Fun_Mittaus(3, 1, A1_Jannite);
       Fun_Teksti(8, 1, tx1);
       Fun_Teksti(11, 1, tx4);
       Fun_Mittaus(14, 1, A2_Jannite);
       Fun_Teksti(19, 1, tx1);
   } // LCD-tulostus loppu
   Fun_Rele(0, 0, 0, 0);
   Flo_U_Ero = A1_Jannite - A2_Jannite;
   if(Int_ViSek > 5 && Flo_U_Ero < 0.5){
       Seq_Mittaus = 6;
       Int_ViSek = 0;
   }// viiven loppu
                        break; 
 case 6: // Valmis
   if(Bol_LCD_tulostus == true){
       Fun_Teksti(0, 0, tx13);
       Fun_Teksti(8, 0, tx4);
       Fun_Mittaus(11, 0, Flo_Kapasi / 3600);
       Fun_Teksti(17, 0, tx15);
       Fun_Teksti(0, 1, tx14);
   } // LCD-tulostus loppu
   Fun_Rele(1, 0, 0, 1);
break;
}// Mittaussekvenssi loppu

Bol_Summaus = false;
Bol_LCD_tulostus = false;
Bol_AskelViive = false;
delay(1);
} // Pääohjelma LOPPU

sunnuntai 29. syyskuuta 2019

MUUTAMIA TESTEJÄ

Kun näiden mikrokontrollerilevyjen parissa puuhailee ja kokeilee, niin silloin tällöin sattuu vahinkoja (puhun omasta kokemuksestani). Tämän jakson ideana on muutama pieni ja yksinkertainen ohjelma, joilla voi testata, onko Arduino kunnossa, ja miltä osin. Jos piirilevy ei vastaa työkaluohjelman lataustoimintaan, tulee ko. piiristä harmi. Toki siitä on hyvä käyttää joitakin toimivia osia, kuten liittimiä, LEDejä, 5 V-regulaattoria ja mahdollisesti joitain muitakin komponentteja.

 On toki mahdollista, että on onnistunut tuhoamaan ainoastaan jonkun I/O:n. Tämänkertainen jakso tähtää nimenomaan liityntöjen testaukseen. Enin osa testeistä on tehty Arduino UNO:lla. Joitakin myös Arduino LEONARDOLLA, mutta muut kuvassa näkyvät piirit eivät osallistuneet näiden ohjelmien kehitykseen.

 
HUOM! Noissa kaikissa kolmessa ohjelman määrittelyosiossa on mukana myös sarjaliikenne ohjelmointityökalulle (Serial.begin(9600);). Se ei ole tarpeen näiden testiohjelmien kannalta, mutta hyvähän sen on siellä olla, jos tekee muutoksia ohjelmaan ja haluaa ajankohtaista dataa näytölle.


DIGITAALILÄHDÖT
Ensimmäisenä on lähtöpinnien testaus. Niitähän on 12 kpl (D/I 2 .. 13). Mutta sen lisäksi analogiatulot (A0 .. A5) voidaan määritellä (14 .. 19) ja käyttää myös digitaalisena (paitsi LEONARDO, jossa täten toimivat vain A0 ja A1). Kokemukseni mukaan aiemmin myös D/I-pinnit D0 ja D1 olivat määriteltävissä tuloiksi ja lähdöiksi, mutta näissä testeissäni se ei onnistunut. Ne on nähtävästi täysin ”pyhitetty” sarjaliikenteelle. DIO0 on RX (sarjadatan tulo) ja DIO1 on TX (sarjadatan lähtö).

Indikaationa (ei kaivanne kytkentäkaaviota) voi olla esim. 1 kohm (sopiva valinta, sillä se etuvastuksena ei kuormita lähtöpinniä liikaa) vastus sarjassa LEDin kanssa. Eli: lähtöpinni, vastus, LED ja maa. (LEDin pitää olla oikein päin kytkettynä). Kun vastus vaihdetaan eri pinneihin, vilkahtaa myös levyllä oleva (OUT13 LED) säännöllisin välein
. Aika koostuu LOOPista 50 + 50 ms, sekä siitä, että luuppi käy läpi kaikki 17 lähtöä. Kun ulkoinen LED välähtää, toimii kyseinen lähtö oikein.

/***************************************
* OUT_Test_1
* 26.09.2019
* I/O-pinnien OUTput - testaus
**************************************/

// ASETUKSET:
void setup(){
Serial.begin(9600);
// Asetetaan DIGI ja ANA I/O-pinnit lähdöiksi
for(int i = 2;i <= 19; i ++){
   pinMode(i, OUTPUT);}
}// Asetuksen loppu

// PÄÄLOOPPI
void loop(){
for(int j = 2; j <= 19; j++){
   digitalWrite(j, HIGH);
   delay(50);
   digitalWrite(j, LOW);
   delay(50);
}
delay(1);
} // Pääohjelma LOPPU


DIGITAALITULOT
Tässä toisessa ohjelmassa käydään läpi kaikki digitaalitulot paitsi DIO-13, minkä LEDiä käytetään indikaattorina. Sen vuoksi se määritellään erikseen OUT-bitiksi. Muut määritellään kahdella eri luupilla tuloiksi, joissa on sisäinen ylös veto vastus (INPUT_PULLUP). Myös pääohjelma jakaantuu tämän vuoksi kahdeksi FOR-luupiksi. Kun jonkin tuloista kytkee maahan, suorittaa ohjelma aliohjelmakutsun. Tällöin piirilevyllä oleva LED (DIO-13) vilkkuu. Kyseinen tulopinni toimii siis oikein.

/***************************************
* IN_Test_1
* 26.09.2019
* I/O-pinnien INput - testaus
**************************************/
// Määrittlyt
int LEDout = 13;
boolean tila = false;

// LEDin aliohjelma
void Fun_LED(){
   digitalWrite(LEDout, HIGH);
   delay(150);
   digitalWrite(LEDout, LOW);
   delay(150);
}

// ASETUKSET:
void setup(){
Serial.begin(9600);
// Asetetaan pinnin 13 LED lähdöksi
pinMode(LEDout, OUTPUT);
// Asetetaan varsinaiset I/O-pinnit tuloiksi
for(int i = 2;i <= 12; i ++){
   pinMode(i, INPUT_PULLUP);}
// Asetetaan ANAlogia pinnit tuloiksi
for(int i = 14;i <= 19; i ++){
   pinMode(i, INPUT_PULLUP);}
}// Asetuksen loppu

// PÄÄLOOPPI
void loop(){
for(int j = 2; j <= 12; j++){
   tila = !digitalRead(j);
   if(tila == true){Fun_LED();}
} // for loppu
for(int j = 14; j <= 19; j++){
   tila = !digitalRead(j);
   if(tila == true){Fun_LED();}
} // for loppu
delay(1);
} // Pääohjelma LOPPU


ANALOGIATULOT
Tässä kolmannessa testiohjelmassa tutkitaan analogiatulojen toiminta. UNOssa ja LEONARDOssa niitä on kuusi (A0 .. A5) kappaletta. Niiden tulojännitealue on 0 .. 5 V. Tämä voidaan syöttää ulkopuolelta tai tehdä niin, että potentiometrin äärinavat kytketään Arduinon maan (GND) ja 5 V:n lähdön väliin ja potentiometrin liu'ulta viedään jännite mitattavaan analogiatuloon. Indikaattoriksi tähän testiin voidaan käyttää ensimmäisen testin LED / vastusyhdistelmää, kytkettynä johonkin analogialähtöön (PWM, pulssinleveysmodulaatio). Tässä ohjelmassa on käytetty lähtöä DO3. Lähdön jännite vaihtelee noin 1 kHz taajuudella nollan (0 V) ja viiden (5 V) voltin välillä, mutta näiden jännitteiden aikasuhde muuttuu ohjauksen mukaan. Analogiatulon muunnos on 10 bittinen, eli lukualue on 0 .. 1023 ja lähdön lukualue kahdeksan (8) bittinen, eli 0 .. 255, joten tuloarvo pitää jakaa neljällä. Kun potentiometria, säätää, vaihtuu tulojännite, minkä muutos ilmenee LEDin kirkkauden vaihteluna. Vaihtamalla potikan johtoa eri tuloihin voi tarkastaa jokaisen tulon toimivuus.


/***************************************
* ANA_Test_3
* 27.09.2019
* Muutetaan analogia-arvojen tuloarvo
* LEDin kirkkaudeksi
**************************************/

// MÄÄRITTELYT:
int Ana_Raaka = 0;
int Ana_Out = 0;
int PWM_LED = 3;

// ASETUKSET:
void setup(){
Serial.begin(9600);
}// Asetuksen loppu

// PÄÄLOOPPI
void loop(){
for(int i = 0; i <= 5; i++){
   Ana_Raaka = analogRead(i);
   Ana_Out = Ana_Raaka / 4;
   Ana_Out = constrain(Ana_Out, 0, 255);
}
analogWrite(PWM_LED, Ana_Out);
delay(1);
} // Pääohjelma LOPPU

maanantai 24. kesäkuuta 2019

AKUN KAPASITEETTIMITTAUS I

Otsikossa on ykkönen sen vuoksi, että tähän akun kapasiteetin mittaukseen akku pitää ladata ulkoisella laturilla esim. verkkovirrasta. Seuraavan (II) sovelluksen on tarkoitus sopia olosuhteisiin, missä verkkovirtaa ei ole käytettävissä, vaan sähkövarastona käytettäviä akkuja ladataan aurinkopaneeleilla tai tuuligeneraattoreilla. Testattavana oleva akku ladataan siis toisten akkujen avulla.

Akkukin kuluu käytössä, joten on hyvä tietää paljonko akussa on kapasiteettia jäljellä. Tässä mittarissa purkauksen kuormituksena on lamppuja ( 1 .. 3, 21 W lamppua, 1,75 .. 5,25 ampeeria) ja virran mittaukseen käytetään Hall-anturia (alue 0 .. 50 A). Anturin mittausalue on huomattavasti laajempi kuin purkausvirrat, joten kovin hyvään tarkkuuteen (muutama %) ei päästä, mutta se ei ole tarpeenkaan, sillä tarkoituksena on saada selville, onko akku vielä käyttökelpoinen vai syytä jo vaihtaa uuteen. Tuo 5 ampeerin virta on samaa luokkaa, mitä 12 V:n Peltier-elementillä toimiva jääkaappi kuluttaa, joten tämä on hyvä tutkimus juuri mökkikäyttöön.

Tämän päivän trendi on tallettaa energiaa, sillä enemmän ja enemmän ollaan siirtymässä sähköllä toimiviin laitteisiin. Energiaa saamme auringosta. Vaahtoamme uusiutuvasta energiasta. Tuuligeneraattorit, aurinkopaneelit, aurinkokeräimet jne. Ihan hyvä ja tällä hetkellä erittäin tärkeä argumentti, mutta tuo tuonne alkuun lykkäämäni sana ”vaahtoamme” johtuu siitä, että ihmisille halutaan antaa ”mielikuva” siitä, että auringon energia olisi uusiutuvaa. Ei ole! Aurinko muuttaa vedyn fuusioreaktiossa syntyvän energian fotovirraksi, mistä me saamme osamme (maapallon puolisko on vain pieni pläntti avaruudessa). Auringon vety ei uusiudu, sitä ei tule mistään lisää, mutta sen loppumista meistä kukaan tällä hetkellä täällä ihmettelevä ei tule näkemään. Käytetään siis sitä hyvällä omallatunnolla, sillä sen käyttö ei lisää kasvihuoneilmiötä, eikä se meidän elinaikanamme juurikaan vähene, eikä tulevien tuhansienkaan sukupolvien aikana sitä tee.

Nyt olen hiukan heikoilla jäillä. Etsin kyllä netistä ja tietosanakirjoista ja muista teknisistä lähteistä, mutta en oikein löytänyt tukea opiskeluaikani käsitykselle, että akun kapasiteetti standardin mukaan ilmoitetaan 10% purkausajalla. Toisin sanoen, jos akun kapasiteetiksi ilmoitetaan 100 Ah, niin 10 A:in virralla se pystyy syöttämään virtaa 10 tunnin ajan (lopussa 12 V:n akun jännite on noin 10,5 V). Tälle en löytänyt tukea, mutta kuten myöhemmin tässä käy ilmi, niin erisuuruisilla purkausvirroilla akun kapasiteetiksi saadaan erilaisia arvoja. Jos tuo standardi pitää paikkansa, niin kaupallisesti on tarjolla akkuja, joiden ampeerituntimäärä (Ah) on merkitty 20 tunnin aikana (5% purkausvirta kapasiteetista). Täten halutaan ostajalle antaa standardia positiivisempi mielikuva. Myös latausvirran olisi hyvä olla 10% kapasiteetista. Akutkin kehittyvät ja niitä voidaan myös pika ladata. Se tosin jossain määrin lyhentää akun käyttöikää.

Näissä testeissä olen käyttänyt vanhoja, käytöstä poistettuja akkuja. Ne ovat sopivia juuri tähän tarkoitukseen, sillä niiden kapasiteetit ovat hyvin vähissä, mistä johtuen purkautumista ei tarvitse odotella pitkään.
Esimerkki: purkausvirran vaikutuksesta akun kapasiteettiin: Testissä oli vanha 75 Ah akku, jossa oli jäljellä muutama ampeeritunti. Yhden lampun purkauksella (noin 1,7 A) kapasiteetiksi tuli 8,4 Ah ja kolmen lampun purkauksella noin 7 Ah. Kapasiteetti pieneni siis noin 17,5 %.

Tällä kerralla en ole piirtänyt kytkentäkaaviota. Tuo kuvassa näkyvä ”rakkine” ei ole varsinaisesti mikään laite, vaan alusta, mille on helppo kytkeä erilaisia yksikköjä vaihdellen aina tarpeen ja meneillään olevan ”projektin” mukaan. Sen pohja on sähköisen eriste (akryyliä), joten ei tarvitse huolehtia painettujen piirien oikosuluista.

Kun johdot on kytketty akkuun, tulee LCD-näyttöön kehotus käynnistyksestä. Koska ihminen on hätäinen (varsinkin tekniikasta kiinnostunut), alkaa laite mittaamaan ampeerisekunteja (Asek). Koko mittauksen ajan virta luetaan ja summataan sekunnin välein. Kun ensimmäinen minuutti on ohi, näyttöön päivittyy ampeeriminuutit (Amin). Saatu summa jaetaan nyt luvulla 60. Kun tunti tulee täyteen, päivittyvät ampeeritunnit (Atun Oikeastihan ne ovat As, Amin ja Ah) ja summa jaetaan luvulla 3600.

Kytkimillä voidaan valita 1, 2 tai 3 kpl 21 W:in lamppua kuormaksi. Kun akun jännite on laskenut 10,5 V:iin, päästää rele ja näyttöön ilmestyy kokonaisampeerimäärä sekä akun jännite, mikä hiukan nousee kuormituksen loputtua. Jos jännite laskee alle tuon rajan jo sekuntien tai minuuttien aikana, vapautuu kuorma ja näyttöön jää sen hetkinen kapasiteetti ja jännitearvo 10,5 V. Näyttöä ei enää päivitetä.



Ohjelmasta
Aluksi määritellään vakiot ja muuttujat. Asetuksissa (suoritetaan ainoastaan kerran) päivitetään ensimmäinen näyttö. Sen jälkeen on 1 s tauko, jotta tilanne stabiloituu. Sitten talletetaan Hall-generaattorin pohjalukema, mikä on noin puolet käyttöjännitteestä (5 V). Hall-generaattori mittaa magneettikentän voimakkuutta, joten ympäristökin vaikuttaa tähän pohjalukemaan. Siksi se pitää kerran tallettaa. Virran suunta joko kasvattaa tätä generaattorin lähtöarvoa tai pienentää sitä. Tämän arvon ja pohjalukeman erotuksesta muodostetaan mitattu virta-arvo. Lopuksi asetuksissa määritellään painike tuloksi ja rele lähdöksi.

Itse toimiva ohjelma muodostuu muutamasta sekvenssiaskeleesta ja parista aliohjelmasta. Toisessa aliohjelmassa päivitetään näytön tekstejä ja toisessa mitattuja numeroarvoja.

Ohjelma57
/***************************************
* AkunKapa
* 22.06.2019
* Akunkapasiteettimittaus.
**************************************/

// MÄÄRITTELYT:
// LCD-näyttö
   #include <LiquidCrystal.h>
   LiquidCrystal lcd(3, 2, 7,6,5,4);
   const byte api = B11100001; // ä

// Mittaukset
   const int Con_Akku = 0; // Akun jännitteen mittaus
   int Int_AkkuRaaka = 0;
   const int Con_Virta = 1; // Purkausvirran mittaus
   int Int_VirtaRaaka = 0;
   int Int_VirtaPohja = 0;
   float Flo_Akku = 0.0; // Akun jännitemittaus
   float Flo_Virta = 0.0; // Kuormitusvirran mittaus
   float Flo_Kapa = 0.00; // Laskettu kapasiteetti
   const float Con_Pohja = 0.25; // Laitteen omakäyttö

// Ohjaukset
   const int Con_START = 8;
   boolean Bol_START = false;
   const int Con_Rele = 9;
   boolean Kep_Rele = false;
   int Seq_Purku = 0; // Purkaussekvenssi

// Kellon määrittely (sisäinen kello)
   unsigned long Ulo_MilliSek = 0;
   unsigned long Ulo_UusiMilliSek = 0;
   const long CoL_EroSekunti = 999;
   long Lng_Sekunti = 0;
   boolean Bol_Tulosta = false;

// ALIOHJELMAT
// Tekstien päivitys
   void Fun_Tekstit(int kohta, int rivi,String teksti){
   lcd.setCursor(kohta, rivi);
   lcd.print(teksti);
   }// Teksti_ali loppu

//Numeroiden päivitys
   void Fun_Lukemat(int kohta, int rivi, float lukema){
   lcd.setCursor(kohta, rivi);
   lcd.print(lukema);
   }// Mittaus_ali loppu

// ASETUKSET:
   void setup(){
   Serial.begin(9600);
   lcd.begin(20,2);
   lcd.clear();
   lcd.setCursor(5, 0);
   lcd.print("K");
   lcd.write(api);
   lcd.print("ynnist");
   lcd.write(api);
   lcd.print(",");
   lcd.setCursor(4, 1);
   lcd.print("paina START");
   delay(1000);
// Hall-generaattin pohjatason talletus
   Int_VirtaPohja = analogRead(Con_Virta);
   pinMode(Con_START, INPUT_PULLUP);
   pinMode(Kep_Rele, OUTPUT);
   }// Asetuksen loppu

// PÄÄLOOPPI
   void loop(){
   // Sisäisen kellon käyttö
      Ulo_MilliSek = millis();
     if(Ulo_MilliSek - Ulo_UusiMilliSek > CoL_EroSekunti){
        Ulo_UusiMilliSek = Ulo_MilliSek;
         Lng_Sekunti++;
      if(Seq_Purku > 0 && Seq_Purku < 5){
         Flo_Kapa = Flo_Kapa + Flo_Virta;
      }
   // Akun jännitteenmittaus
      Int_AkkuRaaka = analogRead(Con_Akku);
      Flo_Akku = Int_AkkuRaaka / 68.2;
   // Purkuvirran mittaus
      Int_VirtaRaaka = analogRead(Con_Virta);
      Flo_Virta = (Int_VirtaRaaka - Int_VirtaPohja) / 8.7;
   }

   // Luetaan tulo
      Bol_START = !digitalRead(Con_START);
   // Käynnistetään purkusekvenssi
      if(Seq_Purku == 0 && Bol_START == true){
        Lng_Sekunti = 0;
        Seq_Purku = 1;
      }

   // Purkaussekvenssi
      switch (Seq_Purku) {
         case 1: // Päivitetään näyttö
            lcd.clear();
            Fun_Tekstit(0, 0, "Akun purku: V");
            Fun_Tekstit(13, 1, "A");
            Fun_Lukemat(16, 1, Flo_Virta);
            Kep_Rele = true;
            Seq_Purku = 2;
         break;
         case 2: // Ampeerisekunnit
            Fun_Lukemat(15, 0, Flo_Akku);
            Fun_Tekstit(0, 1, "Asek: ");
            Fun_Lukemat(6, 1, Flo_Kapa + Con_Pohja);
            Fun_Lukemat(16, 1, Flo_Virta);
            if(Flo_Akku < 10.5){ Seq_Purku = 0;Kep_Rele = false;}
            if(Lng_Sekunti >= 60){
               Fun_Tekstit(6, 1, " ");
         Seq_Purku = 3;
       }
      break;
      case 3: // Ampeeriminuutit
         Fun_Tekstit(0, 1, "Amin: ");
         Fun_Lukemat(6, 1, (Flo_Kapa + Con_Pohja)/60);
         Fun_Lukemat(15, 0, Flo_Akku);
         Fun_Lukemat(16, 1, Flo_Virta);
         if(Flo_Akku < 10.5){ Seq_Purku = 0;Kep_Rele = false;}
         if(Lng_Sekunti >= 3600){
            Fun_Tekstit(6, 1, " ");
         Seq_Purku = 4;
      }
      break;
      case 4: // Ampeeritunnit
         Fun_Tekstit(0, 1, "Atun: ");
         Fun_Lukemat(6, 1, (Flo_Kapa + Con_Pohja)/3600);
         Fun_Lukemat(15, 0, Flo_Akku);
         Fun_Lukemat(16, 1, Flo_Virta);
         if(Flo_Akku < 10.5){
            lcd.clear();
            Kep_Rele = false;
            Seq_Purku = 5;}
      break;
      case 5:
         Fun_Tekstit(0, 0, "VALMIS! V");
         Fun_Lukemat(15, 0, Flo_Akku);
         Fun_Tekstit(0, 1, "Akun kapas. Ah");
         Fun_Lukemat(15, 1, (Flo_Kapa + Con_Pohja)/3600);
      break;
      }// Purkaussekvenssin loppu

// Releen ohjaus
      digitalWrite(Con_Rele, Kep_Rele);
      delay(1);
} // Pääohjelma LOPPU