Guten Tag,
ich habe kaum Erfahrung im Programmieren und bräuchte mal eure Hilfe…
Schonmal im Voraus: Ich benutze einen Arduino Uno mit dem 4 Relays Shield.
Und zwar hab ich eine Temperaturerkennung über einen DS18B20. Bei Unterschreitung einer gewissen Temperatur wird ein Relais geschalten, welches eine Heizung ansteuern soll(Relay1) und eines, welche eine Meldeleuchte zur Erkennung des Schaltzustandes ansteuert(Relay2)
Relay3 zeigt an, ob der Arduino in Betrieb ist bzw. die Anlage eingeschaltet ist.
Das funktioniert auch alles soweit.
Allerdings möchte ich, dass wenn nach 10 Minuten nach dem Einschalten der Heizung kein Temperaturunterschied von beispielsweise 2 Grad vorhanden sein sollte, Relay4 geschalten wird und bestenfalls das Programm stehen bleibt oder initialisiert und beispielsweise über einen Eingangspin zurückgesetzt wird.
Hier das bisherige Programm:
#include <OneWire.h>
#include <DallasTemperature.h>
// Pindefinierung DS18B20 und die Relay Shield
#define ONE_WIRE_BUS A2
#define RELAY1 4
#define RELAY2 7
#define RELAY3 8
#define RELAY4 12
// Initialisierung OneWire-Bus und DallasTemperature
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
void setup() {
// Initialisierung Serieller Monitor
Serial.begin(9600);
// Initialisierung Relay Shield
pinMode(RELAY1, OUTPUT);
pinMode(RELAY2, OUTPUT);
pinMode(RELAY3, OUTPUT);
pinMode(RELAY4, OUTPUT);
// Start DallasTemperature Sensor
sensors.begin();
}
void loop() {
// Lesen Temperatur DS18B20
sensors.requestTemperatures();
float tempC = sensors.getTempCByIndex(0);
// Ausgabe Serieller Monitor
Serial.println(tempC);
// Schalten Relay1 und Relay2: Steuerung und Anzeige Heizlüfter
if(tempC < 5) {
digitalWrite(RELAY1, HIGH);
digitalWrite(RELAY2, HIGH);
}
if(tempC > 10) {
digitalWrite(RELAY1, LOW);
digitalWrite(RELAY2, LOW);
}
// Schalten Relay3: Anzeige Steuerung Ein
digitalWrite(RELAY3, HIGH);
}
Wofür soll das gut sein? Das Programm könnte doch einfach warten, bis ihm jemand oder etwas anzeigt, daß es weiterlaufen soll.
Wenn "das Programm initialisiert" bedeutet das, dass die 10 Minuten Wartezeit und alles andere vorher vergessen wäre. Das willst du nicht.
#include <OneWire.h>
#include <DallasTemperature.h>
// Pindefinierung DS18B20 und die Relay Shield
#define ONE_WIRE_BUS A2
constexpr byte RELAY1 {4};
constexpr byte RELAY2 {7};
constexpr byte RELAY3 {8};
constexpr byte RELAY4 {12};
unsigned long startHeizung;
constexpr unsigned long heizZeitTimeOut = {1000UL * 60 * 10};
int heizStartTemperatur;
constexpr int checkTempHyterese {2};
// Initialisierung OneWire-Bus und DallasTemperature
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
void setup()
{
// Initialisierung Serieller Monitor
Serial.begin(9600);
// Initialisierung Relay Shield
pinMode(RELAY1, OUTPUT);
pinMode(RELAY2, OUTPUT);
pinMode(RELAY3, OUTPUT);
pinMode(RELAY4, OUTPUT);
// Schalten Relay3: Anzeige Steuerung Ein
digitalWrite(RELAY3, HIGH);
// Start DallasTemperature Sensor
sensors.begin();
}
void loop()
{
// Lesen Temperatur DS18B20
sensors.requestTemperatures();
float tempC = sensors.getTempCByIndex(0);
// Ausgabe Serieller Monitor
Serial.println(tempC);
// Schalten Relay1 und Relay2: Steuerung und Anzeige Heizlüfter
if (tempC < 5)
{
if (digitalRead(RELAY1) == LOW)
{
digitalWrite(RELAY1, HIGH);
startHeizung = millis();
heizStartTemperatur = tempC;
digitalWrite(RELAY2, HIGH);
}
else
{
if (millis() - startHeizung > heizZeitTimeOut &&
tempC < heizStartTemperatur + checkTempHyterese)
{
if (digitalRead(RELAY4) == HIGH)
{
Serial.println(F("HEIZUNG AUSGEFALLEN!"));
}
digitalWrite(RELAY4, LOW);
}
}
}
if (tempC > 10)
{
digitalWrite(RELAY1, LOW);
digitalWrite(RELAY2, LOW);
}
}
1 Like
Moin @my_xy_projekt ,
sollte vermutlich so heißen
if (millis() - startHeizung > heizZeitTimeOut &&
tempC < heizStartTemperatur + checkTempHyterese)
{
if (digitalRead(RELAY4) == HIGH)
{
Serial.println(F("HEIZUNG AUSGEFALLEN!"));
}
digitalWrite(RELAY4, HIGH); // <- Hier das Fehler-Relais schalten!!!!
Moin,
NÖ
Das ist so ein kleiner Gag am Rande....
Die Bedingung lautet: Zeit abgelaufen && temperatur nicht erhöht
Die Reaktion soll sein: Dann mach den Pin LOW (und signalisiere damit, das irgendwas fail ist)
Soweit so gut.
Was mir jetzt auffällt, ist die fehlende Aktivierung des PIN im setup().
Die RelaisShields sind eigentlich LOW-aktiv - der müsste also im setup() HIGH gezogen werden.
Und dann kommt die Bedingung davor zum tragen.
Die sorgt nämlich dafür, das die Meldung nur einmal ausgeführt wird und nicht den SerMOn flooded...
(Gut zu wissen, das wer auch meine Codes liest )
Wenn ich mich nicht täusche, benutzt der TO die Relaisansteuerung so, dass HIGH gleich "Eingeschaltet" und LOW = "Ausgeschaltet" ist ...
P.S.: Hab's bei Wokwi nachgestellt ... (allerdings mit 10 s statt 10 min)
Guckst Du hier:
// Schalten Relay3: Anzeige Steuerung Ein
digitalWrite(RELAY3, HIGH);
Dann ists aber richtig falsch.
Wenn die Pegel vertauscht sind, gehört's so:
if (digitalRead(RELAY4) == LOW)
{
Serial.println(F("HEIZUNG AUSGEFALLEN!"));
}
digitalWrite(RELAY4, HIGH);
Sonst hätte die Bedingung auf die PIN-Abfrage keinen Effekt.
Jo, das sieht gut aus!!
Du hast die kurze Fassung mit minimalen Änderungen geschrieben, ich habe mal eine längere Ausführung mit StateMachine verbrochen ...
Sketch
#include <OneWire.h>
#include <DallasTemperature.h>
// Pindefinierung DS18B20 und vom Relay Shield
constexpr byte ONE_WIRE_BUS = A2;
constexpr byte noOfRelays = 4;
enum relayNames {HEIZUNG, HEIZANZEIGE, STEUERUNGSANZEIGE, FEHLERANZEIGE};
byte relayPin[noOfRelays] = {4, 7, 8, 12};
// Parameter und Steuerungsmodi
constexpr unsigned long MessIntervall = 1000UL;
constexpr unsigned long AlarmIntervall = 10*60*1000UL;
constexpr float minTemp = 5.0;
constexpr float maxTemp = 10.0;
constexpr float differenzTemp = 2.0;
float startTemp;
enum SteuerungsModus {DONOTHING, STARTHEATING, HEATING, STOPHEATING, ERROR};
SteuerungsModus modus = DONOTHING;
SteuerungsModus lastModus = ERROR;
unsigned long heizungsStart;
unsigned long heizungsSekunden;
float actTemperature;
// Initialisierung OneWire-Bus und DallasTemperature
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
void switchOn(relayNames rel) {
digitalWrite(relayPin[rel], HIGH);
}
void switchOff(relayNames rel) {
digitalWrite(relayPin[rel], LOW);
}
void checkTemperature() {
// Lesen Temperatur DS18B20
sensors.requestTemperatures();
actTemperature = sensors.getTempCByIndex(0);
// Ausgabe Serieller Monitor
Serial.print("Aktuell: ");
Serial.print(actTemperature);
if (modus == HEATING) {
Serial.print("\tStarttemperatur: ");
Serial.print(startTemp);
Serial.print("\t seit ");
Serial.print(heizungsSekunden);
Serial.print(" [s]");
}
Serial.println();
}
void messung() {
static unsigned long letzteMessung = 0;
if (millis() - letzteMessung > MessIntervall) {
letzteMessung = millis();
checkTemperature();
}
}
// {DONOTHING,STARTHEATING, HEATING, STOPHEATING, ERROR};
void stateMachine() {
static unsigned long lastCheck = 0;
messung();
switch (modus) {
case DONOTHING:
if (actTemperature < minTemp) {
modus = STARTHEATING;
}
break;
case STARTHEATING:
switchOn(HEIZUNG);
switchOn(HEIZANZEIGE);
heizungsStart = millis();
startTemp = actTemperature;
heizungsSekunden = 0;
modus = HEATING;
break;
case HEATING:
//Check for temp!
if (actTemperature > maxTemp) {
modus = STOPHEATING;
return;
};
if (millis()-lastCheck >= 1000) {
lastCheck = millis();
heizungsSekunden++;
}
if (millis() - heizungsStart > AlarmIntervall && actTemperature - startTemp < differenzTemp) {
Serial.println("Error!");
switchOff(HEIZUNG);
switchOff(HEIZANZEIGE);
switchOff(STEUERUNGSANZEIGE);
switchOn(FEHLERANZEIGE);
modus = ERROR;
}
break;
case STOPHEATING:
switchOff(HEIZUNG);
switchOff(HEIZANZEIGE);
modus = DONOTHING;
break;
case ERROR:
break;
}
}
void setup() {
Serial.begin(115200);
for (int i = 0; i < noOfRelays; i++) {
pinMode(relayPin[i], OUTPUT);
}
sensors.begin();
switchOn(STEUERUNGSANZEIGE);
}
void loop() {
stateMachine();
}
siehe Wokwi: https://wokwi.com/projects/366995199527696385
Mit kleinen Änderungen:
Messen der Temperatur nur im Sekundentakt
Schalten der Relais nur je einmal bei Bedarf
Ausdruck der Starttemperatur und der Sekunden seit Beginn des Heizens
Im Fehlerfall alle Relais aus, bis auf die Fehleranzeige
Die Steuerung ist im Fehlerfall nur durch ein Reset wieder zu starten (hier fehlt eine automatische Rücksetz-Bedingung oder ein Knöpfchen ...)
1 Like
ec2021
June 8, 2023, 8:28pm
10
Moin, @sabriadr ,
wenn Du magst, gerne mal in den Post #9 reinschauen...
Ich wollte abwarten, was da noch kommt ....
Habe vergeblich gewartet.
1 Like
Guten Morgen,
vielen Dank für die schnelle Hilfe, ich bin erst jetzt dazu gekommen, das Programm aufzuspielen.
Funktioniert alles soweit, aber könntet ihr mir eventuell noch mit dem Resetknopf helfen?
Wenn es wirklich komplett von vorn losgehen soll, kann man durchaus den Reset-Pin verwenden.
Der Sketch fängt dann wie beim Einschalten mit setup() wieder an.
ec2021
June 12, 2023, 8:51am
14
Schon klar, aber dazu muss der Resetknopf dann natürlich irgendwie zugänglich sein (falls das Ganze eingehäust wird), oder ein Knöpfchen wird nach außen gelegt.
Letztlich bleibt die "Standard-Methode", Stecker raus, warten, Stecker rein
Bei einer ggf. nicht überwachten Steuerung würde ich vorsichtshalber noch den Einbau einer automatische Abschaltung prüfen. Dazu müsste man aber mehr über die Umstände der Anwendung wissen ...
Daher sprach ich vom Reset Pin , an den man einen Taster anschließen kann
ec2021
June 12, 2023, 9:07am
16
Dann sind wir uns doch einig
hier fehlt eine automatische Rücksetz-Bedingung oder ein Knöpfchen ...
Ja das klingt ist gut, danke euch.
Mir ist nun aufgefallen, dass der Arduino beim Starten nicht automatisch abschält, wenn er von Beginn an heizt… Gibt es da eine Möglichkeit?
ec2021
June 12, 2023, 9:13am
18
Ich würde zusätzlich noch eine z.B. im einfachsten Fall zeitgesteuerte Abschaltung vorsehen, um ein dauerhaftes Heizen zu vermeiden, falls ein Sensorfehler auftritt.
Da ein Temperatursensor nicht viel kostet, könnte man auch auf Redundanz setzen.
Wie sieht's Du das?
ec2021
June 12, 2023, 9:30am
19
Normalerweise wird ein Digitalpin mit pinMode(Pin, OUTPUT) auf LOW initialisiert.
Damit sollte das Heizungsrelais nach einem Restart nicht anziehen.
Die folgenden Zeilen an geeigneter Stelle erzeugen auch den bisher angenommenen Einschaltzustand.
digitalWrite(RELAY1, LOW);
digitalWrite(RELAY2, LOW);
digitalWrite(RELAY3, HIGH);
digitalWrite(RELAY4, LOW);
Solltest Du aber den Ruhekontakt des Relais für die Heizung verwenden, wäre das nicht ok.
Das hätte aber die Folge, dass die Heizung auch dann immer läuft, wenn die Steuerung stromlos ist...
Wo wäre denn die geeignete Stelle?