从零玩转Micropython+ESP32(五) GPIO输入和按键操作
前面我们使用了GPIO输出高低电平, 并实现了点灯和闪灯的效果, 但GPIO引脚可不仅仅是输出这么简单, 它还可以检测信号的输入, 来实现控制效果
现在我们就来学习一下吧!
友情提示: 学完本集之后, 请不要用这种方法控制核弹发射🤣🤣🤣
一. 输入电路
1. 引脚输入
我们的引脚非常强大, 当它处于输入模式时, 如果引脚收到高低电平, 就可以获取这些电平, 并将高电平转为1, 将低电平转为0
于是, 我们明白了: 我们给引脚加高电平就相当于告诉单片机一个数字1, 给引脚加低电平就相当于告诉单片机一个数字0
输入电路可以让我们收到外部的信息和命令, 让ESP32实现更加强大的功能
2. 怎么给引脚加高低电平呢?
那么, 我们要怎么给引脚加高低电平呢?
在ESP32开发板上有多个电压来源, 根据板子的不同,可能有不同的标识, 比如3V3 VIN VCC等等
与之对应的, ESP32开发板上也有多个预留的接地点, 比如: GND G等等
比如, 我们将3V3引脚和D5引脚连起来, D5引脚就能获得高电平, 我们将GND引脚和D5引脚连起来, D5引脚就能获得低电平
3. 按键输入电路
上面, 我们学会了输入高低电平, 但是靠短接电源和地输入0, 1是很不方便的, 我们最好能有个按键, 按键按下输入1, 按键抬起输入0, 或者按键按下输入0, 按键抬起输入1也行
所以,根据刚才的分析, 我们可以设计出这样的电路图 (输入电路有好多种形式, 这里我们介绍一种典型了的: 外上拉)
当按键抬起时, VCC电源和引脚D5接通, 形成了高电平, 电流会流过电阻, 再流进D5引脚
当按键按下后, GND和引脚D5接通了, 形成了低电平, 电流会流过电阻, 直接流向GND, 而不流向D5, 因为D5内部是有一点阻抗的
电阻R的阻值随意1K 2K 10K都可以
不过在这里, 告诉大家一个好消息, 我们使用的开发板上已经有一个引脚已经接上了按键, 那就是0号引脚, 所以我们不用自己搭建按键电路了
0号引脚连到了哪个按键呢??? 就是开发板右边这个BOOT按键, 其接线电路就和我们刚刚描述的电路原理图一样
下面, 我们就先用这个按键进行实验
二. MicroPython控制GPIO输入
1. 初始化GPIO为输入
key = Pin(0, Pin.IN)
2. 检测GPIO输入值
key.value()
3. 编写一个程序, 实现按键检测
这里我们要注意加一个延时, 因为不加延时的话, 由于运算太空, 终端会卡死
from machine import Pin #导入引脚模块
import time #导入时间模块
key = Pin(0, Pin.IN) #把0号引脚初始化为输入模式, 并取名为key
while True:
print("GPIO_0:", key.value()) #打印当前0号引脚输入状态
time.sleep(0.01) #延时0.01秒
4. 编写一个程序, 实现按灯即亮
只需要稍微改一改程序
from machine import Pin #导入引脚模块
import time #导入时间模块
key = Pin(0, Pin.IN) #把0号引脚初始化为输入模式, 并取名为key
led = Pin(2, Pin.OUT) #把2号引脚初始化为输出模式, 并取名为led
while True:
print("GPIO_0:", key.value()) #打印当前0号引脚输入状态
led.value(not key.value()) #给led设置值, 因为按键按下时是0, 所以取一下反
time.sleep(0.01) #延时0.01秒
2. GPIO
from machine import Pin, PWM
import time
pwm_freq = 50 #PWM频率
duty_range = 1000 #PWM最大占空比 千分之多少
delay_rgs = 3 #延迟系数
while 1:
for i in range(0,duty_range):
pwm2 = PWM(Pin(5), freq=pwm_freq, duty=25)
time.sleep_ms(delay_rgs)
for i in range(0,duty_range):
pwm2 = PWM(Pin(5), freq=pwm_freq, duty=50)
time.sleep_ms(delay_rgs)
for i in range(0,duty_range):
pwm2 = PWM(Pin(5), freq=pwm_freq, duty=75)
time.sleep_ms(delay_rgs)
for i in range(0,duty_range):
pwm2 = PWM(Pin(5), freq=pwm_freq, duty=100)
time.sleep_ms(delay_rgs)
for i in range(0,duty_range):
pwm2 = PWM(Pin(5), freq=pwm_freq, duty=125)
time.sleep_ms(delay_rgs)
三. 学会搭建按键电路
1. 搭建按键电路
根据上面的电路图, 我们可以这样搭建电路
2. 使用大按键模块
这里推荐大家使用下面这种大按键模块, 大家做实验时可以直接用, 因为它已经焊好了电阻
但这种按键内部电路是这样的:
可以看到, 此模块把电阻R放在了GND管脚一侧, 这和我们的电路图不一样了, 所以, 我们使用时应该把vcc和gnd引脚反过来接线, 如下图
当然, 如果手头没有这种大按键模块, 用普通按键串联电阻也是可以的
搭建完电路后, 我们把上面程序中的0号引脚改为5号引脚即可进行实验
四. 小挑战
1. 按键 开/关 灯
实现这个功能: 按一下按键亮灯, 再按一下灭灯
from machine import Pin # 导入引脚模块
import time # 导入时间模块
key = Pin(5, Pin.IN) # 把0号引脚初始化为输入模式, 并取名为key
led = Pin(2, Pin.OUT) # 把2号引脚初始化为输出模式, 并取名为led
light_flag = False # 创建一个亮灯标志位, 用于管理LED灯的开关状态
while True:
print("GPIO_0:", key.value()) # 打印当前0号引脚输入状态
if not key.value(): # 如果按键被按下
while not key.value(): # 当按键没抬起之前一直死循环在这里
pass
light_flag = not light_flag # 能运行到这里, 说明上面的循环已经被打破, 证明按键已经被抬起
if light_flag: # 根据亮灯标志位判断灯是否亮
led.value(1)
else:
led.value(0)
time.sleep(0.01) # 延迟0.01秒
2. 按键 开/关 闪灯
大家再试着做一个按键闪灯效果: 按一下按键闪灯, 再按一下熄灯
from machine import Pin # 导入引脚模块
import time # 导入时间模块
key = Pin(5, Pin.IN) # 把0号引脚初始化为输入模式, 并取名为key
led = Pin(2, Pin.OUT) # 把2号引脚初始化为输出模式, 并取名为led
light_flag = False # 创建一个亮灯标志位, 用于管理LED灯的开关状态
while True:
print("GPIO_0:", key.value()) # 打印当前0号引脚输入状态
if not key.value(): # 如果按键被按下
while not key.value(): # 当按键没抬起之前一直死循环在这里
pass
light_flag = not light_flag # 能运行到这里, 说明上面的循环已经被打破, 证明按键已经被抬起
if light_flag: # 根据亮灯标志位判断灯是否亮
led.value(not led.value())
time.sleep(1)
else:
led.value(0)
time.sleep(0.01) # 延迟0.01秒
这里大家就发现问题了, 我们发现启动闪灯很简单, 但关闭闪灯有时候不行, 得按的久一点才行, 这是为什么呢???
这是因为, 当程序执行time.sleep(1)的时候, 系统会睡一秒钟, 这一秒钟无论我们怎么按, 都不会执行到 if not key.value():
这个分支, 导致我们按键是无效的, 这个问题我们后面会解决, 现在我就按的久一点
3. 按0键 开/关 闪灯, 按5键调整闪灯速度
效果: 按一下按键0闪灯, 再按一下熄灯, 按下按键5会加快闪灯速度(每次加快0.2秒), 最快0.2秒一闪, 最慢1秒一闪, 当到达最快速度后再按键会重置为1秒一闪, 老样子, 我们按键要按久一点
from machine import Pin # 导入引脚模块
import time # 导入时间模块
key = Pin(0, Pin.IN) # 把0号引脚初始化为输入模式, 并取名为key
key2 = Pin(5, Pin.IN) # 把5号引脚初始化为输入模式, 并取名为key
led = Pin(2, Pin.OUT) # 把2号引脚初始化为输出模式, 并取名为led
light_flag = False # 创建一个亮灯标志位, 用于管理LED灯的开关状态
flash_span = 1 # 默认间隔一秒钟
while True:
if not key.value(): # 如果按键0被按下
while not key.value():
pass
light_flag = not light_flag
if not key2.value(): # 如果按键0被按下
while not key2.value():
pass
flash_span -= 0.2 # 减少闪灯间隔
if flash_span < 0.2: # 当减到最少时, 重置为1秒
flash_span = 1
print(flash_span) # 打印一下当前间隔
if light_flag: # 根据亮灯标志位判断灯是否亮
led.value(not led.value())
time.sleep(flash_span)
else:
led.value(0)
time.sleep(0.01) # 延迟0.01秒