Sonntag, 20. August 2017

JouleThief XXL V2.1 - noch ein Update

der Betrieb der V2.0 ist schon sehr komfortabel. Die Spannung der Batterien wird zuverlässig angezeigt und es kommt eine Meldung, wenn deren Spannung zu weit absinkt.
Allerdings ist der Kontrast des Displays noch nicht optimal, da dessen Versorgungsspannung abhängig der Leere der Batterien im Bereich von 5V bis unter 3V schwankt. Da muss eine Kontrast-Automatik her! In Anlehnung an diese Webseite, habe ich die Schaltung erweitert: Ich habe noch 2 Analogeingänge frei, mit der ich sowohl Versorgungsspannung des Displays, als auch die Kontrastspannung messen kann. Über einen PWM-Ausgang mit nachgeschaltetem Spannungsteiler, sowie Glättungs-Schaltung kann ich nun den Kontrast immer im optimalen Bereich halten.



















In diesem Zusammenhang habe ich noch ein paar kleine Bugs im Programm beseitigt:




// ---------------------------------------------------------
// Batteriemessger�t
// es wird die Spannung von 6 Batterien gemessen und gleichzeitig
// auf einem LCD-Display dargestellt.
// ---------------------------------------------------------

#include

#define DEBUG
#include "log.h"

struct _Batterie
{
    float spannung;  // die gemessene Spannung
    bool ausgetastet;  // wird die Spannung gerade angezeigt, oder ausgetastet
    float abschaltspannung;  // darunter ist die Batterie leer
};

LiquidCrystal lcd(12, 11, 5, 4, 3, 2); // initialize the library with the numbers of the interface pins
int AnalogBatPin1 = A0;
int AnalogBatPin2 = A1;
int AnalogBatPin3 = A2;
int AnalogBatPin4 = A3;
int AnalogBatPin5 = A4;
int AnalogBatPin6 = A5;
int AnalogKontrastPin = A6;  // hier wird die Kontrastspannung gemessen
int AnalogVCCPin = A7; // hier wird die VCC gemessen (für die Kontrastspannungsberechnung)
int KontrastPWM = 6;
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 NEIN 0  // Taste nicht gedr�ckt
#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;

    for(i=0; i<6 br="" i="">        Batterien[i].abschaltspannung = 0.02F;
}

// -------------------------------
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 };

    aval = analogRead(AnalogBatPin1);
    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];

    if(Batterien[0].ausgetastet)
        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);

    if(Batterien[3].ausgetastet)
        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.setCursor(0, 0);
    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;

    gedrueckt = digitalRead(TasterPin);
    digitalWrite(LEDPin, gedrueckt); // visuelle R�ckmeldung

    if (gedrueckt)
    {
        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

    letztes_gedrueckt = gedrueckt;

//    SERIAL_PRINT(anfang);
//    SERIAL_PRINT(" ");
//    SERIAL_PRINT(jetzt);
//    SERIAL_PRINT(" ");
//    SERIAL_PRINTLN(tasterGedrueckt);

    return tasterGedrueckt;
}

