Water pump with timing on button press

Hello , I would appreciate some help , i have been trying for 2 weeks . :crazy_face: :star_struck:

this principal is simple

  1. pressing a button call the peristaltic pump to dose ML based on time (1137 millis = 1 ml of water)
  2. the button activate a simple millis timer . - so far so good

now when im pressing the button , im not getting a consistent real timing. (one press will count 1 sec and the other will count 2 sec for example)
i was checking the outcome with serial and it seems that the right millis is printed and beginning of the function as well as at the end .
i guess i need to reset or flag something some where ?
i was trying every thing , apparently not all of them =)

i was trying to reset the elapsed time to millis every time im pressing the button ,but it didn't work

thank you allot for helping

//------i2c buttons--------

#define SCL 8
#define SDO 9
byte Key;

byte Read_TTP229_Keypad(void)
{
  byte Num;
  byte Key_State = 0;
  for (Num = 1; Num <= 16; Num++)
  {
    digitalWrite(SCL, LOW);
    if (!digitalRead(SDO))
      Key_State = Num;
    digitalWrite(SCL, HIGH);
  }
  return Key_State;
}


boolean count1 = false;

unsigned long startMillis;  //some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long period = 3000;  //the value is a number of milliseconds

void setup()  {

  pinMode(SCL, OUTPUT);
  pinMode(SDO, INPUT);
  Serial.begin(9600);  //start Serial in case we need to print debugging info

  startMillis = millis();  //initial start time

}

void loop() {


  Key = Read_TTP229_Keypad();

  if (Key == 1) {
    Serial.println("press key 1 ");
    count1 = true;
  }



  if (count1 == true)  {

    currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
    Serial.println(millis());
    if (currentMillis - startMillis >= period)  {
      Serial.print("currentMillis "); Serial.println(currentMillis);
      Serial.print("    startMillis ");   Serial.println(startMillis);
      startMillis = currentMillis;  //IMPORTANT to save the start time of the current LED state.
      count1 = false;
    }

  }
}




1 Like

Thankyou for using code tags in your first post!

But your code is still a little difficult to follow. Could you please perform Auto-Format it (Tools menu in IDE) and either re-post or edit original post? Thanks!

I suspect you need your code to do what is known as "state change detection" which is just a fancy way of saying "has a button just changed from not being pressed to being pressed" as opposed to "is a button pressed now" which is what your code is currently doing.

To do this, you just need another variable, maybe called "previousKey" which gets updated just before the end of loop(). Then you can test for the state change using "if (previousKey == 0 && Key == 1)".

Arduino state change detection.

State change detection of active low switches.

Thank you Paul , this auto format is awesome (post the formatted code) .
i was trying this solution before , it didn't worked .

the main problem is the millis counter . when im pressing the button lets say now

im getting 3 sec .

if i press after a few second or what ever , the counter count only 1 or something........ seconds and not the full 3 second that it suppose to count .

the Millis counter not consistent at all !

( i think this code will be useful for black jack but i need to count spinning time for water pump )
what am i doing wrong ?

Hello
What do you expect?

Hi paul .

i expect to press the button what ever i want and get 3 seconds .

not much :sweat_smile:

and what you get ?

random counting

I will now look for my glasbowl see what are the reasons.

untested
but by adding a flag to prevent the timer from re-starting, the timer will run for the duration set
It would have to time out before allowing additional time to be added

//------i2c buttons--------

#define SCL 8
#define SDO 9
byte Key;

byte Read_TTP229_Keypad(void)
{
  byte Num;
  byte Key_State = 0;
  for (Num = 1; Num <= 16; Num++)
  {
    digitalWrite(SCL, LOW);
    if (!digitalRead(SDO))
      Key_State = Num;
    digitalWrite(SCL, HIGH);
  }
  return Key_State;
}


boolean count1 = false;

unsigned long startMillis;  //some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long period = 3000;  //the value is a number of milliseconds


void setup()  {

  pinMode(SCL, OUTPUT);
  pinMode(SDO, INPUT);
  Serial.begin(9600);  //start Serial in case we need to print debugging info

  startMillis = millis();  //initial start time

}

// global variables
unsigned long   elapsedMillis ;
int timer_running ;  // change to boolean or byte if desired
timer_running = 0 ;  // set value

void loop() {


  Key = Read_TTP229_Keypad();

  if (Key == 1) {
    Serial.println("press key 1 ");
    count1 = true;
  }


  if (timer_running) == 0 {  // timer is not running
    if (count1 == true)  {    // the start signal is received
      startMillis = millis() ;   // load the start time once
      timer_running = 1;   // prevent timer from restarting mid timing.
    }}


  if (timer_running == 1) {
    elapsedMillis = millis() - startMillis; // continuously check elapsed time

    if (elapsedMillis <= period)  {
      pumpstatis = 0 ; // sets output for pump running
    }

    if (elapsedMillis >= period) {
      pumpstatis = 1 ;  //  sets output for pump off
      Serial.print("elapsed Millis = "); Serial.println(elapsedmillis);  // print duration of timer event
      count1 = false; // allows for a new start input
      timer_running = 0;  // allows for the timer function to start again
    }

  } // ======= END  if timer_running==1  ==========

//  digitalWrite(pump, pumpstatis ); // need to define output

}  // ========= END LOOP =========

