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

别再用Delay了!STM32按键控制LED的3种高级写法(中断、状态机、滤波)

别再用Delay了STM32按键控制LED的3种高级写法中断、状态机、滤波在嵌入式开发中按键控制LED是最基础的功能之一但很多开发者止步于简单的延时消抖实现。这种传统方法虽然容易理解却存在实时性差、资源浪费等明显缺陷。本文将带你突破基础探索三种更高效、更可靠的进阶实现方案。1. 延时消抖的局限性分析几乎所有STM32入门教程都会教你用Delay_ms()函数实现按键消抖就像这样if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_2) 0) { Delay_ms(20); while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_2) 0); Delay_ms(20); KeyNum 1; }这种方法的问题在于阻塞式等待Delay_ms()会占用CPU资源导致系统无法响应其他任务实时性差在延时期间所有中断和事件都无法得到及时处理消抖效果不稳定不同按键的抖动时间可能不同固定延时无法适应所有情况提示在RTOS或多任务系统中这种阻塞式延时会严重影响系统整体性能2. 外部中断方案即时响应的艺术2.1 中断配置与实现外部中断能立即响应按键动作不占用主循环资源。以下是配置步骤GPIO初始化设置为上拉输入模式NVIC配置设置中断优先级和使能EXTI配置选择触发边沿下降沿/上升沿// 中断初始化示例 void EXTI_Key_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; EXTI_InitTypeDef EXTI_InitStruct; NVIC_InitTypeDef NVIC_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); // GPIO配置 GPIO_InitStruct.GPIO_Pin GPIO_Pin_2; GPIO_InitStruct.GPIO_Mode GPIO_Mode_IPU; GPIO_Init(GPIOA, GPIO_InitStruct); // EXTI线配置 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource2); EXTI_InitStruct.EXTI_Line EXTI_Line2; EXTI_InitStruct.EXTI_Mode EXTI_Mode_Interrupt; EXTI_InitStruct.EXTI_Trigger EXTI_Trigger_Falling; EXTI_InitStruct.EXTI_LineCmd ENABLE; EXTI_Init(EXTI_InitStruct); // NVIC配置 NVIC_InitStruct.NVIC_IRQChannel EXTI2_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority 0x01; NVIC_InitStruct.NVIC_IRQChannelSubPriority 0x01; NVIC_InitStruct.NVIC_IRQChannelCmd ENABLE; NVIC_Init(NVIC_InitStruct); }2.2 中断服务函数实现在中断服务函数中我们需要处理消抖和状态确认void EXTI2_IRQHandler(void) { static uint32_t last_time 0; uint32_t current_time HAL_GetTick(); if(EXTI_GetITStatus(EXTI_Line2) ! RESET) { // 消抖处理两次中断间隔大于50ms才认为是有效按键 if(current_time - last_time 50) { LED_Turn(); // 翻转LED状态 } last_time current_time; EXTI_ClearITPendingBit(EXTI_Line2); } }优缺点对比表特性优点缺点响应速度即时响应无延迟需要硬件支持资源占用不占用主循环资源每个按键需要独立中断线复杂度中等需要处理中断嵌套问题适用场景需要快速响应的场合按键数量有限时3. 状态机实现灵活处理复杂逻辑3.1 状态机原理状态机(FSM)将按键过程分解为多个状态可以轻松实现单击、长按、双击等复杂功能空闲状态 → 按下检测 → 消抖确认 → 按下状态 → 释放检测 → 动作执行3.2 状态机实现代码typedef enum { KEY_STATE_IDLE, KEY_STATE_PRESS_DETECT, KEY_STATE_PRESS_CONFIRM, KEY_STATE_PRESSED, KEY_STATE_RELEASE_DETECT } Key_State; void Key_FSM_Handler(void) { static Key_State state KEY_STATE_IDLE; static uint32_t press_time 0; uint32_t current_time HAL_GetTick(); switch(state) { case KEY_STATE_IDLE: if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_2) 0) { state KEY_STATE_PRESS_DETECT; press_time current_time; } break; case KEY_STATE_PRESS_DETECT: if(current_time - press_time 20) { // 消抖 if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_2) 0) { state KEY_STATE_PRESS_CONFIRM; } else { state KEY_STATE_IDLE; } } break; case KEY_STATE_PRESS_CONFIRM: if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_2) 0) { state KEY_STATE_PRESSED; // 这里可以添加长按检测 } else { state KEY_STATE_IDLE; } break; case KEY_STATE_PRESSED: if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_2) ! 0) { state KEY_STATE_RELEASE_DETECT; press_time current_time; } break; case KEY_STATE_RELEASE_DETECT: if(current_time - press_time 20) { // 释放消抖 if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_2) ! 0) { LED_Turn(); // 执行按键动作 } state KEY_STATE_IDLE; } break; } }状态机扩展功能长按检测在PRESSED状态检测持续时间双击识别记录两次按下间隔时间组合键多个按键状态组合判断4. 软件滤波算法稳定可靠的选择4.1 滑动窗口滤波实现#define FILTER_WINDOW_SIZE 5 uint8_t Key_Filter(void) { static uint8_t filter_buf[FILTER_WINDOW_SIZE] {0}; static uint8_t index 0; uint8_t sum 0; filter_buf[index] (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_2) 0) ? 1 : 0; index (index 1) % FILTER_WINDOW_SIZE; for(uint8_t i 0; i FILTER_WINDOW_SIZE; i) { sum filter_buf[i]; } return (sum FILTER_WINDOW_SIZE) ? 1 : 0; }4.2 定时扫描滤波组合方案void Key_Scan_Task(void) { static uint8_t last_state 1; static uint32_t last_time 0; uint32_t current_time HAL_GetTick(); if(current_time - last_time 10) { // 10ms扫描一次 last_time current_time; uint8_t current_state Key_Filter(); if(last_state !current_state) { // 下降沿 LED_Turn(); } last_state current_state; } }滤波算法对比算法类型优点缺点适用场景滑动窗口实现简单效果稳定响应速度稍慢大多数应用中值滤波抗干扰能力强实现较复杂高噪声环境一阶滞后计算量小参数调整需要经验资源受限系统5. 方案选择与实践建议在实际项目中选择哪种方案取决于具体需求对实时性要求高优先考虑外部中断方案需要复杂按键逻辑状态机是最佳选择系统资源紧张软件滤波定时扫描更合适性能优化技巧将按键扫描放在定时器中断中确保扫描周期稳定使用位操作同时处理多个按键状态对于矩阵键盘可以采用行列扫描状态机的组合方案// 多按键状态处理示例 #define KEY_NUM 4 typedef struct { uint8_t current_state; uint8_t last_state; uint32_t press_time; } Key_Info; Key_Info keys[KEY_NUM]; void MultiKey_Scan(void) { for(uint8_t i 0; i KEY_NUM; i) { keys[i].last_state keys[i].current_state; keys[i].current_state Key_Filter(i); if(!keys[i].last_state keys[i].current_state) { keys[i].press_time HAL_GetTick(); // 按键按下事件处理 } if(keys[i].last_state !keys[i].current_state) { // 按键释放事件处理 } } }在最近的一个物联网设备项目中我们采用了状态机软件滤波的组合方案成功实现了单击、长按、双击三合一按键功能用户反馈操作体验明显优于传统实现方式。

