Relay timer not switching off

I am developing code for a relay timer, with and LCD screen and reset switch. I have the timer, LCD screen and the reset all functioning correctly. However the output to the relay doesn't seem to work. It sets high at the startup as expected, but then doesn't go low.

I am sure the answer is obvious, but I can't seem to find it. Any help would be appreciated.

// include the library code:
#include <Wire.h>
#include <Adafruit_RGBLCDShield.h>
#include <utility/Adafruit_MCP23017.h>

#include<CountUpDownTimer.h>

CountUpDownTimer T(DOWN);
CountUpDownTimer T2(DOWN);

// The shield uses the I2C SCL and SDA pins. On classic Arduinos
// this is Analog 4 and 5 so you can't use those for analogRead() anymore
// However, you can connect other I2C sensors to the I2C bus and share
// the I2C bus.
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();

// These #defines make it easy to set the backlight color
#define RED 0x1
#define YELLOW 0x3
#define GREEN 0x2
#define TEAL 0x6
#define BLUE 0x4
#define VIOLET 0x5
#define WHITE 0x7

long previousMillis = 0;        // will store last time RO was flushed
long previousMillis2 = 0;
long interval = 3580000;           // interval at which to Flush (milliseconds)
long flushtime = 120000;          // set flush time to 2 mins
boolean reset = false;

int pin_out = 3;           // Output to Relay

void setup() {
  // Debugging output
  Serial.begin(9600);
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);

  pinMode(pin_out, OUTPUT);     //set pin as output.
  //digitalWrite(pin_out, LOW);    // Open valve
  reset = true;                 // intialise system and startup flush cycle
  
  T.SetTimer(0,58,0);
  T.StartTimer();

  T2.SetTimer(0,2,0);
  T2.StartTimer();
}

uint8_t i = 0;
void loop() {
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  unsigned long currentMillis = millis();
  T.Timer(); // Interval timer
  T2.Timer(); // Flush timer    
  
  if (reset == false){
    lcd.setCursor(0, 0);
    lcd.print("Next Flush ");
    if (T.TimeHasChanged() ) // this prevents the time from being constantly shown.
    {
      lcd.setCursor(11, 0);
      lcd.print(T.ShowMinutes());
      lcd.print(":");
      lcd.print(T.ShowSeconds());
    }
  }

/* Debug for Relay */
lcd.setCursor(0, 1);
lcd.print("Relay State ");
lcd.print(digitalRead(pin_out));
 
  uint8_t buttons = lcd.readButtons();

  if (buttons) {
    lcd.clear();
    lcd.setCursor(0, 0);
    if (buttons & BUTTON_SELECT) {
      reset = true;
      T2.ResetTimer();
      previousMillis = currentMillis;    // reset the flush timer
    }
  }

  if (currentMillis - previousMillis >= interval) {
    reset = true;
    lcd.clear();
    T2.ResetTimer();
    previousMillis = currentMillis;    // reset the flush timer
  }

  if (reset == true) {
    digitalWrite(pin_out, HIGH);    // Open valve
    lcd.setBacklight(RED);
    lcd.setCursor(0, 0);
    lcd.print("Flushing RO");
    lcd.setCursor(12, 0);
      if (T2.TimeHasChanged() ) // this prevents the time from being constantly shown.
      {
         lcd.print(T2.ShowMinutes());
         lcd.print(":");
         lcd.print(T2.ShowSeconds());
      }
  }

  if ((reset == true) && (currentMillis - previousMillis >= flushtime)) {
    reset = false;
    T.ResetTimer();
    previousMillis = currentMillis;    // reset the flush timer
    digitalWrite(pin_out, LOW);          // Close valve
    lcd.clear();
    lcd.setBacklight(BLUE);
  }

}

The print on serial also shows it staying high?

Then it looks like

  if ((reset == true) && (currentMillis - previousMillis >= flushtime))

Is never getting true... Add

  Serial.print("Reset= ");
  Serial.println((reset ? "true" : "false"));
  Serial.print("Interval over? ");
  Serial.println(((currentMillis - previousMillis >= flushtime) ? "true" : "false"));

And see.

And why is currentMillis nicely a unsigned type and previousMillis not?

I will try that and see, I was assuming it was getting true as the other parts of the code in those if statements execute as expected. IE the screen changes color and the timer resets.

