Code getting stuck / hung up. Please help

Hi all, I’m a complete noob and although I’m getting somewhere and slowly learning I have ran into a couple of problems that many many hours of looking and trying to find an answer hasn’t solved. My project is to use and Arduino to fill a container with RO/DI water after first running a timed flush and purge cycle. My problem is that is constantly getting hung up at the end of the 1st count down (I have used short times just for the trial, but these will be longer) and not moving onto the next case even. I am also getting the same issue at the end of the count up.

Here is my code (apologies this is my very first attempt at coding)

//-----LIBRARIES-----
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
//#include <Time.h>
//#include <TimeLib.h>


//-----Defines-----
#define I2C_ADDR    0x3F
#define BACKLIGHT_PIN 3
#define En_pin  2
#define Rw_pin  1
#define Rs_pin  0
#define D4_pin  4
#define D5_pin  5
#define D6_pin  6
#define D7_pin  7
//Define all the command states
#define ON 0
#define Ready 1
#define Flush 2
#define Purge 3
#define Fill 4
#define Complete 5

LiquidCrystal_I2C  lcd(I2C_ADDR, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin);   //Name lcd pins


//-----CONSTANTS----- (wont change)

const int Startswitch = 2;
const int Levelsensor = 11;
const int Resetbutton = 12;

const int WinRelay = 3;
const int WasteRelay = 4;
const int FlushRelay = 5;
const int FillRelay = 6;

const int PowerLED = 7;
const int FlushLED = 9;
const int FinishLED = 8;
const int PurgeLED = 10;



//------VARIABLES----- (will change)
int Startbuttonstate = digitalRead(Startswitch);
int Levelsensorstate = digitalRead(Levelsensor);
int Resetbuttonstate = digitalRead(Resetbutton);

int commandState = ON; //0=ON, 1=Ready, 2=Flush, 3=Purge, 4=Fill, 5=Complete

int Flushhours = 0; // Flush duration hours
int Flushminutes = 0; // Flush duration min
int Flushseconds = 20; // Flush duration seconds

int Purgehours = 0; // Purge duration hours
int Purgeminutes = 0; // Purge duration min
int Purgeseconds = 10; // Purge duration seconds

int Fillhours = 0; // Fill duration hours
int Fillminutes = 0; // Fill duration min
int Fillseconds = 0; // Fill duration seconds


//=====


void setup() {

  lcd.begin (16, 2);
  lcd.setBacklightPin(BACKLIGHT_PIN, POSITIVE);
  lcd.setBacklight(HIGH);
  lcd.home ();
  Serial.begin(9600);                   //start serial connection
  delay(100);                           //short delay
  pinMode(Startswitch, INPUT_PULLUP);   //configure pin 2 as an input and enable the internal pull-up resistor
  pinMode(Levelsensor, INPUT_PULLUP);   //configure pin 11 as an input and enable the internal pull-up resistor
  pinMode(Resetbutton, INPUT_PULLUP);   //configure pin 12 as an input and enable the internal pull-up resistor

  pinMode(WinRelay, OUTPUT);           //configure outputs
  pinMode(WasteRelay, OUTPUT);
  pinMode(FlushRelay, OUTPUT);
  pinMode(FillRelay, OUTPUT);
  pinMode(PowerLED, OUTPUT);
  pinMode(FinishLED, OUTPUT);
  pinMode(FlushLED, OUTPUT);
  pinMode(PurgeLED, OUTPUT);

}

void loop() {
  int Startbuttonstate = digitalRead(Startswitch);
  //Serial.println(Startbuttonstate);                      //print out the value of the pushbutton
  switch (commandState) {

    //----------------------
    case ON:
      Serial.println(commandState);
      digitalWrite (WasteRelay, LOW);             //waste relay on, solenoid open
      clearLCD();
      for (int ONi = 3; ONi > 0; ONi--) {  //count down from 3
        selectLineOne();
        lcd.print("Elmo Industries");
        selectLineTwo();
        lcd.print("   Hello Dave");
        delay (1000);
      }

      commandState = Ready;
      delay(500);

      break;
    //---------------------
    case Ready:
      Serial.println(commandState);
      digitalWrite (PowerLED, HIGH);

      clearLCD();
      selectLineOne();
      //delay(100);
      lcd.print("Ready to start ");     //Notify user that the system is ready
      selectLineTwo();
      lcd.print("      fill      ");    

      //if (Levelsensorstate == HIGH) {   //check to make sure container is not already filled
      // LevelActivated();                
      // delay(500);                      //blanked out as seems to be tripping even tho switch not made
      //}


      if (Startbuttonstate == HIGH) {    //Wait for start button to be pressed
        commandState = Ready;
        delay(500);

      } else { //if start button is pressed start fill cycle.

        clearLCD();
        selectLineOne();
        delay(100);
        lcd.print("   Starting");
        delay(2000);
        clearLCD();
        commandState = Flush; //Start flush countdown

      }

      break;

    //--------------------------
    case Flush:
      Serial.println(commandState);

      //if (Levelsensorstate == HIGH) {   //check to make sure container is not already filled
      // LevelActivated();                
      // delay(500);                      //blanked out as seems to be tripping even tho switch not made
      //} else
      {

        digitalWrite (WasteRelay, LOW);   //waste relay on, solenoid open
        digitalWrite (FlushRelay, LOW);   //flush relay on, solenoid open
        delay(500);                       //allow time for solenoids to open
        digitalWrite (WinRelay, LOW);     //water in relay on, solenoid open
        Flushcountdown();
        digitalWrite (WinRelay, HIGH);    //water in relay off, solenoid closed
        delay(1000);                      //allow time for pressure to drop
        digitalWrite (FlushRelay, HIGH);  //flush relay off, solenoid closed
        lcd.print("finished flush");
      }

      break;

    case Purge:
      Serial.println(commandState);

      //if (Levelsensorstate == HIGH) {   //check to make sure container is not already filled
      // LevelActivated();                
      // delay(500);                      //blanked out as seems to be tripping even tho switch not made
      //} else
      {

        digitalWrite (WasteRelay, LOW);   //waste relay on, solenoid open
        delay(500);                       //allow time for solenoids to open
        digitalWrite (WinRelay, LOW);     //water in relay on, solenoid open
        Purgecountdown();
        digitalWrite (WinRelay, HIGH);    //water in relay off, solenoid closed
        delay(1000);                      //allow time for pressure to drop

      }

      break;


    case Fill:
      Serial.println(commandState);

      //if (Levelsensorstate == HIGH) {   //check to make sure container is not already filled
      // LevelActivated();                
      // delay(500);                      //blanked out as seems to be tripping even tho switch not made
      //} else
      {

        digitalWrite (FillRelay, LOW);    //fill relay on, solenoid open
        delay(500);                       //allow time for solenoids to open
        digitalWrite (WinRelay, LOW);     //water in relay on, solenoid open
        Fillcountdown();
        digitalWrite (WinRelay, HIGH);    //water in relay off, solenoid closed
        delay(1000);                      //allow time for pressure to drop
        digitalWrite (WasteRelay, LOW);   //waste relay on, solenoid oped
        digitalWrite (FillRelay, HIGH);  //fill relay off, solenoid closed

      }
      break;
  }
}

void Flushcountdown() {

  backlightOn();
  lcd.begin(16, 2);
  lcd.print("FlushingMembrane ");
  delay(150);

  while (Flushhours > 0 || Flushminutes > 0 || Flushseconds >= 0) {

    lcd.setCursor(4, 2);

    (Flushhours < 10) ? lcd.print("0") : NULL;
    lcd.print(Flushhours);
    lcd.print(":");
    (Flushminutes < 10) ? lcd.print("0") : NULL;
    lcd.print(Flushminutes);
    lcd.print(":");
    (Flushseconds < 10) ? lcd.print("0") : NULL;
    lcd.print(Flushseconds);
    lcd.display();
    FlushstepDown();
    delay(1000);
  }
}//close flush countdown();

Code follows on below

void Purgecountdown() {

  backlightOn();
  lcd.begin(16, 2);
  lcd.print("    Purging ");
  delay(150);

  while (Purgehours > 0 || Purgeminutes > 0 || Purgeseconds >= 0) {

    lcd.setCursor(4, 2);

    (Purgehours < 10) ? lcd.print("0") : NULL;
    lcd.print(Purgehours);
    lcd.print(":");
    (Purgeminutes < 10) ? lcd.print("0") : NULL;
    lcd.print(Purgeminutes);
    lcd.print(":");
    (Purgeseconds < 10) ? lcd.print("0") : NULL;
    lcd.print(Purgeseconds);
    lcd.display();
    PurgestepDown();
    commandState = Fill;
    delay(1000);
  }
}//close purge countdown();

