1. Projekt: Zeitgesteuertes Schalten von Schlössern

Moin ins Forum,

zuerst einmal: Ich bin Anfänger in der Arduino Welt. Habe allerdings Programmier- und Elektrotechnische Grundlagen :wink:

Folgende Problemstellung habe ich durch meine bessere Hälfte bekommen:

Bauen einer Steuerung zum zeitgesteuertem / verzögertem schalten von Schlössern. (Zur Erklärung es handelt sich um einen Futterschrank für Pferde welcher 4 Klappen hat die zeitverzögert über den Tag/Nacht fallen sollen, damit das Futter unten rausfällt.)
Natürlich könnte man dieses mit Zeitschaltuhren lösen, empfand ich aber als langweilig und nicht weiterbildend :smiley:

Daher der Ansatz eines Arduino Nano zur Steuerung.

Folgender gedachter Aufbau.
Zwei BCD-Code DIP Schalter -> Einer gibt die Zeit in h bis zum Auslösen der ersten Klappe an, der zweite die Dauer in h der 2., 3., und 4. Klappe;

Einlesen und damit Starten des Programms über einen einfachen Klingelknopf. (Ab dann soll die Zeit des ersten DIP Schalters laufen)

Bisher habe ich getestet: Ansteuern eines Relais für die Schlösser mit den Digital-Ausgängen.
Als nächstes werde ich versuchen die BCD Schalter auszulesen, denke aber auch das dies machbar sein sollte :wink:

Gedanklich bin ich allerdings schon weiter und da stelle ich mir folgende Fragen (evtl. auch dem geschuldet, dass ich vor Projektbeginn noch nie mit einem Arduino gearbeitet habe):

  1. Starten des Programms: Hier sehe ich aktuell zwei Möglichkeiten. Entweder ich lasse den Klingelknopf den Nano resetten und lasse das komplette Programm in der setup() funktion laufen, da ja nicht wirklich wiederholende Tätigkeiten da drin sind. Ausser vllt. das auslösen der 2. und folgenden Klappen.
    Oder ich prüfe permanent in der loop() funktion den Zustand des Knopfes und starte das Programm nach drücken des Knopfes.

Nun endlich die Fragen:

  1. Kann ich über einen Klingelknopf den Reset des Nano machen?
  2. Bei Variante 2 mit der Schleife. Meinem Verständnis nach kann ich solange das Programm läuft ( und nach jetziger Planung rede ich da über mehrere Stunden; 1.Klappe nach 4h, 2. nach weiteren 3h etc....) keine Änderungen einbringen, oder? D.h. selbst wenn ich dann nochmal den Knopf drücke würde er ja immer noch im Programm hängen und die Eingabe gar nicht abprüfen, oder? Mein jetziger Plan wäre es das Zeitverzögerte auslösen über delay() zu realisieren.

Gibt es noch weitere Vor- / Nachteile die ich aktuell nicht sehe? Gibt es generelle Anmerkungen/Vorschläge?

Ja mir ist durchaus bewusst, dass dies mit Kanonen auf Spatzen schießen ist, aber wie gesagt der Weiterbildungsgedanke :wink:

Danke.

Beste Grüße

Ja.

Solange nichts zusätzliches dazukommt, eine einfache Lösung.
Wenn du irgendwann wissen willst, wann der Auslöser das (vor-)letzte Mal betätigt wurde, oder ähnliches, sollte loop natürlich besser "ewig" laufen.

1 Like

Wenn es nötig ist, bzw. wenn du es von Anfang an richtig machen willst, geht das auch. (Auch in Variante 1)

Die Zeiten dürfen natürlich nicht per delay() realisiert werden.
Schau dir BlinkWithoutDelay an und verstehe, was das mit deiner Aufgabe zu tun hat.

[Nachtrag und Korrektur]
Da das Ding ja stundenlang nichts macht, ist es sinnvoll, zumindest anfangs zum Testen sehen zu können was der Arduino grade macht. Da hilft Serial, wenn du kein Display für deine Zeitschaltuhr bauen möchtest ( Was den Aufwand erheblich vergrößern würde).
Allein um jede Minute einen Text ("Noch xx Minuten bis yy") ausgeben zu können, kannst du kein delay() für 4 Stunden brauchen. Da könnte man auch regelmäßig deine BCD-Schalter auswerten und Änderungen erkennen.
Vier Zwei BCD-Schalter brauchen im einfachsten Fall 16 8 Pins, können nur wenige Werte annehmen, und lassen sich nur mühsam einstellen/ablesen. Wie wäre es, auch dafür Serial zu verwenden?

