Programm mit Taster starten und nach 3 Wiederholungen anhalten

Hallo :)

Ich habe ein Programm, das ich gerne mit einem Tasten drück starten würde und es soll nach 3 Wiederholungen anhalten bis ich den Taster wider drücke Dan sol es wider von vorn beginnen ich weis aber nicht wie das geht, kann mir da jemand helfen gesteuert werden soll ein 4 Kanal Relai

Mfg Marcel

Arduino program

const int relaisPin_1 =  10;
const int relaisPin_2 =  11;
const int relaisPin_4 =  13;

void setup() {                
pinMode(relaisPin_1, OUTPUT);
pinMode(relaisPin_2, OUTPUT);
pinMode(relaisPin_4, OUTPUT);
}

void loop()                     
{

 digitalWrite(relaisPin_2, LOW);
 digitalWrite(relaisPin_4, LOW);
 digitalWrite(relaisPin_1, HIGH);  
 delay(12000);                     
 digitalWrite(relaisPin_2, HIGH);
 digitalWrite(relaisPin_4, HIGH);
 digitalWrite(relaisPin_1, LOW);
 delay(6000); 
}

Ein Endlicher Automat wirds werden. Und nutze bitte die Code BBCodes.

was ist ein BBCod ?

Marcel87:
was ist ein BBCod ?

Links über den Smilies findest du den Code Button.

Du speicherst den Zustand des Tasters (zB statustatser) und zählst eine Variable hoch.

if (statustaster ==1 && zaehler <3)
 {
  Wiederholung;
  zaehler ++;
 }
else
  {
  zaehler =0;
  statustaster = 0;
  }

Bitte lerne den Gebrauch von millis statt delay();
siehe https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay

Grüße Uwe

Möglicherweise weitere nützliche Links:

Anleitung Endlicher Automat mit millis

Fußgängerampel Erweiterung und die Vorschläge von jurs!

Hallo

danke für die vielen hilfreichen antworten :)

dar hab ich erstmal viel zu lesen :)

Mfg Marcel

Hi Ich geb auf :( ich bekomme das Programm einfach nicht hin das Programm sollte für eine Sirene seihen die auf Knopf druck los geht und nach 3 runden Heuelen wider aus gehen wie Bai der Feuerwehr wen die alarmiert werden

trotzdem danke für die vielen hilfreichen antworten :)

Mfg Marcel

Marcel87: Ich geb auf :(

Schade, Dein Ansatz war ja durchaus ausbaufähig!

Marcel87: dar hab ich erstmal viel zu lesen :)

Du hast gerade mal eine Stunde gelesen. Möglicherweise ja morgen mit frischer Energie?

Marcel87:
Hi
Ich geb auf :frowning:
ich bekomme das Programm einfach nicht hin das Programm sollte für eine Sirene seihen die auf Knopf druck los geht und nach 3 runden Heuelen wider aus gehen wie Bai der Feuerwehr wen die alarmiert werden

Ist das deutsche Rettungswesen inzwischen so arm dran, dass die Feuerwehren für ihre eigene technische Ausstattung sorgen müssen?

So ganz 100% hast Du den beabsichtigten Ablauf nicht beschrieben, aber ich versuche mal was.

Als Ansatz habe ich eine einfache “State Machine” gewählt, die im Code selbst implementiert ist, d.h. eine zusätzliche Library wird nicht benötigt.

Für die State-Machine habe ich zwei Zustände vorgesehen, für jeden Zustand gibt es eine Funktion:

  • void stateWarten(const boolean firstRun)
  • void stateAlarm(const boolean firstRun)

Diese beiden Funktionen werden von der State-Machine aufgerufen, und zwar einmal mit dem Parameter “firstRun=true” einmalig, wenn der Status gesetzt wird. Und ansonsten ständig mit dem Parameter “firstRun=false”, solange derselbe Status aktiv ist.

Programmlogik für “stateWarten()”:

  • bei “firstRun” werden alle Relais auf LOW gesetzt und eine Meldung auf Serial ausgegeben
  • ansonsten wird auf das Drücken des Tasters gewartet. Beim Drücken ändert sich der Status auf stateAlarm()

Beim Taster bin ich davon ausgegangen, dass dieser zwischen GND und Arduino-Pin angeschlossen wird, ohne einen PullDown-Widerstand in der Schaltung zu verwenden. Daher wird der interne PullUp-Widerstand des Atmega im Programm aktiviert (“pinMode(Taster,INPUT_PULLUP);”) und der gedrückte Taster liefert ein LOW.

