Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

Interrupt‑Driven Button Press Counter (STM32 NUCLEO‑F446RE)

A bare‑metal firmware that counts button presses using a hardware interrupt instead of polling, and reports the running total over UART.

Every time the onboard button is pressed, the EXTI13 interrupt fires, the ISR toggles the LED and increments a counter, and the main loop prints the new value to the serial terminal.

This project marks the jump from polling (used in earlier projects) to event‑driven programming — the way real embedded systems respond to the outside world.


Polling vs Interrupts (Why This Project Matters)

Earlier projects did this:

while (1) {
    if (button_pressed()) do_something();   // CPU asks 1,000,000 times/sec
}

The CPU wastes almost all its time just checking.

This project does this:

while (1) {
    // CPU is free to do other work (or sleep)
}
// Hardware calls the ISR the instant the button is pressed

The button press is detected by hardware, not by software looping. This is the foundation of responsive, low‑power firmware.


How It Works

  1. system_init() configures GPIO, USART2, the EXTI line for PC13, and enables the NVIC interrupt.
  2. The main loop prints Press count: once.
  3. When the button is pressed (falling edge on PC13):
    • The EXTI13 line triggers.
    • The NVIC vectors to EXTI15_10_IRQHandler().
    • The ISR clears the pending flag, increments button_press_count, and toggles the LED.
  4. Back in main(), the loop notices the count changed and prints the new number over UART.

Hardware Needed

  • STM32 NUCLEO‑F446RE
  • USB cable

No external components required.


Pin Usage

Function Pin Role
LED PA5 Toggled inside the ISR
Button PC13 Mapped to EXTI line 13, falling edge
USART2_TX PA2 Prints the press count (AF7)
USART2_RX PA3 Configured (AF7), not used for input here

Concepts Demonstrated

  • EXTI (External Interrupt) configuration: EXTI_IMR, EXTI_FTSR, EXTI_PR
  • SYSCFG_EXTICR — mapping a GPIO port (Port C) onto an EXTI line (13)
  • NVIC — enabling the EXTI15_10 IRQ via NVIC_ISER1
  • ISR (EXTI15_10_IRQHandler) — the function the CPU jumps to on the event
  • Clearing the pending flag first inside the ISR (correct, safe practice)
  • volatile keywordbutton_press_count is shared between the ISR and main(), so the compiler must never optimize away the reads
  • Event‑driven designmain() only reacts to changes, not by constant polling of the pin
  • Falling‑edge trigger — the button is active LOW, so the press is the 1→0 transition
  • UART number printing — a hand‑written uart_send_number() for multi‑digit values
  • Register‑level RCC / GPIO / USART configuration (consistent with earlier projects)

Software Architecture

 Button press (PC13 falling edge)
            |
            v
   EXTI line 13  --(EXTI_FTSR / EXTI_IMR)--> pending flag (EXTI_PR)
            |
            v
   NVIC (NVIC_ISER1 bit 8)  -->  vectors to EXTI15_10_IRQHandler()
            |
            v
   ISR: clear EXTI_PR  ->  button_press_count++  ->  LED_TOGGLE()
            |
            v
   main() loop sees count changed  ->  uart_send_number() over USART2_TX (PA2)

Project Structure

stm32-interrupt-button-counter/
│
├── README.md
├── .gitignore
├── docs/
│   └── wiring.md
└── src/
    └── main.c

Build & Flash

  1. Open STM32CubeIDE
  2. Create a project for NUCLEO‑F446RE
  3. Replace Core/Src/main.c with the code from src/main.c
  4. Build (expect 0 errors)
  5. Flash to the board
  6. Open your terminal at 9600 baud and press the blue button

You should see the count climb on the terminal, and the LED toggle with every press.


Key Implementation Details

  • EXTI line → port mapping: SYSCFG_EXTICR4 bits [7:4] = 0x2 selects Port C for line 13. (SYSCFG clock on APB2 must be enabled — it is.)
  • IRQ vector name: EXTI15_10_IRQHandler is the shared vector for lines 10–15, so the ISR checks EXTI_PR & (1 << 13) to confirm it was line 13.
  • Flag clearing order: the pending bit is cleared before the action, which avoids missing a press that arrives during the ISR.
  • volatile: without it, the compiler could assume button_press_count never changes inside main() (since main() never writes it) and print 0 forever. volatile forces a fresh read each loop.
  • Baud rate: 9600 (USART2_BRR = 0x683 at 16 MHz APB1).

Future Improvements

  • Add software debouncing inside or around the ISR (a press can bounce and fire the interrupt several times)
  • Use a hardware timer to gate re‑triggering for a few ms after each press
  • Move UART printing fully out of the critical path with a small ring buffer
  • Add a second button on a different EXTI line to demonstrate multiple sources on the shared vector
  • Put the CPU into a low‑power sleep mode in main() and let the interrupt wake it (real low‑power design)

About

Bare-metal STM32 interrupt-driven button counter for NUCLEO-F446RE. EXTI13 + NVIC fire an ISR that toggles the LED and increments a volatile counter; main loop reports the count over USART2 — event-driven vs polling.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages