Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Подключение клавиатуры
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
SergeyM
Всем привет wink.gif
Решил усовершенствовать свой проект и добавить клаву 4х4. Прочел AVR240 вроде так называлась статья, но реализовывал используя ЖК а не светодиодный индикатор. К тому же клаву подключил к одному порту, ЖК к другому и програмно отправляю символ нажатой клавиши. Все вроде работает но не доконца smile.gif символы выводятся но только по первому столбцу т.е. 7, 4, 1, С (это символы первого столбца в моей клаве). Пробовал по разному делать задержку для антидребезга, но чето никак. Вообще реализую так:
на порт выдаю 0xF0 и с помощью прерываний проверяю число на PIN если не равно 240, то значит нажали на кнопку и отправляюсь в функцию обработки нажатия:
Код
KeyPress(void){
//delay_ms(20); пробовал ее везде пихать :)
switch (PINB) {
   case 224: key = 0;
       delay_ms(10);
       break;
   case 208: key = 4;
       delay_ms(10);
       break;
   case 176: key = 8;
       delay_ms(10);
       break;
   case 112: key = 12;
       delay_ms(10);
       break;  
   };
PORTB = 0x0F;
DDRB = 0xF0;
delay_us(10);
switch (PINB) {
   case 7: key += 0;
       delay_ms(10);
       break;
   case 11: key += 1;
       delay_ms(10);
       break;
   case 13: key += 2;
       delay_ms(10);
       break;
   case 14: key += 3;
       delay_ms(10);
       break;  
   };
PORTB = 0xF0;
DDRB = 0x0F;
PORTA.2 = 1; типа флаг нажати ниче более мудрого сразу не пришло :)

}


Далее в бесконечном цикле проверяю флаг нажатия и отправляю на экран символ из "таблицы" в качестве которой использовал массив символов, а key это номер символа в массиве. Разумеется после отправки флаг сбрасываю.

PS Сильно не ругайте, а вот за дельный совет всегда благодарен буду.
rezident
Немного не так это делается. По крайней мере я не так делаю.
Сделайте буфер нажатых клавиш. Реализуйте функции типа put_key, check_key и get_key.
put_key это функция сканирования клавиатуры, устранения дребезга и размещения в буфере клавиатуры скан-кода нажатой клавиши (проще всего по табличному принципу). Она же может реализовывать автоповтор нажатой клавиши и обработку нажатия нескольких клавиш (типа ALT + key, CTRL + key и т.п). Количество клавиш ограничено только аппартной реализацией клавиатуры. Буфер клавитуры может иметь любой размер. Буфер циклический. Для помещения и извлечения кодов клавиш используется счетчик скан-кодов и указатель на текущий скан-код. Естественно указатели ограничиваются сверху размером буфера. При равенстве счетчика и указателя (все коды из буфера извлечены) их значения устанавливаются на начало буфера.
Вызывается putkey желательно не менее 6 раз/сек, но не чаще длительности дребезга клавиш (обычно не чаще 100 раз/сек, т.к. чаще ни одна даже профессиональная машинистка не сможет нажимать ИМХО smile.gif). Вызов ее на какое-нибудь прерывание с подходящим периодом подвешивают.
check_key возвращает NULL если в буфере нет ни одного кода клавиши или текущий код клавиши. Указатель на текущий скан-код в буфере и счетчик кодов при этом не изменяется.
get_key возвращает NULL если в буфере нет ни одного кода клавиши или текущий код клавиши. Указатель на текущий скан-код в буфере и счетчик кодов при этом изменяются.
Я не привожу здесь какого-либо программного кода по двум причинам. Во-первых, нет под рукой. Во-вторых, считаю, что лучше уяснить принцип и хотя бы один раз написать самому для полного понимания wink.gif
Make_Pic
Цитата(rezident @ Jun 15 2005, 20:57)
Немного не так это делается. По крайней мере я не так делаю.
Сделайте буфер нажатых клавиш.
*

...


Код в студию! wink.gif
vet
Цитата(SergeyM @ Jun 15 2005, 21:09)

на мой взгляд, какая-то неочевидная реализация, я бы сделал проще: единожды настроенный порт далее не трогал бы, а в процедуре опроса клавиш гасил бы столбцы поодиночке и сканировал бы строки на лог.ноль.
Примерно так:
Код
//коды клавиш построчно
flash byte Keys[4][4]={{1,2,3,12},{4,5,6,13},{7,8,9,14},{10,0,11,15}};
char CurrKey;

