第十二篇、基于Arduino uno,获取多个按键的输入信号(滤波消抖)——结果导向

news2024/12/23 2:43:12

0、结果

说明:先来看看串口调试助手显示的结果,当按下按键的时候,按一次会打印一次按键被按下,并且打印是哪个按键被按下。如果是你想要的,可以接着往下看。

1、外观

说明:虽然每个型号的按键形态各异,但是原理和代码都是适用的,只要能保证按下导通,不按下不导通就行。

2、连线

说明:只需要连接两根线,一端和另一端需要保证按下导通,不按下不导通。
uno————按键

GND--------------按键一端
    D2--------------按键另一端

3、源程序

说明:对按键进行了消抖,基本上不会存在误触发的可能,按键多了或者少了也可以自行更改,很方便。并将对应功能进行函数化,方便移植。

/****************************************按键 part****************************************/
/*
  用到几个按键的话就定义几个引脚,不然引脚悬空的话会误触发!!!
  接线:
  按键一端接GND,一端接D2~D8,能保证按下导通,不按下不导通就行。
*/
#define startButton   2                                             //0号按钮
#define buttonPin1    3                                             //1号按钮
#define buttonPin2    4                                             //2号按钮
#define buttonPin3    5                                             //3号按钮
#define buttonPin4    6                                             //4号按钮
#define buttonPin5    7                                             //5号按钮
#define buttonPin6    8                                             //6号按钮

#define buttonON      LOW                                           //按钮按下时为低电平  

struct Button {
  int buttonState = !buttonON;                                      //按钮状态变量,与按钮按下时的状态取反
  int lastButtonState = !buttonON;                                  //按钮状态初始化,与按钮按下时的状态取反
  long lastDebounceTime = 0;                                        //记录抖动变量
  long debounceDelay = 30;                                          //抖动时间变量
  bool flag = false;                                                //按钮flag
};
const int buttonPins[7] = {startButton, buttonPin1, buttonPin2, buttonPin3, buttonPin4, buttonPin5, buttonPin6};
Button button, buttons[7];                                          //新建1个按钮,和按钮数组,数组含有七个按钮
int runCount = 0;                                                   //定义一个变量
int buttonCount = 9;                                                //按键号
/****************************************set up and loop part*********************************/
void setup() {
  Serial.begin(9600);                                               //初始化串口,波特率为9600
  initButtons();                                                    //初始化所有按键串口
}
void loop() {
  buttonMonitor();                                                  //按键检测函数
}
/****************************************按键 part****************************************/
/*按钮初始化函数,设置为上拉输入,更加稳定*/
void initButtons() {
  for (int i = 0; i < sizeof(buttonPins) / sizeof(buttonPins[0]); i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);                          //适用于多个按钮
  }
}
/*按钮输入读取,采用非阻塞式按键消抖,适用于多个按钮*/
void getButton(int _buttonPin, int _buttonIndex) {
  int reading = digitalRead(_buttonPin);                           //读取状态
  if (reading != buttons[_buttonIndex].lastButtonState) {          //如果状态改变
    buttons[_buttonIndex].lastDebounceTime = millis();             //更新时间
  }                                                                //如果等待大于debounceDelay
  if ((millis() - buttons[_buttonIndex].lastDebounceTime) > buttons[_buttonIndex].debounceDelay) {
    if (reading != buttons[_buttonIndex].buttonState) {            //读取状态不等于按钮状态
      buttons[_buttonIndex].buttonState = reading;                 //更新状态
      if (buttons[_buttonIndex].buttonState == buttonON) {         //判断按钮是否真的按下
        buttonCount = _buttonIndex;
        Serial.print(buttonCount);                                 //打印按钮编号
        Serial.println(" is pressed");                             //输出按钮按下的文字
        buttons[_buttonIndex].flag = true;                         //按钮flag为真
      }
      else {
        buttons[_buttonIndex].flag = false;                        //按钮flag为假
      }
    }
  }
  buttons[_buttonIndex].lastButtonState = reading;                 //更新last状态
}
/*设备上电之后会误触发按键检测,写这个函数是为了稳定后,再来检测按键的状态*/
void runCountToStable() {
  if (runCount < 10) {                                             //防止误触发
    runCount++;
  }
}
/*按键检测函数*/
void buttonMonitor() {
  runCountToStable();                                              //记录运行次数为了按键检测运行精确
  for (int i = 0; i < sizeof(buttonPins) / sizeof(buttonPins[0]); i++) {
    getButton(buttonPins[i], i);                                   //适用于多个按钮
  }
}

4、注意事项

说明:按键有四个引脚或者三个引脚,四个引脚的按键,两个引脚挨得近的是不按下不导通,按下导通;如果是三个引脚的,随便接两个引脚就行。

