Von Modellbauer für Modellbauer, Thermostat für LiPo Heizkoffer, Newbie Projekt.

Ich würde gerne ein kleines Projekt teilen, das ich als Übungsaufgabe gemacht habe.

Es handelt sich um Thermostat, das für das beheizen von LiPo-Ladekoffern genutzt werden kann.

Es war mein erstes Projekt mit einem Display als Newbie mit 5 Wochen Erfahrung.

Die vorab aufgestellte 10. Punkte Aufgabenreihe war wie folgt:

  1. Temperaturbereich mit Poti einstellbar, nicht mit Tasten

  2. Temperaturbereich von 35 bis 42°C ( leicht änderbar für andere Anwendungen )

  3. Es sollte Material verbraucht werden, was da war, daher der Sensor TMP36

  4. Da dieser am analogen Eingang nicht so stabile Werte generiert, und damit am
    Schaltpunkt oft ein Toggeln auftritt, sollte dem auf einfache Art begegnet werden. Dazu bin ich
    wie folgt vorgegangen:

  • Damit nicht dauernd die Heizung anspringt, schaltet si e erst wieder Soll- Temperatur -2° ein, das
    reicht für den Heizkoffer, da kommt es auf ein Grad nicht an. Auch der Wert -2 solle einfach
    änderbar sein.
  • Zusätzlich wartet das Programm dann noch eine Minute, bevor das Relais wieder geschaltet wird.
    Das klappt in Summe ganz ordentlich. Diese Zeit ist ebenfalls leicht änderbar für andere
    Anwendungen.
  1. Es soll ja Spaß machen, also gibt es am Anfang ein kurzes Intro auf dem Display. Zusätzlich soll
    sich, wenn die Heizung an ist, dort auch was bewegen. Wie gesagt, war eine Übungsaufgabe für
    mich selbst.

  2. Im Loop sollten folgende Dinge nicht vorkommen:

  • Delay
  • For Schleifen
  • Goto´s
  1. Das Display sollte regelmäßig ( etwa Sekundentakt ) refreshed werden. Diese Zeit soll auch
    einfach änderbar sein.

  2. Es sollte mindestens angezeigt werden:

-Die aktuelle Temperatur „T", die Solltemperatur „S", jeweils in °C
-Heizung „ein" oder „aus", und etwas, was sich im Zustand „ein" bewegt.

  1. Die Beschreibung in den Kommentaren sollte halbwegs nützlich sein.

  2. Die Formatierung sollte ein wenig Übersicht erlauben. Kann sicher besser, aber ich hab mir Mühe
    gegeben.

Das Ergebnis kommt nachfolgend im Code und sollte mit wenig Aufwand nachbaubar sein.
Lies sich nicht auf einmal machen, da dann die Message zu lang ist. Hoffentlich klappt das,
sonst teile ich den Code nachher auch noch in monatliche Zwölftel :slight_smile:

Danke an microBahner, der mir mit einer Engelsgedult vieles an Basiswissen mitgegeben hat.

Ohne den Crashkurs hätte das Programm sicher schlimm ausgesehen.

Obwohl man es sicher auch jetzt noch mit der Hälft an Aufwand schreiben könnte, wenn man mehr davon kennt, als ich es zur Zeit noch tue.

/* My first finalized project with a display ( 16x2 )
 *  
 * Thermostat für LiPo Heizkoffer
 * Thermostat fo LiPo  heating boxes
 * 
 * Written by skyfox60, but also with some copy paste from the arduino examples
 * 
 * LCD RS pin to digital pin 12
 * LCD Enable pin to digital pin 11
 * LCD D4 pin to digital pin 5
 * LCD D5 pin to digital pin 4
 * LCD D6 pin to digital pin 3
 * LCD D7 pin to digital pin 2
 * LCD R/W pin to ground
 * LCD VSS pin to ground
 * LCD VCC pin to 5V
 * 10K resistor 1:
 * ends to +5V and ground
 * wiper to LCD VO pin (pin 3) thats for the contrast
 * 10K resistor 2:
 * ends to +5V and ground
 * wiper to pin (pin A2) thats to set the max. Temp / heater off-Temp 
 * 
 * 
 */



#include <LiquidCrystal.h>

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

const unsigned int TEMP_SENSOR_PIN = A0;
const unsigned int Vorgabe = A2;
const float        SUPPLY_VOLTAGE =5.31;    // to be set to get correct measurements
unsigned long      interval = 1000 ;        // Time 1s if heater is on ( check if temp limit is reached, ones the limit is reached, it toggles to 60000 to ensure that if the heater is of, there is a min time
                                            // 2 min after temp is Limit-2 °C before theater may be swiched on again. That prevents fast on - off´s due to unstable readings around the measuring point.
                                            
