控制 GPIO 输入 - 按键实验
前面几节课介绍的都是 IO 口输出的使用,本节课我们通过按键实验来介绍 IO 口作为输入的使用并通过按键电路实现开关灯的效果。
实验原理
按键是一种电子开关,使用时轻轻按开关按钮就可使开关接通,当松开手时,开关断开。
![](https://gcore.jsdelivr.net/gh/bigrich-luo/typora-picgo-images-1@master/images/202303121502274.png)
按钮有两组引脚(触点)。当按下按钮时,它会连接这两个触点,从而关闭电路。
一般来说 4 脚开关(轻触按键)相距较远的是相通的,离得较近的是一组开关,最好是测量一下,如果懒得测,接对角肯定是可以的。
下图说明了按钮内部的连接:
![](https://gcore.jsdelivr.net/gh/bigrich-luo/typora-picgo-images-1@master/images/202303121512041.png)
使用按键的时候,通常情况下需要进行消抖。
什么是按键消抖?
该实验中所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动,为了不产生这种现象而作的措施就是按键消抖。
按键的抖动对于人类来说是感觉不到的,但对单片机来说,则是完全可以感应到的,而且还是一个很漫长的过程,因为单片机处理的速度在微秒级,而按键抖动的时间至少在毫秒级。
一次按键动作的电平波形如下图。存在抖动现象,其前后沿抖动时间一般在 5ms~10ms 之间。由于单片机运行速度非常快,刚按下的时候会检测到低电平判断按键被按下。但是由于按键存在抖动,单片机在此时也会检测到高电平,误以为松开按键,紧接着又检测到低电平,判断到按键被按下。周而复始,在 5-10ms 内可能会出现很多次按下的动作,每一次按键的动作判断的次数都不相同。
![](https://gcore.jsdelivr.net/gh/bigrich-luo/typora-picgo-images-1@master/images/202303121127685.png)
这种抖动可能会影响程序误判,造成严重后果,一般我们采用两种方式对按键进行消抖:
- 硬件消抖,硬件消抖的典型做法是:采用 R-S 触发器或 RC 积分电路。
- 软件消抖,通常我们会使用软件延时 10ms 来消抖。例如,当按键按下后,引脚为低电平;所以首先读取引脚电平,若引脚为低电平,则延时 10ms 后再次读取引脚电平,若为低电平,则证明按键已按下。
硬件方法一般用在对按键操作过程比较严格,且按键数量较少的场合,而按键数量较多时,通常采用软件消抖。值得一提的是,对于复杂且多任务的单片机系统来说,若简单地采用循环指令来实现软件延时,则会浪费CPU宝贵的时间资源,大大降低系统的实时性,所以,更好的做法是利用定时中断服务程序或利用标志位的方法来实现软件消抖。
硬件电路设计
使用按键电路实现开关灯的效果。
物料清单(BOM 表):
材料名称 | 数量 |
---|---|
直插式 LED | 1 |
1kΩ 电阻 | 1 |
4 脚按键 | 1 |
杜邦线(跳线) | 若干 |
面包板 | 1 |
将材料按照下图相连:
按键一端接 3V3 引脚,一端接 D14,LED 接 D2。
![](https://gcore.jsdelivr.net/gh/bigrich-luo/typora-picgo-images-1@master/images/202303121853387.png)
软件程序设计
此处我们需要使用 machine
模块中的 Pin
模块对 GPIO 输入检测。
与输出不同的是,设置输入引脚时,我们需要配置上拉或下拉电阻,目的是确定某个状态电路中的高电平或低电平。
上、下拉电阻的作用是提高电路稳定性,避免引起误动作。按键如果不通过电阻上拉到高电平,那么在上电瞬间可能就发生误动作,因为在上电瞬间单片机的引脚电平是不确定的,上拉电阻的存在保证了其引脚处于高电平状态,而不会发生误动作。
提示
如果你不认识上拉电阻和下拉电阻,在这个阶段是无所谓的,你只需要了解他们的存在是为了确定初始电平状态。 选择上拉电阻,GPIO 引脚默认位高电平,那我们想要改变信号,就需要传递一个低电平,接地。 选择下拉电阻,GPIO 引脚默认为低电平,那我们想要改变信号,就需要传递一个高电平,接电源。
因此,我们的代码需要这么写:
import time
from machine import Pin
# 创建按键输入引脚类,如果引脚的一端接 Vcc,则设置下拉电阻;如果一端接的是 GND,则配置上拉电阻。
pin_button = Pin(14, Pin.IN, Pin.PULL_DOWN)
# 定义 LED 输出引脚
pin_led = Pin(2, Pin.OUT)
# 判断 LED 的状态是否改变过
status = 0
while True:
# 按键消抖
if pin_button.value() == 1:
# 睡眠 10ms,如果依然为高电平,说明抖动已消失。
time.sleep_ms(10)
# 延时 10ms 后,如果依然为高电平,并且 LED 的状态没有改变
if pin_button.value() == 1 and status == 0:
pin_led.value(not pin_led.value())
# led 的状态发生了变化,即使我持续按着按键,LED 的状态也不应该改变。
status = 1
# 按键松开,记录 LED 状态的变量也需要响应的改变。
elif pin_button.value() == 0:
status = 0