Problem mit volatile variable (Interrupt)

Hallo,

ich habe ein Problem mit meinem Sketch.

Da der Sketch sehr lang ist spare ich mir Ihn hier komplett einzufügen und poste nur die vom Fehler betroffenen Teile.

Ich habe eine Poolsteuerung programmiert, die bisher Problemfrei funktionierte.
Mein Arduino agiert dabei u.a. als Webserver und so lässt sich z.B. die Pumpe und die Beleuchtung steuern.
Die Funktion zur Steuerung der Beleuchtung hatte ich schon von Anfang an im Sketch drin und sie funktionierte auch Problemlos.

Jetzt bin ich endlich dazu gekommen mein Setup um einen physichen Lichtschalter (bzw. Taster) zu erweitern
und habe ihn per Interrupt in meinen Sketch eingebunden.

Jetzt zum eigentlichen Problem:
Über den Lichtschalter (per Interrupt) kann ich das Licht jetzt schalten, aber nicht mehr über den Webserver.
Der Webserver antwortet zwar, dass er das Licht einschaltet, dies passiert aber nicht mehr.

Meine vermutung ist, dass es mit meiner "globalen" light_state variable zusammenhängt, die ich für die Benutzung im Interrupt auf volatile setzten musste. (bzw. der zugriff versch. Funktionen auf die Variable nicht mehr richtig klappt).

Hier die betroffenen Stellen im Code:

  #define LIGHT_PIN 7
  #define LIGHT_SWITCH 3
  #define LIGHT_SWITCH_I 1 /*INTERNAL INTERRUPT-NUMBER OF PIN 3*/
  
  #define LIGHTSWITCH_THRESHOLD 150 /*millisec.*/

// die folgenden variablen waren vorher nicht volatile:
  volatile   boolean current_light_state = false;
  volatile   boolean last_light_state = false;
  volatile   boolean light_state = false;  
[....]
  void handle_light_interrupt()
  {
      static unsigned long last_interrupt_time = 0;
      unsigned long interrupt_time = millis();
      // If interrupts come faster than 200ms, assume it's a bounce and ignore
      if (interrupt_time - last_interrupt_time > LIGHTSWITCH_THRESHOLD)
      {
        light_state = !light_state;
        handle_pool_light();
        delay_start_MeasureIntervall = millis();
      }
      last_interrupt_time = interrupt_time;
  }


void setup()
  {
[....]
   pinMode(LIGHT_PIN, OUTPUT);
   digitalWrite(LIGHT_PIN, HIGH);  
   
   pinMode(LIGHT_SWITCH, INPUT);
   digitalWrite(LIGHT_SWITCH, HIGH); // ENABLE PULLUP
   
      attachInterrupt(LIGHT_SWITCH_I, handle_light_interrupt, LOW);
[....]
}

void loop()
{
[....]
 Ethernet_WebServerActivity(); //funktionen für den betrieb als webserver... s. unten
      handle_pool_light();
[....]
}

void Ethernet_WebServerActivity()
{
 [... auswertung der ankommenden daten ....]
                    if(firstchar == 'L') //LIGHT_STATE ÄNDERN
                   {
                     if(charnr == 1)
                         {
                           char c = client.read(); charnr++;
                           if(c == (0 + 48))
                           {                           
                              light_state = false;
                              handle_pool_light();
                           }   
                           else if(c == (1 + 48))   
                           {
                              light_state = true;
                              handle_pool_light();                              
                           }
                           else // ERROR OCCURED
                           {
                               ended = true;
                               error_processing_command = 5;
                               Serial.println("ERROR: THIS IS NOT A VALID LIGHT STATE (0 or 1)");
                           }                          
                            ended = true;                                                   
                           
                         }
                         if(error_processing_command == 5)
                         {
                           // ERROR
                           client.print("$ERROR_LIGHT_STATE*5*");
                            client.print(light_state);
                           client.print("$");                           
                         }
                         else
                         {
                          //everythink OK
                           client.print("$LIGHT_STATE_NEW*");
                            client.print(light_state);
                           client.print("$");       
                         }

                  

                                  delay_start_MeasureIntervall = millis(); //force the arduino to do a measurement in next loop cycle   
                 } 
[....]
} //end webserver

  boolean handle_pool_light()
  {
    last_light_state = current_light_state;
    current_light_state = light_state;
    
   digitalWrite(LIGHT_PIN, light_state);
   return light_state;
  }

Ok jetzt mal ein paar Beispiele:

  • Ich drücke den Schalter, Interrupt-Funktion greift, setzt light_state auf true und führt handle_pool_light() funktion aus.
    Das Licht geht an. Alles OK

  • Ich schicke den Befehl "Licht aus" an den Webserver, dieser setzt light_state auf false und führt handle_pool_light() aus, danach antwortet er mir, mit $LIGHT_STATE_NEW*0$. Die 0 (= false) kommt hierbei direkt aus der light_state variable, sprich, Licht müsste aus gehen beim Aufruf von handle_pool_light();
    Problem: Das Licht bleibt weiterhin an, außerhalb der Funktion Ethernet_WebServerActivity() bleibt die Variable außerdem auf true?!

Wie bekomme ich das gelöst?

Hi,
für mich klingt das eher nach einem Scope-Problem (lokale Variable geändert, globale nicht). Wurde die Variable light_state vielleicht in einer Funktion (oder als Funktionsparameter) nochmal definiert?

Das volatile scheint auch für nicht-globale Variablen relevant zu sein, ich hatte in einer Schleife im Interrupt seltsame Verhalten ohne volatile:

int x=0;
for (int i=0;i<3;i++) bitSet(x,i);

-> x war manchmal 48, was garnicht sein kann. Mit for (volatile int i=0...)" ging es dann.

Hi,

light_state ist nur einmal (über setup, also global) definiert, auch als funktionsparameter tritt sie nich nochmals auf.

Meine Probleme waren auch nicht durch das volatile verursacht, sondern dadurch, dass ich beim Kopieren eines Arrays um eins zu hoch gezählt habe und dadurch wahrscheinlich irgendwas im Stack oder so überschrieben habe. Es passiert also nichts "Seltsames". Alles, was ich volatile definiere und im Interrupt ändere, ist im Main-Loop korrekt geändert.
Vielleicht postest du ja den Sketch doch komplett.

Hi,

hab mal den kompletten Code hochgeladen:

PS: Scheinbar verändert sich die Variable light_state auch über den Tag hinweg mehrmals von allein... (seltsam?!)

Hi,

ich habs leider immer noch nicht ganz hinbekommen..
light_state hab ich jetzt erstmal wieder zur normalen variable gemacht und stattdessen eine variable
mit dem namen v_light_state (als volatile boolean) definiert.
Diese ist jetzt in der ISR und wird einmal pro loop-cycle geprüft und ggf. aktualisiert. (also mit light_state "synchronisiert")

Jetzt funktioniert der Schalter und das Web-Interface, jedoch verändert sich die volatile variable trotzdem willkürlich mehrmals am Tag...

Woran kann das liegen??