The [STM32](https://www.ampheo.com/search/STM32) Black Pill (usually based on [STM32F401](https://www.ampheo.com/search/STM32F401) / F411) makes button input very straightforward, because GPIO pins support internal pull-up and pull-down [resistors](https://www.onzuu.com/category/resistors). Below is the recommended, industry-standard approach. ![hq720 (55)](https://hackmd.io/_uploads/HyRr_mAHWl.jpg) **1. Understand the Tactile Button (4-Pin Type)** A common tactile push button has 4 pins: ``` [ A ] [ A ] [ B ] [ B ] ``` * Pins on the same side are internally connected * When pressed: A ↔ B are shorted You only need one A pin and one B pin **2. Recommended Wiring (Internal Pull-Up)** **Why pull-up?** * Fewer external components * Stable default state * Widely used in STM32 designs **Wiring Diagram (Concept)** ``` STM32 GPIO ──────┐ ├───[ Button ]─── GND GND ──────────────┘ ``` **Physical Connections** | Button Pin | Connect To | | -------------- | --------------------- | | One side (A) | STM32 GPIO (e.g. PA0) | | Other side (B) | GND | ✔ No external resistor needed ✔ Uses STM32 internal pull-up **3. GPIO Configuration (CubeMX / HAL)** **GPIO Settings** * Mode: GPIO Input * Pull-up / Pull-down: Pull-Up * Speed: Low (default) When not pressed: `GPIO = HIGH (1)` When pressed: `GPIO = LOW (0)` **4. Example Code (HAL, STM32CubeIDE)** **Read Button State** ``` if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET) { // Button pressed } ``` Because: * Pull-up → default HIGH * Press → pin pulled to GND → LOW **5. Full Example: Toggle LED with Button** ``` uint8_t last_state = 1; while (1) { uint8_t current_state = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0); if (last_state == 1 && current_state == 0) { HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); // LED HAL_Delay(50); // debounce } last_state = current_state; } ``` **6. Button Debouncing (Very Important)** **Why?** Mechanical buttons bounce for 5–20 ms, causing multiple false triggers. **Software Debounce (Simple)** `HAL_Delay(20);` **Better (Timer-Based)** * Sample every 1 ms * Require stable state for N samples **Hardware Debounce (Optional)** ``` GPIO ──┬── Button ── GND | 100nF | GND ``` **7. Alternative Wiring: Internal Pull-Down** If you prefer active-high logic: ``` 3.3V ─── Button ─── GPIO GPIO internal pull-down ``` | State | GPIO | | -------- | ---- | | Released | LOW | | Pressed | HIGH | Either method is fine—pull-up is more common. **8. Using External Interrupt (EXTI) (Advanced & Clean)** Instead of polling: **GPIO Config** * Mode: GPIO_EXTI * Trigger: Falling Edge (pull-up case) **Callback Example** ``` void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin == GPIO_PIN_0) { HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); } } ``` ✔ Lower CPU usage ✔ Cleaner logic ✔ Ideal for low-power designs **9. Electrical Rules You Must Follow** **Important** * STM32 GPIO is 3.3V only * Do NOT connect button to 5V * Always share common GND * Never leave input floating (use pull-up/down) **10. Common Mistakes (Very Common)** ❌ Using diagonal pins of the button incorrectly ❌ Forgetting pull-up / pull-down ❌ No debounce handling ❌ Mixing 5V logic ❌ Assuming button is NO/NC (it’s momentary) **11. Quick Recommendation (Best Practice)** **Button → GND + GPIO with internal pull-up + EXTI interrupt** This is: * Stable * Minimal components * Industry-standard for [STM32](https://www.ampheoelec.de/search/STM32)