[solved]Problems programing button to keep a solenoidvalve open a specified time

Hi.
Early this year I bought my first Arduino. Before that I have never programmed anything in my life but I’m usually a quick learner. However, now I’m stuck!

I’ve been working for about amonth with a project to build a filler station for Bag in Box.
It’s supposed to work like this:
*On/off button (momentary button that turns a LED on or off)
If its OFF you can do the following:
*push “Fill Tank” button and force open the inlet valve (SV1) as long as the button is pressed
*push “Fill Bib” button and force open the outlet valve (SV2) as long as the button is pressed
If it’s ON you can do the following:

*push “Fill Tank”, 1: LedFillTankOn turns ON
2: SV1 opens
3:LedFillTank turns on if SV1 is open
When the level reaches “LevelMax” it turns off SV1 and LedFillTank until the level sinks below the sensor. It’s supposed to keep filling untill I push On/Off button again. This part works fine.

*push “FillBib”
If LedFillTankOn is on and LevelMin(shown by “LedReadyBib”) is on:
SV2 will open for a specified time, the close and wait for new button push.

The “FillBib” part is where I got stuck. I’m not able to get a timer working here. I can’t use “Delay” because then it wont know if the tank gets full and overflows.
I’ve tried a couple of different types of timers, mostly with “millis” but I’m probably to stupid to get it working after a buttonpush.

In the code attached everything is written and working down to the timer part. The last line in the code is when “LeadReadyBib” is on and the “FillBib” button is pushed. Here I need to have the timer.

If you managed to reed all the way here I would much appreciate some help. I will gladly answer any followup questions you have.

Sorry for grammar errors, English is just my second language…:wink:
/Samuel

int state = LOW;      // the current state of the output pin
int reading;           // the current reading from the input pin
int previous = HIGH;    // the previous reading from the input pin
long time = 0;         // the last time the output pin was toggled
long debounce = 200;   // the debounce time, increase if the output flickers


int onoffState = 0;
int filltankState = 0;
int fillbibState = 0;
int levelmaxState = 0;
int levelminState = 0;
int ledonState = 0;
int ledfilltankState = 0;
int ledfillbibState = 0;
int sv1State = 0;
int sv2State = 0;
int ledfilltankonState = 0;
int ledreadybibState = 0;


const int OnOff = 1;
const int FillTank = 2;
const int FillBib = 3;
const int LevelMax = 4;
const int LevelMin = 5;
const int LedOn = 7;
const int LedFillTank = 8;
const int LedFillBib = 9;
const int SV1 = 10;
const int SV2 = 11;
const int LedFillTankOn = 12;
const int LedReadyBib = 13;

