Hallo zusammen ich habe den Code auf dem Tisch mit einem Nano erstellt bis ich damit zufrieden war. Zum Simulieren gibt es ein Steckbrett. Beim Nano blinkt die OnBoardLED bei jedem beschreiben der SDkarte. Dann den Code auf den UNO übertragen die OnBoardLED bleibt dunkel.Dies wurde schon in einem weiteren Post erläutert.
Also wieder 2ten Pin für den Schreibvorgang eingebunden.Hier Pin (9) . Geht Led an Pin 9 blinkt .Per Zufall gesehen das die LED nicht blinkt.Wird nichts gespeichert.
Sketch auf den Nano geladen zusätzlich Pin 9 mit Led beschaltet,hier blinkt die OnBoardLED aber nicht die Led an Pin 9.
/*
Code von my_xy_projekt Arduinoforum bearbeitet
===========================================================
Heizungsüberwachung – Arduino UNO R3
-----------------------------------------------------------
Funktionen:
- Messung Vorlauf/Rücklauf mit 3 x DS18B20 (OneWire-Bus)
- Erfassung der Zustände:
Brenner EIN/AUS / BZ
Ventil Heizung
Ventil Warmwasser
- Logging auf SD-Karte (nur bei Zustandsänderung)
- erweitert wenn Brenner Ein & BZ
loggen in sekundentakt
- Echtzeit über DS3231 RTC
- Alarm-Ausgang bei Vorlauf > 75 °C (mit Hysterese)
- zum Testen serielle Eingabe der Vorlauftemperatur 14.11.25
- Zähler der Alarme im EEPROM
Reset über Pin 5
-----------------------------------------------------------
Hardware:
- DS18B20 Data → Pin 2, Pullup 4,7kΩ nach 5V
- IO PINS
- Brenner
- BZ
- Ventil Warmwasser
- Alarm-LED/Relais
SD-Karte wie folgt an SPI-Bus angeschlossen:
- MOSI - Pin 11 auf Arduino Uno/Nano/Duemilanove/Diecimila
- MISO - Pin 12 auf Arduino Uno/Nano/Duemilanove/Diecimila
- CLK - Pin 13 auf Arduino Uno/Nano/Duemilanove/Diecimila
- SD-CS -Pin 10
- RTC DS3231 via I2C (A4 = SDA, A5 = SCL)
- ON-Board-LED Fehlererkennung
===========================================================
*/
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Wire.h>
#include <RTClib.h>
#include <SPI.h>
#include <SD.h>
#include <EEPROM.h>
// ----------------------------------------------------------
// Pinbelegung angepasst 30-10-25
// ----------------------------------------------------------
constexpr uint8_t ONE_WIRE_BUS{ 2 };
constexpr uint8_t VENTIL_WW_PIN{ 4 };
constexpr uint8_t RESET_PIN{ 5 }; // zum reset des Alarmzählers beim starten nach Ground verdrahten
constexpr uint8_t BRENNER_PIN{ 6 };
constexpr uint8_t BZ_PIN{ 7 };
constexpr uint8_t ALARM_PIN{ 8 };
constexpr uint8_t SP_PIN{ 9 }; // nur bei Uno Anzeige speichern
constexpr uint8_t SD_CS_PIN{ 10 };
constexpr uint8_t EEPROM_ADDR{ 0 }; // Die Adresse im EEPROM, an der der Zähler gespeichert wird
// ----------------------------------------------------------
// Globale Objekte
// ----------------------------------------------------------
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
RTC_DS3231 rtc;
File logfile;
DateTime now;
constexpr uint32_t _ONESECOND{ 1000 };
constexpr char heizungFile[]{ "heizung.csv" };
/* Für die Zählfunktion des Alarms */
// Globale oder statische Variablen, die ihren Zustand beibehalten müssen
static uint8_t zaehler = 0;
static int lastAlarmState = HIGH; // Der vorherige Zustand des Pins
constexpr uint32_t intervalOk{ _ONESECOND }; // LED 1 Sekunde an
constexpr uint32_t intervalFail{ 200 }; // Blink-Intervall (200ms an, 200ms aus)
bool writeSuccess = false; // Flag, das den Erfolg des letzten Schreibvorgangs speichert
// Schwellwerte für Alarm
constexpr uint8_t ALARM_ON_TEMP{ 75 }; // Alarm EIN über 75°C
constexpr uint8_t ALARM_OFF_TEMP{ 68 }; // Alarm AUS unter 68°C
constexpr bool alarmOn{ LOW }; // Pinzustand wenn Relais EIN geschaltet
constexpr bool alarmOff{ !alarmOn };
bool brennerStatus;
bool ventilHzgStatus;
bool ventilWWStatus;
// Letzte bekannte Zustände
bool alarmState = alarmOff;
bool BZStatus;
float tempVorlauf;
float tempRueckl_HZG;
float tempRueckl_WW;
/* 14-11-2025 Werteeingabe zum testen
Temperaturwert Vorlauf manuell setzen
*/
float temperaturWert = 0.0;
bool benutzeEingabeWert = false;
/*-------------------------------------*/
uint32_t lastCheckTime; // Merker, wann das letzte Mal die sensoren abgefragt wurden
uint32_t lastBlinkTime; // Merker, wann das letzte Mal blinkLed geschaltetn wurde
bool changed;
char speicher[10];
// ----------------------------------------------------------
// Adressen der Sensoren 3.11.25
// mit den Adressen könnte ich
// tempVorlauf = sensors.getTempCByIndex(1);
// gegen tempVorlauf = sensors.getTempC(sensorVlauf); ersetzen
//
// DeviceAddress sensorHzg = { 0x28, 0x55, 0x37, 0xB4, 0x00, 0x00, 0x00, 0x91 }; // Adresse Sensor 1
// DeviceAddress sensorVlauf = { 0x28, 0x4B, 0xCA, 0xB2, 0x00, 0x00, 0x00, 0x9A }; // Adresse Sensor 2
// DeviceAddress sensorWw = { 0x28, 0xEF, 0xD3, 0xB1, 0x00, 0x00, 0x00, 0x1D }; // Adresse Sensor 3
// ----------------------------------------------------------
// Setup
// ----------------------------------------------------------
void setup() {
Serial.begin(9600);
delay(300);
Serial.println(F("=== Heizungsüberwachung startet ==="));
inputPinInit();
// Ausgang konfigurieren (Alarm)
pinMode(ALARM_PIN, OUTPUT);
digitalWrite(ALARM_PIN, true); // Anfangszustand: aus
pinMode(SP_PIN, OUTPUT);
digitalWrite(SP_PIN, false); // Anfangszustand: aus
// RTC starten
if (!rtc.begin()) {
Serial.println(F("RTC nicht gefunden!"));
/* 31.10.25 */
}
/*
* erweitert am 13.11.25
* auskommentieren wenn nicht erwünscht
*/
if (rtc.lostPower()) {
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
lastCheckTime = millis();
/* 14.11.25 Zähler der Alarme */
// --- Logik zum Nullen beim Start ---
// Prüfen des RESET_PIN
if (digitalRead(RESET_PIN) == LOW) {
// Wenn der Pin mit Ground verbunden ist (LOW), nullen wir den Zähler im EEPROM
EEPROM.write(EEPROM_ADDR, 0);
zaehler = 0;
Serial.println(F("Zaehler wurde genullt (Reset-Pin war LOW)."));
} else {
// Andernfalls laden wir den letzten Wert aus dem EEPROM
zaehler = EEPROM.read(EEPROM_ADDR);
Serial.print(F("Zaehler aus EEPROM geladen: "));
Serial.println(zaehler);
}
// OnBoardLED entsprechend des Zählerstandes blinken lassen
for (uint8_t i = 0; i < zaehler; i++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(1000);
digitalWrite(LED_BUILTIN, LOW);
delay(1000);
}
/* 15.11.25
delay eingefügt da der Fehler
"SD-Karte nicht initialisierbar oder nicht vorhanden."
im Serialmonitor erschien.
*/
delay(1000);
sdCardInit();
}
// ----------------------------------------------------------
// Hauptschleife
// ----------------------------------------------------------
void loop() {
now = rtc.now();
if (millis() - lastCheckTime >= _ONESECOND) {
lastCheckTime = millis();
getSensorsData();
getPinData();
checkAlarm();
digitalWrite(SP_PIN, false); // nur UNO
/*
loggen wenn Brenner Ein
13.11.25
*/
if (digitalRead(BRENNER_PIN) == LOW && digitalRead(BZ_PIN) == LOW) {
data2LogFile();
}
/*
Temperatur manuell setzen
14.11.25
*/
temp(); // Temperaturwert Vorlauf manuell setzen
}
if (changed == true) {
data2LogFile();
changed = false;
}
}
//
void checkAlarm() {
// --------------------------------------------------------
// Alarmsteuerung mit Hysterese
// Erweitert um den zaehler 14.11.25
// nach dem 4ten auslösen wird das Relais
// nicht mehr automatisch zurückgesetzt
// --------------------------------------------------------
if (alarmState == alarmOff) {
if (tempVorlauf > ALARM_ON_TEMP) {
alarmState = alarmOn;
strcpy(speicher, "Alarm");
}
} else {
if (tempVorlauf < ALARM_OFF_TEMP && zaehler < 4) { alarmState = alarmOff; }
}
// Ausgang entsprechend setzen
digitalWrite(ALARM_PIN, alarmState);
zaehl();
}
//
void data2LogFile() {
// --------------------------------------------------------
// Loggen bei Änderung
// --------------------------------------------------------
char buf[200] = { '\0' };
// sprintf kann ggfls. kein float. Darum vorher zusammenbauen
char vlT[5] = { '\0' };
dtostrf(tempVorlauf, 2, 1, vlT);
char rlH[5] = { '\0' };
dtostrf(tempRueckl_HZG, 2, 1, rlH);
char rlW[5] = { '\0' };
dtostrf(tempRueckl_WW, 2, 1, rlW);
// CSV-Zeile zusammensetzen
// ACHTUNG! die zweite Zeile gehört dazu!
snprintf(buf, sizeof(buf), "%02d.%02d.%d,%02d:%02d:%02d,%s,%s,%s,%d,%d,%d,%d,%s,%d",
now.day(), now.month(), now.year(), now.hour(), now.minute(), now.second(),
vlT, rlH, rlW, ventilWWStatus, brennerStatus, BZStatus, alarmState == alarmOff ? 0 : 1, speicher, zaehler);
// Auf SD-Karte schreiben
writeSuccess = false; // DEFAULT: Fehler beim Öffnen oder Schreiben
logfile = SD.open(heizungFile, FILE_WRITE);
if (logfile) {
logfile.println(buf);
writeSuccess = true; // Schreibvorgang erfolgreich
digitalWrite(SP_PIN, true);
}
logfile.close();
// Ausgabe zur Kontrolle
Serial.println(buf);
strcpy(speicher, " ");
}
//
void getPinData() {
// --------------------------------------------------------
// Digitale Eingänge lesen (bei Optokopplern evtl. invertiert)
// --------------------------------------------------------
if (!digitalRead(BRENNER_PIN) != brennerStatus) {
brennerStatus = !brennerStatus;
strcpy(speicher, "LÜ");
changed = true;
}
if (!digitalRead(VENTIL_WW_PIN) != ventilWWStatus) {
ventilWWStatus = !ventilWWStatus;
strcpy(speicher, "WW");
changed = true;
}
if (!digitalRead(BZ_PIN) != BZStatus) {
BZStatus = !BZStatus;
strcpy(speicher, "BZ");
changed = true;
}
}
//
void getSensorsData() {
// --------------------------------------------------------
// Temperaturen erfassen
// --------------------------------------------------------
tempVorlauf = sensors.getTempCByIndex(1);
tempVorlauf = temperaturWert + tempVorlauf; // temperaturWert zum Simulieren eingefügt
tempRueckl_HZG = sensors.getTempCByIndex(0);
tempRueckl_WW = sensors.getTempCByIndex(2);
sensors.requestTemperatures(); // löst neuen Lese-Zyklus aus! Braucht je nach Auflösung bis zu 750ms
// Serial.println(tempVorlauf);
}
void sdCardInit() {
/* 31.10.2025 */
if (!SD.begin(SD_CS_PIN)) {
Serial.println(F("SD-Karte nicht initialisierbar oder nicht vorhanden."));
writeSuccess = false; // Initialisierungsfehler
} else {
writeSuccess = true;
}
if (writeSuccess == true) {
Serial.println(F("SD-Karte initialisiert."));
// Logdatei vorbereiten
logfile = SD.open(heizungFile, FILE_WRITE);
Serial.print(F("System "));
if (logfile) {
logfile.println(F("Datum,Uhrzeit,Vorl [°C], HZG [°C], WW [°C] , WW , BR , BZ , Al , ,ALZä"));
logfile.close();
} else {
writeSuccess = false;
Serial.print(F("nicht "));
}
Serial.println(F("bereit"));
}
}
//
void inputPinInit() {
// Eingänge konfigurieren
pinMode(BRENNER_PIN, INPUT_PULLUP);
pinMode(RESET_PIN, INPUT_PULLUP);
pinMode(VENTIL_WW_PIN, INPUT_PULLUP);
pinMode(BZ_PIN, INPUT_PULLUP);
getPinData();
sensors.begin();
}
//
void temp() {
// 1. Seriellen Monitor auf neue Eingaben pruefen
if (Serial.available() > 0) {
// Lesen des eingegebenen Float-Wertes
float eingabe = Serial.parseFloat();
// Prüfen, ob die Eingabe gültig war (parseFloat gibt 0.0 zurück, wenn keine gültige Zahl gefunden wurde)
if (eingabe != 0.0 || (eingabe == 0.0 && Serial.peek() == '0')) {
temperaturWert = eingabe;
benutzeEingabeWert = true;
Serial.print("Temperatur auf manuellen Wert gesetzt: ");
Serial.println(temperaturWert);
} else {
Serial.println("Ungueltige Eingabe.");
}
// Puffer leeren, um alte Daten zu entfernen
while (Serial.available() > 0) {
Serial.read();
}
}
// Serial.print(F(" Temperatur eingegeben : "));
// Serial.println(temperaturWert);
}
//
void zaehl() {
// Aktuellen Zustand des Pins lesen
int currentAlarmState = digitalRead(ALARM_PIN);
// Prüfen, ob eine fallende Flanke vorliegt:
// War der Pin vorher HIGH UND ist jetzt LOW?
if (currentAlarmState == LOW && lastAlarmState == HIGH) {
zaehler++;
changed = true;
Serial.print(F("Flanke erkannt. Zaehler: "));
Serial.println(zaehler);
// Sofort nach dem Inkrementieren im EEPROM speichern
EEPROM.write(EEPROM_ADDR, zaehler);
}
// Den aktuellen Zustand für den nächsten Durchlauf speichern
lastAlarmState = currentAlarmState;
}
Bitte wo ist mein Fehler ?

