Arduino程序设计(四)按键消抖+按键计数

按键消抖+按键计数

  • 前言
  • 一、按键消抖
  • 二、按键计数
    • 1、示例代码
    • 2、按键计数实验
  • 参考资料


前言

  • 本文主要介绍两种按键控制LED实验:
  • 第一种是采用软件消抖的方法检测按键按下的效果;
  • 第二种是根据按键按下次数,四个LED灯呈现不同的流水灯效果。

一、按键消抖

  • 按键在按下时,由于机械和物理特定的原因,经常会产生一些开关变换,而这些变换会让程序误认为是短时间内进行了多次按键。
  • 如何对输入信号进行消抖?也就是在一段短时间内进行两次检查来确保按键确实被按下。如果没有消抖的话,按下一次按键会产生很多不可预知的结果。
  • 所以Arduino按键消抖是为了解决按键在物理接触瞬间可能产生多次触发的现象。
  • 下面介绍两种常见的按键消抖方法:
  • ① 使用外部电容(硬件消抖):通过在按键引脚和地之间并联一个适当大小的电容(例如:MCU复位电路采用0.1uF陶瓷电容),减少了按键连接和断开时产生的电压突变,同时也可以减少按键在短时间内多次触发的可能性。MCU复位电路如下图所示:
    在这里插入图片描述
  • ② 软件消抖:利用Arduino的延时函数或计时器来检测按键状态的变化,只有在按键状态保持一段时间后才认为按键有效。例如,当检测到按键按下时,可以设定一个延时时间,在延时时间内如果检测到按键保持按下状态,则认为按键有效。

按键消抖实验:

  • 1、本实验采用Arduino UNO R3开发板及自主搭建电路的方式,实现预设功能。

  • 2、按键消抖的电路图如下图所示:
    在这里插入图片描述

  • 3、功能实现:按下一个按键,控制LED灯亮50ms然后熄灭。

  • 4、实验要求:采用延时消抖(方法1),编写按键扫描程序(方法2),计数器消抖(方法3)三种按键消抖方式实现功能。

代码实现(方法1):

//延时消抖,按键控制LED
//按下一个按键,控制LED灯亮50ms然后熄灭int buttonPin = 7;
int ledPin = 12;void setup() {pinMode(buttonPin, INPUT_PULLUP);pinMode(ledPin, OUTPUT);}
void loop() {if (digitalRead(buttonPin) == LOW){delay(10);if (digitalRead(buttonPin) == LOW){digitalWrite(ledPin, HIGH);delay(50);digitalWrite(ledPin, LOW);while (digitalRead(buttonPin) == LOW);}}
}

代码实现(方法2):

//编写按键扫描程序,实现按键消抖
//按下一个按键,控制LED灯亮50ms然后熄灭#define LED 12
#define KEY 7int KEY_NUM = 0;                   //按键键值存放变量,不等于1说明有按键按下void setup()
{pinMode(LED, OUTPUT);         //定义LED为输出引脚pinMode(KEY, INPUT_PULLUP);   //定义KEY为带上拉输入引脚
}void loop()
{ScanKey();                   //按键扫描程序,当按键按下时候,该子程序会修改KEY_NUM的值if (KEY_NUM == 1)            //是否按键按下{digitalWrite(LED, HIGH);delay(50);digitalWrite(LED, LOW);}
}void ScanKey()                        //按键扫描程序
{KEY_NUM = 0;                        //清空变量if (digitalRead(KEY) == LOW)        //有按键按下{delay(10);                        //延时去抖动if (digitalRead(KEY) == LOW)      //有按键按下{KEY_NUM = 1;                    //变量设置为1while (digitalRead(KEY) == LOW); //等待按键松手}}
}

代码实现(方法3):

//计数器消抖,按键控制LED
//按下一个按键,控制LED灯亮50ms然后熄灭const int buttonPin = 7;  // 按键引脚
const int ledPin = 12;    //LED引脚int buttonState = HIGH;   // 按键状态
int lastButtonState = HIGH;  // 上一次的按键状态
unsigned long lastDebounceTime = 0;  // 上一次的触发时间
unsigned long debounceDelay = 10;    // 消抖延时void setup() {pinMode(buttonPin, INPUT_PULLUP);pinMode(ledPin,OUTPUT);
}void loop() {int reading = digitalRead(buttonPin);  // 读取按键引脚状态// 如果当前状态与上一次状态不同,更新上一次状态和触发时间if (reading != lastButtonState) {lastDebounceTime = millis();}// 如果经过了消抖延时,且当前状态与按键状态不同,更新按键状态if ((millis() - lastDebounceTime) > debounceDelay) {if (reading != buttonState) {buttonState = reading;// 按键按下时执行的操作if (buttonState == HIGH) {digitalWrite(ledPin, HIGH);delay(50);digitalWrite(ledPin, LOW);}}}lastButtonState = reading;
}

