Библиотека для опроса матричной клавиатуры 4x4 и 3х4

13/10/2011 - 05:03

Введение

Написал программный модуль для опроса матричной клавиатуры.

Особенности модуля:

- простая интеграция с готовым проектом
- поддержка всех микроконтроллеров семейства mega
- возможность использования с любым из трех компиляторов CodeVision, IAR, GCC
- поддержка клавиатур 4х4 и 3х4
- поддержка работы на общей шине
- возможность подключения к одному или двумя портами
- программная антидребезговая защита
- возможность установки произвольных кодов кнопок

Подключение модуля

- скачиваем архив с модулем
- переписываем файлы keyboard.h и keyboard.c в папку проекта
- подключаем keyboard.c к проекту внутри среды разработки
- включаем keyboard.h в требуемый файл проекта, например main.c
- настраиваем конфигурацию в файле keyboard.h
- прописываем в свой код вызов пользовательских функций
 
Настройка конфигурации включает в себя несколько шагов.
 
Установка тактовой частоты микроконтроллера
 
#define F_CPU 16000000
 
   При высокой тактовой частоте микроконтроллера логические сигналы, формируемые программным модулем, из-за паразитных емкостей «не успевают» устанавливаться до требуемого уровня. Поэтому в некоторых местах кода используется программная задержка, для вычисления которой требуется значение тактовой частоты.
Установка типа матричной клавиатуры – 4х4 или 3х4
 
#define KEYBOARD_4X4
 
   Если закомментировать это макроопределение будет установлена клавиатура 3х4. 
Тип заданной клавиатуры сообщается пользователю в процессе сборки проекта. Поэтому не удивляйтесь предупреждению в окне Messages. 
 
Установка типа подключения матричной клавиатуры 
 
#define COMMON_BUS
 
   Для подключения клавиатуры и индикаторов часто используют общую шину, что позволяет экономить выводы микроконтроллера. Если это макроопределение не закомментировано, значит, клавиатура подключена именно таким способом.
   В этом случае выводы, используемые клавиатурой, конфигурируются лишь на время ее опроса. А по завершению процедуры опроса состояние выводов восстанавливается.  
   Закомментировав макроопределение, можно сэкономить несколько байт флеш памяти.
 
Установка  портов, к которым подключены строки и столбцы клавиатуры
 
//порт, к которому подключены строки
#define PORTX_ROW PORTA
#define PINX_ROW  PINA
#define DDRX_ROW  DDRA
 
//порт, к которому подключены столбцы
#define PORTX_COL PORTB
#define PINX_COL  PINB
#define DDRX_COL  DDRB
 
   Все строки клавиатуры должны быть подключены к одному порту микроконтроллера. Данный модуль не позволяет подключить, например, одну строку к порту B, а остальные к порту С. Это же относится и к столбцам клавиатуры. 
   При этом группа строк или столбцов клавиатуры может быть подключена как к одному, так и к разным портам микроконтроллера. 
 
Установка  выводов, к которым подключены строки и столбцы клавиатуры
 
//выводы, к которым подключены строки 
#define PIN_ROW1 4
#define PIN_ROW2 5
#define PIN_ROW3 6
#define PIN_ROW4 7
 
//выводы, к которым подключены столбцы
#define PIN_COL1 0
#define PIN_COL2 1
#define PIN_COL3 2
#define PIN_COL4 3
 
   Выводы микроконтроллера, подключенные к строкам и столбцам матричной клавиатуры, не должны совпадать между собой. Это требования должно выполняться, когда клавиатура подключена к двум портам микроконтроллера.
 
Установка кодов кнопок
 
//коды кнопок
#define EVENT_NULL 0
#define EVENT_KEY0 '0'
#define EVENT_KEY1 '1'
#define EVENT_KEY2 '2'
#define EVENT_KEY3 '3'
#define EVENT_KEY4 '4'
#define EVENT_KEY5 '5'
#define EVENT_KEY6 '6'
#define EVENT_KEY7 '7'
#define EVENT_KEY8 '8'
#define EVENT_KEY9 '9'
#define EVENT_KEYA 'A'
#define EVENT_KEYB 'B'
#define EVENT_KEYC 'C'
#define EVENT_KEYD 'D'
#define EVENT_KEYZ '*'
#define EVENT_KEYR '#'
 
   Здесь никаких требований нет. Коды кнопок совершенно произвольные. Можно задать символьные значения, соответствующие кнопкам клавиатуры, как это сделано по умолчанию. А можно задать коды, которые будут использоваться в событийной системе. 

Использование модуля

   В модуле реализовано три пользовательские функции.
 
void KEYB_Init(void) – функция инициализации
void KEYB_ScanKeyboard(void) – функция сканирования клавиатуры
unsigned char KEYB_GetKey(void) – функция проверки буфера
 
