Output control Timming (problems)

#include <SPI.h>
#include <Controllino.h>
int counter = 0;
int prev_val = 0;
int st=0;
int sw =0;
int sig = 0;
int timer =0;
void setup() {
Serial.begin(9600);
pinMode(CONTROLLINO_A2, INPUT); // SWITCH in
pinMode(CONTROLLINO_D2, OUTPUT); // SWITCH out
pinMode(CONTROLLINO_D5, OUTPUT); // SWITCH LIGHT
pinMode(CONTROLLINO_D3, OUTPUT); // E Valve
pinMode(CONTROLLINO_D7, OUTPUT); // Sl valve
}
void (*resetFunc)(void)=0;
void loop() {
int timer =0;
digitalWrite(CONTROLLINO_D2, HIGH); //button signal
sw = digitalRead(CONTROLLINO_A2); // button signal status
if(sw == HIGH and st==0){
Serial.println("Activated...");
}
if(sw == HIGH){

digitalWrite(CONTROLLINO_D5, HIGH); // button light indicator
digitalWrite(CONTROLLINO_D7, HIGH); // Switch valve powering
st = 1;
delay(1000);
}
if(st == 1){
if(timer==0){
digitalWrite(CONTROLLINO_D3, HIGH);
}
int timer = millis(); // starting timer
int val;

if (timer >3000){ // timer reaching crit value
digitalWrite(CONTROLLINO_D3, LOW);
}

if (timer == 10000){ // timer reaching crit value
st=LOW;
digitalWrite(CONTROLLINO_D5, LOW);
digitalWrite(CONTROLLINO_D7, LOW);
}

if (timer > 15000){ resetFunc();} // system reset
}
}

I wrote above code for 2 solenoid valve and 1 switch button system. When u press system button 1st valve is on for 16 sec and other only for 3 secs. There is delay between 1st valve and 2nd valve opening time. I dont know why but my code either doesnt closes valves or have time calculation errors. Could you please help me out please. Any SW code improvements or suggestions would be appreciated.

Please just clarify what's supposed to happen... I think (but not 100% sure) that you want both solenoids to activate when the button is pressed, but they must de-activate respectively 3 and 16 seconds later?

The short answer to any problem where timing's not working as expected hoped and the code has loads of delay()s, is to read for example UKHelibob on millis() and/or Robin2's "many things" tutorial as well perhaps dougp on state machines.

Sorry if it is confusing :slight_smile:

Button Pressed:
Sol 1 Activated
Delay 1 sec
Sol 2 Activated
Timer
When timer is more than 3 sec close Sol 2
When timer more than 15 sec close sol 1
restart system

See if this code is what you need. (Except I didn't bother with the system reset, I have no idea why you want to do that and suspect it's unnecessary.) The serial output below shows you can press the button again once the cycle finishes: it's a state machine that cycles through the states of Waiting, Sol1 only, Sol1 and Sol2, Sol1 only (again) and back to Waiting. The serial output confirms how long the solenoids are on.

This whole thing is delay()-less: led13 should pulse nicely the whole time ala blink without delay.

Waiting for button @ 188
Solenoid 1 on @ 1051
   Solenoid 2 on @ 2051
   Solenoid 2 off @ 5051, was on for 3000
Solenoid 1 off @ 17051, was on for 16000
 
Waiting for button @ 17052
Solenoid 1 on @ 26371
   Solenoid 2 on @ 27371
   Solenoid 2 off @ 30371, was on for 3000
Solenoid 1 off @ 42371, was on for 16000
 
Waiting for button @ 42372
Solenoid 1 on @ 72189
   Solenoid 2 on @ 73189
   Solenoid 2 off @ 76189, was on for 3000
Solenoid 1 off @ 88189, was on for 16000
// forum 639092
//has a proofOfLife pulse on 13 to prove there's no blocking
// press button, solenoid 1 on
// 1s later solenoid 2 starts thats time=0
// t+3 solenoid2 off
// t+15 solenoid1 off (so 16 total for this one)

// since button takes us out of the only state where we look at it, we don't need edge detect

enum {state_WAITING, state_S1_ONLY_A, state_S1_AND_S2, state_S1_ONLY_B } currentState = state_WAITING;

unsigned long previousPulseMillis;
int pulseInterval = 500;
bool pulseLedState = LOW;
byte pulseLedPin = 13;
bool newlyArrivedInThisState = true;

