HELP: ATMEGA 328P simple debouncing program switch

Go To Last Post
19 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I still dont understand how to make a simple debouncing switch program, here is the description of how the switch should work: 

  1. There are two states in the switch: State 0 and 1. When it is in State 0, all LEDs connected to Port D are off. When it is in State 1, all LEDs are on. At the beginning, the switch is in State 0. When the switch is pressed and it is in State 0, it goes to State 1. When the switch is pressed and it is in State 1, it goes to State 0.

 

Here is my attempt to make the simple debouncing switch program in C language

#define F_CPU 1234567UL // set this to what you know the CPU speed to be in Hz
#include <avr/io.h>
#include <util/delay.h>

unsigned char x = 0;

int main(void)
{
   DDRB = 0x00; //activate port B as 0 bits input
   DDRD = 0xff; //activate port D as output

   while(1)
   {
       if(PINB&(1<<0))
       {
          if(x == 0)
          {
            PORTD = 0xff; // turn on LED as 1 statement
            x = 1; // turns
          }
          else
          {
            PORTD = 0x00; //turn on LED as 0 statement
            x = 0; // turns
          }
	   }

   }
}

However when the program activates, sometimes I have to press the button 3 times to state 1, sometimes it goes state 0 and it wont turn off LED. All I want about the debouncing switch is press 1 time to become state 1 and press 1 time to become state 0 of the switch, can someone help me?

 

P.S please make the program much simple to understand as a beginner

 

This topic has a solution.
Last Edited: Tue. Sep 20, 2022 - 12:33 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

Here is my hardware example for this switch and led programming

 

Last Edited: Mon. Sep 19, 2022 - 03:27 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How do you expect that code to do any debouncing?  What sets the timing interval of the debouncing interval?  How long are you planning to look at the switch to determine the correct debounced state? 2ms? 200ms? what were you intending?

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Mon. Sep 19, 2022 - 03:50 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK I intend to debounce in 200ms

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

How do you expect that code to do any debouncing?  What sets the timing interval of the debouncing interval?  How long are you planning to look at the switch to determine the correct debounced state? 2ms? 200ms? what were you intending?

 

OK I would like to delay around 200ms for this debouncing switch program.

 

Also one more question, what happen if I use 1000ms(aka 1 second of real time) for debouncing the switch?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


 

What's this ??? point the LEDs downwards towards gnd.  What made you draw so insanely? Four LEDs are taking up half your page

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Mon. Sep 19, 2022 - 04:08 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

s021623 wrote:

OK I would like to delay around 200ms for this debouncing switch program.

 

Also one more question, what happen if I use 1000ms(aka 1 second of real time) for debouncing the switch?

Those delays are too long, they will make the program very sluggish.  Something between 20 and 50ms would be more typical.

 

To debounce, look for the button-down edge (when the button input goes from HI to LO), then do your debounce delay.  At the end of the delay, the mechanical bouncing should have stopped.  Do the same for the button-up edge (LO to HI).

 

And don't call your LED state variable 'x', call it qq77.  Seriously, give all your variables meaningful names.

Last Edited: Mon. Sep 19, 2022 - 04:13 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kk6gm wrote:

Those delays are too long, they will make the program very sluggish.  Something between 20 and 50ms would be more typical.

 

To debounce, look for the button-down edge (when the button input goes from HI to LO), then do your debounce delay.  At the end of the delay, the mechanical bouncing should have stopped.  Do the same for the button-up edge (LO to HI).

 

And don't call your button state variable 'x', call it qq77.  Seriously, give all your variables meaningful names.

  •  

 

so what functions should I use for my code? seems my code debouncing were out of control without those delays 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

s021623 wrote:
so what functions should I use for my code? seems my code debouncing were out of control without those delays 

The simple approach would be to use _delay_ms().  It's not the best method in general, because it ties up the CPU just to waste cycles in a delay, but for what you're doing it's a good first step.

 

EDIT: also, your test for the button push is backwards, it is detecting when the button is NOT pushed.  You want to detect when the bit is 0, not 1.

