Interrupt funktioniert nicht

Moin zusammen,
ich will mit dem Mega2560 abwechselnd zwei Gruppen von Relais schalten (mit Pause zwischendurch). Die Zyklen sollen gezählt, im EEPROM gespeichert und auf dem LCD Display ausgeggeben werden. Das funktioniert auch soweit. Mit einem Interrupt soll der Zyklus gestoppt werden können (da die Relais je 30s geschltet sind mit je 30s Pause). Dazu will ich einen Variablenstatus mit dem interrupt auf 0 setzen und diesen dann am Anfang des nächsten Loops abfragen. Zum Starten will ich einen zweiten Taster verwenden, der den Variablenstatus auf 1 setzt. Das Problem beim Interrupt ist folgende Fehlermeldung:
"expected constructor, destructor, or type conversion before '(' token"

Hallo
Zeige den Sketch wohl formatiert und in code tags.
grafik

Wozu ein Interrupt?

Zum Button auslesen braucht man üblicherweise keinen Interrupt.

Halte dich an das Beispiel BlinkWithoutDelay - programmiere ohne lange Delay - dann kannst du "parallel" auch deine Buttons abfragen während der Zyklus läuft.

Vorschlag ungetestest:

// constants won't change. Used here to set a pin number:
const int ledPin =  LED_BUILTIN;// the number of the LED pin

// Variables will change:
int ledState = LOW;             // ledState used to set the LED

// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0;        // will store last time LED was updated

// constants won't change:
const long interval = 1000;           // interval at which to blink (milliseconds)

const byte startPin = 2;
const byte endPin = 3;
bool isRunning = true;

void setup() {
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT);
  pinMode(startPin, INPUT_PULLUP);
  pinMode(endPin, INPUT_PULLUP);
}

void loop() {
  // here is where you'd put code that needs to be running all the time.

  // check to see if it's time to blink the LED; that is, if the difference
  // between the current time and last time you blinked the LED is bigger than
  // the interval at which you want to blink the LED.
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval && isRunning) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }

  if (digitalRead(startPin) == LOW && !isRunning)
  {
    isRunning = true;
    previousMillis = millis();
    ledState = HIGH;
    digitalWrite(ledPin, ledState);
  }

  if (digitalRead(endPin) == LOW && isRunning)
  {
    isRunning = false;
    ledState = LOW;
    digitalWrite(ledPin, ledState);
  }
}
#include <LiquidCrystal.h>
#include <EEPROM.h>

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;           // Standardtext für LCD
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

float Speicherwert;
bool reset ;
volatile geschaltet = 0;                                              // Schaltzustand für start / stop

int start = 19;                                                       // Taster für start


int K1 = 22;                                                          // Relais Pins
int K2 = 24;
int K3 = 26;
int K4 = 28;
int K5 = 30;
int K6 = 32;


void setup() {

  lcd.begin(16, 2);                            //"Takte:" auf lcd anzeigen
  lcd.setCursor(0, 0);
  lcd.print("Takte:");


  pinMode(8, INPUT);                            // reset Taster
  pinMode(start, INPUT);                        // start Taster
  pinMode(10, OUTPUT);

  pinMode(K1, OUTPUT);                          // Relais Outputs
  pinMode(K2, OUTPUT);
  pinMode(K3, OUTPUT);
  pinMode(K4, OUTPUT);
  pinMode(K5, OUTPUT);
  pinMode(K6, OUTPUT);

}

attachInterrupt(digitalPinToInterrupt(0) , STOP, RISING);    // aktivierung des Interrupts