void Fillcountdown() {

  backlightOn();
  lcd.begin(16, 2);
  lcd.print("    Filling ");
  delay(150);

  while (Fillhours < 0 || Fillminutes <= 2  || Fillseconds <= 0) {

    lcd.setCursor(4, 2);

    (Fillhours < 10) ? lcd.print("0") : NULL;
    lcd.print(Fillhours);
    lcd.print(":");
    (Fillminutes < 10) ? lcd.print("0") : NULL;
    lcd.print(Fillminutes);
    lcd.print(":");
    (Fillseconds < 10) ? lcd.print("0") : NULL;
    lcd.print(Fillseconds);
    lcd.display();
    FillstepUp();
    commandState = Complete;
    delay(1000);
  }
}// close fill countdown

void FlushstepDown() {
  if (Flushseconds > 0) {
    Flushseconds -= 1;
  } else {
    if (Flushminutes > 0) {
      Flushseconds = 59;
      Flushminutes -= 1;
    } else {
      if (Flushhours > 0) {
        Flushseconds = 59;
        Flushminutes = 59;
        Flushhours -= 1;
      } else {
        clearLCD();                         //GETTING HUNG UP HERE<<<<<<<<<<<<<<<<
        selectLineOne();
        delay(1000);
        lcd.print("flush finished2");
        Serial.print(commandState);
        commandState = Purge;                 //GETTING HUNG UP HERE<<<<<<<<<<<<<<<<<
      }
    }
  }
}

void PurgestepDown() {
  if (Purgeseconds > 0) {
    Purgeseconds -= 1;
  } else {
    if (Purgeminutes > 0) {
      Purgeseconds = 59;
      Purgeminutes -= 1;
    } else {
      if (Purgehours > 0) {
        Purgeseconds = 59;
        Purgeminutes = 59;
        Purgehours -= 1;
      } else {
        commandState = Flush;
      }
    }
  }
}

void FillstepUp() {
  if (Fillseconds <= 58) {
    Fillseconds += 1;
  } else {
    if (Fillminutes <= 58) {
      Fillseconds = 0;
      Fillminutes += 1;
    } else {
      if (Fillhours <= 0) {
        Fillseconds = 0;
        Fillminutes = 0;
        Fillhours += 1;
      } else {
        clearLCD();                         //GETTING HUNG UP HERE<<<<<<<<<<<<<<<<
        selectLineOne();
        delay(1000);
        lcd.print("fill stuck");
        Serial.print(commandState);
        commandState = ON;                 //GETTING HUNG UP HERE<<<<<<<<<<<<<<<<<
      }
    }
  }
}

//close fill countdown();
void LevelActivated() {
  clearLCD();
  selectLineOne();
  delay(100);
  lcd.print("*LEVEL SENSOR*");
  selectLineTwo();
  lcd.print("***TRIGGERED***");
  delay(10000);
  commandState = Complete; //complete fill
  delay(500);
}

void selectLineOne() { //puts the cursor at line 0 char 0.
  lcd.setCursor(1, 0); //position
}
void selectLineTwo() { //puts the cursor at line 0 char 0.
  lcd.setCursor(0, 1); //position
}

void clearLCD() {
  lcd.setCursor(1, 0);
  lcd.clear();
}
void backlightOn() { //turns on the backlight
  lcd.setBacklightPin(BACKLIGHT_PIN, POSITIVE);
  lcd.setBacklight(HIGH);
}
void backlightOff() { //turns off the backlight
  lcd.setBacklightPin(BACKLIGHT_PIN, POSITIVE);
  lcd.setBacklight(LOW);
}

//END of program.

Any help and advice would be greatly appreciated.
Thanks

void Flushcountdown() {
...
  while (Flushhours > 0 || Flushminutes > 0 || Flushseconds >= 0) {
...
    FlushstepDown();
...
  }
}//close flush countdown();
...
void FlushstepDown() {
  if (Flushseconds > 0) {
    Flushseconds -= 1;
  } else {
    if (Flushminutes > 0) {
...
      } else {
        clearLCD();                         //GETTING HUNG UP HERE<<<<<<<<<<<<<<<<
        selectLineOne();
        delay(1000);
        lcd.print("flush finished2");
        Serial.print(commandState);
        commandState = Purge;                 //GETTING HUNG UP HERE<<<<<<<<<<<<<<<<<
      }
    }
  }
}

