按键消抖+按键计数
- 前言
- 一、按键消抖
- 二、按键计数
- 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官方教程】数字处理示例(五):按键状态变化检测