相关文章:

别再用Delay了!STM32按键控制LED的3种高级写法(中断、状态机、滤波)

别再用Delay了!STM32按键控制LED的3种高级写法(中断、状态机、滤波) 在嵌入式开发中,按键控制LED是最基础的功能之一,但很多开发者止步于简单的延时消抖实现。这种传统方法虽然容易理解,却存在实时性差、资…...

告别Docker臃肿:PhpWebStudy轻量级本地开发环境终极指南

告别Docker臃肿:PhpWebStudy轻量级本地开发环境终极指南 【免费下载链接】PhpWebStudy Lightweight Native Local Dev Toolbox for Windows, macOS & Linux. Run Hermes Agent/OpenClaw/n8n/Apache/Nginx/Caddy/Tomcat/PHP/Node.js/Bun/Deno/Python/Java/Go/Rub…...

独立开发者如何借助 Taotoken 的透明计费模式精准控制 AI 应用成本

独立开发者如何借助 Taotoken 的透明计费模式精准控制 AI 应用成本 1. 理解 Taotoken 的计费机制 Taotoken 采用按实际消耗 token 计费的模式,这与直接调用大模型厂商 API 的计费方式一致。每 1000 个 token 作为一个计费单位,开发者可以在控制台的定价…...

WRF气象模式编译前传:手把手搞定netcdf-c-4.8.1、hdf5-1.10.5等7个核心依赖库