unsigned long interval2 = 1000 ;            // Time after which the actual Temp is refresht on display
const long    moveinterval = 200 ;          //The small character on line 2, cursor  pos 15 ( down , right ) moves if heater is on
unsigned long currentMillis = millis() ;    // used to count the time to refresh the actual Temp on display
unsigned long previousMillis = 0 ;          // for the interval of refreshing the actual temp
unsigned long currentmoveMillis = millis() ;// sets, how fast the character moves if heater is on
unsigned long previousmoveMillis = 0 ;      // for the little boy shaking arms up an down during heater is on
unsigned long currentsmoothMillis = 0 ;     //used to have a timly hysteresis, otherwise when switching heater of, it toggles around to much
unsigned long previoussmoothMillis = 0 ;    // needed get defined switching points
bool m = 0;                                 //toggles the movement of the character lower line right                   
float Tempvorgabe=38.0; //default = 38      // just to remember the ideal temp to charge Lipo-batteries, otherwise value can be something
int Relais = (6);                           // activates my relais via a transistor
int Ledpin = 13;                            // not even necessary, used it during debug, but, set temp limit very near to actual temp and you´ll see it flash, but Relais is stable due to smoothing.
                                            // if you switch you Relais with the same condition, it will go on/off/on/off several times before heater is stably switched on. thats why the 1000/60000 Interval is given.
                                            
// make some custom characters: out of the examples, I just coy/paste it, not all needed here.
byte heart[8] = {
  0b00000,
  0b01010,
  0b11111,
  0b11111,
  0b11111,
  0b01110,
  0b00100,
  0b00000
};

byte smiley[8] = {
  0b00000,
  0b00000,
  0b01010,
  0b00000,
  0b00000,
  0b10001,
  0b01110,
  0b00000
};

byte frownie[8] = {
  0b00000,
  0b00000,
  0b01010,
  0b00000,
  0b00000,
  0b00000,
  0b01110,
  0b10001
};

byte armsDown[8] = {
  0b00100,
  0b01010,
  0b00100,
  0b00100,
  0b01110,
  0b10101,
  0b00100,
  0b01010
};

byte armsUp[8] = {
  0b00100,
  0b01010,
  0b00100,
  0b10101,
  0b01110,
  0b00100,
  0b00100,
  0b01010
};

byte aUmlaut[8] = {
  0b01010,
  0b00000,
  0b01110,
  0b00001,
  0b01111,
  0b10001,
  0b01111,
  0b00000
};
void setup() 
{
  
   
  pinMode (Ledpin, OUTPUT);
  pinMode (A2, INPUT);
  pinMode (Relais, OUTPUT);  
  lcd.begin(16, 2);
  
  
  lcd.createChar(0, heart);       // create a new character    / out of the examples
 
  lcd.createChar(1, smiley);      // create a new character
 
  lcd.createChar(2, frownie);     // create a new character
  
  lcd.createChar(3, armsDown);    // create a new character    / little boy with arms down
  
  lcd.createChar(4, armsUp);      // create a new character    /little boy with arms up
   
  lcd.createChar(5, aUmlaut);     // create a new character ä, which he did´nt out of the written text
  
  Serial.begin(9600);             //necessary only for debug

  delay(1000);                    // playing around a little at startup, only runs ones during startup in the setup region, so delays here are not harfull, 
                                  // so we can let off steam, and try and practise. 
  lcd.setCursor(0,0);
  lcd.print("Guten Tag Herr");
  
  lcd.setCursor(0, 1);
  lcd.print("Kapit");lcd.write(5);lcd.print("n  ");lcd.write(1);
  delay(2000);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Soll`s losgehen?"); // he only makes a `, if you write ´, it will not be shown as expected, damn.
  lcd.setCursor(15, 1);lcd.write((byte)3);
  delay(2000);
  lcd.setCursor(0, 1);
  lcd.print("na dann los  ");lcd.write(1);

  for(int a=1;a<=5;a++){
  lcd.setCursor(15, 1);
  // draw him arms up:
  lcd.write(4);
  delay(200);
  lcd.setCursor(15, 1);
  // draw him arms down:
  lcd.write(3);
  delay(200);  }
  
  lcd.clear();
}