Programmlogik für “stateAlarm()”:

  • bei “firstRun” werden die Relais LOW, LOW, HIGH gesetzt und eine Meldung ausgegeben
  • ansonsten: nach 12 Sekunden die Relais auf HIGH, HIGH, LOW setzen und
    nach 18 Sekunden wieder auf LOW, LOW, HIGH und den Wiederholungszähler um 1 hochzählen
  • sobald der Wiederholungszähler 3 erreicht, wieder auf Zustand “stateWarten()” schalten

So ungefähr?

typedef void(*stateFunctionPointer)(const boolean); // type of state function

class StateMachine
{
  public:
    StateMachine() // constructor StateMachine
    {
      stateActiveSince=0;
      stateFunction=NULL;
    }; 
    void setState(stateFunctionPointer newState)
    { // state change
      stateActiveSince = millis(); //reset timeout timer
      stateFunction=newState;
      stateFunction(true);
    };
    unsigned long stateTime()
    {//return ms since current state was set
      return millis() - stateActiveSince;
    }; //stateTime();
    boolean timeout(unsigned long time)
    {//returns true if Statetime >= time
      return (millis() - stateActiveSince)>=time;
    }; //timeout()
    void run()
    { //runstate running
      stateFunction(false);
    }; //run()
private:
  stateFunctionPointer stateFunction; //pointer to current state function
  unsigned long stateActiveSince;
};

// void idle(boolean firstRun){}; // every state function has a boolean parameter

StateMachine sm;
byte Taster=2;
byte relays[]={10,11,12};
#define NUMRELAYS sizeof(relays)

void setRelays(byte r0, byte r1, byte r2)
{
  digitalWrite(relays[0],r0);
  digitalWrite(relays[1],r1);
  digitalWrite(relays[2],r2);
  Serial.print(r0);Serial.print(r1);Serial.println(r2);
}

void stateWarten(const boolean firstRun)
{
  if (firstRun)
  {
    setRelays(LOW, LOW, LOW); // Relaisstatus während der Wartezeit
    Serial.println("Warte auf Tastendruck...");
  }
  else
  {
    if (digitalRead(Taster)==LOW) sm.setState(stateAlarm);
  }
}

void stateAlarm(const boolean firstRun)
{
  static unsigned long startZeit;
  static byte Wiederholungen;
  static byte anfang;
  if (firstRun) // Wenn dieser Status neu gesetzt wird
  {
    startZeit=millis();
    Wiederholungen=0;
    anfang=true;
    setRelays(LOW, LOW, HIGH);
    Serial.println("3 Wiederholungen starten jetzt");
  }
  else // Wenn dieser Status gesetzt ist und wiederholt aufgerufen wird
  {
    if (anfang && millis()-startZeit>=12000)
    {
      anfang=false;
      setRelays(HIGH, HIGH, LOW);
    }
    else if (millis()-startZeit>=18000)
    {
      startZeit=millis();
      anfang=true;
      setRelays(LOW, LOW, HIGH);
      Wiederholungen++;
      if (Wiederholungen==3) sm.setState(stateWarten);
      else Serial.println("Wiederholung startet");
    }
  }
}

void setup() {
  Serial.begin(9600);
  for (int i=0;i<NUMRELAYS;i++) pinMode(relays[i],OUTPUT);
  pinMode(Taster,INPUT_PULLUP);
  sm.setState(stateWarten);
}

void loop() {
  sm.run();
}

Die von Dir zu verwendenden Pins wären in diesen beiden Zeilen einzutragen:

byte Taster=2;
byte relays[]={10,11,12};

Hast Du Solid-State-Relais, die auf “HIGH” schalten?
Oder mechanische Relais, die auf “HIGH” im Ruhezustand sind und auf “LOW” schalten?
Bei mechanischen “Active-LOW” schaltenden Relais müßtest Du auf die korrekte Initialisierung im setup() achten!

Wenn sich an der Programmlogik etwas ändern soll, wären diese beiden Funktionen zu ändern:

  • void stateWarten(const boolean firstRun)
  • void stateAlarm(const boolean firstRun)
    Bei Problemen einfach nachfragen.

Ein sehr hübsches "Beispiel", jurs.

Warum hast du sm.timeout() nicht verwendet ?

michael_x:
Ein sehr hübsches “Beispiel”, jurs.

Warum hast du sm.timeout() nicht verwendet ?