WRF气象模式编译前传:7大核心依赖库的深度解析与实战指南 气象数值模拟的世界里,WRF(Weather Research and Forecasting)模式无疑是科研与业务预报的利器。但在这把利剑出鞘之前,我们需要为其锻造坚实的剑鞘——编译环…...

企业安全自查:手把手教你用Python脚本检测金蝶Apusic应用服务器的任意文件上传漏洞

企业安全自查:Python自动化检测金蝶Apusic文件上传漏洞实战指南 金蝶Apusic应用服务器作为企业级中间件,承载着ERP、CRM等核心业务系统的稳定运行。近期曝光的任意文件上传漏洞可能让攻击者通过恶意文件植入获取服务器控制权,这对企业数据安全…...

如何在 Taotoken 平台快速接入 OpenAI 兼容 API 并调用多模型

如何在 Taotoken 平台快速接入 OpenAI 兼容 API 并调用多模型 1. 获取 API Key 与模型 ID 登录 Taotoken 控制台后,在「API 密钥」页面点击「创建新密钥」生成 API Key。建议复制并妥善保存该密钥,页面关闭后将无法再次查看完整内容。随后进入「模型广…...

告别if-else!用SVA断言给你的SystemVerilog验证代码做个大瘦身

用SVA断言重构SystemVerilog验证代码:从if-else到高效断言的艺术 在数字芯片验证领域,SystemVerilog Assertions (SVA) 正逐渐成为验证工程师的必备技能。传统验证代码中充斥着大量if-else语句和手写checker,不仅维护成本高,而且难…...

3分钟快速上手Vue Designer:让Vue组件开发告别浏览器刷新

3分钟快速上手Vue Designer:让Vue组件开发告别浏览器刷新 【免费下载链接】vue-designer Vue component design tool 项目地址: https://gitcode.com/gh_mirrors/vu/vue-designer 你是否厌倦了在Vue组件开发过程中频繁切换编辑器与浏览器的繁琐操作&#xff…...

终极指南:如何用XInputTest精准测试你的Xbox控制器性能

终极指南:如何用XInputTest精准测试你的Xbox控制器性能 【免费下载链接】XInputTest Xbox 360 Controller (XInput) Polling Rate Checker 项目地址: https://gitcode.com/gh_mirrors/xin/XInputTest 你是否在游戏中遇到过按键响应延迟的问题?明明…...

从博弈到共赢:深度解读oCPC中广告主、代理与平台的‘三国杀’困局

从博弈到共赢:深度解读oCPC中广告主、代理与平台的‘三国杀’困局 在数字广告的竞技场上,oCPC(优化每次转化成本)机制本应是连接广告主、代理服务商与广告平台三方的桥梁,却意外演变成了一场微妙的权力博弈。当广告主紧…...

2025年MIFARE Classic Tool完整指南:轻松掌握Android NFC标签管理

