Go Down

Topic: Debounce on a switch with variable resistance (Read 1 time) previous topic - next topic


Assuming that each position has an output voltage not close to the others (I look at the circuit and that seems like a safe assumption) that you can know each one,

Maybe when you detect a change, you keep reading over and over until the new value stays within +/- perhaps .2V of one of the accepted values for 20 to 50 reads in a row which should take less than 10 ms. You could be pretty certain the switch has settled by then.
I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.


May 27, 2012, 06:37 pm Last Edit: May 27, 2012, 06:56 pm by GeoDave Reason: 1

Did I implement the running average correctly?

You implemented an average not a running average.
If your readings are changing too fast then increase the number of terms in the average.

How are you wiring this up? You do have a pull up resistor on the analogue input as well do you?

Pin 1 on the button schematic goes to 5v.  Pin 2 goes to analog 0 and a 1K resistor tied to gnd.   I am going to play some more and see what I can come up with based on the comments.  Thanks again!


In your readButtons() function you need to remember what poosition the button was in previously and do your range checks to see what position it is in now. If they are different, the button has been pressed or released so set lastButtonPushed to indicate the new position. Otherwise (the position has not changed) set lastButtonPushed to zero, or whatever value you're using to represent the 'not pressed' position.

I got it working much better.  Thoughts on improvements?  Here is what I did: 

Code: [Select]
IMPORTANT: to use the menubackend library by Alexander Brevig download it at http://www.arduino.cc/playground/uploads/Profiles/MenuBackend_1-4.zip and add the next code at line 195
void toRoot() {
setCurrent( &getRoot() );
#include <MenuBackend.h>    //MenuBackend library - copyright by Alexander Brevig

#define buttonPinLeft (1<<0)
#define buttonPinRight (1<<1)
#define buttonPinEsc   (1<<2)
#define buttonPinEnter  (1<<3)

int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0; 
int buttonPushed;
int lastButtonPushed;

int inputPin = 0;

// LiquidCrystal display with:
// rs on pin 7
// rw on ground
// enable on pin 6
// d4, d5, d6, d7 on pins 5, 4, 3, 2

//Menu variables
MenuBackend menu = MenuBackend(menuUsed,menuChanged);
//initialize menuitems
    MenuItem menu1Item1 = MenuItem("Item1");
      MenuItem menuItem1SubItem1 = MenuItem("Item1SubItem1");
      MenuItem menuItem1SubItem2 = MenuItem("Item1SubItem2");
    MenuItem menu1Item2 = MenuItem("Item2");
      MenuItem menuItem2SubItem1 = MenuItem("Item2SubItem1");
      MenuItem menuItem2SubItem2 = MenuItem("Item2SubItem2");
      MenuItem menuItem3SubItem3 = MenuItem("Item2SubItem3");
    MenuItem menu1Item3 = MenuItem("Item3");

void setup()


  //lcd.begin(16, 2);

  //configure menu
  Serial.print("$GO 1 1\r\n");
  //lcd.print("Hello World!");
  Serial.print("$PRINT Hello World!        \r\n");
}  // setup()...

void loop()

  readButtons();  //I splitted button reading and navigation in two procedures because
  navigateMenus();  //in some situations I want to use the button for other purpose (eg. to change some settings)
} //loop()...