1 Like

wie sieht es denn aus, für die Uhr ein RTC Modul zu verwenden
und die Zeiten mittels Display und Buttons einstellbar zu machen und im EEPROM zu speichern

1 Like

BlinkWithoutDelay habe ich mir angeschaut. Ja macht Sinn um nicht "dauerhaft" im delay() zu hängen. Werde ich mal mit rumprobieren.

Ich benötige tatsächlich nur zwei BCD Schalter da ich nur die Stunden bis zur 1. Klappe und mit dem zweiten BCD die Abstände zwischen den Klappen einstellen will. Es soll ja nicht höchstmöglich flexibel sondern möglichst einfach und (hoffentlich) Anwenderfreundlich sein....

@noiasca : Über Zeitmodul habe ich auch nachgedacht, aber aufgrund der eigentlich recht simplen Anwendungsgebietes mich dagegen entschieden.

Ziel meinerseits ist es aufgrund der Umgebung wo das Ding nachher stehen wird (kalt, staubig) einen möglichst verschlossenen Kasten mit nur dem Knopf und den beiden BCD Schaltern hinzustellen. Der Rest gut geschützt im Kasten.

Danke euch erstmal

Hallo
Auf der Basis von BlinkWithoutDelay einfach für jeden Futtertrog eine Eieruhr bauen und dann diese zeitlich für n-Futtertroge verketten.
Wie wird die Klappe am Futtertrog ausgelöst?
Ich wünsche einen schönen Tag und viel Spaß beim Programmieren in C++.

1 Like

Habe hierfür mir 12V Schlösser besorgt. Die Ansteuerung über ein 4-fach Relais habe ich auch schon hinbekommen.
Werde mich sobald Abends wieder Zeit ist hinsetzen und das ganze mit BlinkWithoutDelay mal probieren.

Ein Mittelding wäre ein delay(60000); in loop() und jede Minute die Zeit runterzählen.

Aber eine loop die gar keine Zeit braucht, ist natürlich prinzipiell besser.
Viel Spaß beim Schreiben von ewig laufender Software. Vermutlich eine Ergänzung zu deiner Programmiererfahrung.

1 Like

Habe nun endlich mal Zeit gefunden mich mal wieder mit meinem Projekt zu beschäftigen und nun stehe ich grad voll auf dem Schlauch....

Versuche einen BCD Schalter (Einstellmöglichkeit 0-9) einzulesen und hänge grad massiv.
Habe den BCD an A0 -A3 gehangen, weil wenn ich das richtig verstanden habe, ich mit

byte StartZeit = PINC & 0x0F;

den BCD einfach einlesen kann ? Stimmt das ?

Falls dem so ist, steht ja nun der Wert (ich nehme mal 2 an) als byte in der Variablen StartZeit quasi: 0010

Das soll ja jetzt für mich 2 Stunden bedeuten. Wie kriege ich jetzt aus dem byte ein int um das über multiplikation die 2Stunden in Millisekunden umzurechnen, oder kann ich da auch mit den byte weiterrechnen?

char *b2s(byte myByte)
//https://forum.arduino.cc/t/serial-print-n-bin-displaying-all-bits/46461
{
  static char Str[8];
  byte mask = B10000000;
  for (byte i = 0; i < 8; i++)
  {
    Str[i] = '0';
    if (((mask >> i) & myByte) == (mask >> i))
    {
      Str[i] = '1';
    }
  }
  // terminate the string with the null character
  Str[8] = '\0';
  return Str;
}
void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
  for (byte startZeit = 0; startZeit <= 12; startZeit++)
  {
    Serial.print(b2s(startZeit));
    Serial.print(" ");
    Serial.print((startZeit / 16 * 10) + (startZeit % 16) );
    Serial.print("\t");
    unsigned long Stunde=(uint32_t)startZeit*1000*60*60;
    Serial.println(Stunde);
  }
  
}
void loop()
{
}

Die Lösung ist in der vorletzten Zeile.

1 Like

Wenn Du das in der Rechnung mit einem int kombinierst, wandelt der Compiler das automatisch in ein int. Standard Typ für Rechnungen ist int.

1 Like

Na ganz einfach:

byte b = 0b10; // 2
unsigned long stunden = 1000UL * 3600 * b; // UL, damit die Rechnung 
                             //  in unsigned long durchgeführt wird.

Gruß Tommy

1 Like

Dann solltest Du das Ergebnis aber auch in einem unsigned long speichern :wink:

1 Like

Da hast Du wahr.

Gruß Tommy

1 Like

Alles klar habe ich verstanden. Schonmal gut. Aber mein Code funktioniert nicht....

int led=13;
int D2=2;
int D3=3;
int D4=4;
int D5=5;
byte StartZeit = PINC & 0x0F;
unsigned long StartInMS = 0;
unsigned long WiederholungInMS = 0;

void setup() {
  // put your setup code here, to run once:

//D2 bis D5 als Ausgänge festlegen
pinMode(led, OUTPUT);
pinMode(D2, OUTPUT);
pinMode(D3, OUTPUT);
pinMode(D4, OUTPUT);
pinMode(D5, OUTPUT);
// Alle Relays auf geschlossen schalten
digitalWrite(D2, HIGH);
digitalWrite(D3, HIGH);
digitalWrite(D4, HIGH);
digitalWrite(D5, HIGH);

StartInMS = StartZeit*3600000UL;

if (StartInMS == 3600000){
  digitalWrite(D2, LOW);
  delay(200);
  digitalWrite(D2, HIGH);
}

if (StartInMS == 7200000){
  digitalWrite(D3, LOW);
  delay(200);
  digitalWrite(D3, HIGH);
}

if (StartInMS == 10800000){
  digitalWrite(D4, LOW);
  delay(200);
  digitalWrite(D4, HIGH);
}

Habe ich jetzt einfach mal testweise gemacht um mit dem BCD Schalter 1-3 die Relays 1-3 anzusteuern...aber es funktioniert nicht....

Funktioniert nicht ist keine Fehlerbeschreibung. Was passiert real und wie sollte es passieren?

Gruß Tommy

Das funktioniert so nicht. Das musst Du innerhalb einer Funktion machen. Und wie sind die Schalter angeschlossen? Du wirst vermutlich den internen Pullup Widerstand einschalten müssen ( oder hast Du externe Pullup/Pulldown Widerstände dran? ).

1 Like

Ok. Wusste nicht, dass dies nur innerhalb einer Funktion geht.
Externe Pullup Wiederstände habe ich nicht.

int led=13;
int D2=2;
int D3=3;
int D4=4;
int D5=5;

unsigned long StartInMS = 0;
unsigned long WiederholungInMS = 0;

void setup() {
  // put your setup code here, to run once:

//D2 bis D5 als Ausgänge festlegen
pinMode(led, OUTPUT);
pinMode(D2, OUTPUT);
pinMode(D3, OUTPUT);
pinMode(D4, OUTPUT);
pinMode(D5, OUTPUT);
pinMode(A0, INPUT_PULLUP);
pinMode(A1, INPUT_PULLUP);
pinMode(A2, INPUT_PULLUP);
pinMode(A3, INPUT_PULLUP);
// Alle Relays auf geschlossen schalten
digitalWrite(D2, HIGH);
digitalWrite(D3, HIGH);
digitalWrite(D4, HIGH);
digitalWrite(D5, HIGH);
byte StartZeit = PINC & 0x0F;

StartInMS = StartZeit*3600000UL;

if (StartInMS == 3600000){
  digitalWrite(D2, LOW);
  delay(200);
  digitalWrite(D2, HIGH);
}

if (StartInMS == 7200000){
  digitalWrite(D3, LOW);
  delay(200);
  digitalWrite(D3, HIGH);
}

if (StartInMS == 10800000){
  digitalWrite(D4, LOW);
  delay(200);
  digitalWrite(D4, HIGH);
}

so geändert um die Pullup Widerstände zu aktivieren. Passt das?

Habe den BCD Schalter folgendermaßen angeschlossen.

1 --> A0
2 --> A1
4 --> A2
8 --> A3
C --> 3V ?? Ist das Richtig oder muss das an die Erdung?! Evtl da der Fehler?

@Tommy56 : Es passiert tatsächlich nix.... leider keine aussagekräftige Fehlerbeschreibung :wink:

Wenn Du interne PullUp verwendest, müssen die Schalter nach GND schalten.

Damit ist

byte StartZeit = PINC & 0x0F; // = 0xf im ungeschalteten Zustand
// Du musst das dann negieren
byte StartZeit = ~PINC & 0x0F;  // 0x0 im ungeschalteten Zustand

Hier zeigt sich wieder Mal, wie sinnvoll es ist, Debugausgaben auf den seriellen Monitor einzubauen.

Gruß Tommy

1 Like

Super ! Schalter auf GND und negiert und schon läuft es....jetzt muss ich nur noch n bissel schleifen bauen. Aber nicht mehr heute :wink:

Vielen Dank für eure Hilfe soweit. Ich werde mich bestimmt wieder melden wenn ich mal wieder nicht weiter komme :grimacing: