Is this a switch bounce problem?

Thread Starter

mwalden824

Joined Mar 6, 2011
51
I recently ordered the EasyAVR6 and have made a few small things with it. I am having troubles with my current little project. I am trying to just make the menu keypad type whatever on the 2x16 LCD. It starts off just showing an A and if you press up it goes up through the ASCII characters, and down opposite, and left and right moves while cancel resets. The problem is when i press any of the buttons it does what it's suppose to but like 10 times, or something more or less, randomly. And then sometimes it does nothing. I can't press it to fast either, it seems like it freezes or something.

Anyway, I am new to this so I am probably overlooking something stupid. I hoped someone could point it out for me. In particularly look at the area where I do the debouncing. I got the idea from a post:
http://forum.allaboutcircuits.com/showthread.php?t=53507&highlight=software+debounce
Not sure if I implemented it correctly though. I am pretty sure that is the problem, and I just don't understand why. I have tried many different values for the delay, etc. but no luck.

The push buttons for the keypad are connected to high when the button is pressed and I assume they are pulled down with a resistor while not pressed, yet it doesn't show this in the schematic, but its not full schematic. I dunno, you think they may be open when not pressed? surely they wouldn't have designed this board that way?

I read this post having similar problem:
http://forum.allaboutcircuits.com/showthread.php?t=55020
He said he had to add caps to power rail, but I'm using USB power from the programming cable.


Thanks for any help,
Michael Walden

P.S. Here's the code...
Rich (BB code):
#include <mega16.h>
#include <alcd.h>
#include <string.h>
#include <delay.h>

#define UP      0b00000001
#define DOWN    0b00001000
#define LEFT    0b00000010
#define RIGHT   0b00000100
#define ENTER   0b00010000
#define CANCEL  0b00100000

unsigned char letter = 'A';
unsigned char pad = 0x00;   // To save keypad press
const unsigned char startmsg[] = "A               \n                ";
unsigned char msg[35];
unsigned index = 0;         // Current string (msg) position
unsigned char count = 0;    // To count for Debounce

void upf(void);             // Declare Functions
void downf(void);
void leftf(void);
void rightf(void);
void enterf(void);
void cancelf(void);
void move(unsigned char c);

void main(void)
{
    DDRA = 0x00;  
    
    strcpy(msg, startmsg);      // Start Message

    lcd_init(16);       // Initialize 2x16 LCD
    lcd_clear();
    lcd_gotoxy(0,0);
    lcd_puts(msg);      // Print Start Message

    while (1)
    {             
        pad = PINA;
        
        while ((pad > 0x00) && (count < 6))    // Debounce
        {                                   
            delay_ms(1);
            pad = PINA;
            count++;
        }           
        
        if (count >= 5)      // Debounce
        {
            move(pad);      // Only move if 5 successful highs from button
            count = 0;
        }
        
    }
}

void upf(void)
{
    letter = msg[index];    
    
    if (letter != 32)    // Lowest Acceptable ASCII range
    {
        letter--;
        msg[index] = letter;    // Change current positions character 
        lcd_gotoxy(0,0);        // and reprint string
        lcd_puts(msg);
    }
}

void downf(void)
{
    letter = msg[index];        // Basically same as above
    
    if (letter != 126)
    {
        letter++;
        msg[index] = letter;
        lcd_gotoxy(0,0);
        lcd_puts(msg);
    }
}

void rightf(void)
{
    if (index == 15)    // If at end of LCD jump of null character
        index = 17;
    else if (index == 32)   // Go back to beginning
        index = 0;
    else
        index++;
}

void leftf(void)        // Same as above but in reverse
{
    if (index == 17)
        index = 15;
    else if (index == 0)
        index = 32;
    else
        index--;
}

void enterf(void)
{
 // write later
}

void cancelf(void)  // Restarts
{
    lcd_clear();
    index = 0;
    lcd_gotoxy(0,0);
    strcpy(msg, startmsg);
    lcd_puts(msg);
}

void move(unsigned char c)  // Does action
{
    switch (c)
    {
        case UP:
            upf();
            break;
        
        case DOWN:
            downf();
            break;
        
        case LEFT:
            leftf();
            break;
               
        case RIGHT:
            rightf();
            break;
                
        case ENTER:
            enterf();
            break;
                
        case CANCEL:
            cancelf();
            break;
                    
        default: ;  // Do nothing
    }
}
 

