# AVR Button Interfacing

I am a beginner of the micro-controller and I have the kit for AVR. I am currently using an ATMega16 to learn the basics. I have tried a few simple experiments with this micro-controller using LED's. Now I wanted to do some hardware interfacing and I found an interesting project.

I want to use 6 push buttons for counting to 2500 and display it on the multiplexed seven segment LED's. 3 buttons for counting upwards, i.e., (100's, 10's and 1's). For instance, if I have to display 1532, I will press 100's button 15 times, 10's button 3 times and 1's button twice. Similarly, for counting down, I want to use 3 buttons. I have tried some code that makes use of conditional statements for checking the pin status but none of them seem to work.

Please help me out with this as I have been stuck on this for quite a while. It seems to be the issue with "debouncing" but I am not entirely sure about that concept.

I am trying to count the number of times the switch has been pressed (PB0) and when it reaches 5, I want to turn ON an LED(PD0). The below code does not work.

int main(void)
{
unsigned char count=0;

TCCR0 = (1<<WGM01)|(1<<CS02)|(1<<CS00); // Timer0 Mode 2: CTC-Prescaler 1024
TCNT0 = 0;
OCR0 = (((XTAL / 1024.0)*10e-3)-1); // For 10ms
TIMSK = 1<<OCIE0;           // enable T0 interrupt

DDRB = 0x00;                // PB0 input
PORTB = 0x00;               // external pullup

DDRD = 0x01;                // PD0 LED output
PORTD = 0x00;               // LEDs off

sei();

while(1)
{                               // main loop
if(!(PINB & _BV(PB0)))
{
count++;

if(count>=5)
{
PORTD|= (1<<PD0);   // SET LED on keypress
_delay_ms(10);
count = 0;
}

}

}

}


Debouncing is something you must be familiar with when using buttons. When a contact closes, it does not just close, but bounces back a few times until it finally settles in its closed position.

Depending on how fast your sampling code is, the code can count many button presses, although you only moved your finger once. There are a number of debouncing strategies around. Search www.avrfreaks.net for debouncing and you will find plenty of posts. Most of the recent threads contain a link to some pretty good old examples/strategies which you can use.

This might not be the only problem with your code - but we can only know that when we've seen the code. Post it here or on avrfreaks and we might be able to help you.

• The concept is quite clear but I wanted help on how to implement it in the code. I searched the forums but did not find anything that explained my current problem. Feb 19 '13 at 11:05

Are you enabling internall pullup resistors for your inputs or using external pullups?

MCU pin PB0 -> button -> GND

The something like this should work:

DDRB &= ~_BV(PB0); //set PB0 to input
PORTB |= _BV(PB0); //enable pullup on input

while(1) {
if(!(PINB & _BV(PB0))) { //PINB will have PB0 set to 0 on button press

//do whatever you like

_delay_ms(150);//wait a bit while the button is bouncing
while(!(PINB & _BV(PB0))); //do nothing while the button is still pressed
}
}


Please note, this is not a good proper way to do it, it's just the most simple foolproof way to get you started. After you get thru this, lookup numerous proper button debouncing techniques and ask more specific questions here.

• I have tried a similar code and this code too. Neither of them worked. I am still stuck with the button interfacing. Please refer to my code below and tell me what could be the error. I want to count the number of times the switch has been pressed and when it reached the predefined limit(in this example - 5), I want to turn ON an LED. Feb 19 '13 at 11:26
• @AshishKoujalgi please edit your question and put your code into the question. Feb 19 '13 at 16:23

To start, a button would typically connect to ground when it is pushed. The microcontroller pin should be set as an input with the internal pull up resistor enabled. There is no need to use external components here. If the pin reads LO, then the button was pushed. I usually use small tactile buttons in my designs, and I have never had them bound for more than a few milliseconds. With that in mind, it is also easy to know how long a button has been pressed so you can actually have different actions for a short press or a long press. For a simple example, in the following code, the state of a set of pins is continuously polled in MAIN. When a button is pressed, the program will delay for a specified amount of time before rechecking the buttons and doing something useful.

#define MS_DEBOUNCE    10   // Time in ms to debounce button
DDRC = 0x00;                // Set All as Inputs
PORTC = 0xFF;               // Inputs: Pulls Ups Enabled

if(!(PINC & BUTTON){        // If Some Button is pressed...
delay_ms(MS_DEBOUNCE);        //   Delay to debounce button
if(!PINC & BUTTON){           //   If Button is Still Pressed...
//... Do Something useful here ...
}
}
while(!(PINC & BUTTON)); // This will loop until the button has been released.


This is a very simple example that has always worked well for me. To actually count the press duration, I would set a global flag before a final while loop to alert a routine in a timer ISR. This ISR would then count up until the button has been released. After so long, a different action can take place. For example (in MAIN, in place of the above while loop):

stat_flag |= BUTTON_PRESS;          //   Set Bit to enter loop
duration_cnt = MS_HOLD;             //   Preset duration counter
while(stat_flag & BUTTON_PRESS);    //   Loop until button released


Then, in a 1ms timer ISR, I would do something like the following. If will count down from the specified "MS_HOLD" time. If after such time, the button is still pressed, then take an additional "long press" action. This could be done in place of the short press, or could be repeated indefinitely as long as the button is still held, such as holding a volume button, the volume will increase every so many ms.

if(duration_cnt){               // Button was pressed
if(--duration_cnt == 0){        // Counter has expired
if(PINC != DEFAULT_PINS){       // Some button is still pressed
//... Do something useful for long press
}
else{                          // No Buttons being pressed
stat_flag &= ~BUTTON_PRESS;  // Reset flag to exit delay loop
}
}
}