01-04GPIO-按键控制LED
一、硬件准备
- 1块STM32F103C8T6最小系统板
- 1个ST-LINK V2烧录器
- 两个按键
- 若干杜邦线
运用:
用按键控制板载PC13LED亮灭
延时函数同上
LED.h
点击查看代码
#ifndef __LED_H
#define __LED_H
#include "stm32f10x.h" // Device header
// PC13 宏定义LED端口和引脚
#define LED_PIN GPIO_Pin_13
#define LED_PORT GPIOC
//函数声明
void LED_Init(void); //LED GPIO初始化
void LED_ON(void); //LED点亮
void LED_OFF(void); //LED熄灭
void LED_Toggle(void); //LED翻转函数:切换LED的亮/灭状态
void LED_Blink(uint32_t times); //控制LED闪烁指定次数(times=闪烁次数,1次=亮200ms+灭200ms)
#endif
LED.c
点击查看代码
#include "LED.h"
#include "Delay.h"
// LED GPIO初始化(推挽输出,初始点亮)
void LED_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = LED_PIN;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(LED_PORT, &GPIO_InitStruct);
LED_ON(); // 初始状态:LED点亮
}
// LED点亮
void LED_ON(void)
{
GPIO_ResetBits(LED_PORT, LED_PIN);
}
// LED熄灭
void LED_OFF(void)
{
GPIO_SetBits(LED_PORT, LED_PIN);
}
// LED状态翻转(读取当前状态,反置)
void LED_Toggle(void)
{
if (GPIO_ReadOutputDataBit(LED_PORT, LED_PIN) == Bit_SET)
{
LED_ON();
}
else
{
LED_OFF();
}
}
// LED阻塞式闪烁:times=闪烁次数(1次=亮200ms+灭200ms)
void LED_Blink(uint32_t times)
{
for (uint32_t i = 0; i < times; i++)
{
LED_ON();
Delay_ms(200);
LED_OFF();
Delay_ms(200);
}
// 闪烁结束后恢复点亮状态
LED_ON();
}
Key.h
点击查看代码
#ifndef __KEY_H
#define __KEY_H
#include "stm32f10x.h" // Device header
//宏定义按键端口和引脚
#define KEY1_PORT GPIOB
#define KEY1_PIN GPIO_Pin_1
#define KEY2_PORT GPIOB
#define KEY2_PIN GPIO_Pin_0
//按键状态定义
#define KEY_NONE 0 //无按键
#define KEY1_SHORT 1 //按键1短按(按下后<500ms释放)
#define KEY1_LONG 2 //按键1长按(按下后>=500ms仍未释放)
#define KEY2_SHORT 3 //按键2短按
//长按判断时间(ms)
#define LONG_PRESS_TIME 500
//函数声明
void Key_Init(void); //按键初始化
uint8_t Key_Scan(void); //按键检测
uint8_t Key_CheckPress(void); //实时检测按键是否按下
#endif
Key.c
点击查看代码
#include "key.h"
#include "Delay.h"
void Key_Init(void)
{
// 开启GPIOB时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
// 配置GPIO参数
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; // PB1引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
// 阻塞式按键检测:返回按键状态(KEY_NONE/KEY1_SHORT/KEY1_LONG/KEY2_SHORT)
uint8_t Key_Scan(void)
{
// 1. 检测按键1
if (GPIO_ReadInputDataBit(KEY1_PORT, KEY1_PIN) == 0)
{
Delay_ms(20); // 消抖延时(20ms,过滤机械抖动)
if (GPIO_ReadInputDataBit(KEY1_PORT, KEY1_PIN) == 0) // 确认按键1真的按下
{
uint32_t press_time = 0;
// 2. 等待按键释放,同时计时
while (GPIO_ReadInputDataBit(KEY1_PORT, KEY1_PIN) == 0)
{
Delay_ms(10); // 每10ms计数一次,避免占用过多CPU
press_time += 10;
// 3. 若按下时间≥500ms,判定为长按
if (press_time >= LONG_PRESS_TIME)
{
// 等待按键释放后返回长按状态
while (GPIO_ReadInputDataBit(KEY1_PORT, KEY1_PIN) == 0);
Delay_ms(20); // 释放消抖
return KEY1_LONG;
}
}
// 4. 若按下时间<500ms,判定为短按
Delay_ms(20); // 释放消抖
return KEY1_SHORT;
}
}
// 5. 检测按键2(仅支持短按,逻辑同按键1简化版)
if (GPIO_ReadInputDataBit(KEY2_PORT, KEY2_PIN) == 0)
{
Delay_ms(20); // 消抖
if (GPIO_ReadInputDataBit(KEY2_PORT, KEY2_PIN) == 0)
{
while (GPIO_ReadInputDataBit(KEY2_PORT, KEY2_PIN) == 0); // 等待释放
Delay_ms(20); // 释放消抖
return KEY2_SHORT;
}
}
return KEY_NONE; // 无按键
}
// 实时检测按键是否按下(无消抖,用于功能4“按着灭、松开亮”)
uint8_t Key_CheckPress(void)
{
// 返回0=按键1按下,1=按键1未按下
return GPIO_ReadInputDataBit(KEY1_PORT, KEY1_PIN);
}
LED_Func1.h
点击查看代码
#ifndef __LED_FUNC1_H
#define __LED_FUNC1_H
void LED_Func1_Init(void);
void LED_Func1_Run(void);
#endif
LED_Func1.c
点击查看代码
//按键 1 控制 LED 亮灭切换(按一下灭 / 再按一下亮)
#include "LED_Func1.h"
#include "LED.h"
#include "Key.h"
void LED_Func1_Init(void)
{
LED_Init(); // 初始化LED
Key_Init(); // 初始化按键
}
//按一下按键1切换LED状态
void LED_Func1_Run(void)
{
uint8_t key = Key_Scan(); // 检测按键
if (key == KEY1_SHORT) // 按键1短按
{
LED_Toggle(); // 翻转LED(亮→灭/灭→亮)
}
}
LED_Func2.h
点击查看代码
#ifndef __LED_FUNC2_H
#define __LED_FUNC2_H
void LED_Func2_Init(void);
void LED_Func2_Run(void);
#endif
LED_Func2.c
点击查看代码
#include "LED_Func2.h"
#include "LED.h"
#include "Key.h"
// 状态标记:记录LED是否被按键1熄灭(0=未熄灭/亮,1=已熄灭)
static uint8_t is_led_off_by_key1 = 0;
void LED_Func2_Init(void)
{
// 初始化硬件:LED默认点亮,按键初始化
LED_Init(); // LED初始状态为亮(由LED_Init()保证)
Key_Init(); // 按键初始化(上拉输入)
// 初始状态:LED亮,未被按键1熄灭
is_led_off_by_key1 = 0;
}
void LED_Func2_Run(void)
{
uint8_t key_state = Key_Scan(); // 检测按键事件
// 1. 按键1短按:熄灭LED,并标记“已被按键1熄灭”
if (key_state == KEY1_SHORT)
{
LED_OFF(); // 熄灭LED
is_led_off_by_key1 = 1; // 标记状态:已被按键1熄灭
}
// 2. 按键2短按:仅在“LED已被按键1熄灭”的状态下,才点亮LED
else if (key_state == KEY2_SHORT && is_led_off_by_key1 == 1)
{
LED_ON(); // 点亮LED
is_led_off_by_key1 = 0; // 重置状态:已被按键2点亮
}
}
LED_Func3.h
点击查看代码
#ifndef __LED_FUNC3_H
#define __LED_FUNC3_H
void LED_Func3_Init(void);
void LED_Func3_Run(void);
#endif
LED_Func3.c
点击查看代码
//长按按键 1 灭、短按亮
#include "LED_Func3.h"
#include "LED.h"
#include "Key.h"
// 功能3专用:标记“是否已执行长按灭灯”
static uint8_t long_press_flag = 0;
void LED_Func3_Init(void)
{
LED_Init();
Key_Init();
}
void LED_Func3_Run(void)
{
uint8_t key = Key_Scan();
// 长按按键1且未灭灯→灭灯
if (key == KEY1_LONG && long_press_flag == 0)
{
LED_OFF();
long_press_flag = 1;
}
// 短按按键1且已灭灯→亮灯
else if (key == KEY1_SHORT && long_press_flag == 1)
{
LED_ON();
long_press_flag = 0;
}
}
LED_Func4.h
点击查看代码
#ifndef __LED_FUNC4_H
#define __LED_FUNC4_H
void LED_Func4_Init(void);
void LED_Func4_Run(void);
#endif
LED_Func4.c
点击查看代码
//按着按键 1 灭、松开亮
#include "LED_Func4.h"
#include "LED.h"
#include "key.h"
#include "Delay.h"
void LED_Func4_Init(void)
{
LED_Init();
Key_Init();
}
void LED_Func4_Run(void)
{
// 实时检测按键:按下(0)→灭,松开(1)→亮
if (Key_CheckPress() == 0)
{
LED_OFF();
}
else
{
LED_ON();
}
Delay_ms(10); // 降低CPU占用
}
LED_Func5.h
点击查看代码
#ifndef __LED_FUNC5_H
#define __LED_FUNC5_H
void LED_Func5_Init(void);
void LED_Func5_Run(void);
#endif
LED_Func5.c
点击查看代码
#include "LED_Func5.h"
#include "LED.h"
#include "Key.h"
#include "Delay.h"
static uint8_t is_blinking = 0; // 0=不闪烁,1=闪烁
void LED_Func5_Init(void)
{
LED_Init(); // 初始化LED(默认点亮)
Key_Init(); // 初始化按键
is_blinking = 0; // 强制初始为不闪烁
}
void LED_Func5_Run(void)
{
// 1. 非闪烁状态:检测按键
if (is_blinking == 0)
{
uint8_t key = Key_Scan();
// 短按:翻转LED(保持不变)
if (key == KEY1_SHORT)
{
LED_Toggle();
}
// 长按:强制进入闪烁(用最简单的逻辑)
else if (key == KEY1_LONG)
{
is_blinking = 1; // 标记为闪烁
// 调试:长按后立即翻转一次,直观看到进入闪烁
LED_Toggle();
}
}
// 2. 闪烁状态:循环翻转,直到按键释放
else
{
// 固定200ms翻转一次(简化逻辑)
Delay_ms(200);
LED_Toggle();
// 检测按键是否释放(释放则退出闪烁)
if (Key_CheckPress() == 1) // 1=释放
{
is_blinking = 0;
}
}
}
LED_Func6.h
点击查看代码
#ifndef __LED_FUNC6_H
#define __LED_FUNC6_H
void LED_Func6_Init(void);
void LED_Func6_Run(void);
#endif
LED_Func6.c
点击查看代码
//按一下闪烁 5 次
#include "LED_Func6.h"
#include "LED.h"
#include "Key.h"
void LED_Func6_Init(void)
{
LED_Init();
Key_Init();
}
void LED_Func6_Run(void)
{
uint8_t key = Key_Scan();
if (key == KEY1_SHORT) // 按一下按键1→闪烁5次
{
LED_Blink(5); // 阻塞式闪烁(结束后自动亮)
}
}
主函数main.c
点击查看代码
#include "stm32f10x.h"
// 1. 选择要启用的功能:包含对应功能的头文件(注释其他功能)
#include "LED_Func6.h" // 启用功能1(切换功能时,改这里的头文件名)
// #include "LED_Func2.h" // 启用功能2
// #include "LED_Func3.h" // 启用功能3
// #include "LED_Func4.h" // 启用功能4
// #include "LED_Func5.h" // 启用功能5
// #include "LED_Func6.h" // 启用功能6
int main(void)
{
// 2. 初始化选择的功能(对应头文件的Init函数)
LED_Func6_Init(); // 启用功能1(切换功能时,改这里的函数名)
// LED_Func2_Init(); // 启用功能2
// LED_Func3_Init(); // 启用功能3
// LED_Func4_Init(); // 启用功能4
// LED_Func5_Init(); // 启用功能5
// LED_Func6_Init(); // 启用功能6
while (1)
{
// 3. 循环执行功能逻辑(对应头文件的Run函数)
LED_Func6_Run(); // 启用功能1(切换功能时,改这里的函数名)
// LED_Func2_Run(); // 启用功能2
// LED_Func3_Run(); // 启用功能3
// LED_Func4_Run(); // 启用功能4
// LED_Func5_Run(); // 启用功能5
// LED_Func6_Run(); // 启用功能6
}
}

浙公网安备 33010602011771号