二、按键计数

1、示例代码

  • 使用Arduino来实现按键计数。简单的示例代码如下:
//按键计数示例
const int buttonPin = 2;   // 按钮连接到数字引脚2
int buttonState = 0;       // 保存按钮状态
int count = 0;             // 计数器void setup() {pinMode(buttonPin, INPUT);     // 设置按钮引脚为输入模式Serial.begin(9600);            // 打开串口通信
}void loop() {buttonState = digitalRead(buttonPin);   // 读取按钮状态if (buttonState == HIGH) {    // 如果按钮按下count++;                   // 计数器加1Serial.print("Button pressed. Count: ");Serial.println(count);delay(200);                // 等待200毫秒,避免连续多次计数}
}

示例中,我们将一个按钮连接到Arduino的数字引脚2。循环中,我们读取按钮的状态,如果按钮被按下(高电平),计数器就会加1,并通过串口打印出计数器的值。为了避免按钮按下时的抖动,我们在每次计数后延迟200毫秒。

上传这个代码到Arduino板,然后打开串口监视器(波特率设置为9600),当你按下按钮时,你将看到计数器的值递增。

2、按键计数实验

  • (1)本实验采用Arduino UNO R3开发板及自主搭建电路的方式,实现预设功能。

  • (2)按键计数的电路图如下图所示:
    在这里插入图片描述

  • (3)实现功能(基础):

  • ① 第一次按下按键,LED1点亮;

  • ② 第二次按下按键,LED1和LED2点亮;

  • ③ 第三次按下按键,LED1~LED3点亮;

  • ④ 第四次按下按键,LED1~LED4点亮;

  • ⑤ 第五次按下按键,LED1~LED4熄灭;

  • ⑥ 第六次按下按键,重复①现象;

  • ⑦ 第七次按下按键,重复②现象……,以此类推。

代码实现:

//编写按键扫描程序,实现按键计数
/*实验现象:
① 第一次按下按键,LED1点亮;
② 第二次按下按键,LED1和LED2点亮;
③ 第三次按下按键,LED1~LED3点亮;
④ 第四次按下按键,LED1~LED4点亮;
⑤ 第五次按下按键,LED1~LED4熄灭;
⑥ 第六次按下按键,重复①现象;
⑦ 第七次按下按键,重复②现象……,以此类推。
*/const int KEY = 7;      //按键引脚
const int LED1 = 9;     //LED1引脚
const int LED2 = 10;    //LED2引脚
const int LED3 = 11;    //LED3引脚
const int LED4 = 12;    //LED4引脚int KEY_count = 0;      //按键计数void setup()
{pinMode(KEY, INPUT_PULLUP);    //定义KEY为带上拉输入引脚pinMode(LED1, OUTPUT);         //定义LED1为输出引脚pinMode(LED2, OUTPUT);         //定义LED2为输出引脚pinMode(LED3, OUTPUT);         //定义LED3为输出引脚pinMode(LED4, OUTPUT);         //定义LED4为输出引脚
}void loop()
{ScanKey();                   //按键扫描程序,当按键按下时候,该子程序会修改KEY_count的值switch (KEY_count) {case 0:{digitalWrite(LED1, LOW);digitalWrite(LED2, LOW);digitalWrite(LED3, LOW);digitalWrite(LED4, LOW);}break;case 1:{digitalWrite(LED1, HIGH);}break;case 2:{digitalWrite(LED1, HIGH);digitalWrite(LED2, HIGH);}break;case 3:{digitalWrite(LED1, HIGH);digitalWrite(LED2, HIGH);digitalWrite(LED3, HIGH);}break;case 4:{digitalWrite(LED1, HIGH);digitalWrite(LED2, HIGH);digitalWrite(LED3, HIGH);digitalWrite(LED4, HIGH);}break;default:{KEY_count = 0;}}
}void ScanKey()                        //按键扫描程序
{if (digitalRead(KEY) == LOW)        //有按键按下{delay(10);                        //延时去抖动if (digitalRead(KEY) == LOW)      //有按键按下{KEY_count++;                   //按键计数while (digitalRead(KEY) == LOW); //等待按键松手}}
}
  • (4)实现功能(进阶):
  • ① 第一次按下按键,LED1和LED3亮500ms后熄灭,间隔150ms后,LED2和LED4亮150ms后熄灭,间隔150ms后,LED1和LED3亮150ms后熄灭……,重复操作。
  • ② 第二次按下按键,LED1~LED4从左往右依次点亮,等LED4熄灭后,再从左往右依次点亮,重复操作,相邻两个LED灯亮灭的时间间隔为50ms。
  • ③ 第三次按下按键,LED1~LED4从右往左依次点亮,等LED1熄灭后,再从右往左依次点亮,重复操作,相邻两个LED灯亮灭的时间间隔为50ms。
  • ④ 第四次按下按键,LED1~LED4从左往右依次点亮,再从右往左依次点亮,重复操作,相邻两个LED灯亮灭的时间间隔为50ms。
  • ⑤ 第五次按下按键,LED1~LED4熄灭。
  • ⑥ 第六次按下按键,重复①现象
  • ⑦ 第七次按下按键,重复②现象……,以此类推。

