Leider ist das Editieren seines Beitrags nach 24h nicht mehr möglich. Daher werde ich - um nichts aus den Zusammenhang zu reißen - mit jedem Update den Kompletten Beitrag neu einfügen.
------------------------------------------
Ich wollte euch gerne mein "Projekt" vorstellen und hoffe, ihr habt Verbesserungsvorschläge oder Interesse, das selber nach zu bauen.
Ist hoffentlich genau das Richtige für eure Lipos in der Winterzeit.
Die folgende Schaltung ist sicher nicht die günstigste Methode seine Akkus warm zu halten, das war auch nicht das Ziel.
Worum geht es
Die vorgestellte Heizung basiert auf einem Arduino-Board (ATMEL Mikroprozessor), digitalen Temperatursensoren zum Messen der Innen- und Außentemperatur sowie einem Display zur Anzeige der Messwerte.
Um dem Betriebsakku (3S-LiPo) nicht zu quälen wurde eine einfache Spannungsüberwachung mit Abschaltung integriert.
Es wird eine zu erreichende Endtemperatur definiert. Wird diese erreicht schaltet die Heizung erst nach dem Erreichen einer Mindesttemperatur wieder ein. So wird das Gerät nicht permanent an und ausschalten nur um 0.1° Differenz auszugleichen. Welche Werte ideal sind wird sich herausstellen.
In der Zeit in der geheizt werden soll wird der Heizvorgang periodisch unterbrochen. Diese Zeit wird gegeben damit sich die Wärme im Koffer verteilen kann, außerdem wird so verhindert, dass die Akkus einseitig zu heiß werden während am Temperatursensor noch nicht die richtige Temperatur erreicht wurde.
Die gemessene Außentemperatur wirkt sich (zur Zeit) nicht auf die Temperatursteuerung aus. Da der Sensor aber nur 2Euro kostet habe ich ihn mit vorgesehen. Zum einen weiß man wie Arschkalt der Winter wirklich ist, zum Anderen kann man so später per Softwareupdate eine verbesserte Regelung integrieren (sofern nötig).
Auf dem Display werden Innen- und Außentemperatur, sowie die Batteriespannung und den aktuellen Status angezeigt.
Schaltplan
vorgeschlagenes Layout auf Lochrasterplatine
QuellCode (V1.0.1)
Code: Alles auswählen
#include <OneWire.h>
#include <LiquidCrystal.h>
#include <DallasTemperature.h>
//Geräte-Adressen definieren. Wenn diese noch nicht bekannt sind muss "setup_mode" auf TRUE gestellt werden,
//dann sucht das System nach Sensoren und übermittelt die Adressen per Seriellem Ausgang an den PC
DeviceAddress insideThermometer = { 0x28, 0x86, 0x9C, 0x27, 0x03, 0x00, 0x00, 0xC2 };
DeviceAddress outsideThermometer = { 0x28, 0xD5, 0xC1, 0x28, 0x03, 0x00, 0x00, 0x56 };
boolean setup_mode=false;
float temp_on = 25.0; //bei Unterschreiten dieser Temperatur heizen
float temp_off = 28.0; //bei Erreichen dieser Temperatur nicht mehr heizen
byte workstatus=0; //0=idle, 1=Heizen, 2=Heizpause, 8=Batterie leer, 9=Fehler | 0-4 = normaler Status, 5-9 = Fehlerstatus
byte relais = 9; //Pin des Relais-Ausgangs
byte bat_sensor = 0; //Pin für den Batteriesensor (muss ein Pin mit DAD-Wandler sein)
float voltage = 0.0; //errechnete Spannung
float max_vin = 14.0; //Maximale Spannung. Wirkt sich auf die Berechnung der Akku-Spannung aus. Muss in Einklang mit dem Spannugnsteiler sein. Der Spannungssensor darf NIE über 5V kommen
float min_vin = 11.2; //Minimale Spannung, Beim unterschreiten wird aufgehört zu heizen und eine Meldung ausgegeben
int heating_interval=50;//Dauer der Heizperiode. Wenn geheizt werden soll wird nach dieser Zahl Sekunden eine Pause eingelegt für die Konvektion (gravitative Wärmeverteilung)
int heating_pause = 10; //Dauer der eingelegten Konvektionspause
#define ONE_WIRE_BUS 8 //Pin für die Signalleitung des 1Wire BUS
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// Ende der einstellbaren Parameter
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
byte deg[8] = { //es gibt kein GRAD-Zeichen? Machen wir uns eins.
B01100,
B10010,
B10010,
B01100,
B00000,
B00000,
B00000,
};
LiquidCrystal lcd(12, 11, 5, 4, 3, 2); //Objekt initialisieren, Parameter sind die Pins zur Kommunikation
float temp_i; //speichert die gemessene Innentemperatur
float temp_o; //speichert die gemessene Aussentemperatur
unsigned long current_millis = 0; //aktuelle ms seit Systemstart
long last_millis = 0; //letzter Zeitpunkt an dem ein Intervall (heizen oder pause) gestartet wurde
String versionnumber = "1.0.1";
//-------------------------------------------------------------------------
void setup(void) {
pinMode(bat_sensor, INPUT);
pinMode(relais, OUTPUT);
lcd.begin(2,16); // Objekt erstellen. PArameter: Anzahl der Zeilen und Zeichen pro Zeile
lcd.createChar(0, deg); // eigenes Zeichen in den RAM laden
lcd.clear(); // Bildschirm leeren
lcd.setCursor(0,0); // Cursor auf Zeichen 0 und Zeile 0 setzen
/*
1Wire-Geräte haben alle eine eigene Adresse. Die steht leider nicht auf dem Baustein.
Im Setup-Modus lesen wir den ganzen Bus aus und geben alle gefundenen Adressen per Serial an den PC aus.
Der Nutzer muss diese dann weiter oben eingeben. Welcher Temperatursensor innen und welcher außen ist kann
geprüft werden wenn man einen in die Hand nimmt und schaut, welcher Wert sich dann im
Normalen Modus (nicht Setup Modus) ändert.
Vielleicht kann man das kompfortabler gestalten?
*/
if (setup_mode) {
Serial.begin(9600);
lcd.print("Setup Modus");
find_sensor_adresses();
return;
}
lcd.print("Starte System");
lcd.setCursor(0,1);
lcd.print("Version: ");
lcd.print(versionnumber);
sensors.begin();
//Sensoren auf 12Bit Auflösung einstellen
sensors.setResolution(insideThermometer, 12);
sensors.setResolution(outsideThermometer, 12);
delay(2000);
lcd.clear();
}
//-------------------------------------------------------------------------
void loop(void) {
if(setup_mode) return; //im Setup-Modus muss hier nichts getan werden
current_millis = millis(); //aktuelle Zeit seit Systemstart
sensors.requestTemperatures(); //die Temperaturwerte der Sensoren abfragen
temp_i = sensors.getTempC(insideThermometer);
temp_o = sensors.getTempC(outsideThermometer);
calculate_voltage(analogRead(bat_sensor)); //Spannung aus dem gemessenen Wert errechnen
if (workstatus < 5) { //kein Fehlercode?
if (temp_i < temp_on) { //ist die aktuelle Innentemperatur unter der Einschalt-Temperatur
if(workstatus==0) workstatus=1; //und ist der Status "Bereit", dann stellen wir den Status auf "Heizen"
} else if(temp_i >= temp_off) { //Liegt die Temperatur über der Zieltemperatur...
workstatus=0; //...stellen wir das Heizen ab
}
if(workstatus == 1) { //soll geheizt werden, dann heizen wir nur die Intervalldauer lang..
if((current_millis-last_millis) > (heating_interval*1000)) {
workstatus=2;
last_millis=current_millis;
}
}
if(workstatus == 2) { //...und legen dann eine Pause ein
if((current_millis-last_millis) > (heating_pause*1000)) {
workstatus=1;
last_millis=current_millis;
}
}
}
display_sensor_values(); //gesammelte Werte anzeigen
handle_heating(); //Heizstatus auswerten und agieren
delay(400); //kurze Pause einlegen und dann geht's weider von Vorne los
}
//-------------------------------------------------------------------------
void handle_heating() {
//Heizung einschalten bzw abschalten, je nach workstatus
if(workstatus==1) {
digitalWrite(relais, HIGH); // Heizungsrelais einschalten
} else {
digitalWrite(relais, LOW); // Heizungsrelais ausschalten
}
}
//-------------------------------------------------------------------------
void calculate_voltage(int value) {
//Spannung aus dem Mavimalwert (für den der Spannungsteiler ausgelegt wurde) und dem aktuellen MEsswert errechnen,
//ist die Spannung unter min_vin einen Fehlercode einstellen
voltage = (max_vin/1024)*value;
if (voltage < min_vin) workstatus = 8;
}
//-------------------------------------------------------------------------
void display_sensor_values() {
lcd.setCursor(0,0);
lcd.print("I:");
lcd.print(temp_i);
lcd.write(0);
lcd.setCursor(0,1);
lcd.print("A:");
lcd.print(temp_o);
lcd.write(0);
lcd.setCursor(9,0);
lcd.print("B:");
lcd.print(voltage,1);
lcd.print("V ");
lcd.setCursor(9,1);
switch(workstatus) {
case 0: lcd.print(" BEREIT"); break;
case 1: lcd.print(" HEIZEN"); break;
case 2: lcd.print(" PAUSE "); break;
case 8: lcd.print(" !AKKU!"); break;
case 9: lcd.print(" FEHLER"); break;
}
}
//-------------------------------------------------------------------------
void find_sensor_adresses() {
//sicht nach 1Wire-Geräten auf dem BUS und gibt deren Adresse aus
byte i;
byte present = 0;
byte data[12];
byte addr[8];
Serial.print("Suche nach 1-Wire Geraete...\n\r");
while(oneWire.search(addr)) {
Serial.print("\n\r \'1-Wire\' Geraet gefunden, Adresse:\n\r");
for( i = 0; i < 8; i++) {
Serial.print("0x");
if (addr[i] < 16) {
Serial.print('0');
}
Serial.print(addr[i], HEX);
if (i < 7) {
Serial.print(", ");
}
}
if ( OneWire::crc8( addr, 7) != addr[7]) {
Serial.print("CRC ungueltig!\n");
return;
}
}
Serial.print("\n\r\n\rEnde der Suche\r\n");
oneWire.reset_search();
return;
}
Code: Alles auswählen
Änderungen 1.0.1
1.
min_vin Vorgabewert von 11.1V um 0.2V auf 11.3V erhöht. Je nach Akku kann 11.1V schon zu spät sein. Den Idealen Wert sollte jeder selbst "erproben", aber wir fangen lieber etwas höher an um die Akkus zu schonen.
2.
Grundwerte für die Heizpause von 40s Heizen/10s Pause auf 50s Heizen/10s Pause
3.
Änderung der Abfrage
if(workstatus!=2) workstatus=1;
auf
if(workstatus==0) workstatus=1;
(Zeile 113)
- 1x Arduino Pro Mini
- 1x USB auf RS232 Konverter , wird benötigt um das Arduino zu programmieren (gibs sehr billig - kann man auch selber basteln aus anderen Geräten)
- 1x 16x2 Zeichen Display - DEM16216SYH-LY
- 1x Spannungsregler 5V Typ 7805 im TOC220 Gehäuse
- 1x Relais das bei 5V schaltet, und bei 15V 3-4A durchschalten kann ohne selbst zur Heizung zu werden (z.B.JV5s-KT)
- 2x digitaler Temperatursensor DS18B20
- 1x Widerstand 100 Ohm
- 1x Widerstand 4,7 kOhm
- 1x Widerstand 10 kOhm, 0.5% Toleranz
- 1x Widerstand 18 kOhm, 0.5% Toleranz
- 1x Potentiometer 10kOhm
- 1x Transistor NPN C546A
- 1x Kondensator 0,33µF
- 1x Kondensator 0.1µF
- 1x Diode 1N4148
- 1x Heizfolie, die Leistung ist Abhängig von eurem zu beheizenden Koffer. Ich habe eine 35W Folie gekauft.
Die entstehende Wärme (ca 1.4Watt) kann man auch gleich im Inneren des Koffers belassen
Den Arduino, das Display, die Temperatursensoren und wer will auch den USB-Serial Wandler zum Programmieren kann man unter Anderem auf http://www.watterott.com kaufen, aber auch ebay und co haben sowas sicher da.
FAQ
- Das Display ist HD44780 Kompatibel. Es kann über 4 oder 8Bit parallel angesprochen werden, wir nutzen 4Bit, reicht aus und spart Ausgänge am Arduino die man für andere Dinge nutzen kann.
Siehe auch http://www.arduino.cc/en/Tutorial/LiquidCrystal - Die Materialkosten liegen bei ca 40 - 50Euro.
Updates
- 23102011 0900: neuer Schaltplan (größere Auflösung,eingezeichnete Temp-Sensoren), Diode am Relais um Induktionsstöme zu töten (tnx echo.zulu)
- 27102011 1930: aktualisierte Software, Platinenlayout
Die Bilder in diesem Album zeigen meinen Koffer. Dies ist NUR ein Beispiel. Jeder kann/darf/soll seinen Koffer so gestalten wie er es für richtig hält. Es gibt sicher bessere Aufbaumöglichkeiten als meine, ggf mit mehreren Folien, Lüftern, was auch immer. Also bitte nicht über diesen einen Beispielaufbau diskutieren, sondern einfach selber besser machen
Für Diskussionen nutzt bitte den Diskussionsthread, so dass die Anleitung hier übersichtlich und fachlich bleibt.