void setup() {
  pinMode (OnOff , INPUT); //on-off, through optocoupler, want's LOW
  pinMode (FillTank , INPUT); //Fill Tank, through optocoupler, want's LOW
  pinMode (FillBib , INPUT); //fill Bag in Box, through optocoupler, want's LOW
  pinMode (LevelMax , INPUT); //Levelsensor MAX, through optocoupler, want's LOW
  pinMode (LevelMin , INPUT); //Levelsensor MIN, through optocoupler, want's LOW
  pinMode (LedOn , OUTPUT); // LED ON/OFF
  pinMode (LedFillTank , OUTPUT); //LED, indicates SV1 is open
  pinMode (LedFillBib , OUTPUT); //LED, indicates SV2 is open
  pinMode (SV1 , OUTPUT); // SolenoidValve 1, inlett
  pinMode (SV2 , OUTPUT); // SolenoidValve 2, outlett
  pinMode (LedFillTankOn , OUTPUT); // LED, indicates Fill Tank cycle is active
  pinMode (LedReadyBib , OUTPUT); //LED, indicates Tank is full enough for a Bag in Box

}
void loop() {
  // Momentary button to turn LedOn On and OFF
  { reading = digitalRead(OnOff);
    if (reading == LOW && previous == HIGH && millis() - time > debounce) {
      if (state == LOW)
        state = HIGH;
      else
        state = LOW;
      time = millis();
    }
    digitalWrite(LedOn, state);
    previous = reading;
    if (ledonState == LOW) {
      digitalWrite(LedFillTankOn, LOW);
    }
  }

  //Force open SV1, works when LedOn is turned off
  ledonState = digitalRead(LedOn);
  filltankState = digitalRead(FillTank);
  if (ledonState == LOW) {
    if (filltankState == LOW) {
      digitalWrite(SV1, HIGH);
      digitalWrite(LedFillTank, HIGH);
    }
    else {
      digitalWrite(SV1, LOW);
      digitalWrite(LedFillTank , LOW);
    }
  }

  //Force open SV2, works when LedOn is turned off
  ledonState = digitalRead(LedOn);
  fillbibState = digitalRead(FillBib);
  if (ledonState == LOW) {
    if (fillbibState == LOW) {
      digitalWrite(SV2, HIGH);
      digitalWrite(LedFillBib, HIGH);
    }
    else {
      digitalWrite(SV2, LOW);
      digitalWrite(LedFillBib, LOW);
    }
  }

  //Fill Tank
  ledonState = digitalRead(LedOn);
  sv2State = digitalRead(SV2);
  filltankState = digitalRead(FillTank);
  levelmaxState = digitalRead(LevelMax);
  ledfilltankonState = digitalRead(LedFillTankOn);
  { if (ledonState == HIGH && sv2State == LOW && filltankState == LOW && levelmaxState == HIGH)
    { digitalWrite(LedFillTankOn, HIGH);
      digitalWrite(SV1, HIGH);
      digitalWrite(LedFillTank, HIGH);
    }
    else if (ledonState == HIGH && filltankState == HIGH && levelmaxState == LOW && ledfilltankonState == HIGH)
    { digitalWrite(LedFillTankOn, HIGH);
      digitalWrite(SV1, LOW);
      digitalWrite(LedFillTank, LOW);
    }
    else if (ledonState == HIGH && filltankState == HIGH && levelmaxState == HIGH && ledfilltankonState == HIGH)
    { digitalWrite(LedFillTankOn, HIGH);
      digitalWrite(SV1, HIGH);
      digitalWrite(LedFillTank, HIGH);
    }
  }

  //Fill Bag in Box
  ledonState = digitalRead(LedOn);
  ledfilltankonState = digitalRead(LedFillTankOn);
  levelminState = digitalRead(LevelMin);
  fillbibState = digitalRead(FillBib);
  ledreadybibState = digitalRead(LedReadyBib);
  { if (ledonState == HIGH && ledfilltankonState == HIGH
        && levelminState == HIGH)
    {
      digitalWrite(LedReadyBib, HIGH);
    }
    else if (ledonState == HIGH && ledfilltankonState == HIGH
             && levelminState == LOW)
    {
      digitalWrite(LedReadyBib, LOW);
    }
  }
  fillbibState = digitalRead(FillBib);
  ledreadybibState = digitalRead(LedReadyBib);

  if (ledreadybibState == HIGH && fillbibState == LOW) {


  }

}

drawing bib filler.jpg

The "FillBib" part is where I got stuck. I'm not able to get a timer working here. I can't use "Delay" because then it wont know if the tank gets full and overflows.

Forget about the Arduino, for a moment. Explain how YOU would operate a device of unknown flow rate to fill a container of unknown quantity. I seriously doubt that it will involve your watch at all.

   pinMode (OnOff ,INPUT);//on-off, through optocoupler, want's LOW
   pinMode (FillTank ,INPUT);//Fill Tank, through optocoupler, want's LOW
   pinMode (FillBib ,INPUT);//fill Bag in Box, through optocoupler, want's LOW
   pinMode (LevelMax ,INPUT);//Levelsensor MAX, through optocoupler, want's LOW
   pinMode (LevelMin ,INPUT);//Levelsensor MIN, through optocoupler, want's LOW