代码实现:

//编写按键扫描程序,实现按键计数
//注意:按下按键后,即下一次按下按键前,时间间隔>10s
/*实验现象:① 第一次按下按键,LED1和LED3亮150ms后熄灭,间隔150ms后,LED2和LED4亮150ms后熄灭,间隔150ms后,LED1和LED3亮150ms后熄灭……,重复操作。② 第二次按下按键,LED1~LED4从左往右依次点亮,等LED4熄灭后,再从左往右依次点亮,重复操作,相邻两个LED灯亮灭的时间间隔为50ms。③ 第三次按下按键,LED1~LED4从右往左依次点亮,等LED1熄灭后,再从右往左依次点亮,重复操作,相邻两个LED灯亮灭的时间间隔为50ms。④ 第四次按下按键,LED1~LED4从左往右依次点亮,再从右往左依次点亮,重复操作,相邻两个LED灯亮灭的时间间隔为50ms。⑤ 第五次按下按键,LED1~LED4熄灭。⑥ 第六次按下按键,重复①现象⑦ 第七次按下按键,重复②现象……,以此类推。
*/const int KEY = 7;      //按键引脚
const int LED1 = 9;     //LED1引脚
const int LED2 = 10;    //LED2引脚
const int LED3 = 11;    //LED3引脚
const int LED4 = 12;    //LED4引脚int KEY_count = 0;      //按键计数void setup()
{pinMode(KEY, INPUT_PULLUP);    //定义KEY为带上拉输入引脚pinMode(LED1, OUTPUT);         //定义LED1为输出引脚pinMode(LED2, OUTPUT);         //定义LED2为输出引脚pinMode(LED3, OUTPUT);         //定义LED3为输出引脚pinMode(LED4, OUTPUT);         //定义LED4为输出引脚
}void loop()
{ScanKey();                   //按键扫描程序,当按键按下时候,该子程序会修改KEY_count的值switch (KEY_count) {case 0:{digitalWrite(LED1, LOW);digitalWrite(LED2, LOW);digitalWrite(LED3, LOW);digitalWrite(LED4, LOW);}break;case 1:{//第一次按下按键digitalWrite(LED1, HIGH);digitalWrite(LED2, LOW);digitalWrite(LED3, HIGH);digitalWrite(LED4, LOW);delay(150);digitalWrite(LED1, !digitalRead(LED1));digitalWrite(LED2, !digitalRead(LED2));digitalWrite(LED3, !digitalRead(LED3));digitalWrite(LED4, !digitalRead(LED4));delay(150);}break;case 2:{//刷新LED1~LED4状态digitalWrite(LED1, LOW);digitalWrite(LED2, LOW);digitalWrite(LED3, LOW);digitalWrite(LED4, LOW);//第二次按下按键digitalWrite(LED1, HIGH);delay(50);digitalWrite(LED1, !digitalRead(LED1));digitalWrite(LED2, HIGH);delay(50);digitalWrite(LED2, !digitalRead(LED2));digitalWrite(LED3, HIGH);delay(50);digitalWrite(LED3, !digitalRead(LED3));digitalWrite(LED4, HIGH);delay(50);digitalWrite(LED4, !digitalRead(LED4));delay(50);}break;case 3:{//刷新LED1~LED4状态digitalWrite(LED1, LOW);digitalWrite(LED2, LOW);digitalWrite(LED3, LOW);digitalWrite(LED4, LOW);//第三次按下按键digitalWrite(LED4, HIGH);delay(50);digitalWrite(LED4, !digitalRead(LED4));digitalWrite(LED3, HIGH);delay(50);digitalWrite(LED3, !digitalRead(LED3));digitalWrite(LED2, HIGH);delay(50);digitalWrite(LED2, !digitalRead(LED2));digitalWrite(LED1, HIGH);delay(50);digitalWrite(LED1, !digitalRead(LED1));delay(50);}break;case 4:{//刷新LED1~LED4状态digitalWrite(LED1, LOW);digitalWrite(LED2, LOW);digitalWrite(LED3, LOW);digitalWrite(LED4, LOW);//第四次按下按键digitalWrite(LED1, HIGH);delay(50);digitalWrite(LED1, !digitalRead(LED1));digitalWrite(LED2, HIGH);delay(50);digitalWrite(LED2, !digitalRead(LED2));digitalWrite(LED3, HIGH);delay(50);digitalWrite(LED3, !digitalRead(LED3));digitalWrite(LED4, HIGH);delay(50);digitalWrite(LED4, !digitalRead(LED4));delay(50);digitalWrite(LED4, HIGH);delay(50);digitalWrite(LED4, !digitalRead(LED4));digitalWrite(LED3, HIGH);delay(50);digitalWrite(LED3, !digitalRead(LED3));digitalWrite(LED2, HIGH);delay(50);digitalWrite(LED2, !digitalRead(LED2));digitalWrite(LED1, HIGH);delay(50);digitalWrite(LED1, !digitalRead(LED1));delay(50);}break;default:{digitalWrite(LED1, LOW);digitalWrite(LED2, LOW);digitalWrite(LED3, LOW);digitalWrite(LED4, LOW);KEY_count = 0;}}
}void ScanKey()                        //按键扫描程序
{if (digitalRead(KEY) == LOW)        //有按键按下{delay(10);                        //延时去抖动if (digitalRead(KEY) == LOW)      //有按键按下{KEY_count++;                   //按键计数while (digitalRead(KEY) == LOW); //等待按键松手}}
}

