2024-04-25 12:00 PM
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++;
}
Solved! Go to Solution.
2024-04-26 12:52 PM - edited 2024-04-26 01:16 PM
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.
2024-04-25 12:25 PM
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
2024-04-25 01:58 PM
> 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.
2024-04-25 03:19 PM
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:
2024-04-25 04:05 PM
Then there's the jitter. Reply of @Peter BENSCH , above.
2024-04-25 04:38 PM
@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?
2024-04-25 10:43 PM
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
2024-04-26 12:52 PM - edited 2024-04-26 01:16 PM
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.