// -------------------------------
void PruefeBatterien(void)
{
    int i;
    int leereBatterie = -1;

    for(i=0; i<6 br="" i="">    {
        if (Batterien[i].spannung < Batterien[i].abschaltspannung)
            leereBatterie = i+1;           
    }
    // SERIAL_PRINTLN(leereBatterie);
   
    if (leereBatterie > Slot)
    {
        Pieps = true;
        //SERIAL_PRINT("Slot ");
        //SERIAL_PRINTLN(Slot);
    }
    else
        Pieps = false;
   
}

// -------------------------------
void StelleKontrast(void)
{
    int kont, vcc;
    static int kontrastwert=0;  // der PWM-Stellwert für den Kontrast
   
    kont = analogRead(AnalogKontrastPin);
    SERIAL_PRINT("Kin=");
    SERIAL_PRINT(kont);

    vcc = analogRead(AnalogVCCPin);
    SERIAL_PRINT("VCC=");
    SERIAL_PRINTLN(vcc);  // 1000bit = 5V

    kontrastwert += ((800*(vcc/1000))-kont)/7;
    if (kontrastwert<0 br="">        kontrastwert = 0;
    if (kontrastwert>255)
        kontrastwert = 255;

    SERIAL_PRINT(" Kout=");
    SERIAL_PRINTLN(kontrastwert);

    analogWrite(KontrastPWM, kontrastwert);
}

// -------------------------------
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

    jetzt = millis();
    taste = LeseTaster();
    PruefeBatterien();

    if ((jetzt-jedeSekunde) > 1000)
    {   // was hier steht, wird zyklisch jede Sekunde ausgef�hrt
        MesseBatterien();
        StelleKontrast();

        SekundenBlinkbit = ~SekundenBlinkbit;
        jedeSekunde = jetzt;
    }

    if ((jetzt-jedeHalbeSekunde) > 500)
    {   // was hier steht, wird zyklisch jede halbe Sekunde ausgef�hrt
        AusgabeLCD();

        Slot++;
        if (Slot>5)
            Slot=0;

        SERIAL_PRINTLN(Slot);

        HalbsekundenBlinkbit = ~HalbsekundenBlinkbit;
        jedeHalbeSekunde = jetzt;
    }

    if ((jetzt-jedeViertelSekunde) > 250)
    {   // was hier steht, wird zyklisch jede viertel Sekunde ausgef�hrt
        static bool letzte; // nur maximal 1/4 Sek. piepsen
        if (Pieps & !letzte)
        {
            letzte = true;
            digitalWrite(SummerPin, HIGH);
        }
        else
        {
            letzte = false;
            digitalWrite(SummerPin, LOW);
        }
        ViertelsekundenBlinkbit = ~ViertelsekundenBlinkbit;
        jedeViertelSekunde = jetzt;
    }
}

Dienstag, 1. August 2017

Joule-Thief XXL V2.0

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
#include "log.h"

struct _Batterie
{
    float spannung;  // die gemessene Spannung
    bool ausgetastet;  // wird die Spannung gerade angezeigt, oder ausgetastet
    float abschaltspannung;  // darunter ist die Batterie leer
};

LiquidCrystal lcd(12, 11, 5, 4, 3, 2); // initialize the library with the numbers of the interface pins
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 NEIN 0  // Taste nicht gedrückt
#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;

    for(i=0; i<6 br="" i="">        Batterien[i].abschaltspannung = 0.1F;
}

// -------------------------------
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 };

    aval = analogRead(AnalogBatPin1);
    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];

    if(Batterien[0].ausgetastet)
        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);

    if(Batterien[3].ausgetastet)
        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.setCursor(0, 0);
    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;

    gedrueckt = digitalRead(TasterPin);
    digitalWrite(LEDPin, gedrueckt); // visuelle Rückmeldung

    if (gedrueckt)
    {
        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

    letztes_gedrueckt = gedrueckt;

//    SERIAL_PRINT(anfang);
//    SERIAL_PRINT(" ");
//    SERIAL_PRINT(jetzt);
//    SERIAL_PRINT(" ");
//    SERIAL_PRINTLN(tasterGedrueckt);

    return tasterGedrueckt;
}

