Thermometer mit 4x LED-Siebensegmentanzeigen, SAA1064 u. LM35

Hallo,
endlich habe ich es geschafft, den Code von ursprünglich einem LCD Display auf die Ausgabe auf LED Anzeigen aufzubohren. Der SAA1064 eigent sich dafür sehr gut, denn er kümmert sich ums Multiplexen der Anzeige, um die Strombegrenzung der Anzeigen und man kann die Anzeige auch über lediglich 4 Adern etwas abgesetzt vom µC platzieren. 1m Kabel sind überhaupt kein Problem.
youtube Videos gibts davon genug, nur keinen fertigen Code.
Deshalb hier mein Code:

/*
Example 39.3 - NXP SAA1064 I2C LED Driver IC Demo III
Displaying numbers on command
http://tronixstuff.com/tutorials > chapter 39
John Boxall July 2011 | CC by-sa-nc
*/
#include "Wire.h" // enable I2C bus
#include <LiquidCrystal_I2C.h>
#define sensorPin 0    // Verbunden mit LM35 Ausgang
#define DELAY1 10      // kurze Wartezeit beim Messen
#define DELAY2 500     // kurze Wartezeit beim Anzeigen
#define heaterPin 9     // Heizung-Pin
#define threshold 40   // Schalt-Temperatur für Lüfter (40 Grad Celsius)
#define hysterese 0.1  // Hysterese-Wert (0.1 Grad Celsius)
const int cycles = 50; // Anzahl der Messungen
LiquidCrystal_I2C lcd(0x20, 16, 2); // Adresse auf 0x27 für 16 Zeichen/2 Zeilen

byte saa1064 = 0x70 >> 1; // define the I2C bus address for our SAA1064 (pin 1 to GND)
int digits[12]={
63, 6, 91, 79, 102, 109, 125,7, 127, 111, 204, 0};
// these are the byte representations of pins required to display each digit 0~9, °C sign, and blank digit
// right hand digit 180° flip - DP ist used as ° symbol :-) 204 is °c for big C use 143
void setup()
{
  lcd.init(); // LCD initialisieren
  lcd.backlight(); // Hintergrundbeleuchtung aktivieren  
pinMode(heaterPin, OUTPUT);
Wire.begin(); // start up I2C bus
delay(500);
initDisplay();
}
void initDisplay()
// turns on dynamic mode and adjusts segment current to 12mA
{
Wire.beginTransmission(saa1064);
Wire.write(B00000000); // this is the instruction byte. Zero means the next byte is the control byte
Wire.write(B01110111); // control byte (dynamic mode on, digits 1+3 on, digits 2+4 on, 21mA segment current
// left 111 is relevant for current left hand "1" 12mA, middle 6mA and right 3mA - so you can tewak it
Wire.endTransmission();
}
void clearDisplay()
{
Wire.beginTransmission(saa1064);
Wire.write(1); // start with digit 1 (right-hand side)
Wire.write(0); // blank digit 1
Wire.write(0); // blank digit 2
Wire.write(0); // blank digit 3
Wire.write(0); // blank digit 4
Wire.endTransmission();
}
void displayInteger(int num, int zero)
{
int hundred, ten, one;
// breakdown number into columns
hundred = num/100;
ten = (num-(hundred*100))/10;
one = num-((hundred*100)+(ten*10));
if (zero==1) // yes to leading zero
{
Wire.beginTransmission(saa1064);
Wire.write(1);
Wire.write(digits[hundred]);
Wire.write(digits[ten]+128); // 128 turns on DP
Wire.write(digits[one]);
Wire.write(digits[10]); // print position 10 from arry - °C
Wire.endTransmission();
delay(10);
}
else
if (zero==0) // no to leading zero
{
if (hundred==0) { hundred=11; }
if (hundred==0 && num<100) { hundred=16; }
if (ten==0 && num<10) { ten=16; }
Wire.beginTransmission(saa1064);
Wire.write(1);
Wire.write(digits[hundred]);
Wire.write(digits[ten]+128);
Wire.write(digits[one]);
Wire.write(digits[10]);
Wire.endTransmission();
delay(10);
}
}
void loop()
{
 {
float resultTemp = 0.0;
for(int i = 0; i < cycles; i++){
int analogValue = analogRead(sensorPin);
float temperature = (5.07 * 100.0 * analogValue) / 1024; // reale Spannung Ub (theoretisch 5.00V) 
resultTemp += temperature; // Aufsummieren der Messwerte
delay(DELAY1);
  } 
resultTemp /= cycles; // Berechnung des Durchschnitts
lcd.clear(); // clear-Methode löscht LCD Inhalt
lcd.print("Temp: "); // print-Methode schreibt LCD Inhalt
lcd.print(resultTemp);
lcd.setCursor(10, 0);
#if ARDUINO < 100
lcd.print(0xD0 + 15, BYTE); // Grad-Zeichen (Arduino 0022)
#else
lcd.write(0xD0 + 15); // Grad-Zeichen (Arduino 1.00)
#endif
lcd.print("C");
lcd.setCursor(0, 1); // setCorsor-Methode positioniert LCD-Cursor
lcd.print("Heizung: ");
{
delay(20);
}
clearDisplay();
{
displayInteger(resultTemp * 10 ,0); //for LED-Display x10 - DP is hardwired
 delay(5);
if(resultTemp < (threshold - hysterese)) // Temperaturvergleich pos.
digitalWrite(heaterPin, HIGH);           // Heizung anschalten
else if(resultTemp > (threshold + hysterese)) // Temperaturvergleich neg.
digitalWrite(heaterPin, LOW);                 // Heizung abschalten
lcd.print(digitalRead(heaterPin) == HIGH?"an":"aus");
delay(DELAY2);
}
}
}

