Skip to main content
Graduate
September 21, 2024
Solved

External interrupt and button debounce

  • September 21, 2024
  • 2 replies
  • 6738 views

Hi all,

 I currently work on STM32F030K6 .

I am working with a reed switch connected to pin PA8 (EXTI8).

I havec onfigured the PIN like : "external Interrupt Mode rising/falling ....
I need to perform an action on the rising edge AND on the falling edge.
But since the switch is slow there are certainly bounces.
What would be the good method to not detect the bounces.
I tried to set a timer but it does not work. I tried to disable the interrupts but it does not work either.

 

I have create a test code like this.

 

 

 while (1)
 {
	 if (Bouton_WU == 1) // ILS
	 {		 
		 HAL_Delay(500);
		 Bouton_WU = 0;
		 Envoi_msg();
	 } 
	 if (test > 5)
	 {
		 test = 0;
	 }
}

 

 

 

 

 

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	switch (GPIO_Pin)
	{
		case ILS_Pin:	Bouton_WU = 1; 
 test++; 
		 break;
	}
}

 

 

 

I tried to use the function :  "HAL_NVIC_DisableIRQ(EXTI4_15_IRQn);"   in several places in the code without succes.

I tried to put some HAL_delays without succes.

I used the debugger to watch the value of my variable "test", and the value is higher 10 in every change of my switch.

 

do you have any idea to deal with the problem ?


thanks for reading me

 

    This topic has been closed for replies.
    Best answer by gbm

    For a button, you always need a timer interrupt. So - there is no point in using any other interrupt.

    Add the code similar to this to SysTick ISR: (define BUTTON_PRESSED macro to return non-zero when button is pressed)

    #define BUTTON_PRESSED (~B1_GPIO->IDR & B1_PIN)
    static uint8_t btn_div;
    
    if (btn_div == 20)
    {
     btn_div = 0;
     static bool btn_prev;
     bool btn_curr = BUTTON_PRESSED;
     if (!btn_prev && btn_curr)
     onButtonPressed();
     btn_prev = btn_curr;
    }

     

    2 replies

    Super User
    September 22, 2024

    There are many methods for debouncing a switch in software. This is the one I prefer:

    • When the pin changes state, assume the state change is real (i.e. act upon the switch press) and set a timer. If the pin changes state within, say, 50 ms of when that timer is set, ignore the new state. You can use HAL_GetTick() for this check.

    If you don't have noise on the line, this is a good method since it lets you respond instantly to the event.

    JJoao.1Author
    Graduate
    September 22, 2024

    Thank for your answer TDK,

    But in fact the pin change state so quickly.

    I don't know why i can't put a HAL_Delay() in the interrupt ! 

    I try to wake up by standby mode, and I need to determinate wich pin wake up the STM32 and in which sens ( up to down or down to up)

     

     

    while (1)
     {
    	 if (Bouton_WU == 1) // ILS
    	 {		 
    		 HAL_Delay(500);
     printf ("test=%u\r\n",test);
    		 Bouton_WU = 0;
     test = 0;
    		 //do something
     GoToStopMode();
     }
     }
    void GoToStopMode(void)
    {
    	//Sleep wake up by EXTI
    }
    
    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    {
    	switch (GPIO_Pin)
    	{
    		case ILS_Pin:						
    						Bouton_WU = 1;
    						test++;
    						break;
    
    		break;
    	}
    }

     

     

    Here is the result every time I switch.

    In one way it's ok, but in the other way I have some bounces

     

    Test:1 
    Test:6 
    Test:1 
    Test:5 
    Test:1 
    Test:5
     
     
     

     

     

     

    Graduate II
    September 22, 2024

    >>I don't know why i can't put a HAL_Delay() in the interrupt ! 

    Typically because that needs an interrupt to work, one that can preempt the interrupt you're now in and blocking. Interrupts ideally complete almost immediately, not linger half a second blocking darn near everything..

    It would make more sense to flag the initial event, and then monitor subsequently in the SysTick handler at every 1ms from then on out.

    You can time stamp the event in the EXTI, either with the HAL Tick count, or a much higher resolution count from a maximal, free-running, TIM via TIM->CNT register.

    gbmAnswer
    Graduate
    September 22, 2024

    For a button, you always need a timer interrupt. So - there is no point in using any other interrupt.

    Add the code similar to this to SysTick ISR: (define BUTTON_PRESSED macro to return non-zero when button is pressed)

    #define BUTTON_PRESSED (~B1_GPIO->IDR & B1_PIN)
    static uint8_t btn_div;
    
    if (btn_div == 20)
    {
     btn_div = 0;
     static bool btn_prev;
     bool btn_curr = BUTTON_PRESSED;
     if (!btn_prev && btn_curr)
     onButtonPressed();
     btn_prev = btn_curr;
    }