cancel
Showing results for 
Search instead for 
Did you mean: 

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

FPicc.1
Senior

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++;
}

1 ACCEPTED SOLUTION

Accepted Solutions

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.

View solution in original post

7 REPLIES 7
Peter BENSCH
ST Employee

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

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
Pavel A.
Evangelist III

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.

 

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.
Pavel A.
Evangelist III

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

 

@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? 

PGump.1
Senior III

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

 

AI = Artificial Intelligence, NI = No Intelligence, RI = Real Intelligence.

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.