// CLK = D2; DT = D3; SW = D4; SSR = D6; SCL = A5; SDA = A4; SCK = D13; CS = D10; SO = D11;
#include <PID_v1.h>
//#include <EEPROM.h>
//#include „EEPROMAnything.h“
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RotaryEncoder.h>
#include „max6675.h“
// Rotary Encoder
#define PIN_IN1 2
#define PIN_IN2 3
#define Button 4
// LCD Display
LiquidCrystal_I2C lcd(0x27, 20, 4);
const int thermoDO = 11;
const int thermoCS = 10;
const int thermoCLK = 13;
MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);
RotaryEncoder encoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::FOUR3);
int Aufheizen = 0;
int PreAufheizen;
int Abkuehlen = 0;
int PreAbkuehlen;
int x, k;
int y = 0;
int newPos;
int pos;
double TempPoint = 25;
double PreTempPoint;
const int Spirale = 6;
double Output;
double IstTemp;
bool los;
bool PostAbkuehlen = false;
int Val1;
int PreVal;
double Kp=10, Ki=0, Kd=0;
PID myPID(&IstTemp, &Output, &TempPoint, Kp, Ki, Kd, DIRECT);
void setup() {
Serial.begin(9600);
pinMode(Button, INPUT_PULLUP);
pinMode(Spirale, OUTPUT);
lcd.begin();
lcd.backlight();
encoder.setPosition(1);
IstTemp = thermocouple.readCelsius();
// EEPROM_readAnything(0, Kp);
// EEPROM_readAnything(1, Ki);
// EEPROM_readAnything(2, Kd);
// EEPROM_readAnything(3, TempPoint);
// EEPROM_readAnything(4, Aufheizen);
// EEPROM_readAnything(5, Abkuehlen);
//windowStartTime = millis();
//initialize the variables we’re linked to
pos = 0;
PreTempPoint = TempPoint;
los = false;
y = 0;
//tell the PID to range between 0 and the full window size
//myPID.SetOutputLimits(0, WindowSize);
//turn the PID on
myPID.SetMode(AUTOMATIC);
Startbildschirm();
}
void loop() {
myPID.Compute();
pos = 1;
Startseite();
if (los == true) Heizen();
if (digitalRead(Button) == LOW)
{
delay(1000);
if (digitalRead(Button) == LOW)
{
if (los == true) {
los = false;
digitalWrite(Spirale, LOW);
lcd.clear();
lcd.setCursor(9, 1);
lcd.print(„STOP“);
delay(4000);
lcd.clear();
}
else {
if (Aufheizen != 0) {
//PreTempPoint = TempPoint;
PreAufheizen = Aufheizen;
TempPoint = 0;
}
if (Abkuehlen != 0) {
//PreTempPoint = TempPoint;
PreAbkuehlen = Abkuehlen;
}
los = true;
lcd.clear();
lcd.setCursor(7, 1);
lcd.print(„HEIZEN“);
delay(4000);
lcd.clear();
}
}
else
{
lcd.clear();
delay(500);
Auswaehlen();
}
}
}
// Solltemperatur einstellen
void Auswaehlen() {
encoder.setPosition(pos);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(„Temp.-Konfigurieren“);
lcd.setCursor(2, 1);
lcd.print(„Soll-Temp. :“);
lcd.setCursor(2, 2);
lcd.print(„Aufheizzeit:“);
lcd.setCursor(2, 3);
lcd.print(„Abk\xF5hlzeit :“);
lcd.setCursor(16, 1);
lcd.print(int (TempPoint));
lcd.setCursor(16, 2);
lcd.print(Aufheizen);
lcd.setCursor(16, 3);
lcd.print(Abkuehlen);
lcd.setCursor(0, pos);
lcd.print(„\x7E„);
do {
encoder.tick();
newPos = encoder.getPosition();
if (pos != newPos) {
pos = newPos;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(„Temp.-Konfigurieren“);
lcd.setCursor(2, 1);
lcd.print(„Soll-Temp. :“);
lcd.setCursor(2, 2);
lcd.print(„Aufheizzeit:“);
lcd.setCursor(2, 3);
lcd.print(„Abk\xF5hlzeit :“);
lcd.setCursor(16, 1);
lcd.print(int (TempPoint));
lcd.setCursor(16, 2);
lcd.print(Aufheizen);
lcd.setCursor(16, 3);
lcd.print(Abkuehlen);
lcd.setCursor(0, pos);
lcd.print(„\x7E„);
if (pos == 4) {
pos = 1;
PIDmenu();
break;
}
if (pos == 0) {
pos = 3;
PIDmenu();
break;
}
}
if (digitalRead(Button)==LOW) {
delay(1000);
if (digitalRead(Button) == LOW) x = 1;
else Einstellen1();
delay(500);
}
} while(x<1);
x=0;
lcd.clear();
delay(500);
Startseite();
}
void Einstellen1() {
lcd.setCursor(0, pos);
lcd.print(„\xA5„);
if (pos == 1)
{
encoder.setPosition(TempPoint);
Val1 = TempPoint;
}
if (pos == 2)
{
encoder.setPosition(Aufheizen);
Val1 = Aufheizen;
}
if (pos == 3)
{
encoder.setPosition(Abkuehlen);
Val1 = Abkuehlen;
}
do {
encoder.tick();
PreVal = encoder.getPosition();
if (Val1 != PreVal) {
Val1 = PreVal;
if (pos == 1) {
TempPoint = Val1;
PreTempPoint = TempPoint;
//EEPROM_writeAnything(3, TempPoint);
lcd.setCursor(16, 1);
lcd.print(int (TempPoint));
}
if (pos == 2) {
Aufheizen = Val1;
//EEPROM_writeAnything(4, Aufheizen);
lcd.setCursor(16, 2);
lcd.print(Aufheizen);
}
if (pos == 3) {
Abkuehlen = Val1;
//EEPROM_writeAnything(5, Abkuehlen);
lcd.setCursor(16, 3);
lcd.print(Abkuehlen);
}
}
if (digitalRead(Button)==LOW) x = 1;
} while(x<1);
if (pos == 1) encoder.setPosition(2);
if (pos == 2) encoder.setPosition(3);
if (pos == 3) encoder.setPosition(1);
x=0;
lcd.clear();
delay(500);
}
void Einstellen2() {
lcd.setCursor(0, pos);
lcd.print(„\xA5„);
if (pos == 1)
{
encoder.setPosition(Kp);
Val1 = Kp;
}
if (pos == 2)
{
encoder.setPosition(Ki);
Val1 = Ki;
}
if (pos == 3)
{
encoder.setPosition(Kd);
Val1 = Kd;
}
do {
encoder.tick();
PreVal = encoder.getPosition();
if (Val1 != PreVal) {
Val1 = PreVal;
if (pos == 1) {
Kp = Val1;
//EEPROM_writeAnything(0, Kp);
lcd.setCursor(6, 1);
lcd.print(Kp);
}
if (pos == 2) {
Ki = Val1;
//EEPROM_writeAnything(1, Ki);
lcd.setCursor(6, 2);
lcd.print(Ki);
}
if (pos == 3) {
Kd = Val1;
//EEPROM_writeAnything(2, Kd);
lcd.setCursor(6, 3);
lcd.print(Kd);
}
}
if (digitalRead(Button)==LOW) x = 1;
} while(x<1);
if (pos == 1) encoder.setPosition(2);
if (pos == 2) encoder.setPosition(3);
if (pos == 3) encoder.setPosition(1);
x=0;
lcd.clear();
delay(500);
}
void Startseite() {
TempMessen();
lcd.setCursor(0, 0);
lcd.print(„Ist-Temp. :“);
lcd.setCursor(0, 1);
lcd.print(„Soll-Temp. :“);
lcd.setCursor(0, 2);
lcd.print(„Aufheizzeit:“);
lcd.setCursor(0, 3);
lcd.print(„Abk\xF5hlzeit :“);
lcd.setCursor(13, 0);
lcd.print(int (IstTemp));
lcd.print(„\xDF„);
lcd.print(„C“);
lcd.setCursor(13, 1);
lcd.print(int (TempPoint));
lcd.print(„\xDF„);
lcd.print(„C“);
lcd.setCursor(13, 2);
lcd.print(Aufheizen);
lcd.print(„min“);
lcd.setCursor(13, 3);
lcd.print(Abkuehlen);
lcd.print(„min“);
}
void Startbildschirm() {
lcd.clear();
lcd.setCursor(4, 1);
lcd.print(„HAND-FORGED“);
lcd.setCursor(4, 2);
lcd.print(„Version 1.0“);
delay(4000);
lcd.clear();
Startseite();
}
void PIDmenu() {
encoder.setPosition(pos);
lcd.clear();
lcd.setCursor(2, 0);
lcd.print(„PID-Konfigurieren“);
lcd.setCursor(2, 1);
lcd.print(„P:“);
lcd.setCursor(2, 2);
lcd.print(„I:“);
lcd.setCursor(2, 3);
lcd.print(„D:“);
lcd.setCursor(6, 1);
lcd.print(Kp);
lcd.setCursor(6, 2);
lcd.print(Ki);
lcd.setCursor(6, 3);
lcd.print(Kd);
lcd.setCursor(0, pos);
lcd.print(„\x7E„);
do {
encoder.tick();
newPos = encoder.getPosition();
if (pos != newPos) {
pos = newPos;
lcd.clear();
lcd.setCursor(2, 0);
lcd.print(„PID-Konfigurieren“);
lcd.setCursor(2, 1);
lcd.print(„P:“);
lcd.setCursor(2, 2);
lcd.print(„I:“);
lcd.setCursor(2, 3);
lcd.print(„D:“);
lcd.setCursor(6, 1);
lcd.print(Kp);
lcd.setCursor(6, 2);
lcd.print(Ki);
lcd.setCursor(6, 3);
lcd.print(Kd);
lcd.setCursor(0, pos);
lcd.print(„\x7E„);
if (pos == 4) {
pos = 1;
Auswaehlen();
break;
}
if (pos == 0) {
pos = 3;
Auswaehlen();
break;
}
}
if (digitalRead(Button)==LOW) {
delay(1000);
if (digitalRead(Button) == LOW) x = 1;
else Einstellen2();
}
} while(x<1);
x=0;
lcd.clear();
delay(500);
}
void Heizen() {
if (k == 300) {
// Wenn die Ist-Temperatur höher is als die Voreingestellte, Abkühlzeit vorhanden ist und die Aufheizzeit vor ist
if (PreTempPoint <= IstTemp) {
if (Abkuehlen > 0) {
if (Aufheizen == 0) PostAbkuehlen = true;
}
}
if (PostAbkuehlen == true) {
TempPoint = TempPoint – (PreTempPoint/PreAbkuehlen);
Abkuehlen = Abkuehlen – 1;
if (Abkuehlen == 0) los = false;
} else {
if (Aufheizen != 0) {
TempPoint = (PreTempPoint/PreAufheizen) + TempPoint;
Aufheizen = Aufheizen – 1;
}
}
k = 0;
lcd.clear();
}
k++;
if (Output > 0) digitalWrite(Spirale, HIGH);
else digitalWrite(Spirale, LOW);
}
void TempMessen() {
if (y == 10) {
IstTemp = thermocouple.readCelsius();
y = 0;
// Der Temperatursensor kann nur maximal alle 0,5 Sekunden abgefragt werden
}
y++;
delay(100);
}
Cool,
vielen Dank für die schnelle und doch recht umfangreiche Beschreibung der Steuerung in deinem Blog.
Hi,
ich bekomme Fehlermeldungen beim Compilieren der Steuersoftware.
Könntest du mir das File was bei dir funktioniert vielleicht mailen oder als download bereitstellen?
Danke
Thomas
Hi Thomas
aus der Ferne lässt sich ein Fehler ohne weitere Angaben nicht beheben. Welche Fehlermeldung bekommst du denn? Hast du die Bibliotheken von mir heruntergeladen und in den entsprechenden Ordner getan?
Gruß Glenn
Hi,
ich hab die Fehler gefunden, sie entstehen beim Kopieren des Codes von der Webseite, manche der Zeichen werden anscheinend nicht verfälscht. Z.Bsp. “ und – Zeichen wurden nicht dargestellt. Deshalb meine Bitte es als Download bereitzustellen. 😉
LG
Thomas
Hallo Glenn,
tolles Projekt hast du da auf die Beine gestellt.
Ich bekomme allerdings, wie Thomas auch, Fehlermeldungen beim compilieren, die sich im Arduino Program unter „Werkzeuge“ und dann „Kodierung korrigieren“ beheben lassen sollten.
Zeile 11 muss ich aber die Gänsefüsschen in eckige Klammern ändern.
Beim compilieren blebt das Programm immer in der Zeile 405 mit dem Fehler : stray \303
hängen, kannst du mir da bitte weiterhelfen?
Hallo Thomas,
ich habe den Arduino-Code als Download bereitgestellt.
Hoffentlich können so die Fehler behoben werden. Wichtig sind die Bibliotheken, die ich im Blogbeitrag auch bereitgestellt habe.
Wieso er bei dir bei Zeile 405 hängen bleibt? Keine Ahnung!
An der Stelle ist nur eine einfache Wenn-Dann abfrage, die keinen Fehler produzieren dürfte.
Gruß Glenn
Hi,
ich hätte noch eine Frage.
Könntest du ein Schaltdiagramm machen?
MAX6675 an D10,D11,D13,GND,+5V
Rotary Encoder an D2,D3,D4,GND,+5V
I2C Interface an SCL,SDA,GND,+5V
SSR ???
Würde mir sehr helfen!
Danke
Thomas
Hi Thomas, ich habe einen Schaltplan hinzugefügt.
Gruß Glenn
Vielen Dank Glenn,
daß hilft mir sehr und ich bin beigeistert am basteln.
Vielen Dank
Thomas
Hallo Glenn,
Mit dem von dir bereitgestellen Code zum download hat das compilieren und programmieren sofort und ohne Fehler funktioniert.
Danke dafür.
Da ich meinen zukünftigen Ofen mit Kraftstrom betreiben möchte : schafft der Arduino an seinem Ausgang 3 parallel geschaltete SSR’s zu versorgen,(wäre am einfachsten), oder sollte ich noch einen Transistor dazwischen setzen ?
Gruß
Hartmut
Super Hartmut,
ich hab mittlerweile zwei SSR am Arduino dran und noch läuft er. Beide auch am gleichen Ausgang. Ich hab allerdings nicht nachgemessen, wie hoch der Verbrauch der SSR sind.
Gruß Glenn
Hallo Glenn, entschuldige bitte dass ich einen älteren Beitrag wieder kommentiere. Ich wollte mal fragen, ob du noch weißt wo du die Keramiktragrohre bestellt hast? Die sind recht schwer in Längen um die 40cm zu finden.
Hi Rudi,
ich hatte die Stangen damals hier bestellt:
https://www.keramik-kraft.com/
Hi Glenn,
kannst du noch die Library, die du für dein Display genutzt hast? Ideal vielleicht mit der Version? Ich habe schon einige durchprobiert, aber es scheint bisher nicht die richtige dabei gewesen zu sein.
Danke und schöne Grüße aus Franken,
Christoph
Hi Christoph,
die Bibliothek heist: „LiquidCrystal_I2C“. Ich hab leider keinen Link für dich. Nur die Datei selbst, die ich dir gleich per Mail zusende. Ich hoffe du kannst damit etwas anfangen.
Gruß Glenn