当前位置: 首页 > news >正文

01-03GPIO-按键控制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. 检测按键1if (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计数一次,避免占用过多CPUpress_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_Hvoid 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();  // 初始化LEDKey_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_Hvoid 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();                  // 熄灭LEDis_led_off_by_key1 = 1;     // 标记状态:已被按键1熄灭}// 2. 按键2短按:仅在“LED已被按键1熄灭”的状态下,才点亮LEDelse if (key_state == KEY2_SHORT && is_led_off_by_key1 == 1){LED_ON();                   // 点亮LEDis_led_off_by_key1 = 0;     // 重置状态:已被按键2点亮}
}

LED_Func3.h

点击查看代码
#ifndef __LED_FUNC3_H
#define __LED_FUNC3_Hvoid 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_Hvoid 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_Hvoid 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_Hvoid 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"  // 启用功能6int 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();  // 启用功能6while (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}
}
http://www.jsqmd.com/news/17237/

相关文章:

  • 2025 年防火涂料厂家最新推荐!膨胀型 / 非膨胀型 / 室内外 / 超薄型 / 厚型钢结构防火涂料品牌排行榜,精选优质厂家
  • 打通CI/CD最后一公里:制品库如何成为高效流水线的核心枢纽
  • 2025年10月高端奢侈家电品牌推荐排行榜及深度对比分析
  • 嵌入式调式方案:
  • DevExpress WinForms v25.1亮点 - 电子表格组件、富文档编辑器全新升级
  • 高效实现内外网文件传输方法介绍与解决方案
  • 2025年GEO品牌推荐排行榜前十强权威发布
  • 2025年GEO品牌推荐榜与排行榜Top10:权威解析与行业洞察
  • 2025年10月高端奢侈家电品牌推荐排行榜单对比与评测分析
  • 第五章 linux实战-CMS01
  • windows下命令
  • vLLmOllama推理部署以及压测对比
  • 2025年10月高端奢侈家电品牌推荐排行榜:五大品牌综合对比与选购指南
  • A. Vasya and Petyas Game
  • [nvidia docker]
  • vite插件——vite-plugin-inspect
  • ceph管理后台dashboard部署
  • CRMEB标准版订单核销的业务逻辑
  • 内外网文件摆渡系统有哪些?一文读懂主流方案与选型方向
  • mysql 更新默认时间
  • autohotkey 控制输入法
  • 【最新推荐】分享十大常用又靠谱的文件摆渡系统
  • C语言实现LDPC码译码功能
  • 关系型数据库的基本理论
  • [NOIP 2012 提高组] 开车旅行 的AC代码
  • Voice Chat: Resolving Lag and Stuttering with a Jitter Buffer
  • 2025 年报警器经销商最新推荐榜单:全面剖析海湾、青鸟等品牌服务商优势,为您筛选优质可靠合作伙伴燃气 / 太阳能 / 交通道路报警器推荐
  • 2025 年报警器经销商最新推荐榜单:全面剖析海湾、青鸟等品牌服务商优势,为您筛选优质可靠合作伙伴燃气 / 太阳能 / 交通道路报警器推荐
  • 解决IDEA引入依赖报错
  • 线性DP,区间DP