文档
STM32 HAL:GPIO 流水灯与按键控制
目标
基于 STM32CubeMX 生成的 HAL 工程,实现 3 个 LED 流水灯和按键切换流水方向。
硬件配置(CubeMX)
- MCU:STM32F407VGT6(Nucleo-F407ZG,其他 F4/F1/H7 类似)
- LED1-3:PD12、PD13、PD14(Nucleo 板载 LED 为 LD4=PD12, LD5=PD13, LD6=PD14)
- 按键:PC13(Nucleo 蓝色用户按键),上拉输入,按下为低电平
- 时钟:HSE 8MHz → PLL 168MHz(F407 最大)
完整代码
/* main.c — 流水灯 + 按键方向控制,非阻塞实现 */
#include "main.h"
/* 外设句柄(CubeMX 自动生成) */
extern TIM_HandleTypeDef htim2; /* 用于非阻塞定时 */
/* LED 配置 */
#define LED_COUNT 3
const uint16_t LED_PINS[LED_COUNT] = {
GPIO_PIN_12, // PD12 - LED1 (绿)
GPIO_PIN_13, // PD13 - LED2 (橙)
GPIO_PIN_14 // PD14 - LED3 (红)
};
GPIO_TypeDef *const LED_PORT = GPIOD;
/* 按键配置 */
#define KEY_PORT GPIOC
#define KEY_PIN GPIO_PIN_13
/* 全局状态 */
typedef enum { FORWARD, REVERSE } Direction;
static Direction dir = FORWARD;
static uint8_t active_led = 0;
static uint32_t last_toggle_tick = 0;
static uint32_t last_key_check = 0;
/* ── 初始化 ── */
void led_init(void) {
for (int i = 0; i < LED_COUNT; i++) {
HAL_GPIO_WritePin(LED_PORT, LED_PINS[i], GPIO_PIN_RESET);
}
HAL_TIM_Base_Start(&htim2);
}
/* ── 按键扫描(消抖 + 检测下降沿) ── */
uint8_t key_pressed(void) {
static uint8_t last_state = 1;
uint8_t now = HAL_GPIO_ReadPin(KEY_PORT, KEY_PIN);
if (last_state == 1 && now == 0) { // 下降沿
HAL_Delay(20); // 消抖
if (HAL_GPIO_ReadPin(KEY_PORT, KEY_PIN) == 0) {
last_state = now;
return 1; // 有效按下
}
}
last_state = now;
return 0;
}
/* ── 流水灯更新 ── */
void led_shift(void) {
// 先全部关闭
for (int i = 0; i < LED_COUNT; i++) {
HAL_GPIO_WritePin(LED_PORT, LED_PINS[i], GPIO_PIN_RESET);
}
// 点亮当前 LED
HAL_GPIO_WritePin(LED_PORT, LED_PINS[active_led], GPIO_PIN_SET);
// 根据方向移动
if (dir == FORWARD) {
active_led = (active_led + 1) % LED_COUNT;
} else {
active_led = (active_led == 0) ? (LED_COUNT - 1) : (active_led - 1);
}
}
/* ── 主循环 ── */
int main(void) {
HAL_Init();
SystemClock_Config(); // CubeMX 生成
MX_GPIO_Init(); // CubeMX 生成
MX_TIM2_Init(); // CubeMX 生成,TIM2 用于基准计时
led_init();
uint32_t now;
while (1) {
now = HAL_GetTick();
// 流水灯定时 (200ms)
if (now - last_toggle_tick >= 200) {
last_toggle_tick = now;
led_shift();
}
// 按键检测 (每 10ms)
if (now - last_key_check >= 10) {
last_key_check = now;
if (key_pressed()) {
dir = (dir == FORWARD) ? REVERSE : FORWARD;
// LED 快速闪烁指示方向切换
for (int i = 0; i < 2; i++) {
HAL_GPIO_WritePin(LED_PORT, LED_PINS[1], GPIO_PIN_SET);
HAL_Delay(50);
HAL_GPIO_WritePin(LED_PORT, LED_PINS[1], GPIO_PIN_RESET);
HAL_Delay(50);
}
}
}
}
}
运行步骤
- STM32CubeMX 打开
.ioc→ 引脚配置 PD12-14 为 Output,PC13 为 Input(上拉) - TIM2 使能(用作
HAL_GetTick()的时基),生成代码 - 将上述
main.c替换 CubeMX 生成的 main 函数体 - 编译下载:
arm-none-eabi-gcc或 CubeIDE → Run - 观察 LED 流水效果,按蓝色用户按键切换方向
预期行为
- 3 个 LED 以 200ms 间隔依次点亮形成流水效果
- 按一次按键,方向反转(逆流水)
- 切换时中间 LED 快闪两次确认
关键点
HAL_GetTick()由 SysTick 中断驱动(默认 1ms),用作非阻塞定时基准- 按键消抖用硬件延时 20ms + 二次确认
- 避免在中断或主循环中使用
HAL_Delay做长延时(阻塞型)