I don't understand these comments. What does what an optocoupler wants have to do with what the state of the pin is?

  {reading = digitalRead(OnOff);
  if (reading == LOW && previous == HIGH && millis() - time > debounce) {
  if (state == LOW)
  state = HIGH;
  else

What is that open curly brace there for?

Why does all of your code start in column one?

Proper indentation makes for much more readable code. Tools + Auto Format makes doing proper indentation trivial.

If I understand correctly you can have a while loop that executes when the filling begins and stops when the specified amount of time has elapsed. Inside the while loop you can check for overflow and, if it has occurred, stop the filling and break out of the while loop.

  fillbibState = digitalRead(FillBib);
  ledreadybibState = digitalRead(LedReadyBib);

  unsigned long timeToFill = 5000;  // stay open this long or until full

  if (ledreadybibState == HIGH && fillbibState == LOW){

    // start filling

    unsigned long startTime = millis();

    // wait for specified time or until full  
    while( millis() <= (millis() - startTime) )
    {
      // if overflow
      if( )
      {
        // stop filling

        // exit early
        break;

      }

    }

  }

PaulS: Forget about the Arduino, for a moment. Explain how YOU would operate a device of unknown flow rate to fill a container of unknown quantity. I seriously doubt that it will involve your watch at all.

   pinMode (OnOff ,INPUT);//on-off, through optocoupler, want's LOW
   pinMode (FillTank ,INPUT);//Fill Tank, through optocoupler, want's LOW
   pinMode (FillBib ,INPUT);//fill Bag in Box, through optocoupler, want's LOW
   pinMode (LevelMax ,INPUT);//Levelsensor MAX, through optocoupler, want's LOW
   pinMode (LevelMin ,INPUT);//Levelsensor MIN, through optocoupler, want's LOW

I don't understand these comments. What does what an optocoupler wants have to do with what the state of the pin is?

  {reading = digitalRead(OnOff);
  if (reading == LOW && previous == HIGH && millis() - time > debounce) {
  if (state == LOW)
  state = HIGH;
  else

What is that open curly brace there for?

Why does all of your code start in column one?

Proper indentation makes for much more readable code. Tools + Auto Format makes doing proper indentation trivial.

Thanks for Reply! I've modified the code with auto format so it will be easier to read.

About the optocoupler and what signal it want's it mostly for my self to remember that the optocupler gives a LOW when a button is pushed. Also I thought it would be more understandable for you...Maybe not. I'm still learning this.

I want the Tank to fill continuously and it is not supposed to be affected by the filling of Bag in box. The levelMax is to stop the tank form overflowing and has nothing to do with the Bag in box filling.

When LevelMin is on it means there is enough liquid to fill a Bib (short for Bag in box) and then I can push FillBib button and it will open SV2 for the amount of time I've calculated it takes for 3 liters of liquid to flow through the pipes and into the Bib. With enough flow into the tank this means I can keep filling Bib without any waiting.

The open curly brace is ended after "time = millis();", three rows below your quote.

[quote author=Blue Eyes link=msg=3110287 date=1485887823] If I understand correctly you can have a while loop that executes when the filling begins and stops when the specified amount of time has elapsed. Inside the while loop you can check for overflow and, if it has occurred, stop the filling and break out of the while loop. [/quote]

I think you got me wrong, I hope my explanation in this post was clearer. :)

Thanks again /Samuel

About the optocoupler and what signal it want’s it mostly for my self to remember that the optocupler gives a LOW when a button is pushed. Also I thought it would be more understandable for you…Maybe not. I’m still learning this.

What is does is important. What it wants is not.

The open curly brace is ended after “time = millis();”, three rows below your quote.

{That} {is} {not} {what} {matters} {.} {What} {matters} {is} {that} {the} {open} {curly} {brace} (and matching close brace) {are} {not} {needed}.

That they are there simply illustrates that you do not know what you are doing. I try hard to minimize things that show that I do not know what I am doing. 8)

I want the Tank to fill continuously

So, it doesn’t matter that you’ve pumped 300 gallons into a 5 gallon bucket?

Ok, the optocoupler doesn't "want" a low signal, it "gives" one. That is what i meant but it probably got lost in translation. However I really don't think it's relevant for the rest of the code.

PaulS: What is does is important. What it wants is not. {That} {is} {not} {what} {matters} {.} {What} {matters} {is} {that} {the} {open} {curly} {brace} (and matching close brace) {are} {not} {needed}.

That they are there simply illustrates that you do not know what you are doing. I try hard to minimize things that show that I do not know what I am doing. 8)

Thanks for enlightening me! I really didn't know this. This part of the code was copied almost as was from an example I found. And because it didn't generate an error I left it there.

As I said before, I'm really a beginner at this but none the less, quite proud how much I've achieved in less than a month. Feel free to give me some credit for that...;)

PaulS: So, it doesn't matter that you've pumped 300 gallons into a 5 gallon bucket?

That's what LevelMax is needed for. If the liquid hits that sensor it closes SV1 (inlet) and keeps it closed until the level is below LevelMax. This part of the code also works as intended, even though probably could been written in another, easier way. This is what I'm capable of coding and as long as it works it's ok with me. The more I learn the smother the code.