While you're at it, have some spare time to answer the questions?

OK so I tried that. And it does change state. Reset changes from true to false after the standard interval. And the interval over also switched from false to true for one moment.

Still waiting for the other answers...

Sorry, for some reason I couldn't post again, the forum would not let me.

The serial also shows it as high.

The difference in the unsigned long vs long. No idea. Have changed all of those to unsigned long.

Using 1 long and 1 as unsinged long will give you errors over time.

If serial shows it high all the time, that's weird. Never low?

Only thing I can think of is that it's set high again. And the only place it's set high is on line 97.

Can you try the following code? I commented that part out

// include the library code:
#include <Wire.h>
#include <Adafruit_RGBLCDShield.h>
#include <utility/Adafruit_MCP23017.h>

#include<CountUpDownTimer.h>

CountUpDownTimer T(DOWN);
CountUpDownTimer T2(DOWN);

// The shield uses the I2C SCL and SDA pins. On classic Arduinos
// this is Analog 4 and 5 so you can't use those for analogRead() anymore
// However, you can connect other I2C sensors to the I2C bus and share
// the I2C bus.
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();

// These #defines make it easy to set the backlight color
#define RED 0x1
#define YELLOW 0x3
#define GREEN 0x2
#define TEAL 0x6
#define BLUE 0x4
#define VIOLET 0x5
#define WHITE 0x7

unsigned long previousMillis = 0;        // will store last time RO was flushed
unsigned long previousMillis2 = 0;
long interval = 3580000;           // interval at which to Flush (milliseconds)
long flushtime = 120000;          // set flush time to 2 mins
boolean reset = false;

int pin_out = 3;           // Output to Relay

void setup() {
  // Debugging output
  Serial.begin(9600);
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);

  pinMode(pin_out, OUTPUT);     //set pin as output.
  digitalWrite(pin_out, HIGH);  //init it here
  reset = true;                 // intialise system and startup flush cycle
  
  T.SetTimer(0,58,0);
  T.StartTimer();

  T2.SetTimer(0,2,0);
  T2.StartTimer();
}

uint8_t i = 0;
void loop() {
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  unsigned long currentMillis = millis();
  T.Timer(); // Interval timer
  T2.Timer(); // Flush timer    
  
  if (reset == false){
    lcd.setCursor(0, 0);
    lcd.print("Next Flush ");
    if (T.TimeHasChanged() ) // this prevents the time from being constantly shown.
    {
      lcd.setCursor(11, 0);
      lcd.print(T.ShowMinutes());
      lcd.print(":");
      lcd.print(T.ShowSeconds());
    }
  }

/* Debug for Relay */
lcd.setCursor(0, 1);
lcd.print("Relay State ");
lcd.print(digitalRead(pin_out));
 
  uint8_t buttons = lcd.readButtons();

  if (buttons) {
    lcd.clear();
    lcd.setCursor(0, 0);
    if (buttons & BUTTON_SELECT) {
      reset = true;
      T2.ResetTimer();
      previousMillis = currentMillis;    // reset the flush timer
    }
  }

  if (currentMillis - previousMillis >= interval) {
    reset = true;
    lcd.clear();
    T2.ResetTimer();
    previousMillis = currentMillis;    // reset the flush timer
  }

  if (reset == true) {
    //for testing, i will not reset it
    //digitalWrite(pin_out, HIGH);    // Open valve
    lcd.setBacklight(RED);
    lcd.setCursor(0, 0);
    lcd.print("Flushing RO");
    lcd.setCursor(12, 0);
      if (T2.TimeHasChanged() ) // this prevents the time from being constantly shown.
      {
         lcd.print(T2.ShowMinutes());
         lcd.print(":");
         lcd.print(T2.ShowSeconds());
      }
  }

  if ((reset == true) && (currentMillis - previousMillis >= flushtime)) {
    reset = false;
    T.ResetTimer();
    previousMillis = currentMillis;    // reset the flush timer
    digitalWrite(pin_out, LOW);          // Close valve
    lcd.clear();
    lcd.setBacklight(BLUE);
  }

}

Ok, that doesn't change anything. I put the code for the serial monitor in, and again it runs as before. However The moment I close the serial monitor it starts ficking the relay on and off every few seconds.

