课程2:昉·星光开发板按键处理
本次课程为昉·星光开发板IoT开发系列课程的第二讲,将带领同学们在昉·星光开发板上,通过GPIO进行按键处理。
一、学习目标
- 学习昉·星光开发板GPIO输入和普通按键处理
- 学习昉·星光开发板上矩阵键盘的处理
二、准备工作
在开始本次课程的实际操作之前,同学们需要做好一些准备工作,课程中涉及到的硬件如下:
- 开发板:昉·星光开发板
- LED:单色LED模块
- 按键与键盘:
- 普通按键
- 薄膜键盘
- 杜邦线:若干
三、Ubuntu系统设备权限设置
在第一讲中,当运行GPIO相关的指令,或者运行Python程序时,都使用到了sudo来取得root权限运行。
大多数时候,我们希望在普通用户环境下,也能编程控制GPIO设备。
在Ubuntu系统中,可以通过设置合适的udev规则,来使得普通用户也可以得到所需的权限。
GPIO设备的udev权限设置如下:
# 添加gpio用户组
sudo groupadd -f -r gpio
# 将当前用户添加到gpio组
sudo usermod -a -G gpio $USER
# 设置gpio的udev权限规则
sudo nano /etc/udev/rules.d/99-gpio.rules
# 将下面的内容添加到文件中
SUBSYSTEM=="gpio", KERNEL=="gpiochip*", ACTION=="add", RUN+="/bin/chgrp -R gpio /sys/class/gpio/export /sys/class/gpio/unexport /dev/gpiochip0 /dev/gpiochip1", RUN+="/bin/chmod -R u+rw,g=u /sys/class/gpio/export /sys/class/gpio/unexport /dev/gpiochip0 /dev/gpiochip1"
SUBSYSTEM=="gpio", KERNEL=="gpio*", ACTION=="add", RUN+="/bin/chgrp -R gpio /sys%p", RUN+="/bin/chmod -R u+rw,g=u /sys%p", RUN+="/bin/chmod -R u+rw,g=u /sys%p/value"
SUBSYSTEM=="gpio", KERNEL=="gpio*", ACTION=="change", ENV{TRIGGER}!="none", RUN+="/bin/chgrp -R gpio /sys%p", RUN+="/bin/chmod -R u+rw,g=u /sys%p", RUN+="/bin/chmod -R u+rw,g=u /sys%p/value"
# 重置udev规则使其生效
sudo udevadm control --reload-rules
# 查看规则:列出文件的用户和组均为root gpio
ls -lh /dev/gpiochip* /sys/class/gpio/{export,unexport}
# 如有可能,重启生效更彻底
sudo reboot
四、普通按键处理
在第一讲中,我们通过GPIO控制LED,是通过GPIO输出高低电平来控制的。
而要使用按键,则需要通过GPIO输入信息。通常按键会有按下时候的电平,本次课程实验准备的按键模块,是按下低电平。
我们需要获取按键的状态,并根据状态来设置LED,如果按下按键,则点亮LED,如果松开按键,则熄灭LED。
首先,参考下图,将单色LED模块和按键模块,连接到昉·星光开发板:
实物连接如下:
然后,编写如下的程序:
# -*- coding: utf-8 -*-
# file: ~/projects/key/button.py
import time
import gpio as GPIO
LED = 448
BUTTON = 450
GPIO.setup(LED, GPIO.OUT)
GPIO.setup(BUTTON, GPIO.IN)
value_prev = 1
GPIO.output(LED, GPIO.LOW)
while True:
value = GPIO.input(BUTTON)
if not value == value_prev:
value_prev = value
if value == 1:
GPIO.output(LED, GPIO.LOW)
else:
GPIO.output(LED, GPIO.HIGH)
time.sleep(0.1)
上述程序的逻辑较为简单,就是检测按键状态,然后为高电平(松开)则熄灭LED,为低电平(按下)则点亮LED。
编写完成后,运行 button.py ,即可按键控制LED了。
# 如果遇到错误,再次运行,直到正常运行不出错为止:
python3 button.py
五、矩阵键盘处理
除了通常的普通按键以外,常用的按键还有ADC按键和矩阵按键。ADC按键通过检测电压值来区分不同的按键,矩阵按键则通常通过逐行扫描的方式来检测按键。
因为昉·星光开发板上没有ADC模块,需要外接转接板才能使用ADC按键,因此本次课程就先不讲ADC按键了。
矩阵按键仅需要足够的GPIO口,就可以进行检测。昉·星光开发板有40Pin,足够使用了。
矩阵键盘的原理并不是很复杂,通常一个4x4的矩阵键盘结构如下:
矩阵键盘通过上线路(列)和下线路(行)的联通,来进行按键的区分检测。
线路的默认电平都为低电平。每次检测时,先将上线路4条线路中的第1条线路设置为高电平,然后马上检测下线路4条线路的电平状态。如果检测到下线路某条线为高电平,说明这条线路,与上线路第1条线的交叉点联通,从而确定具体的按键位置。如果没有检测到高电平,则将上线路4条线路中的第2条线路设置为高电平,然后重复下线路检测过程。直到检测完成。因为检测的速度很快,所以可以较为准确的确定具体的按键。
这样检测的好处在于,只需要n+m根线,即可检测n*m个按键,极大了减少了开发板上GPIO口的占用。
注意:在有的资料中,会选择默认高电平,检测低电平的方式;另外,上下线路原则上,是可以互换的,只需要对好逻辑关系即可。
了解以上原理以后,我们就可以开始实际操作了。参考下图,将矩阵键盘连接到昉·星光开发板上:
连好线后的实物如下:
为了方便操作,把连接线压到了昉·星光开发板的下面。
之前我们使用的GPIO模块,较为基础,不适合复杂的GPIO操作。要完成矩阵模块的检测,我们需要使用更为高级的gpiod模块,通过如下指令安装:
# 安装系统gpiod工具
sudo apt install gpiod
# 安装Python的gpiod模块
sudo pip install gpiod
# 查看系统gpio处理设备:
sudo gpiodetect
# 查看gpio设备:
sudo gpioinfo
通过gpiodetect和gpioinfo,可以查看到昉·星光开发板上的GPIO设备情况。
gpiod比之前通过shell或者python3-gpio操作更方便,引脚与设备号之间,不需要转换,40Pin上的GPIO0,在gpiod里面,直接就对应0号,下面要编写的程序中就能体现。
安装完成后,编写如下的程序:
# -*- coding: utf-8 -*-
# file: ~/projects/key/keypad.py
import sys
from datetime import timedelta
from gpiod import chip, line_request, line_event
import time
# 设置按键键码
KEYPAD = [
["1","2","3","A"],
["4","5","6","B"],
["7","8","9","C"],
["*","0","#","D"]
]
# 设置行列对应的GPIO引脚
ROW_PINS = [0,1,2,3] # 控制行
COL_PINS = [4,6,8,9] # 控制列
# 使用gpiochip0,其为40Pin的gpio处理设备
c = chip(0)
# 设置控制行输出模式
config = line_request()
config.request_type = line_request.DIRECTION_OUTPUT
# 设置4个控制行
pins = [None, None, None, None]
for i in range(len(ROW_PINS)):
# 设为输出口
pins[i] = c.get_line(ROW_PINS[i])
pins[i].request(config)
pins[i].set_value(0)
# 设置控制列为输入:上升沿触发配置,下拉模式
buttons = c.get_lines(COL_PINS)
config = line_request()
config.request_type = line_request.EVENT_RISING_EDGE
config.flags = line_request.FLAG_BIAS_PULL_DOWN
# 设置按键输入
for i in range(buttons.size):
config.consumer = "{}".format(i)
buttons[i].request(config)
# 扫描按键
def scanLine(line,characters):
# 检测开始,设置高电平
line.set_value(1)
# 检测按键
lines = buttons.event_wait(timedelta(seconds=0.05))
if not lines.empty:
for it in lines:
event = it.event_read()
# 检测触发状态
if event.event_type == line_event.RISING_EDGE:
# 输出对应的按键
print("Key: ", characters[int(it.consumer)])
# 检测完毕,设置低电平
line.set_value(0)
try:
print("\nKeyPad detector start:")
while True:
# 依次扫描
for i in range(len(ROW_PINS)):
scanLine(pins[i], KEYPAD[i])
except KeyboardInterrupt:
print("\nKeyPad detector stopped!")
编写完程序后,运行该程序,并进行按键测试,即可收到如下的输出结果:
六、总结
在本次课程中,我们学习了通过GPIO来读取普通按键的状态,并进一步学习了矩阵按键的处理。
这两种按键,在IoT开发中,都很常用,用于使用者的基本输入处理。
在矩阵按键处理中,使用到了gpiod模块,其使用比gpio模块要复杂,但是可以做的操作更多,可以详细了解学习。
如果要进一步学习gpiod模块的用法,可以查看网址:Python gpiod | https://wiki.loliot.net/docs/lang/python/libraries/gpiod/python-gpiod-about/
七、课后作业
- 了解gpiod的用法
- 编写通过矩阵按键,来控制LED的程序
- 长按键或者短按键,观察样例程序的输出,然后尝试编程实现判断长按键和短按键