Inadvertently Repeating Code

Hello,

I'm making a plant watering project. I started pretty simple, each plant gets watered for a set amount of time, then two days later the program resets the Nano and it starts over. The problem is that sometimes it leaves relays open, causing double or triple activations of the relays.

Below is a simplified version of my code. Every once in a while the first relay led will blink 3 times instead of once and moving on to the next. The puzzling part is that it only happens maybe 1 out of 10 times. Any suggestions?

int motorPower = 2;
int valve1 = 3;
int valve2 = 4;
int valve3 = 5;
int valve4 = 6;

const long interval1 = 1000;
const long interval2 = interval1+1000;
const long interval3 = interval2+1000;
const long interval4 = interval3+1000;
const long interval5 = interval4+1000;
const long interval6 = interval5+1000;
const long interval7 = interval6+1000;
const long interval8 = interval7+1000;

const long interval9 = 172800000;

boolean valveCheck = false;
boolean motorOn = false;
boolean motorOff = false;
boolean openV1 = false;
boolean closeV1 = false;
boolean openV2 = false;
boolean closeV2 = false;
boolean openV3 = false;
boolean closeV3 = false;
boolean openV4 = false;
boolean closeV4 = false;

void(* resetFunc) (void) = 0;
void setup() {
  pinMode(2, OUTPUT);
  digitalWrite(motorPower, HIGH);
  pinMode(3, OUTPUT);
  digitalWrite(valve1, HIGH);
  pinMode(4, OUTPUT);
  digitalWrite(valve2, HIGH);
  pinMode(5, OUTPUT);
  digitalWrite(valve3, HIGH);
  pinMode(6, OUTPUT); 
  digitalWrite(valve4, HIGH);
}

void loop() {
  // put your main code here, to run repeatedly:
unsigned long currentMillis = millis();
  if (!valveCheck && currentMillis > 500){
    digitalWrite(motorPower, HIGH);
    digitalWrite(valve1, HIGH);
    digitalWrite(valve2, HIGH);
    digitalWrite(valve3, HIGH);
    digitalWrite(valve4, HIGH);
    valveCheck = true;
  }

  //Here is where the inadvertent loop/repeat starts after a 1 second pause
  //valve 1
  if (currentMillis >= interval1 && !openV1 && !closeV1) {
    openV1 = true;
    digitalWrite(motorPower, LOW);
    digitalWrite(valve1, LOW);
  }  
  if (currentMillis >= interval2 && openV1 && !closeV1) {
    openV1 = false;
    closeV1 = true;
    digitalWrite(valve1, HIGH);
  }
  //Here is where the inadvertent loop/repeat ends

  //valve 2
  if (currentMillis >= interval3 && !openV2 && !closeV2) {
    openV2 = true;
    digitalWrite(valve2, LOW);
  }  
  if (currentMillis >= interval4 && openV2 && !closeV2) {
    openV2 = false;
    closeV2 = true;
    digitalWrite(valve2, HIGH);
  }

  //valve 3
  if (currentMillis >= interval5 && !openV3 && !closeV3) {
    openV3 = true;
    digitalWrite(valve3, LOW);
  }  
  if (currentMillis >= interval6 && openV3 && !closeV3) {
    openV3 = false;
    closeV3 = true;
    digitalWrite(valve3, HIGH);
  }  

//valve 4
  if (currentMillis >= interval7 && !openV4 && !closeV4) {
    openV4 = true;
    digitalWrite(valve4, LOW);
  }  
  if (currentMillis >= interval8 && openV4 && !closeV4) {
    openV4 = false;
    closeV4 = true;
    digitalWrite(valve4, HIGH);
    digitalWrite(motorPower, HIGH);
  }  
  
//reset
  if (currentMillis >= interval9) {
    resetFunc();
  }   
}```

Why are you resetting the controller.

Later I will be adding other peripherals to the setup that may need to run async, so I'm using millis() for timing instead of delay(). This will potentially be running for months at a time, and millis() will overflow back to zero in 50 days. If I reset the controller every two days (the timing I need to rewater the plants), I don't need to worry about accounting for the 50 day issue.

The way you are tackling this is wrong.

  • Firstly, you really need to use an RTC for time operations.

  • Secondly, you need the look at the proper use of millis( ) to create non-blocking timing.

  • There is no need to reset your controller.

You should master what is discussed here.

I agree that the way I am tackling this is non-ideal. Eventually it will be hooked up to a Pi, so the timing will be controlled there, and it will be easier to schedule the tasks.

Back to the root question, why would it run the valve 1 actuation code anywhere between 1 and 3 times? The reset isn't until much later, and it doesn't make sense to me that it seems to happen randomly. Also, after it passes valve 1, the rest of the code works fine.

Show us a good schematic of your proposed circuit.
Show us a good image of your ‘actual’ wiring.
Give links to components.

What has that got to do with your project.
Overflow shouldn't be a problem if you do things on a daily or weekly base.

if (millis() - previousMillis >= "a month"); // is not a problem

It keeps working as it should after an overflow.
Leo..

Change const long to const unsigned long.


You may be experiencing resets on the controller caused by circuit switching.

The code is odd but should not behave unpredictably. Forcing a system restart to reset the millis() counter is not normal practice.
More likely the unwanted repetition is due to the switching of the loads causing a brown out.

Schematic:
12V 3A supply to distribution block
12V and grd to relay board from distribution block
5V and grd from relay board to Nano
D2-D6 signals from Nano to relay board for relays 2-6 control
12V from distribution block to relays. When activated via signals they power the valves and pump (motor in code)
Grd from distribution block to each valve

Links:
Nano https://www.amazon.com/dp/B08PZ36KBX?psc=1&ref=ppx_yo2_dt_b_product_details
Relays https://www.amazon.com/dp/B0057OC66U?psc=1&ref=ppx_yo2_dt_b_product_details

It is worth noting that this issue was occurring when it was only the Nano hooked up to the relays with no other equipment hooked up. Being a new member, I am limited in the number of links I can post.

Actual setup:

It all looks very neat. Have all inductive DC loads (motor, relay coils, solenoid valves etc.) got flyback diodes to limit back EMF?

I was looking at that the wrong way I suppose. Rather, I was thinking of:
if (millis() >= previousMillis + interval)

@6v6gt Thanks! My first project like this. No, I hadn't considered that. It will go on the list.

From the Amazon pictures, it looks like the relay board uses uln2803 driver chips. These chips have built in diodes and should be active.

1 Like

Assume your 5V to the Nano goes to the Nano's 5 volt pin ?

Where is the your 5V power supply ?

If those valves are DC they will need kickback diodes.

Yes, 5V from the relay board to the Nano 5V pin. The relay board supplies steady 5V from one of it's pins, as well as an appropriate ground. 6v6gt had mentioned that it looks like the diodes are built into the relay board. All values are DC.

I am sure the relays on the relay board do have kickback diodes.

However, the DC values would need reversed biased kickback diodes too.

With out these diodes, there can be hundreds of volts spikes generated by the valve coils.

These spikes can cause system resetting that you are experiencing.

Alright, I will look into how to make that happen, thanks!

Inexpensive 1N4007 diodes should suffice for these diodes.

I would put the diodes across the valve coils, i.e. solder them to the valve terminals.

OR

Crimp them in the red spade lugs. (they must be properly orientated !)

1 Like

Correct, if coded like that, you will get the rollover problem after 49 days or whatever. But like this if (millis() - previousMillis >= interval) it will be fine.