Skip to main content
Visitor II
April 25, 2024
Solved

ReadPin returns multiple increments when it's supposed to increment only one each ''read''

  • April 25, 2024
  • 4 replies
  • 2151 views

Hi all,

I want to increment the lap_marker variable only once when the lap_button is pressed, but when I press the button, it increments multiple times, untill I let go of the button (when I put a breakpoint in the loop it works fine).

I only want to increment once, Have I done something wrong? Is there another logic?

The pin is PC13, in input mode and the internal pull-down resistor activated.

Here is the code:

 

//Read lap button
if(HAL_GPIO_ReadPin(lap_button_GPIO_Port, lap_button_Pin))
{
lap_marker++;
}

    This topic has been closed for replies.
    Best answer by FPicc.1

    Here's what I did:

     

    //Lap button debouncing
    uint32_t previousMillis = 0;
    uint32_t currentMillis = 0;

    .

    .

    /* USER CODE BEGIN 4 */

    //Callback for GPIO Interrupt and button debounce
    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    {
    currentMillis = HAL_GetTick();
    if (GPIO_Pin == lap_button_Pin && (currentMillis - previousMillis > 10))
    {
    lap_marker++;
    previousMillis = currentMillis;
    }
    }

    /* USER CODE END 4 */

     

    It worked, but sometimes it increments 2 times, instead of one (1, 2, 3, 4, 5, 6, 8, for example)
    I'm using in falling edge, and in rising edge it increments 2 times always


    I based myself here: https://www.micropeta.com/video34

     

    Edit: I increased the value '10' for 100, expanding the period of comparison.

    4 replies

    Technical Moderator
    April 25, 2024

    You will most likely experience contact bounce, which typically occurs to a greater or lesser extent with mechanical switches, depending on their design. There are several ways to suppress such bouncing. You have obviously switched the button against VDD, right?

    In this case, you could very simply place a capacitor of 100nF between the GPIO (PC13 in your case) and VDD, with the switch connected to the GPIO via a resistor of approx. 100k. The capacitor is then charged via the pull-down with t= 100nF*Rpulldown ~5ms and discharged via the external resistor with t= 100nF*100k ~10ms when the button is pressed, which should suppress bouncing quite well. If you use a resistor of 1k instead of 100k, the discharge time is reduced to approx. 0.1ms, but the contact is loaded with a slightly higher current, which is favourable for the self-cleaning of the contact. You can try out which option is more suitable for your switch.

    Further information on debouncing can be found there, for example.

    Hope that helps?

    Regards
    /Peter

    Super User
    April 25, 2024

    Here is the code:

    Is this code fragment executed in a loop? Then obviously every time it executes and the button still is pressed, the variable will increment. Unless you want other logic there, configure the button pin as interrupt on the rising edge (0->1) and increment in the interrupt handler or callback.

     

    FPicc.1Author
    Visitor II
    April 25, 2024

    Yes, it's in the while loop.

    I activated EXTI13 in rising edge with a pull down, instead of a GPIO_Input, and called the callback, like this:

     

    /* USER CODE BEGIN 4 */
    //Callback for GPIO Interrupt
    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    {
    if(GPIO_Pin == lap_button_Pin)
    {
    lap_marker++;
    }
    }
     
    The distance between the increments have decreased, but I still can't increment only one when pressing the button.
    Super User
    April 25, 2024

    Then there's the jitter. Reply of @Peter BENSCH , above.

     

    FPicc.1Author
    Visitor II
    April 25, 2024

    @Peter BENSCH Tried putting a 100nF in parallel with Vcc and GPIO, and the 100kohm series resistor with the GPIO. It didn't change the value at all. When i put 50k, the distance is even smaller, but I still can't get only one increment.

    Isn't there anything wrong that I'm doing in the code? 

    Graduate II
    April 26, 2024

    Hi,

    You need to debounce, and latch your botton. Try this..

    /*
     Button down = pin high.
    	Minimum debounce (for both press and release) = 30mS.
    	Using a 5mS timer interrupt.
    
    	Fixed sampling timers, like the one below, have an iteration tolerance of +0, -1. So,
    	if your debounce time needs to be no less than 30mS, you will need to add 1 to the iteration count.
    	A 5mS timer makes it 7 (30-35mS debounce).
    */
    
    volatile bool button_pressed = false;
    
    #define DEBOUNCEDNMASK 0b01111111 /// = 7 bit mask = 2^((30 \ 5) + 1) - 1
    #define DEBOUNCEUPMASK DEBOUNCEDNMASK
    
    void timer_5mS_interrupt(void) {
    
    	static uint button_samples = 0;
    	static bool button_down = false;
    
    	button_samples <<= 1;
    	if ((my_button_port->input_data_register & my_button_bit) != 0) { // for active low button - change !=0 to ==0
    		button_samples++;
    	}
    
    	if ((button_samples & DEBOUNCEUPMASK) == 0) {
    		button_down = false;
    	}
    	else if ((button_samples & DEBOUNCEDNMASK) == DEBOUNCEDNMASK) {
    		if (!button_down) {
    			button_down = true;
    			button_pressed = true;
    		}
    	}
    }
    
    ------ meanwhile, back at main.c -------
    
    extern volatile bool button_pressed;
    
    main() {
    	...
    	if (button_pressed) {
    		button_pressed = false; /// acknowledge button_pressed
    		... handle button press
    	}
    	...
    }

    I hope this helps.

    Kind regards
    Pedro

     

    FPicc.1AuthorAnswer
    Visitor II
    April 26, 2024

    Here's what I did:

     

    //Lap button debouncing
    uint32_t previousMillis = 0;
    uint32_t currentMillis = 0;

    .

    .

    /* USER CODE BEGIN 4 */

    //Callback for GPIO Interrupt and button debounce
    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    {
    currentMillis = HAL_GetTick();
    if (GPIO_Pin == lap_button_Pin && (currentMillis - previousMillis > 10))
    {
    lap_marker++;
    previousMillis = currentMillis;
    }
    }

    /* USER CODE END 4 */

     

    It worked, but sometimes it increments 2 times, instead of one (1, 2, 3, 4, 5, 6, 8, for example)
    I'm using in falling edge, and in rising edge it increments 2 times always


    I based myself here: https://www.micropeta.com/video34

     

    Edit: I increased the value '10' for 100, expanding the period of comparison.