DumboFixer

Joined Feb 10, 2009
217
The problem you are seeing is that you are going to be calling move(pad) many times.

When you press a key you wait 1ms and increment count. Once count reaches 6 you exit the while loop and because count is now 6 the next block of code is called which calls move(pad).

You now go back to start of the first while loop and if the key is still pressed the whole process will start all over again, calling move(pad) for as long as you have your finger on the key.

A way round this is to checking for a leading edge in pad. By that I mean it changing from 0 to a value (and only a change from 0 to something). Once you have this edge you can then perform your output. you could also put in a delay of, say 25mS after the edge has been detected to ignore the bounce.
 

Thread Starter

mwalden824

Joined Mar 6, 2011
51
Got it. Thanks again. I used two variables to read input from buttons, one to start of and one was looped until they were not equal then they were compared and if the latest one was greater, then the move function was called with that current value.

I just could not figure that out for nothing the other night. I guess I'll learn these things as I encounter them.

Only thing now is that you still can't press the buttons too fast or it will not do anything which I assume is from the delay. So I will play with that value and see what I get now, but the smaller I make it I risk taking in weird data from bouncing.. I usually have to wait about a half second in between presses for a successful call to the right function or it will not do anything. But at least it doesn't jump.

Here is the fixed code for anyone having this problem and wants to see how I implemented what DumboFixer suggested...

Rich (BB code):
#include <mega16.h>
#include <alcd.h>
#include <string.h>
#include <delay.h>

#define UP      0b00000001
#define DOWN    0b00001000
#define LEFT    0b00000010
#define RIGHT   0b00000100
#define ENTER   0b00010000
#define CANCEL  0b00100000

unsigned char letter = 'A';
const unsigned char startmsg[] = "A               \n                ";
unsigned char msg[35];
unsigned index = 0;         // Current string (msg) position
unsigned char currbut = 0, prevbut = 0;

void upf(void);             // Declare Functions
void downf(void);
void leftf(void);
void rightf(void);
void enterf(void);
void cancelf(void);
void move(unsigned char c);

void main(void)
{
    DDRA = 0x00;  
    
    strcpy(msg, startmsg);      // Start Message

    lcd_init(16);       // Initialize 2x16 LCD
    lcd_clear();
    lcd_gotoxy(0,0);
    lcd_puts(msg);      // Print Start Message

    while (1)
    {             
        prevbut = PINA;
        
        do
        {
            currbut = PINA;         // Checks for edge
        } while (prevbut == currbut);
        
        if (currbut > prevbut)      // if rising edge...
        {
            delay_ms(25);
            move(currbut); 
        }
    }
}

void upf(void)
{
    letter = msg[index];    
    
    if (letter != 32)    // Lowest Acceptable ASCII range
    {
        letter--;
        msg[index] = letter;    // Change current positions character 
        lcd_gotoxy(0,0);        // and reprint string
        lcd_puts(msg);
    }
}

void downf(void)
{
    letter = msg[index];        // Basically same as above
    
    if (letter != 126)
    {
        letter++;
        msg[index] = letter;
        lcd_gotoxy(0,0);
        lcd_puts(msg);
    }
}

void rightf(void)
{
    if (index == 15)    // If at end of LCD jump of null character
        index = 17;
    else if (index == 32)   // Go back to beginning
        index = 0;
    else
        index++;
}

void leftf(void)        // Same as above but in reverse
{
    if (index == 17)
        index = 15;
    else if (index == 0)
        index = 32;
    else
        index--;
}

void enterf(void)
{
 // write later
}

void cancelf(void)  // Restarts
{
    lcd_clear();
    index = 0;
    lcd_gotoxy(0,0);
    strcpy(msg, startmsg);
    lcd_puts(msg);
}

void move(unsigned char c)  // Does action
{
     
    switch (c)
    {
        case UP:
            upf();
            break;
        
        case DOWN:
            downf();
            break;
        
        case LEFT:
            leftf();
            break;
               
        case RIGHT:
            rightf();
            break;
                
        case ENTER:
            enterf();
            break;
                
        case CANCEL:
            cancelf();
            break;
                    
        default: ;  // Do nothing
        }
}
 
Top