KEYB_Init() нужно запускать перед использованием двух других функций. Обычно это делается  в начале main`a.
 
KEYB_ScanKeyboard() – это основная функция, реализующая всю работу модуля. Она требует периодического запуска. Можно вставить ее в обработчик прерывания таймера, а можно вызывать ее из основного цикла программы по его сигналу. Первый вариант более расточителен в плане ресурсов микроконтроллера. 
 
KEYB_GetKey() – эта функция возвращает код кнопки, заданный в заголовочном файле keyboard.h. Если кнопочный буфер пуст – функция возвращает код  EVENT_NULL. Вызываем эту функцию там, где собираемся обрабатывать нажатия кнопок. 

Тестовые проекты

   Как обычно, прилагаю тестовые проекты для трех компиляторов. Все они были проверены в железе. Схема на рисунке ниже.
Для любителей симуляций - проект для Протеуса. Сделан на скорую руку, поэтому отличается от реальной схемы.
 

Файлы

Comments   

# foxit 2011-10-14 18:13
Спасибо, то что надо
# Gromozeka 2011-10-14 19:18
Вот, вот. Здесь всегда то, что надо. Большое человеческое спасибо, Pashgan.
# Pashgan 2011-10-14 21:31
Пожалуйста. Главное, чтобы это принесло пользу.
# s_black 2011-10-15 20:02
Я, конечно, не такой спец как Вы, Pashgan, но мне кажется, что у меня вышло проще http://www.embed.com.ua/mikrokontrollernyiy-konstruktor/matrichnaya-klaviatura/. И строки со столбцами можно подключать на любые разряды любых портов.
# Pashgan 2011-10-16 07:56
За основу я брал код из applications note фирмы IAR. Все претензии к ним).
К тому же проще не значит лучше.
Да и функционал твоего и моего кода отличается.
# s_black 2011-10-16 13:32
Функционал одинаков - отработка нажатия кнопки в матрице. А насчёт аппноутов... Там очень часто, почти всегда, куча лишнего кода.
# JoJo 2011-10-17 07:50
Отличие все таки есть.
- возможность использования с любым из трех компиляторов IAR, GCC, CodeVision,
- поддержка клавиатур 4х4 и 3х4
- поддержка работы на общей шине
- программная антидребезговая защита
# s_black 2011-10-17 09:09
to JoJo:
- зная среду разработки перенести код не составит труда;
- добавив аналогичный в коде фрагмент, возможна поддержка хоть 8х8 (в статье указано);
- хоть на одном порту, хоть вразброс;
- добавляется две строки в зависимости от использования (в прерывании, в цикле);
Я никоим образом не говорю, что мой код лучше))) Я адекватно оцениваю способности людей и могу сказать, что товарищ Pashgan разработчик уровнем выше меня. Форумы для того и нужны, чтобы обмениваться опытом, искать что-то новое. Всем удачи!
# ROM 2011-10-22 10:17
При использовании #define COMMON_BUS в ATMEGA8 в протерусе вылетают ошибки: что-то с доступом к памяти (за пределами)
# Igor-k 2011-10-22 13:05
Может ты порты неправильно определил? В восмой меге их же меньше, чем в шестнадцатой
# Alex_F 2011-10-27 02:58
Спасибо автору за сайт и его труд.Все материалы,по концепции программировани я и по Си в частности, изложены простым и понятным образом. Мне очень поучительно. Хотелось бы уточнить момент с вариантом вызова функции KEYB_ScanKeyboa rd(). Я не совсем понял, как все же лучше с ней поступить, в плане экономии ресурсов контроллера? Не совсем понятна фраза "можно вызывать ее из основного цикла программы по его сигналу".
# Pashgan 2011-10-27 06:27
Например так. В прерывании взводим флаг, в основном цикле проверяем.

Code:
...
volatile unsigned char flag = 0;
...
int main(void)
{
...
while(1){
if (flag){
KEYB_ScanKeyboard();
flag = 0;
}

}

}
....
//прерывание таймера
...
{
flag = 1;
}
# Alex_F 2011-10-27 07:28
Спасибо! Теперь ясно :-)
# Alex_R 2012-01-04 14:44
Хм А подскажите неужели ваши исходники не позволяют использовать одинаковые пины но на разных портах для row и col ?
Code:
if (~PINX_ROW & ROW_MASK) {
keyCode = PINX_ROW & ROW_MASK;
keyCode |= PORTX_COL & COL_MASK;
return;
# Pashgan 2012-10-31 21:41
в тексте написано
Quote:
Выводы микроконтроллера, подключенные к строкам и столбцам матричной клавиатуры, не должны совпадать между собой.
# Xarm 2012-10-29 02:36
Pashgan, скажите, есть ли ограничение длины провода от МК до Клавиатуры?
# Pashgan 2012-10-31 21:42
Больше полуметра я бы не стал делать.
# pavel s 2012-12-29 17:11
доброго времени суток, пожалуйста подскажите не могу сделать так чтобы данные матричной клавиатуры собрать в буфер (переменную,дву х и трёх разрядную в десятичном эквиваленте) для операций с ними, заранее спасибо
# gadmin 2012-12-30 00:20
Atmel Studio 6.0 постоянно ругаетца
Error 4 variable 'keyTable' must be const in order to be put into read-only section by means of '__attribute__( (progmem))' C:\ Users\gadmin\Do cuments\Atmel Studio\GccApplication2\GccApplication2\keyboard.c 61 39 GccApplication2
как это исправить
`
# Plotnik 2013-07-15 19:28
"Можно задать символьные значения, соответствующие кнопкам клавиатуры, как это сделано по умолчанию."-Я все оставил по умолчанию,но вместо 1-светится 9,и т.д.Все перепутано.В чем моя проблема?(1-9;2 -0;3-1;A-5;.... ..)
# Pashgan 2013-07-15 21:39
Выложи здесь свой проект http://chipenable.ru/index.php/forum/materialy-sajta-chipenable/3245-vetka-dlya-vremennogo-khraneniya-proektov.html
# vitaliy 2014-01-04 15:14
Здравствуйте.Сп асибо за статью.
В файле протеуса ножки строк клавиатуры подключены к МК паралельно ногам шины даных LCD.Все симулируется нормально.
Поскажите как в реальной схеме защищаться от одновременого нажатия двух кнопок,залипани й и тд.,чтобы остались целыми контролер и LCD?Достаточно ли одних резисторов 100 Ом?
# Pashgan 2014-01-04 16:03
По идее да. Ток через выводы мк будет ограничен на уровне 5/(100 + 100) = 25 мА. И то он будет не постоянный, а импульсный. Для пущей надёги можно поставить больший номинал.
# vitaliy 2014-01-04 16:19
Я где-то читал,что-то про защитные диоды.
# Pashgan 2014-01-07 05:36
Резисторов вполне достаточно.
# Максим 2014-01-29 13:45
Спасибо за библиотеку.
Хочу использовать для подключения 4 кнопок.
Грубо говоря получается клавиатура 1*4 или 4*1. Причем кнопки будут подключены на корпус одним выводом, т.е. 4 ряда на контроллер, а 1 столбец на корпус или наоборот.
Подскажите что надо на контроллер - ряды или столбцы?
# Pashgan 2014-01-31 11:56
Лучше взять вот эту библиотеку http://chipenable.ru/index.php/programming-avr/item/38-uchebnyy-kurs-opros-knopok.html. Она как раз для 4-ех кнопок.
# vitaliy 2014-01-31 18:13
И будет использоваться 4 порта,вместо пяти.
Еще раз спасибо автору за материал.Особен но радует совместное использование портов для клавы и LCD.Проверял в реальном железе,усе работает.Резист оры по 100 Ом.
# vitaliy_ 2014-03-10 19:29
Добрый вечер!
У меня вопрос.А возможно ли переделать библиотеку под 3*3 кнопки?Вот "юзал" 3*4 все гуд,но для многих целей вполне достаточно 3*3 + выиграш в 1 пин.
# Pashgan 2014-03-18 20:06
Да все можно, если посидеть и подумать. Но на вскидку не могу сказать, что там нужно поменять, потому что давно код писал.
# wowa 2014-04-02 06:14
Atmel Studio 6.2
variable 'keyTable' must be const in order to be put into read-only section by means of '__attribute__( (progmem))'
Как бы скорректировать запись в память программы.
Gadmin уже интересовался. Решения по прежнему нет?
# САБ 2014-04-02 08:36
Решение есть. Компилятор же вам подсказывает - добавьте const к PROGMEM
Code: #define FLASH_ATR PROGMEM const
# Plotnik 2014-04-02 11:08
У меня работает AS 6.1 так:добавил только const.Ранее при подключении библиотеки Студия ругалась.Поучил что-то вроде этого:
Code: FLASH_ATR const unsigned char keyTable[][2] = {
{((~(1<<PIN_ROW1)&(ROW_MASK))|(~(1<<PIN_COL1)&(COL_MASK))), EVENT_KEY1},
{((~(1<<PIN_ROW1)&(ROW_MASK))|(~(1<<PIN_COL2)&(COL_MASK))), EVENT_KEY2},
{((~(1<<PIN_ROW1)&(ROW_MASK))|(~(1<<PIN_COL3)&(COL_MASK))), EVENT_KEY3},
# wowa 2014-04-02 14:21
Спасибо. Все Ок!

У вас недостаточно прав для комментирования.