2025年MIFARE Classic Tool完整指南:轻松掌握Android NFC标签管理 【免费下载链接】MifareClassicTool An Android NFC app for reading, writing, analyzing, etc. MIFARE Classic RFID tags. 项目地址: https://gitcode.com/gh_mirrors/mi/MifareClassicTool …...

GLM-TTS:基于大语言模型与强化学习的高质量语音合成实战

1. 项目概述:当大语言模型“开口说话”如果你关注过近两年的AI发展,会发现一个有趣的现象:大语言模型(LLM)在文本理解和生成上已经取得了惊人的成就,但在“开口说话”——也就是语音合成(TTS&am…...

保姆级教程:在Ubuntu 20.04上为RK3588(ARM64)交叉编译Qt 5.15.2开发环境

保姆级教程:在Ubuntu 20.04上为RK3588(ARM64)交叉编译Qt 5.15.2开发环境 RK3588作为新一代高性能ARM64处理器,在边缘计算和嵌入式领域展现出强大潜力。而Qt框架凭借其跨平台特性和丰富的GUI组件库,成为开发嵌入式应用的…...

STM32H750驱动正点原子1.3寸屏,这个SPI4参数没设对,屏幕会卡顿黑屏

STM32H750驱动正点原子1.3寸屏的SPI4参数优化指南 第一次在STM32H750核心板上成功点亮正点原子1.3寸屏时,那种成就感确实让人兴奋。但当我在压力测试阶段遇到屏幕突然黑屏、显示卡顿甚至必须连接调试器才能工作的诡异现象时,这种兴奋很快被困惑取代。经过…...

产品经理和开发吵架?用‘用户故事地图’反推用例图,让需求落地不再扯皮

用户故事地图到用例图:化解产品与开发冲突的实战指南 会议室里的气氛凝固得像块冰。产品经理指着原型图强调"这个功能必须按用户习惯设计",开发组长则敲着桌子反驳"技术实现根本不合理"。这样的场景在敏捷团队中几乎每天都在上演——…...

OpenNext实战:将Next.js应用无缝部署至Cloudflare Workers边缘网络

1. 项目概述:当Next.js遇见Cloudflare Workers如果你和我一样,是个喜欢折腾前端部署的开发者,那你肯定对Next.js和Cloudflare Workers这两个名字不陌生。前者是React生态里最强大的全栈框架,后者是边缘计算领域的明星平台。长久以…...

别再傻傻分不清!一文搞懂蓝牙BR/EDR、BLE和LE2M到底有啥区别(附应用场景选择指南)

蓝牙技术全景解析:从BR/EDR到LE2M的实战选型指南 当你打开手机连接无线耳机时,是否想过背后是哪种蓝牙协议在默默工作?市面上超过90%的物联网设备都搭载了蓝牙模块,但开发者常陷入技术选型的迷雾。本文将用真实产品案例&#xff0…...

使用Taotoken聚合平台为你的Nodejs后端服务接入多模型能力

使用Taotoken聚合平台为你的Nodejs后端服务接入多模型能力 1. 多模型接入的核心价值 在现代Web应用开发中,集成AI功能已成为提升用户体验的重要手段。然而,直接对接多个大模型厂商往往面临接口差异、密钥管理复杂等问题。Taotoken作为大模型聚合分发平…...

Windows安卓应用安装终极指南:告别臃肿模拟器,体验轻量级APK安装方案

Windows安卓应用安装终极指南:告别臃肿模拟器,体验轻量级APK安装方案 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 你是否厌倦了在Windows上运…...

终极指南:3种方法在Windows上直接安装Android应用无需模拟器

终极指南:3种方法在Windows上直接安装Android应用无需模拟器 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 想在Windows电脑上流畅运行手机应用&#xff0…...

IntelliJ IDEA AI插件实战:用LLM自动化代码注释与文档生成

1. 项目概述:一个为开发者“减负”的智能助手如果你是一名开发者,尤其是使用 JetBrains 全家桶(比如 IntelliJ IDEA、PyCharm、WebStorm)的开发者,那么你一定对“写注释”、“写文档”、“解释代码”这类重复性工作深恶…...

Go-CQHTTP终极指南:构建跨平台QQ机器人的完整解决方案

Go-CQHTTP终极指南:构建跨平台QQ机器人的完整解决方案 【免费下载链接】go-cqhttp cqhttp的golang实现,轻量、原生跨平台. 项目地址: https://gitcode.com/gh_mirrors/go/go-cqhttp 在当今数字化时代,QQ机器人已经成为社群管理、客服自…...

从USB3.0到PCIe 5.0:高速串行链路耦合电容的‘规矩’与‘变通’全解析

从USB3.0到PCIe 5.0:高速串行链路耦合电容的设计哲学与技术演进 在数字通信领域,高速串行链路的设计犹如在钢丝上跳舞——需要在信号完整性与系统可靠性之间寻找精妙的平衡。耦合电容的放置策略,这个看似简单的设计选择,实则蕴含…...

炉石传说脚本终极指南:5个步骤掌握自动化对战工具

炉石传说脚本终极指南:5个步骤掌握自动化对战工具 【免费下载链接】Hearthstone-Script Hearthstone script(炉石传说脚本) 项目地址: https://gitcode.com/gh_mirrors/he/Hearthstone-Script Hearthstone-Script 是一款专为炉石传说玩…...

从芯片设计到软件调试:逻辑函数五种表示法在实际工程中的隐藏用法与避坑指南

从芯片设计到软件调试:逻辑函数五种表示法在实际工程中的隐藏用法与避坑指南 刚入行的硬件工程师小张最近遇到了一个棘手问题:他设计的Verilog模块在仿真时功能正常,但实际烧录到FPGA后却出现了随机错误。经过三天三夜的调试,最终…...

ThinkPad X280二手淘机指南:从接口缩水到板载内存,这些坑你绕开了吗?

ThinkPad X280二手淘机避坑指南:从验机技巧到性价比分析 在预算有限的办公设备选择中,二手ThinkPad始终是务实主义者的首选。作为X系列最后一款12.5英寸机型,X280在二手市场的价格已跌至2000-3000元区间,但这款2018年发布的商务本…...

从‘控制字6040’到‘状态字6041’:手把手图解EtherCAT伺服驱动器的对象字典通讯全流程

从控制字6040到状态字6041:EtherCAT伺服驱动器对象字典通讯实战指南 第一次接触EtherCAT总线伺服的技术人员,面对密密麻麻的十六进制索引号时,往往会感到无从下手。对象字典就像一本神秘的操作手册,而控制字6040h和状态字6041h则是…...

不只是安装:用DVWA搭建你的第一个Web安全实验室(Kali+Apache2+MySQL实战)

不只是安装:用DVWA搭建你的第一个Web安全实验室(KaliApache2MySQL实战) 在网络安全领域,理论知识的积累固然重要,但真正的技能提升往往来自于实践。DVWA(Damn Vulnerable Web Application)作为一…...

ESP32-FreeRTOS实战:多任务架构与物联网应用开发指南

1. 项目概述与核心价值最近在捣鼓一个智能家居的传感器节点,需要它既能实时采集温湿度、光照数据,又能通过Wi-Fi稳定上报,还得在电池供电下撑够半年。选型时,ESP32这颗芯片自然成了首选,它集成了双核处理器和Wi-Fi/蓝牙…...

别再乱用try-catch-finally了!Spring Boot项目里这样处理异常才优雅

Spring Boot异常处理的艺术:告别try-catch-finally的野蛮时代 在微服务架构盛行的今天,一个优雅的异常处理机制已经成为区分专业开发与业余编码的关键标志。想象这样的场景:当你的API被疯狂调用时,某个服务突然抛出异常&#xff…...