Skip to content

Instantly share code, notes, and snippets.

@karljosefschneider
Created April 25, 2021 12:05
Show Gist options
  • Save karljosefschneider/30731126ce8ccf22f5837baca2ddb0dd to your computer and use it in GitHub Desktop.
Save karljosefschneider/30731126ce8ccf22f5837baca2ddb0dd to your computer and use it in GitHub Desktop.
Schaltuhr mit Dämmerungsschalter und Bewegungsmelder
// Projekt: KJS Schaltuhr mit Dämmerungsschalter und Bewegungsmelder
// Datei: KJS_RTC_Schaltuhr_Sensoren
// Thema: RTC-Uhr als Schaltuhr mit Dämmerungsschalter und Bewegungsmelder
// mit automatischer Umschaltung auf Sommerzeit für Außenbeleuchtung
// Hardware: Arduino Uno, 8 x 2 LCD-Display, DS3231, AM312, Photowiderstand
// Autor: Karl-Josef Schneider
// Bearbeitung: erstellt am 26.03.2021, letzte Änderungen am 11.04.2021
//..!....1....!....2....!....3....!....4....!....5....!....6....!....7....!....8....!
// Libraries hinzufügen -------------------------------------------------------------
#include <Wire.h> // Lib zur I2C-Kommunikation
#include <LiquidCrystal_I2C.h> // Lib für das LCD-Display über I2C
#include "RTClib.h" // Lib für die Real Time Clock
#include <EEPROM.h> // Lib für das interne EEPROM
// Setup LCD-Display ----------------------------------------------------------------
LiquidCrystal_I2C lcd(0x27, 8, 2); // HEX-Adresse 0x27,8 Zeichen,2 Zeilen
// Setup Real Time Clock ------------------------------------------------------------
RTC_DS3231 RTC;
// Variablen deklarieren ------------------------------------------------------------
// Variablen für Digital-Pins --------------------------------------
#define Taster_OK 13 // Taster für Bestätigung nach Eingabe
#define Taster_Plus 11 // Taster um Wert zu erhöhen
#define Taster_Minus 12 // Taster um Wert zu erniedrigen
const int TastePin[] = {10, 9, 8, 7}; // Nummern der Tast-Pins
const int LEDPin[] = {3, 4, 5, 6}; // Nummern der Output-Pins
const byte pins = 4; // Anzahl der Pins
int OK = 1; // OK-Pin auf 1 setzen
int Stunden, Minuten; // Zeitvariablen für Taster
int Ein_Stunde, Ein_Minute; // Einschaltzeit
int Aus_Stunde, Aus_Minute; // Ausschaltzeit
int Uhr_h, Uhr_m, Uhr_s; // Variablen für Uhrzeit
int Sommer; // Sommerzeit true/false
const int LDR = A0; // Pin für LDR Eingang
const int Relais = 2; // Pin für Relais Ausgang
int LDR_Wert = 0; // Wert für LDR = 0
const int PIR = A1; // Pin für Bewegungsmelder
// Zeit-Variablen --------------------------------------
bool dunkel = false; // Merker Schwellwertunterschreitung
bool action = false; // Merker für ausgelöste Aktion
unsigned long dunkel_Start = 0; // Merker für Begin der Dunkelphase
// Startroutine ---------------------------------------------------------------------
void setup(){
Serial.begin(9600); // Seriellen Monitor starten
for (byte i = 0; i < pins; i++) {
pinMode(TastePin[i], INPUT_PULLUP); // Pins = Inputs mit PullUp
pinMode(LEDPin[i], OUTPUT); } // Pins = Outputs
digitalWrite(LEDPin[0], HIGH); // Pin 6 = HIGH nach Booten
lcd.init(); // LCD starten
lcd.backlight(); // Hintergrundbeleuchtung einschalten
RTC.begin(); // Uhr starten
// Wenn Uhrzeit neu gesetzt werden soll, sonst auskommentieren !!!
// RTC.adjust(DateTime(__DATE__, __TIME__)); // Zeit vom PC einlesen
//EEPROM.update(0, 7);EEPROM.update(1, 15);
//EEPROM.update(2, 1);EEPROM.update(3, 10);
Ein_Stunde = EEPROM.read(0); // Einschaltzeit Stunde einlesen
Ein_Minute = EEPROM.read(1); // Einschaltzeit Minute einlesen
Aus_Stunde = EEPROM.read(2); // Ausschaltzeit Stunde einlesen
Aus_Minute = EEPROM.read(3); // Ausschaltzeit Minute einlesen
pinMode(Taster_OK, INPUT_PULLUP); // Pin = Input mit PullUp
pinMode(Taster_Plus, INPUT_PULLUP); // Pin = Input mit PullUp
pinMode(Taster_Minus, INPUT_PULLUP); // Pin = Input mit Pullup
pinMode(Relais, OUTPUT); // Pin = Output
digitalWrite(Relais, HIGH); // Relais Output bei Start HIGH
pinMode(PIR, INPUT); // Pin = Input Bewegungsmelder
pinMode(A2,OUTPUT); // Pin = Output Bewegungsmelder
digitalWrite(A2, HIGH); // Bewegungsmelder bei Start HIGH
} // Ende Startroutine -----------------------------------------------------------
// Hauptroutine =====================================================================
void loop() { // Schleife starten
Sommer = Sommerzeit(); // Abfrage Sommerzeit
// Schaltungslogik --------------------------------------
// Der Schalter soll bei einsetzender Dunkelheit die Lampe einschalten, jedoch nur
// bis zu einer bestimmten Nachtzeit (Ausschaltzeit) aktiv bleiben. Nach Pause bis
// zur zu einer bestimmten Tageszeit (Einschaltzeit) wird das System wieder aktiv.
// In der Pausenzeit wird der Bewegungsmelder aktiviert.
DateTime now = RTC.now(); // Datum und Zeit ermitteln
if (int(now.hour()) > Aus_Stunde &&
int(now.minute()) > Aus_Minute &&
int(now.hour()) < Ein_Stunde &&
int(now.minute()) < Ein_Minute) { // Bewegungsmelder ------------------
if (digitalRead(PIR) == HIGH) { // wenn Bewegung erkannt wurde
digitalWrite(A2, LOW); } // Relaisausgang = LOW > Relais EIN
else { // wenn keine Bewegung erkannt wurde
digitalWrite(A2, HIGH); } } // Relaisausgang = HIGH > Relais AUS
else { // Dämmerungsschalter ----------------
Serial.print(dunkel_Start);Serial.print(" ");
Serial.println(millis()-dunkel_Start);
LDR_Wert = analogRead(LDR)/10.23; // LDR-Wert in % abfragen
if (LDR_Wert < 30) { // wenn der Wert < 30 (Dunkelheit)
if (!dunkel) { // ja, gerade eben unterschritten?
dunkel_Start = millis(); // Startzeit für Dunkelphase merken
dunkel = true; } // Merker dass es Dunkel ist setzen
else { // wenn die Dunkelphase schon läuft
if (millis() - dunkel_Start > 60000){ // schon seit 60 Sekunden dunkel?
if (!action) { // Aktion bereits ausgeführt?
digitalWrite(Relais, LOW); // Relaisausgang = LOW > Relais EIN
action = true; } }}} // Merker setzen, Action ausgeführt
else { // Schwellwert nicht unterschritten
if (action) { // ist Aktion gestartet?
digitalWrite(Relais, HIGH); // Relaisausgang = HIGH > Relais AUS
action = false; // Merker für Aktion zurücksetzen
if (dunkel) { // ist Dunkelphase gestartet?
dunkel = false; } }} // Merker für Dunkelphase zurücksetzen
}
// Betriebsmodus über Taster abfragen --------------------------------------------
for (byte i = 0; i < pins; i++) {
if (!digitalRead(TastePin[i])) { // invers, weil mit Pullups betrieben
Serial.print(i); Serial.println(F(" pressed"));
for (byte j = 0; j < pins; j++) {
Serial.print(j);
if (i == j) { // Einschalten des gedrückten Pins
digitalWrite(LEDPin[j], HIGH);
Serial.println(F("--> HIGH")); }
else { // Ausschalten der übrigen Pins
digitalWrite(LEDPin[j], LOW);
Serial.println(F("--> LOW")); }}}}
// Normalbetrieb -----------------------------------------------------------------
if (digitalRead(LEDPin[0]) == HIGH) { // Normalbetrieb
Uhrzeit(); } // Uhrzeit anzeigen
// Uhrzeit einstellen ------------------------------------------------------------
if (digitalRead(LEDPin[1]) == HIGH) { // Modus Uhrzeit einstellen
lcd.setCursor(0,1);lcd.print("Uhr-Zeit");// Display Anzeige Einschaltzeit
digitalWrite(LEDPin[0],LOW); // LEDPin Betrieb auf LOW
UhrStellen(); } // Uhrzeit einstellen
digitalWrite(LEDPin[1],LOW); // LEDPin UhrStellen wieder auf LOW
digitalWrite(LEDPin[0],HIGH); // LEDPin Betrieb wieder auf HIGH
// Einschaltzeit einstellen ------------------------------------------------------
if (digitalRead(LEDPin[2]) == HIGH) { // Modus Einschaltzeit einstellen
lcd.setCursor(0,0);lcd.print(" "); // Cursor 1. Zeile
if (Ein_Stunde <10){ lcd.print("0");} // führende 0 anzeigen
lcd.print(Ein_Stunde);lcd.print(":"); // Stunden anzeigen
if (Ein_Minute <10){ lcd.print("0");} // führende 0 anzeigen
lcd.print(Ein_Minute); lcd.print(" "); // Minuten anzeigen
lcd.setCursor(0,1);lcd.print("Ein-Zeit");// Display Anzeige Einschaltzeit
digitalWrite(LEDPin[0],LOW); // LEDPin Betrieb auf LOW
Einschaltzeit(); } // Einschaltzeit einstellen
digitalWrite(LEDPin[2],LOW); // LEDPin Einschaltzeit wieder auf LOW
digitalWrite(LEDPin[0],HIGH); // LEDPin Betrieb wieder auf HIGH
// Ausschaltzeit einstellen ------------------------------------------------------
if (digitalRead(LEDPin[3]) == HIGH) { // Modus Ausschaltzeit einstellen
lcd.setCursor(0,0);lcd.print(" "); // Cursor 1. Zeile
if (Aus_Stunde <10){ lcd.print("0");} // führende 0 anzeigen
lcd.print(Aus_Stunde);lcd.print(":"); // Stunden anzeigen
if (Aus_Minute <10){ lcd.print("0");} // führende 0 anzeigen
lcd.print(Aus_Minute); lcd.print(" "); // Minuten anzeigen
lcd.setCursor(0,1);lcd.print("Aus-Zeit");// Display Anzeige Ausschaltzeit
digitalWrite(LEDPin[0],LOW); // LEDPin Betrieb auf LOW
Ausschaltzeit(); } // Ausschaltzeit einstellen
digitalWrite(LEDPin[3],LOW); // LEDPin Ausschaltzeit wieder auf LOW
digitalWrite(LEDPin[0],HIGH); // LEDPin Betrieb wieder auf HIGH
} // Ende Hauptroutine ===========================================================
// Subroutine Uhrzeit ---------------------------------------------------------------
void Uhrzeit() {
DateTime now = RTC.now(); // Datum und Zeit ermitteln
Uhr_h = int(now.hour()); // Stunden ermitteln
if (Sommer == true) { // bei Sommerzeit
Uhr_h = int(now.hour()+1); } // 1 Stunde addieren
lcd.setCursor(0, 0); // Cursor Position=0, Zeile=0
if (Uhr_h <10){ lcd.print("0");} // führende 0 anzeigen
lcd.print(Uhr_h); // Stunden anzeigen
lcd.print(":");
Uhr_m = int(now.minute()); // Minuten ermitteln
if (Uhr_m <10){ lcd.print("0");} // führende 0 anzeigen
lcd.print(Uhr_m); // Stunden anzeigen
lcd.print(":");
Uhr_s = int(now.second()); // Sekunden ermitteln
if (Uhr_s <10){ lcd.print("0");} // führende 0 anzeigen
lcd.print(Uhr_s); // Stunden anzeigen
lcd.setCursor(0,1); // Cursor Position=0, Zeile=1
lcd.print("Betrieb "); // Uhrzeit
} // Ende Uhrzeit ----------------------------------------------------------------
// Subroutine Sommerzeit ermitteln --------------------------------------------------
boolean Sommerzeit() {
DateTime now = RTC.now();
if (now.month()<3 || now.month()>10) return false; // keine Sommerzeit Jan - Dez
if (now.month()>3 && now.month()<10) return true; // Sommerzeit Apr bis Sep
if (now.month()==3 && now.day()<25) return false; // keine Sommerzeit bis 25.März
if (now.month()==10 && now.day()<25) return true; // Sommerzeit bis 25.Okt.
if (now.month()==3 && (now.hour() + 24 * now.day())
>=(1 + 24*(31 - (5 * now.year() /4 + 4) % 7))
|| now.month()==10 && (now.hour() + 24 * now.day())
<(1 + 24*(31 - (5 * now.year() /4 + 1) % 7)))
return true;
else
return false;
} // Ende Sommerzeit -------------------------------------------------------------
// Subroutine Uhr stellen -----------------------------------------------------------
void UhrStellen(){
DateTime now = RTC.now(); // Datum und Zeit auslesen
Stunden = int(now.hour()); // Stunden ermitteln
Minuten = int(now.minute()); // Minuten ermitteln
Taster(); // Abfrage Taster
RTC.adjust(DateTime(now.year(),now.month(),now.day(),Stunden, Minuten,0));
} // Ende Uhr stellen ------------------------------------------------------------
// Subroutine Einschaltzeit einstellen ----------------------------------------------
void Einschaltzeit(){
Stunden = Ein_Stunde; // Stunden übernehmen
Minuten = Ein_Minute; // Minuten übernehmen
Taster(); // Abfrage Taster
Ein_Stunde = Stunden; // neue Stunden übernehmen
Ein_Minute = Minuten; // neue Minute übernehmen
EEPROM.update(0, Ein_Stunde); // neue Stunden ins EEPROM schreiben
EEPROM.update(1, Ein_Minute); // neue Minuten ins EEPROM schreiben
Serial.print ("Einschaltzeit ");
Serial.print (Ein_Stunde); Serial.print (":");
Serial.println (Ein_Minute);
} // Ende Einschaltzeit ----------------------------------------------------------
// Subroutine Ausschaltzeit einstellen ----------------------------------------------
void Ausschaltzeit(){
Stunden = Aus_Stunde; // Stunden übernehmen
Minuten = Aus_Minute; // Minuten übernehmen
Taster(); // Abfrage Taster
Aus_Stunde = Stunden; // neue Stunden übernehmen
Aus_Minute = Minuten; // neue Minute übernehmen
EEPROM.update(2, Aus_Stunde); // neue Stunden ins EEPROM schreiben
EEPROM.update(3, Aus_Minute); // neue Minuten ins EEPROM schreiben
Serial.print ("Ausschaltzeit ");
Serial.print (Aus_Stunde); Serial.print (":");
Serial.println (Aus_Minute);
} // Ende Einschaltzeit ----------------------------------------------------------
// Subroutine Taster abfragen -------------------------------------------------------
void Taster() {
lcd.setCursor(0,0);lcd.print(">> "); // Display Anzeige setzen
if (Stunden <10){ lcd.print("0");} // führende 0 anzeigen
lcd.print(Stunden);lcd.print(":"); // Stunden anzeigen
if (Minuten <10){ lcd.print("0");} // führende 0 anzeigen
lcd.print(Minuten); // Minuten anzeigen
OK = 1; // OK auf 1 setzen
while(OK == 1) { // solange OK = 1
delay(200); // Pause
if (digitalRead(Taster_Plus) == LOW) { // wenn Taster "+" gedrückt wird
delay(200); // Pause
if(Stunden>22) Stunden =0; // um 23 Uhr auf 0 setzen
else Stunden ++; } // sonst 1 Stunde addieren
if (digitalRead(Taster_Minus) == LOW) { // wenn Taster "-" gedrückt wird
delay(200); // Pause
if(Stunden<=0) Stunden =23; // um 0 Uhr auf 23 setzen
else Stunden --; } // sonst 1 Stunde subtrahieren
OK = digitalRead(Taster_OK); // Taste "OK" abfragen
lcd.setCursor(3, 0); // Cursor Position=0, Zeile=0
if (Stunden <10){ lcd.print("0");} // führende 0 anzeigen
lcd.print(Stunden); } // Stunden anzeigen
lcd.setCursor(0,0); // Display Anzeige Set
if (Stunden <10){ lcd.print("0");} // führende 0 anzeigen
lcd.print(Stunden);lcd.print(":"); // Stunden anzeigen
if (Minuten <10){ lcd.print("0");} // führende 0 anzeigen
lcd.print(Minuten);lcd.print(" <<"); // Minuten anzeigen
OK = 1; // OK auf 1 setzen
while(OK == 1) { // solange OK = 1
delay(200); // Pause
if (digitalRead(Taster_Plus) == LOW) { // wenn Taster "+" gedrückt wurde
delay(200); // Pause
if(Minuten>59) Minuten =0; // bei > 59 Minuten auf 0 setzen
else Minuten ++; } // sonst 1 Minute addieren
if (digitalRead(Taster_Minus) == LOW) { // wenn Taste "-" gedrückt wurde
delay(200); // Pause
if(Minuten<=0) Minuten =59; // bei < 0 Minuten auf 59 setzen
else Minuten --; } // sonst 1 Minute subtrahieren
OK = digitalRead(Taster_OK); // Taste "OK" abfragen
lcd.setCursor(3, 0); // Cursor Position=0, Zeile=0
if (Minuten <10){ lcd.print("0");} // führende 0 anzeigen
lcd.print(Minuten); } // Minuten anzeigen
} // Ende Taster abfragen --------------------------------------------------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment