STM32F103ZET6 按键初始化与控制逻辑
在嵌入式系统开发里,按键是最基础且常用的人机交互外设。通过按键,我们能实现设备的状态切换、功能触发等操作。本文基于 STM32,详细拆解 WKUP、KEY0、KEY1 三个按键的驱动配置,以及它们各自的控制逻辑,帮助大家理解如何在 STM32 中实现按键功能。一、按键硬件电路分析这些按键可用于实现不同功能,比如控制 LED 灯状态、触发蜂鸣器播放音乐、系统复位等。二、按键初始化配置。
在嵌入式系统开发里,按键是最基础且常用的人机交互外设。通过按键,我们能实现设备的状态切换、功能触发等操作。本文基于 STM32,详细拆解 WKUP、KEY0、KEY1 三个按键的驱动配置,以及它们各自的控制逻辑,帮助大家理解如何在 STM32 中实现按键功能。
一、按键硬件电路分析

从原理图可知:
- WKUP 按键:连接 PA0 引脚,一端接 3V3 电源,按下时 PA0 引脚会检测到高电平,未按下时由电路配置决定电平(后续代码会配置为下拉输入,初始为低电平 )。
- KEY0 按键:连接 PE4 引脚,一端接地,按下时 PE4 引脚检测到低电平,未按下时由电路配置为上拉输入,保持高电平 。
- KEY1 按键:连接 PE3 引脚,一端接地,按下时 PE3 引脚检测到低电平,未按下时由电路配置为上拉输入,保持高电平 。
这些按键可用于实现不同功能,比如控制 LED 灯状态、触发蜂鸣器播放音乐、系统复位等。
二、按键初始化配置
(一)WKUP 按键初始化(wkup_config函数)
void wkup_config(void){
#ifdef c
// 库函数方式:使能GPIOA时钟,配置PA0为下拉输入
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef key_wkup;
key_wkup.GPIO_Pin = GPIO_Pin_0;
key_wkup.GPIO_Mode = GPIO_Mode_IPD; // 下拉输入
GPIO_Init(GPIOA,&key_wkup);
#else
// 寄存器方式:使能GPIOA时钟,配置PA0为上拉/下拉输入模式并设置为下拉
RCC->APB2ENR |= (0X1 << 2);
GPIOA->CRL &= ~(0XF);
GPIOA->CRL |= (0X8); // 上拉下拉输入模式
GPIOA->ODR &= ~(0x1); // 设置为下拉模式,初始低电平
#endif
}
- 库函数方式通过
RCC_APB2PeriphClockCmd使能 GPIOA 时钟,利用GPIO_InitTypeDef结构体配置 PA0 为下拉输入模式(GPIO_Mode_IPD)。 - 寄存器方式直接操作
RCC->APB2ENR使能时钟,通过配置GPIOA->CRL寄存器设置引脚模式,再用GPIOA->ODR设置初始电平为下拉。
(二)KEY0 和 KEY1 按键初始化(库函数方式)
void key0_config(void){
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
GPIO_InitTypeDef key_key0;
key_key0.GPIO_Pin = GPIO_Pin_4;
key_key0.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
GPIO_Init(GPIOE,&key_key0);
GPIO_SetBits(GPIOE,GPIO_Pin_4); // 设置初始高电平
}
void key1_config(void){
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
GPIO_InitTypeDef key_key1;
key_key1.GPIO_Pin = GPIO_Pin_3;
key_key1.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
GPIO_Init(GPIOE,&key_key1);
GPIO_SetBits(GPIOE,GPIO_Pin_3); // 设置初始高电平
}
对于 KEY0 和 KEY1,因为它们一端接地,所以配置为上拉输入模式(GPIO_Mode_IPU ),这样未按下时引脚保持高电平,按下时变为低电平。通过GPIO_SetBits设置初始高电平,确保初始化状态正确。
三、按键状态获取与功能实现

(一)WKUP 按键:控制 LED 灯状态(get_wkup_state函数)
// 按键状态定义
#define KEY_UP 0
#define KEY_DOWN 1
uint8_t get_wkup_state(uint8_t *key_state) {
uint8_t result = 255;
uint8_t key_pressed = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0); // 高电平表示按下
// 检测按键状态变化
if (key_pressed && (*key_state == KEY_UP)) {
// 按键按下处理,消抖
delay_ms(10);
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)) {
// 等待释放
while (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)) {};
*key_state = KEY_DOWN;
// 切换LED(PB5)状态
//这个代码的逻辑就是翻转PB5的电平
GPIO_WriteBit(GPIOB, GPIO_Pin_5,
(BitAction)(1 - GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_5)));
result = 0;
}
}
else if (key_pressed && (*key_state == KEY_DOWN)) {
// 按键释放处理,消抖
delay_ms(10);
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)) {
// 等待按下
while (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)) {};
*key_state = KEY_UP;
// 切换LED(PB5)状态
GPIO_WriteBit(GPIOB, GPIO_Pin_5,
(BitAction)(1 - GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_5)));
result = 1;
}
}
return result;
}
- 定义
KEY_UP和KEY_DOWN表示按键的两种状态。 - 通过
GPIO_ReadInputDataBit读取 PA0 引脚电平,判断按键是否按下。 - 加入消抖处理(
delay_ms(10)),避免按键机械抖动导致误判。 - 当按键状态变化时,切换 PB5 引脚控制的 LED 灯状态,实现按下或释放按键时 LED 状态翻转。
(二)KEY0 按键:控制另一路 LED 灯状态(get_key0_state函数)
uint8_t get_key0_state(uint8_t *key_state) {
uint8_t result = 255;
uint8_t key_pressed = !GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4); // 低电平表示按下
// 检测按键状态变化
if (key_pressed && (*key_state == KEY_UP)) {
// 按键按下处理,消抖
delay_ms(10);
if (!GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4)) {
// 等待释放
while (!GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4)) {};
*key_state = KEY_DOWN;
// 切换LED(PE5)状态
GPIO_WriteBit(GPIOE, GPIO_Pin_5,
(BitAction)(1 - GPIO_ReadOutputDataBit(GPIOE, GPIO_Pin_5)));
result = 0;
}
}
else if (key_pressed && (*key_state == KEY_DOWN)) {
// 按键释放处理,消抖
delay_ms(10);
if (!GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4)) {
// 等待按下
while (!GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4)) {};
*key_state = KEY_UP;
// 切换LED(PE5)状态
GPIO_WriteBit(GPIOE, GPIO_Pin_5,
(BitAction)(1 - GPIO_ReadOutputDataBit(GPIOE, GPIO_Pin_5)));
result = 1;
}
}
return result;
}
- KEY0 连接 PE4 引脚,低电平表示按下,所以用
!GPIO_ReadInputDataBit判断。 - 功能与 WKUP 按键类似,不过是控制 PE5 引脚的 LED 灯状态,实现按下或释放时 LED 状态翻转。
(三)KEY1按键:控制蜂鸣器播放音乐,见蜂鸣器博客
按键KEY1控制蜂鸣器/复位
uint8_t get_key1_state(uint8_t *key_state) {
uint8_t result = 255;
uint8_t key_pressed = !GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_3); // 低电平表示按下
// 检测按键状态变化
if (key_pressed && (*key_state == KEY_UP)) {
// 按键按下处理
delay_ms(10); // 消抖
if (!GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_3)) {
// 等待释放
while (!GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_3)) {};
*key_state = KEY_DOWN;
// 播放音乐
play_two_tigers();
result = 0;
}
}
else if (key_pressed && (*key_state == KEY_DOWN)) {
// 按键长按处理(触发复位)
delay_ms(10); // 长按确认
if (!GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_3)) {
// 等待释放
while (!GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_3)) {};
*key_state = KEY_UP;
// 触发系统复位
system_reset();
result = 1;
}
}
return result;
}
四、按键功能整合与应用
在主程序或其他逻辑中,可通过不断调用这些get_xxx_state函数来检测按键状态,执行相应操作,示例如下:
int main(void)
{
uint8_t wkup_state = KEY_UP;
uint8_t key0_state = KEY_UP;
uint8_t key1_state = KEY_UP;
// 按键初始化
wkup_config();
key0_config();
key1_config();
// 其他初始化(如LED、蜂鸣器等)
while(1)
{
get_wkup_state(&wkup_state);
get_key0_state(&key0_state);
get_key1_state(&key1_state);
// 可在此根据按键状态执行更多逻辑
}
}
通过循环检测按键状态,能实时响应按键操作,实现 LED 控制、音乐播放、系统复位等功能,构建完整的人机交互逻辑。
####当然目前是轮询方式检测按键,在后续按键中断控制灯的博客可以看到中断的方式,提高系统效率,让 CPU 在按键未操作时处理其他任务,有按键事件时再响应。
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐

所有评论(0)