Как использовать клавиатуру с Raspberry Pi 4
В данном материале разберём простой способ подключения клавиатуры к Raspberry Pi 4 для различных задач.
Для пользователей доступно множество вариантов ввода данных в Raspberry Pi. Один из них — применение 16-кнопочной клавиатуры, содержащей цифры от нуля до девяти и несколько дополнительных кнопок:
Далее мы расскажем о принципе работы таких клавиатур и о том, как без труда интегрировать их в проекты с Raspberry Pi 4.
Клавиатура
Используемую клавиатуру можно разбить на четыре строки и четыре столбца:
Для определения нажатой кнопки Raspberry Pi последовательно подаёт импульс на каждый из четырёх рядов клавиатуры. Когда пользователь нажимает кнопку, подключённую к линии, находящейся в данный момент в состоянии HIGH, соответствующий столбец также переходит в HIGH.
По комбинации строки и столбца можно определить, какая именно кнопка была нажата. К примеру, если пользователь нажимает кнопку B, расположенную во второй строке четвёртого столбца, Raspberry Pi обнаруживает нажатие в момент подачи импульса на вторую строку и последующей проверки состояния четырёх столбцов.
Подключение клавиатуры к Raspberry Pi 4
Клавиатуры подобного типа не требуют внешнего питания для работы. Достаточно просто подсоединить все восемь линий данных клавиатуры к любым восьми контактам GPIO на Raspberry Pi:
Использована та же цветовая маркировка, что и на изображении выше. Синие провода обозначают строки, а оранжевые — столбцы.
Простой пример кода
После выполнения подключений согласно приведённой выше схеме можно запустить несложную тестовую программу, которая будет выводить в консоль Raspberry Pi информацию о нажимаемых клавишах:
# GPIO setup and imports omitted
def readLine(line, characters):
GPIO.output(line, GPIO.HIGH)
if(GPIO.input(C1) == 1):
print(characters[0])
if(GPIO.input(C2) == 1):
print(characters[1])
if(GPIO.input(C3) == 1):
print(characters[2])
if(GPIO.input(C4) == 1):
print(characters[3])
GPIO.output(line, GPIO.LOW)
try:
while True:
readLine(L1, ["1","2","3","A"])
readLine(L2, ["4","5","6","B"])
readLine(L3, ["7","8","9","C"])
readLine(L4, ["*","0","#","D"])
time.sleep(0.1)
except KeyboardInterrupt:
print("\nApplication stopped!")
Как видно, тестовая программа содержит метод readLine. Этот метод подаёт импульс на одну строку, после чего проверяет, какая из кнопок была нажата в момент, когда линия находилась в HIGH. Процедура повторяется для всех четырёх рядов. Метод также принимает список символов, соответствующих кнопкам.
Данная программа является базовым примером. Она не способна определить, удерживается ли кнопка нажатой, — при каждом отправленном импульсе фиксируется новое нажатие. Далее приводится более продвинутая программа, корректно распознающая отдельные нажатия и реализующая простую кодовую блокировку.
Бюджетные клавиатуры, как правило, устроены одинаково: четыре строки и четыре столбца. Ввод определяется путём подачи импульса в каждую строку с последующей проверкой столбцов для выявления нажатой кнопки.
Продвинутый код
Базовую версию приложения реализовать несложно, однако при необходимости более продвинутого функционала код может существенно усложниться.
Пример 1
import RPi.GPIO as GPIO
import time
L1 = 5
L2 = 6
L3 = 13
L4 = 19
C1 = 12
C2 = 16
C3 = 20
C4 = 21
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(L1, GPIO.OUT)
GPIO.setup(L2, GPIO.OUT)
GPIO.setup(L3, GPIO.OUT)
GPIO.setup(L4, GPIO.OUT)
GPIO.setup(C1, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(C2, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(C3, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(C4, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
def readLine(line, characters):
GPIO.output(line, GPIO.HIGH)
if(GPIO.input(C1) == 1):
print(characters[0])
if(GPIO.input(C2) == 1):
print(characters[1])
if(GPIO.input(C3) == 1):
print(characters[2])
if(GPIO.input(C4) == 1):
print(characters[3])
GPIO.output(line, GPIO.LOW)
try:
while True:
readLine(L1, ["1","2","3","A"])
readLine(L2, ["4","5","6","B"])
readLine(L3, ["7","8","9","C"])
readLine(L4, ["*","0","#","D"])
time.sleep(0.1)
except KeyboardInterrupt:
print("\nApplication stopped!")
Пример 2
import RPi.GPIO as GPIO
import time
# These are the GPIO pin numbers where the
# lines of the keypad matrix are connected
L1 = 5
L2 = 6
L3 = 13
L4 = 19
# These are the four columns
C1 = 12
C2 = 16
C3 = 20
C4 = 21
# The GPIO pin of the column of the key that is currently
# being held down or -1 if no key is pressed
keypadPressed = -1
secretCode = "4789"
input = ""
# Setup GPIO
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(L1, GPIO.OUT)
GPIO.setup(L2, GPIO.OUT)
GPIO.setup(L3, GPIO.OUT)
GPIO.setup(L4, GPIO.OUT)
# Use the internal pull-down resistors
GPIO.setup(C1, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(C2, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(C3, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(C4, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
# This callback registers the key that was pressed
# if no other key is currently pressed
def keypadCallback(channel):
global keypadPressed
if keypadPressed == -1:
keypadPressed = channel
# Detect the rising edges on the column lines of the
# keypad. This way, we can detect if the user presses
# a button when we send a pulse.
GPIO.add_event_detect(C1, GPIO.RISING, callback=keypadCallback)
GPIO.add_event_detect(C2, GPIO.RISING, callback=keypadCallback)
GPIO.add_event_detect(C3, GPIO.RISING, callback=keypadCallback)
GPIO.add_event_detect(C4, GPIO.RISING, callback=keypadCallback)
# Sets all lines to a specific state. This is a helper
# for detecting when the user releases a button
def setAllLines(state):
GPIO.output(L1, state)
GPIO.output(L2, state)
GPIO.output(L3, state)
GPIO.output(L4, state)
def checkSpecialKeys():
global input
pressed = False
GPIO.output(L3, GPIO.HIGH)
if (GPIO.input(C4) == 1):
print("Input reset!");
pressed = True
GPIO.output(L3, GPIO.LOW)
GPIO.output(L1, GPIO.HIGH)
if (not pressed and GPIO.input(C4) == 1):
if input == secretCode:
print("Code correct!")
# TODO: Unlock a door, turn a light on, etc.
else:
print("Incorrect code!")
# TODO: Sound an alarm, send an email, etc.
pressed = True
GPIO.output(L3, GPIO.LOW)
if pressed:
input = ""
return pressed
# reads the columns and appends the value, that corresponds
# to the button, to a variable
def readLine(line, characters):
global input
# We have to send a pulse on each line to
# detect button presses
GPIO.output(line, GPIO.HIGH)
if(GPIO.input(C1) == 1):
input = input + characters[0]
if(GPIO.input(C2) == 1):
input = input + characters[1]
if(GPIO.input(C3) == 1):
input = input + characters[2]
if(GPIO.input(C4) == 1):
input = input + characters[3]
GPIO.output(line, GPIO.LOW)
try:
while True:
# If a button was previously pressed,
# check, whether the user has released it yet
if keypadPressed != -1:
setAllLines(GPIO.HIGH)
if GPIO.input(keypadPressed) == 0:
keypadPressed = -1
else:
time.sleep(0.1)
# Otherwise, just read the input
else:
if not checkSpecialKeys():
readLine(L1, ["1","2","3","A"])
readLine(L2, ["4","5","6","B"])
readLine(L3, ["7","8","9","C"])
readLine(L4, ["*","0","#","D"])
time.sleep(0.1)
else:
time.sleep(0.1)
except KeyboardInterrupt:
print("\nApplication stopped!")
На этом всё. Успешных проектов.