Матричная клавиатура 4x4 на Arduino: подключение и сканирование
Мембранная клавиатура 4x4 — плёнка с шестнадцатью кнопками за цену пачки чая, и это самый дешёвый способ дать устройству полноценный ввод: цифры 0-9 плюс A, B, C, D, звёздочка и решётка. Ловушка в другом: у каждой кнопки нет своего пина. Шестнадцать кнопок живут на восьми проводах, потому что каждая — пересечение строки и столбца, и найти нажатие можно только сканированием. Кто не понимает принципа — сидит на четырёх кнопках и фортепианной раскладке из шестнадцати пинов.
В симуляторе клавиатура — компонент палитры «Макетка»: восемь пинов строк и столбцов, клавиши нажимаются мышкой в карточке, сканер в скетче видит нажатия по-настоящему. Скан без библиотеки рантайм исполняет целиком — прогон ниже; а вот getKey() из Keypad.h браузер не исполняет, и это честно зафиксировано в таблице границы.
Матрица: почему 16 кнопок живут на 8 проводах
Плёнка — клетчатая сетка: четыре строки и четыре столбца, кнопка замыкает свою строку со своим столбцом и больше ни с чем. Контроллер не спрашивает кнопки по одной — он проводит эксперимент: ставит одной строке активный уровень и слушает все четыре столбца. Нажатая кнопка переносит уровень строки на её столбец, и пересечение считается как шахматный ход: строка с индексом 2, столбец с индексом 1 — нажата клавиша на их перекрёстке. Полный проход — 16 опросов, на 16 МГц это микросекунды, так что сканить можно хоть тысячу раз в секунду и всё равно не пропустить нажатие.
- 8 проводов шлейфа: R1-R4 — строки, C1-C4 — столбцы; на Uno я сажаю их подряд на D2-D9.
- Строки — OUTPUT, столбцы — INPUT_PULLUP: подтяжка не даёт неопрошенному столбцу читать воздух.
- Активная строка даёт HIGH, нажатый столбец отдаёт LOW — так выставлена и сцена симулятора.
- Раскладка клавиш хранится массивом на 16 ячеек: индекс = строка × 4 + столбец.
- 16 кнопок на 8 пинов — предел простой сетки; больше кнопок — I2C-расширитель наподобие PCF8574.
Скетч: сканер без библиотеки
const int STROKI[4] = {2, 3, 4, 5};const int STOLBY[4] = {6, 7, 8, 9};char klavishi[16] = {'1','2','3','A','4','5','6','B','7','8','9','C','*','0','#','D'}; void setup() { for (int r = 0; r < 4; r++) pinMode(STROKI[r], OUTPUT); for (int c = 0; c < 4; c++) pinMode(STOLBY[c], INPUT_PULLUP); Serial.begin(9600);} void loop() { for (int r = 0; r < 4; r++) { digitalWrite(STROKI[r], HIGH); // ведём строку for (int c = 0; c < 4; c++) { if (digitalRead(STOLBY[c]) == LOW) { // столбец прижат — клавиша Serial.print("Klavisha: "); Serial.println(klavishi[r * 4 + c]); delay(250); // грубая защита от дребезга } } digitalWrite(STROKI[r], LOW); // гасим строку }}Прогон в симуляторе: компонент «Матричная клавиатура 4x4» из палитры «Макетка» — строки на D2-D5, столбцы на D6-D9, как в скетче. Нажимаете клавишу «5» в карточке — в мониторе печатается Klavisha: 5; держите — через 250 мс приходит повтор, это работает та же задержка от дребезга. Уровни в браузере и на живой плате зеркальны: в реальной матрице строку ведут LOW при подтянутых INPUT_PULLUP столбцах — поменяется один уровень в скетче, логика не сдвинется ни на строку. Именно так сканер и устроен в уроке про матричную клавиатуру — с раскладкой, призраками трёх кнопок и антидребезгом вглубь.
Keypad.h: что она даёт на живой плате
| Возможность | Библиотека Keypad.h | Свой сканер |
|---|---|---|
| Скан и раскладка | внутри, объект keypad.getKey() | два цикла, видно каждую строку |
| События нажатия/отпускания | да: KEYEVENT_* и state-машина | пишутся руками при нужде |
| Мультинажатия с диодами | поддержаны | ограниченно |
| Исполнение в симуляторе | нет: getKey даёт «Неизвестное имя» | да — исполняется целиком |
Библиотека честная и на плате я её ставлю без стеснения: конструктор Keypad(makeKeymap(keys), rowPins, colPins, 4, 4), дальше getKey() вместо циклов. Но в браузере её вызовы не исполняются: скетч с Keypad.h компилируется, а первый getKey() падает с «Неизвестное имя» — рантайм знает сканер на пинах, а не класс библиотеки. Поэтому схема работы двусторонняя: логику и раскладку гоняете в симуляторе своим сканером, Keypad.h подключаете на живой плате, когда нужен state-машина с событиями. Для типового кодового замка свой сканер закрывает всё: урок с кодовым замком 4x4 собран именно без библиотеки, калькулятор с LCD — тоже.
Грабли мембранки
- Зеркальная раскладка: производители нумеруют выводы кто как; чинится массивом klavishi[], провода не перекладываются.
- Дребезг: один повтор на проход сканера; пауза 100-250 мс после срабатывания — грубо, но честно.
- Призраки: три нажатых кнопки рождают четвёртую — ток идёт в обход; лечится диодами в разрыв каждой кнопки.
- Пины строк и столбцов перепутаны местами: нажатие отзывается не в том столбце — сверьте первую пару проводов.