This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430G2553 - Debounce Problem

Other Parts Discussed in Thread: MSP430G2553

Hi ,  I'm  inexperienced about microcontrollers and i'm  having a problem with switch debouncing   on MSP430G2553/Launchpad...

First , my  "project' is :    2 LEDS + 1 BUZZER + 3 Push Buttons connected to MSP430 ,     Every time a switch is pressed , buzzer  should   ''beep''.   When key 1 is pressed , LED 1 turns ON ,  when key 2 is pressed, LED 2  turns ON   , and  key 3  turns off  /reset  all the LEDs .

This is my code  at this moment :

#include <msp430g2553.h>

#define    LED1     BIT3         //LED1 on P1.3    , LED2 on P1.4   , KEY1 on P2.0 , KEY2 on P2.1 , KEY3 on P2.2 , BUZZER on P1.5
#define    LED2     BIT4
#define    BUZZER   BIT5
#define    BOTAO_1  BIT0
#define    BOTAO_2  BIT1
#define    BOTAO_3  BIT2

volatile unsigned  int botao = 5;

void main(void)
{
    WDTCTL = WDTPW + WDTHOLD;                 //desativa WDT
     P1SEL = 0x00;
     P2SEL &= ~(BOTAO_1+BOTAO_2+BOTAO_3);
     P1SEL2 = 0x00;
     P2SEL2 &= ~(BOTAO_1+BOTAO_2+BOTAO_3);
     P1DIR |= LED1 + LED2 + BUZZER;

    P2DIR &= ~(BOTAO_1 + BOTAO_2 + BOTAO_3);   //ENTRADAS
    P2REN |=  BOTAO_1 + BOTAO_2 +  BOTAO_3;    //PULL'S
    P2OUT &= ~(BOTAO_1 + BOTAO_2 + BOTAO_3);   //PULL DOWN

 P2IE  |=  BOTAO_1 + BOTAO_2 + BOTAO_3;            //ativa interrupçoes
 P2IES &= ~(BOTAO_1 + BOTAO_2 + BOTAO_3);     // BORDA SUBIDA
 P2IFG &= ~(BOTAO_1 + BOTAO_2 + BOTAO_3);    //LIMPA FLAGS

  P1OUT &= ~(LED1+LED2);   //limpa porta 

  BCSCTL3|= XCAP_3;

  for(;;)
  {

     _BIS_SR(LPM3_bits + GIE);                       // entra no modo de descanso  ate ocorrer interrupção pelas portas


 switch (botao) {
     case 1:                                          
         P1OUT |= LED1;
         break;
     case 2:
         P1OUT |= LED2;
         break;
     case 3:
         P1OUT&= ~(LED1+LED2);
         break;
      }

  }

}


#pragma vector=PORT2_VECTOR     //interrupçao caso algum botao seja pressionado
__interrupt void Port_2(void)
{
    
    if(BOTAO_1 & P2IFG )         //checa de onde veio a interrupção
        botao=1;
    if(BOTAO_2 & P2IFG )
        botao=2;
    if(BOTAO_3 & P2IFG )
        botao=3;                                           //DEBOUNCING:

    P2IE &= ~(BOTAO_1+BOTAO_2+BOTAO_3);          //desativa interrupçao pela porta
    P2IFG = 0x00;                                 //limpa flag

    WDTCTL = WDT_ADLY_250;
    IFG1 &= ~WDTIFG;
    IE1 |= WDTIE;                         

    //BEEP:

        volatile int i = 3000;
        P1OUT |= BUZZER;             //liga buzzer
        do{ i--; }while(i!=0);         //delay para bip
        P1OUT &= ~BUZZER;             //desliga buzzer

_bic_SR_register_on_exit(LPM3_bits);

}


#pragma vector=WDT_VECTOR
__interrupt void WDT(void)
{
    IE1 &= ~WDTIE;                                           //desliga interrupçao por wdt
    IFG1 &= ~WDTIFG;                                      //limpa flag      
    WDTCTL = WDTPW + WDTHOLD;              //stop wdt
    P2IE |= (BOTAO_1+BOTAO_2+BOTAO_3);    //religa interrupçao nas portas           //DEBOUNCING FINISHED
}

//////////////////////////////

This is debouncing is not  working well ...   When i press one key , sometimes more than 1 beep happens ... !