Gute Frage. Da schreibe ich eine kleine StateMachine C+±Klasse und von den vier Funktionen stelle ich dann nur die Funktionen run() und setState() vor.

Eigentlich könnte ich auch stateTime() und timeout() vorstellen, und die Programmlogik wird damit sogar vielleicht noch deutlicher.

Es gibt ja immer mehrere Möglichkeiten. Zur Verdeutlichung: Die State-Machine in Antwort #9 betrachtet den Alarmzustand insgesamt als einen Zustand der State-Machine. Die Anzahl der Wiederholungen wird intern in einer statischen Variablen innerhalb der Funktion mitgezählt.

Man könnte andererseits auch eine einzelne Wiederholung der Alarmphase für sich als einen Zustand der State-Machine betrachten. Dann würde am Ende einer Wiederholung beim Auftreten eines timeout() eine neue Wiederholung gestartet, indem dieselbe State-Funktion, die gerade einen timeout hatte, nochmals neu als neue State-Funktion gesetzt wird, womit eine neue Zeitzählung beginnt.

Auch das habe ich einmal realisiert.

Außerdem habe ich die State-Machine Klasse mal in eine extra .h Datei ausgelagert, so dass der (wiederverwertbare) Algorithmus der State-Machine einzeln in einer Datei steht und der Sketch nur noch die Programmlogik des zu realisierenden Programms mit den State-Funktionen.

Datei ist als Anhang beigefügt. Zur Installation einfach den im ZIP-Archiv enthaltenen Ordner im Arduino-Sketch-Ordner entpacken.

P.S.: Die von mir realisierte State-Machine Klasse belegt einschließlich Konstruktor und den vier Funktionen setState(), stateTime(), timeout() und run() weniger als 40 Codezeilen. Überraschend wenig Code für ein äußerst vielseitig verwendbares State-Machine Objekt, mit dem man sogar diverse gleichzeitig laufende State-Machines in einem einzigen Sketch realisieren kann.

StateMachine_Test1.zip (1.59 KB)

Hallo Marcel, da ich sehe, Du bist angemeldet, überdenkst Du ja möglicherweise Deine Aufgabe?

Ganz frisch etwas mehr Lesestoff für Dich: Anleitung Ein Endlicher Automat entsteht

Die klasse Klassen von jurs sind natürlich ebenfalls lesenswert! Es gibt da unterschiedliche Ansätze.

Ist das deutsche Rettungswesen inzwischen so arm dran, dass die Feuerwehren für ihre eigene technische Ausstattung sorgen müssen?

Nein ich mach das nur für mich zum Anfang mit einer 12V Sirene die denselben Intervall Alarm haben so wie die Sirene der Feuerwehr das heißt 12s an und 12s aus das Ganse 3X aber ich muss nach 6s wider einschalten dar die Sirene weniger Alls 12s im Leerlauf bleibt das klingt Dan nicht so gut wenn sie komplett stillsteht

Danke für das progam jurs ich bin einfach noch zu unerfahren mit dem Programmiren

Kann mir jemand ein Buch zu Arduino Programmierung empfehlen wens geht von Amazon

Mfg Marcel

Hast Du Solid-State-Relais, die auf "HIGH" schalten? Oder mechanische Relais, die auf "HIGH" im Ruhezustand sind und auf "LOW" schalten?

ich habe dise Relais

http://www.amazon.de/Kanal-Relais-Module-Arduino-TTL-Logik/dp/B00ALNJN72/ref=sr_1_6?ie=UTF8&qid=1436614446&sr=8-6&keywords=Relais

Hier noch mehr zu Zustandsautomaten: http://forum.arduino.cc/index.php?topic=332907.0

Beispiel #1 ist ähnlich einfach wie das von jurs. Statt einen globalen Zeiger auf die nächste Funktion zu verwalten, kann man auch jede Funktion einen Zeiger auf ihren Nachfolger zurückgeben lassen. Der Compiler macht da auch sehr kompakten Code draus.

Marcel87: Kann mir jemand ein Buch zu Arduino Programmierung empfehlen wens geht von Amazon

Ein Buch, das mir richtig gut gefallen hat, habe ich leider noch nicht gefunden.

Wenn Du mein Ampelbeispiel nimmst, dann kommt das Deiner Aufgabenstellung doch recht nahe: Anstelle der Ampel-LEDs hast Du die Relaiseingänge, anstelle der Ampelphasen die Sirenenphasen. Welchen Arduino hast Du? Wenn es ein UNO ist, kannst Du das Programmbeispiel direkt in Deinen UNO laden. Dann spiel etwas damit rum, denn an einer Stelle muß der Taster abgefragt werden. Erklärungen gibt es hier.