It will not work if you do not try it in the correct way.

I think you now have 3 flags here, count1, timer_running and pumpstatis, when only 1 flag is needed?

if we are trying to reduce code, then things like timenow = millis() is redundant, eliminate another variable.

one of the variations of BWD is to get a value of duration
then use that in an if() statement.
and yes, this could be considered unnecessary as well. but the OP want to print the duration so it will be needed.

one flag is needed to isolate new inputs from the running of the timing loop.
that is the major required change and it has to be separate from count1, our it would have to isolate the intput to prevent new inputs while timing.

I think if the user wants to get 3 periods, , so sets the cout1, 3 separate times, they could pass this into the timing loop. that prevents using only 1 flag.

if count1 were an int
count1 * period ; ( plus some additional code)
would allow increments of period.

also, I don't like to put digitalWrite in the logic section if I can avoid it.
rather have the program break into inputs, logic, outputs.
so pumpstatis passes a value from the logic section to the output section.

=======

so, adding one if() line and one end bracket could do it easier ?

void loop() {
  Key = Read_TTP229_Keypad();

  if (count1 == false) {  //  prevents key presses from effecting timing 
    if (Key == 1) {
      Serial.println("press key 1 ");
      count1 = true;
    }
  }

gentlemens bet there is much more code we have not seen ?

based on the existing code, there area a couple other flaws.

Not handling the startmillis properly is a major problem in the OP's sketch.
should be loaded only once after the keypress.

why ask for a keypress with the keypress change ? I'm not sure of that bit at all.

paul , dave ... thank you guys for your time

im sorry for the previous post .
i didn't understand that the flag needed was for the timer .
i was trying a button state instead .

so with this kind of timers , i need to know how to constrain the miilis time start with a flag .
i thought that the count1 ==1 , was a sufficient for this task .

thank you for help and explanation the code is working perfectly .

First Question is "what code"

I think the biggest problem was that startmillis was not set at the same time as the button.

yes sir that was the main problem

i read some where that 1024 millis will count 1 second . should i consider this number in my calculation ? or the processor round this numbers for me ?
for example
3000 = 3 sec or 3072 = 3 sec

thank you

here is the final code for the pump

//------i2c buttons--------

#define SCL 8
#define SDO 9
byte Key;

byte Read_TTP229_Keypad(void)
{
  byte Num;
  byte Key_State = 0;
  for (Num = 1; Num <= 16; Num++)
  {
    digitalWrite(SCL, LOW);
    if (!digitalRead(SDO))
      Key_State = Num;
    digitalWrite(SCL, HIGH);
  }
  return Key_State;
}


unsigned long startMillisA;  //some global variables available anywhere in the program
const unsigned long periodA = 11470;  //the value is a number of milliseconds
unsigned long elapsedMillisA = 0;
boolean timer_runningA = 0 ;  // set value
long ML_printA = 0;   /// print out ml count

int pumpstate = 0;
int counterA = 4;


void setup()  {
  Serial.begin(9600);  //start Serial in case we need to print debugging info
  delay(10);
  pinMode(SCL, OUTPUT);
  pinMode(SDO, INPUT);



  long ML_printA = 0;
  startMillisA = millis();  //initial start time
  elapsedMillisA = 0;
  timer_runningA = 0 ;  // set value

  ML_printA = dosingML_printA(elapsedMillisA);  /// call function

}


void loop() {

  pumptest();

  Key = Read_TTP229_Keypad();
  if ((Key == 1) && (timer_runningA == 0)) {  // timer is not running
    Serial.println(Key);
    if (Key == 1)  {    // the start signal is received
      startMillisA = millis() ;   // load the start time once
      timer_runningA = 1;   // prevent timer from restarting mid timing.



    }
  }
}
void pumptest() {   // function millis for water pump counting time timer

  if (timer_runningA == 1) {

    elapsedMillisA = millis() - startMillisA; // continuously check elapsed time

    ML_printA = dosingML_printA(elapsedMillisA);
    Serial.print(ML_printA); Serial.println("Ml");

    if (elapsedMillisA <= periodA)  {
      pumpstate = 1 ; // sets output for pump running
    }

    else if (elapsedMillisA >= periodA) {
      pumpstate = 0;  //  sets output for pump off
      timer_runningA = 0;  // allows for the timer function to start again
    }

  }
}

long dosingML_printA(long elapsedMillisA) {  ///<function for counting 1 ml per 1132 millis step
  long MLsec_MillisA = 0;
  long ONEsecforMLA = 1132;
  MLsec_MillisA = elapsedMillisA / 1132;

  return MLsec_MillisA;
}

Millis() counts in 1,000 of a second.

Analog input reads 0 to 1024

Totally different

6000 = six seconds exactly