Mm, that doesn't make sens... The code now has NO point in loop() to set the output high... Only in setup(). So how can it flicker?

z4zacharia:
I put the code for the serial monitor in

Wait, what code?

Can you make a video of it?

Okay, I did a test and I can't see anything weird. Because I have no LCD or RGB stuff I did a quick edit:

// include the library code:
#include <Wire.h>
//#include <Adafruit_RGBLCDShield.h>
//#include <utility/Adafruit_MCP23017.h>

#include<CountUpDownTimer.h>

CountUpDownTimer T(DOWN);
CountUpDownTimer T2(DOWN);

// The shield uses the I2C SCL and SDA pins. On classic Arduinos
// this is Analog 4 and 5 so you can't use those for analogRead() anymore
// However, you can connect other I2C sensors to the I2C bus and share
// the I2C bus.
//Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();

// These #defines make it easy to set the backlight color
#define RED 0x1
#define YELLOW 0x3
#define GREEN 0x2
#define TEAL 0x6
#define BLUE 0x4
#define VIOLET 0x5
#define WHITE 0x7

unsigned long previousMillis = 0;        // will store last time RO was flushed
unsigned long previousMillis2 = 0;
long interval = 3580000;           // interval at which to Flush (milliseconds)
long flushtime = 120000;          // set flush time to 2 mins
boolean reset = false;

int pin_out = 13;           // Output to Relay

void setup() {
  // Debugging output
  Serial.begin(115200);
  // set up the LCD's number of columns and rows:
  //lcd.begin(16, 2);

  pinMode(pin_out, OUTPUT);     //set pin as output.
  digitalWrite(pin_out, HIGH);  //init it here
  reset = true;                 // intialise system and startup flush cycle

  T.SetTimer(0, 58, 0);
  T.StartTimer();

  T2.SetTimer(0, 2, 0);
  T2.StartTimer();

  pinMode(10, INPUT_PULLUP);
}


void loop() {
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  unsigned long currentMillis = millis();
  T.Timer(); // Interval timer
  T2.Timer(); // Flush timer

  if (reset == false) {
    //lcd.setCursor(0, 0);
    Serial.println("Next Flush ");
    if (T.TimeHasChanged() ) // this prevents the time from being constantly shown.
    {
      //lcd.setCursor(11, 0);
      Serial.print(T.ShowMinutes());
      Serial.print(":");
      Serial.println(T.ShowSeconds());
    }
  }

  /* Debug for Relay */
  //lcd.setCursor(0, 1);
  Serial.print("Relay State ");
  Serial.println(digitalRead(pin_out));
  if (!digitalRead(pin_out)) {
    Serial.println("WHEEEEEEEEEEEEEEEEEEEEEEEEE");
  }

  uint8_t buttons = digitalRead(10);

  if (true) {
    //lcd.clear();
    //lcd.setCursor(0, 0);
    if (!buttons) {
      reset = true;
      T2.ResetTimer();
      previousMillis = currentMillis;    // reset the flush timer
    }
  }

  if (currentMillis - previousMillis >= interval) {
    reset = true;
    //lcd.clear();
    T2.ResetTimer();
    previousMillis = currentMillis;    // reset the flush timer
  }

  if (reset == true) {
    //for testing, i will not reset it
    //digitalWrite(pin_out, HIGH);    // Open valve
    
    
    //lcd.setBacklight(RED);
    //lcd.setCursor(0, 0);
    Serial.println("Flushing RO");
    //lcd.setCursor(12, 0);
    if (T2.TimeHasChanged() ) // this prevents the time from being constantly shown.
    {
      Serial.print(T2.ShowMinutes());
      Serial.print(":");
      Serial.println(T2.ShowSeconds());
    }
  }

  if ((reset == true) && (currentMillis - previousMillis >= flushtime)) {
    reset = false;
    T.ResetTimer();
    previousMillis = currentMillis;    // reset the flush timer
    digitalWrite(pin_out, LOW);          // Close valve
    //lcd.clear();
    //lcd.setBacklight(BLUE);
  }

  delay(500);

}

This will print everything to serial.

But now I notice some details in the code. Why only use the timer to display the time? And have a matching millis interval? You can do both with the same timer object. Just check for T.TimeCheck(0,0,0).

But like I said, after the two minutes have passed the output is switched off just fine...