Bei den Anzeigen handelt es sich um "Ostalgie"
Es sind Siebensegmentanzeigen des Typ VQA 28 Made in GDR 8)
Owohl ich den lichtstärksten Suffix F habe, sind die Dinger nicht besonders hell. Das ist auch der Symbolgröße von 17,9mm geschuldet. Deshalb bestrome ich die Dinger auch mit den max. möglichen 21mA, die der SAA1064 zuläßt :slight_smile:
Die rechte Stelle ist kopfstehend montiert, um den Dezimalpunkt als "°" Zeichen verwenden zu können. Die Segmente habe ich so verschaltet, als würde die Anzeige richtig herum montiert sein, also wie vom Hersteller angegeben. Wenn man anders verdrahtet, ist Pos. 10 im Arry für die Anzeige von °C entsprechend anzupassen!
204 als kleines c oberhalb der Mitte finde ich optisch am besten. 143 erzeugt ein großes C
Im Zehner (3. Stelle) wird 128 addiert, da 128 den Dezimalpunkt aktiviert. Segment a=1, b=2, c=4 usw. Aufaddieren erzeugt dann das anzuzeigende Zeichen.
displayInteger(resultTemp * 10 ,0); hat folgenden Sinn: die Temperatur wird x10 genommen, da ich für das LED Display eine 3stellige ganze Zahl benötige - der Dezimalpunkt (+128) ist hart gesetzt und bewirkt wieder die Division durch 10 beim Betrachter :wink:
,0 bedeutet, den Integerwert auf eine ganze Zahl zu runden - null Nachkommastellen
Für das ursprüngliche 16x2 I2C LCD Display habe ich den Code zur Kontrolle drin gelassen.
Ich habe das Ganze, wie man am Code erkennen kann, zur Steuerung eines Wärmeschrankes genutzt. Das LCD war mir dort zu schlecht ablesbar.
Meine Frage ist nun, wie kann ich die PID_v1 Lib. hier noch mit einbinden? Pin 9, der Heizungs-Pin steuert über einen Transistor die LED eines Solid-State-Relay an.
So mit festem Schaltpunkt, wie ich es jetzt habe, steigt die Temparatur nach dem Abschalten bei 40°C noch auf 41,5°C an, da die Heizwiderstände noch Wärme abgeben. Dieses Überschwingen ist aber nicht gewünscht :~
Kann mir da jemand weiterhelfen?

Gruß Gerald

nix_mehr_frei:
youtube Videos gibts davon genug, nur keinen fertigen Code.

Echt nicht? Mein Google findet auch für den SAA1064 problemlos Arduino-Code:

nix_mehr_frei:
So mit festem Schaltpunkt, wie ich es jetzt habe, steigt die Temparatur nach dem Abschalten bei 40°C noch auf 41,5°C an, da die Heizwiderstände noch Wärme abgeben. Dieses Überschwingen ist aber nicht gewünscht :~
Kann mir da jemand weiterhelfen?

Heizleistung stark überdimensioniert?
Dann vielleicht eine Heizung mit etwas weniger Leistung verwenden!

