STM32F103C8T6基础开发教程(HAL库)—按键控制LED灯状态切换

张开发
2026/4/13 20:36:50 15 分钟阅读

分享文章

STM32F103C8T6基础开发教程(HAL库)—按键控制LED灯状态切换
1. 硬件连接与原理分析先来看看我们要用到的硬件部分。STM32F103C8T6开发板上通常会有多个GPIO引脚我们需要选择一个引脚连接LED灯另一个引脚连接按键。这里我建议使用PB0作为LED控制引脚PA0作为按键检测引脚因为这两个引脚在大多数开发板上都容易找到。LED的连接方式有两种常见方案一种是LED正极接VCC负极接GPIO这种需要低电平点亮另一种是LED正极接GPIO负极接GND这种需要高电平点亮。我建议采用第二种方式因为STM32的GPIO输出高电平时驱动能力更强。实际接线时记得串联一个220Ω-1kΩ的限流电阻防止电流过大烧坏LED。按键的连接也有讲究。最简单的方式是按键一端接地另一端接GPIO引脚同时需要在GPIO引脚上加一个上拉电阻STM32内部有可配置的上拉电阻。这样当按键按下时GPIO会检测到低电平松开时检测到高电平。2. STM32CubeMX工程配置打开STM32CubeMX按照以下步骤配置2.1 GPIO引脚配置首先配置LED控制引脚为输出模式在Pinout视图中找到PB0引脚右键选择GPIO_Output在左侧GPIO配置中将PB0的初始状态设为Low这样上电时LED默认熄灭然后配置按键引脚为输入模式找到PA0引脚右键选择GPIO_Input在GPIO配置中将PA0的上拉/下拉设为Pull-up使用内部上拉电阻2.2 时钟配置在Clock Configuration标签页中确保HSE外部高速时钟已启用将系统时钟配置为72MHz输入72后按回车检查APB1和APB2的时钟分频设置2.3 生成工程在Project Manager标签页设置工程名称和存储路径选择Toolchain/IDE为MDK-ARMKeil在Code Generator中勾选Generate peripheral initialization as a pair of .c/.h files点击Generate Code按钮生成工程3. Keil代码编写打开生成的Keil工程我们需要在main.c文件中添加按键检测和LED控制逻辑。3.1 主循环实现在while(1)循环中添加以下代码while (1) { // 检测按键状态 if(HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) GPIO_PIN_RESET) { // 按键消抖延时 HAL_Delay(20); // 确认按键确实按下 if(HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) GPIO_PIN_RESET) { // 翻转LED状态 HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); // 等待按键释放 while(HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) GPIO_PIN_RESET); // 释放消抖延时 HAL_Delay(20); } } /* USER CODE END WHILE */ }这段代码实现了按键消抖和LED状态切换功能。HAL_GPIO_TogglePin函数会自动翻转指定引脚的电平状态比手动写HAL_GPIO_WritePin更简洁。3.2 按键消抖原理机械按键在按下和释放时会产生抖动通常持续10-20ms。如果不处理一次按键可能会被误判为多次按下。我们的解决方案是检测到按键按下后延时20ms再次检测确认按键状态确认按下后执行操作等待按键释放并再次消抖4. 程序下载与调试4.1 使用ST-Link下载连接ST-Link到开发板的SWD接口SWCLK、SWDIO、GND、3.3V在Keil中配置调试器点击Options for Target在Debug标签选择ST-Link Debugger在Utilities标签勾选Use Debug Driver点击Load按钮下载程序4.2 使用串口下载连接USB转TTL模块到开发板的UART1PA9-TX、PA10-RX使用FlyMcu等工具下载hex文件注意设置正确的波特率和启动模式5. 功能扩展与优化5.1 添加LED状态指示可以在程序中添加一个变量来记录LED当前状态uint8_t led_state 0; // 0表示熄灭1表示点亮 // 在按键处理中更新状态 if(HAL_GPIO_ReadPin(LED_GPIO_Port, LED_Pin) GPIO_PIN_SET) { led_state 1; } else { led_state 0; }5.2 实现长按功能通过检测按键按下的时间可以实现长按功能uint32_t press_time 0; if(HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) GPIO_PIN_RESET) { HAL_Delay(20); if(HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) GPIO_PIN_RESET) { press_time HAL_GetTick(); while(HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) GPIO_PIN_RESET) { // 检测长按时间 if(HAL_GetTick() - press_time 1000) { // 长按1秒执行的操作 HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET); break; } } if(HAL_GetTick() - press_time 1000) { // 短按执行的操作 HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); } HAL_Delay(20); } }5.3 使用中断方式检测按键为了提高效率可以使用外部中断检测按键在CubeMX中将按键引脚配置为GPIO_EXITx模式在NVIC设置中启用对应的中断在stm32f1xx_it.c中添加中断处理代码void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin KEY_Pin) { HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); } }6. 常见问题排查6.1 LED不亮可能原因及解决方法检查LED极性是否接反测量GPIO引脚电压确认输出正常检查限流电阻值是否合适确认CubeMX中配置的引脚与实际硬件一致6.2 按键不响应排查步骤用万用表测量按键按下时GPIO电压变化检查上拉电阻配置是否正确确认消抖延时时间是否足够检查按键GPIO模式是否为输入6.3 程序运行不稳定可能原因系统时钟配置错误电源不稳定复位电路有问题代码中存在死循环我在实际项目中遇到过按键响应不灵敏的情况后来发现是消抖延时太短。调整到20ms后就稳定了。建议大家在调试时使用HAL_GetTick()函数打印时间戳这样可以更直观地了解程序运行情况。

更多文章