Schaltuhr mit Dämmerungsschalter und Bewegungsmelder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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