//finally getting started
void loop() 
  
  {

  
  
  
// Temperatur prüfen und Heizung schalten / check temp and switch heater / main program

  int Temptest = analogRead(Vorgabe);
  int Tempbase = map(Temptest,0,1023,350,422);    // This maps the range of temp that can be set times 10 ( here it is 35°C to 42.2°C 
                                                  // (actually it makes 42.1 here due o rounding) ) times 10 needed to make a float out 
                                                  //of the mapped int afterwords
                                                  // Can be set toother ranges easily. The lower the range, the better to set with potmeter
  Tempvorgabe = Tempbase/10.0;                    // force "tempvorgabe" to have float value out of the int tempbase )
  
  
  const float tempC = get_temperature();
 
  lcd.setCursor(0, 1);lcd.print("S=");lcd.print(Tempvorgabe,1);lcd.write(0xDF),lcd.print("C");  //S means temp S-hould be ( value ) when heated up 
  
  
  if (digitalRead (Relais) == LOW){
      lcd.setCursor(15, 1);lcd.write((byte)3);}   // show and stay arms down for the little boy on line 2 when heater not working


   
  if (digitalRead (Relais) == HIGH) {             // this determins the speed of the movemend of the little boy lower line right
      currentmoveMillis = millis();
        
         if (currentmoveMillis - previousmoveMillis >= moveinterval) {   
             m=!m;
             previousmoveMillis = currentmoveMillis ;
   
    
}
// This moves the boy on last character of line 2 when heater is on at a speed of the value moveinterval
   if (m==1 ){
      lcd.setCursor(15, 1);
      lcd.write(4);
      //Serial.println(m);
   }
   if (m==0 ) {
      lcd.setCursor(15, 1);
      lcd.write(3);
     
   }}
        
// time to refresh the display an to do the real work ( switching the relais )
//Zeit, mal das Display zu aktualisieren und die eigentliche Arbeit zu erledigen, das Schalten des Relais
  currentMillis = millis();
  Serial.println( currentMillis - previousMillis);
  Serial.println( currentsmoothMillis - previoussmoothMillis);
  if (currentMillis - previousMillis >= interval2){   
      previousMillis = currentMillis ;
      lcd.setCursor(0, 0);              // write the first row of display
      lcd.print("T=");
      lcd.print(tempC,1);
      lcd.write(0xDF),lcd.print
      ("C");lcd.setCursor(9, 0);
      lcd.print("Heizung");
      lcd.setCursor(0, 1);              // write the first part of second row of display
      lcd.print("S=");
      lcd.print(Tempvorgabe,1);
      lcd.write(0xDF);
      lcd.print("C");
  }
  currentsmoothMillis = millis();
  if (currentsmoothMillis - previoussmoothMillis >= interval){   
      previoussmoothMillis = currentsmoothMillis ;
    
      if (tempC<=Tempvorgabe-2) { 
          lcd.setCursor(11, 1); 
          lcd.print("ein");              // fill the second row of display if heater is "ein" "on"
          digitalWrite(Relais, HIGH);
          interval = 1000;
      }      
  
    
            if (tempC>=Tempvorgabe) {
                lcd.setCursor(11, 1);
                lcd.print("aus");       // exchange the "ein" "on" to "aus "of" in second row of the display
                digitalWrite(Relais, LOW);
                interval = 60000;
              
  }}
    
     lcd.setCursor(0,0);
 
  
   }
 
  // calculate the temp out of the readings of the sensor TMP36
  const float get_temperature()
  
  {const int sensor_voltage =analogRead(TEMP_SENSOR_PIN);
  const float voltage = sensor_voltage * SUPPLY_VOLTAGE /1024;
    return(voltage *1000-604) /10; 
    
  }       
  // normally -500, the additional 104 are a correction value to achieve the correct temp
  // If Voltage is not excatly 5V there is also deviation. You have to try a little bit 
  //with this value to calibrate measured temperature

Es hat sich da doch ein kleiner BUG eingeschlichen.
Wenn die Temperatur ( aktuell ) zweistellig unter 0 wird ( T=-10.0°C ), dann rückt das C in die Leerstelle vor "Heizung" So weit, so gut.
Wird es dann wärmer, bleibt in der erstelle ein zweites C stehen.
Manchmal denkt man halt nur von 12 bis Mittag:-)

if (currentMillis - previousMillis >= interval2){
previousMillis = currentMillis ;
lcd.setCursor(0, 0); // write the first row of display
lcd.print("T=");
lcd.print(tempC,1);
lcd.write(0xDF),lcd.print
("C");lcd.setCursor(9, 0);

Man suche im Code die fett gedruckte Stelle und ersetze sie durch:

lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 0); // write the first row of display

das sieht dann so aus:

