Debounce Problem

Hi,

  • I’m new in programming Arduino Boards, this is my first Nano board that I connected with MG 966R Servo Motor. I have wrote code for controlling position with 2 momentary buttons. Now I need to add Debouncing but I cant find the way. I tried on many different ways but nothing works.

There is a code:

#include <EEPROM.h>
#include <Servo.h>

Servo RearServo;
const byte RearUpPin = 3;
const byte RearDownPin = 4;
byte CurrRearUpButtonState = LOW;
byte PrevRearUpButtonState = LOW;
byte CurrRearDownButtonState = LOW;
byte PrevRearDownButtonState = LOW;
int RearServoPosition = EEPROM.read(0);
int RearStepIncrement = 20;

void setup()
{
  pinMode(RearUpPin, INPUT);
  RearServo.attach(2);
  RearServo.write(RearServoPosition);
  Serial.begin(9600);
}

void loop()
{
  CurrRearUpButtonState = digitalRead(RearUpPin);
    
  if(CurrRearUpButtonState != PrevRearUpButtonState && CurrRearUpButtonState == HIGH && RearServoPosition <= 180) {
    RearServoPosition += RearStepIncrement;
    RearServo.write(RearServoPosition);
    delay(10);
    EEPROM.update(0, RearServoPosition);
  }
  PrevRearUpButtonState = CurrRearUpButtonState;

  CurrRearDownButtonState = digitalRead(RearDownPin);
  
  if(CurrRearDownButtonState != PrevRearDownButtonState && CurrRearDownButtonState == HIGH && RearServoPosition >= 0)
  {
    RearServoPosition -= RearStepIncrement;
    RearServo.write(RearServoPosition);
    delay(10);
    EEPROM.update(0, RearServoPosition);
  }
  PrevRearDownButtonState = CurrRearDownButtonState;
}

You forgot to set the pinMode() on the second button.

You are not using INPUT_PULLUP so did you forget to put a pull-up or pull-down resistor on the input pins?

See the example: File->Examples->02.Digital->Debounce

Thanks, I set INPUT mode for second pin. Yes, I added 1K ressistor between ground and input pin. I tried to implement code from tutorial but it didn't worked :(

I wrote this code, but nothing happens with motor when I push button. DebounceCheck variable gets grather than 500 but IF Statement that compares DebounceCheck and other parameters don't work. It works without comparing DebounceCheck...

#include 
#include 

Servo RearServo;
const byte RearUpPin = 3;
const byte RearDownPin = 4;
byte CurrRearUpButtonState = LOW;
byte PrevRearUpButtonState = LOW;
byte CurrRearDownButtonState = LOW;
byte PrevRearDownButtonState = LOW;
int RearServoPosition = EEPROM.read(0);
int RearStepIncrement = 20;
int DebounceCheck;
int LastDebounceTime;
int DebounceInterval = 500;

void setup()
{
  pinMode(RearUpPin, INPUT);
  pinMode(RearDownPin, INPUT);
  RearServo.attach(2);
  RearServo.write(RearServoPosition);
  Serial.begin(9600);
}

void loop()
{
  CurrRearUpButtonState = digitalRead(RearUpPin);

  if(CurrRearUpButtonState != HIGH) {
    LastDebounceTime = millis();
  }

  DebounceCheck = millis() - LastDebounceTime;

  Serial.print(DebounceCheck);
  Serial.print("\n");

  if(CurrRearUpButtonState != PrevRearUpButtonState && DebounceCheck >= DebounceInterval && CurrRearUpButtonState == HIGH && RearServoPosition <= 180)  {
    RearServoPosition += RearStepIncrement;
    RearServo.write(RearServoPosition);
    delay(10);
    EEPROM.update(0, RearServoPosition);
  }  
  PrevRearUpButtonState = CurrRearUpButtonState;
}

Here is a really nice button library that will take care of it for you: https://github.com/JChristensen/Button --- bill

Have a look at the demo Several Things at a Time. It just uses millis() to arrange a short interval between successive reads of the button and that is sufficient to eliminate bounce problems.

...R

