Oh!Coder

Coding Life

好玩的Arduino-停止抖动!

| Comments

Hi,大家好!又跟大家见面啦!在上一次讲解按键开关临近结束的时候,我们提到在正常的使用过程中,美中有不足,按键开关还有一个小问题需要解决。那是什么问题呢?

每当你按下或抬起按键开关的一瞬间,由于读取信号的操作是持续进行的,又由于按键自身的物理元器件的问题,每次触碰的一瞬间,可能会发生多次短暂的物理接触,以至于最终产生的信号发生了抖动。为了消除这种抖动,让按键变得更加好用,这次我们一起来试试看如何解决这个问题!这一次的学习过程中,我们用到了之前在《另一种时间延迟》中学过的知识点。如果你对此还有印象,那将会对这一次的学习有很大的帮助呢!

好!介绍的差不多了。还是老环节,先准备一下我们需要的材料。

硬件方面

arduino-read-digital-parts

图片来源:Arduino电路配件

具体包括如下:

  • Arduino UNO电路板(1块)
  • 面包板(1块)
  • 10k电阻(1个)
  • 按键开关(1个)
  • 面包线(3根)

咦?是不是看起来很像上一次在《按键开关》那一节中所使用的硬件啊!哼哼!其实不单是硬件用的一样,连电路的连接也是一摸一样呢!同样的,这次我们对按键测试所使用的LED神灯,用的还是Arduino UNO电路板上自带的那一盏!

软件方面

不多说,依然是Arduino官方提供的IDE。

连接电路

arduino-read-digital

图片来源:Arduino连接开关按键电路示意图

既然和上一次的电路连接一样,就不多啰嗦了,我们直接进入最后一步!

添加几行代码

首先,还是新建一个项目窗口。

arduino-ide-new

图片来源:Arduino官方IDE

然后向其中添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// 定义按键输入针脚号常量,
// 并初始化为2号针脚。
const int buttonPin = 2;
// 定义LED输入针脚号常量,
// 并初始化为13号针脚。
// 注:此处我们使用的LED神灯是Arduino UNO电路板自带,
// 此神灯对应的针脚号默认为13,此数值不得随意更改,
// 所以这里定义的数值13是为了和默认值相对应。
const int ledPin = 13;
// 定义记录LED神灯当前状态的变量,
// 并初始化状态为HIGH。
int ledState = HIGH;
// 定义记录按键当前状态的变量
int buttonState;
// 定义记录按键最近一次状态变化的变量,
// 并初始化状态为LOW。
int lastButtonState = LOW;
// 定义记录最近一次抖动的时间变量,
// 并初始化时间为0毫秒。
long lastDebounceTime = 0;
// 定义延迟抖动的时间变量,
// 并初始化为50毫秒。
long debounceDelay = 50;

// 对Arduino电路板或相关状态进行初始化方法
void setup() {
  // 设置按键的针脚为输入状态
  pinMode(buttonPin, INPUT);
  // 设置电路板上LED神灯的针脚状态为输出状态
  pinMode(ledPin, OUTPUT);
  // 设置电路板上LED神灯的初始状态,
  // 此处因为变量ledState的初始状态为HIGH,
  // 所以LED神灯的初始状态为亮。
  digitalWrite(ledPin, ledState);
}

// 系统调用,无限循环方法
void loop() {
  // 读取按键的状态
  int reading = digitalRead(buttonPin);
  // 判断当前的按键状态是否和之前有所变化
  if (reading != lastButtonState) {
    // 如果按键发生了变化,
    // 则重新设置最近一次抖动的时间。
    lastDebounceTime = millis();
  }
  // 判断按键按下或抬起的状态时间间隔是否大于延迟抖动的时间长度。
  // 方法millis()可以获取当前时间,单位统一为毫秒。
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // 判断当前的按键状态是否和之前有所变化
    if (reading != buttonState) {
      // 如果发生了变化,
      // 则更新按键状态变量。
      buttonState = reading;
      // 判断按键的状态是否为按下,
      // 只有在按键按下的时候,
      // 才改变LED神灯的状态。
      if (buttonState == HIGH) {
        // 如果LED神灯当前为亮度,
        // 则变为灭。如果为灭,
        // 则变为亮。
        ledState = !ledState;
      }
    }
  }
  // 最终改变电路板上LED神灯的状态
  digitalWrite(ledPin, ledState);
  // 更新按键最近一次状态变化的变量
  lastButtonState = reading;
}

好!总共的代码就是酱紫!看起来有些长呢!其实也只是看起来而已啦!老实说这里并没有出现任何新的面孔,唯一看起来有点绕的,就是对时间延迟的控制。如果觉得有些吃力,可以回顾一下《另一种时间延迟》小节所学的内容。之所以能够最终解决抖动问题,其实就是通过加入时间延迟来解决的。通过延长按键状态改变的时间长度,来最终消除信号的抖动。

arduino-menu

图片来源:Arduino官方IDE的文件编辑菜单选项

点击上图中标有向右指向的箭头图标,将代码一键烧入Arduino UNO电路板。现在试试看,每次单击按键,电路板上的LED神灯会不会有所变化?如果一切正常,现在每单击一下按键,LED神灯的状态就会变化一次。在《按键开关》那一节,是每次按下按键,点亮LED神灯。抬起按键,LED神灯熄灭。而现在是每单击一次按键,LED神灯变化一次。可以体会一下它们之间的不同。

总结

通过这次学习,我们解决了按键的信号抖动的问题。解决的核心方法呢,是通过引入时间延迟,来消除信号抖动。技术来说并没有碰到新内容,难点就在于对时间延迟的理解。

下期预告

通过前两次学习,我们发现每次连接按键总要外加一个10k的电阻。在电路合理连接的情况下,能不能不引入电阻,直接就能使用按键呢!好!下一次,我们将一起学习一种如何不用外接电阻,也能正常使用按键的方法!

Comments