Last Edited: Mon. Sep 19, 2022 - 04:22 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

At the end of the delay, the mechanical bouncing should have stopped. 

Do the same for the button-up edge (LO to HI)

This is just one of many methods, take a look around here for several!

 

To summarize, Keep in mind to help yourself making the code:  

pressing the button makes a burst of hi's and lows

releasing the button makes a burst of hi's and lows

 

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Mon. Sep 19, 2022 - 04:21 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kk6gm wrote:

s021623 wrote:
so what functions should I use for my code? seems my code debouncing were out of control without those delays 

The simple approach would be to use _delay_ms().  It's not the best method in general, because it ties up the CPU just to waste cycles in a delay, but for what you're doing it's a good first step.

 

#define F_CPU 1234567UL // set this to what you know the CPU speed to be in Hz
#include <avr/io.h>
#include <util/delay.h>

unsigned int debouncer = 0; //debouncer int determines 1 or 0 statement

int main(void)
{
   DDRB = 0x00; //activate port B as 0 bits input
   DDRD = 0xff; //activate port D as output

   while(1)
   {
       if(PINB&(1<<0))
       {
          if(debouncer == 0)
          {
            PORTD = 0xff; // turn on LED as 1 statement
            debouncer = 1; // turns into state 1
            _delay_ms(20);
          }
          else
          {
            PORTD = 0x00; //turn on LED as 0 statement
            debouncer = 0; // turns into state 0
            _delay_ms(20);
          }
	   }

   }
}

 

Did tried to add delays to the function of the switch, again I have to press several times of the button to switch state between 1 and 0 statement, what is the problem of my code?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

This is just one of many methods, take a look around here for several!

 

Correct.  The suggested method is what I would first propose to a beginner, to get something working.  Then I would explain how there are better methods.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

s021623 wrote:
Did tried to add delays to the function of the switch, again I have to press several times of the button to switch state between 1 and 0 statement, what is the problem of my code?

You're confusing the debouncing with the LED state changing.

 

First, detect the button push HI to LO.  Think of that as the leading or active edge of the button event.  Debounce it and do the LED state change.

Second, detect the button release LO to HI and debounce it, not doing anything with the LED.  That is the trailing edge of the button event.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK i get it what you mean. I also used a switch function and it work as I intended to be. 

 

Is using a switch and increment function correct for 1 and 0 statement of the debouncing of a switch?

#define F_CPU 12345678UL // set this to what you know the CPU speed to be in Hz
#include <avr/io.h>
#include <util/delay.h>


unsigned char check_button() //checks button
{
  if(!(PINB&(1<<0)))
  {
    _delay_ms(250);
    if(PINB&(1<<0)) return 1;
  }
  return 0;
}

int main(void)
{
   unsigned char press_button = 1; //char used for increment variable
   DDRB = 0x00; //activate port B as 0 bits input
   DDRB &= ~(1<<0);
   PORTB = 0x00; 
  
   DDRD = 0xff; //activate port D as output
   PORTD = 0x00;
   while(1)
   {
       if(check_button())
       {
          switch(press_button)
          {
            case 1:
            PORTD = 0xff;
            break;
            
            case 2:
            PORTD = 0x00;
            press_button=0; //reset into 0
            break;
          }
          press_button++; // increment of variable increases
          _delay_ms(200);
	   }

   }
   return 0;
}

 

 

 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For this Ultra-Simple program you need only debounce the switch release. I.e. the program reacts very quickly to the button press but you cannot press again until you determine that the switch has been released.

 

This is a fairly simple addition to your #1 code.

BTW: F_CPU isn't 12345678 is it ?

#define F_CPU 8000000UL // set this to what you know the CPU speed to be in Hz
#include <avr/io.h>
#include <util/delay.h>

unsigned char x = 0;

