Up and Down counter with Debounce

Greetings!

I need to change a counter variable to go up or down upon the state change of 2 digital input pins on the Arduino. I'm having trouble interfacing it to a debounce code.

The idea is to have counter++ run when pin6 is HIGH and counter-- when pin7 is HIGH, it would be connected to momentary switches.

Any tips or ideas? I have tried the tutorial on Arduino site and seems I need a bit more code than that.

I have tried the tutorial on Arduino site and seems I need a bit more code than that.

Why? Post the code you have, and explain the problem you are having with it, please.

So far, this is the code without the debounce, so as I press either up or down, it will go very far very quick...

const int inPinUp = 6; 
const int inPinDown = 7;
int channel = 1;
int buttonUpState = 0;
int buttonDownState = 0;
void setup()
{
  Serial.begin(9600);
  pinMode(inPinUp, INPUT);
  pinMode(inPinDown, INPUT);
  
}


void loop()
{
  buttonUpState = digitalRead(inPinUp);
  buttonDownState = digitalRead(inPinDown);
  
  if (buttonUpState == HIGH)
  {
   channel++;
  }
  if (buttonDownState == HIGH)
  {
   channel--;
  }
  Serial.println(channel);
}

How do you suggest I do about the debounce for this ?

You want to do two things.

First, you want to increment (or decrement) the count when the button is HIGH, but only when it WAS LOW. So, you need to add two more variables so that you can keep track of the previous button state:

int prevBtnUp = LOW;
int prevBtnDwn = LOW;

Then, in loop:

if(buttonUpState == HIGH && prevBtnUp == LOW)
{
   // increment...
}
prevBtnUp = buttonUpState;

Make a similar change for the down button.

Second, you want to debounce the button. When the button is pressed, there is some fluttering happening, so you'll see LOW, HIGH, LOW, LOW, HIGH, HIGH, HIGH, etc. You only want to increment, or decrement the button if sufficient time has elapsed since the last LOW to HIGH transition. Add two variables to hold when the last transition occurred:

unsigned long lastBtnUp = 0;
unsigned long lastBtnDwn = 0;

You'll also need to determine a suitable length of time between transitions. Start with something like 50 milliseconds:

int transInt = 50;

Then, in loop, after you determine that the LOW to HIGH transition has occurred (that is, inside the if block), replace the existing code with this:

if(millis() - lastBtnUp > transInt)
{
    // increment
    lastBtnUp = millis();
}

Make a similar change for the button down code.

PaulS

Your suggested lines of code worked flawlessly

this is my current code, It is far from finished, but this current code can count from 1 to 9 and back and print them on the serial port as you press the up and down buttons.

const int inPinUp = 6;
const int inPinDown = 7;
int channel = 1;
int buttonUpState = 0;
int buttonDownState = 0;
int prevBtnUp = LOW;
int prevBtnDwn = LOW;
unsigned long lastBtnUp = 0;
unsigned long lastBtnDwn = 0;
int transInt = 50;

void setup()
{
  Serial.begin(9600);
  pinMode(inPinUp, INPUT);
  pinMode(inPinDown, INPUT);
  
}


void loop()
{
  
  buttonUpState = digitalRead(inPinUp);
  buttonDownState = digitalRead(inPinDown);
  
  if (buttonUpState == HIGH && prevBtnUp == LOW)
  {
    if (millis() - lastBtnUp > transInt)
    {
    channel++;
    if (channel > 9)
    {
      channel = 1;
    }
    lastBtnUp = millis();
    Serial.println(channel);
    }
  }
  prevBtnUp = buttonUpState;
  
  if (buttonDownState == HIGH && prevBtnDwn == LOW)
  {
    if(millis() - lastBtnDwn > transInt)
    {
    channel--;
    if (channel < 1)
    {
      channel = 9;
    }
    lastBtnDwn = millis();
    Serial.println(channel);
    
    }
  }
  prevBtnDwn = buttonDownState;
}

Thank you greatly for your help, :wink:

Now, I have another issue, after this my code is finished.

I like this part of my code to only run when I push a button , that is so it prints +TSC01 or +TSC02 etc only when I change the variable channel. But it prints it indefinitely, also after some time it starts polling indefinitely "+TSC?" , not sure why...still looking.

switch (channel)
      {
      case 1:
        Serial.println("+TSC01");
        break;
      case 2:
        Serial.println("+TSC02");
        break;
      case 3:
        Serial.println("+TSC03");
        break;
      case 4:
        Serial.println("+TSC04");
        break;
      case 5:
        Serial.println("+TSC05");
        break;
      case 6:
        Serial.println("+TSC06");
        break;
      case 7:
        Serial.println("+TSC07");
        break;
      case 8:
        Serial.println("+TSC08");
        break;
      case 9:
        Serial.println("+TSC09");
        break;
       }

