Mittwoch, 7. März 2018

Intrigo: Buchrezension einer spannenden Schatzsuche auf Hawaii



Die junge Flugbegleiterin Hortensia von Lindenthal freut sich darauf endlich mal wieder ihre Freundin Sarah zu treffen und Urlaub auf Hawaii zu machen. Doch als sie auf der Insel ankommt ist alles anderes als erwartet: Sarah, die als Archäologin arbeitet, hat kaum Zeit und arbeitet an einer neuen, streng geheimen Ausgrabung. Da lernt Hortensia den geheimnisvollen Engländer Ethan McGowann kennen und verbringt viel Zeit mit ihm. Sie beginnt Gefühle für ihm zu entwickeln, doch irgendwie hat sie den Verdacht, dass er ihr etwas verheimlicht.

Plötzlich verschwindet Sarah spurlos und Hortensia bekommt einen sonderbaren Brief von ihrer Freundin, der ein kryptisches Rätsel beinhaltet. Während Hortensia an der Lösung des Rätsels arbeitet gerät sie in große Gefahr und entrinnt knapp einem Mordanschlag. Sie weiß nicht mehr wem sie eigentlich trauen darf und ihr erholsamer Urlaub auf Hawaii wird zu einem Wettlauf mit dem Tod...

"Intrigo" ist ein sehr spannender Roman, der auf den zauberhaften Inseln von Hawaii spielt. Ich könnte noch viel mehr zu Inhalt schreiben, weil in dem Buch so viel passiert, doch ich will nicht zu viel verraten. Man merkt jedenfalls sofort, dass die Autorin wirklich sehr viel recherchiert hat, denn sie hat viele Informationen zu Hawaii in den Roman eingebaut. Ich hatte teilweise das Gefühl wirklich dort zu sein, die Autorin erzählt sehr bildhaft. Der Schreibstil ist packend und sehr flüssig, dass sich das Buch recht schnell lesen lässt. Die Autorin erzählt in der dritten Person, meist aus der Sicht der Heldin, doch auch einige andere Figuren bekommen ihre Sichtweise.

Der Crimepart ist recht spannend und auch wenn ich das große Geheimnis bald gelüftet hatte, so war das Buch, dennoch sehr spannend und ich habe mit der Heldin mitgefiebert. Die Liebesgeschichte passt gut dazu, doch in dem Buch ist klar die Schatzsuche und der Crimepart im Fokus.

Derzeit ist das Buch als Kindle-Ebook bei Amazon und als epub bei anderen Webshops, z.B. Buecher.de zu bekommen. Die Print-Ausgabe ist Stand Anfang März 2018 noch nicht verfügbar, kommt aber später noch. Die ISBN-Nummern sind

für die Print-Ausgabe: 978-9963-53-826-3
als PDF: 978-9963-53-827-0
als epub: 978-9963-53-828-7
und als mobi: 978-9963-53-829-4

Viel Spaß beim Lesen

Sonntag, 28. Januar 2018

Umbau meines Fahrrads zum Pedelec

nach nunmehr fast 4 Monaten und über 1200km mit meinem zum Pedelec umgebauten Fahrrad, möchte ich diesen Umbau hier einmal beschreiben.

Ich fand im Internet einen günstigen Umbausatz, bestehend aus einem eingespeichten Nabenmotor als Ersatz für das unmotorisierte Hinterrad.
Mitgeliefert wurde praktischerweise gleich eine Ritzelkassette. Diese enthält einen Freilauf und ist kompatibel zu den alten Shimano-Kassetten mit integriertem Freilauf. Praktischerweise passten auch die Abstufung und die Abstände der Ritzel zueinander für meine Alivio 7 Gänge.
Außerdem im Set dabei: der Motorcontroller, ein Pedalsensor und 2 Bremshebel mit Schalter, 2 Griffe (der rechte ist als Gasgriff ausgeführt - wie bei einem Motorrad) sowie eine Tasche zum Anbinden der Elektrik an den Rahmen und einige Kabelbinder.
Leider musste ich für den Pedalsensor etwas Material der Tretkurbel abfeilen, der Sensor hätte sonst geklemmt und wäre beim Anziehen der Befestigungsschraube der Tretkurbel beschädigt worden.
Auf den Sensor kommt eine Scheibe mit Magneten. Der Sensor ist fest unter der linken Mutter des Tretlagers befestigt, die Scheibe ist auf den Vierkant der Tretlagerwelle aufgesteckt und dreht sich mit.


Da ich die kombinierte Brems-Schaltungs-Elemente der Alivio-Schaltung am Lenker weiterverwenden wollte, kamen die mitgelieferten Bremshebel mit Schalter nicht in Frage. Ich habe mich für Reed-Relais in Festo-Zylinderschaltern entschieden und diese mit Montagekleber auf den Block geklebt. Die Ansteuerung der Relais erfolgt über kleine Neodym-Magneten, die ich in die Bremshebel eingebohrt habe. Bisher hatte ich noch keine Probleme, obwohl mir das Rad bereits mehrmals umgefallen ist.
Die Griffe habe ich nicht benutzt, sondern stattdessen den Forumscontroller aus dem Pedelec-Forum auf einer Lochrasterplatine aufgebaut. Der Controller basiert auf einem Arduino und ist extrem flexibel an die eigenen Bedürfnisse anpassbar.


