STM32 HAL Tutorial: Handling Push Buttons and Debouncing
Abstract
Learn how to configure STM32 GPIO input pins using CubeMX and HAL drivers. Step-by-step tutorial on controlling an LED with a push button and handling debouncing.
1. Introduction
In Episode 2, we learned how to blink an LED using STM32 HAL drivers.
Now, it’s time to read input from GPIO pins—a fundamental skill for interactive embedded systems.
In this episode, you’ll learn:
- How to configure GPIO pins as input.
- How to read button presses.
- How to control an LED based on button input.
- Techniques for debouncing mechanical switches.
This project will make your board react to user input, laying the foundation for more complex applications.
2. Prerequisites
Make sure you have:
- A STM32 board (e.g., Nucleo or Discovery).
- One push button (or use the on-board USER button).
- One LED (on-board LED works).
- STM32CubeIDE installed with a previously generated project (from Episode 2).
3. Configuring GPIO Input Pins in CubeMX
Step 1 – Open Your STM32CubeMX
- Create a new project for the [STM32G071RBT6]
Step 2 – Set Button Pin Mode
- Find the USER button pin, PC13 on NUCLEO-G071RB.
- Click the pin → select GPIO_Input.
- Optionally, enable Pull-Up if the button doesn’t have a resistor, which is not the case for the selected hardware:
📌 Pull-up ensures the pin reads HIGH when the button is not pressed.
Step 3 – Verify LED Pin
- Ensure your LED pin is still configured as GPIO_Output. Refer to EP2 in case you have issues.
Step 4 – Generate Code
- Click Project → Generate Code.
- CubeMX updates the HAL initialization for your input pin.
4. Writing Button-Controlled LED Code
/* USER CODE BEGIN WHILE */
while (1)
{
// Read button state
if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_RESET) // Button pressed
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); // Turn LED ON
}
else
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); // Turn LED OFF
}
}
/* USER CODE END WHILE */
Code Explanation
- HAL_GPIO_ReadPin(GPIOx, PINx) → Reads HIGH or LOW from the button.
- GPIO_PIN_RESET indicates the button is pressed (due to pull-up resistor).
- HAL_GPIO_WritePin() sets the LED state based on button input.
5. Handling Button Debouncing
Mechanical buttons may generate multiple signals when pressed. This is called bouncing.
Simple Debounce Method
Add a short delay after detecting a press:
if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_RESET)
{
HAL_Delay(50); // Wait 50ms
if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_RESET)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // Toggle LED
while(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_RESET); // Wait for release
}
}
Tip: 50ms delay is usually enough for most buttons.
6. Compiling and Running the Project
Step 1 – Build
- Click Build (hammer icon) in STM32CubeIDE or [Ctrl + B].
Step 2 – Flash
- Connect your STM32 board via USB.
- Enter in Debug Mode and Run the code
Step 3 – Test
- Press the button: LED should toggle ON/OFF.
- Release button: LED remains in last state.
- Monitor the GPIOA ODR5 and GPIOC IDR13 in the [SFRs].
7. Common Issues & Fixes
| Issue | Cause | Solution |
|---|---|---|
| LED doesn’t respond to button | Wrong GPIO pin | Check CubeMX configuration |
| LED toggles multiple times | Button bouncing | Implement debounce using HAL_Delay() |
| Compilation error | Pin or HAL not initialized | Regenerate CubeMX code |
8. Hands-On Lab Recap
You’ve learned:
- How to configure GPIO pins as input using CubeMX.
- How to read push button states with HAL.
- How to control an LED with a button.
- How to debounce a mechanical switch.
This adds interactivity to your STM32 projects, preparing you for timers, interrupts, and sensors in the next tutorials.
9. What’s Next
In Episode 4, we’ll explore External Interrupts (EXTI):
- Configure GPIO pins to trigger interrupts.
- Learn real-time button handling without polling.
- Improve performance and responsiveness for embedded applications.