Here is the whole code

const int inPinUp = 6;
const int inPinDown = 7;
int channel = 1;
int buttonUpState = 0;
int buttonDownState = 0;
int prevBtnUp = LOW;
int prevBtnDwn = LOW;
unsigned long lastBtnUp = 0;
unsigned long lastBtnDwn = 0;
int transInt = 50;
int chanPolling = 10000;
int chanPrevPoll = 0;


void setup()
{
  Serial.begin(9600);
  pinMode(inPinUp, INPUT);
  pinMode(inPinDown, INPUT);
  for (int updown = 6; updown < 8; updown++) {
         pinMode(updown, INPUT);
       }
  for (int BCD = 2; BCD < 6; BCD++) {
         pinMode(BCD, OUTPUT);
       } 
  
}


void loop()
{
  buttonUpState = digitalRead(inPinUp);
  buttonDownState = digitalRead(inPinDown);
  if (buttonUpState == HIGH && prevBtnUp == LOW)
  {
    if (millis() - lastBtnUp > transInt)
    {
    channel++;
    if (channel > 9)
      {
      channel = 1;
      }
    lastBtnUp = millis();
    }
   }
  prevBtnUp = buttonUpState;
  
  if (buttonDownState == HIGH && prevBtnDwn == LOW)
  {
    if (millis() - lastBtnDwn > transInt)
    {
    channel--;
    if (channel < 1)
    {
      channel = 9;
    }
    lastBtnDwn = millis();
  }
  }
  prevBtnDwn = buttonDownState;

      switch (channel)
      {
      case 1:
        Serial.println("+TSC01");
        break;
      case 2:
        Serial.println("+TSC02");
        break;
      case 3:
        Serial.println("+TSC03");
        break;
      case 4:
        Serial.println("+TSC04");
        break;
      case 5:
        Serial.println("+TSC05");
        break;
      case 6:
        Serial.println("+TSC06");
        break;
      case 7:
        Serial.println("+TSC07");
        break;
      case 8:
        Serial.println("+TSC08");
        break;
      case 9:
        Serial.println("+TSC09");
        break;
       }
    if (millis() - chanPrevPoll > chanPolling)
  {
    chanPrevPoll = millis();
    Serial.println("+TSC?");
  }
  if (Serial.available() > 0) 
  {
     int chan = Serial.read();
     switch ((char)chan){
     case '+TSC01':    
       digitalWrite(2, LOW);
       digitalWrite(3, LOW);
       digitalWrite(4, LOW);
       digitalWrite(5, HIGH);
       break;
     case '+TSC02':    
       digitalWrite(2, LOW);
       digitalWrite(3, LOW);
       digitalWrite(4, HIGH);
       digitalWrite(5, LOW);
       break;
     case '+TSC03':    
       digitalWrite(2, LOW);
       digitalWrite(3, LOW);
       digitalWrite(4, HIGH);
       digitalWrite(5, HIGH);
       break;
     case '+TSC04':    
       digitalWrite(2, LOW);
       digitalWrite(3, HIGH);
       digitalWrite(4, LOW);
       digitalWrite(5, LOW);
       break;
     case '+TSC05':    
       digitalWrite(2, LOW);
       digitalWrite(3, HIGH);
       digitalWrite(4, LOW);
       digitalWrite(5, HIGH);
       break;
     case '+TSC06':    
       digitalWrite(2, LOW);
       digitalWrite(3, HIGH);
       digitalWrite(4, HIGH);
       digitalWrite(5, LOW);
       break;
     case '+TSC07':    
       digitalWrite(2, LOW);
       digitalWrite(3, HIGH);
       digitalWrite(4, HIGH);
       digitalWrite(5, HIGH);
       break;
     case '+TSC08':    
       digitalWrite(2, HIGH);
       digitalWrite(3, LOW);
       digitalWrite(4, LOW);
       digitalWrite(5, LOW);
       break;
     case '+TSC09':    
       digitalWrite(2, HIGH);
       digitalWrite(3, LOW);
       digitalWrite(4, LOW);
       digitalWrite(5, HIGH);
       break;
     default:
       for (int thisPin = 2; thisPin < 6; thisPin++) {
         digitalWrite(thisPin, LOW);
       }
     }
  }
}

How can I achieve this?

Put the first bit of code into a function. Call the function when you increment or decrement the channel.

also after some time it starts polling indefinitely "+TSC?" , not sure why...still looking.

After how much time?

It does after I use the buttons for channel up or down or after like a minute, very odd.

Thank you PaulS for the Function Idea, now it only runs the code on channel variable change.

Now the crazy polling, it takes exactly 42 seconds every time I reset the Arduino. This is what it looks like

+TSÿ
!Z'á+TSC?
+TSC?
+TSC?
+TSC?

Right before it goes nuts...

Here is the complete code at the moment...

const int inPinUp = 6;
const int inPinDown = 7;
int channel = 1;
int buttonUpState = 0;
int buttonDownState = 0;
int prevBtnUp = LOW;
int prevBtnDwn = LOW;
unsigned long lastBtnUp = 0;
unsigned long lastBtnDwn = 0;
int transInt = 50;
int chanPolling = 10000;
int chanPrevPoll = 0;
int TSC = channelFunction();


void setup()
{
  Serial.begin(9600);
  pinMode(inPinUp, INPUT);
  pinMode(inPinDown, INPUT);
  for (int updown = 6; updown < 8; updown++) {
         pinMode(updown, INPUT);
       }
  for (int BCD = 2; BCD < 6; BCD++) {
         pinMode(BCD, OUTPUT);
       } 
  
}

int channelFunction()
{
  switch (channel)
      {
      case 1:
        Serial.println("+TSC01");
        break;
      case 2:
        Serial.println("+TSC02");
        break;
      case 3:
        Serial.println("+TSC03");
        break;
      case 4:
        Serial.println("+TSC04");
        break;
      case 5:
        Serial.println("+TSC05");
        break;
      case 6:
        Serial.println("+TSC06");
        break;
      case 7:
        Serial.println("+TSC07");
        break;
      case 8:
        Serial.println("+TSC08");
        break;
      case 9:
        Serial.println("+TSC09");
        break;
       }
}
void loop()
{  
  buttonUpState = digitalRead(inPinUp);
  buttonDownState = digitalRead(inPinDown);
  if (buttonUpState == HIGH && prevBtnUp == LOW)
  {
    if (millis() - lastBtnUp > transInt)
    {
    channel++;
    if (channel > 9)
      {
      channel = 1;
      }
    lastBtnUp = millis();
    TSC;
    }
   }
  prevBtnUp = buttonUpState;
  
  if (buttonDownState == HIGH && prevBtnDwn == LOW)
  {
    if (millis() - lastBtnDwn > transInt)
    {
    channel--;  
    if (channel < 1)
    {
      channel = 9;
    }
    lastBtnDwn = millis();
    TSC;
  }
  }
  prevBtnDwn = buttonDownState;

      if (millis() - chanPrevPoll > chanPolling)
  {
    chanPrevPoll = millis();
    Serial.println("+TSC?");
  }
  if (Serial.available() > 0) 
  {
     int chan = Serial.read();
     switch ((char)chan){
     case '+TSC01':    
       digitalWrite(2, LOW);
       digitalWrite(3, LOW);
       digitalWrite(4, LOW);
       digitalWrite(5, HIGH);
       break;
     case '+TSC02':    
       digitalWrite(2, LOW);
       digitalWrite(3, LOW);
       digitalWrite(4, HIGH);
       digitalWrite(5, LOW);
       break;
     case '+TSC03':    
       digitalWrite(2, LOW);
       digitalWrite(3, LOW);
       digitalWrite(4, HIGH);
       digitalWrite(5, HIGH);
       break;
     case '+TSC04':    
       digitalWrite(2, LOW);
       digitalWrite(3, HIGH);
       digitalWrite(4, LOW);
       digitalWrite(5, LOW);
       break;
     case '+TSC05':    
       digitalWrite(2, LOW);
       digitalWrite(3, HIGH);
       digitalWrite(4, LOW);
       digitalWrite(5, HIGH);
       break;
     case '+TSC06':    
       digitalWrite(2, LOW);
       digitalWrite(3, HIGH);
       digitalWrite(4, HIGH);
       digitalWrite(5, LOW);
       break;
     case '+TSC07':    
       digitalWrite(2, LOW);
       digitalWrite(3, HIGH);
       digitalWrite(4, HIGH);
       digitalWrite(5, HIGH);
       break;
     case '+TSC08':    
       digitalWrite(2, HIGH);
       digitalWrite(3, LOW);
       digitalWrite(4, LOW);
       digitalWrite(5, LOW);
       break;
     case '+TSC09':    
       digitalWrite(2, HIGH);
       digitalWrite(3, LOW);
       digitalWrite(4, LOW);
       digitalWrite(5, HIGH);
       break;
     default:
       for (int BCD = 2; BCD < 6; BCD++) {
         digitalWrite(BCD, LOW);
       }
     }
  }
}

I gotten this far thanks to you :wink:

int TSC = channelFunction();

This makes a call to the function. The function does not actually return a value, so I have no idea what is assigned to the TSC variable.

    TSC;

This is not (or, at least I don't believe that is should be) calling the function. Replace this with:

    channelFunction();

Change the definition of channelFunction to "void channelFunction()", since it doesn't actually return anything.

     int chan = Serial.read();
     switch ((char)chan){

You could just define chan to be a char, and avoid the cast to char.

To investigate the problem, change this:

      if (millis() - chanPrevPoll > chanPolling)
  {
    chanPrevPoll = millis();
    Serial.println("+TSC?");
  }

to this:

      if (millis() - chanPrevPoll > chanPolling)
  {
    chanPrevPoll = millis();
    Serial.print("millis() returned: ");
    Serial.println(millis());
    Serial.print("chanPrevPoll = ");
    Serial.print(chanPrevPoll);
    Serial.print("chanPolling = ");
    Serial.println(chanPolling);
    Serial.println("+TSC?");
  }

Let us know how this goes.

PaulS:

I replaced the suggested code, now I call the function without the use of a variable, and I declare the char chan on top.

Now this is what I get on the serial window:

+TSC?
+TSC?
+Tmillis() returned: 10018
chanPrevPoll = 10001chanPolling = 10000
+TSC?
millis() returned: 20020
chanPrevPoll = 20002chanPolling = 10000
+TSC?
millis() returned: 30020
chanPrevPoll = 30003chanPolling = 10000
+TSC?
millis() returned: 40022
chanPrevPoll = -25532chanPolling = 10000
+TSC?
millis() returned: 40099
chanPrevPoll = -25456chanPolling = 10000
+TSC?
millis() returned: 40177
chanPrevPoll = -25378chanPolling = 10000
+TSC?
millis() returned: 40255
chanPrevPoll = -25300chanPolling = 10000
+TSC?
millis() returned: 40333
chanPrevPoll = -25223chanPolling = 10000
+TSC?
millis() returned: 40412
chanPrevPoll = -25145chanPolling = 10000
+TSC?
millis() returned: 40489
chanPrevPoll = -25066chanPolling = 10000
+TSC?
millis() returned: 40567
chanPrevPoll = -24988chanPolling = 10000
+TSC?
millis() returned: 40645
chanPrevPoll = -24910chanPolling = 10000
+TSC?
millis() returned: 40723
chanPrevPoll = -24832chanPolling = 10000
+TSC?
millis() returned: 40802
chanPrevPoll = -24755chanPolling = 10000
+TSC?
millis() returned: 40880
chanPrevPoll = -24677chanPolling = 10000
+TSC?
millis() returned: 40957
chanPrevPoll = -24598chanPolling = 10000

takes 10 seconds between:

millis() returned: 30020
chanPrevPoll = 30003chanPolling = 10000
+TSC?

and

millis() returned: 40022
chanPrevPoll = -25532chanPolling = 10000
+TSC?

Right after this line is all nuts...

I read on int vs long

That int = -32768 to 32767 and long = -2147483648 to 2147483647

So I changed

int chanPrevPoll = 0;

to

long chanPrevPoll = 0;

Now I get

+TSC?
millis() returned: 10018
chanPrevPoll = 10001chanPolling = 10000
+TSC?
millis() returned: 20020
chanPrevPoll = 20002chanPolling = 10000
+TSC?
millis() returned: 30020
chanPrevPoll = 30003chanPolling = 10000
+TSC?
millis() returned: 40022
chanPrevPoll = 40004chanPolling = 10000
+TSC?
millis() returned: 50023
chanPrevPoll = 50006chanPolling = 10000
+TSC?
millis() returned: 60024
chanPrevPoll = 60007chanPolling = 10000
+TSC?

And on, so it is fixed.

Also I was wondering, since Millis overflows after 9 hours or so per this post

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1167861718

How do I do about resetting millis to 0 or is there a better way instead of millis? I can't understand the commands they reference too... still trying...

I missed that. It should, actually, be unsigned long, though.

I just edited the post above...

You don't want to reset millis.

There was a very good explanation about how and why subtraction involving millis was always safe (if(millis() - someTime > someDuration)), even when millis rolls over, posted to the forum. You could search for that, if you are interested, but the result is that if you are using millis() like you are, you are safe even when millis rolls over.

By the way, the rollover time is more like 51 days, not 9 days.

OK!!!

So once millis reaches the maximum value, then it rolls over to 0, good to know!!!!

My code works perfectly when powered on USB to the terminal window.

My issue now is:

I power the Arduino Duemilanove ATMEGA168 board externally with 12V, since Rx and Tx are TTL, I thought I could loop Pin0 and Pin1, but it does not seem to work...

How do you make a Loop on the Arduino Pin0 and Pin1?

How do you make a Loop on the Arduino Pin0 and Pin1

A couple of centimetres of hookup wire.

But why?

Basically, the code sends a channel # Ex. "+TSC04" and if it echos back, the Arduino will display the current channel on the BCD/7-segment display...so if I could loop both serial pins it would act like I have it connected to the radio I plan to change channels too.

But it was a no-go when I did the mentioned hoop up wire from Pin0 to Pin1.

You've disconnected the FTDI chip?

No, can I do this with jumper?