static enum question

I´m trying to control an actuator with static enum.

I´m using this code:

int endStopClose = 8;
int endStopCloseState = LOW;
int lastEndStopCloseState = 0;
int endStopOpen = 9;
int endStopOpenState = LOW;
int lastEndStopOpenState = 0;
int controlClose = 10;
int controlCloseState = LOW;
int lastcontrolCloseState = 0;
int controlOpen = 11;
int controlOpenState = LOW;
int lastcontrolOpenState = 0;
int openWindow = 12;      //Manual switch - Open window
int openWindowState = LOW;
int lastOpenWindowState = 0;
int closeWindow = 5;      //Manual switch - Close Window
int closeWindowState = LOW;
int lastCloseWindowState = 0;
int audioSensor = 6;
int audioSensorState = LOW;
int sensorPin = 2;
int sensorState = LOW;
int lastSensorState = 0;
int sensorPinValue = 0;  // variable to store the value coming from the sensor
int val = LOW;

byte byteRead;

void setup() {

  pinMode(openWindow, INPUT_PULLUP);
  pinMode(closeWindow, INPUT_PULLUP);
  pinMode(audioSensor, INPUT);
  pinMode(sensorPin, INPUT);
  pinMode(endStopClose, INPUT_PULLUP);
  pinMode(endStopOpen, INPUT_PULLUP);
  pinMode(controlClose, OUTPUT);
  pinMode(controlOpen, OUTPUT);
  Serial.begin(57600); while (!Serial); // UART serial debug

void loop() {
  static enum {MOVING_controlClose, MOVING_controlOpen, STOPPED_controlClose, STOPPED_controlOpen, STOPPED2_controlOpen} state;
  static unsigned long time_stopped;
  unsigned long now = millis();


  switch (state) {
    case MOVING_controlClose:
      if (digitalRead(endStopClose) == LOW) {
        digitalWrite(controlClose, LOW);
        state = STOPPED_controlClose;
        time_stopped = now;
      }
      break;
    case MOVING_controlOpen:
      if (digitalRead(endStopOpen) == LOW) {
        digitalWrite(controlOpen, LOW);
        state = STOPPED_controlOpen;
        time_stopped = now;
      }
      break;
    case STOPPED_controlClose:
      if (digitalRead(openWindow) == LOW) {
        digitalWrite(controlOpen, HIGH);
        state = MOVING_controlOpen;
        delay(50);
        Serial.println("Window is opened by manual switch");  //Serial monitor information.
      }
      break;

    case STOPPED_controlOpen:
      if (digitalRead(sensorPin) == HIGH || digitalRead(closeWindow) == LOW ||    digitalRead(audioSensor) == HIGH) {
        //   if (digitalRead(sensorPin) == HIGH || digitalRead(closeWindow) == LOW) {
        digitalWrite(controlClose, HIGH);
        state = MOVING_controlClose;
        delay(50);
        Serial.println("Movment sensor activated!! Window is closing...");  //Serial monitor information.
        //send_flag = true;
      }
      break;

    case STOPPED2_controlOpen:
      if (digitalRead(sensorPin) == HIGH || digitalRead(endStopOpen) == LOW) {
        digitalWrite(controlClose, HIGH);
        state = MOVING_controlClose;
        delay(50);
        Serial.println("TEST: This is instead of sending an email");  //Serial monitor information.
        //  send_flag = true;  //sending an email with ESP8266
      }
      break;

  }

In the void loop, I have added STOPPED2_controlOpen to the static enum
and this case:

case STOPPED2_controlOpen:
      if (digitalRead(sensorPin) == HIGH || digitalRead(endStopOpen) == LOW) {
        digitalWrite(controlClose, HIGH);
        state = MOVING_controlClose;
        delay(50);
        Serial.println("TEST: This is instead a sending an email");  //Serial monitor information.
        //  send_flag = true;  //sending an email with ESP8266
      }
      break;

just to describe for you, what I have done.

As you probably have guessed, it do not work and I´m lost!...

Is it posible to add more than 4 cases in the above code and how do I do it? If not - any suggestions, please?

I also have another problem:
If power is switched off when the actuator is running and the actuator is stopping between the endStopOpen and endStopClose, the program do not work, when it is powered up again.
How can I make an reset, so when the power is switched ON again, the actuator will go back to endStopClose?

Thanks in advance!!

Where do you set state to STOPPED2_controlOpen ?

Yes, thats probably the problem. I can´t figure out where the other states are set:

static enum {MOVING_controlClose, MOVING_controlOpen, STOPPED_controlClose, STOPPED_controlOpen} state;

Hope anyone can help me with that?

I must say, that I´m an totally newbee.

I can´t figure out where the other states are set:

Look what happens when the state is MOVING_controlClose for instance

      case MOVING_controlClose:
        if (digitalRead(endStopClose) == LOW)
        {
          digitalWrite(controlClose, LOW);
          state = STOPPED_controlClose;
          time_stopped = now;
        }
        break;

If the endStopClose pin is found to be LOW then the state is changed to STOPPED_controlClose so that next time through loop() the code for that state is executed otherwise the state remains the same and the same code will be executed next time through loop().

i think you would be doing yourself a favor by declaring the states before setup like this:

typedef enum {

  MOVING_controlClose,
  MOVING_controlOpen,
  STOPPED_controlClose,
  STOPPED_controlOpen,
  STOPPED2_controlOpen

} states;

then you could declare your static inside loop like this:

 static states state;

to make the code more readable as you add states.

If you want the program to begin in a known state, why not add a STARTUP state as the first state and set things as they should be?

Dude, you are declaring the state as a stack variable. Stack (auto) variables are not initialised. It will contain rubbish each time you execute the loop

.I always:

  • declare the state enum gloablly
  • have a global state variable
  • set the initial state in an initializer or in setup()

Thank you all!

I have tried your suggestions, but wihtout any good results.

I have tried to add this to the global:

typedef enum {
  MOVING_controlClose,
  MOVING_controlOpen,
  STOPPED_controlClose,
  STOPPED_controlOpen
  STOPPED2_controlOpen, // used for sending an email/sms
} states;

and this to the setup:

static states state;

It compiles fine with the global, but not with the setup.

The case STOPPED2_controlOpen in the void loop still doesn`t have any effects.

I'm not sure what Paul means by this - or how to

  • have a global state variable
  • set the initial state in an initializer or in setup()

Apologize for my ignorance of basic knowledge. :frowning:

It compiles fine with the global, but not with the setup.

You didn't post any code so it is impossible to comment on it, but does the code ever set the state to one of the new ones that you have added to the enum ?

Posting the code would enable us to see for ourselves.

does the code ever set the state to one of the new ones that you have added to the enum ?

Yes, I think so.

int endStopClose = 8;     // switch 1 inside actuator
int endStopCloseState = LOW;
int lastEndStopCloseState = 0;
int endStopOpen = 9;     // switch 2 inside actuator
int endStopOpenState = LOW;
int lastEndStopOpenState = 0;
int controlClose = 10;    // relay 1
int controlCloseState = LOW;
int lastcontrolCloseState = 0;
int controlOpen = 11;    // relay 2
int controlOpenState = LOW;
int lastcontrolOpenState = 0;

int openWindow = 12;      // push switch for manual extend actuator
int openWindowState = LOW;
int lastOpenWindowState = 0;
int closeWindow = 5;      // push switch for manual retract actuator
int closeWindowState = LOW;
int lastCloseWindowState = 0;

int audioSensor = 6;    // Audio sensor, detects noise
int audioSensorState = LOW;

int sensorPin = 2;    // Pir sensor
int sensorState = LOW;
int lastSensorState = 0;
int sensorPinValue = 0;  // variable to store the value coming from the sensor
int val = LOW;

byte byteRead;

void setup(){

typedef enum {
  MOVING_controlClose,
  MOVING_controlOpen,
  STOPPED_controlClose,
  STOPPED_controlOpen
  STOPPED2_controlOpen, // used for sending an email/sms
} states;

  pinMode(openWindow, INPUT_PULLUP);
  pinMode(closeWindow, INPUT_PULLUP);
  pinMode(audioSensor, INPUT);
  pinMode(sensorPin, INPUT);  //JEOR
  pinMode(endStopClose, INPUT_PULLUP);  //JEOR
  pinMode(endStopOpen, INPUT_PULLUP);  //JEOR
  pinMode(controlClose, OUTPUT);  //JEOR
  pinMode(controlOpen, OUTPUT);  //JEOR
  Serial.begin(57600); while (!Serial); // UART serial debug
}

void loop() {

  static enum {MOVING_controlClose, MOVING_controlOpen, STOPPED_controlClose, STOPPED_controlOpen, STOPPED2_controlOpen} state;
  static unsigned long time_stopped;
  unsigned long now = millis();

switch (state) {
    case MOVING_controlClose:
      if (digitalRead(endStopClose) == LOW) {
        digitalWrite(controlClose, LOW);
        state = STOPPED_controlClose;
        time_stopped = now;
      }
      break;
    case MOVING_controlOpen:
      if (digitalRead(endStopOpen) == LOW) {
        digitalWrite(controlOpen, LOW);
        state = STOPPED_controlOpen;
        time_stopped = now;
      }
      break;
    case STOPPED_controlClose:
      if (digitalRead(openWindow) == LOW) {
        digitalWrite(controlOpen, HIGH);
        state = MOVING_controlOpen;
        delay(50);
        Serial.println("Window is opened by manual switch");  //Serial monitor information.
      }
      break;

    case STOPPED_controlOpen:
      if (digitalRead(sensorPin) == HIGH || digitalRead(closeWindow) == LOW || digitalRead(audioSensor) == HIGH) {
        digitalWrite(controlClose, HIGH);
        state = MOVING_controlClose;
        delay(50);
        Serial.println("Movment sensor activated!! Window is closing...");  //Serial monitor information.
        //send_flag = true;
      }
      break;

    case STOPPED2_controlOpen:
      if (digitalRead(sensorPin) == HIGH && digitalRead(endStopOpen) == LOW) {
        digitalWrite(controlClose, HIGH);
        state = MOVING_controlClose;
        delay(50);
        Serial.println("TEST: This is instead of sending an email");  //Serial monitor information.
        //  send_flag = true;  //sending an email with ESP8266
      }
      break;

  }

If I use this code it compile, but it do not do what I expected it should do:

When digitalRead sensorPin and endStopOpen is HIGH / LOW, I would like it to use case STOPPED2_controlOpen:, but it use de previous case STOPPED_controlOpen: in the loop.

It I type in static states state; in void set, it doesn´t compile.

I hope it makes sense :-[

When digitalRead sensorPin and endStopOpen is HIGH / LOW, I would like it to use case STOPPED2_controlOpen:

So,when the trigger events occur set case to STOPPED2_controlOpen

By the way, why do you have 2 enums in your code, one called state and another called states ?

Somehow I managed to destroy my Arduino Uno!!! :frowning:

I will have to order a new one (or several) before I can go further.

BTW, I´m not sure if Static enum is the right way to go for this project?

The purpose with this project is (if it isn´t clear so far), that I want to control an actuator by one motion sensor, one sound detector sensor and two push switches for manually extend and retract the actuator.

Only if the motion sensor is activated and the actuator is extended, it then supposed to retract the actuator and then send a email/SMS. The actuator shall stay retracted when motion detection ends.

If the sound detector is activated, Is should retract the actuator as long as the sound detector is activ.
When it is not activ, it should extend again.

The actuator is an old one. I have taken from a table. It is modified with two relays and two end stop switches.

This static enum code, I have found in another forum thread, where it just run extract/extend in a loop, over and over again.

If anyone have an better idear to what I can use instead, I will be very happy for any suggestions.

Thanks in advance!

I´ll be back a.s.a.p. :slight_smile:

UKHeliBob:

By the way, why do you have 2 enums in your code, one called state and another called states ?

I have by mistake write states instead of state. Its corrected now.

Still waiting for the new Arduinos to arrive, so I can proceed with the project.

The fault in the Arduino hardware is, that the two output pins to the relay only deliver +2 volt instead of 5 volt when HIGH.
I suppose, that there should not be any problem connecting the relays directly to the Arduino?
I have mounted a diode over the relay coils. The current of the relays is measured to 60 mA.

jeor:
The fault in the Arduino hardware is, that the two output pins to the relay only deliver +2 volt instead of 5 volt when HIGH.
I suppose, that there should not be any problem connecting the relays directly to the Arduino?
I have mounted a diode over the relay coils. The current of the relays is measured to 60 mA.

Ups. Arduino pins should deliver not more than 20 mA.

You need a transistor/fet to drive a relay that needs 60 mA.

Thanks Whandall

It makes good sense.

jeor:
UKHeliBob:
I have by mistake write states instead of state. Its corrected now.

So, do you now have 2 different enums named state or only one ?

If you have two then could I ask why ?

Sorry, but I´m not sure what you mean,
Maybe because of my lack of knowledge I thought, that:

void setup(){

typedef enum {
MOVING_controlClose,
MOVING_controlOpen,
STOPPED_controlClose,
STOPPED_controlOpen
STOPPED2_controlOpen, // used for sending an email/sms
} state;

referes to:

void loop() {

static enum {MOVING_controlClose, MOVING_controlOpen, STOPPED_controlClose, STOPPED_controlOpen, STOPPED2_controlOpen} state;
static unsigned long time_stopped;
unsigned long now = millis();

And then I will think, that I have only one enums named state. correct me if I´m wrong.

Hi

I have now got a new Arduino Uno and have made a actuator circut with transistors. Please see the attached document.
The actuator is from a table and I have modified it with relays and endstop switches.

I still struggling with the enum code. It is not releiable and I can not figure out why.
Extend og retract the actuator with openWindow = 12 and closeWindow = 5 seems to work, but when the actuator is extended and the PIR sensor or the audio sensor is activated, it looks like the arduino stop working after retracting the actuator. The only solution is, to reset the arduino.

I am not sure where the problem is. I suspect, that it is the code.

Would someone please take a look at the code and give me some suggestions to what could be wrong?

Thanks in advance!

const int endStopClose = 8;     //switch 1 inside actuator
const int endStopOpen = 9;     //switch 2 inside actuator
const int controlClose = 10;    //relay 1
const int controlOpen = 11;    //relay 2
const int openWindow = 12;      // push switch for manual extend actuator
const int closeWindow = 5;      // push switch for manual retract actuator
const int resetPwr = 13;        // push swich for manual reset after power down and actuator is between endstops
const int audioSensor = 6;    // Audio sensor, detects noise
int audioSensorValue = 0;  // variable to store the value coming from the sensor
const int sensorPin = 2;    // select the input pin for the Pir
int sensorPinValue = 0;
int val = LOW;
byte byteRead;

void setup() {

 Serial.begin(57600); while (!Serial); // UART serial debug
 char buffer[50];

  pinMode(audioSensor, INPUT);
  pinMode(closeWindow, INPUT);
  pinMode(openWindow, INPUT);
  pinMode(sensorPin, INPUT);
  pinMode(resetPwr, INPUT);
  pinMode(endStopClose, INPUT_PULLUP);
  pinMode(endStopOpen, INPUT_PULLUP);
  pinMode(controlClose, OUTPUT);
  pinMode(controlOpen, OUTPUT);

}

void loop() {

  static enum {MOVING_controlClose, MOVING_controlOpen, STOPPED_controlClose, STOPPED_controlOpen} state;

  static unsigned long time_stopped;
  unsigned long now = millis();

  switch (state) {
    case MOVING_controlClose:
    if (digitalRead(endStopClose) == LOW) {
      if (now - time_stopped >= 1500) {
      digitalWrite(controlClose, LOW);
      state = STOPPED_controlClose;
      time_stopped = now;
      }
    }
    break;
    case MOVING_controlOpen:
    if (digitalRead(endStopOpen) == LOW) {
      digitalWrite(controlOpen, LOW);
      state = STOPPED_controlOpen;
      time_stopped = now;
    }
    break;
    case STOPPED_controlClose:
    if (digitalRead(openWindow) == HIGH){
      digitalWrite(controlOpen, HIGH);
      state = MOVING_controlOpen;
      delay(50);
      Serial.println("Window is opened by manual switch...!");  //Serial monitor information.

    }
    break;
    case STOPPED_controlOpen:
    if (digitalRead(sensorPin) == HIGH) {
      digitalWrite(controlClose, HIGH);
      state = MOVING_controlClose;
      delay(50);
      Serial.println("PIR sensor activated...!");  //Serial monitor information.
    }
     break;


  }
  if (digitalRead(resetPwr) == HIGH && digitalRead(endStopOpen) == HIGH && digitalRead(endStopClose) == HIGH) {
    digitalWrite(controlClose, HIGH);
    state = MOVING_controlClose;
    time_stopped = now;
    delay(50);
    Serial.println("Manual RESET switch after power down"); // If the actuator stops between the end stops after power loss, it is possible to reset actuator to endStopClosed position.
  }

  if (digitalRead(endStopOpen) == LOW && digitalRead(closeWindow) == HIGH) {
    digitalWrite(controlClose, HIGH);
    state = MOVING_controlClose;
    time_stopped = now;
    delay(50);
    Serial.println("Manual close switch activated");
  }

  if (digitalRead(audioSensor) == HIGH && digitalRead(endStopOpen) == LOW) {
    digitalWrite(controlClose, HIGH);
    state = MOVING_controlClose;
    time_stopped = now;
    delay(50);  
    Serial.println("Audio sensor activated"); // If audio sensor is HIGH, 
  }

}

Try printing the value of state before the switch/case to see what it is. Is it changing to the expected value ?

I am still not clear how the inputs are wired. Can you please explain this ?

Try printing the value of state before the switch/case to see what it is. Is it changing to the expected value ?

Yes

I am still not clear how the inputs are wired. Can you please explain this ?

Please take a look at the attached circutdrawing. Sorry for the bad drawing - I am not a good friend with Inkscape.
The transistor circut is not included in this drawing.

In closed condition:
endStopClose = LOW
endStopOpen = HIGH
In open condition:
endStopClose = HIGH
endStopOpen = LOW

openWindow = LOW in standby condition and gets HIGH when the switch is pushed
closeWindow = LOW in standby condition and gets HIGH when the switch is pushed
resetPwr = LOW in standby condition and gets HIGH when the switch is pushed

sensorPin(PIR) and audioSensor are LOW when not activated and gets HIGH when activated.

I get all the serial.println when it is working.

I hope this is the information you asked for?

Taking an example from your post

openWindow = LOW in standby condition and gets HIGH when the switch is pushed

openWindow is pin 12

On the circuit diagram you can see that when in standby, ie open, the pin is not connected to anything, ie it is floating, and could be at any voltage. So your statement that it is LOW is not correct.

The same goes for other inputs too. I suggest that you add pulldown resistors to inputs where the switch does not provide a voltage when it is open. Better still, change the circuit and program so that the switches connect to GND when closed and use INPUT_PULLUP in the pinMode()s to activate the built in pullup resistors as you do for some inputs.

As it is, with inputs floating at an uncertain voltage then all bets are off.