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.
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
Henrique Tann��s said:do{ i--; }while(i!=0); //delay para bip
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 ?
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...Henrique Tann��s said:Considering that IE bits were cleared
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