Button and LED (Measuring the Time between presses)

dear community,

i have tried to do the following:
i have added a button for the digital input.
i have also added a led for the output.
currently if i press on my board the button, the led goes on until i stay on the button.
now i have added a counter. i see now how much i have pressed the button.
i need to find out the time between the last and current presses.

i have tried it with

int timeA = 0;
int timeNeeded = 0;

here on my loop:

if(timeA==0)
{
timeA = millis();
}

if(timeNeeded==0)
{
timeNeeded = timeA-millis();
}

// here i doe a output to a display
// print -> timeNeeded

timeNeeded = 0;
timeA=0;

so now i think it should work, but i dont know...
for the first 10-20 presses, the time is correct.
then the time is not correct (between the presses).

can anybody tell me how i can do this?

in this case:
if i press on 00:00:00 the button and the next i press on 00:00:05,
then i need the "last time taken" 5000 millis.

if i press on 00:00:00 the button and the next i press on 00:00:12,
then i need the "last time taken" 12000 millis.

need this for calculation for the following.

if i press now all 10 seconds the button, then i must calculate this / 8.
in this case i get 1,25 per cycle.

now the led should blink 8 times in this time. and then if the next push is there,
the script should auto calculate the next 8 cycle (from the readed "last time taken").

can anybody helps me how i can do this on the best way?

thank you very much,

many greets

Hi, welcome to the forum. Please have a look at How to use the forum. Especially the part about code-tags and posting all your code (or a MCVE). Also, we’re not as picky on syntax as the compiler but we certainly do like sentences starting with a capital instead of a new line…

Okay, sorry so i have now attached my current code at the end of my post.

i need the following function:
i have here a display and a button.

so i think at the beginning of the script, all seems working fine.
but there is an error.

my needings:
if i press now all 1 second the button, then my display should give me out:
TPR (time per round): that means; if i have pressed first the button, then the next button press will be calculated whats the time difference between the two presses. then this value should be divided throw 8. that means; if i have now 1 difference for 5 seconds, then i must get the PREIght value from 625 millis.

now my goal is that if i do the presses on customize times, that on each button press the time per round and then the time per round / 8 will be new calculated.

i have now no buzzer, but the program should then works exact so:

  1. i press the first time button
  2. i press the 2nd time button
    2.1 the program calculates the time for 1 to 2 button presses
    2.2 the prgoramm caluclates now from this time in point 2.1 (divide / 8) the exact millis
    3.1 the program now should do a buzzer for the exact calulated time for the 8 millis.
  3. then if the button will pressed again, then the new time per round and divide / 8 should be calculated.

the led functionality is not the problem, but i think i have a problem withe millis and calculations.
anything is going wrong here. can anybody tells me where is my failure in my script?
for the first time all is working fine, but if the time between the presses will over 1 second, then the whole calculations are not correct. if i press then the button very fast, i get TPR from about 10000 millis, …

can anybody helps me?

thank you very much

here my code:

#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

int buttonPin = 3;
int check = 0;

int timeA = 0;
int timePR = 0;
int timePREight = 0;

void setup() {
  lcd.begin(16, 2);
  lcd.print("TPR     TPR/8");

  pinMode(buttonPin, INPUT_PULLUP);  
}

void loop() {

  if (digitalRead(buttonPin) == LOW)
  {
    check = 1;
  }  
  if (digitalRead(buttonPin) == HIGH && check==1)
  {

    if(timeA==0)
    {
      timeA=millis();
      timePREight=0;
    }
    else
    {
      timePR=millis()-timeA;
      timePREight=(millis()-timeA)/8;
      timeA=0;
    }
    
    lcd.setCursor(0, 1);
    lcd.print(timePR);

    lcd.setCursor(8, 1);
    lcd.print(timePREight);

    check=0;
  }
}

I think you might want some of your variables to be unsigned long instead of int. (An int only goes up to 32767.)

Read: Data Types in Arduino - learn.sparkfun.com

Thank you, i have changed this, but i think i have another problem.

the first 10-15 seconds all is fine (the calulation here only for my time per run).
but after this time, the time per run runs over 4000+.

i only need always the time between the last and current presses to the button.

have shortened my code that i can find my problem:

#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

int buttonPin = 3;
int check = 0;

unsigned long timeA;
unsigned long timePR;
unsigned long timePREight;

void setup() {
  lcd.begin(16, 2);
  //lcd.print("TPR     TPR/8");

  pinMode(buttonPin, INPUT_PULLUP); 

  timeA=0;
  timePR=0;
  timePREight=0;
}

void loop() {

  if (digitalRead(buttonPin) == LOW)
  {
    check = 1;
  } 
  if (digitalRead(buttonPin) == HIGH && check==1)
  {
    if(timeA==0)
    {
      lcd.setCursor(0, 0);
      lcd.print("Empty");  
      timeA=millis();
    }
    else
    {
      lcd.setCursor(0, 0);
      lcd.print("nEmpty");
      lcd.setCursor(8, 0);
      lcd.print(timeA);
      timePR=millis()-timeA;
      lcd.setCursor(9, 1);
      lcd.print(timePR);
      timeA=millis();
      timePR=0;
    }
    check=0;
  }
}

can you help me?

thank you very much

So now, i have tried this code:

#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

int buttonPin = 3;
int check = 0;

