Solenoid controller runs fine for 2days & then goes bad.Using millis() for delay

Hi,

I made a plant watering system using arduino.
There are four outputs.
output1 remains high for 10 seconds and then remains low for 2hrs
output2 remains high for 10 seconds and then remains low for 8hrs
output3 remains high for 10 seconds and then remains low for 12hrs
output4 remains high for 10 seconds and then remains low for 24hrs

This is in a loop, so it should keep happening in an infinite loop.
Idea is that plants get watered periodically.

In addition to this I have a 'debugMode' where I made low time from 2hrs to 10seconds, 8hrs to 70seconds, 12hrs to 110 seconds and 24hrs to 230seconds. This is there to quickly enable checking if the program is fine.

Everything works fine. Except that after about 2 days, something is going wrong and the system pipe which is on, stays ON even after 10 seconds. This is leading to a lot of water wastage.
I re-checked the code multiple times, but cannot see why this is happening.
Please help!!

/*
Water Controller
4 outputs are given out at 2hrs, 8hrs, 12hrs and 24 hr gaps
1 input is to determine if it is in debug mode or not.
In debug mode instead of OFF time being (2hrs - 10s), it will be (20s - 10s).
Similarly instead of (8hrs - 10s), it will be (80s - 10s)
*/

const int NUMOUTPINS = 4;
const int OUTPINS[NUMOUTPINS] = {
5, 6, 7, 8};
const int INPIN = 9;
unsigned long int currMillis;
unsigned long int prevMillis[4];
int pipeStatus[NUMOUTPINS];
const unsigned long int ONTIME = 10000UL;
unsigned long int offTime[4];
int isDbgMode;

// the setup routine runs once when you press reset:
void setup() {
// initialize the digital pin as an output.
for(int i=0 ; i<NUMOUTPINS; i++)
{
pinMode(OUTPINS*, OUTPUT); *
_ pipeStatus* = LOW;_
_
}_
_
pinMode(INPIN, INPUT); _
_
isDbgMode = 0;_
_
for(int i=0 ; i<NUMOUTPINS; i++)_
_
{_
_ prevMillis = 0;
offTime = 0;
}
currMillis = 0;
}
void invertOutPin(int pin){
if(digitalRead(pin) == LOW)
{
digitalWrite(pin, HIGH);
}
else*

* {
digitalWrite(pin, LOW);
}
}
// the loop routine runs over and over again forever:
void loop() {
//read dbg switch status*

* isDbgMode = digitalRead(INPIN);
if(isDbgMode == HIGH)
{
offTime[0] = 10000UL;
offTime[1] = 70000UL;
offTime[2] = 110000UL;
offTime[3] = 230000UL;
}
else {
offTime[0] = 7200000UL; //2hrs : 7200s*

* offTime[1] = 28800000UL; //8hrs : 28800s*
* offTime[2] = 43200000UL; //12hrs: 43200s*
* offTime[3] = 86400000UL; //24hrs: 86400s*
* }
//read current Millis:
currMillis = millis();
//check for overflow:
for(int i=0; i<NUMOUTPINS; i++)
{
prevMillis = (prevMillis > currMillis) ? 0 : prevMillis;
}
for(int i=0; i<NUMOUTPINS; i++)
{
//is pipe ON?
if(pipeStatus == HIGH)
{
if((currMillis - prevMillis) > ONTIME)
{
pipeStatus = LOW; //turn off the pipe*

digitalWrite(OUTPINS*, LOW);
prevMillis = currMillis;
}
}
//else pipe is OFF:
else*

* {
if((currMillis - prevMillis) > offTime)
{
pipeStatus = HIGH; //turn ON the pipe*

digitalWrite(OUTPINS*, HIGH);
prevMillis = currMillis;
}
}
} //for*

}
[/quote]
PS: please note that I tried changing "unsigned long int" to "unsigned long", but the hex files generated in both the cases is the same._

The code that you posted has been mangled by the forum software because you used quote tags instead of code tags. Because the code uses i as an array index in several places the text has been turned into italics and the array index is not visible, which makes the code hard to follow.

Please repost the code in code tags rather than quote tags.

Thanks UKHeliBob. I am posting the code using code tags.

/*
Water Controller
4 outputs are given out at 2hrs, 8hrs, 12hrs and 24 hr gaps
1 input is to determine if it is in debug mode or not. 
In debug mode instead of OFF time being (2hrs - 10s), it will be (20s - 10s). 
Similarly instead of (8hrs - 10s), it will be (80s - 10s)
*/

const int NUMOUTPINS = 4;
const int OUTPINS[NUMOUTPINS] = {
  5, 6, 7, 8};
