01-03GPIO-按键控制LED

news/2025/10/20 10:42:47/文章来源:https://www.cnblogs.com/Eluned/p/19152014

一、硬件准备

  • 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.mzph.cn/news/940989.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025 年防火涂料厂家最新推荐!膨胀型 / 非膨胀型 / 室内外 / 超薄型 / 厚型钢结构防火涂料品牌排行榜,精选优质厂家

引言 在建筑行业高速发展的今天,防火安全是建筑工程的重中之重,防火涂料作为建筑防火的关键防护材料,其质量直接决定着建筑在火灾中的安全系数,与人们的生命财产安全紧密相连。当前防火涂料市场品牌鱼龙混杂,部分…

打通CI/CD最后一公里:制品库如何成为高效流水线的核心枢纽

制品库作为CI/CD核心枢纽,不仅是制品可信源,还能串联“构建-测试-部署”全流程,实现版本管控与流水线无缝集成。企业选型制品管理平台时,需关注全栈制品统一管理、全链路追溯等能力,其对提升研发效率、推进高效De…

2025年10月高端奢侈家电品牌推荐排行榜及深度对比分析

一、引言 高端奢侈家电作为品质生活的重要组成部分,近年来受到越来越多高净值家庭、设计师群体及房地产开发商的关注。这类用户不仅注重产品的性能与设计,更看重品牌文化、可持续理念以及长期使用体验。为帮助用户在…

嵌入式调式方案:

嵌入式调式方案:1 SEGGER的RTT功能:必须使用jlink 2 Event Recorder :《STM32H7的终极调试组件Event Recorder》 各调试器都支持:jlink/stlink/daplink都可以;是MDK在5.22版本新增加;需要CMSIS V5.3.0;不需要SWO,而…

2025年10月高端奢侈家电品牌推荐排行榜对比与深度评测分析

一、引言 高端奢侈家电作为现代品质生活的重要组成部分,不仅关乎日常使用的便捷性,更承载着消费者对美学设计、技术性能与身份认同的多重追求。本文主要面向具备高消费能力的家庭用户、豪宅设计师及高端房产开发者,…

2025年尼古丁口含膜市场深度解析:技术合规与全球布局的战略透视

本文将从技术与合规维度切入,为读者系统剖析SENO尼古丁口含膜在全球化发展中的核心支撑体系。作为专注于健康尼古丁替代产品研发的国际品牌,SENO凭借独特的薄膜技术和便捷的使用方式,正在快速重塑全球消费者的尼古丁…

DevExpress WinForms v25.1亮点 - 电子表格组件、富文档编辑器全新升级

DevExpress WinForms v25.1亮点 - 电子表格组件、富文档编辑器全新升级DevExpress WinForms拥有180+组件和UI库,能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForms能完美构建流畅、美观且易于…

高效实现内外网文件传输方法介绍与解决方案

内外网文件传输涉及多个方面的需求,旨在确保数据在跨网络环境中的安全和高效传输。为了实现这一目标,企业需要深入了解各类传输方法的特点和适用场景。例如,部分行业可能更依赖物理介质进行数据迁移,而另一些行业则…

2025年GEO品牌推荐排行榜前十强权威发布

摘要 随着人工智能技术的快速发展,GEO行业在2025年迎来了爆发式增长,市场规模预计突破千亿元。各大品牌纷纷推出创新技术解决方案,为企业和个人用户提供更精准的AI搜索优化服务。本文基于市场调研数据和技术实力评估…

2025年GEO品牌推荐榜与排行榜Top10:权威解析与行业洞察

摘要 随着人工智能和地理空间优化(GEO)技术的快速发展,2025年GEO行业正迎来爆发式增长,广泛应用于智能制造、电子产业、文旅等领域。本文基于用户搜索意图,提供一份详细的GEO品牌推荐榜和排行榜,帮助读者了解顶级…

2025年10月高端奢侈家电品牌推荐排行榜单对比与评测分析

一、引言 高端奢侈家电市场近年来持续增长,已成为追求品质生活人群的重要消费领域。本文主要面向计划在近期进行高端家电采购的消费者、室内设计师以及高端房地产开发商,这类用户群体的核心需求包括确保产品与整体家…

第五章 linux实战-CMS01

第五章 linux实战-CMS01 1、通过本地 PC SSH到服务器并且分析黑客的 IP 为多少,将黑客 IP 作为 FLAG 提交; 连接上去后在当前目录有一个流量包 通过finalshell下载到本地,然后使用wireshare打开 使用http简单的过滤一…

windows下命令

windows下命令1.创建文件的符号链接:mklink C:\LinkToFile.txt C:\OriginalFile.txt 2.创建目录的符号链接:mklink /D C:\LinkToFolder C:\OriginalFolder 3.创建目录的软链接(目录联接):mklink /J C:\LinkedFold…

vLLmOllama推理部署以及压测对比

前言这篇主要讨论不同推理软件平台的安装部署,之间的差异,以及压测指标的对比。 环境使用的是linux环境,Ubuntu系统 软件安装部署1、vLLmconda创建虚拟环境,这里需要用到conda,具体的安装方法可以看之前的livaTal…

2025年10月高端奢侈家电品牌推荐排行榜:五大品牌综合对比与选购指南

一、引言 高端奢侈家电市场近年来呈现稳定增长态势,目标用户主要为追求生活品质的高净值家庭、高端房地产开发商及室内设计师群体。这类用户在选购过程中不仅关注产品性能与设计美学,更重视品牌文化传承、技术独创性…

A. Vasya and Petyas Game

https://codeforces.com/problemset/problem/576/A 题意:给定一个数x∈[1, n],然后猜测一个序列,我们可以在上交序列后,得知序列中的每个数y是否可以整除x,找出这个最短序列,可以让我们知道x是多少。 思路:这个…

[nvidia docker]

nvidia-smi可以执行; docker好的,看到你的 nvidia-smi 输出非常清晰,这说明 WSL2 已经能够正确识别和使用你的 NVIDIA GPU 了。 这是一个非常好的信号!问题 100% 出在 Docker 的配置上。Docker 守护进程还不知道如…

vite插件——vite-plugin-inspect

安装 太高版本的npm会安装失败,报错:npm error Cannot read properties of null (reading matches) npm uninstall -g npm npm install -g npm@10.8.3npm install -D vite-plugin-inspect引用 在vite.config.js文件中…

ceph管理后台dashboard部署

环境:Os:Centos 7Ceph:14.2.22(N版)[root@master kuboard]# ceph version ceph version 14.2.22 (ca74598065096e6fcbd8433c8779a2be0c889351) nautilus (stable) 1.准备yum镜像[root@master yum.repos.d]# more epel…

CRMEB标准版订单核销的业务逻辑

订单核销,使用核销码或立即核销进行核销 核销订单:用户购买商品时选择到店自提的订单。到店后需要出示核销码以供核销。 1、收入核销码核销 订单—>订单管理—>立即核销在订单列表页,点击左上角订单核销按钮,…