//опрос
void ProcessKbd(void) {
   char i,j;

   CurrKey = 0xFF; //считаем, что ничего не нажато
   for (i=0;i<4;i++) { //по очереди выводим лог.0 на столбцы
     CLR_KBD_COL(i);
     #asm("nop")
     #asm("nop")
     //опрос входов (строк)
     for (j=0;j<4;j++)
       if (READ_KBD_ROW(j)==0) CurrKey = Keys[j][i];
   }
   //CurrKey - код
   //дальше при желании вешается антидребезг
}
yung
[quote=vet,Jun 15 2005, 21:24]
[quote=SergeyM,Jun 15 2005, 21:09][/quote]
а в процедуре опроса клавиш гасил бы столбцы поодиночке и сканировал бы строки на лог.ноль.

и это правильно, да-ду-да-ду-да.
SergeyM
Цитата(rezident @ Jun 15 2005, 20:57)
Немного не так это делается. По крайней мере я не так делаю.
Сделайте буфер нажатых клавиш. Реализуйте функции типа put_key, check_key и get_key.
*


Цитата(vet)
на мой взгляд, какая-то неочевидная реализация, я бы сделал проще: единожды настроенный порт далее не трогал бы, а в процедуре опроса клавиш гасил бы столбцы поодиночке и сканировал бы строки на лог.ноль.


А какое у вас начальное значение выводов или по какому принципу вы определяете что клавиша нажата? Или у вас всегда опрашиваются все клавиши?
yung
Обычно делается так. Строки определяются как выходы, столбцы как входы (или наоборот, но рассмотрим этот вариант). Столбцы неплохо бы внешними резисторами к + подтянуть (внутренний pull-up не всегда помогает). В исходном состоянии строки установлены в 1. По таймеру каждые, к примеру, 30 мс переводим очередную строку в 0, возвращая предыдующую в 1. Читаем состояние столбцов. Когда столбец равен 0, то нажата клавиша на пересечении столбца и строки. Для верности дожидаемся следующего прохода через эту строку, и в случае, когда там опять 0, считаем клавишу нажатой. Это простейший путь защиты от дребезга, но обычно его достаточно.
rezident
Цитата(SergeyM @ Jun 16 2005, 11:01)
А какое у вас начальное значение выводов или по какому принципу вы определяете что клавиша нажата? Или у вас всегда опрашиваются все клавиши?
*

Обычно используем матрицу 4х4 или 2х4. Соответственно четыре сканирующие линии (выходы с ОК или обычные выходы с диодами) и четыре считывающие линии (входы с pull-up резисторами). В памяти хранится предыдущее состояние матрицы кнопок. 16 кнопок - одно слово. Установленному биту соответствует нажатая клавиша. Если предыдущее состояние равно 0x0000, то перед полным сканированием достаточно проверить нажата ли хоть одна клавиша. Для этого все сканирующие линии можно враз активировать. Если хоть одна кнопка нажата, но начинается полноценная процедура сканирования каждой линии. В результате получаем матрицу текущего состояния кнопок. XORим две матрицы и получаем изменение между двумя состояниями. Если результат XORения равен нулю, то состояние устойчивое и можно определять код нажатой клавиши. Затем запоминаем текущее состояние для использования в следующем цикле сканирования как предыдущее состояние. В цикле накладываем маску вида (1<<i) на маску состояния клавиш и при совпадении получаем смещение (i) в таблице скан-кодов. Вот и все в общих чертах. Далее идут всякие усовершенствования с автоповтором нажатой клавиши, с определением нескольких нажатых клавиш и т.д и т.п.
P.S. Забыл уточнить, что меня обычно интересует только нажатая клавиша, хотя никто не мешает в этом алгоритме сделать и скан-коды отпускания.
P.P.S. Иногда бывает важным, чтобы не все кнопки имели функцию автоповтора. У меня обычно SET и ESC не имеют этой функции, все остальные для удобства навигации в меню и редактирования имеют автоповтор с программируемой паузой и частотой автоповтора.
SergeyM
Цитата(rezident @ Jun 16 2005, 18:52)
Обычно используем матрицу 4х4 или 2х4. Соответственно четыре сканирующие линии (выходы с ОК или обычные выходы с диодами) и четыре .......
*


Слушай это все пока что очень сильно для меня, я хотел бы попросить код для анализа и изучения.
SergeyM
Цитата(vet @ Jun 15 2005, 21:24)
Код
//коды клавиш построчно
flash byte Keys[4][4]={{1,2,3,12},{4,5,6,13},{7,8,9,14},{10,0,11,15}};
char CurrKey;

*


У меня что то на строку с flash byte ругается (использую cvavr)
rezident
Цитата(SergeyM @ Jun 16 2005, 22:17)
Цитата(vet @ Jun 15 2005, 21:24)
Код
//коды клавиш построчно
flash byte Keys[4][4]={{1,2,3,12},{4,5,6,13},{7,8,9,14},{10,0,11,15}};
char CurrKey;

*


У меня что то на строку с flash byte ругается (использую cvavr)
*


