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

news2024/11/25 2:58:32

按键消抖+按键计数

  • 前言
  • 一、按键消抖
  • 二、按键计数
    • 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 7

int 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;                    //变量设置为1
      while (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++;                   // 计数器加1
    Serial.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.coloradmin.cn/o/923019.html

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

相关文章

mysql的登录与退出

mysql是c/s架构,意味着同时要有客户端和服务端 1 找到客户端。mysql.exe的安装目录 打开命令行 2 输入对应的服务器的ip,如果是本地,就是Localhost,如果是远程服务器,那就输入对应ip/域名。并且指定mysql监听的端口 …

10大开源工具,每个开发者都应该知道

🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…

通过仿真理解RLC串联电路和RLC并联电路的阻抗、导纳、品质因数等概念

一.RLC串联电路 1.阻抗 CSDN编辑公式太难受了。。。直接上PPT~ 2.RLC串联电路阻抗的仿真分析 仿真与理论计算,还是有些误差存在的。 二.RLC并联电路 1.导纳 2.RLC并联电路阻抗的仿真分析 3.RLC并联电路的“虚断”特性 三、LC电路的作用 四、品质因子Q 1.RLC串…

【keepalived双机热备与 lvs(DR)】

目录 一、概述 1.简介 2.原理 3.作用 二、安装 1.配置文件 2.配置项 三、功能模块 1.core 2.vrrp 3.check 四、配置双机热备 1.master 2.backup 五、验证 1.ping验证 2.服务验证 六、双机热备的脑裂现象 七、keepalivedlvs(DR) 1.作…

C++11特性详解

一、简介 在C11标准出来之前,一直是C98/03标准占引领地位,而C98/03标准是C98标准在2003年将存在的一些漏洞进行了修复,但并没有核心语法的改动。相比于C98/03,C11则带来了数量可观的变化,其中包含了约140个新特性&…

通过Putty对Linux服务器进行文件的上传与下载

1、下载安装Putty,下载地址:https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html 2、打开cmd窗口,通过命令行进入安装路径,如: 3、上传文件 pscp 文件 用户名服务器ip:目录使用“ -l ”选项可以指定用户…

keepalived+lvs(DR)

目录 一,作用 二,调度器配置 1,安装keepalived 2, 安装ipvsadm 3, 配置keepalived 4. 查看lvs节点状态 5, web节点配置 1.1 调整ARP参数 1.2 配置虚拟IP地址 1.3添加回环路由 1.4安装nginx并写…

【Unity学习笔记】DOTween(2)官方案例

本文中大部分内容学习来自DOTween官方文档 此处无法展示动图(懒得录GIF),请下载官方案例场景自行学习 文章目录 场景1 基本补间场景2 动态补间场景3 Shader修改场景4 路径拟合运动场景5 序列播放场景6 UGUI 场景1 基本补间 案例一展示了最基…

技术博客写作「个人经验分享」

技术博客写作「个人经验分享」 仔细想来,从19年我刚开始试着技术写作算起,已经过去了好几年时间。刚好趁着这次的[赠送奖牌活动(奖牌很好看,我很想要hhh😂)],来分享一下我关于技术博客写作的一些个人经验~ 文章目录 技术博客写作「…

k8s 常用命令(四)

12、删除pod中的nginx服务及service [rootmaster ~]# kubectl delete deployment nginx -n kube-public [rootmaster ~]# kubectl delete svc -n kube-public nginx-service 13、查看endpoint的信息 [rootmaster ~]# kubectl get endpoints 14、修改/更新(镜像、…

内网穿透实战应用-windwos10系统搭建我的世界服务器,内网穿透实现联机游戏Minecraft

文章目录 1. Java环境搭建2.安装我的世界Minecraft服务3. 启动我的世界服务4.局域网测试连接我的世界服务器5. 安装cpolar内网穿透6. 创建隧道映射内网端口7. 测试公网远程联机8. 配置固定TCP端口地址8.1 保留一个固定tcp地址8.2 配置固定tcp地址 9. 使用固定公网地址远程联机 …

Unbutu系统-Docker安装、JDK环境配置,Docker常用指令、Docker安装MySQL、Redis、Tomcat、Nginx,前端后分离项目部署

目录 1、防火墙 1.1、查看防火墙状态 1.2、开启防火墙 1.3、关闭防火墙 1.4、重启防火墙 1.5、查看防火墙版本 2、安装JDK 2.1、官网下载tar包 2.3、解压tar.gz文件 2.4、配置环境变量 2.4.1、查看安装路径 2.4.2、设置环境变量 2.4.3、执行该让环境变量生效 2.4…

vue2.6及以下版本导入 TDesign UI组件库

TDesign 官方文档:https://tdesign.tencent.com/vue/components/button 我们先打开一个普通的vue项目 然后 如果你是 vue 2.6 或者 低于 2.6 在终端执行 npm i tdesign-vue如果你是 2.7 或者更高 执行 npm i tdesign-vuenaruto这里 我们 以 2.6为例 因为大部分人 用vue2 都是…

华为“天才少年”稚晖君发布具身智能机器人远征A1,引领智能科技新时代!

原创 | 文 BFT机器人 继前几天小米发布仿生四足机器人CyberDog2之后,2023年8月18日上午,被称为“华为天才少年”、“野生钢铁侠”的彭志辉,也就是B站硬核科技UP主稚晖君。 他目前担任智元CTO和首席架构师,他和他的智元团队创业半…

【C++STL入门】vector查、改、交换

文章目录 前言一、查1.1 输出全部迭代器下标运算for_each函数 1.2 输出单个元素at()函数[] 下标运算back()函数 二、改assign函数 三、交换swap函数 总结 前言 一、查 在C中,使用vector进行查找操作可以分为两类:输出全部和输出单个元素。下面将详细介绍…

音视频FAQ(二)视频直播延时高

摘要 延时高是实时互动技术中常见的问题之一,解决延时高问题需要综合考虑网络、设备、编解码算法等多个因素。解决方案包括优化设备端延时、优化网络传输延时和使用UDP进行音视频传输等。在选择音视频传输协议时,需要综合考虑实际需求和网络条件&#x…

图神经网络与分子表征:2. SchNet

SchNet 在2018年的面世彻底引爆了神经网络势函数(NNP, Neural Network Potential)领域,虽然说NNP的开山鼻祖还要更早,但均未像 SchNet 这样真正被物理化学家接受,引发变革。 这篇博客浅浅记录下自己阅读SchNet代码的心得。2023年的今天&…

如何五分钟设计制作自己的蛋糕店小程序

在现如今的互联网时代,小程序已成为企业推广和销售的重要利器。对于蛋糕店来说,搭建一个小程序可以为其带来更多的品牌曝光和销售渠道。下面,我们将以乔拓云平台为例,来教你如何从零开始搭建自己的蛋糕店小程序。 首先&#xff0c…

Mybatis分页及特殊字符

目录 MyBatis分页 特殊字符 接着上篇博客接下来我们要写的是MyBatis分页 MyBatis分页 首先我们导入pom依赖 <dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.1.2</version>…

workbench连接MySQL8.0错误 bad conversion 外部组件 异常

阿里云搭建MySQL实用的版本是8.0 本地安装的版本是: workbench 6.3 需要升级到&#xff1a; workbench 8.0 https://dev.mysql.com/downloads/workbench/