What do you reckon happens when Flushseconds == 0 ?

arduarn: What do you reckon happens when Flushseconds == 0 ?

I believe that it runs the else code, so: clears the lcd screen selects line 1 waits for 1 second prints "flush finished2" changes the command to purge

I then think that is should goto the purge case.

I then think that is should goto the purge case.

No, because Flushseconds >= 0 will still evaluate to true.

arduarn: No, because Flushseconds >= 0 will still evaluate to true.

so am I right in thinking that if I changed Flushseconds >= 0 to Flushseconds > 0 then that statement would become false at 0 hours, 0 minutes, 0 seconds?

Have tried the above and it still gets stuck in the loop.

Generally speaking - don't attempt to do things like this using separate hours/minutes/seconds variables. Convert these types of value to a serial seconds value - the second over the whole day. The logic becomes much clearer.

PaulMurrayCbr:
Generally speaking - don’t attempt to do things like this using separate hours/minutes/seconds variables. Convert these types of value to a serial seconds value - the second over the whole day. The logic becomes much clearer.

How would i do this? Sorry if that’s a stupid question.

elmo2002: How would i do this? Sorry if that's a stupid question.

total_second = hours * 3600 + minutes * 60 + seconds;

total_second = hours * 3600UL +etc, etc

how would you get these to display as a count down on the lcd? I'm now majorly confused by this all :(

elmo2002: Have tried the above and it still gets stuck in the loop.

Yes, because now you will never match the end condition in FlushstepDown() and so will never set commandState = Purge. A simple fix to the original sketch, which may work for you, is to add Flushseconds -= 1; after the commandState = Purge.

As others have pointed out, you are doing this in a unusual and somewhat complicated way. To be honest, I think you have written too much code before asking for advice, especially if this is your first sketch as you suggest.

You should spend a little time reading the forum stickies, if you haven't already.

Hello elmo2002,

the first thing I notices was that you declare "Startbuttonstate" twice: - once global in the header of your sketch:

...

//------VARIABLES----- (will change)
int Startbuttonstate = digitalRead(Startswitch);
...
  • and once locally inside the "loop()" function:
void loop() {
  int Startbuttonstate = digitalRead(Startswitch);
...

What you are actually using ist the 2nd one, so you can drop the global one. I think it is intended in this case that on each execution of loop() this value gets read. More, you might want to use the "bool" type in this case instead of "int", to express just True/False, or HIGH/LOW .

Then, for variables with positive-going values up to 255 only, you should possibly get used to use "byte" instead of "int". This will save you valuable space as your sketches become more complex.

Personally, instead of writing e.g.

if (Startbuttonstate == HIGH) {
...

... I'd prefer to just do

if (Startbuttonstate) {
...

since this in itself already gives a True/HIGH/1 , or False/LOW/0 value. More or less cosmetic here, but in very time-critical appplications this can save you the time for an extra comparison against HIGH.

Also personally, I would not do such a thing in the global variables setup: ...

//------VARIABLES----- (will change)
int Startbuttonstate = digitalRead(Startswitch);
int Levelsensorstate = digitalRead(Levelsensor);
int Resetbuttonstate = digitalRead(Resetbutton);

but only declare the variables here: ...

//------VARIABLES----- (will change)
// int Startbuttonstate;  // drop this one anyway, see above
bool Levelsensorstate; // changed this to bool type
bool Resetbuttonstate; // changed this to bool type

... and do the "digitalRead()" 's later in the "setup()" (or maybe cyclic in the "loop()" ) section only. Well, my preference only - YMMV ...

BR

stargar

arduarn: A simple fix to the original sketch, which may work for you, is to add Flushseconds -= 1; after the commandState = Purge.

As others have pointed out, you are doing this in a unusual and somewhat complicated way. To be honest, I think you have written too much code before asking for advice, especially if this is your first sketch as you suggest.

You should spend a little time reading the forum stickies, if you haven't already.

The simple fix worked many thanks, its something to get me going. yes this is my first sketch using Arduino so i am learning all the time.

I will have a read through the stickies. Many thanks for your help and advice Arduarn.

Stargar

Thanks for your advice, now that i have a sketch that works, all be it perhaps not the best i now have something that i can adjust and fine tune. I will look at changing / implementing the things you have suggested.

Many thanks for all of your help and advice. It is greatly appreciated.

Thanks Dave