Дык зачем массив-то? Достаточно линейную таблицу.
Я с AVR и CVAVR не работал, но ИМХО директива должна как __flash выглядеть.
Код дома есть, но я забыл его на флешку записать сегодня. Только он для MSP430, а не для AVR.
vet
Цитата(rezident @ Jun 16 2005, 20:29)
Цитата(SergeyM @ Jun 16 2005, 22:17)
Цитата(vet @ Jun 15 2005, 21:24)
Код
//коды клавиш построчно
flash byte Keys[4][4]={{1,2,3,12},{4,5,6,13},{7,8,9,14},{10,0,11,15}};
char CurrKey;

*


У меня что то на строку с flash byte ругается (использую cvavr)
*


Дык зачем массив-то? Достаточно линейную таблицу.

А так читабельнее. Можно, конечно.

Цитата(rezident @ Jun 16 2005, 20:29)
Я с AVR и CVAVR не работал, но ИМХО директива должна как __flash выглядеть.
*

Нет, именно так. Я только забыл свой typedef-нный тип убрать, так что вместо byte пишем char.
SergeyM
Цитата(rezident)


Ниче страшного самое главное суть, давай код
rezident
Цитата(SergeyM @ Jun 16 2005, 22:43)
Цитата(rezident)


Ниче страшного самое главное суть, давай код
*


Суть, то бишь сам алгоритм я уже описал выше wink.gif
AndyBig
Я делаю по тому же принципу, что описал vet:
Цитата
единожды настроенный порт далее не трогал бы, а в процедуре опроса клавиш гасил бы столбцы поодиночке и сканировал бы строки на лог.ноль

Но хранение состояний клавиш немного более разветвленное.
У меня хранятся:
1. Текущее состояние (Не нажата, Преднажата, Нажата, Долго нажата, Отпущена) state
2. Значение сантисекунд, когда было выставлено последнее состояние time
3. Флаг ее обработки worked
4. Счетчик повторений count

Упрощенный алгоритм опроса клавиш таков:
Код
- С клавиатуры считывается состояние кнопки.
- Если она не нажата, то:
{
   - если state не равно "Отпущена" или "Не нажата", то установить state в "Отпущена" и worked в "ложь"
}
- Иначе:
{
   switch()
   {
     - Если state равно "Преднажата", установить state в "Нажата", worked в "ложь" и time в текущие сантисекунды
     - Если ее состояние равно "Нажата" и разница между текущими сантисекундами и time больше 50 (пол-секунды), установить state в "Долго нажата", worked в "ложь", time в текущие сантисекунды, count в 1
     - Если ее состояние равно "Долго нажата" и разница между текущими сантисекундами и time больше 10, установить worked в "ложь", инкрементировать count
   }
}
Повторить для всех клавиш



Вот... А в главном цикле просто проверяются флаги worked, и если у какой-то клавиши он установлен в "ложь", то в зависимости от state производятся каки-либо действия, после чего флаг worked сбрасывается в "истина" (а если клавиша была в состоянии "Отпущена", то и состояние сбрасывается в "Не нажата").

Довольно простой алгоритм, позволяющий обрабатывать нажатия кнопок как угодно - одиночные нажатия, долгие нажатия с периодом автонажатия, отпускания...

Да, кстати... период опроса клавиш у меня обычно 10 милисекунд (1 сантисекунда), с одной стороны для антидребезга этого вполне достаточно, с другой стороны - позволяет реагировать на довольно краткие нажатия клавиш.
rezident
Вот вам мой модуль для обслуживания клавиатуры 2х3 с автоповтором.
Отличия от того, что я описывал выше.
- сканирующие линии имеют активный высокий (а не низкий) уровень, соответственно стоят pull-down, а не pull-up резисторы как на сканирующих, так и на считывающих линиях;
- матрица не 2х4, а 2х3, но легко расширяется до 2Х4 изменением одной константы MAX_KEY_NUM. Если же нужно 4Х4, то кроме этого нужно некоторые переменные объявить как unsigned int, а не unsigned char;
- допускает одновременное нажатие нескольких кнопок. При этом коды нажатых кнопок помещаются в буфер в порядке их сканирования;
- допускается нажатие любой кнопки при уже нажатой одной или нескольких;
- имеет автоповтор последней нажатой клавиши с задержкой и паузой.
Еще раз обращаю внимание, что пример для MSP430, а не AVR. Сканирующие линии эмулируют сигналы с активной единицей и Z-состоянием в качестве лог.нуля.
P.S. Функция сканирования вызывается из прерывания с периодом 10ms.
SergeyM
Цитата(rezident @ Jun 16 2005, 18:52)
Вот вам мой модуль для обслуживания клавиатуры 2х3 с автоповтором.
*


Спасибо посмотрим
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.