Hab dazu gerade ne Antwort geschrieben, warum ich den Sensor ein- und ausschalte. Kann sein, dass das nicht nötig ist.
Ist eine Freilaufdiode notwendig in diesem Aufbau mit dem verwendeten Relais? Zu welchen Problemen führt das, wenn keine verbaut ist? Was für eine würdest du empfehlen?
Danke dir.
Mein Grund, warum ich das RTC Modul verwende ist, dass ich gelesen habe, dass ein RTC Modul langfristig stabiler ist so große Zeiträume zu erfassen im Vergleich zu millis().
Ist es ein Problem, wenn ich zur Zeitmessung das RTC modul und millis() verwende?
Ah.OK.
Ich bin nachher mit etwas Zeit unterwegs. Wenn ich es schaffe, bau ich mal was für alle 3 Arbeitskreise.
Das war ja auch nur ein Beispiel, um das Programmieren selbst zu lernen.
An jeder Induktivität innerhalb einer Schaltung sollte eine Freilaufdiode angebracht werden.
Bei dir die Pumpe.
Diese verhindert anders gepolte Spannungsspitzen beim Abschalten der Spannung, die Teile der Elektronik zerstören können.
Eine 1N4001 ist für die Schaltung ok.
Stabiler ja, ob das für dein Projekt aber wichtig ist, musst du beurteilen.
Nein, da sehe ich kein Problem.
Das trifft für deine Sensoren nicht zu.
Welches Problem hättest du denn gerne?
Habe mir mal deinen Code angesehen....
Viele Schleifen, viele if.
Fast alle völlig unnötig.
Mein Rat:
- Die Modularisierung voran treiben.
- Anfangen, in Nebenläufigkeiten zu denken.
Danke für die ausführliche Antwort.
Blockzitat
Die muss ich dann parallel zum Stromkreis der Pumpe in Sperrrichtung anschließen, richtig?
Sorry, für das Blockzitat.
Bezieht sich natürlich auf die Freilaufdiode
Das wäre top, danke!
Hab das mal auf die schnelle so umgesetzt:
#include <INTERVAL.h>
#include <Wire.h>
// moisture threshold, higher number means dryer soil
const int MOISTURE_THRESHOLD = 300;
// determine for how long the pump is running in seconds
unsigned int PUMP_DURATION = 2;
// used as reference point to start measuring the pump
unsigned long startMillis = 0;
// bool to keep track if pump is running
bool pump_on = false;
// declare pins for power for sensor and pump
int GREEN_SENSOR = 6;
int GREEN_PUMP = 7;
// Analog pins to read moisture value
int GREEN_MOISTURE = A0;
void setup() {
Serial.begin(9600);
// set up power pins for sensor and pump
pinMode(GREEN_SENSOR, OUTPUT);
digitalWrite(GREEN_SENSOR, LOW);
pinMode(GREEN_PUMP, OUTPUT);
digitalWrite(GREEN_PUMP, HIGH);
// set up pin to measure moisture
pinMode(GREEN_MOISTURE, INPUT);
delay(500);
Serial.println("Setup finished");
}
void loop() {
// every 24h
INTERVAL(60000UL * 1) {
Serial.println("Check moisture");
read_sensor(GREEN_MOISTURE);
}
if (pump_on == true) {
if (millis() - startMillis > PUMP_DURATION * 1000UL) {
// turn off pump after PUMP_DURATION has passed
digitalWrite(GREEN_PUMP, HIGH);
}
}
}
// function to rea the sensor values. If the soil is dry, start the pump
void read_sensor(int moisturePin) {
int moisture = analogRead(moisturePin);
Serial.println(moisture);
if(moisture > MOISTURE_THRESHOLD) {
Serial.print("Start pump");
digitalWrite(GREEN_PUMP, LOW);
pump_on = true;
// save millis to keep track of pump duration
startMillis = millis();
}
}
// function to turn pump off
void pumpe_ausschalten()
{
digitalWrite(GREEN_PUMP, HIGH);
pump_on = false;
}
Funktioniert so ganz gut, allerdings noch ohne Freilaufdiode.
Kann das der Grund sein, warum das Setup immer zweimal durchlaufen wird?
Hier dazu der OUtput
Setup finished
Setup finished
Check moisture
504
Start pumpCheck moisture
503
Start pump
Davon gehe ich aus. Da wird der Controller neu starten.
setze das mal hinter Serial.begin(9600);
delay(100);
Serial.println("Setup start...");
und evtl. auch mal die Pumpe abnehmen.
Hallo flowerpot123
Ich habe deine Beschreibung gelesen und habe eine Frage:
Sind das ganz spezielle Topf-Pflanzen, die u.U nur alle 24 Stunden mit Wasser versorgt werden müssen?
Mal ein Versuch aus der Hosentasche heraus.
Für alle 3 Kreise.
Bitte beachte im setup die Zeitzuordnung.
Ich hhoffe nix vergessen zu haben - es ist noch ausbaufähig ![]()
#include "RTClib.h"
#include <Wire.h>
// Configuration, setup moisture threshold and checking time
// high number means dry soil
const int MOISTURE_THRESHOLD = 300;
// Intervall check
const long INTERVALL_PUMP_CHECK = 60;
// wait for the sensor before measuring
const long SENSOR_WAIT_TIME = 2000;
// pump time in ms, determines how much water will flow
const long PUMP_INTERVAL = 1000;
constexpr bool enable {LOW};
// Clock
RTC_DS3231 rtc;
DateTime now;
// declare pins for power for sensor and pump
struct WATERING
{
const uint8_t sensorPin;
const uint8_t enablePin;
const uint8_t pumpePin;
const char *name;
};
constexpr uint8_t waterBoxSize {3};
struct WATERBOX
{
WATERING watering[waterBoxSize];
uint8_t measureHour; // Auslösezeit -> nur Stunde
uint8_t zyklusTime; // Merker für Vergleich mit aktueller Laufzeit
bool isActive; // wird als Statusvariable benutzt
uint8_t activeBox;
uint8_t step; // Schrittkettenvariable
};
WATERBOX waterBox
{
{
{A0, 6, 7, "GREEN",}, // sensorPin, enablePin, pumpePin, name
{A1, 8, 9, "BLUE",},
{A2, 10, 11, "WHITE",},
},
0, 0, 0, 0, 0,
};
void setup()
{
Serial.begin(115200);
delay(500);
Serial.println(F("Start..."));
if (!rtc.begin())
{
Serial.println(F("Couldn't find RTC"));
Serial.flush();
abort();
}
// When time needs to be set on a new device, or after a power loss, the
// following line sets the RTC to the date & time this sketch was compiled
Serial.println(F("Setting the time..."));
rtc.adjust(DateTime(__DATE__, __TIME__));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
// set up power pins for sensor and pump
wateringInit();
}
void wateringInit()
{
for (byte b = 0; b < waterBoxSize; b++)
{
pinMode(waterBox.watering[b].sensorPin, INPUT);
pinMode(waterBox.watering[b].enablePin, OUTPUT);
pinMode(waterBox.watering[b].pumpePin, OUTPUT);
allOff();
}
/*************/
waterBox.measureHour = rtc.now().hour(); // aktivieren, wenn Systemstart Zyklusstart sein soll
// waterBox.measureHour = 12; // alternativ!!! - feste Stundenvorgabe
}
void allOff()
{
for (byte b = 0; b < waterBoxSize; b++)
{
digitalWrite(waterBox.watering[b].enablePin, !enable);
digitalWrite(waterBox.watering[b].pumpePin, !enable);
}
}
void loop()
{
now = rtc.now();
switch (waterBox.step)
{
case 0:
if (waterBox.measureHour == now.hour()) // Zeitgleichheit
{
if (waterBox.isActive == false) // und nicht schon aktiv gewesen?
{
waterBox.isActive = true; // merken
waterBox.activeBox = 0; // Startwert festlegen
waterBox.step = 1; // nächster Step
}
}
else if (waterBox.isActive == true) // Zeit abgelaufen und aktiv?
{
allOff();
waterBox.isActive = false; // deaktivieren
}
break;
case 1:
Serial.print(F("Aktiviere Sensor: "));
Serial.println(waterBox.watering[waterBox.activeBox].name);
digitalWrite(waterBox.watering[waterBox.activeBox].enablePin, enable); // aktiviert den Sensor
waterBox.zyklusTime = millis(); // Zeit merken
waterBox.step = 2; // nächster Step
break;
case 2:
if (millis() - waterBox.zyklusTime > SENSOR_WAIT_TIME)
{
Serial.print(F("Messe Sensor: "));
Serial.println(waterBox.watering[waterBox.activeBox].name);
Serial.print(F("Sensor: "));
Serial.print(waterBox.watering[waterBox.activeBox].name);
if (analogRead(waterBox.watering[waterBox.activeBox].sensorPin) > MOISTURE_THRESHOLD) // wenn trocken
{
Serial.println(F("trocken"));
digitalWrite(waterBox.watering[waterBox.activeBox].pumpePin, enable); // aktiviert die Pumoe
waterBox.zyklusTime = millis(); // Startzeit merken
waterBox.step = 3; // ;)
}
else // Wenn nass genug
{
Serial.print(F("nass"));
waterBox.step = 4;
}
}
break;
case 3:
if (millis() - waterBox.zyklusTime > PUMP_INTERVAL) // Pumpzeit abgelaufen?
{
Serial.print(F("Pumoe: "));
Serial.print(waterBox.watering[waterBox.activeBox].name);
Serial.println(F("AUS"));
digitalWrite(waterBox.watering[waterBox.activeBox].pumpePin, !enable); // Pinstatus setzen
waterBox.step = 4; // :)
}
break;
case 4:
waterBox.activeBox++; // nächsten Sensor auswählen
waterBox.activeBox < waterBoxSize ? waterBox.step = 1 : waterBox.step = 0; // Wenn Sensor vorhanden fang an von vorn, sonst Ende
default:
allOff();
waterBox.step = 0;
break;
}
}
Das kommt "in echt" sicher separat in einen Notfallsketch, der die Uhr nur stellt, wenn erforderlich. Sonst wird bei jedem Reset die Uhr wieder auf die Zeit des Compilierens zurückgesetzt.
Eigentlich schon. ![]()
Ich habs nur übernommen. Stört ja nix.
Aber da ich dich schon mal dran habe...
Im case 4 geht doch auch ein Einzeiler, wenn die zweite Zeile genommen und vor der Variablen ein ++ gesetzt wird?
(Ja, man könnte auch die Ergebniszurdnung zu .step verbessern, aber ich wollt nicht gleich mit der Tür ins Haus fallen)
Geht schon.
Die Funktion ist: Entweder nächster Sensor (step 1) oder, (falls alle Sensoren durch sind), auf nächsten Zyklus warten (step 0)
Wie man das verständlich in C++ formuliert, ist Geschmacksfrage.
Man kann in C/C++ auch Knobelrätsel formulieren (was passiert in dieser Anweisung?)
Der TO hat 3 gleiche Arbeitskreise.
An der Stelle wird der nächste Arbeitskreis aufgezählt.
Wenn der aufgezählte Kreis noch im Gültigkeitsbereich ist, dann wird die Giessequenz durchlaufen.
Ist der Gültigkeitsbereich überschritten, wird ganz von vorn begonnen, incl. Reset der Variablen.
Ne, sind keine besonderen Topfpflanzen. Ohne Bewässerungssystem schau ich 1 bis 2 mal pro Woche selbst nach, ob noch genug Wasser drin ist. Deswegen dachte ich wäre 1 mal am Tag ein gutes Intervall für nen Sensor
Ich habe mich näher am blinkwithoutdelay Beispiel orientiert und nun folgenden funktionierenden Code:
// Arduino soil moisture sensor and real time clock
// This sketch works as an self watering flower pot
// https://iotspace.dev/arduino-bodenfeuchtesensoren---anleitung-und-sketch
//
#include "RTClib.h"
#include <Wire.h>
// Configuration, setup moisture threshold and checking time
// high number means dry soil
const int MOISTURE_THRESHOLD = 300;
// Intervall check
const long INTERVALL_PUMP_CHECK = 43200;
// pump time in ms, determines how much water will flow
const long PUMP_INTERVAL = 1500;
// Timer variable
long lastPumpCheckCycle = 0;
// Clock
RTC_DS3231 rtc;
// declare pins for power for sensor and pump
int GREEN_PUMP = 6;
int BLUE_PUMP = 7;
int WHITE_PUMP = 8;
// Analog pins to measure moisture
int GREEN_MOISTURE = A0;
int BLUE_MOISTURE = A1;
int WHITE_MOISTURE = A2;
// bool to save if the pump is on
bool green_pump_on = false;
bool blue_pump_on = false;
bool white_pump_on = false;
// store the starting point when the pump started in milliseconds
unsigned long green_start = 0;
unsigned long blue_start = 0;
unsigned long white_start = 0;
void setup() {
// serial communication with 9600 baud rate
Serial.begin(9600);
#ifndef ESP8266
while (!Serial)
; // wait for serial port to connect. Needed for native USB
#endif
if (!rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
abort();
}
Serial.println("Setting the time...");
// When time needs to be set on a new device, or after a power loss, the
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(__DATE__, __TIME__));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
// set up power pins for pumps
pinMode(GREEN_PUMP, OUTPUT);
digitalWrite(GREEN_PUMP, HIGH);
pinMode(BLUE_PUMP, OUTPUT);
digitalWrite(BLUE_PUMP, HIGH);
pinMode(WHITE_PUMP, OUTPUT);
digitalWrite(WHITE_PUMP, HIGH);
// set up pin to measure moisture
pinMode(GREEN_MOISTURE, INPUT);
pinMode(BLUE_MOISTURE, INPUT);
pinMode(WHITE_MOISTURE, INPUT);
Serial.println("Setup finished");
delay(500);
}
void loop() {
long nowTime = rtc.now().secondstime();
long difference = nowTime - lastPumpCheckCycle;
// Check if the current time is the predetermined check time
// If so, execute the checkMoisture function
if (lastPumpCheckCycle == 0 || difference > INTERVALL_PUMP_CHECK) {
Serial.println("Check moisture");
lastPumpCheckCycle = nowTime;
// Measure green sensor
checkMoisture(GREEN_MOISTURE, GREEN_PUMP, green_start, green_pump_on, "green");
// Measure blue sensor
checkMoisture(BLUE_MOISTURE, BLUE_PUMP, blue_start, blue_pump_on, "blue");
// Measure white sensor
checkMoisture(WHITE_MOISTURE, WHITE_PUMP, white_start, white_pump_on, "white");
}
if (green_pump_on == true) {
if (millis() - green_start > PUMP_INTERVAL) {
turn_off_pump(GREEN_PUMP, green_pump_on);
}
}
if (blue_pump_on == true) {
if (millis() - blue_start > PUMP_INTERVAL) {
turn_off_pump(BLUE_PUMP, blue_pump_on);
}
}
if (white_pump_on == true) {
if (millis() - white_start > PUMP_INTERVAL) {
turn_off_pump(WHITE_PUMP, white_pump_on);
}
}
}
// function to check the moisture at a given sensor and turn of the pump if needed
int checkMoisture(int moisture_pin, int pump_pin, unsigned long &starting_point, bool &pump_status, String colour) {
int moisture = analogRead(moisture_pin);
Serial.println(colour + " moisture: " + moisture);
if (moisture > MOISTURE_THRESHOLD && !pump_status) {
// set starting point to keep track of time
starting_point = millis();
// Turn on the pump
Serial.println("Turning pump on at " + colour);
digitalWrite(pump_pin, LOW);
pump_status = true;
}
}
// function to turn off the pump
void turn_off_pump(int pump_pin, bool &pump_status) {
digitalWrite(pump_pin, HIGH);
pump_status = false;
}
Der Code funktioniert zwar, ist aber nicht optimiert (viele Wiederholungen).
Ich werde, wenn ich wieder etwas Zeit habe, mal gerne deinen Code ausprobieren und etwas an mein Problem anpassen (die Sensoren lasse ich jetzt dauerhaft an, vereinfacht das Problem etwas), der sieht strukturierter aus, da viele Sachen sinnvoll zusammengefasst werden. Ich geb dann gerne Feedback, ob es bei meinem Problem auch klappt ![]()
Vielleicht solltest Du dich mit dem Konzept von „struct“ und Arrays mal vertraut machen. Der Code von @my_xy_project könnte da Inspiration sein.
Da Du mit Sicherheit nicht mehr als 256 Pins hast, könnte man die Pins auch als byte anstelle von int declarieren un da sie sich zur Laufzeit nicht ändern, auch als const. Beispiel:
const byte GREEN_PUMP = 6;
Gruß Tommy