Am billigsten wäre die Umrüstung per Software auf eine niedrigere Heizleistung.

Die billigste Lösung bei einer zu groß dimensionierten Heizleistung ist bei einer Zweipunkt-Regelung und Schalten mit SSR Relais: Taktung!

Für eine Taktung der Heizleistung habe ich hier mal einen kleinen Sketch für Heizungen mit SSR-Schaltung geschrieben:
http://forum.arduino.cc/index.php?topic=180102.msg1335839#msg1335839
Der Funktion wird einfach die gewünschte Heizleistung in Prozent als Parameter übergeben, das SSR Relais schaltet die Taktung dann selbständig. Um keine Schaltzeiten unter 1,0 Sekunden entstehen zu lassen ist die Regelung nur zwischen 10% und 90% Heizleistung aufs Prozent genau. Unterhalb 10% Heizanforderung wird die Heizung ausgeschaltet und über 90% Heizanforderung wird die Heizung voll eingeschaltet.

Wenn Du nun eine halb so starke Heizung haben möchtest, rufst Du (in einer "nicht blockierenden loop") auf:
heizen(50);
Und dann schaltet die Heizung immer 5 Sekunden ein, und 5 Sekunden aus.
Ergebnis: 50% Heizleistung innerhalb eines 10-Sekunden Intervalls.

Um ein Überschießen der Temperatur bei Deiner Zweipunktregelung zu vermeiden, könnte man sich auch geeignete Heizstufen überlegen mit Prozentwerten Heizleistung unter 100%, und dann eine Zwei- oder Dreipunktregelung machen. Z.B. für eine Solltemperatur von 40°C z.B. so heizen:
Isttemperatur <32°C ==> "heizen(100);"
Isttemperatur >=32 und <36°C==> "heizen(75);"
Isttemperatur >=36°C <39,5°C ==> "heizen(50);"
Isttemperatur zwischen 39,5 und 40 ==> zuletzt gesetzte Heizleistung beibehalten (Hysterese!)
Isttemperatur >= 40°C ==> "heizen(0)"

So dass im Endeffekt mit weniger Heizleistung geheizt wird, wenn man bereits nahe an der Zieltemperatur dran ist.
Bei dieser Art Regelung müßte aber die niedrigste geschaltete Heizleistung (z.B. 50%) immer noch ausreichend hoch sein, um die Zieltemperatur zu erreichen, sonst kann es Dir passieren, dass die Temperatur dauerhaft zu niedrig bleibt.

Den verlinkten SAA1064 Code habe ich ja als Basis genommen. Sieht man sogar noch ganz oben. Nur als Thermometer hat den keiner dokumentiert. Bei ELV gibts was mit dem MCP9801 http://www.elv.de/i2c-4-digit-led-display-i2c-4dled-komplettbausatz.html

Die Heizung ist eigentlich nicht überdimensioniert. Nur handelt es sich um Zementwiderstände, die wie ein Nachtspeicherofen noch Wärme speichern.
Hier hatte ich das Ganze mal vorgestellt: Heizungssteuerung für einen Behälter - #11 by nix_mehr_frei - Deutsch - Arduino Forum
Dachte nur, wenn es schon eine PID Lib gibt, ist deren Verwendung eleganter :wink:

Gruß Gerald

Ohne selbst Erfahrung damit gemacht zu haben würd ich sagen daß es mit einer PID Regelung auch gehen würde: du mußt halt selbst die 3 Parmeter finden.

Grüße Uwe

An die Parameter würde ich mich rantasten. Faustformelverfahren (Automatisierungstechnik) – Wikipedia
Ich weiß nur nicht, wie ich die PID Lib einbinden muß. Include bekomme ich noch hin, aber dann... :blush:
Und ich muß dem PID beibringen, das er PWM halt langsamer machen soll für ein SSR

Gruß Gerald

Und ich muß dem PID beibringen, das er PWM halt langsamer machen soll für ein SSR

Wer sagt denn, dass ein PID-Ausgang einen PWM ansteuern muss?

Begrenze den PID-Ausgang auf 0 - 100 und verwende jurs' heizen() Funktion.

Muß ich mal gucken, ob ich das hin bekomme. Das kann aber etwas dauern.
Den PID als Core Funktion würde ich aber auf alle Fälle favorisieren, da ich eventuell die Temperatur noch im Bereich von 35-40° einstellbar machen werde.

Gruß Gerald