Ich mache das übrigens nicht anders. Manchmal lade ich mir ein Beispiel runter, nur um es mal zu probieren.

Marcel87: ich habe dise Relais

http://www.amazon.de/Kanal-Relais-Module-Arduino-TTL-Logik/dp/B00ALNJN72/ref=sr_1_6?ie=UTF8&qid=1436614446&sr=8-6&keywords=Relais

Das sind mechanische Relais und die dürften aller Voraussicht nach auf "Active-LOW" schalten.

D.h. so wie Du Deine setup() Funktion laufen läßt, schalten diese Relais, sobald die setup() Funktion läuft:

void setup() {                
pinMode(relaisPin_1, OUTPUT); // Output/LOW ==> Relais schaltet
pinMode(relaisPin_2, OUTPUT); // Output/LOW ==> Relais schaltet
pinMode(relaisPin_4, OUTPUT); // Output/LOW ==> Relais schaltet
}

Das kannst Du ja leicht ausprobieren: Wenn Du diese Relais mal nur mit diesem setup() ansteuerst und sonst überhaupt nicht schaltest: Wenn sie dann beim Power-On einmal leise klicken, wenn das setup() läuft, dann sind Deine Relais Active-LOW schaltend.

D.h. während der Bootloader läuft, ist das Relais nicht geschaltet, sobald das setup() gelaufen ist, haben alle drei Relais geschaltet.

Zwar kannst Du durch vertauschen der Kontakte (NC - normally closed, NO - normally open) es so hinbekommen, dass am eingeschalteten Arduino die Sirene nicht gleich losheult, aber problematisch wäre diese Schaltung trotzdem:

Wenn in dem Fall, dass die Sirene bei geschaltetem Relais aus und bei nicht geschaltetem Relais ein ist, die Stromversorgung teilweise ausfällt: - Sirene hängt an ihrer Stromversorgung - Stromversorgung des Arduino fällt aus würde in diesem Fall das Relais in die Ausgangslage zurückfallen und die Sirene losheulen.

Bei "active Low" schaltenden mechanischen Relais macht man daher im allgemeinen die Schaltung so, dass sowohl bei vollständig als auch bei teilweise ausgefallener Stromversorgung ein "sicherer und erwünschter" Schaltzustand eingenommen wird. Also: - Sirene Stromversorgung vorhanden, Arduino Stromversorgung ausgefallen ==> Sirene aus Es sei denn, die Sirene soll Dich ausdrücklich darüber informieren, dass die Arduino Stromversorgung ausgefallen ist.

Ansonsten mußt Du ein "Active LOW" Relais entsprechend beschalten und mit der Software auch sachdienlich ansteuern.

Wobei fraglich ist, ob Du überhaupt mechanische Relais verwenden solltest. Wenn Du hardwaretechnisch genau so wenig Ahnung hast wie softwaretechnisch, dann wäre es insbesondere problematisch, wenn die angeschlossenen Sirenen eine "induktive Last" darstellen, also motorbetrieben sind.

Daher mal die Frage: Von was für Sirenen reden wir, die Du schalten möchtest? Laufen die auf Gleichstrom mit Kleinspannung? Auf Wechselstrom mit Netzspannung? Gibt es ein Datenblatt?

Zwar kannst Du durch vertauschen der Kontakte (NC - normally closed, NO - normally open) es so hinbekommen, dass am eingeschalteten Arduino die Sirene nicht gleich losheult,

Grundregel: Aktoren verschaltet man immer NO. Schalter und Taster auch. Sicherheitseinrichtungen NC. Es sei denn es sprechen gewichtige Gründe dagegen.

Aktiv Low Geräte (solche Relais) machen am AVR keine Sorgen wenn man folgendes Verfahren einhält. 1. pinMode(xx,INPUT_PULLUP); 2. pinMode(xx,OUTPUT);

Dann geht der Pin ohne zwischenzeitliche/versehentliche LOW Phase direkt von hochohmig, über eine mini Pullup Phase, zu HIGH.

Hallo

Danke an alle die mir so fleißig geholfen haben :) :) und auch Danke für die fielen links und Programme :) :) ich werde mit alle Links ansehen und auch viel darfon Cupiren was ich bisher schon gesehen habe ist sehr hilfreich für mich .

p.s das was ich bauen wollte läuft jetzt wie ich es mir vorgestellt habe Danke :) :)

Mfg Marcel