// this constant won't change:
const int  buttonPin = 3;    // the pin that the pushbutton is attached to
//   the button must be wired from pin to ground, its pinmode is input_pullup
const int solenoid1 = 14;
const int solenoid2 = 16;
const int solenoid1staysOnFor = 15000; //actually on for this + delayBetweenStarts
const int solenoid2staysOnFor = 3000;
const int delayBetweenStarts = 1000;
unsigned long buttonBecamePressedAt; //this is solenoid1 start time
unsigned long solenoid2startedAt;

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(solenoid1, OUTPUT);
  pinMode(solenoid2, OUTPUT);
  Serial.begin(9600);
  Serial.println(".... 2 solenoids 1 button ....");
  Serial.print("Compiler: ");
  Serial.print(__VERSION__);
  Serial.print(", Arduino IDE: ");
  Serial.println(ARDUINO);
  Serial.print("Created: ");
  Serial.print(__TIME__);
  Serial.print(", ");
  Serial.println(__DATE__);
  Serial.println(__FILE__);
  Serial.println("");
  Serial.print("Current state "); Serial.println(currentState);
  Serial.println("Setup done...\n");
}//setup

void loop()
{
  proofOfLife();
  doStates();
}//loop

void proofOfLife()
{
  if (millis() - previousPulseMillis >= pulseInterval)
  {
    pulseLedState = !pulseLedState;
    digitalWrite(pulseLedPin, pulseLedState);
    previousPulseMillis = millis();;
  }
}//proof of life

//state_WAITING, state_S1_ONLY_A, state_S1_AND_S2, state_S1_ONLY_B
void doStates()
{
  switch (currentState)
  {
    case state_WAITING:
      if (newlyArrivedInThisState)
      {
        Serial.print("Waiting for button @ ");
        Serial.println(millis());
        newlyArrivedInThisState = false;
      }

      if (!digitalRead(buttonPin))
      {
        newlyArrivedInThisState = true;
        currentState = state_S1_ONLY_A;
      }
      break;

    case state_S1_ONLY_A:
      if (newlyArrivedInThisState)
      {
        Serial.print("Solenoid 1 on @ ");
        buttonBecamePressedAt = millis();
        Serial.println(buttonBecamePressedAt);
        newlyArrivedInThisState = false;
        digitalWrite(solenoid1, HIGH);

      }

      if (millis() - buttonBecamePressedAt >= delayBetweenStarts)
      {
        newlyArrivedInThisState = true;
        currentState = state_S1_AND_S2;
      }

      break;

    case state_S1_AND_S2:
      if (newlyArrivedInThisState)
      {
        Serial.print("   Solenoid 2 on @ ");
        solenoid2startedAt = millis();
        Serial.println(solenoid2startedAt);
        newlyArrivedInThisState = false;
        digitalWrite(solenoid2, HIGH);
      }

      if (millis() - solenoid2startedAt >= solenoid2staysOnFor)
      {
        newlyArrivedInThisState = true;
        currentState = state_S1_ONLY_B;
      }
      break;

    case state_S1_ONLY_B:
      if (newlyArrivedInThisState)
      {
        Serial.print("   Solenoid 2 off @ ");
        Serial.print(millis());
        Serial.print(", was on for ");
        Serial.println(millis()-solenoid2startedAt);
        newlyArrivedInThisState = false;
        digitalWrite(solenoid2, LOW);
      }

      if (millis() - solenoid2startedAt >= solenoid1staysOnFor)
      {
        Serial.print("Solenoid 1 off @ ");
        Serial.print(millis()); 
        Serial.print(", was on for ");
        Serial.println(millis()-buttonBecamePressedAt);
        Serial.println(" ");
        digitalWrite(solenoid1, LOW);   // oops left this out
        newlyArrivedInThisState = true;
        currentState = state_WAITING;
      }

      break;

  }//switch
}//doStates

oops... forgot to actually turn solenoid 1 off, I was too busy checking that the serial output was right!

Add this

digitalWrite(solenoid1, LOW);

... to that last block if you already copied it before I fixed it.

Here's a diagram to go with that code.

Thanks a lot. I will try to implement/understand it now. :slight_smile:

You need something like this..

Write a class that acts like that and use 3 instances of it.

-jim lee