const int INPIN = 9;
unsigned long int currMillis;
unsigned long int prevMillis[4];
int pipeStatus[NUMOUTPINS];
const unsigned long int ONTIME = 10000UL;
unsigned long int offTime[4];
int isDbgMode;

// the setup routine runs once when you press reset:
void setup() {                
  // initialize the digital pin as an output.
  for(int i=0 ; i<NUMOUTPINS; i++)
  {
    pinMode(OUTPINS[i], OUTPUT);     
    pipeStatus[i] = LOW;
  }
  pinMode(INPIN, INPUT);     
  isDbgMode = 0;
  for(int i=0 ; i<NUMOUTPINS; i++)
  {
    prevMillis[i] = 0;
    offTime[i] = 0;
  }
  currMillis = 0;
}

void invertOutPin(int pin){
  if(digitalRead(pin) == LOW) 
  {
    digitalWrite(pin, HIGH); 
  }
  else
  {
    digitalWrite(pin, LOW); 
  }
}

// the loop routine runs over and over again forever:
void loop() {
  //read dbg switch status
  isDbgMode = digitalRead(INPIN);
  if(isDbgMode == HIGH)
  {
    offTime[0] = 10000UL;
    offTime[1] = 70000UL;
    offTime[2] = 110000UL;
    offTime[3] = 230000UL;
  }
  else {
    offTime[0] =  7200000UL;    //2hrs :  7200s
    offTime[1] = 28800000UL;    //8hrs : 28800s
    offTime[2] = 43200000UL;    //12hrs: 43200s
    offTime[3] = 86400000UL;    //24hrs: 86400s
  }
  //read current Millis:
  currMillis = millis();
  //check for overflow:
  for(int i=0; i<NUMOUTPINS; i++)
  {  
    prevMillis[i] = (prevMillis[i] > currMillis) ? 0 : prevMillis[i];
  } 

  for(int i=0; i<NUMOUTPINS; i++)
  {
    //is pipe ON?
    if(pipeStatus[i] == HIGH) 
    {
      if((currMillis - prevMillis[i]) > ONTIME)
      {
        pipeStatus[i] = LOW; //turn off the pipe
        digitalWrite(OUTPINS[i], LOW);
        prevMillis[i] = currMillis;
      }

    }
    //else pipe is OFF:
    else
    {
      if((currMillis - prevMillis[i]) > offTime[i])
      {
        pipeStatus[i] = HIGH; //turn ON the pipe
        digitalWrite(OUTPINS[i], HIGH);
        prevMillis[i] = currMillis;
      }
    }
  } //for
}

unsigned long int currMillis;
unsigned long int prevMillis[4];

Can that be right?? long and int??

mOskit:
Can that be right?? long and int??

Yes, it can be right.

Slightly OT: All this

  isDbgMode = 0;
  for(int i=0 ; i<NUMOUTPINS; i++)
  {
    prevMillis[i] = 0;
    offTime[i] = 0;
  }
  currMillis = 0;

is pointless; they're already all zero.

  //check for overflow:
  for(int i=0; i<NUMOUTPINS; i++)
  {  
    prevMillis[i] = (prevMillis[i] > currMillis) ? 0 : prevMillis[i];
  }

...is not necessary. Remove it.

"Coding Badly", AWOL and mOskit : thanks for replying. Though some of the code might be redundant, it can't be the reason for the failure I am seeing after the system is up for a couple of days, right?

Show us the circuit. Solenoids always scream "back EMF" to me.

AWOL, The diode across Solenoid is IN4007.

Please note that the dotted lines indicate wires.
And 'X' indicates a screw that is connected to the pin. And through this screw a wire can be connected. Hope I've made this clear..

nagarajn:
And 'X' indicates a screw that is connected to the pin. And through this screw a wire can be connected. Hope I've made this clear..

Your "toggle switch" toggles the signal to the Arduino between "5V" and "GND", correct?

You don't toggle the signal between "5V" and "not connected", or do you?

The toggle switch circuit looks a bit strange to me, normally I'd use a switch and a pull-resistor (or pinMode "INPUT_PULLUP" in the sketch) to toggle a signal.

How long is the wire from the Arduino controller to the toggle switch?

This might not be very professional answer but you can reset the entire board in software say after 24h if after 48 hours your program start to wiggle.

hardware/software combination

Why don't you get your sketch to tell you what it is doing, instead of inferring what it is doing from its output? (Partial, uncompiled, untested)

  currMillis = millis();

  for(int i = 0; i < NUMOUTPINS; i++)
  {
    if(pipeStatus[i] == HIGH) 
    {
      if((currMillis - prevMillis[i]) >= ONTIME)
      {
        updateState (i, LOW);
      }
    }
    else
    {
      if((currMillis - prevMillis[i]) >= offTime[i])
      {
        updateState (i, HIGH);
      }
    }
    digitalWrite(OUTPINS[i], pipeStatus[i]);
  }
}