// -------------------------------
void PruefeBatterien(void)
{
    int i;
    int leereBatterie = -1;

    for(i=0; i<6 br="" i="">    {
        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

    jetzt = millis();
    taste = LeseTaster();
    PruefeBatterien();

    if ((jetzt-jedeSekunde) > 1000)
    {   // was hier steht, wird zyklisch jede Sekunde ausgeführt
        MesseBatterien();

        SekundenBlinkbit = ~SekundenBlinkbit;
        jedeSekunde = jetzt;
    }

    if ((jetzt-jedeHalbeSekunde) > 500)
    {   // was hier steht, wird zyklisch jede halbe Sekunde ausgeführt
        AusgabeLCD();

        Slot++;
        if (Slot>5)
            Slot=0;

        SERIAL_PRINTLN(Slot);

        HalbsekundenBlinkbit = ~HalbsekundenBlinkbit;
        jedeHalbeSekunde = jetzt;
    }

    if ((jetzt-jedeViertelSekunde) > 250)
    {   // was hier steht, wird zyklisch jede viertel Sekunde ausgeführt
        if (Pieps)
            digitalWrite(SummerPin, HIGH);
        else
            digitalWrite(SummerPin, LOW);

        ViertelsekundenBlinkbit = ~ViertelsekundenBlinkbit;
        jedeViertelSekunde = jetzt;
    }
}

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:




Montag, 30. Januar 2017

Joule-Thief XXL

Im vorigen Post habe ich die Verwertung von leeren Batterien durch einen Joule-Thief thematisiert. Da die von mir vorgestellte Taschenlampe für den Alltag nicht wirklich taugt, habe ich noch etwas weiter experimentiert und eine weitere Idee - für den Alltag durchaus praktikabel.

Ich habe jede Menge leerer Batterien, die in keinem Gerät mehr verwendbar sind. Viele Geräte können bei 1.2V schon nicht mehr richtig arbeiten, das schließt sogar den Betrieb an NiMH-Akkus aus. Quartz-Uhrwerke laufen noch etwas länger, aber auch hier ist häufig bei 1.0V der Ofen aus. Und eine NiMH ist da schon tiefentladen, also eigentlich hier gar nicht sinnvoll einsetzbar:

  • ich habe mehrere dieser leeren Primärzellen hintereinander gehängt
  • die resultierende Spannung mit einem DC/DC-Wandler auf etwas über 15V transformiert
  • das Ganze über einen Vorwiderstand und eine Diode an einen Blei-Akku gehängt
  • und damit die leeren Batterien so lange leergesaugt, bis sie ohne Last unter 0.1V hatten
  • hintereinander diese, dann wirklich leeren Batterien, gegen etwas Bessere getauscht
  • und dieses Spiel solange wiederholt, bis ich alle Batterien so leer hatte, dass der Spannungswandler nicht mehr anlief.
  • diesen nun aus Abfall gefüllten Bleiakku  schloss ich über einen weiteren Spannungswandler
  • an eine USB-Powerbank
  • und kann damit mindestens 2x mein Smartphone laden
So habe ich dimensioniert:
  • 8 leere AA-Batterien in Reihe. Ich habe da eine ausgemusterte Batteriehalterung mit einem Tamiya Stecker dran.
  • das ergibt selbst bei nur noch 1V pro Zelle immerhin 8V! Unter Last sind's grad noch 4V.
  • als DC/DC-Aufwärts-Wandler habe ich den MT3608 gewählt. Bei ebay gibt es haufenweise Händler, die damit bestückte Platinen für wenige Euro anbieten. Die Ausgangsspannung kann man mit einem Poti stufenlos einstellen.
  • Einstellen auf 15.0V, damit der Vorwiderstand für den Bleiakku den Strom begrenzt. Ich habe etwa 50mA Ladestrom.
  • Wenn ich den Regler direkt anschließe (also ohne den Vorwiderstand), wird der Strom in den Blei-Akku so groß, dass die Spannung an den leeren Batterien gleich so weit zusammenbricht, dass der Spannungswandler wieder aus geht.
  • Am Akku habe ich einen Abwärtswandler, eingestellt auf 5.1V für USB
  • und daran ein abgeschnittenes USB-Verlängerungskabel, um USB-Geräte einstecken zu können


(Die Skale des Messgerätes im Bild hat die falsche Beschriftung. Der Endausschlag ist bei 60mA)

Der DC/DC-Abwärts-Wandler arbeitet mit einem LM2596. Auch hier gibt es für kleines Geld eine Menge Händler (auch aus Deutschland).


Messungen mit dieser Anordnung ergaben, dass ich noch mindestens 200mAh aus den, normalerweise bereits als Müll bezeichneten, Batterien ziehen kann. Man muss nur aufpassen, dass die so leer gesaugten Batterien gerne mal auslaufen, also nach der Benutzung nicht in der Halterung lassen und fachgerecht entsorgen - diesmal aber wirklich leer!

Samstag, 14. Januar 2017

sinnvolle Verwendung von leeren Batterien, Recycling einmal anders

jedesmal wenn ich in einem Gerät eine Batterie austauschen muss, ärgere ich mich, dass eigentlich noch reichlich Energie in der Primärzelle ist, die ich nun wegwerfen muss.
Vor einiger Zeit fand ich eine interessante Idee zu diesem Thema: Der Joule-Thief. Das ist eine kleine Schaltung, die mit Hilfe einer selbst gewickelten Spule und einem Transistor aus der eigentlich schon ratzeputz leeren Batterie auch noch mit weniger als 1V eine Spannung von über 3V erzeugt. Das reicht sogar für den Betrieb einer weißen LED.

Ich hatte damals etwas rumexperimentiert und die Bauteile in einen leeren Klebestift eingebaut.


 Die Batterie im Bild ist übrigens eine AAA mit 2 selbstgedruckten Ringen als Adapter zu AA.


Die Batterie hat eine Spannung von nur noch 0.85V und die Lampe leuchtet noch!
Eigentlich nur Spielzeug, eine Power-Taschenlampe ist das definitiv nicht. Aber das Experiment beweist, dass die Batterie noch Potential hat.

Dienstag, 17. November 2015

aktuelles Wetter aus der eigenen Wetterstation im Internet mit dem Raspberry Pi

Seit einiger Zeit läuft bei mir eine Wetterstation WS2800IT von Technoline. Die Station misst die Außentemperatur, die Luftfeuchtigkeit, die Wind-Stärke und -Richtung, sowie die Regenmenge. Die zum Teil solarbetriebenen Sensoren stehen auf dem Dach. Alle gemessenen Daten werden übersichtlich auf einem Drahtlos angebundenen Display angezeigt, welches bei mir im Wohnzimmer steht.














Das sieht nicht nur schick aus, sondern ist auch praktisch, da kein Drahtverhau rumliegt. Ein weiteres Feature ist die ebenfalls drahtlose Kommunikation über einen USB-Stick zu einer PC-Software zur Anzeige der von der Station gesammelten historischen Daten (maximal 1700 Messwerte, gespeichert jede 5 Minuten).
Hier müsste ich jedoch regelmäßig den PC anwerfen, um die Daten auszulesen, denn für mehr als eine Woche reicht der Speicher der Station nicht. Auf der Suche nach einer besseren Lösung, (die die Daten kontinuierlich in eine SQL-Datenbank schreiben kann) bin ich auf den Raspberry Pi gestoßen. Da ich ohnehin mal ein Projekt mit diesem kleinen Computer machen wollte, drängte sich die Wetteraufzeichnung geradezu auf.
Ich habe ein Starterpaket mit einem Raspberry Pi B erstanden, die Rechenleistung und Ausstattung reicht vollkommen.













Der Pi wurde mit einer SD-Karte geliefert, die NOOBS enthielt. Das ist ein grafisches Installationsprogramm für verschiedene Betriebssysteme des Pi. Also Maus, Tastatur und TV (über HDMI) angeschlossen und los geht's. Ich wählte Raspbian Jessie, eine aktuelle Debian-Distribution. Da ich für den späteren Betrieb keinen Bildschirm, Tastatur oder Maus benötige (Headless), muss Telnet und SSH laufen. Das ist standardmäßig aktiviert, also habe ich jetzt nur noch folgende Komponenten:
- ein Steckernetzteil
- der Raspberry Pi im Gehäuse
- ein Netzwerkkabel zur Fritzbox
- der USB-Stick der Wetterstation
Nun kommt die Installation des eigentlichen Wetterdaten-Abholprogramms. Ich habe mich für weewx entschieden, weil es schöne Übersichtsgrafiken für Tag, Woche und Jahr erzeugen kann.

Die Installation startete ich über die Anleitung von  Byte Insight, bin dann aber auf die Überholspur gewechselt und habe mir das vorgefertigte Debian-Paket vom weewx-Server gezogen. die Datei weewx_3.2.1-1_all.deb funktionierte tadellos und hinterließ ein funktionsfähiges System, das ohne angemeldeten Benutzer läuft.
Leider gibt es beim Raspberry Pi noch einen Fallstrick. Da die Hardware keine Echtzeituhr besitzt, ist nach dem Einschalten erst mal die falsche Uhrzeit im System. Die Installation von NTP reicht noch nicht, denn Weewx startet, bevor Ntp die aktuelle Uhrzeit hat. Weewxs Rasberry-Pi-Dokumentation geht darauf ein: einfach warten, bis die Uhrzeit aktuell ist. Der dort beschriebene Code muss nach /usr/share/weewx/user/extensions.py
Zur Bereitstellung als Website brauchen wir noch einen Webserver. Das erledigt lighttpd mit einer Portfreigabe von meiner dynamischen Internetadresse rainerbahr.no-ip.biz an den Pi.
Da die Wetterstation die Luftdruckdaten als relativen Luftdruck und nicht, wie von weewx erwartet absoluten Luftdruck sendet, ist dessen Anzeige schlicht falsch. Abhilfe bringt hier eine Änderung in der Konfiguration in /etc/weewx/weewx.conf:

[StdConvert]
target_unit = METRIC
[StdCalibrate]
pressure = pressure - 53

Dienstag, 21. Juli 2015

Freifunk - freies WLAN für Alle

neulich bin ich über ein interessantes Mitmach-Projekt gestolpert: Freifunk
Hier geht es um freie WLAN-Hotspots für Jeden. Die Knoten bieten einen unverschlüsselten Internetzugang, an den sich Jedermann anmelden kann.
In Deutschland ist solch ein Projekt rechtlich nicht einfach durchzuführen, denn jeder, der einen Internetzugang anbietet, haftet für das, was darüber an Daten ausgetauscht wird. Die sogenannte Störerhaftung greift auch dann, wenn man selbst nicht einmal weiß, dass illegale Daten über sein Netz gingen. Abmahnungen und Anzeigen wegen unerlaubtem Anbieten von illegalen Dateien sind wahrscheinlich.
Im Freifunk wird das umgangen, indem jeder Knoten die Daten, die darüber laufen, über eine verschlüsselte VPN-Verbindung zum Freifunk-Backbone leitet und dieser dann als Provider auftritt. Provider sind ausdrücklich von der Haftung ausgeschlossen, sonst wären ja auch T-Online und Konsorten in der Haftung. Durch diesen Trick bekommt derjenige, der sich am Hotspot anmeldet, eine IP-Adresse aus dem Pool des Freifunks, der eigentliche, physikalisch anbietende Knoten erscheint nicht in den Logs.
Bei solchen Projekten muss ich einfach mitmachen! Ihr findet meinen Knoten in der Freifunk-Gruppe Stuttgart als Knoten ffs-rutesheim02. Also, wenn Ihr mal in der Nähe seid, bedient Euch.

Sonntag, 28. Juni 2015

Stickmode ändern beim UDI U818A-1

nachdem ich mich in letzter Zeit viel um Nicht-Heli-spezifische Dinge gekümmert habe, will ich mal wieder etwas zum Besten geben:
Seit kurzem haben wir ein UFO in der Familie. Es ist eine UDI U818A-1 Drohne mit HD-Kamera. Das Teil soll unverwüstlich sein, aber das glaube ich erst, wenn es nach einem Jahr Kinder immer noch lebt...


Da ich nur Stickmode 1 fliege, es die Drohne aber nur mit Stickmode 2 zu kaufen gibt, habe ich mich entschlossen, die Fernsteuerung für meine Bedürfnisse anzupassen.
Ein erster Blick in's Innere der Funke offenbart eine übersichtliche Elektronik. Die Federn in den Knüppelaggregaten lassen sich leider nicht entfernen, es sind fest verbundene Potis für die X- und Y-Achse. Also musste ich die Aggregate auslöten, um sie an der anderen Position wieder einzulöten. Die eine Funktion, die vertauscht ist, lötete ich kurzerhand um. Hier ist das Design zum Glück sehr übersichtlich. Einfach die Leitungen für den Mittelpin des Potis and die andere Seite legen. Das wird auch für die anderen Modis funktionieren. Exoten mit vertauschten Knüppelrichtungen gehen natürlich nur mit größerem Aufwand.