void menuChanged(MenuChangeEvent changed){
  MenuItem newMenuItem=changed.to; //get the destination menu
  //lcd.setCursor(0,1); //set the start position for lcd printing to the second row
      //lcd.print("Main Menu       ");
      Serial.print("$CLEAR 2 1\r\n");
       Serial.print("$GO 2 1\r\n");
       Serial.print("$PRINT Main Menu       \r\n");
  }else if(newMenuItem.getName()=="Item1"){
    Serial.print("$CLEAR 2 1\r\n");
      Serial.print("$GO 2 1\r\n");
      Serial.print("$PRINT Item1       \r\n"); 
    //lcd.print("Item1           ");
  }else if(newMenuItem.getName()=="Item1SubItem1"){
    Serial.print("$CLEAR 2 1\r\n");
      Serial.print("$GO 2 1\r\n");
      Serial.print("$PRINT Item1SubItem1       \r\n"); 
  }else if(newMenuItem.getName()=="Item1SubItem2"){
      Serial.print("$CLEAR 2 1\r\n");
      Serial.print("$GO 2 1\r\n");
      Serial.print("$PRINT Item1SubItem2       \r\n");
    //lcd.print("Item1SubItem2   ");
  }else if(newMenuItem.getName()=="Item2"){
      Serial.print("$CLEAR 2 1\r\n");
      Serial.print("$GO 2 1\r\n");
      Serial.print("$PRINT Item2       \r\n");   
    //lcd.print("Item2           ");
  }else if(newMenuItem.getName()=="Item2SubItem1"){
      Serial.print("$CLEAR 2 1\r\n");
      Serial.print("$GO 2 1\r\n");
      Serial.print("$PRINT Item2SubItem1       \r\n");   
    //lcd.print("Item2SubItem1   ");
  }else if(newMenuItem.getName()=="Item2SubItem2"){
      Serial.print("$CLEAR 2 1\r\n");
      Serial.print("$GO 2 1\r\n");
      Serial.print("$PRINT Item2SubItem2       \r\n");   
    //lcd.print("Item2SubItem2   ");
  }else if(newMenuItem.getName()=="Item2SubItem3"){
      Serial.print("$CLEAR 2 1\r\n");
      Serial.print("$GO 2 1\r\n");
      Serial.print("$PRINT Item2SubItem3       \r\n");   
    //lcd.print("Item2SubItem3   ");
  }else if(newMenuItem.getName()=="Item3"){
      Serial.print("$CLEAR 2 1\r\n");
      Serial.print("$GO 2 1\r\n");
      Serial.print("$PRINT Item3       \r\n");   
    //lcd.print("Item3           ");

void menuUsed(MenuUseEvent used){
//do something here

void  readButtons(){  //read buttons status
unsigned char button = analogRead(inputPin) >> 2;
  if (button == 0){

  if (button > 20 && button < 60){
  else if (button > 60 && button < 100){
  else if (button > 140 && button < 160){
  else if (button > 160 && button < 200){
  else {
// read the pushbutton input pin:
  buttonState = buttonPushed;

  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState != 0 ) {
      // if the current state is HIGH then the button
      // wend from off to on:
      lastButtonPushed = buttonPushed;     
    else {
      // if the current state is LOW then the button
      // wend from on to off:
      lastButtonPushed = 0;
  // save the current state as the last state,
  //for next time through the loop
  lastButtonState = buttonState;

void navigateMenus() {
  MenuItem currentMenu=menu.getCurrent();
  switch (lastButtonPushed){
    case buttonPinEnter:
      if(!(currentMenu.moveDown())){  //if the current menu has a child and has been pressed enter then menu navigate to item below
      }else{  //otherwise, if menu has no child and has been pressed enter the current menu is used
    case buttonPinEsc:
      menu.toRoot();  //back to main
    case buttonPinRight:
    case buttonPinLeft:
  lastButtonPushed=0; //reset the lastButtonPushed variable


Code: [Select]
unsigned char button = analogRead(inputPin) >> 2;
Unsigned char? Why? Why not byte?


I'm a bit perplexed by the number of state variables you are using in readButtons.

Using buttonState and lastButtonState looks fine to hold the current detected state and previously detected state so you can detect changes. Using lastButtonPushed as a way to pass the change from readButtons() to navigateMenus() (and then clear it once it's been processed) is also OK. Personally I'd have preferred to have readButtons() return the key that was pressed (or 0 is nothing was pressed) rather than using a global variable, because this reduces the amount of global data and that is always a good thing, but that's mainly a matter of style. But then you also have buttonPushed and buttonPushCounter, and I have no idea what they're for. If you can eliminate them that would reduce the complexity by a useful amount.
I only provide help via the forum - please do not contact me for private consultancy.

Go Up