Die Platine habe ich in einen Ziplock-Beutel eingepackt, damit in die Tasche eindringender Regen keine Beschädigung der Elektronik hervorruft. Auch hier habe ich nach mehreren längeren Regenfahrten noch keinerlei Ausfälle zu beklagen.
Ich habe mich weitestgehend an die Schaltung der Version 1.4 gehalten und folgende Komponenten verbaut:
  • Arduino Nano
  • fertig aufgebauter Stromsensor, der als Zubehör für Arduino verkauft wird
  • fertig aufgebauter Spannungsregler zur Versorgung der Fahrbeleuchtung mit 6V
  • jede Menge Stocko-Pfostenverbinder für die Peripherie
  • BUZ10 zur Schalten der Beleuchtung
 Zur Anzeige und Einstellung der Parameter habe ich ein Nokia-Grafik-Display und ein Poti in ein 3D-selbstgedrucktes Kästchen, welches am Lenker befestigt ist.

Vervollständigt wird die Maschine noch durch ein Daumengas, ein abgezwickter Fahrradtacho-Sensor nebst Speichen-Magnet und natürlich ein Akku, der an den Befestigungslöchern der Trinkflaschenhalterung am unteren Rahmen hängt.






Der Akku hat 11Ah bei 36V. Das ergibt bei 250W Motorleistung theoretisch etwa 80-100km je Akkuladung. In der Praxis ist das natürlich stark von der Außentemperatur (der Lipo-Akku hat eine Spannungslage bei niediger Temperatur, die bereits bei halb entleerter Kapazität und mäßiger Last zur Notabschaltung zum Schutz des Akkus führt), der Belastung und dem Alter abhängig. Ich lade immer so zwischen 35 und 45km nach. Im Sommer komme ich da wahrscheinlich deutlich weiter.

Da ich im Winter überwiegend bei Dunkelheit unterwegs bin, habe ich mir noch eine anständige Beleuchtung gegönnt. Die Vorderlampe ist speziell für Pedelecs konstruiert und macht ordentlich Licht.

Ich bin nun, trotz legaler Dimensionierung von Motor-Leistung  auf max 250W und Begrenzung der elektrischen Unterstützung bis maximal 25km/h recht flott unterwegs. Die Felgenbremsen des Fahrraden schienen mir drastisch unterdimensioniert (das Gesamtgewicht des frisch gebackenen Pedelecs liegt bei etwa 22kg). Die bereits vor einigen Jahren nachgerüstete Federgabel hat bereits Befestigungslöcher für Scheibenbremsen. Ich Scheiben/Bremssättel gefunden, die mit Seizug angesteuert werden. Eingebaut im Vorderrad (das Ausfallende des Rahmens hat leider nicht genug Platz, um auch die hintere Bremse umzurüsten) entschärft es die Situation merklich.




Zum Schluss noch die Kosten, die ich für den Umbau investiert habe:

  • 165,99€ 26” Zoll 36V 250W Hinterrad E Bike Conversion Kit Elektro Fahrrad Umbausatz Kit 
  • 209,00€ Akku zum Anbau anstatt eines Flaschenhalters
  • 10,45€ Schaltwerk-Schutzbuegel-lang-Befestigung-am-Ausfallende-455216
  • 3,79€ 1 x Schwalbe Fahrrad-Felgenband PU Größen 16 / 18 / 20 / 24 / 26 / 28 Zoll
  • 3,95€ Stromsensor
  • 4,99€ LCD-Display
  • 4,00€ Neodym-Supermagnete Stäbe - 5x8mm
  • 19,99€ Gepäckträger
  • 18,90€ LED-Scheinwerfer 45 Lux Sport Pro E-Bike 6 - 48 Volt DC Fahrradlampe Pedelec
  • 8,99€ AXA BLUELINE mit Standlicht LED Rücklicht Fahrrad Rücklicht für Nabendynamo 50mm
  • 3,90€ 10 Stück Bremszüge 2000 mm Bremszug MTB Bowdenzug Fahrrad Innenzug Bremsseil
  • 24,95 Felt Vorderrad 26" Disc Moutainbike MTB Alex Hohlkammer Felge, VR Schwarz
  • 12,95€ Fahrrad Scheibenbremse mechanische Scheibe MTB Bremsscheibe Vorne+Hinten Set
  • 5,45€ Daumengas Gasgriff Gashebel für E-Bike Elektro Bike Elektrofahrrad E-Scooter Neu
macht eine Gesamtsumme von 497,30€. Das ist eiine Stange Geld, aber ich habe einen deutlichen Komfortgewinn und das Fahrrad stark aufgewertet. Wenn ich nun die Investition durch eingesparten Sprit meines Autos darstelle, würde ich bei 8L/100km (Diesel, Kurzstrecke) und einem derzeitigen Preis von 1,19€/Liter nach etwa 4200km den Umbau finanziert haben. Das ist bei meinen derzeit ca. 60km/Woche (täglich zur Arbeit und zurück) binnen eines Jahres der Fall. Natürlich nur, wenn das System solange durchhält...

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