Additional fact: At the moment the filler isn't completed with the actual valves and sensors. I've ordered everything from China but shippingtime is a bi**h. However everything is rigged upp on a breadboard with optocoupler, buttons and LEDs. /Samuel

Feel free to give me some credit for that.

I pushed your Karma button. 8) Better than pushing your hot button.

That's what LevelMax is needed for. If the liquid hits that sensor it closes SV1 (inlet) and keeps it closed until the level is below LevelMax.

Do you need to be able to do other things while the container is filling? If not,

   digitalWrite(SV1, HIGH); // Or LOW if that is what turn the pump on
   while(digitalRead(LevelMax) == LOW) // while the tank is not full
   {
      // Do nothing
   }
   // Tank is full

I've ordered everything from China but shippingtime is a bi**h.

That's what you get for ordering during the Chinese New Year celebration time. Which goes on for a very long time by American standards.

PaulS:
I pushed your Karma button. 8) Better than pushing your hot button.
Do you need to be able to do other things while the container is filling? If not,

Thanks for not being an a**hole.
As I said, I know almost nothing about programing and for everything I learn or get working I realize there is even more things to learn. Lucky me, I have got a lot of spare time during school…

The FillTank part is supposed to operate “on it’s own”, at least not affected by the fill Bib part. Only thing that will interupt the FillTank part is the main On/Off button (if you don’t count the LevelMax sensor)

PaulS:
That’s what you get for ordering during the Chinese New Year celebration time. Which goes on for a very long time by American standards.

I actually ordered most of my part as early as the first week in January, but the delivery time to Sweden is between 3 and 6 weeks. Some parts has started to arrive but not enough to start build the real thing.
Some of the pipes i ordered just before the Chinese New Year and they were shipped before the holiday.
Even without the pipes I can build all the electrical and make shure it works.
I should have all the parts needed before February ends.

/Samuel

It works!
I searched around today and found a thread here where someone asked about using a button to controll a “blink without delay”.
In that thread i found this example made by a user called “drone”:

unsigned int debounceTime = 100;
unsigned long          onTime = 5000;


...


void loop() {

  static bool                     ledOn = false;
  static unsigned long buttonTm = 0;
  static unsigned long      ledTm = 0;

    // always debounce your inputs, but debouncing uses a different time counter
    // than your LED on, necessarily, as you want to be able to press the button
    // more than once every on period

  if( digitalRead(buttonPin) == HIGH && millis() - buttonTm > debounceTime ) {

    buttonTm = millis();

    if( ledOn ) {
        // LED is already on, turn it off
      digitalWrite(LEDPin, LOW);
      ledOn = false;
    }
    else {
       // LED is not on, turn it on
      digitalWrite(LEDPin, HIGH);
      ledOn = true;
      ledTm = millis();
   }
}

if( ledOn == true && millis() - ledTm >= onTime ) {
     // LED has been on long enough to turn off automatically
   digitalWrite(LEDPin, LOW);
   ledOn = false;
}
}

I modified it slightly to fit my program and i ended up whit this:

//for the Timer
unsigned int debounceTime = 100;
unsigned long          onTime = 10000;
static bool                     ledOn = true;
static unsigned long buttonTm = 0;
static unsigned long      ledTm = 0;

...

//Force open SV1, works when LedOn is turned off
    filltankState = digitalRead(FillTank);

    if (filltankState == LOW) {
      digitalWrite(SV1, HIGH);
      digitalWrite(LedFillTank, HIGH);
    }
    else {
      digitalWrite(SV1, LOW);
      digitalWrite(LedFillTank , LOW);
    }
  

  //Force open SV2, works when LedOn is turned off

  fillbibState = digitalRead(FillBib);

  if (fillbibState == LOW) {
    digitalWrite(SV2, HIGH);
    digitalWrite(LedFillBib, HIGH);
  }
  else {
    digitalWrite(SV2, LOW);
    digitalWrite(LedFillBib, LOW);
  }

I attached the programfile if someone want’s to look at it. It has got a slight remake since yesterday and everything works almost as planned. I’m constantly modifying it when I learn more about programming.

Thanks again for your help!

/Samuel

bag_in_box_filler.ino (5.57 KB)