5、基本原理

        在按键被按下时使得电路闭合,从而触发相应的程序操作。按键通常由两个部分组成:一个是用于连接电路的接点(也称为触点或固定触点),另一个是用于控制接点状态的弹簧式机构(也称为活动触点)。
        当按键未被按下时,接点处于断开状态,此时电路不通,无法传递电信号。当按键被按下时,机械结构将弹簧压缩,使活动触点与固定触点接触,从而形成闭合电路。在这个过程中,电流可以沿着闭合的电路流通,达到控制相应程序操作的目的。
        在Arduino中,按键的工作流程主要包括两个阶段:输入和处理。在输入阶段,当按键被按下时,Arduino会读取对应的数字或模拟输入引脚的电压状态,并将其转换为高或低电平信号。在处理阶段,Arduino根据输入信号的状态进行相应的判断和操作,如执行特定函数、调用模块等操作。

6、消抖的方法

        采用软件消抖的原理是通过编程实现,在按键被按下后,通过程序进行一定的处理和判断,使得系统仅响应有效的按键操作,避免因按键抖动等原因产生误触发现象。
        具体来说,软件消抖的原理主要包括以下几个步骤:

  1. 读取按键状态:首先需要读取按键状态,即检测输入引脚的电平是否发生变化(从高电平到低电平)。可以使用Arduino中的digitalRead函数实现该功能。

  2. 延时消抖:当检测到按键状态发生变化时,需要延时一段时间,以等待按键抖动消除。可以使用Arduino中的delay函数或借助定时器实现延时功能。

  3. 再次读取按键状态:在延时结束后,需要再次读取按键状态,并与之前的状态比较,以确定是否发生有效的按键操作。只有当两次读取的状态相同,且状态为低电平时,才表示发生了有效的按键操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/597255.html

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

相关文章

Linux---用户的权限

专栏&#xff1a;Linux 个人主页&#xff1a;HaiFan. 本章为大家带来用户的权限的讲解 用户的权限 Linux权限的概念权限的三类对象权限的三种类型权限设置chmod/chown/chgrp更改权限chmodchownchgrp umask目录的权限粘滞位 Linux权限的概念 Linux下有两种用户&#xff1a;超级…

安科瑞应急照明的环境适用性

安科瑞 徐浩竣 江苏安科瑞电器制造有限公司 zx acrelxhj 摘要&#xff1a;论述消防应急照明和疏散指示系统在实际工程应用过程中系统产品选型、设置及维护环节普遍存在的问题&#xff0c;并提出相应的解决对策。 关键词&#xff1a;应急照明疏散指示产品选型环境适用性灯具…

机器学习笔记 - 使用稳定扩散模型创建图像

一、简述 文本到图像生成是机器学习 (ML) 模型从文本描述生成图像的任务。目标是生成与描述非常匹配的图像,捕捉文本的细节和细微差别。这项任务具有挑战性,因为它要求模型理解文本的语义和语法,并生成逼真的图像。文本到图像生成在 AI 摄影、概念艺术、建筑建筑、时尚、视…

用JMeter自动化测试实现高效稳定的接口测试方案!

目录 前言&#xff1a; 1. 接口与接口测试 1.1 接口概述 1.2 接口测试 2. 基于JMeter的接口测试 2.1 JMeter概述 2.2 用JMeter实现接口测试 3. 基于JMeter的接口自动化测试 3.1 接口自动化测试基础 3.2 使用JMeter进行接口自动化测试 总结 前言&#xff1a; 接口是…

(字符串) 541. 反转字符串 II——【Leetcode每日一题】

❓541. 反转字符串 II 难度&#xff1a;简单 给定一个字符串 s 和一个整数 k&#xff0c;从字符串开头算起&#xff0c;每计数至 2k 个字符&#xff0c;就反转这 2k 字符中的前 k 个字符。 如果剩余字符少于 k 个&#xff0c;则将剩余字符全部反转。如果剩余字符小于 2k 但大…

【dns awsl】RedHat8配置DNS服务器

文章目录 一、安装 配置DNS验证 一、安装 配置DNS 安装 sudo dnf install bind bind-utils配置named.conf 指定正向解析和反向解析的所需文件 vim /etc/named.conf在文件中找到options部分&#xff0c;并进行如下修改&#xff1a;options {listen-on port 53 { any; };allow…

day02——特征工程之特征提取

特征工程之特征提取 一、什么是特征工程二、特征提取1&#xff0c;字典特征提取2&#xff0c;文本特征提取&#xff08;1&#xff09;英文文本特征提取&#xff08;2&#xff09;中文文本特征提取&#xff08;3&#xff09;Tf-idf 文本特征提取 一、什么是特征工程 特征工程是…

CRM和SCRM有什么区别?

首先讲下CRM是什么&#xff1f;光是概念就有7个之多&#xff1a; 提出者概念GartnerGroupCRM是一种商业策略&#xff0c;它按照客户的分类情况有效地组织企业资源&#xff0c;培养以客户为中心的经营行为以及实施以客户为中心的业务流程&#xff0c;并以此为手段来提高企业的赢…

低代码平台安全性探究:解析低代码平台的安全性及应对措施