void loop() {

  if (digitalRead(start) == HIGH)                 // Abfrage start Taster
  {
    geschaltet = 1
  }

  if (geschaltet == 1) {                          // wenn der Zustand des start / stop Wertes 1 ist, den Testablauf starten

    //Ablauf beginnt

    EEPROM.get(5, Speicherwert);                  // Speicherwert aus Adresse 5 des EEPROM lesen

    lcd.setCursor(0, 1);
    lcd.print(Speicherwert);                      // Speichewert auf Display ausgeben

    delay(1000);

    digitalWrite(K1, LOW);                        // Relais Gruppe 1 schalten
    digitalWrite(K2, HIGH);
    digitalWrite(K3, LOW);
    digitalWrite(K4, HIGH);
    digitalWrite(K5, LOW);
    digitalWrite(K6, HIGH);
    delay(1000);

    digitalWrite(K1, HIGH);                        // Pause
    digitalWrite(K2, HIGH);
    digitalWrite(K3, HIGH);
    digitalWrite(K4, HIGH);
    digitalWrite(K5, HIGH);
    digitalWrite(K6, HIGH);
    delay(2000);


    digitalWrite(K1, HIGH);                        // Relais Gruppe 2 schalten
    digitalWrite(K2, LOW);
    digitalWrite(K3, HIGH);
    digitalWrite(K4, LOW);
    digitalWrite(K5, HIGH);
    digitalWrite(K6, LOW);
    delay(1000);

    digitalWrite(K1, HIGH);                        // Pause, während der Taktwert ins EEPROM geschrieben wird (sonst Verzögerung)
    digitalWrite(K2, HIGH);
    digitalWrite(K3, HIGH);
    digitalWrite(K4, HIGH);
    digitalWrite(K5, HIGH);
    digitalWrite(K6, HIGH);
    //delay(2000);


    Speicherwert++;                                // Speicherwert + 1 (1 Takt)

    EEPROM.put(5, Speicherwert);                   // den neuen Speicherwert ins EEPROM schreiben

    reset = digitalRead(8);                        // Taster für Reset des EEPROM
    if (reset == HIGH) {
      EEPROM.put(5, Speicherwert = 0);
    }

  }

}

void STOP() {                                 // ISR
  geschaltet = 0;                             // digitaler Schalter aus

volatile was? byte? int? float?

Pin 0 unterstützt keinen (External-) Interrupt.

Timing per delay ist mega unpraktisch.

Vielen Dank schonmal. Kann ich dann "const long interval" auf 30.000 setzten und statt "ledState" die Pins der Relais, die geschaltet bzw. nicht geschaltet werden sollen?

jein nicht ganz.

ergänze die digitalWrite
Weiters, du hast nicht nur "Ein" / "Aus" sondern offenbar mehrere States

GruppeA
AUS
GruppeB
AUS

also brauchst du eine Statusvariable die 0...3 speichert und nicht nur LOW/HIGH. Ist aber egal, weil ledState eh schon eine int Variable ist, also kannst dort auch Zahlen aufnehmen.

Bei Zeitablauf dann jeweils in den nächsten Status schalten .

Hallo
löte die ganzen delay()´s aus und ersetze diese durch einen Time-Handler. Damit wird die ISR überflüssig.

Ich habe den gesamten Sketch umgeschrieben ohne delay. Jetzt ist der Sketch zwar formal richtig, funtioniert aber noch nicht. Nach Tasterdruck (S3) werden 3 Relais eingeschaltet, danach ändert sich nichts mehr.

#include <LiquidCrystal.h>
#include <EEPROM.h>

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;           // Standardtext für LCD
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);



int RelaisStatus = 0;                        // Status, welchen Schaltzustand die Relais haben
unsigned long previousMillis = 0;            // will store last time LED was updated

// constants won't change:
const long interval = 3000;                 // Intervall der einzelnen Schaltzeiten

float Speicherwert;
bool reset ;
bool geschaltet = LOW;


  int start = 19;                              // Taster für start und stop (S3)

  int K1 = 22;                                 // Relais Pins
  int K2 = 24;
  int K3 = 26;
  int K4 = 28;
  int K5 = 30;
  int K6 = 32;


