Ich habe nun schon einige Batterien leer gesaugt, jedoch immer wieder das Problem, dass Manche einfach auslaufen oder gar ihre ätzende Flüssigkeit versprühen. Woran liegt das?
Die Antwort ist einfach: da die Zellen in Reihe verdrahtet sind, fließt der Strom durch alle Zellen. Wenn deren Ladung unterschiedlich ist, ist deren Spannung unter Last natürlich auch unterschiedlich. Ist eine Zelle nun leer, so fließt ja weiterhin Strom durch diese Zelle und sie wird negativ aufgeladen. Das quitieren die Batterien mit Auslaufen, je nach Stromstärke mit mehr oder weniger Getöse. Was her muss, ist eine einfache Möglichkeit die Spannung jeder einzelnen Batterie zu überwachen und bevor sie Schaden anrichten kann, muss eine Meldung kommen.
Der Joule-Thief XXL V2.0 ist geboren!
Ich habe einen meiner Arduinos mit einem LCD-Display versehen und die Spannung jeder einzelnen Zelle über ein Widerstandsnetzwerk gemessen und angezeigt. Fällt nun die Spannung einer Zelle unter +0.01V, so wird ein Piepston ausgegeben, der die Position der Zelle im Verbund angibt. So ist sichergestellt, dass auch dann, wenn die Gesamtspannung zu niedrig ist um eine vernünftige Anzeige zu erzeugen, die leere Zelle gemeldet wird.
Zur Verdeutlichung habe ich die Schaltung mal im Eagle gemalt:
Die Spannungen werden über die Potis abgegriffen und dann so eingestellt, dass die Eingangsspannung des Arduino auf dessen Analog-Pins nicht überschritten wird. Das bedeutet dann, dass die Spannung an A0 bei 0-1.5V, an A1 zwischen 0-3.0V, an A2 zwischen 0-4.5V usw. liegt. Die Messgenauigkeit wird bei jeder weiteren Zelle schlechter, aber für meine Anforderungen reicht das vollkommen.
Und so sieht das Programm aus:
// ———————————————————
// Batteriemessgerät
// es wird die Spannung von 6 Batterien gemessen und gleichzeitig
// auf einem LCD-Display dargestellt.
// ———————————————————
#include #define DEBUG struct _Batterie LiquidCrystal lcd(12, 11, 5, 4, 3, 2); // initialize the library with the numbers of the interface pins #define NEIN 0 // Taste nicht gedrückt // ——————————- // ——————————- for(i=0; i<6 br="" i=""> Batterien[i].abschaltspannung = 0.1F; // ——————————- aval = analogRead(AnalogBatPin1); // ——————————- if(Batterien[0].ausgetastet) if(Batterien[3].ausgetastet) lcd.setCursor(0, 0); // ——————————- gedrueckt = digitalRead(TasterPin); if (gedrueckt) letztes_gedrueckt = gedrueckt; // SERIAL_PRINT(anfang); return tasterGedrueckt; // ——————————- for(i=0; i<6 br="" i=""> { // ——————————- jetzt = millis(); if ((jetzt-jedeSekunde) > 1000) SekundenBlinkbit = ~SekundenBlinkbit; if ((jetzt-jedeHalbeSekunde) > 500) Slot++; SERIAL_PRINTLN(Slot); HalbsekundenBlinkbit = ~HalbsekundenBlinkbit; if ((jetzt-jedeViertelSekunde) > 250) ViertelsekundenBlinkbit = ~ViertelsekundenBlinkbit;
#include „log.h“
{
float spannung; // die gemessene Spannung
bool ausgetastet; // wird die Spannung gerade angezeigt, oder ausgetastet
float abschaltspannung; // darunter ist die Batterie leer
};
int AnalogBatPin1 = A0;
int AnalogBatPin2 = A1;
int AnalogBatPin3 = A2;
int AnalogBatPin4 = A3;
int AnalogBatPin5 = A4;
int AnalogBatPin6 = A5;
int TasterPin = 10;
int SummerPin = 9;
int LEDPin =13;
bool Pieps; // währenddessen wird gepiepst
int Slot; // zählt immer durch
struct _Batterie Batterien[6];
bool SekundenBlinkbit; // toggle jede Sekunde
bool HalbsekundenBlinkbit; // toggle jede halbe Sekunde
bool ViertelsekundenBlinkbit; // toggle jede viertel Sekunde
#define KURZ 1 // Taste kurz gedrückt
#define LANG 2 // Taste lang gedrückt
void setup()
{
SERIAL_BEGIN;
lcd.begin(16, 2); // set up the LCD’s number of columns and rows:
analogReference(INTERNAL);
pinMode(TasterPin, INPUT);
pinMode(SummerPin, OUTPUT);
pinMode(LEDPin, OUTPUT);
InitVariablen();
}
void InitVariablen(void)
{
int i;
}
void MesseBatterien(void)
{
int aval;
float offset[6] = { 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F };
float zaehl[6] = { 1.24F, 1.24F, 1.24F, 1.24F, 1.24F, 1.24F };
float nenner[6] = { 0.83F, 0.83F, 0.83F, 0.83F, 0.83F, 0.83F };
Batterien[0].spannung = (float)aval *zaehl[0] / nenner[0] / 1000.0F + offset[0];
aval = analogRead(AnalogBatPin2);
Batterien[1].spannung =
(float)aval *2.0F * zaehl[1] / nenner[1] / 1000.0F + offset[1];
Batterien[1].spannung -= Batterien[0].spannung;
aval = analogRead(AnalogBatPin3);
Batterien[2].spannung =
(float)aval *3.0F * zaehl[2] / nenner[2] / 1000.0F + offset[2];
Batterien[2].spannung -= Batterien[0].spannung;
Batterien[2].spannung -= Batterien[1].spannung;
aval = analogRead(AnalogBatPin4);
Batterien[3].spannung =
(float)aval *4.0F * zaehl[3] / nenner[3] / 1000.0F + offset[3];
Batterien[3].spannung -= Batterien[0].spannung;
Batterien[3].spannung -= Batterien[1].spannung;
Batterien[3].spannung -= Batterien[2].spannung;
aval = analogRead(AnalogBatPin5);
Batterien[4].spannung =
(float)aval *5.0F * zaehl[4] / nenner[4] / 1000.0F + offset[4];
Batterien[4].spannung -= Batterien[0].spannung;
Batterien[4].spannung -= Batterien[1].spannung;
Batterien[4].spannung -= Batterien[2].spannung;
Batterien[4].spannung -= Batterien[3].spannung;
aval = analogRead(AnalogBatPin6);
Batterien[5].spannung =
(float)aval *6.0F * zaehl[5] / nenner[5] / 1000.0F + offset[5];
Batterien[5].spannung -= Batterien[0].spannung;
Batterien[5].spannung -= Batterien[1].spannung;
Batterien[5].spannung -= Batterien[2].spannung;
Batterien[5].spannung -= Batterien[3].spannung;
Batterien[5].spannung -= Batterien[4].spannung;
}
void AusgabeLCD(void)
{
char buffer1[40], buffer2[40];
char t1[10], t2[10], t3[10], t4[10], t5[10], t6[10];
strcpy(t1, “ „);
else
dtostrf(Batterien[0].spannung, 4, 2, t1);
if(Batterien[1].ausgetastet)
strcpy(t2, “ „);
else
dtostrf(Batterien[1].spannung, 4, 2, t2);
if(Batterien[2].ausgetastet)
strcpy(t3, “ „);
else
dtostrf(Batterien[2].spannung, 4, 2, t3);
sprintf(buffer1, „%s %s %s „, t1, t2, t3);
strcpy(t4, “ „);
else
dtostrf(Batterien[3].spannung, 4, 2, t4);
if(Batterien[4].ausgetastet)
strcpy(t5, “ „);
else
dtostrf(Batterien[4].spannung, 4, 2, t5);
if(Batterien[5].ausgetastet)
strcpy(t6, “ „);
else
dtostrf(Batterien[5].spannung, 4, 2, t6);
sprintf(buffer2, „%s %s %s „, t4, t5, t6);
lcd.print(buffer1);
lcd.setCursor(0, 1);
lcd.print(buffer2);
}
int LeseTaster(void)
{
int tasterGedrueckt; // und hier ist die Taste
static long int anfang; // hier merken wir uns, seit wann der Taster gedrückt ist
long int jetzt=millis(); // Millisekunden
long int drueckdauer; // so lange ist der Taster bereits gedrückt
bool gedrueckt;
static bool letztes_gedrueckt=0;
digitalWrite(LEDPin, gedrueckt); // visuelle Rückmeldung
{
drueckdauer = jetzt-anfang;
if (drueckdauer > 1000)
tasterGedrueckt = LANG;
else
{
if (drueckdauer > 500)
tasterGedrueckt = KURZ;
else
tasterGedrueckt = NEIN;
}
if (letztes_gedrueckt == 0)
anfang = jetzt;
}
else
anfang = jetzt; // damit die Tasten-Drück-Dauer kurz ist
// SERIAL_PRINT(“ „);
// SERIAL_PRINT(jetzt);
// SERIAL_PRINT(“ „);
// SERIAL_PRINTLN(tasterGedrueckt);
}
void PruefeBatterien(void)
{
int i;
int leereBatterie = -1;
if (Batterien[i].spannung < Batterien[i].abschaltspannung)
leereBatterie = i+1;
}
// SERIAL_PRINTLN(leereBatterie);
if ((leereBatterie > Slot) && ViertelsekundenBlinkbit)
{
Pieps = true;
//SERIAL_PRINT(„Slot „);
//SERIAL_PRINTLN(Slot);
}
else
Pieps = false;
}
void loop()
{
long int jetzt;
int taste;
static long int jedeSekunde=0; // für den Timer jeder Sekunde
static long int jedeHalbeSekunde=0; // für den Timer jeder halben Sekunde
static long int jedeViertelSekunde=0; // für den Timer jeder viertel Sekunde
taste = LeseTaster();
PruefeBatterien();
{ // was hier steht, wird zyklisch jede Sekunde ausgeführt
MesseBatterien();
jedeSekunde = jetzt;
}
{ // was hier steht, wird zyklisch jede halbe Sekunde ausgeführt
AusgabeLCD();
if (Slot>5)
Slot=0;
jedeHalbeSekunde = jetzt;
}
{ // was hier steht, wird zyklisch jede viertel Sekunde ausgeführt
if (Pieps)
digitalWrite(SummerPin, HIGH);
else
digitalWrite(SummerPin, LOW);
jedeViertelSekunde = jetzt;
}
}6>6>
Nicht schön, aber der Code funktioniert. Wie man sieht, habe ich auch noch eine Taste mit eingebaut, damit die Maschine auch noch parametriert werden könnte. Platz für V2.1…
Zu guter Letzt habe ich noch Alles auf einer Lochrasterplatine zusammengelötet:
