Arduino Nano Taster mit mehreren Funktionen

Hallo Zusammen,

ich bin neu auf den Gebiet.
Durch Google und mehrere Einräge habe ich schonmal einen passenden Teil gefunden, der je Taster Eingang einen Ausgang steuert.

Jetzt habe ich aber noch folgende Thematik.

Taster steuert 1 Relais - erledigt
Taster steuert x Relais - open
Taster per kurz druck - open
Taster doppelt oder länger steuer Relais - open

Am Ende müsste ich noch einen Eingang haben, der sozusagen alles ausschaltet, wenn x bestimmte Relais an sindt oder eben x bestimmte Relais anschaltet wenn alle aus sind.

Nun habe ich mehrere Einträge gefunden, wie man das einzeln abbildet aber ich steig nicht dahinter, wie man das kombiniert.

#include <Adafruit_NeoPixel.h>


#define maxTaster 4
constexpr byte taster[maxTaster] {A0, A1, A2, A3};
constexpr byte led[maxTaster] {2, 3, 4, 5};

constexpr uint32_t  Entprellzeit {15}; //Entprellzeit für den Taster in ms

bool lastState[maxTaster] = {false};
uint32_t bounceStart[maxTaster];

void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");
  Serial.println();
  Serial.println();

  for (byte b = 0; b < maxTaster; b++) {
    printArrayErklaerung(b);
    pinMode(taster[b], INPUT_PULLUP);
    digitalWrite(led[b], LOW);
    pinMode(led[b], OUTPUT);
    digitalWrite(led[b], HIGH);
  }
}

void loop() {
  for (byte b = 0; b < maxTaster; b++)                   // frage alles ab
  {
    if (!digitalRead(taster[b]))                      // Taste gedrückt?
    {
      if (!lastState[b])                              // vorher nicht gedrückt?
      {
        lastState[b] = true;                          // merken, das gedrückt
        bounceStart[b] = millis();                    // merken, wann ausgelöst
        digitalWrite(led[b], !digitalRead(led[b]));   // PIN  toggeln
      }
    }
    else if (millis() - bounceStart[b] > Entprellzeit)// Taste losgelassen UND BounceTime abgelaufen
    {
      lastState[b] = false;
    }
  }
}

Mir scheint, du möchtest eine Ablauf Steuerung bauen.
Da bieten sich "endliche Automaten" geradezu an.

Das wichtigste ist vor dem Code eine eindeutige Beschreibung. Ich werde aus dem oben geschriebenem nicht schlau. Bitte noch einmal beschreiben: was soll wann passieren?

Edit am 31.08.2024

Hallo,

natürlich gerne, bin über jede Hilfe dankbar.

Also Ausgangsbasis ist folgendes:

1x Arduino Nano
1x 8-fach Relaisplatine zum ansteuern
6 einzelne Taster

Funktion 1: (Taster 1-4) /
Taster 1 - Relais 1
Taster 2 - Relais 2
Taster 3 - Relais 3
Taster 4- Relais 4

Funktion 2:
Taster 5

  • langes Drücken Relais 1 / 2 / 3 / 4 an
  • kurz klicken: Relais 1 / 2 / 3 / 4 aus
  • mehrfaches klicken: Relais 5 & Relais 6 an / aus

Taster 6:
*langes Drücken alle Relais an

  • kurz klicken: alle Relais aus
  • mehrfaches klicken: Relais 7 & Relais 8 an / aus

-> zusätzlich soll eine Status LEd ausgelöst werden, hier würde ich noch eine 4-fach Relais Platine kaufen.

Auch ich verstehe deine Beschreibung nicht!

Nach der genaueren Ausführung auch nicht?

Wenn du den gedrückten Taster feststellst, speicherst du die aktuelle Zeit

start = millis();

dann prüft du wann der Taster wieder losgelassen wird berechnest die Zeit:
dt = millis() - start

wenn dt <

  • 50ms -> ignorieren, nennt sich debounce.
  • 1s -> kurzer druck festgestellt
  • sonst -> langer druck festgestellt

Nein!
Da tauchen so einige x auf, die ich nicht auflösen kann.

Habs aufgelöst. X war nur der Platzhalter für Taster 1:8 oder Relais 1:8 damit ich nicht alle auflösen muss.

Hallo davidmei

Wofür ist das Programm im echten Leben?

Mein Tip:
Lese dich in die Verwendung von ARRAYs und STRUCTs ein.
Damit lassen sich prima schlanke und geschmeidige Programme schreiben.

wenn du dir mal die OneButton Library ansiehst, die kann Click, LongPress und DoubleClick erkennen.

Schau dir die Beispiele genau an, damit müsstest du zurecht kommen.

Hatte ich gestern Abend mal studiert.
Was ich nicht verstehe oder gefunden habe ein gezielter mehrfach Click.

Also zum Beispiel:

3x innerhalb eines gewissen Zeitraums
Aber auch 4x pro innerhalb eines Zeitraums.

Wenn ich es richtig verstanden habe kann ich da ja eine Aktion nach der anderen auslösen und die blockieren sich nicht?

OneButton hat eine gute Doku.
https://www.mathertel.de/Arduino/OneButtonLibrary.aspx

Es gibt auch einen Callback für multiclick()

Das State-Diagram gibt einen Überblick was es alles in der Library gibt - und ist ein gutes Beispiel warum man ein State-Diagram zeichnen soll. Wäre auch für deine Programm Logik eine Empfehlung.

das liegt wohl eher an deinen Aktionen - die sollen sich nicht gegenseitig blockieren.
Die OneButton wertet die Buttons - nicht blockierend - aus.

Ich weiß nicht, was du kannst.
Aber ja, man kann Dinge (quasi) nebeneinander laufen lassen.
Große Teile des Forums beschäftigen sich mit genau sowas. (ca. 3 mal täglich)

Ich möchte noch einen Schritt weiter gehen!
Klare Gedanken und klare Logik führen zu klaren und widerspruchsfreien Ablauf- und Statusdiagrammen.
Klare und widerspruchsfreie Beziehungs-, Datenfluss-, Ablauf- und Statusdiagramme kann man 1:1 in klare und übersichtliche Programme überführen.
Diese funktionieren dann auch.

Das fertige Programm ist dann ein Abbild des Geistes, der Denkweise, des Programmierers.

Hallo Zusammen,

so habe jetzt mal die OneButton Libary angesehen.
Habe mal das Beispiel mit LongPress genommen und versucht ein Relais zu schalten.

Ansich klappt das schalten, aber mein Problem ist, dass im "Start Modi" das Relay immer angezogen ist.

Habe aber im Setup das drin:

  pinMode(RELAY1_PIN, OUTPUT);
  digitalWrite(RELAY1_PIN, LOW);

// 05.05.2023 created by Ihor Nehrutsa

#include "OneButton.h"

#define PIN_INPUT A0
#define PIN_INPUT_2 A1
const byte RELAY1_PIN = 2;
const byte RELAY2_PIN = 3;
int relaystate = 0;
int relaystate1 = 0;


// Setup a new OneButton on pin PIN_INPUT
// The 2. parameter activeLOW is true, because external wiring sets the button to LOW when pressed.
OneButton button(PIN_INPUT, true);
OneButton button2(PIN_INPUT_2, true);

// In case the momentary button puts the input to HIGH when pressed:
// The 2. parameter activeLOW is false when the external wiring sets the button to HIGH when pressed.
// The 3. parameter can be used to disable the PullUp .
// OneButton button(PIN_INPUT, false, false);

// setup code here, to run once:
void setup()
{
  Serial.begin(115200);
  Serial.println("\nOneButton Example.");
  Serial.println("Please press and hold the button for a few seconds.");
  pinMode(RELAY1_PIN, OUTPUT);
  pinMode(RELAY2_PIN, OUTPUT);
  digitalWrite(RELAY1_PIN, LOW);
  digitalWrite(RELAY2_PIN, LOW);

  // link functions to be called on events.
  button.attachLongPressStart(LongPressStart, &button);
  button.attachDuringLongPress(DuringLongPress, &button);
  button.attachLongPressStop(LongPressStop, &button);
  button2.attachClick(Click, &button);
  button2.attachLongPressStart(LongPressStart2, &button);

  button.setLongPressIntervalMs(1000);
} // setup


// main code here, to run repeatedly:
void loop()
{
  // keep watching the push button:
  button.tick();
  button2.tick();

  // You can implement other code in here or just wait a while
  delay(10);
} // loop


// this function will be called when the button started long pressed.
void Click(void *oneButton)
{
  Serial.println("\t - Click button 2()");
  relaystate1 = digitalRead(RELAY2_PIN);
  if (relaystate1 == LOW) {
      digitalWrite(RELAY2_PIN, HIGH);
    }
    else {
      digitalWrite(RELAY2_PIN, LOW);
    }
}  
void LongPressStart2(void *oneButton)
{
  Serial.print(((OneButton *)oneButton)->getPressedMs());
  Serial.println("\t - LongPressStart(2)");
  relaystate = digitalRead(RELAY1_PIN);
  relaystate1 = digitalRead(RELAY2_PIN);
  if (relaystate == LOW & relaystate1 == LOW) {
      digitalWrite(RELAY1_PIN, HIGH);
      digitalWrite(RELAY2_PIN, HIGH);
    }
    else {
      digitalWrite(RELAY1_PIN, LOW);
      digitalWrite(RELAY2_PIN, LOW);
    }
}

void LongPressStart(void *oneButton)
{
  Serial.print(((OneButton *)oneButton)->getPressedMs());
  Serial.println("\t - LongPressStart()");
  relaystate = digitalRead(RELAY1_PIN);
  if (relaystate == LOW) {
      digitalWrite(RELAY1_PIN, HIGH);
    }
    else {
      digitalWrite(RELAY1_PIN, LOW);
    }
}

// this function will be called when the button is released.
void LongPressStop(void *oneButton)
{
  Serial.print(((OneButton *)oneButton)->getPressedMs());
  Serial.println("\t - LongPressStop()\n");
}

// this function will be called when the button is held down.
void DuringLongPress(void *oneButton)
{
  Serial.print(((OneButton *)oneButton)->getPressedMs());
  Serial.println("\t - DuringLongPress()");
}

// End

Würdet ihr jetzt einfach die Taster erweitern oder gibt es da nen schöneren Weg? Brauche bei meinem Nano aktl schon 23% speicher auf und muss ja auf 8 Taster & Relais kommen.

nimm für Fix-Texte das F-Makro

statt

Serial.println("Please press and hold the button for a few seconds.");

besser

Serial.println(F("Please press and hold the button for a few seconds."));

zieh das durch das ganze Programm - vergleiche wie sich der SRAM Verbrauch verändert.

const byte RELAY1_PIN = 2;
const byte RELAY2_PIN = 3;

dupliziere keinen Code, zähle keine Variablen durch.
Lerne Arrays anzuwenden.

const byte relayPin[] {2, 3];

Aber hier wäre doch immer eine 1 zu 1 Beziehung?
Sprich z.B.

const byte relayPin[] {2, 3];
const byte buttinoin[] {A0, A3];

A0 löst Relay 2 aus.
Wenn aber jetzt A0 manchmal Relay 2 +3 auslösen soll geht das doch mit nem Array nicht?

Nein das geht dann nicht. Bevor man mit dem Programmieren beginnt sollte man erst einmal eine genaue Spezifikation haben was das Programm wann machen soll.

definiere "manchmal" ...

man kann schon auch sowas machen:

if (digitalRead(buttinoin[0]) == LOW) {
  digitalWrite(relayPin[0], HIGH);
  if (manchmal == true) 
    digitalWrite(relayPin[1], HIGH);
}

also wie schon @wwerner geschrieben hat - definiere die genaue Logik / Zustandsverhalten

edit:

vieleicht machst noch mal einen aktualisierten Post von deinem Beitrag #4 sodass er auch stimmt.
Weil hast du jetzt 8 Taster oder 10?
Taster 11 genauer beschreiben ob der nun 4 oder 8 Relais schaltet
Funktion 3
was meinst du genau mit "teilweise". Es gibt keinen c++ Befehl "teilweise". Das musst schon ganz genau beschreiben.