int main(void)
{
    DDRB = 0x00; //activate port B as 0 bits input
    DDRD = 0xff; //activate port D as output

    while (1) {
        if (PINB & (1 << 0)) {
            if (x == 0) {
            PORTD = 0xff; // turn on LED as 1 statement
            x = 1; // turns
            }
            else {
            PORTD = 0x00; //turn on LED as 0 statement
            x = 0; // turns
            }

            /* We've actioned the KeyPress. Now debounce KeyRelease. (dmms in millisecond) */
            for (uint8_t dbms = 0; db < 20; db++) {
                if ((PINB & PINB0) == 0) {
                    _delay_ms(1);
                }
                else {
                    dbms = 0;
                }
            }
        }
    }
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

N.Winterbottom wrote:

For this Ultra-Simple program you need only debounce the switch release. I.e. the program reacts very quickly to the button press but you cannot press again until you determine that the switch has been released.

 

This is a fairly simple addition to your #1 code.

BTW: F_CPU isn't 12345678 is it ?

#define F_CPU 8000000UL // set this to what you know the CPU speed to be in Hz
#include <avr/io.h>
#include <util/delay.h>

unsigned char x = 0;

int main(void)
{
    DDRB = 0x00; //activate port B as 0 bits input
    DDRD = 0xff; //activate port D as output

    while (1) {
        if (PINB & (1 << 0)) {
            if (x == 0) {
            PORTD = 0xff; // turn on LED as 1 statement
            x = 1; // turns
            }
            else {
            PORTD = 0x00; //turn on LED as 0 statement
            x = 0; // turns
            }

            /* We've actioned the KeyPress. Now debounce KeyRelease. (dmms in millisecond) */
            for (uint8_t dbms = 0; db < 20; db++) {
                if ((PINB & PINB0) == 0) {
                    _delay_ms(1);
                }
                else {
                    dbms = 0;
                }
            }
        }
    }
}

 

 

Ah the F_CPU is a typo mistake, sorry for that.

 

Also one more question, whatis uint8_t in terms of a variable?

What is the variable of db?

Last Edited: Mon. Sep 19, 2022 - 11:07 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:
What's this ??? point the LEDs downwards towards gnd.  What made you draw so insanely? Four LEDs are taking up half your page

 

There is NOTHING WRONG with the way the LEDs are drawn.  They are connected correctly and you can see what port pins they are connected to.  If the OP wants to use half a page...ITS THEIR PREROGATIVE!  If you do not like it, do not contribute to the thread.

 

 

@s021623,

The 'art' of debouncing has been brought up here more times than anyone cares to count.  I suggest you do a search of the forums and look at the hundreds of options, that really boil down to IMO two ways.

 

Use _delay_ms(), which as you have learned wastes the CPU's time.

 

or

 

Look at using a Timer, and Interrupts.

 

Again in both of these scenarios,  more the Timer version though there are many sub options available.

 

All the best on your project!

 

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There is NOTHING WRONG with the way the LEDs are drawn. 

It was simply a very poor arrangement. Never said there was anything nonfunctional.  However, schematics should get good detail attention as much as code cleanup. Not sure why you'd be opposed to making improvement along the way, though you provided none. If higher complexity circuits are created in this same haphazard manner, it will be almost complete chaos, so it is important to mention it now, or they'll say, why didn't someone bring it up sooner.

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Also one more question, what is uint8_t in terms of a variable?

uint8_t is standard (compiler agnostic) way of defining an unsigned integer of width 8-bits. Before you ask; yes int8_t/uint8_t, int16_t/uint16_t, int32_t/uint32_t etc all exist for the same reason. See stdint.h for the gory details.

 

What is the variable of db?

That's my typo. I typed that in a hurry so as not to miss the beginning of the Queen's funeral. Correction below:

for (uint8_t db = 0; db < 20; db++) {

The idea here is to continuously check that the Key-switch is released throughout a 20ms debounce period. If the switch release bounce is still occurring then reset the 20ms over again.

 

Debounce techniques vary in complexity and yes you could configure a Timer/Counter etc. but I don't think this very simple code warrants such endeavour. You can learn about advanced debouncing another day.