注意:按下按键后,即下一次按下按键前,时间间隔>10s。


参考资料

参考资料1: 【Arduino官方教程】数字处理示例(三):按键防抖
参考资料2: 【Arduino官方教程】数字处理示例(五):按键状态变化检测

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

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

相关文章

什么是负载均衡

前提概述 关于负载均衡,我会从四个方面去说 1. 负载均衡产生的背景 2. 负载均衡的实现技术 3. 负载均衡的作用范围 4. 负载均衡的常用算法 负载均衡的诞生背景 在互联网发展早期,由于用户量较少、业务需求也比较简单。对于软件应用,我们只需要…

《Zookeeper》源码分析(二十)之 Follower

目录 Follower创建Follower实例followLeader()findLeader()connectToLeader()registerWithLeader()syncWithLeader() FollowerZooKeeperServer Follower Leader选举结束后,成为Follower的服务器开始进行Follower的工作,过程如下: 与Leader…

计算机终端核心安全配置规范

声明 本文是学习 政务计算机终端核心配置规范. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 范围 本标准提出了政务计算机终端核心配置的基本概念和要求,规定了核心配置的自动化实现方法,规范了核心配置实施流程。 本标准适…

【Terraform学习】使用 Terraform 创建Amazon VPC(Terraform-AWS最佳实战学习)

使用 Terraform 创建Amazon VPC 实验步骤 前提条件 安装 Terraform: 地址 下载仓库代码模版 本实验代码位于 task_vpc 文件夹中。 变量文件 variables.tf 在上面的代码中,您将声明,aws_access_key,aws_secret_key和 区域变量…

pxe linux7,PXE+Kickstart 实现自动安装系统

部署准备 服务器 操作系统:rhel7.7 软件准备: rhel-server-7.5-x86_64-dvd.iso、rhel-server-7.7-x86_64-dvd.iso 客户机 硬件配置:至少2G以上内存 基础环境准备 关闭selinux sed -i “s/SELINUXenforcing/SELINUXdisabled/g” /etc/…

Linux搭建SSLVpn

