bouton-hal.c
The board user button (GPIOA/GPIO_PIN_0, active HIGH) toggles the LED on each press. 50 Hz sampling debounce is the standard embedded-C pattern, with no interrupt nor blocking delay.
Hardware
A Blue Pill STM32F103C8T6 (Cortex-M3 @ 72 MHz, 64 KB flash) powered by micro-USB or external 3.3 V; programmed over SWD or the serial bootloader. Nothing to start with: the user button is factory-wired. Optionally an external button to 3.3 V.
Wiring
Internal button: already tied to GPIOA/GPIO_PIN_0 (bouton externe vers 3,3 V, la carte n'a pas de bouton utilisateur). External button: between the pin and 3.3 V, internal pull-down.
How it works
Every 20 ms the pin state is read and stored; a 0→1 transition (rising edge) calls HAL_GPIO_TogglePin. Two identical consecutive samples filter the bounce.
Running it
STM32CubeIDE project (STM32F103C8) or Arduino (STM32 core): program over SWD (ST-LINK, DAPLink adapter) or the serial bootloader (BOOT0 to 1). Note: PC13 LED is active LOW.
Variants
Move to an EXTI interrupt with HAL_GPIO_EXTI_Callback, or add a long-press (sample counter).
bouton-hal.c
// Bouton utilisateur + LED, anti-rebond par echantillonnage.
#include "main.h"
#define LED_PORT GPIOC
#define LED_PIN GPIO_PIN_13
#define BTN_PORT GPIOA
#define BTN_PIN GPIO_PIN_0
/* Bouton actif a l'etat HIGH. */
uint32_t tEchantillon = 0;
uint8_t stable = 0, precedent = 0;
int main(void) {
HAL_Init();
SystemClock_Config();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
GPIO_InitTypeDef g = {0};
g.Pin = LED_PIN; g.Mode = GPIO_MODE_OUTPUT_PP;
HAL_GPIO_Init(LED_PORT, &g);
g.Pin = BTN_PIN; g.Mode = GPIO_MODE_INPUT; g.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(BTN_PORT, &g);
for (;;) {
if (HAL_GetTick() - tEchantillon >= 20) { // 50 Hz
tEchantillon = HAL_GetTick();
precedent = stable;
stable = (HAL_GPIO_ReadPin(BTN_PORT, BTN_PIN) == GPIO_PIN_SET);
if (stable && !precedent) { // front montant
HAL_GPIO_TogglePin(LED_PORT, LED_PIN);
}
}
}
}