近年来&#xff0c;低代码平台由于能够以最少的代码快速开发应用程序而变得越来越流行。然而&#xff0c;随着数据泄露和网络威胁的增加&#xff0c;企业有理由质疑低码平台是否安全。在本文中&#xff0c;我们将探讨低代码平台安全吗&#xff1f; 一、低码平台如何工作。 在我…

集成websocket实现实时通信(ruoyi 使用笔记)

集成websocket实现实时通信(ruoyi 使用笔记 1.简单介绍WebSocket2.详细代码2.1WebSocketConfig2.2 SemaphoreUtils2.3 WebSocketServer2.4 WebSocketUsers2.5 html2.6 vue版本前端代码2.7 controller 1.简单介绍WebSocket Websocket 是一种基于 TCP 协议的全双工通信协议&#…

加油站“变身”快充站,探讨充电新模式

摘要&#xff1a;新能源汽车规模化发展的同时&#xff0c;充电不便利的痛点愈发明显。在未来的新能源汽车行业发展当中&#xff0c;充电的矛盾要远远大于造车的矛盾&#xff0c;解决好充电的问题成为电动汽车行业发展的一个突出问题。解决充电补能问题&#xff0c;重要的方式之…

自动化测试还是手动测试?深度探讨Web自动化测试的利与弊,精准性和可靠性抉择应如何。

目录 前言&#xff1a; 1. 自动化测试的价值 2. 自动化测试的瓶颈 总结 前言&#xff1a; 随着互联网的飞速发展&#xff0c;Web应用越来越成为我们日常工作和生活中必不可少的一部分。这也就意味着&#xff0c;Web应用的质量和稳定性变得至关重要。而Web自动化测试作为保…

87.建立主体页面-第三部分

上节我们完成的页面如下&#xff1a; ● 我们预计在按钮下面放置一些用户案例 去年我们送了25万多份餐品! ![在这里插入图片描述](https://img-blog.csdnimg.cn/c71d57199b834a8c9763a345939adc5d.png) ● 我们将这些图片文字以flex布局方式排列摆放 .delivered-meals {dis…

ebpf代码编写小技巧

查看所有tracepoint perf list perf追踪tracepoint perf trace --no-syscalls --event net:*查看tracepoint的具体参数 sudo python3 /usr/share/bcc/tools/tplist -v net:napi_gro_receive_entry cat /sys/kernel/debug/tracing/events/net/netif_rx/format内核vmlinux.h生…

Zinx框架学习 - 链接封装与业务绑定

Zinx - V0.2 链接封装与业务绑定 之前的v0.1版本&#xff0c;已经实现了一个基础的Server框架&#xff0c;现在需要对客户端链接和不同的客户端链接锁处理的不同业务再做一层接口封装在ziface下创建一个属于链接的接口文件iconnection.go&#xff0c;znet下创建文件connection…

异步利刃CompletableFuture

什么是CompletableFuture? CompletableFuture 类实现了 Future 和 CompletionStage 接口并且新增了许多方法&#xff0c;它支持 lambda&#xff0c;通过回调利用非阻塞方法&#xff0c;提升了异步编程模型。简单来说可以帮我们实现任务编排。【文中所有代码已上传码云】 Com…

程序员必修必炼的设计模式之工厂模式

本文首发自「慕课网」&#xff08;www.imooc.com&#xff09;&#xff0c;想了解更多IT干货内容&#xff0c;程序员圈内热闻&#xff0c;欢迎关注"慕课网"或慕课网公众号&#xff01; 作者&#xff1a;李一鸣 | 慕课网讲师 工厂模式是平时开发过程中最常见的设计模式…

15.3:最多做K个项目,初始资金是W,返回最大资金

输入正数数组costs、正数数组profits、正数K和正数M costs[i]表示i号项目的花费 profits[i]表示i号项目在扣除花费之后还能挣到的钱(利润) K表示你只能串行的最多做k个项目 M表示你初始的资金 说明&#xff1a;每做完一个项目&#xff0c;马上获得的收益&#xff0c;可以支持你…

FP独立站支付渠道市场逐渐向好!信用卡和AB轮询哪个好?

之前一篇文章写过品牌方使用ChatGPT技术检测FP网站&#xff0c;对FP独立站的收款起到了很大的影响。今天是6月的第一天&#xff0c;我为各位带来了一个好消息&#xff01;那就是在过去的3-5月份&#xff0c;信用卡收款实行整顿&#xff0c;目前支付渠道都有所松动。例如&#x…

好孩子福利|Sup游戏机,一秒回到童年

这份六一礼物对儿童来说有点幼稚&#xff0c;但对程序员刚刚好&#xff5e; ​ Sup 游戏机&#xff0c;一秒回到童年&#xff01; 到底有多好玩呢&#xff1f;可以参考 B 站试玩视频&#xff01; 太火鸟好物推荐——掌上游戏机sup 参加流程&#xff1a; STEP 1&#xff1a;扫…