Can everyone help me  with that ?

Thanks

  • Hi!

    I'm just trying to help!

    Perhaps if you change this:

     do{ i--; }while(i!=0);

    For this:

    __delay_cycles(100000);

    You are gonna be luckier :) Can you give it a try?

  • Henrique Tann��s said:
            do{ i--; }while(i!=0);         //delay para bip


    'empty' loops are usually optimized away by the compiler. The trick of using a volatile variable to force the compiler into doing the increments/decrements, doesn't work for local variables, as the compiler knows for sure that optimizing them away cannot have any side-effects (since the variable is auto-created by the compiler itself)

    However, th eproblem with your code is that you clea rthe IE bits and IFG bits inside the port ISR, but when the timer has expired, more interrupt smay have been flagged (IFG bits set) in the meantime. So as soon as you re-enable the IE bits, the port interrupt is called once more.

    A quick hack would be to clear P2IFG in the tiemr ISR right before setting the IE bits.

    But a better way (which also would eliminate spikes) would be to just disable the interrupts in the port ISR and start the tiemr. And when the timer expires, check the then current state of the port bits, do the necessary action and re-enable the interrupts.

    However, for the beep, you shouldn't do the waiting loop inside an ISR. ISRs are fast-in, fast-out. No place for busy-waiting loops or delays. use a timer instead. (if you're clever, you can use the WDT for this: do not enable port interrupts but wait for the next call of the WDT ISR, then deactivat ethe beeper and re-activate the port interrupts. Requires a static/global variable for the current state of operation)

  • Thank you both...!     * I didn't know that _delay_cycles(x) exists  rsrs

    Jens-Michael ,

    I don't understand well  why more  interrupts may have been flagged while the WDT is "timing" .. Considering that IE bits were cleared ( and the interrupts disabled ) as soon as i used the Flag for Switch Case ...   

     Could you explain me more ?

  • Henrique Tann��s said:
    Considering that IE bits were cleared

    The IE bits (if clear) only prevent the ISR from being called. They do not prevent the IFG bits from being set when an interrupt event happens. So the interrupt is already 'on hold' and as soon as you set the IE bits again...

    In other words:

    if (IE && IFG) call_ISR();

    Where IE is oly changed by user and IFG is changed by user or hardware.

  • Jens-Michael Gross said:
    The IE bits (if clear) only prevent the ISR from being called. They do not prevent the IFG bits from being set when an interrupt event happens. So the interrupt is already 'on hold' and as soon as you set the IE bits again...

    Now I think I understand ...    

    I used to think  that  only changings on IFG bits that occurred After setting IE bits would call a ISR.  I substituted all empty loops for _delay_cycles()  and  put a cleaning  P2IFG instruction   before setting P2IE at the end of WDT ISR.

    I removed "Beep instructions"  from   Port2-ISR  and put them  inside of main()  , just like this :

    for(;;)
      {



         _BIS_SR(LPM3_bits + GIE);     // entra no modo de descanso  ate ocorrer interrupção pelas portas

        P1OUT |= BUZZER;             //liga buzzer
         _delay_cycles(30300);        //delay para bip
        P1OUT &= ~BUZZER;             //desliga buzzer



     switch (botao){
         case 1:
             P1OUT |= LED1;
             break;
         case 2:
             P1OUT |= LED2;
             break;
         case 3:
             P1OUT&= ~(LED1+LED2);
             break;
          }
     

    So , everytime a button is pressed   ISR will be called  and after returning from it ,   a Beep will occurs.

    And now...   it's   working  fine !  :)

    Jens-Michael Gross said:

    But a better way (which also would eliminate spikes) would be to just disable the interrupts in the port ISR and start the tiemr. And when the timer expires, check the then current state of the port bits, do the necessary action and re-enable the interrupts.

    However, for the beep, you shouldn't do the waiting loop inside an ISR. ISRs are fast-in, fast-out. No place for busy-waiting loops or delays. use a timer instead. (if you're clever, you can use the WDT for this: do not enable port interrupts but wait for the next call of the WDT ISR, then deactivat ethe beeper and re-activate the port interrupts. Requires a static/global variable for the current state of operation)

     

     I will try to do these  suggestions ... !

    Thanks

**Attention** This is a public forum