I can't get it working. I don't have enought experience :( i =f someon can help me how to make my code working.

Viruss: Thanks, I set INPUT mode for second pin. Yes, I added 1K ressistor between ground and input pin. I tried to implement code from tutorial but it didn't worked :(

That's a pull down resistor. Use a 10K between the pin and Vcc. Then run a wire from the side of the button that is not attached to the pin, to the ground.

You can skip the whole resistor thing if, in pinMode, you specify INPUT_PULLUP instead of just INPUT. So it will be like: pin --> button --> gnd. Then digitalRead(pin) will be HIGH if the button is open (not pressed), and LOW if pressed (closed).

The code you've presented is pretty good ... looks like you've already gained a good amount of experience. You may have jumped to far ahead with your code and neglected some debugging along the way.

I haven't used a servo motor before, so you're ahead of me on that aspect. I don't think debouncing is the main problem at this point, however it needs to be dealt with. A few comments and questions:

What did you want the RearServoPosition value to do when you press the up or down button? a) Increment or decrement the RearServoPosition value just once for each press. b) Continuously increment or decrement the RearServoPosition value every 10ms "while" the button is pressed. c) Other.

The RearServoPosition is assigned an int data type. This has a range -32,768 to 32,767 on an AVR. In your code from the first post, you're only checking if >=0 or if <=180. If the value gets outside of this range, nothing happens.

I'm new in Arduino World, but I have experience in PHP programming that have almost same syntax.

I want to make: 1. By pressing button on D3 motor must move for 20 deegres forward and stop until next release and pressing, not continuosly moving while button is pressed. 2. By pressing button on D4 motor must move for 20 deegres backward.

Why I have >=0 and <=180? - Because my Servo can move only 180 degrees, there is no way for value to go outside 0 - 180 because step is 20 deegres and 9 steps per 20 deegres are equal to 180.

There is no way to change circuit by changing ressistor. First of all, all is fixed and mounted and if I touch something I will destoy something else. Second if I decide to touch circuit I can't find 10K resisor that I can install...

Now, I only want to prevent bouncing. Also i want to notice that bouncing is not continiously, it isn't happens often but i need protection...

Thanks a lot, and sorry about my English, I'm from Serbia :)

Put a capicitor from the pin side of the button to ground for a bit of debouncing.

I still think the button library is the way to go. Not only does it not require any external h/w but it has several useful features so you can detect:

  • a button being pressed
  • a button that is not being pressed
  • a button that was pressed
  • a button that was released
  • a long press for a user selectable amount of time

and others. It frees you having to write any of the code to do those kinds of things.

I've used it in several projects and it is quite simple to use.

--- bill

Why I have >=0 and <=180? - Because my Servo can move only 180 degrees, there is no way for value to go outside 0 - 180 because step is 20 deegres and 9 steps per 20 deegres are equal to 180.

Exactly. But your code doesn't prevent the RearServoPosition value from going less than 0 or beyond 180. In each of your "if" conditions, just before you write to the servo, you could use the constrain function to ensure the value stays within range.

RearServoPosition = constrain(RearServoPosition, 0, 180);
RearServo.write(RearServoPosition);

I still don't know how you want the buttons to work.

WHILE up button pressed --> RearServoPosition += RearStepIncrement , then delay 10ms, then RearServoPosition += RearStepIncrement, then delay 10ms, repeating continuously until the button is released.

or

When JUST pressed --> RearServoPosition += RearStepIncrement (only once per press).

Viruss: I can't get it working.

I don't know what you mean by "it".

Please post the latest version of your program.

...R

I tried to make system working well on various ways, but I kept old, most stable version that works pretty good but I think that securing from debounce will be good choice.

Most stable code:

#include 
#include 

Servo RearServo;
const byte RearUpPin = 3;
const byte RearDownPin = 4;
byte CurrRearUpButtonState = LOW;
byte PrevRearUpButtonState = LOW;
byte CurrRearDownButtonState = LOW;
byte PrevRearDownButtonState = LOW;
int RearServoPosition = EEPROM.read(0);
int RearStepIncrement = 20;
int DebounceCheck;
int LastDebounceTime;
int DebounceInterval = 500;

void setup()
{
  pinMode(RearUpPin, INPUT);
  pinMode(RearDownPin, INPUT);
  RearServo.attach(2);
  RearServo.write(RearServoPosition);
  Serial.begin(9600);
}