void updateState (byte pin, byte state)
{
  pipeStatus[pin] = state;
  prevMillis[pin] = currMillis;
  
  Serial.print (currMillis);
  Serial.print (" pin ");
  Serial.print (pipeStatus[pin]);
  Serial.println (pipeStatus [pin] ? " HIGH" : " LOW);
}

nagarajn:
Though some of the code might be redundant, it can't be the reason for the failure I am seeing after the system is up for a couple of days, right?

Maybe.

Regardless: less code = less bugs; less code = easier to evaluate; small bugs are distracting; bugs can have unexpected side-effects.

Fix the problems that have been mentioned, post the updated version, and then we'll work on specific symptoms.

@jurs:

jurs:
Your "toggle switch" toggles the signal to the Arduino between "5V" and "GND", correct?

You don't toggle the signal between "5V" and "not connected", or do you?

It toggles between 5V and Gnd. BUT, for a brief moment when I am toggling from 5V to Gnd (or vice versa) it will be "not connected". Hope this is not a problem.

jurs:
The toggle switch circuit looks a bit strange to me, normally I'd use a switch and a pull-resistor (or pinMode "INPUT_PULLUP" in the sketch) to toggle a signal.

How long is the wire from the Arduino controller to the toggle switch?

This wire is very short. Less than 10cm.
There are two very long wires, about 8 meters each. These wires are used to connect the solenoid to the circuit. I am doing this because solenoid is on roof top and the PCB is in my room. So, I need a long wire.

Hi, what I don't see in your circuit diagram are bypass capacitiors, particularly on the ATMEGA 8.

Can you include your power supplies in the diagram and a picture of your project so we can see how you have configured the GND connections.

Thanks.. Tom...... :slight_smile:

for a brief moment when I am toggling from 5V to Gnd (or vice versa) it will be "not connected".

If you used a pullup or pulldown resistor it would always be HIGH or LOW and you should consider using one. It is particularly easy to use INPUT_PULLUP in the pinMode() command to do this.

mOskit, thanks for the idea.
AWOL: I have to keep my system ON for two days? Sounds a little difficult to do.
Coding Badly: I agree with you and will post the modified code if required. It might not be required because it could not be a programming issue at all.

Here is what I am seeing:

  1. When the failure was seen (ie., solenoid just continued to remain ON indefinitely), the system was using OUTPIN[2], i.e., offtime of 12 hours and On time of 10 seconds.

  2. In debugMOde=1, the OUTPIN[2] should produce a pulse whose offtime is 110 seconds and On time is 10 seconds. Now, after resetting even this mode is not working fine. (ie., solenoid remains high for more than 10 seconds!!) . But, OUTPIN[0] , OUTPIN[1] and OUTPIN[3] are all working fine.
    Could the pin have been damaged?

  3. Next I started using OUTPIN[1] in debugMode=0. But even this failed after a couple of days.
    And now I am seeing that only OUTPIN[0] and OUTPIN[3] are working fine in debugMode = 1.

  4. If you see the circuit diagram, I have an option to connect the output signal to an LED or a solenoid. When LED is driven instead of solenoid ALL four OUTPIN[] are working fine.

Hope I have explained it clearly.
What am I missing? TIA

nagarajn:
@jurs:
It toggles between 5V and Gnd. BUT, for a brief moment when I am toggling from 5V to Gnd (or vice versa) it will be "not connected". Hope this is not a problem.

This could only be a problem (button state "flloating") during the actual switching action.

If the button is not switched while the problems begin, no problem.

nagarajn:
This wire is very short. Less than 10cm.

Very good, no problem then.

I can see no hardware problem then.

So most likely a problem with your software switching logic.

Could you please post the code again?
But this time include the code in "code tags" and not in "quote tags"?

The code from your initial message is not compiling, because it is ruined in some lines, because you didn't use "code tags" for posting code. "Quote tags" are for quoting text messages, and "code tags" are for posting code.

Hi jurs, thanks for replying.
I have already posted the code in code tags. Please see the 3rd post in this chain.
The toggle switch was not being operated when the failure happened.

TomGeorge:
Hi, what I don't see in your circuit diagram are bypass capacitiors, particularly on the ATMEGA 8.

Can you include your power supplies in the diagram and a picture of your project so we can see how you have configured the GND connections.

Thanks.. Tom...... :slight_smile:

Tom, I am not using capacitors anywhere.
Here's how my PCB looks:(not sure how much it will help)


The big screw+bolt is an improvised heat sink for the voltage regulator.

Where do I need to use bypass capacitors ?

For power supply I am using a 12V/1A supply. This is connected to a LM1085 regulator which converts 12V to 5V and is used to power ATMEGA8.
Hope this was clear.