STM32F411寄存器级编程求助:按键控制LED状态无响应
Let's break down the issues in your code step by step—there are a few register configuration mistakes and a logic error that's causing your LED to stay on regardless of the button state.
1. Incorrect GPIO Mode Register (MODER) Configuration
The MODER register uses 2 bits per pin to set the mode, so you can't just toggle single bits with |= ~(bit)—that will corrupt other bits in the register.
For PA5 (LED Pin):
Your code tries to set PA5 to output mode, but this line is wrong:
GPIOA->MODER |= ~(1<<11);
Instead, you need to first clear the two bits for PA5 (bits 10 and 11) before setting them to output mode (01):
// Clear PA5's MODER bits first GPIOA->MODER &= ~(3 << 10); // Set PA5 to general purpose output mode (01) GPIOA->MODER |= (1 << 10);
For PC13 (Button Pin):
Your code for PC13's MODER is also incorrect. To set it to input mode (the default, but we should explicitly clear it to avoid unintended changes):
// Clear PC13's MODER bits (bits 26 and 27) GPIOC->MODER &= ~(3 << 26); // Leave as input mode (00, which is reset state, so no need to set anything here)
2. Wrong Pull-Up/Pull-Down Register (PUPDR) Setup
PC13's PUPDR configuration is broken—again, it uses 2 bits per pin. You want a pull-up resistor (since most user buttons pull the pin low when pressed), so we need to set bits 26 and 27 to 01:
// Clear PC13's PUPDR bits first GPIOC->PUPDR &= ~(3 << 26); // Set PC13 to pull-up mode (01) GPIOC->PUPDR |= (1 << 26);
3. Incorrect Button State Reading
You're reading the entire IDR register into var, which is an 8-bit variable. The IDR is a 32-bit register, so var = GPIOC->IDR; will only capture the lower 8 bits (not PC13, which is bit 13). Instead, you need to isolate just the PC13 bit:
// Read PC13 state: shift bit 13 down to bit 0, then mask to get 0 or 1 var = (GPIOC->IDR >> 13) & 1;
Also, with a pull-up resistor, the button will read 1 when released and 0 when pressed. Your original logic checks if var == 0 to turn on the LED, which is correct for a low-active button—but only if you're reading the right bit!
4. (Optional) Add Button Debouncing
Mechanical buttons bounce, so you might see flickering or incorrect state changes. A simple software debounce can fix this—add a small delay after reading the button state before acting on it. For example:
while(1) { var = (GPIOC->IDR >> 13) & 1; if(var == 0) // Button pressed (low) { // Debounce: wait a bit and recheck for(uint32_t i=0; i<10000; i++); if(((GPIOC->IDR >> 13) & 1) == 0) { GPIOA->BSRR = (1 << 5); // Turn LED on } } else // Button released (high) { GPIOA->BSRR = 1 << (5 + 16); // Turn LED off } }
Corrected Full Code
Here's the fixed version of your code with all the above changes:
#include "stm32f4xx.h" /* NOTES USER LED IS ON PIN A5 USER BUTTON IS ON PIN C13 */ uint8_t var=0; int main(){ RCC->AHB1ENR |=(1<<0); //Clock on port A RCC->AHB1ENR |=(1<<2); //Clock on port C //PORT A PIN 5 Config (Output) GPIOA->MODER &= ~(3 << 10); // Clear PA5 MODER bits GPIOA->MODER |= (1 << 10); // Set to general purpose output mode GPIOA->OSPEEDR |= ((1<<11)|(1<<10)); // High speed (optional, but okay) //PORT C PIN 13 Config (Input with Pull-Up) GPIOC->MODER &= ~(3 << 26); // Clear PC13 MODER bits (set to input) GPIOC->OSPEEDR |= ((1<<27)|(1<<26)); // High speed (optional) GPIOC->PUPDR &= ~(3 << 26); // Clear PC13 PUPDR bits GPIOC->PUPDR |= (1 << 26); // Set to pull-up mode while(1) { var = (GPIOC->IDR >> 13) & 1; // Isolate PC13 state if(var == 0) // Button pressed { GPIOA->BSRR = (1 << 5); // LED on } else // Button released { GPIOA->BSRR = 1 << (5 + 16); // LED off } } }
Quick Testing Tips
- Double-check your board's schematic to confirm the button's active state (some boards use pull-down instead of pull-up—if the LED stays off instead, swap the logic to check
var == 1). - Use a debugger to step through the code and check the values of
GPIOC->IDRwhen pressing/releasing the button—this will help confirm if you're reading the pin correctly.
内容的提问来源于stack exchange,提问作者Ivan Rob

