Hallo!
Ich verwende derzeit folgenden Code für einen Arduino um eine Hühnerschiebe mit einem Lichtsensor zu öffnen und zu schließen.
#define LED 12
#define LDR 2 // LDR Modul ist an Pin 3 angeschlossen
#define Relais1 8 // Relais 1 ist an Pin 8 angeschlossen
#define Relais2 9 // Relais 2 ist an Pin 9 angeschlossen
int val = 0;
void setup () {
pinMode (LED, OUTPUT);
pinMode (Relais1, OUTPUT);
pinMode (Relais2, OUTPUT);
pinMode (LDR, INPUT);
}
+++++++++++++++
void loop () {
int val = digitalRead (LDR);
if (val == 0) { // "wenn" der Lichtsensor hell ist, dann schalten die Relais wie folgt...
delay (1000); //Schaltung regiert erst nach 1 Sekunden...Wert kannst du natürlich ändern
digitalWrite (Relais1, HIGH);
digitalWrite (Relais2, LOW);
digitalWrite (LED, HIGH);} // Diese LED befindet sich auf dem ArduinoBoard und dient nur als Anzeige
else { // ansonsten schalten die Relais umgekehrt...
delay(7200000); //Verzögerung von 2 Stunden
digitalWrite (Relais1, LOW);
digitalWrite (Relais2, HIGH);
digitalWrite (LED, LOW);}
}
Ich habe im Else Zweig ein delay von 7200000 eingeüft um das Schließen um 2 Stunden zu verzögern. Dies funktioniert auch, aber ich habe jetzt auch das Problem, dass das Öffnen auch jetzt sehr lange verzögert wird.
Daher wollte ich fragen, was ich da falsch mache.
Danke
Logisch, bevor auf "0" geprüft werden kann muss ja der delay von zwei Stunden in else abgearbeitet werden.
In diesen zwei Stunden ist es völlig egal was der Sensor sagt, der Prozessor "dreht Däumchen".
Zu der Sekunde Verzögerung kommt also immer der Rest aus else, theoretisch kann das Ganze also zwei Stunden und eine Sekunde dauern.
Hallo,
Solange es dunkel ist wird ständig der else Zweig bearbeitet. Damit wird jedes mal die zwei Stunden gewartet bevor er wieder verlassen wird. Damit kann dann auch die hell Erkennung erst nach zwei Stunden wieder abgefragt werden. Die einfachste Variante wird wohl sein du merkst Dir wenn Du einmal durch den else Zweig gekommen bist. Diesen Merker setzt Du zurück wenn es hell geworden ist.
etwa so
ungetestet
bool merker=false; // im Allgemeinteil
if (val == 0 ) { // "wenn" der Lichtsensor hell ist, dann schalten die Relais wie folgt...
merker = false;
delay (1000); //Schaltung regiert erst nach 1 Sekunden...Wert kannst du natürlich ändern
digitalWrite (Relais1, HIGH);
digitalWrite (Relais2, LOW);
digitalWrite (LED, HIGH);} // Diese LED befindet sich auf dem ArduinoBoard und dient nur als Anzeige
else if (merker== false){ // ansonsten schalten die Relais umgekehrt...
merker=true ;
delay(7200000); //Verzögerung von 2 Stunden
digitalWrite (Relais1, LOW);
digitalWrite (Relais2, HIGH);
digitalWrite (LED, LOW);}
Damit wir dir auch zielgerichtet helfen können, kannst du uns bitte mal erklären, warum du nur das Schließen um die 2 Stunden verzögern möchtest.
Ein Dämmerungssensor sollte doch schon beides (Öffnen und Schließen) richtig machen, wenn du die Schwellwerte richtig eingestellt hast.
Weil es auch bei den Hühner welche gibt die gerne etwas länger unterwegs sind... Gibt auch welche die unter einem Busch o.Ä. schon mal ein Nickerchen machen und zu spät merken dass eigentlich "Bettgehzeit" ist.
Abends würde man solche "Klienten" aussperren und Fuchs und Marder ermuntern zuzuschlagen, Morgends ist das egal, da sind sie ja save.
Sorry, habe die Frage übersehen.
Ja wie schon @herbk geschrieben hat geht es darum, dass ich jetzt 2 neue Hühner habe die leider auch wenn es schon finster ist unterwegs sind.
lg
Dann solltest du das doch besser über eine genauere und evtl. auch nachträglich einstellbare Dämmerungsschaltung lösen.
Mein Tipp:
Mach es mit einem ESP8266 oder ESP32, da kannst du die Schwelle der Dämmerung jederzeit nachträglich per Weboberfläche anpassen.
Ja, deshalb soll die Klappe ja irgendwann zu gehen.
Das Raubgetier kommt meistens (Betonung auf "meistens" ) erst einige Zeit nach Sonnenuntergang so nahe an menschliche Ansiedlungen.
Zumindest auf dem Land, - in Städten sind viele Räuber schon so an den Menschen (und daran dass ihnen hier vom Menschen so gut wie keine Gefahr droht) gewöhnt, dass ihr Verhalten anders ist.
Wenn ich hier (Raum WIndsbach) mit einer Wildkamera ein Hühnergehege beobachtet habe, haben die Räuber im Regelfall so zwischen 23 Uhr und 5 Uhr Morgens mal vorbeigeschaut.
Ich habe hier eine Variante die in zweifacher Hinsicht (blockierungsfrei) verzögert. Einmal beim Lesen des LDR. Im Beispielprogramm wird dieser im Abstand von 15 Sekunden abgefragt. Ändert sich der Status und bleibt zwei "Lesungen" gleich, wird geschaltet.
Diese Verzögerung soll verhindern, dass die Schaltung zu empfindlich reagiert. Z.b. Wenn in der Nacht nur kurz Licht auf den Sensor fällt (Taschenlampe, Licht von vorbei fahrendem Auto o.ä.). Dann soll die Klappe nicht sofort auf und zu gehen.
Das zweite Verzögern geschieht, wenn der Lichtsensor-Wert akzeptiert wird und die Relais geschaltet werden sollen. Hier kann eine "Tag- und Nacht"-Verzögerung definiert werden (Konstanten).
#include <Streaming.h>
Print &cout {Serial};
using uint = unsigned int;
using ulong = unsigned long;
constexpr byte LDR_PIN {2};
constexpr byte RELAIS_PIN1 {8};
constexpr byte RELAIS_PIN2 {9};
constexpr byte LED_PIN {LED_BUILTIN};
// Time im milliseconds (ms)
constexpr ulong MEASURE_DELAY_MS {15 * 1000}; // Time between two LDR measurements
constexpr ulong DAYLIGHT_DELAY_MS {5 * 1000}; // Delay time for daytime switching.
constexpr ulong DARKNESS_DELAY_MS {10 * 1000}; // {120 * 60 * 1000} Delay time for night switching.
// Program parameters end
// Class / struct Definition(s)
//////////////////////////////////////////////////////////////////////////////
/// @brief Helper class for non-blocking execution of
/// code sections at certain intervals.
///
//////////////////////////////////////////////////////////////////////////////
class Interval {
public:
//////////////////////////////////////////////////////////////////////////////
/// @brief Determine whether the specified interval has expired.
///
/// @param duration Interval duration
/// @return true when the interval has elapsed
/// @return false interval not elapsed yet
//////////////////////////////////////////////////////////////////////////////
bool operator()(const ulong duration) {
if (false == isStarted) { return start(false); }
return (millis() - timeStamp >= duration) ? start(true) : retFalse();
}
private:
bool start(bool state = false) {
isStarted = !state; // Set the value to true on the first call
timeStamp = millis();
return state;
}
bool retFalse() { return false; }
private:
bool isStarted {false}; // Flag = true if the first Operator() call has been made.
ulong timeStamp {0};
};
enum class LDRStatus : byte { daylight, darkness, unchecked };
//////////////////////////////////////////////////////////////////////////////
/// @brief Class for reading in an LDR (digital output) with delayed response
///
//////////////////////////////////////////////////////////////////////////////
class Ldr {
public:
Ldr(byte pin, Interval &timer, ulong time) : pin {pin}, timer {timer}, time {time} {}
Ldr(const Ldr &) = delete; // No copy constructor
Ldr &operator=(const Ldr &) = delete; // No assignment
void begin() { pinMode(pin, INPUT); } // Init LDR input pin
bool check(); // Check for value change
LDRStatus getStatus() const { return status; } // Returns the LDR status (light/dark)
private:
const byte pin; // LDR Pin
Interval &timer; // Timer for delaying readings
const ulong time; // Length of the delay in milliseconds
LDRStatus status {LDRStatus::daylight}; // Actual LDR read status
LDRStatus prevStatus {LDRStatus::daylight}; // Previous LDR read status
byte result[2] {0}; // LDR read values for comparison
byte index {0}; // Index for the result array
};
//////////////////////////////////////////////////////////////////////////////
/// @brief Read in the LDR value and check whether it has changed since the last check.
///
/// @return true LDR Value has changed
/// @return false LDR Value hasn't changed
//////////////////////////////////////////////////////////////////////////////
bool Ldr::check() {
bool statusHasChanged {false};
if (timer(time)) {
result[index++] = digitalRead(pin);
status = (result[1]) ? LDRStatus::darkness : LDRStatus::daylight;
if (result[0] == result[1] && status != prevStatus) {
prevStatus = status;
statusHasChanged = {true};
}
if (index > 1) { index = 0; };
}
return statusHasChanged;
}
struct SwdTimerData {
const ulong daylightDelay;
const ulong darknessDelay;
Interval &timer;
};
// Class / struct definition(s) end
Interval mdTimer; // Measure delay timer
Interval swdTimer; // Switch delay timer
SwdTimerData swdtData {DAYLIGHT_DELAY_MS, DARKNESS_DELAY_MS, swdTimer}; // initialize SwdTimerData structure
Ldr ldr {LDR_PIN, mdTimer, MEASURE_DELAY_MS}; // create ldr object
//////////////////////////////////////////////////////////////////////////////
/// @brief Handles the switching of the relays
///
/// @param ldrStatus Status for deciding which relay switching should take place
//////////////////////////////////////////////////////////////////////////////
void switchRelais(LDRStatus ldrStatus) {
switch (ldrStatus) {
case LDRStatus::daylight:
cout << F("Tageslichtschaltung aktiv\n");
digitalWrite(RELAIS_PIN1, HIGH);
digitalWrite(RELAIS_PIN2, LOW);
digitalWrite(LED_PIN, HIGH);
break;
case LDRStatus::darkness:
cout << F("Dunkelschaltung aktiv\n");
digitalWrite(RELAIS_PIN1, LOW);
digitalWrite(RELAIS_PIN2, HIGH);
digitalWrite(LED_PIN, LOW);
break;
default: break;
}
}
//////////////////////////////////////////////////////////////////////////////
/// @brief Control of the switching delays for day/night switching
///
/// @param status Is it light or dark?
/// @param swdt struct with timer data
/// @return true The switching process has been completed
/// @return false The delay time has not yet expired
//////////////////////////////////////////////////////////////////////////////
bool switchControl(LDRStatus status, SwdTimerData &swdt) {
bool hasSwitched {false};
switch (status) {
case LDRStatus::darkness:
if (swdt.timer(swdt.darknessDelay)) {
switchRelais(LDRStatus::darkness);
hasSwitched = true;
}
break;
case LDRStatus::daylight:
if (swdt.timer(swdt.daylightDelay)) {
switchRelais(LDRStatus::daylight);
hasSwitched = true;
}
break;
default: break;
}
return hasSwitched;
}
void setup() {
Serial.begin(115200);
cout << F("Programm ") << __FILE__ << F(" gestarted") << endl;
pinMode(LED_PIN, OUTPUT);
pinMode(RELAIS_PIN1, OUTPUT);
pinMode(RELAIS_PIN2, OUTPUT);
ldr.begin();
switchRelais(LDRStatus::daylight);
}
void loop() {
static LDRStatus ldrStatus {LDRStatus::daylight};
static bool callSwitchControl {false};
if (ldr.check()) {
cout << F("Status geändert. Schaltverzögerung ein: ");
ldrStatus = ldr.getStatus();
callSwitchControl = true;
}
if (callSwitchControl) { callSwitchControl = not switchControl(ldrStatus, swdtData); }
}
Hallo!
Der code von @Rentner funktioniert, zumindest habe ich bis jetzt kein Problem feststellen können.
Ich habe eine Verzögerung am Abend und in der Früh geht die Schiebe gleich auf.
Vielen Dank für die Unterstützung
Hallo,
schön das es jetzt so funktioniert wie Du Dir das vorstellst. Nun könnte es sicher noch den Fall geben das Du ebenfalls von Hand mittels Taster öffnen und schliessen willst, auch während die Zeiten laufen. Dann solltest Du auf eine Variante mit millis() umbauen damit das blokadefrei funktioniert.
Hallo!
Leider doch zu früh gefreut.
Ich habe es in der Früh nochmals getestet und da habe ich leider die selbe Verzögerung wie am Abend.
Hier nochmals der geänderte Code. Vielleicht habe ich da etwas falsch verstanden:
#define LED 12
#define LDR 2 // LDR Modul ist an Pin 3 angeschlossen
#define Relais1 8 // Relais 1 ist an Pin 8 angeschlossen
#define Relais2 9 // Relais 2 ist an Pin 9 angeschlossen
int val = 0;
void setup () {
pinMode (LED, OUTPUT);
pinMode (Relais1, OUTPUT);
pinMode (Relais2, OUTPUT);
pinMode (LDR, INPUT);
}
void loop () {
int val = digitalRead (LDR);
bool merker=false; // im Allgemeinteil
if (val == 0) { // "wenn" der Lichtsensor hell ist, dann schalten die Relais wie folgt
merker = false;
delay (1000); //Schaltung regiert erst nach 1 Sekunde.
digitalWrite (Relais1, HIGH);
digitalWrite (Relais2, LOW);
digitalWrite (LED, HIGH);} // Diese LED befindet sich auf dem ArduinoBoard und dient nur als Anzeige
else if (merker== false){ // ansonsten schalten die Relais umgekehrt...
merker=true;
//delay(1000);
delay(1800000); //Verzögerung von 30min
digitalWrite (Relais1, LOW);
digitalWrite (Relais2, HIGH);
digitalWrite (LED, LOW);}
}
Wenn Du das tust musst du aber für den "Echtbetrieb" den
Wert von constexpr ulong DARKNESS_DELAY_MS {10 * 1000} auf den Wert im Kommentar ändern, um auf die zwei Stunden Verzögerung zu kommen. So, sind es nur 10 Sekunden.