Switch debouncing on code

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

Hi there, I am an automation engineering student and I am struggling with the coding of an exercise i had to in class. With a ATMEGA328p We are to interface a keypad and display what number was last pressed on the LCD AND denounce a switch so that toggles between 2 LED without issue.

 

I understand that I need to make the reading of the switch signal a bit longer so it confirms that the button has been pressed. I share my code

 

void init_interrupts() {
  // To set up the interrupts for the pin - PCINT1
  // Enable the particular pin change interrupt - PC0
  // Enable global interrupts
  
  PCMSK0 = (1<<PCINT1);                  // Enable PCINT1 interrupt, and clear others
  PCICR &= ~(1<<PCIE1) & ~(1<<PCIE2); // Disable PC Int 1 and PC Int 2
  PCICR |= (1<<PCIE0);                  // Enable PC Int 0 
  sei();                                 // Enable global interrupts

  
  
}  // END init_interrupts

//**************************************************

void init_switch_port() {
  // Initialises Port B 
  // PB1 set as input for switch
  // PB2 and PB3 set as outputs for LEDs
  // Turn Red LED off and Green LED on initially
  
  DDRB &= ~(1<<PB1); // Set PB1 as input 
  PORTB |= (1<<PB1); // Enable PB1 internal pull-up
  DDRB |= (1<<PB2) | (1<<PB3); // Set PB2 and PB3 as outputs
  PORTB |= (1<<PB2); // Red LED off
  PORTB &= ~(1<<PB3); // Green LED on

}  // END init_switch_port

//**************************************************

ISR(PCINT0_vect) {
// This uses the predefined ISR function to create an ISR
// The compiler generates the initial and final code 
// (including the RETI instruction)
// This will result in the following code being run when 
// Interrupt PC0 (Pin change 0) happens 
    

  delay_ms(10);                      // Short delay to 'debounce' switch
     // XOR bits 3 and 5 to toggle LEDs
  
  PCIFR |= (1<<PCIF0);
  if ((PINB & (1<<PB1)) == 0) {
    PORTB ^= (1<<PB2) | (1<<PB3); 
  }
  
  
}   //End ISR PCINT0

 

reason why I am using the interrupt pins is because the next exercise I need to make the LEDs toggle as many seconds as the key pressed on the keypad. 

 

Also I read that I have to set a timer but I am not really sure how a timer would work in here.

Last Edited: Mon. Sep 13, 2021 - 02:59 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

why do you make this a complete mis-mash mess ??

DDRB &= ~(1<<PB1); // Set PB1 as input 
  PORTB |= (1<<PB1); // Enable PB1 internal pull-up
  DDRB |= (1<<PB2) | (1<<PB3); // Set PB2 and PB3 as outputs
  PORTB |= (1<<PB2); // Red LED off
  PORTB &= ~(1<<PB3); // Green LED on

 

-----------

DDRB=(1<<PB2) | (1<<PB3);

PORTB= (1<<PB1) | (1<<PB2;

   is all you need

  use =  when you initially set things, so there is no ambiguity or uncertainty

 

  // PB2 and PB3 set as outputs for LEDs ...is somewhat useless comment, since you can just look at DDRB

 

maybe say DDRB=(1<<PB2) | (1<<PB3); // PB3 is red led, PB2 is blu led, PB0 is abort switch 

Watch you don't clog your screen with lines of stuff that prevent you from looking at your code...if you can't see code, you won't see your errors/typos.

use names ...instead of PB2, use REDLED   , much less chance of error  DDRB |= (1 << REDLED);   //will be on when warming up

 

 

 

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

Never put a delay in an interrupt handler.

Happy Trails,

Mike

JaxCoder.com

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

Set up a timer to overflow every 20ms, in the ISR() for the timer overflow, poll (read) the status of the button, you debounce by counting the number of consecutive times you see the button pushed, 2,3, 4 etc. if button is not pressed, reset count back to zero. when you see the count is high enough, set a global flag saying the button is pressed. This can also be used for short vs long presses too.

Using interrupt pins for buttons is not a good idea as buttons bounce and can cause multiple interrupts to happen very quickly, better to poll and a timer interrupt is a good place to do that.

 

Jim

 

 

Keys to wealth:

Invest for cash flow, not capital gains!

Wealth is attracted, not chased! 

Income is proportional to how many you serve!

 

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

Just search for the word "bounce" (perhaps also "debounce") here on Freaks as this has all been discussed a thousand times and many good solutions have been presented. Also just generally Google "Jack Ganssle bounce" and read what you find - it remains one of the best descriptions of the contact bounce problem and possible ways to solve it.

 

Bottom line, as Jim said, is do not use INTn interrupts with buttons (unless it's simply being used as a wakeup from SLEEP on the press of a button). Most button reading is done in a timer interrupt that just samples the state of the buttons each time. If any have been seen in the same state for a number of successive interrupts then consider the button is now in that state.

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

The "best" debounce also debounces the release.  So small glitches during pressed are not treated as released.

 

Say you are holding down a debounced button to deliver a ton of coal.  But your finger is a little shaky & the switch contact is dirty & falsely looks like you released the switch.  Now without release debouncing, it thinks the switch opened, and the pressed debouncing thereafter thinks you've pressed it again. All of a sudden you get an extra ton of coal dumped on your feet.

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

Last Edited: Tue. Sep 14, 2021 - 03:53 PM