安装http、ssl服务 编辑http配置文件 修改http的136行,276行以及990行 1、136行将监听端口注释 2、276行和990行修改为自己的域名和要访问的端口 修改http文档最后那部分 新添ssl配置信息,将端口修改为443(截图错了server.key应该放在/etc/…

jenkins Linux如何修改jenkins 默认的工作空间workspace

由于jenkins默认存放数据的目录是/var/lib/jenkins,一般这个var目录的磁盘空间很小的,就几十G,所以需要修改jenkins的默认工作空间workspace 环境 jenkins使用yum安装的 centos 7 正题 1 查看jenkins安装路径 [rootlocalhost jenkins_old_data]# rpm…

【80天学习完《深入理解计算机系统》】第九天 3.2 数据传送指令【mov】【栈和堆】【leaq】【一元操作】【二元操作】

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客,如有问题交流,欢迎评论区留言,一定尽快回复!(大家可以去看我的专栏,是所有文章的目录)   文章字体风格: 红色文字表示&#…

如何优雅的使用Git?

第一部分:Git的基本概念和初始设置 Git是一个分布式版本控制系统,它允许多人共同工作,同时跟踪和管理项目的版本历史。使用Git,您可以恢复旧版本、创建新分支进行实验,并与其他开发者进行协作,而不会影响主…

基于AWS的3D模型搜索服务实现

3D模型广泛应用于计算机游戏、电影、工程、零售业、广告等许多领域。市场上有很多制作3D模型的工具,但几乎没有工具可以直观地搜索3D模型数据库以找到类似的3D模型 因为开发好的 3D 模型搜索工具非常具有挑战性。 它需要复杂的计算和 AI/ML 框架来创建模型描述符并提…

【MySQL系列】Select语句单表查询详解(二)ORDERBY排序

💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤 📃个人主页 :阿然成长日记 …

C语言:选择+编程(每日一练Day8)

目录 选择题: 题一: 题二: 题三: 题四: 题五: 编程题: 题一:字符个数统计 思路一: 题二:多数元素 思路一: 本人实力有限可能对一些…

em 和 rem 的区别

前言 em 和 rem 都是相对单位,在使用时由浏览器转换为像素值,具体取决于你的设计中的字体大小设置。 如果你使用值 1em 或 1rem,它可以被浏览器解析成 从16px 到 160px 或其他任意值。 em 和 rem 的区别 em 和 rem 单位之间的区别是浏览器…

k8s 安装 istio(二)

3.3 部署服务网格调用链检测工具 Jaeger 部署 Jaeger 服务 kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.16/samples/addons/jaeger.yaml 创建 jaeger-vs.yaml 文件 apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata…

【面试】一文讲清组合逻辑中的竞争与冒险

竞争的定义:组合逻辑电路中,输入信号的变化传输到电路的各级逻辑门,到达的时间有先后,也就是存在时差,称为竞争。 冒险的定义:当输入信号变化时,由于存在时差,在输出端产生错误&…

Debug result = unpickler.load() ModuleNotFoundError: No module named ‘models‘

1.torch训练的yolov5转trt出现问题如下&#xff1a; Using CUDA device0 _CudaDeviceProperties(nameNVIDIA GeForce RTX 3080, total_memory10017MB)Find Pytorch weight Traceback (most recent call last):File "export.py", line 243, in <module>ckpt t…

Mac nvm 切换为淘宝镜像

编辑环境配置 # 或者 vim ~/.bash_profile $ vim ~/.zshrc贴入镜像 # 淘宝镜像 export NVM_NODEJS_ORG_MIRRORhttp://npm.taobao.org/mirrors/node export NVM_IOJS_ORG_MIRRORhttp://npm.taobao.org/mirrors/iojs# nvm环境配置 export NVM_DIR"$HOME/.nvm"[ -s &quo…

【实战】十一、看板页面及任务组页面开发(四) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(二十六)

文章目录 一、项目起航&#xff1a;项目初始化与配置二、React 与 Hook 应用&#xff1a;实现项目列表三、TS 应用&#xff1a;JS神助攻 - 强类型四、JWT、用户认证与异步请求五、CSS 其实很简单 - 用 CSS-in-JS 添加样式六、用户体验优化 - 加载中和错误状态处理七、Hook&…

使用haproxy搭建web架构

haproxy HAProxy是一个免费的负载均衡软件&#xff0c;可以运行于大部分主流的Linux操作系统上。 HAProxy提供了可以在七层和四层两种负载均衡能力&#xff0c;它可以提供高可用性、负载均衡、及基于TCP和HTTP应用的代理。适用于负载大的Web站点&#xff0c;在运行在硬件上可…

libdrm全解析十九 —— 源码全解析(16)

接前一篇文章&#xff1a;libdrm全解析十八 —— 源码全解析&#xff08;15&#xff09; 本文参考以下博文&#xff1a; DRM 驱动程序开发&#xff08;VKMS&#xff09; 特此致谢&#xff01; 本文继续对include/drm/drm.h中实际功能宏定义进行讲解。 27. DRM_IOCTL_SET_SAR…