if (currentMillis - previousMillis >= interval2){   
      previousMillis = currentMillis ;
      lcd.setCursor(0, 0);
      lcd.print("         ");
      lcd.setCursor(0, 0);              // write the first row of display
      lcd.print("T=");
      lcd.print(tempC,1);
      lcd.write(0xDF),lcd.print
      ("C");lcd.setCursor(9, 0);

Jetzt wird das überflüssige C zur rechten Zeit nicht mehr erscheinen.

Die Zeitkonstanten hängen stark von der Heizleistung ab, falls jemand sowas nachbauen möchte.

Zwar sind Zweipunktregler beim Heizen quasi Standard, doch könnte man die Zeitkonstanten mit PWM (weniger Heizleistung) etwas niedriger gestalten. Das geht dann natürlich nur noch mit FET statt Relais. Aber wer unbedingt das Klicken hören möchte, kann das Relais ja wie bisher schalten.

Kann man machen, ja.

Macht aber in dem Fall nur bedingt Sinn.
Die Heizkoffer sind meist so ausgelegt, das man im Winter eh ständig volle Heizleistung benötigt, um überhaupt auf Temperatur zu kommen. Die Stromquellen haben häufig begrenzte Leistung, die man besser zum Laden verwendet, als zu Heizen.

Dann werden die dauernd geöffnet, weil man Akkus einlegt oder entnimmt.
Dabei ist die Temp. zack wieder weg.

Mit der Art Thermostat laufen die jedenfalls bisher alle genauso wie man das haben will/muss.

Warum da umstädlich High-Tec einbauen, wenn es so einfach geht.
Und das ist "nur Elektrik" zum Anschliessen, keine zu komplizierte Elektronik, mit der nicht jedermann zurecht kommt.

Ich hatte ja debei geschrieben, dass das für andere Anwendungsfälle durchaus anpassbar ist.
Hier ist es speziell auf diese Anwendung quasi auf dem freien Feld konzipiert.

Hi

Gerade mit diesem Post verstehe ich Deinen Aufwand gar nicht mehr - einen Akku, einen Thermostaten (gibt's auch zum auf die Wand schrauben, so ein Ding mit Drehrad) und eine Heizpatrone, Die von dem Akku direkt betrieben werden kann.

  • 1x Thermostat
  • 1x Akku
  • 3x Strippe zwischen Akku->Thermostat->Heizpatrone->Akku

Vll. noch einen Schalter, damit man die Heizung auch komplett aus bekommt - also zusätzlich einen Schalter und eine weitere Strippe.

Hier sehe ich absolut keine Notwendigkeit für eine Intelligenz.
Hier wird von der Funktion ja kein Härte-Ofen benötigt.

MfG

Wenn ich einen kleinen Alukoffer habe, in dem eine mehr oder weniger gut isolierte Box ist, beheizt, damit ich dort PiPo-Akkus einlegen kann und diese warm werden, damit sie geladen werden können unter optimalen Bedingungen ( also etwa bei 38-42°C ),dann nutzt mir ein an die Wand geschraubtes Thermostat wenig.

Und wieso den Akku mit dem Thermostat verbinden?
Der soll doch nur geladen werden in der Box.
Und wenn ich mit dem Akku die Heizung betreibe, wer heizt dann weiter, wenn der Akku wieder im Flugzeug oder Hubschrauber sitzt?
Da hast du gleube ich, etwas mißverstanden.

Die notwendigen 12V kommen von der Wand, oder vom im Koffer, jedoch außerhalb des Heizbehälters gelegenen Servernetzteil. Wir haben am Modellflugplatz 12V und 230V zur Verfügung am Ladetisch.

Ja, man kann das auch mit einem simplen Thermoschalter machen ( wobei hier meist die Hysterese zu groß ist ).

Es geht aber darum, das mit einem Arduino zu machen, auch weil es Spaß macht, und ich dadurch lernen kann, Programmierung zu verstehen. ( mache das ja erst ein paar Wochen )

So ein Thermostat kann man in China teilw. für < 2€ kaufen. Einfach gestrickte Anzeige ( nur IST-Temp.)

Ist aber eben hier nicht Sinn der Sache.

Der "Aufwand" dient mir persönlich eher dem Lernen und Spieltrieb.

Und letzterer wurde grad wieder angeregt.
Das Thermostat soll jetzt ein Display bekommen mit RGB-Hintergrundbeleuchtung, die von Blau über den Regenbogen bis Rot den Temperaturbereich abdeckt, so das man schon aus der Ferne sehen kann, ob das mit dem Laden bald losgehen kann usw.
Völlig unnötig, man könnte ja hingehen und die Temp. ablesen.
Aber Spaß wird es machen, das sauber da rein zu programmieren.
Zerlegung des Regenbogens in den Farbkreis.
Anpassung des relativ kleinen Temp.-Bereiches auf 360° Farbkreis, die Übergänge möglichst fliessend.

All das ist für die eigentliche Funktion weit mehr als überflüssig.
Wird aber trotzdem gemacht, weil...
es Spaß macht.