unsigned long timeA;
unsigned long timeLast;
unsigned long sum;

void setup() {
  lcd.begin(16, 2);
  pinMode(buttonPin, INPUT_PULLUP); 
  timeLast=millis();
}

void loop() {

  if (digitalRead(buttonPin) == LOW)
  {
    check = 1;
  } 
  if (digitalRead(buttonPin) == HIGH && check==1)
  {
    timeA=millis();

    lcd.setCursor(0, 0);
    lcd.print(timeA);

    lcd.setCursor(0, 1);
    lcd.print(timeLast);

    sum = timeA - timeLast;

    lcd.setCursor(8, 1);
    lcd.print(sum);

    timeLast=millis();    
    check=0;
  }
}

In my Example, the first Line (timeA) = 19808
The 2nd Line (timeLast) i have here 19334.

so now and the right “sum” i get 4094. but WHY?

if i now do a 19808-19334, i get (in my windows calculator): 474.
but why i get here on the sum 4094?

can anybody helpe me? what i do wrong?

thank you

have now tried with addition.
this worked fine. but why my substraction does not work? :frowning:

iceget:
So now, i have tried this code:

#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

int buttonPin = 3;
int check = 0;

unsigned long timeA;
unsigned long timeLast;
unsigned long sum;

void setup() {
  lcd.begin(16, 2);
  pinMode(buttonPin, INPUT_PULLUP);
  timeLast=millis();
}

void loop() {

if (digitalRead(buttonPin) == LOW)
  {
    check = 1;
  }
  if (digitalRead(buttonPin) == HIGH && check==1)
  {
    timeA=millis();

lcd.setCursor(0, 0);
    lcd.print(timeA);

lcd.setCursor(0, 1);
    lcd.print(timeLast);

sum = timeA - timeLast;

lcd.setCursor(8, 1);
    lcd.print(sum);

timeLast=millis();   
    check=0;
  }
}




In my Example, the first Line (timeA) = 19808
The 2nd Line (timeLast) i have here 19334.

so now and the right "sum" i get 4094. but WHY?

if i now do a 19808-19334, i get (in my windows calculator): 474.
but why i get here on the sum 4094?

can anybody helpe me? what i do wrong?

thank you

iceget:
if i now do a 19808-19334, i get (in my windows calculator): 474.
but why i get here on the sum 4094?

can anybody helpe me? what i do wrong?

Maybe it will help if you erase the old number before writing a new number.
Like this:

    lcd.setCursor(8, 1);
    lcd.print("       "); // erase the old value of "sum" from the display
    lcd.setCursor(8, 1);
    lcd.print(sum); // write the new value of "sum"

I don’t know why you get the results you do but when I run your code on my Arduino UNO the math works out fine. The digits left over from previous results will need to be erased, as odometer said, but the first few digits should be correct.

Because of the PULLUP resistor the pin will read HIGH when not connected and LOW when connected to Ground. That means you should probably act on a change from HIGH to LOW instead of LOW to HIGH.

Because mechanical contacts are notorious for bouncing (closing and opening several times in a few milliseconds) it is good to add ‘debounce’ to your button code. This ignores any changes that happen within a short time of the first one. In my case I chose 10 milliseconds.

Here is the code with a few changes to make it more reliable. I like to use an initial capital letter on the names of global variables so I can more easily tell globals from locals. I use the ‘static’ keyword on local variables if I want them to keep their value between function calls. Local variables are safer to use because, unlike globals, they can’t be changed by code outside the function.

#include <LiquidCrystal.h>


// LiquidCrystal lcd(8, 9, 4, 5, 6, 7);  // My LCD shield uses this different pin layout
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);


const byte ButtonPin = 3;


unsigned long TimeLast;


void setup()
{
  lcd.begin(16, 2);
  pinMode(ButtonPin, INPUT_PULLUP);
  TimeLast = millis();
}


void loop()
{
  unsigned long currentMillis = millis();
  static boolean buttonWasPressed = false;
  static unsigned long lastButtonChangeMillis = 0;
  
  boolean buttonIsPressed = digitalRead(ButtonPin) == LOW;  // LOW means Pressed


  // Detect button change
  // DEBOUNCE:  Ignore state changes if the button has not been in the current state
  //            for at least 10 milliseconds.
  if (buttonIsPressed != buttonWasPressed && currentMillis - lastButtonChangeMillis > 10)
  {
    // Button just changed
    buttonWasPressed = buttonIsPressed;
    lastButtonChangeMillis = currentMillis;  // Start debounce timer


    if (buttonIsPressed)
    {
      // Button pressed
      lcd.setCursor(0, 0);
      lcd.print(currentMillis);


      lcd.setCursor(0, 1);
      lcd.print(TimeLast);


      unsigned long interval = currentMillis - TimeLast;


      lcd.setCursor(8, 1);
      lcd.print("       "); // erase the old value of "interval" from the display


      lcd.setCursor(8, 1);
      lcd.print(interval);


      TimeLast = currentMillis;
    }
  }
}

Thank you! i have tried all, and my solution was: set the timeLast from int to float. now all working fine. thank you very much!

my solution was: set the timeLast from int to float.

That "solution" makes no sense at all.

millis() returns an unsigned long, so when you do

  TimeLast = millis();

or

TimeLast = currentMillis;

and TimeLast is a float what do you expect it to be set to ?