IO 口输入的使用与按键实验
前面几节课介绍的都是 IO 口输出的使用,本节课我们通过按键实验来介绍 IO 口作为输入的使用,并通过按键电路实现开关灯的效果。
一、实验原理
(一)元器件介绍
按键是一种电子开关,使用时轻轻按开关按钮就可使开关接通,当松开手时,开关断开。
以4脚按键为例,按钮有两组引脚(触点)。当按下按钮时,它会连接这两个触点,从而关闭电路。一般来说,4 脚开关(轻触按键)相距较远的是相通的,离得较近的是一组开关,最好是测量一下,如果懒得测,接对角肯定是可以的。
下图说明了按钮内部的连接:
(二)按键消抖
使用按键的时候,通常情况下需要进行消抖。
该实验中所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动,为了不产生这种现象而作的措施就是按键消抖。
按键的抖动对于人类来说是感觉不到的,但对单片机来说,则是完全可以感应到的,而且还是一个很漫长的过程,因为单片机处理的速度在微秒级,而按键抖动的时间至少在毫秒级。一次按键动作的电平波形如下图。存在抖动现象,其前后沿抖动时间一般在 5ms10ms 之间。
这种抖动可能会影响程序误判,造成严重后果,一般我们采用两种方式对按键进行消抖:
- 硬件消抖:硬件消抖的典型做法是采用 R-S 触发器或 RC 积分电路。
- 软件消抖:通常我们会使用软件延时 10ms 来消抖。例如,当按键按下后,引脚为低电平;所以首先读取引脚电平,若引脚为低电平,则延时 10ms 后再次读取引脚电平,若为低电平,则证明按键已按下。
硬件方法一般用在对按键操作过程比较严格,而按键数量较多时,通常采用软件消抖。值得一提的是,对于复杂且多任务的单片机系统来说,若简单地采用循环指令来实现软件延时,则会浪费 CPU 宝贵的时间资源,大大降低系统的实时性,所以,更好的做法是利用定时中断服务程序或利用标志位的方法来实现软件消抖。
二、硬件电路设计
实验目的:使用按键电路实现开关灯的效果。
(一)物料清单(BOM 表)
材料名称 | 数量 |
2 脚或4 脚按键(本次实验采用2脚) | 1 |
杜邦线(跳线) | 若干 |
面包板 | 1 |
(二)电路连接
将材料按照下图相连:按键一端接 3V3 引脚,另一端接 D7。 LED灯位于单片机上,通过GPIO13实现控制。
三、软件程序设计
这里我们在使用 pinMode
方法的时候,第二个参数就不能传递 OUTPUT
了,并且我们需要使用 digitalRead
方法来获取输入值。与输出不同的是,设置输入引脚时,我们需要配置上拉或下拉电阻。
(一)上拉电阻
上、下拉电阻的作用是提高电路稳定性,避免引起误动作。按键如果不通过电阻上拉到高电平,那么在上电瞬间可能就发生误动作,因为在上电瞬间单片机的引脚电平是不确定的,上拉电阻的存在保证了其引脚处于高电平状态,而不会发生误动作。
在 Arduino 中,设置引脚的上拉电阻或下拉电阻需要使用 pinMode
函数和 INPUT_PULLUP
或 INPUT_PULLDOWN
常量。如果要设置引脚为上拉电阻,需要将引脚设置为输入模式,并调用 pinMode(pin, INPUT_PULLUP)
函数,其中 pin
为引脚号。
提示:如果你不认识上拉电阻和下拉电阻,在这个阶段是无所谓的,你只需要了解他们的存在是为了确定初始电平状态。
选择上拉电阻,GPIO 引脚默认位高电平,那我们想要改变信号,就需要传递一个低电平,接地。选择下拉电阻,GPIO 引脚默认为低电平,那我们想要改变信号,就需要传递一个高电平,接电源。
(二)示例代码
1. 下面我们打开Arduino IDE,可以点击左上角文件 -> 新建项目;
当然你也可以打开一个例程文件,通过修改或重写文件里的代码实现功能,示例文件参见下图。
2. 接下来编写程序,以下是参考代码:
// 定义 LED 与 按键引脚
int led_pin = 13;
int button_pin = 7;
// 定义 LED 逻辑值
int led_logic = 0;
// 判断 LED 的状态是否改变过
bool status = false;
void setup() {
pinMode(led_pin, OUTPUT);
pinMode(button_pin, INPUT_PULLDOWN);
}
void loop() {
// 按键消抖
if (digitalRead(button_pin)) {
// 睡眠 10ms,如果依然为高电平,说明抖动已消失。
delay(10);
if (digitalRead(button_pin) && !status) {
led_logic = !led_logic;
digitalWrite(led_pin, led_logic);
// led 的状态发生了变化,即使我持续按着按键,LED 的状态也不应该改变。
status = !status;
} else if (!digitalRead(button_pin)) {
status = false;
}
}
}
3. 编译运行
在运行代码之前,让我们先确认已选择NanoE的开发板。
然后点击左上角的→,就可以编译运行啦~
四、实验结果
(一)实验现象
程序编译上传后,可通过外接按键来控制板载LED的亮灭。
(二)代码优化
我们也可以不在setup
前定义变量,而是选择 宏定义
的方法。在 Arduino 中,宏定义是一种预处理器指令,它被用于创建常量和替代符号。通过使用宏定义,可以让代码更易读,更易于维护和修改,同时也可以避免在代码中出现重复的代码块。大家可以尝试修改上文代码,使用宏定义的方法完成实验~