void setup() {


  pinMode(8, INPUT);                            // reset Taster (S1)
  pinMode(start, INPUT);                        // startstop Taster
  pinMode(10, OUTPUT);

  pinMode(K1, OUTPUT);                          // Relais Outputs
  pinMode(K2, OUTPUT);
  pinMode(K3, OUTPUT);
  pinMode(K4, OUTPUT);
  pinMode(K5, OUTPUT);
  pinMode(K6, OUTPUT);

}



void loop() {

  if (digitalRead(19) == HIGH)                         // Abfrage startstop Taster
  {
    geschaltet = !geschaltet;                         // bei Tasterdruck den Startus des Schaltzustandes umkehren
  }

  if (geschaltet == HIGH) {                           // wenn der Zustand des startstop Tasters HIGH ist, den Testablauf starten

    //Ablauf beginnt

    EEPROM.get(5, Speicherwert);                      // Speicherwert aus Adresse 5 des EEPROM lesen

    lcd.setCursor(0, 1);
    lcd.print(Speicherwert);                          // Speichewert auf Display ausgeben


    // check to see if it's time to blink the LED; that is, if the difference
    // between the current time and last time you blinked the LED is bigger than
    // the interval at which you want to blink the LED.
    unsigned long currentMillis = millis();

    if (currentMillis - previousMillis >= interval) {
      // save the last time you blinked the LED
      previousMillis = currentMillis;

      // if the LED is off turn it on and vice-versa:
      if (RelaisStatus == 0) {
        RelaisStatus = 1;

        // set the LED with the ledState of the variable:
        digitalWrite(K1, LOW);                                       // Relais Gruppe 1 schalten
        digitalWrite(K2, HIGH);
        digitalWrite(K3, LOW);
        digitalWrite(K4, HIGH);
        digitalWrite(K5, LOW);
        digitalWrite(K6, HIGH);
      }
    }

    if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;

      if (RelaisStatus == 1) {
        RelaisStatus = 2;

        digitalWrite(K1, HIGH);                                     // Pause
        digitalWrite(K2, HIGH);
        digitalWrite(K3, HIGH);
        digitalWrite(K4, HIGH);
        digitalWrite(K5, HIGH);
        digitalWrite(K6, HIGH);
      }
    }

    if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;

      if (RelaisStatus == 2) {
        RelaisStatus = 3;

        digitalWrite(K1, HIGH);                                     // Relais Gruppe 2 schalten
        digitalWrite(K2, LOW);
        digitalWrite(K3, HIGH);
        digitalWrite(K4, LOW);
        digitalWrite(K5, HIGH);
        digitalWrite(K6, LOW);
      }
    }


    if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;

      if (RelaisStatus == 3) {
        RelaisStatus = 0;

        digitalWrite(K1, HIGH);                                     // Pause
        digitalWrite(K2, HIGH);
        digitalWrite(K3, HIGH);
        digitalWrite(K4, HIGH);
        digitalWrite(K5, HIGH);
        digitalWrite(K6, HIGH);
      }
    }

    Speicherwert++;                                // Speicherwert + 1 (1 Takt)

    EEPROM.put(5, Speicherwert);                   // den neuen Speicherwert ins EEPROM schreiben

    reset = digitalRead(8);                        // Taster für Reset des EEPROM
    if (reset == HIGH) {
      EEPROM.put(5, Speicherwert = 0);
    }
  }
}

Hallo
baue an deiner Meinung nach wichtigen Stellen Serial.println ein.
So kannst du ganz einfach sehen an welchen Stellen das Programm welchen Zustand einnimmt.

Wie auch? Du hast das genauso programmiert:

if (geschaltet == HIGH) {     

Da geht es einmal durch.
Wenn LOW wertest Du nicht mehr aus.

Du verwendest previousMillis in 4 Funktionen.
Und setzt die jedesmal auf die aktuelle Zeit.
Ich bin auch aus der Aufgabenstellung unglücklich.

Mach das mit mit switch case und nicht mit if.

Nachtrag:
Ich hab mal was zusammengebaut - ungetestet und ohne Anspruch auf Vollständigkeit.

#include <LiquidCrystal.h>
#include <EEPROM.h>

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;           // Standardtext für LCD
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

const unsigned long bouncetime = 20; // Zeit in ms
unsigned long tastmillis = 0; // Merker für letzten Tastendruck
static bool lastSwitch = LOW;
bool geschaltet = LOW;

const unsigned long interval = 3000;
unsigned long previousMillis = 0;

enum {anzeige, gruppe1, pause1, gruppe2, pause2, ende};
unsigned int relaisStatus = ende;

unsigned int Speicherwert;

const byte start = 19;                              // Taster für start und stop (S3)

const byte K1 = 22;                                 // Relais Pins
const byte K2 = 24;
const byte K3 = 26;
const byte K4 = 28;
const byte K5 = 30;
const byte K6 = 32;


void setup()
{
  pinMode(8, INPUT);                            // reset Taster (S1)
  pinMode(start, INPUT);                        // startstop Taster
  pinMode(10, OUTPUT);
  pinMode(K1, OUTPUT);                          // Relais Outputs
  pinMode(K2, OUTPUT);
  pinMode(K3, OUTPUT);
  pinMode(K4, OUTPUT);
  pinMode(K5, OUTPUT);
  pinMode(K6, OUTPUT);
}


void loop()
{
  if (millis() - tastmillis >= bouncetime)
  {
    geschaltet = digitalRead(19);
    if (geschaltet && !lastSwitch)
    {
      relaisStatus = anzeige;
      tastmillis = millis();
      lastSwitch = true;
    }
  }
  switch (relaisStatus)
  {
    case anzeige:
      //Ablauf beginnt
      EEPROM.get(5, Speicherwert);
      lcd.setCursor(0, 1);
      lcd.print(Speicherwert);
      previousMillis = millis();
      relaisStatus = gruppe1;
      break;
    case gruppe1:
      if (millis() - previousMillis >= interval)
      {
        relaisgruppe1();
        previousMillis = millis();
        relaisStatus = pause1;
      }
      break;
    case pause1:
      if (millis() - previousMillis >= interval)
      {
        relaisaus();
        previousMillis = millis();
        relaisStatus = gruppe2;
      }
      break;
    case gruppe2:
      if (millis() - previousMillis >= interval)
      {
        relaisgruppe2();
        previousMillis = millis();
        relaisStatus = pause2;
      }
      break;
    case pause2:
      if (millis() - previousMillis >= interval)
      {
        relaisaus();
        Speicherwert++;
        if (digitalRead(8))
        {
          Speicherwert = 0;
        }
        EEPROM.put(5, Speicherwert = 0);
        relaisStatus = ende;
        lastSwitch = false;
      }
      break;
    case ende:
      {
        // hier nichts machen
        // wartet auf Neustart mit Pin 19
      }
      break;
  }
}

void relaisgruppe1()
{
  digitalWrite(K1, LOW);   // Relais Gruppe 1 schalten
  digitalWrite(K2, HIGH);
  digitalWrite(K3, LOW);
  digitalWrite(K4, HIGH);
  digitalWrite(K5, LOW);
  digitalWrite(K6, HIGH);
}

void relaisaus()
{
  digitalWrite(K1, HIGH);
  digitalWrite(K2, HIGH);
  digitalWrite(K3, HIGH);
  digitalWrite(K4, HIGH);
  digitalWrite(K5, HIGH);
  digitalWrite(K6, HIGH);
}

void relaisgruppe2()
{
  digitalWrite(K1, HIGH); // Relais Gruppe 2 schalten
  digitalWrite(K2, LOW);
  digitalWrite(K3, HIGH);
  digitalWrite(K4, LOW);
  digitalWrite(K5, HIGH);
  digitalWrite(K6, LOW);
}

Damit sollte man vorsichtig sein....
Denn das EEPROM hält 100000 garantierte Zyklen aus.
Das schaffst du u.U. in 2 bis 3 Sekunden

Na ja, hier wohl schon deutlich länger. Aber wofür
float Speicherwert;
überhaupt gut ist, würde mich schon interessieren.

@klx305 also eigentlich sehe ich hier eine ganz klare Finite State Machine.
Bevor ich ein Beispiel geben, möchte ich aber, dass wir uns klar über die einzelnen Schritte werden:

Sehe ich es richtig, dass es 5 Zustände sind?
Die Reihenfolge soll
IDLE
Pause1
Gruppe1
Pause2
Gruppe2
sein?

Aus dem IDLE möchtest mit dem Startbutton die Sequenz starten?
Während des Status Gruppe 2 möchtest du mit dem Reset Button den Zähler zurücksetzen können?
Wenn die Gruppe 2 beginnt möchtest du den Zähler erhöhen (und ins EEPROM speichern)?
Wie lange soll Gruppe2 an sein?
Läuft Gruppe 2 auch per Zeit ab?

wenn du die Fragen beantworten bzw. die Annahmen bestätigen/korrigieren kannst, kann ich in der Folge auch Code zeigen...

1 Like

Es gibt noch den Zustand auslesen und anzeigen, und am Ende noch speichern.
Ich wart' ja auch drauf, ob sich noch was ergibt nach meiner statemachine... :wink:

schonmal vielen Dank für die vielen und hilfreichen Antworten!!!!!!!!!!!
Das Programm soll durch einen taster gestartet werden. Dann soll zuerst die Relaisgruppe 1 für 30s eingeschaltet sein (zum testen hab ich immer 2s gewählt). Nach 30s Pause soll die Relaisgruppe 2 für 30s eingeschaltet werden. Danach nopchmal 30s Pause. Am Ende eines jeden Loops soll der Speicherwert 1 hochgezählt und im EEEPROM gespeichert werden. Per Tasterdruck soll der Ablauf zu jedem Zeitpunkt unterbrochen werden können. Und es soll möglich sein, den Speicherwert auf 0 zu setzen und im EEPROM entsprechend zu speichern (da reicht es, wenn das nur nach Unterbrachung möglich ist). Ich werde es jetzt mal mit euren Sketches versuchen. Wie gesagt schon mal vielen vielen Dank!!!!!

Frage 1:
läuft das nur einmal bis zum EEPROM speichern durch und muss es dann wieder durch Taster gestartet werden
oder
läuft das in einer Dauerschleife bis zum Unterbrechen mittels Tasterdruck

Frage 2:
warum hast du in deinem Sketch aus Post #4 nach dem Starten und Ausgabe auf dem LCD eine Sekunde Pause?

    lcd.setCursor(0, 1);
    lcd.print(Speicherwert);                      // Speichewert auf Display ausgeben

    delay(1000);                       // <-- dieses delay hast du nicht beschrieben

    digitalWrite(K1, LOW);                        // Relais Gruppe 1 schalten
    digitalWrite(K2, HIGH);
    digitalWrite(K3, LOW);

soll es diese geben? Beschrieben hast du es nicht.

  1. Der Zyklus soll in Dauerschleife durchlaufen, bis er unterbrochen wird (vermutlich wird das Ganze einige Tage laufen), aber soll jederzeit unterbrechbar sein
  2. die Pause hatte ich gesetzt, um dem Arduino Zeit zu geben, den EEPROM wert zu ändern, aber eigentlich war das völliger Schwachsinn

Dann meinen umgeschrieben - taste an pin 8 wird jetzt dauerhaft abgerufen und nicht erst vor dem Speichern des Inhaltes und die erste Pause nach dem Display ist raus.
Ob ich das mit der stop verstanden habe, musst Du probieren.

#include <LiquidCrystal.h>
#include <EEPROM.h>

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;           // Standardtext für LCD
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

const unsigned long bouncetime = 20; // Zeit in ms
unsigned long tastmillis = 0; // Merker für letzten Tastendruck
static bool lastSwitch = LOW;
bool geschaltet = LOW;

const unsigned long interval = 3000;
unsigned long previousMillis = 0;

enum {warten, anzeige, gruppe1, pause1, gruppe2, pause2};
unsigned int relaisStatus = warten;

unsigned int Speicherwert;

const byte start = 19;                              // Taster für start und stop (S3)
const byte rest = 8; // Zaehler auf 0 stellen
bool restMerker = false;

const byte K1 = 22;                                 // Relais Pins
const byte K2 = 24;
const byte K3 = 26;
const byte K4 = 28;
const byte K5 = 30;
const byte K6 = 32;


void setup()
{
  pinMode(8, INPUT);                            // reset Taster (S1)
  pinMode(start, INPUT);                        // startstop Taster
  pinMode(10, OUTPUT);
  pinMode(K1, OUTPUT);                          // Relais Outputs
  pinMode(K2, OUTPUT);
  pinMode(K3, OUTPUT);
  pinMode(K4, OUTPUT);
  pinMode(K5, OUTPUT);
  pinMode(K6, OUTPUT);
}


void loop()
{
  if (millis() - tastmillis >= bouncetime)
  {
    geschaltet = digitalRead(start);
    if (geschaltet)
    {
      tastmillis = millis();
      if (!lastSwitch)
      {
        relaisStatus = anzeige;
        lastSwitch = true;
      }
      else
      {
        relaisStatus = warten;
        lastSwitch = false;
      }
    }
  }
  if (digitalRead(rest))
  {
    restMerker = true;
  }

  switch (relaisStatus)
  {
    case warten:
      {
        // hier nichts machen
        // wartet auf Neustart mit Pin 19
      }
      break;
    case anzeige:
      //Ablauf beginnt
      EEPROM.get(5, Speicherwert);
      lcd.setCursor(0, 1);
      lcd.print("               ");
      lcd.setCursor(0, 1);
      lcd.print(Speicherwert);
      relaisStatus = gruppe1;
      break;
    case gruppe1:
      {
        relaisgruppe1();
        previousMillis = millis();
        relaisStatus = pause1;
      }
      break;
    case pause1:
      if (millis() - previousMillis >= interval)
      {
        relaisaus();
        previousMillis = millis();
        relaisStatus = gruppe2;
      }
      break;
    case gruppe2:
      if (millis() - previousMillis >= interval)
      {
        relaisgruppe2();
        previousMillis = millis();
        relaisStatus = pause2;
      }
      break;
    case pause2:
      if (millis() - previousMillis >= interval)
      {
        relaisaus();
        Speicherwert++;
        if (restMerker)
        {
          Speicherwert = 0;
          restMerker = false;
        }
        EEPROM.put(5, Speicherwert);
        relaisStatus = anzeige;
        lastSwitch = false;
      }
      break;
  }
}

void relaisgruppe1()
{
  digitalWrite(K1, LOW);   // Relais Gruppe 1 schalten
  digitalWrite(K2, HIGH);
  digitalWrite(K3, LOW);
  digitalWrite(K4, HIGH);
  digitalWrite(K5, LOW);
  digitalWrite(K6, HIGH);
}

void relaisaus()
{
  digitalWrite(K1, HIGH);
  digitalWrite(K2, HIGH);
  digitalWrite(K3, HIGH);
  digitalWrite(K4, HIGH);
  digitalWrite(K5, HIGH);
  digitalWrite(K6, HIGH);
}

void relaisgruppe2()
{
  digitalWrite(K1, HIGH); // Relais Gruppe 2 schalten
  digitalWrite(K2, LOW);
  digitalWrite(K3, HIGH);
  digitalWrite(K4, LOW);
  digitalWrite(K5, HIGH);
  digitalWrite(K6, LOW);
}

[edit: Beim Put war das =0 noch mit reinkopiert[/edit]