void loop()
{
  CurrRearUpButtonState = digitalRead(RearUpPin);

  if(CurrRearUpButtonState != HIGH) {
    LastDebounceTime = millis();
  }

  DebounceCheck = millis() - LastDebounceTime;

  Serial.print(F("Trenutna Pozicija Servo Motora: "));
  Serial.print(RearServoPosition);
  Serial.print("\n");

  if(CurrRearUpButtonState != PrevRearUpButtonState && CurrRearUpButtonState == HIGH && (RearServoPosition + 20) <= 180)  {
    RearServoPosition += RearStepIncrement;
    RearServo.write(RearServoPosition);
    delay(10);
    EEPROM.update(0, RearServoPosition);
  }  
  PrevRearUpButtonState = CurrRearUpButtonState;

  CurrRearDownButtonState = digitalRead(RearDownPin);
  
  if(CurrRearDownButtonState != PrevRearDownButtonState && CurrRearDownButtonState == HIGH && (RearServoPosition - 20) >= 0)
  {
    RearServoPosition -= RearStepIncrement;
    RearServo.write(RearServoPosition);
    delay(10);
    EEPROM.update(0, RearServoPosition);
  }
  PrevRearDownButtonState = CurrRearDownButtonState;
}

Video of working system: http://sendvid.com/dfzz6fkk

Re-organized the code, speed up print baudrate to 115200, added print interval to speedup loop, added internal pullups, check when buttons pressed (HIGH to LOW) or falling. Untested:

#include <EEPROM.h>
#include <Servo.h>

Servo RearServo;
const byte RearUpPin = 3;
const byte RearDownPin = 4;
byte CurrRearUpButtonState = LOW;
byte PrevRearUpButtonState = LOW;
byte CurrRearDownButtonState = LOW;
byte PrevRearDownButtonState = LOW;
int RearServoPosition = EEPROM.read(0);
int RearStepIncrement = 20;
int DebounceCheck;
int PrintCheck;
int LastDebounceTime;
int LastPrintTime;
int DebounceInterval = 50;
int PrintInterval = 500;

void setup()
{
  pinMode(RearUpPin, INPUT_PULLUP);
  pinMode(RearDownPin, INPUT_PULLUP);
  RearServo.attach(2);
  RearServo.write(RearServoPosition);
  Serial.begin(115200);
}

void loop()
{
  // Check status
  CurrRearUpButtonState = digitalRead(RearUpPin);
  CurrRearDownButtonState = digitalRead(RearDownPin);
  DebounceCheck = millis() - LastDebounceTime;
  PrintCheck = millis() - LastPrintTime;

  // Print
  if (PrintCheck >= PrintInterval) {
    Serial.print(F("Trenutna Pozicija Servo Motora: "));
    Serial.print(RearServoPosition);
    Serial.print("\n");
    LastPrintTime = millis(); // reset print timer
  }

  if (DebounceCheck >= DebounceInterval) {

    if ((CurrRearUpButtonState == LOW && PrevRearUpButtonState == HIGH) && (RearServoPosition + 20) <= 180) {
      RearServoPosition += RearStepIncrement;
      RearServo.write(RearServoPosition);
      delay(10);
      EEPROM.update(0, RearServoPosition);
    }
    if ((CurrRearDownButtonState == LOW && PrevRearDownButtonState == HIGH) && (RearServoPosition - 20) >= 0) {
      RearServoPosition -= RearStepIncrement;
      RearServo.write(RearServoPosition);
      delay(10);
      EEPROM.update(0, RearServoPosition);
    }
    PrevRearUpButtonState = CurrRearUpButtonState;
    PrevRearDownButtonState = CurrRearDownButtonState;
    LastDebounceTime = millis(); // reset debounce timer
  }
}

Viruss: but I think that securing from debounce will be good choice.

I wonder are you confusing switch bounce with changes of switch state?

Bounce is what happens when the switch contacts make an imperfect connection resulting in maybe half a dozen ON-OFF sequences within a millisecond or two. The simple solution for that is to wait maybe 50 millisecs before the next digitalRead() of that switch. This is much easier to implement if you have a separate function for reading all the switches.

...R

@Dlloyd, this is perfect. Thank you so much. Now I understand this things clearly.

@Robin2, I know what is debouncing very well, I’m in electronics more than 4 years… But this is my first Arduino, I don’t know why I didn’t tried it before :slight_smile:

I attached final version of code, and I will release project when I finish with pictures on this forum…

Thanks a lot to all!

ServoUpDownControll.ino (1.52 KB)