1

I want to find the timing between HIGH state and LOW state of push button. For that, I made a program. You can see my program below. In my program, I made logic like that when switch is pressed then one variable "currentMillis" store the value of millis() and it store value until button pressed. But whenever I pressed button again then it also add previous value. For example, if button pressed for first time then suppose we got 200ms, now suppose if button pressed second time then we got 500ms and if button pressed third time then we got 1000ms. That mean every time value added. No doubt I made a logic which seem to be perfect but I can't figure out what is problem. Please give me some suggestions.

const int  buttonPin = 2;   

unsigned long currentMillis = 0; 
unsigned long previousMillis = 0;
unsigned long finalMillis = 0;

int buttonPushCounter = 0;

void setup() 
{
   Serial.begin(9600);

   pinMode(buttonPin, INPUT);
   digitalWrite(buttonPin, HIGH);
}

void loop() 
{
  if (digitalRead(buttonPin) == LOW)
  {
    buttonPushCounter++;
    Serial.println("on");
    Serial.print("number of button pushes:  ");
    Serial.println(buttonPushCounter);

    while(digitalRead(buttonPin) == LOW)
    {
      currentMillis = millis();
    }

    finalMillis = currentMillis - previousMillis;  
    Serial.println(finalMillis);

    previousMillis = finalMillis;
    //finalMillis = 0;
  }
}

Here, it is my serial monitor output.

on
number of button pushes:  1
0
on
number of button pushes:  2
775
on
number of button pushes:  3
873
on
number of button pushes:  4
1425
on
number of button pushes:  5
1496
on
number of button pushes:  6
2073
on
number of button pushes:  7
2010
on
number of button pushes:  8
2643
on
number of button pushes:  9
3052
on
number of button pushes:  10
3195
on
number of button pushes:  11
3396
on
number of button pushes:  12
3575
on
number of button pushes:  13
3737
  • TL;DR make sure you keep switch-bounce in mind. – Gerben Jan 10 '17 at 11:05
1

While the previously given answers should work for you, they share a couple of problems with your original code:

  • they do not debounce the button
  • they block while waiting for the button to be released

Blocking the program is not a big deal if you do not have to do anything else. However, chances are you are showing us only a fraction of what will ultimately be a larger program. In this case, doing a busy wait (like while (digitalRead(buttonPin) == LOW) ;) will block the whole program, not only this particular feature. Then, I suggest you get immediately in the habit of writing non blocking code:

  • when the button is pressed, record that fact and the current time
  • when the button is released, report to the user

The important notion is that you never wait for anything. Instead, you check whether something has to be done right now and, if so, you do it.

Here is a non-blocking version of your program, with some debounce added:

const uint8_t button_pin = 2;

void setup()
{
    pinMode(button_pin, INPUT_PULLUP);
    Serial.begin(9600);
}

void loop()
{
    static int last_button_state = HIGH;
    static unsigned int push_count;
    static unsigned long last_press_time;
    int button_state = digitalRead(button_pin);
    unsigned long now = millis();

    // Record when the button is pressed.
    if (last_button_state == HIGH && button_state == LOW) {
        push_count++;
        last_press_time = now;
    }

    // Report when the button is released.
    if (last_button_state == LOW && button_state == HIGH) {
        unsigned long push_duration = now - last_press_time;
        if (push_duration < 10) {  // discard bounce
            push_count--;
        }
        else {
            Serial.print(F("pushes: "));
            Serial.print(push_count);
            Serial.print(F(", duration: "));
            Serial.print(push_duration);
            Serial.println(F(" ms"));
        }
    }

    last_button_state = button_state;
}
  • Thank you for your suggestion. It's works great. Yes, you're right. Previous answers gives me result which I expected but sometimes it's provides garbage value even if I pressed button for same time. – Hasan Jan 11 '17 at 7:12
1

First of all, frarugi87 is right. Second, why not use this:

finalMillis = millis() - previousMillis;
previousMillis = millis();

Instead of what you wrote.

if (digitalRead(buttonPin) == LOW) {
    buttonPushCounter++;
    Serial.println("on");
    Serial.print("number of button pushes:  ");
    Serial.println(buttonPushCounter);
    finalMillis = millis() - previousMillis;
    previousMillis = millis();
    Serial.println(finalMillis);
    while(digitalRead(buttonPin) == LOW){}    
  }

It works great.

Hope it helps.

Yoav

0

You wrote

previousMillis = finalMillis;

This means that you store the duration of the pulse, not the last time it was pressed.

Change it with

previousMillis = currentMillis;

and you will be able to detect the high + low time.

By the way, constantly reading the millis function is useless. You can change your code to

while(digitalRead(buttonPin) == LOW);
currentMillis = millis();

which reads only once.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.