Библиотека для опроса матричной клавиатуры 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. Вызываем эту функцию там, где собираемся обрабатывать нажатия кнопок. 

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

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

Файлы

Комментарии   

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

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

}

}
....
//прерывание таймера
...
{
flag = 1;
}
Ответить | Ответить с цитатой | Цитировать
# Alex_F 27.10.2011 07:28
Спасибо! Теперь ясно :-)
Ответить | Ответить с цитатой | Цитировать
# Alex_R 04.01.2012 14:44
Хм А подскажите неужели ваши исходники не позволяют использовать одинаковые пины но на разных портах для row и col ?
Код:
if (~PINX_ROW & ROW_MASK) {
keyCode = PINX_ROW & ROW_MASK;
keyCode |= PORTX_COL & COL_MASK;
return;
Ответить | Ответить с цитатой | Цитировать
# Pashgan 31.10.2012 21:41
в тексте написано
Цитата:
Выводы микроконтроллера, подключенные к строкам и столбцам матричной клавиатуры, не должны совпадать между собой.
Ответить | Ответить с цитатой | Цитировать
# Xarm 29.10.2012 02:36
Pashgan, скажите, есть ли ограничение длины провода от МК до Клавиатуры?
Ответить | Ответить с цитатой | Цитировать
# Pashgan 31.10.2012 21:42
Больше полуметра я бы не стал делать.
Ответить | Ответить с цитатой | Цитировать
# pavel s 29.12.2012 17:11
доброго времени суток, пожалуйста подскажите не могу сделать так чтобы данные матричной клавиатуры собрать в буфер (переменную,дву х и трёх разрядную в десятичном эквиваленте) для операций с ними, заранее спасибо
Ответить | Ответить с цитатой | Цитировать
# gadmin 30.12.2012 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 15.07.2013 19:28
"Можно задать символьные значения, соответствующие кнопкам клавиатуры, как это сделано по умолчанию."-Я все оставил по умолчанию,но вместо 1-светится 9,и т.д.Все перепутано.В чем моя проблема?(1-9;2 -0;3-1;A-5;.... ..)
Ответить | Ответить с цитатой | Цитировать
# Pashgan 15.07.2013 21:39
Выложи здесь свой проект http://chipenable.ru/index.php/forum/materialy-sajta-chipenable/3245-vetka-dlya-vremennogo-khraneniya-proektov.html
Ответить | Ответить с цитатой | Цитировать
# vitaliy 04.01.2014 15:14
Здравствуйте.Сп асибо за статью.
В файле протеуса ножки строк клавиатуры подключены к МК паралельно ногам шины даных LCD.Все симулируется нормально.
Поскажите как в реальной схеме защищаться от одновременого нажатия двух кнопок,залипани й и тд.,чтобы остались целыми контролер и LCD?Достаточно ли одних резисторов 100 Ом?
Ответить | Ответить с цитатой | Цитировать
# Pashgan 04.01.2014 16:03
По идее да. Ток через выводы мк будет ограничен на уровне 5/(100 + 100) = 25 мА. И то он будет не постоянный, а импульсный. Для пущей надёги можно поставить больший номинал.
Ответить | Ответить с цитатой | Цитировать
# vitaliy 04.01.2014 16:19
Я где-то читал,что-то про защитные диоды.
Ответить | Ответить с цитатой | Цитировать
# Pashgan 07.01.2014 05:36
Резисторов вполне достаточно.
Ответить | Ответить с цитатой | Цитировать
# Максим 29.01.2014 13:45
Спасибо за библиотеку.
Хочу использовать для подключения 4 кнопок.
Грубо говоря получается клавиатура 1*4 или 4*1. Причем кнопки будут подключены на корпус одним выводом, т.е. 4 ряда на контроллер, а 1 столбец на корпус или наоборот.
Подскажите что надо на контроллер - ряды или столбцы?
Ответить | Ответить с цитатой | Цитировать
# Pashgan 31.01.2014 11:56
Лучше взять вот эту библиотеку http://chipenable.ru/index.php/programming-avr/item/38-uchebnyy-kurs-opros-knopok.html. Она как раз для 4-ех кнопок.
Ответить | Ответить с цитатой | Цитировать
# vitaliy 31.01.2014 18:13
И будет использоваться 4 порта,вместо пяти.
Еще раз спасибо автору за материал.Особен но радует совместное использование портов для клавы и LCD.Проверял в реальном железе,усе работает.Резист оры по 100 Ом.
Ответить | Ответить с цитатой | Цитировать
# vitaliy_ 10.03.2014 19:29
Добрый вечер!
У меня вопрос.А возможно ли переделать библиотеку под 3*3 кнопки?Вот "юзал" 3*4 все гуд,но для многих целей вполне достаточно 3*3 + выиграш в 1 пин.
Ответить | Ответить с цитатой | Цитировать
# Pashgan 18.03.2014 20:06
Да все можно, если посидеть и подумать. Но на вскидку не могу сказать, что там нужно поменять, потому что давно код писал.
Ответить | Ответить с цитатой | Цитировать
# wowa 02.04.2014 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 уже интересовался. Решения по прежнему нет?
Ответить | Ответить с цитатой | Цитировать
# САБ 02.04.2014 08:36
Решение есть. Компилятор же вам подсказывает - добавьте const к PROGMEM
Код: #define FLASH_ATR PROGMEM const
Ответить | Ответить с цитатой | Цитировать
# Plotnik 02.04.2014 11:08
У меня работает AS 6.1 так:добавил только const.Ранее при подключении библиотеки Студия ругалась.Поучил что-то вроде этого:
Код: 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 02.04.2014 14:21
Спасибо. Все Ок!
Ответить | Ответить с цитатой | Цитировать

Добавить комментарий

Защитный код
Обновить