Схема подключения клавиатуру к микроконтроллеру. Подключение к микроконтроллеру клавиатуры матричного типа

  • Дата: 12.01.2024

Резисторы R2 – R4, R8 – R11 предназначены для ограничения входного/выходного тока в случае неправильной настройки портов или одновременного нажатия нескольких кнопок. Выводы PD0(RXD), PD1(TXD) подключены к преобразователю UART-RS232, который на схеме не отображен. Обмен по USART`у используется для отладки программы.

Алгоритм опроса матричной клавиатуры

Строки клавиатуры подключены к выводам PD4, PD5, PD6, PD7. Они настроены на выход и в начальном состоянии на этих выводах напряжение логического нуля. Столбцы подключены к выводам PC0, PC1, PC2. Они настроены на вход, внутренние подтягивающие резисторы отключены и эти линии “придавлены к нулю питания” с помощью внешних резисторов номиналом в 10 КОм.

Процедура сканирования клавиатуры выглядит следующим образом. Выставляем 1 на выводе PD4 и проверяем состояние выводов PC0, PC1, PC2 (то есть считываем содержимое регистра PINC). Если на каком-то из выводов установлена 1, значит, на клавиатуре в данный момент нажата кнопка, подключенная к первой строке. Сохраняем биты PD4, PD5, PD6, PD7 и PC0, PC1, PC2 в одной переменной – по этому коды мы будем определять номер нажатой кнопки. Если ни одна из кнопок не нажата, продолжаем процедуру сканирования.

Сбрасываем 1 на выводе PD4 и устанавливаем 1 на выводе PD5. Снова проверяем состояние выводов PC0, PC1, PC2, и в случае нажатия кнопки сохраняем биты PD4, PD5, PD6, PD7 и PC0, PC1, PC2 в переменной.

Повторяем описанную последовательность для двух оставшихся строк.

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

Код, получаемый в процессе сканирования клавиатуры, часто требуется преобразовать в символьное значение номера/буквы кнопки (например, для передачи по USART`у). Для этого можно создать таблицу перекодировки - двумерный массив. В первом столбце таблицы будут храниться коды кнопок, а во втором соответствующие символьные значения. Методом последовательного перебора в таблице можно находить нужное значение.

Алгоритм опроса матричной клавиатуры можно реализовать в виде конечного автомата (State Machine) – функции, которая в зависимости от своего состояния (значения определенной переменной) и входного воздействия, выполняет разную работу. На рисунке ниже представлена диаграмма подобного автомат.

Начальное состояние автомата - 0. В этом состоянии автомат находится, пока не будет нажата какая-нибудь кнопка. Когда зафиксировано нажатие на кнопку, запускается функция сканирования клавиатуры ScanKey(), запоминается код нажатой кнопки и автомат переходит в состояние 1.

В состоянии 1 автомат проверяет, нажата ли в данный момент та же кнопка, что и в состоянии 0 или нет. Если коды кнопок не совпадают, автомат возвращается в состояние 0, если совпадают, запускается функция FindKey(), которая находит символьное значение номера кнопки и устанавливает флаги, сигнализирующие системе о нажатой кнопке. По завершению функции автомат переходит в состояние 2.

Пока удерживается одна и та же кнопка, автомат находится в состоянии 2. Если произошли какие-то изменения, он переходит в состояние 3.

Если изменения было случайным, автомат возвращается в состояние 2, а если нет, переходит в начальное состояние, чтобы снова запустить функцию сканирования клавиатуры.

Программная реализация автомата

Представленную диаграмму конечного автомата легко преобразовать в программный код.

//хранит текущее состояние автомата
unsigned char keyState;

//прототипы функций используемых автоматом
unsigned char AnyKey(void );
unsigned char SameKey(void );
void ScanKey(void );
unsigned char FindKey(void );
void ClearKey(void );

void ScanKeyboard(void )
{
switch (keyState){
case 0:
if (AnyKey()) {
ScanKey();
keyState = 1;
}
break;

case 1:
if (SameKey()) {
FindKey();
keyState = 2;
}
else keyState = 0;
break;

case 2:
if (SameKey()){}
else keyState = 3;
break;

case 3:
if (SameKey()) {
keyState = 2;
}
else {
ClearKey();
keyState = 0;
}
break;

Default:
break;
}

Довольно наглядная запись. Теперь все, что нам остается, это написать/разобрать реализации недостающих функций. Чтобы код программы был максимально понятным, давайте обойдемся без макроопределений. Итак, по порядку.


unsigned char AnyKey(void )
{
PORTD |= 0xf0;
return (PINC & 0x07);
}

Устанавливаем на выводах PD7 – PD4 единицы, возвращаем состояния выводов PC2 – PC0. Если какая-нибудь из кнопок клавиатуры в этот момент нажата, функция вернет значение отличное от нуля, то есть true.

//хранит код нажатой кнопки
unsigned char keyCode;

void ScanKey(void )
{
unsigned char activeRow = (1<<4);
while (activeRow) {
PORTD = (PORTD & 0x0f)|activeRow;
if (PINC & 0x07) {
keyCode = (PINC & 0x07);
keyCode |= (PORTD & 0xf0);
}
activeRow <<= 1;
}
}

Устанавливаем в 1 четвертый бит переменной activeRow (активизируем первую строку). Обнулив биты PD7 – PD4, записываем переменную в PORTD. Если какой-нибудь из трех младших разрядов регистра PINC установлен в единицу, значит в данный момент нажата кнопка, относящаяся к первой строке. Сохраняем биты PD7 – PD4 и PC2 - PC0 в переменную keyCode. Сдвигаем влево значение переменной activeRow на один разряд и повторяем цикл еще три раза.


unsigned char SameKey(void )
{
PORTD = (PORTD & 0x0f) | (keyCode & 0xf0);
return ((PINC & keyCode) & 0x07);
}

Функция проверяет, совпадает ли код нажатой в данный момент кнопки с кодом, полученным в предыдущем цикле опроса. Для этого на нужной строке устанавливается 1 – в PORTD записываются старшие 4 бита keyCode. Затем считывается регистр PINC, на него накладывается маска в виде переменной keyCode и выделяются 3 младших разряда. Полученное значение возвращается. Если коды кнопок совпадут, значение будет отлично от нуля, то есть true.


//хранит символьное значение нажатой кнопки
unsigned char keyValue;
//флаговая переменная - устанавливается, если кнопка удерживается
unsigned char keyDown;
//флаговая переменная - устанавливается, когда нажата новая кнопка
unsigned char keyNew;

//таблица перекодировки
__flash unsigned cha r keyTable = {
{ 0x11, "1"},
{ 0x12, "2"},
{ 0x14, "3"},
{ 0x21, "4"},
{ 0x22, "5"},
{ 0x24, "6"},
{ 0x41, "7"},
{ 0x42, "8"},
{ 0x44, "9"},
{ 0x81, "*"},
{ 0x82, "0"},
{ 0x84, "#"}
};

unsigned char FindKey(void )
{
unsigned char index;
for (index = 0; index < 12; index++) {
if (keyTable == keyCode) {
keyValue = keyTable ;
keyDown = 1;
keyNew = 1;
return 1;
}
}
return 0;

Aruna Rubasinghe

Матричные клавиатуры до сих пор еще применяются в качестве устройств ввода информации в проектах на микроконтроллерах. Обычный способ подключения такой клавиатуры к микроконтроллеру заключается в использовании нескольких портов ввода/вывода. В свою очередь, микроконтроллер выполняет алгоритм сканирования, чтобы определить, какая кнопка была нажата пользователем. Недостаток такого способа - необходимость использования достаточно большого количества портов микроконтроллера для обслуживания клавиатуры. Например, для подключения клавиатуры 4×3 потребуется семь свободных линий ввода/вывода. Это становится проблемой, когда в проекте планируется использование микроконтроллера с малым количеством выводов, или когда микроконтроллер не имеет свободных портов.

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

Многие расширители портов для обмена данными требуют коммуникации по специальным протоколам (например, I 2 C или SPI), потому в этом случае микроконтроллер должен иметь встроенные коммуникационные интерфейсы, или пользователь должен реализовать их программно, что повысит нагрузку на ядро. С другой стороны, назначение каждой кнопке определенного напряжения с помощью резисторов может быть затруднительным при большом количестве кнопок и приводит к сужению диапазона напряжений для каждой кнопки. Кроме того, сопротивление резисторов может изменяться с температурой, что совместно с узким диапазоном напряжений приведет к неправильному определению нажатий. Другой существенный недостаток этого способа - обязательное наличие в микроконтроллере аналогового входа (АЦП).

В статье мы рассмотрим способ подключения клавиатуры, который эффективно решает все вышеуказанные проблемы и имеет несколько преимуществ: требуются только две линии ввода/вывода независимо от числа используемых кнопок, не используются специальные коммуникационные протоколы, не нужен АЦП. Идея заключается в использовании двух доступных микросхем (десятичный счетчик-делитель).

На Рисунке 1 изображена схема модуля матричной клавиатуры 4×3. Резисторы R 1 , R 4 , R 5 и R 6 используются для ограничения тока; резистор R 7 , диоды D 4 , D 5 и D 6 образуют логический элемент ИЛИ.

Далее мы рассмотрим, как реализовать этот метод для сканирования кнопок матричной клавиатуры 4×3. Одна микросхема счетчика CD4017 используется для контроля строк (IC 2), другая - для контроля столбцов клавиатуры (IC 1).

Микроконтроллер генерирует тактовый сигнал и подает его на вход CLK счетчика, контролирующего столбцы. Первоначально выходы Q0 двух счетчиков находятся в состоянии лог. 1 и значение счетчика IC 1 инкрементируется на 1 с каждым тактовым импульсом. На четвертый импульс счетчик IC 1 сбрасывается и одновременно инкрементирует значение счетчика IC 2 , управляющего строками клавиатуры. Счетчик IC 2 сбросится через пять импульсов, поступающих от счетчика IC 1 , обслуживающего столбцы. При генерировании одного тактового импульса микроконтроллер должен инкрементировать значение переменной COUNT (Рисунок 2) и сбрасывать ее в 1 на пятом тактовом импульсе для счетчика IC 2 . Выход матричной клавиатуры через логический элемент ИЛИ подключается в выводу внешнего прерывания микроконтроллера.

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

Счетчик тактовых импульсов, реализованный в микроконтроллере, инкрементируется в моменты их генерирования. Значение в этом счетчике соответствует номеру нажатой кнопки на клавиатуре. Блок-схема программы микроконтроллера на Рисунке 2 наглядно демонстрирует этот алгоритм.

Обратите внимание, несмотря на то, что в примере мы рассматриваем клавиатуру 4×3, при данном способе можно управлять клавиатурой 10×10, задействовав оставшиеся выходы обеих микросхем CD4017. Кроме того, применив каскадное включение счетчиков, количество кнопок можно увеличить, если в этом есть необходимость.

Дополнительные материалы

Чтение состояния 10 и более кнопок с использованием двух линий ввода/вывода микроконтроллера - Журнал Радиолоцман (еще не публиковался) .

  • Первая же импульсная помеха от бритвы соседа - и кнопки меняются местами:)
  • Купи соседу бритву Жилет с антистатикой:-) По твоему, например, если сосед электросваркой дуговой увлекается, вокруг никто цифровой техникой не пользуется??? Судя по схеме - один через 3, другой через 4 такта ресетятся, что в динамике почти мгновенно, а про МК ты вообще забываешь при этом, хотя он на несколько порядков сложнее. На крайняк, хотя и существуют фильтры по питанию, но ManualReset никто не запрещал
  • Две микросхемы, пять резисторов и 10 диодов большая "цена" за экономию пяти выводов микроконтроллера за 12 кнопок. Конечно, можно сказать и за 100 кнопок эта плата. Но можно ли придумать такое устройство на 100 кнопок на микроконтроллере с 8 выводами? Такие устройства, как правило, используют отдельный микропроцессор, обслуживающий клавиатуру и соединяются с основным процессором интерфейсом, используя небольшое количество выводов, минимум один. Для познавательных целей схема интересна, для практического применения - не уверен.
  • Похоже, никто не понял непостижимой глубины моей эпической сентенции. Схема имеет 12 устойчивых состояний, в каждое из которых может перейти под управлением МК, или под действием помехи. Каждому состоянию будет соответствовать индивидуальная раскладка клавиш. В схеме отсутствуют средства сброса в начальное состояние! Даже после подачи питания!
  • Теоретически возможно, значит - желательно предусмотреть, а т.к. аппаратный сброс задействован в схеме, то монтажное ИЛИ +RC-цепочку для питания, но на практике что-то не сталкивался с хаосом в работе ИЕ8 и ещё раз повторю, как бы не встали триггеры, первый счётчик сбросится, за ним - второй, и всё хоккей...Прошла помеха...Да, есть маловероятный шанс, что ты успеешь нажать кнопку до сброса(который есть!) и с такой быстротой...Ну тогда ты -Шаман:-) Да, а по поводу цены вопроса...Разумеется, в проммасштабе, т.е. если всё покупать+монтаж+габариты+и т.д. - то на то и выйдет, но если в загашнике мешок старых микрух, то почему бы на МК не съэкономить?
  • Нет, не "теоретически возможно", а практически и принципиально эта схема не будет работать. Всё будет ОК, только если сброс триггеров произойдет вместе с подачей питания. Тогда после 12 импульсов опроса они вернутся в исходное состояние и синхронизм между схемой и программой сохранится. Но, во-первых, триггеры не обязаны сбрасываться по подаче питания (и на практике встают как попало). И во-вторых, любая помеха изменяет состояние триггеров в одно из 12-ти возможных. В итоге: в схеме не предусмотрена начальная установка состояния и у МК нет какого-либо способа прочитать текущее состояние или установить любое известное состояние. Поэтому синхронизм между программой и схемой будет наступать с вероятностью 8%. Неплохо для игрового автомата:)
  • Что-то кто-то где-то недоперепонял:-) Внутри 4017 все пять тригеров объединены по входу Reset, который выведен наружу, в данном варианте под именем MR, (куда можно вставить простейший Reset через кондёр(+) и резистор(-) Проц постоянно выдаёт такт (CLOCK), 4-й импульс положительным перепадом ресетит до нуля счётчик1 с выхода дешифратора1(Q3) и одновременно выдаёт первый такт на счётчик2, который через 4 на пятый обнулится всё по тому же входуMR с выхода дешифратора2(Q4), в наихудшем варианте счётчик2 по помехе станет в состояние дешифратора Q5=1, то ему придётся пройти почти полный круг, но так как всё это происходит постоянно и циклически, а внешнее прерывание происходит не по помехе, а по совпадению в момент нажатия единиц и там и там, то очень затруднительно нажать кнопку за время первого цикла после включения или помехи...Наверно ты имел ввиду возможность сдвига значений внутри МК и снаружи, но ведь и внутрений счётчик сбрасывается внешним прерыванием... Так что работать будет...
  • Это ещё надо подумать, как его туда прицепить, чтоб не было конфликта с синалами на других выводах, куда подключен этот сброс...
  • Но мы обсуждаем приведенную схему, и именно про нее я сказал, что она нерабочая. Ты начинаешь понимать, что косяк есть, и предлагаешь ее изменить, чтобы этот косяк исправить. Эти подробности рассматривать нет необходимости. Счетчик работает по кругу, проходя 12 равноценных состояний под управлением одного внешнего сигнала. Смотрите в общем. Между двумя схемами, между которыми происходит обмен, теоретически и практически возможна рассинхронизация, которая нарушит ее работу, и нет средств приведения частей в соответствие. Когда-нибудь ремонтировал видик Панасоник? Вынул шестеренки, вставил обратно - и привет. Меток на них не ставят, а стоять должны строго в определенном положении, о котором знает только Панасоник и управляющий процессор. Только схема об этом не может узнать, вот ведь засада какая. Исправить схему можно тремя способами. 1. Добавить линию из клавы в проц, означающую "начальное состояние". Тогда проц обязан долбить клоки до тех пор, пока на этой линии не появится сигнал - вот тогда можно начинать сканирование. 2. Добавить линию от проца в клаву и организовать по ней сброс в начальное состояние - тут всё очевидно. 3. Добавить одновибратор, который бы разрешал счет. После первого обращения он запускается и во время импульса можно произвести опрос. После окончания импульса счетчики сбрасываются в исходное. Все три способа будут работать. PS. Видоизменение 1-го способа без кардинальных изменений. Пожертвовать одной кнопкой, замкнув ее на постоянно. Тогда проц будет знать (в большинстве случаев), откуда начать сканирование. Так никто не делает и это лажа и моветон, но если будет стоять задача "ничего не менять, но чтобы работало", то так сделать можно.
  • Автору исходной схемы пользователи задают тот же самый вопрос - как насчет синхронизации? http://www.edn.com/design/power-mana...g-two-I-O-pins На что он советует применить линию с тремя состояниями:) То есть, автор косвенно признает, что есть проблема, но, желая оставаться в рамках идеи минимизации количества проводов, вынужден увеличивать число состояний одной линии с 2 до 3, что равносильно увеличению количества самих линий. http://www.edn.com/design/components...icrocontroller
  • Ну вот и добрались до сути, ты говоришь вообще не будет работать, я говорю будет, но с минимальными переделками (у журнала Радио научился не верить в то что видишь) и без использования 3-го порта...
  • Внутренняя схема счетчика CD4017 построена таким образом, что после прохождения 10, максимум, счетных импульсов он установится в одно из 10 разрешенных состояний, включая и нулевое. Произойдет это потому, что внутри счетчика присутствуют обратные связи, исключающие запрещенные состояния. Ну а дальше все будет синхронизироваться как пишет автор. Схема рабочая, кто не уверен может собрать и проверить, хотя и имеется одно "скользкое" место - схема сброса самого себя, работающая на задержках переключения. При таком построении импульс сброса будет очень коротким и теоретически возможен сброс не всех триггеров в ноль.
  • Вы меня не слышите. Я не говорил о кривых состояниях, которые теоретически возможны в триггерах без сброса. Я говорил о принципиальном отсутствии средств синхронизации между МК и схемой. Ну, тогда "на пальцах". Предположим, триггеры встали в состояние 5. МК об этом не знает и узнать не может - нет такого проводка. МК может только прогнать весь цикл сканирования, состоящий из 12 импульсов тактирования, и прочувствовать, на каком из импульсов на выходе появится логический уровень, соответствующий нажатой кнопке. ОК. После всего цикла сканирования триггеры окажутся опять в состоянии 5. Понимаете? Ну и что, что они во время сканирования прошли через сброс? МК об этом не знает! Нужен не сам сброс, а нужно четкое соответствие начала цикла сканирования и состояния внутреннего счетчика тактов в МК, как это обеспечивается в предложенной схеме? Покажите.
  • Да все всё слышат! Очень мало схем сразу начинают работать или работают нормально в одних условиях и совершенно не хотят(не могут) в других... Может, действительно, у автора нет вредных соседей.. ИМХО, приведённая схемка, приведёт к небольшому удорожанию, но позволит разрешить некоторые разногласия, хотя и не является вершиной конструкторской мысли:-))) PS. А если, вообще, Начинать отсчёт тактов с момента появления сигнала Interrupt, который одновременно коротким импульсом обнулит и счётчики, то за время нажатия вполне можно определить кнопку(не в этой схемке) PPS. Меня терзают смутные сомнения...А зачем вообще считать всё время? Или я не доглядел? Кстати, что это за ФункшнБаттон у автора? в левой ветке алгоритма, если это и есть инициализация счётчика тактов от нажатия любой кнопки, то весь наш спор почти бред, если нет, то так и надо сделать програмно, заменив счётчики на обычные, с предустановкой в 1111 и 1111 ну и используя только однозначные пересечения.
  • Вы все правильно говорите, но мы обсуждаем конкретную схему, а синхронизация это задача проца и программиста. Самое простое договориться (написать в эксплуатационной документации), что после включения питания нажимается конкретная любая кнопка, от которой проц начинает отсчет.
  • Ну слава б-гу. Нет, мои схемы я буду делать так, чтобы они работали всегда. Представьте, вы сделали разработку, всё готово, можно показывать шефу. Шеф включает прибор, нажимает кнопку 5, на табло вылетает цифра 9. Шеф смотрит на табло, на вас и говорит - "а чё за х-нь?" И вы начинаете объяснять, что мы, мол, напишем инструкцию, как правильно включать прибор:) Ладно, написали, запустили. Потом прибегает операторша и говорит: "Здесь клавиатура постоянно глючит! Работает 5 минут, а потом вместо одной цифры бьётся другая!" - а вы ей терпеливо начинаете объяснять, что состояние регистров процессора не обязано соответствовать актуальному состоянию счетчиков в клавиатуре и что синхронизация - это дело программиста:) А может, лучше не экономить проводок, а сделать сразу, чтобы работало?
  • В первом своем посте в теме я об этом и писал.
  • Ребята, давайте жить дружно! И не путать работу с хобби, ведь не управление реактором и не постройка храма обсуждается, а всего лишь какая-то хренотень(Прим. Тень, отбрасываемая кустом Хрена на близко расположенные предметы), которая якобы чем-то управляет, и дружно последуем совету из темы про клеточные автоматы, не дадим победить Матрице!!!, и будем держать в кармане кнопку "MasterReset"...
  1. Изучить особенности работы параллельных портов микроконтроллера.
  2. Изучить схемы подключения кнопок и матричной клавиатуры к микроконтроллеру.
  3. Научиться определять состояние кнопок при помощи программы.
  4. Изучить способы отладки программ на лабораторном стенде LESO1.
  5. Изучить принцип работы матричной клавиатуры.

2 Предварительная подготовка к работе

  1. По конспекту лекций и рекомендуемой литературе изучить схемы параллельных портов микроконтроллеров.
  2. По конспекту лекций и рекомендуемой литературе изучить схемы подключения кнопок и клавиатуры к параллельным портам.
  3. Изучить архитектуру микроконтроллера ADuC842 .
  4. Изучить принципиальную схему лабораторного стенда LESO1.
  5. Составить алгоритм работы программы: при нажатии на кнопку, согласно варианту, загорается комбинация светодиодов, соответствующая в бинарном виде номеру кнопки; при отпускании кнопки, светодиоды должны погаснуть.
  6. Составить программу на языке программирования С.

3 Краткие теоретические сведения

3.1 Применение матричной клавиатуры для ввода информации в микропроцессорную систему

Для реализации взаимодействия пользователя с микропроцессорной системой используют различные устройства ввода-вывода информации. В самом простом случае в роли устройства ввода может выступать кнопка, представляющая собой элементарный механизм, осуществляющий замыкание-размыкание контактов под действием внешней механической силы. Схема подключения кнопки к линии ввода параллельного порта ввода микроконтроллера показана на рисунке 1. Когда контакты кнопки S1 разомкнуты через резистор R1 на вход контроллера поступает высокий логический уровень "1", когда же контакты замкнуты, то вход оказывается соединенным с общим проводом, что соответствует логическому уровню "0". Если параллельный порт микроконтроллера имеет встроенный генератор тока, то в схеме можно обойтись без резистора R1.

Рисунок 1 – Подключение одиночной кнопки к параллельному порту

Недостаток приведенной схемы заключается в том, что для подключения каждой кнопки требуется отдельная линия параллельного порта. Так как часто требуется вводить информацию с большого количества кнопок, то для уменьшения количества линий ввода-вывода используется клавиатура, представляющая собой двухмерную матрицу кнопок, организованных в ряды и столбцы (рисунок 2).

Подключение клавиатуры отличается от схемы подключения одиночной кнопки тем, что потенциал общего провода на опрашиваемые кнопки подается не непосредственно, а через порт вывода.

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


Рисунок 2 – Подключение матричной клавиатуры к параллельному порту

Временная диаграмма напряжений на портах вывода при выполнении программы опроса клавиатуры приведена на рисунке 3.


Рисунок 3 – Временные диаграммы работы порта вывода

В каждый момент времени производится чтения информации из порта ввода. Программа микроконтроллера по считанной комбинации должна определить номер нажатой кнопки клавиатуры.

Программа для микроконтроллера жестко зависит от принципиальной схемы разрабатываемого устройства. Невозможно написать программу для микроконтроллерного устройства не имея перед глазами его схемы. Поэтому, перед началом работы по принципиальной схеме учебного стенда LESO1 следует изучить способ подключения клавиатуры и светодиодов к микроконтроллеру: определить, к каким портам подключены светодиоды, столбцы и строки клавиатуры. Затем по таблице SFR нужно узнать адреса регистров задействованных портов ввода-вывода.

Программа, управляющая микроконтроллером, запускается при включении питания устройства и не завершает свою работу, пока не будет выключено питание. Поэтому в программе обязательно должен быть организован бесконечный цикл. В теле цикла должен производиться опрос клавиатуры, анализ полученных данных и вывод результата на светодиод. Опрос клавиатуры заключается в последовательном сканировании каждого столбца, для этого на соответствующую линию порта вывода подается логический ноль (эквивалент общего провода), на остальных столбцах должен быть высокий уровень, после чего с порта ввода, к которому подключены строки, считывается код. Если считаны все единицы, то ни одна из клавиш не нажата, в противном случае код содержит информацию о нажатых клавишах. Стоит заметить, что считанный код содержит не только номер замкнутого контакта, но и информацию о нажатии нескольких кнопок одновременно, поэтому лучше хранить в памяти котроллера непосредственно считанный код, а не готовый номер кнопки. Для хранения считанного кода следует ввести специальную переменную.

При написании программы нужно помнить об особенности параллельного порта P1 в микроконтроллере ADuC842 . Этот порт по умолчанию настроен на ввод аналоговых сигналов (функция АЦП). Для того чтобы перевести порт в режим цифрового входа, в соответствующий бит порта необходимо записать логический ноль. Сделать это нужно один раз при инициализации микроконтроллера. Порт не имеет внутреннего усиливающего транзистора, и потому при вводе дискретной информации через него не требуется записывать в разряды логическую единицу.

4 Задание к работе в лаборатории

  1. По принципиальной схеме установите, к каким портам микроконтроллера подключены светодиоды, а также столбцы и строки клавиатуры.
  2. По таблице регистров специальных функций (SFR) определите адреса регистров требуемых портов.
  3. Войдите в интегрированную среду программирования Keil-C.
  4. Создайте и настройте должным образом проект.
  5. Введите текст программы в соответствии с заданием: При нажатии на кнопку, согласно варианту, загорается комбинация светодиодов, соответствующая в бинарном виде номеру кнопки; при отпускании кнопки, светодиоды должны погаснуть.
  6. Оттранслируйте программу, и исправьте синтаксические ошибки.
  7. Загрузите полученный *.hex файл в лабораторный стенд LESO1 .
  8. Убедитесь, что программа функционирует должным образом.

5 Указания к составлению отчета

Отчет должен содержать:

  1. Цель работы.
  2. Принципиальную схему подключения клавиатуры к микроконтроллеру.
  3. Графическую схему алгоритма работы программы.
  4. Исходный текст программы.
  5. Содержимое файла листинга программного проекта.
  6. Выводы по выполненной лабораторной работе.

Схемы, а также отчет в целом, выполняются согласно нормам ЕСКД.

В этой статье мне бы хотелось познакомить читателей с подключением к микроконтроллерам клавиатуры. Дело в том, что обычно большинству схем на микроконтроллерах для ввода данных требуется одна или несколько кнопок. Но, когда проекты становятся сложнее, может возникнуть потребность в применении небольшой клавиатуры. Встречаются варианты клавиатур 3х4 или 4х4, и почти всегда клавиши в них соединены по схеме матрицы. Применение матрицы необходимо из -за того, что для её подключения нужно минимальное число линий ввода - вывода. Например, для клавиатуры 4х4 необходимо, состоящей из 16 кнопок необходимо 16 линий ввода, поэтому рациональнее организовать её в виде матрицы, т.е. расположить 4 кнопки в 4 строки, использовав 8 линий ввода - вывода (один порт микроконтроллера). Самое распространённое решение подключения матрицы на один порт - это подключить строки к старшим разрядам, а столбцы к младшим. Однако, здесь возникает проблема - считывание состояния клавиатуры происходит при возникновении прерывания, но в микроконтроллере ATtiny2313 мы можем использовать два внешних прерывания (остальные выводы заняты). Эта проблема решается подключением четырёх диодов, образующих с подтягивающим резистором на входе INT0 элемент «ИЛИ».

Схема подключения клавиатуры 4х4 матричного типа к микроконтроллеру приведена на Рис.1. Она имеет разъём DB-9F, преобразователь уровней MAX3232, которые необходимы для взаимодействия UART микроконтроллера с RS-232, и работа которых была описана в предыдущей статье. Резисторы R3 - R6 защищают микроконтроллер от короткого замыкания питания на землю. На входе INT0 имеется подтягивающий резистор R7 . Четыре диода VD1 - VD4 подключены к линиям ввода- вывода клавиатуры (катодами) и к выводу INT0 (анодами). Теперь при нажатии любой кнопки, если на столбцы подать нули, на входе INT0 появится низкий уровень.

Как показано на Рис.1 клавиатура подключена к порту В микроконтроллера. Её схема представлена на Рис.2.

Предположим, что весь порт В настроен на вход, и все входа имеют подтяжку:

DDRB = &B00000000

PORTB = &B11111111

Пусть кнопки (Рис.2) каким -то образом соединены ещё и «землёй» (GND), тогда при нажатии, например, кнопки «1» на контактах порта В РВ3 и РВ4 будет низкий уровень, т.е. порт примет значение PORTB = &B11100111, которое и является кодом кнопки «1». Аналогично и в отношении остальных кнопок (код кнопки «В» - 01111011, «5» - 11011011 и т.д.). Но, поскольку кнопки не соединены с GND, необходимо ввести раздельное определение строк и столбцов с последующим суммированием и идентификацией результата с названием кнопки.

Сделаем строки РВ0 - РВ3 входами и включим их подтяжку, а столбцы РВ3 - РВ7 - выходами:

DDRB = &B11110000

PORTB = &B00001111

При нажатии кнопки определённая строка будет иметь низкий уровень. Например, при нажатии кнопки «1» порт В примет значение 00000111, которое является кодом строки. Одновременно с этим включится прерывание, при обработке которого необходимо считать данный код в переменную Stro:

Инвертируем настройки порта - сделаем столбцы РВ3 - РВ7 входами и включим их подтяжку, а строки РВ0 - РВ3 - выходами:

DDRB = &B00001111

PORTB = &B11110000

Теперь при нажатой кнопке «1» порт будет иметь значение 11100000, которое является кодом столбца. Считаем этот код в переменную Col.

И как же мы собираемся делать матрицу? А самое главное - зачем она вообще нужна? Ну, виной тому, в основном, физические ограничения микроконтроллеров, на базе которых строятся клавиатуры. Дело в том, что с увеличением количества выводов у микроконтроллеров и программируемых логических микросхем растёт и их размер, что, в свою очередь, влечёт за собой рост энергопотребления, возможностей, но главное - цены. В итоге, вы можете выбрать либо дешёвый чип с небольшой производительностью (которая вас вполне устраивает), но с малым количеством входов и выходов, либо более мощную микросхему, производительность которой, однако, сильно превышает ваши требования. Но только этот мощный чип будет обладать достаточным количеством выводов, чтобы подключить каждую кнопку клавиатуры.

За десятилетия в электронике сложилась практика при помощи различных ухищрений искусственно расширять встроенные коммуникационные возможности процессоров и контроллеров. Одним из таких способов, который хорошо подходит для механических контактов (кнопок), и является создание матрицы. Чтобы понять, как она работает, требуются некоторые базовые знания. Прежде, чем мы продолжим, пожалуйста, освежите в памяти закон Ома .

Немного теории

Чтобы разобраться, как работает цифровая электроника, надо усвоить два базовых принципа.

Принцип первый гласит, что процесс коммуникации внутри схемы - это не передача или получение чего-то там. Чтобы обеспечить коммуникацию между двумя устройствами, вы просто соединяете между собой их выводы электропроводящим материалом. После этого предполагается, что состояние материала (напряжение и ток) на обоих его концах будет одинаковым. В реальности это, конечно, не так, но для медленных коммуникаций и коротких проводников наше предположение работает отлично. Выходит, что посылка и получение информации на самом деле является её совместным использованием.

Со стороны передатчика вы просто изменяете электрическое состояние проводника (запуская в него постоянный ток, изменяя его потенциал), рассчитывая на то, что приёмник сможет определить это изменение и правильно его понять.

Из этого принципа также следует, что между направлением коммуникации и направлением электрического тока нет никакой зависимости. Многие люди ошибочно предполагают обратное, и это мешает им понять, как работает электроника.

Если нужно послать логический уровень «0», то обычно для этого напряжение на выводе передатчика понижают до 0 В, и из приёмника в передатчик начинает течь ток, чтобы приёмник смог определить, что логический уровень соответствует «0». (Тогда как обратное направление тока означало бы, что где-то в схеме присутствует отрицательный потенциал - а этого, как правило, в цифровой электронике не бывает.) С другой стороны, для передачи логического уровня «1» прикладывают напряжение, равное напряжению питания, а так как это, чаще всего, самое высокое напряжение в схеме, то электрическому току не останется ничего другого, как потечь из передатчика в приёмник.

Принцип номер два заключается в том, что невозможно определить состояние проводника, не изменив это состояние. Неважно, собрались ли вы измерять напряжение или ток - в любом случае, для этого необходимо, чтобы через ваш измерительный прибор потекли электроны. Поток электронов - это и есть электрический ток, а раз он течёт, то значит, что в узле, к которому вы подключились для измерения, токи и напряжение уже изменились (см. законы Кирхгофа). Из этого следует, что если вам нужно «передать» информацию, изменив состояние вывода, электрически связанного с другим выводом, то для этого требуется поддерживать данное состояние, а значит, соблюдать все требования, налагаемые приёмником.

Кнопка

Механическая кнопка (а в данном контексте слово «механическая» не связано со словосочетанием «механическая клавиатура») - это просто пара металлических контактов, которые, соприкасаясь, электрически соединяют два вывода. Конечно, бывают и другие типы переключателей, конструктивно более сложные и имеющие большее количество выводов, но нам они не интересны, потому что в клавиатурах не используются.

Ну, и как мы будем подключать кнопку ко входу микроконтроллера? Принципиально, любой вход может оперировать двумя возможными логическими уровнями: «0» и «1». Обычной практикой является принятие напряжений, близких к 0 В, за логический ноль, а напряжений, близких к напряжению питания (как правило, 5 В или 3,3 В) - за логическую единицу. Но проблема состоит в том, что управлять напряжением механическая кнопка сама по себе не может. Она управляет током - то есть, если мы соединим два узла с разным электрическим потенциалом через кнопку, то ток между этими узлами потечёт тогда и только тогда, когда кнопка будет нажата.

Но если мы добавим резистор, то очень просто сможем преобразовать ток в напряжение.

Кнопка с подтягивающим резистором

Взгляните на эту схему. Когда кнопка не нажата (цепь разорвана), ток через неё не течёт, поэтому напряжение в узле «A» будет близким к напряжению питания VCC (на самом деле, меньше VCC на величину падения напряжения на резисторе, равную R I). Когда кнопка нажата (цепь замкнута), ток течёт через резистор на землю. С учётом того, что сопротивление замкнутой кнопки очень мало (порядка сотен миллиом), напряжение в узле «A» будет близким к «0».

В данной конфигурации резистор называют подтягивающим, потому что он «подтягивает напряжение вверх» до уровня VCC. А без подключения к питанию через резистор никакого напряжения в узле «A» вообще бы не было (в таком случае вывод микросхемы называют «висящим в воздухе» или находящимся в высокоимпедансном состоянии).

Необходимо отметить, что внутри у большинства современных микроконтроллеров уже присутствуют подтягивающие резисторы, которые можно оперативно подключать или отключать при помощи программы. Так что, основным способом соединения кнопки с микроконтроллером является следующий: один вывод кнопки - ко входу микроконтроллера, другой вывод кнопки - к земле. В таком случае, если кнопка не нажата, то на микроконтроллер подаётся «1», а если нажата, то «0». Возможно, это и противоречит интуиции, но данный способ подключения - самый популярный.

Обратите внимание, что если мы оставим один из выводов кнопки висящим в воздухе, то есть никуда его не подключим, то эта кнопка работать не будет вообще: сколько её не нажимай, она никак не повлияет на электрическое состояние вывода микроконтроллера. Мы ещё воспользуемся этим свойством, когда будем составлять матрицу.

Принцип матрицы

Основным принципом клавиатурной матрицы является возможность подключать к одному входу микроконтроллера более одной кнопки.

При помощи транзисторов или правильно сконфигурированных выходов микроконтроллера мы можем сделать так, что кнопки к земле будут подключаться по одной, в то время как остальные будут висеть в воздухе. Оставшиеся выводы каждой из кнопок объединены в один узел и подключены ко входу микроконтроллера. Я опустил подтягивающий резистор, так как мы знаем, что он уже присутствует внутри микроконтроллера, в его входном каскаде. Мы по очереди «включаем» каждую кнопку, соединяя её вывод номер 1 с землёй через соответствующий выход микроконтроллера, после чего на входе мы можем прочесть состояние кнопки, сняв напряжение с её вывода номер 2. Другие кнопки, подключённые к этому же входу, не влияют на его состояние, потому что их выводы номер 1 в данный момент времени висят в воздухе. Следующая схема иллюстрирует эту идею.


Много кнопок, один вход (узел «A»)

«A» - это единственный вход микроконтроллера, а «C1»..«Cn» - его выходы. На одном из выходов установлен логический «0», то есть внутри микросхемы этот контакт каким-то образом соединён с землёй - следовательно, ток всегда будет течь к этому контакту (в соответствии с первым базовым принципом). Теперь, когда нажмётся кнопка, подключённая к данному выходу, то через неё вход «A» сразу же «придавится» к земле, и он установится в «0». Нажатия на другие кнопки ничего не изменят, потому что их земляные выводы в данный момент времени никуда не подключены. Когда нам потребуется опросить следующую кнопку, мы убираем с текущего выхода логический «0» и устанавливаем этот уровень на следующий выход, так что в любой момент времени будет задействован только один из выходов микроконтроллера.

Такая конфигурация (когда выход либо подключён к земле, либо вообще отключён) называется выходом с открытым стоком (ОС) (исторически - с открытым коллектором (ОК)). Здесь я допустил некоторое упрощение - на самом деле, контакт не может быть полностью отключён от схемы, если только он физически от неё не отрезан. Но для простого цифрового ввода-вывода такое упрощение вполне подходит. Большинство микроконтроллеров предоставляют возможность программной конфигурации своих выходных контактов для работы в режиме ОС. Но что, если у нас нет такой возможности? Существует и другая конфигурация - двухтактный режим; на сегодняшний день этот вариант - один из самых популярных. Работает такая конфигурация немного по-другому. В состоянии «0» выход всё так же придавлен к земле, но когда наступает состояние «1», он подтягивается к напряжению питания VCC, так что выход в воздухе больше не висит, теперь он сам может стать источником тока.

Какие изменения это повлечёт в конструкции матрицы? Если мы не собираемся нажимать несколько кнопок одновременно, то никаких. Но если собираемся, то взгляните на рисунок и представьте на секунду, что тогда произойдёт. Нажимая на две кнопки, мы соединяем два нижних выхода в замкнутый контур. Если при этом один из них в состоянии «0», а другой - в состоянии «1», то от выхода, установленного в «1», к выходу, установленному в «0», потечёт электрический ток. А так как этот ток ничем не ограничен (нет резисторов), то мало того, что схема станет нестабильной, так ещё и чип может вылететь. Ну и, само собой, вряд ли получится нормально считать логическое состояние.

Добавление строк

Можете рассматривать предыдущий пример как матрицу, состоящую из одной строки. А теперь давайте увеличим её, нарастив дополнительные строки. В самом деле, если мы можем повесить на один вход целую строку, то почему мы не можем повесить на один выход целый столбец кнопок? Правда, есть обязательное условие - каждая кнопка столбца должна подключаться к отдельному входу микроконтроллера.

Если мы расположим кнопки в форме обычной матрицы, то это условие выполнится автоматически. А на следующем рисунке показано, как будет выглядеть матрица кнопок, состоящая из n столбцов и m строк (на зелёные фигуры внимания пока не обращайте ).


Простая клавиатурная матрица

Считывать эту матрицу очень просто. Мы опрашиваем по одному столбцу за раз. Столбец для считывания выбирается путём соединения одного из выходов «C1»..«Cn» с землёй (выход в режиме ОС переводится в «0»). Теперь, поочерёдно опрашивая строки «R1»..«Rm», мы можем определить состояние каждой кнопки выбранного столбца. Кнопки из других столбцов ни на что не влияют, даже если они нажаты, потому что в данный момент их земляные выводы висят в воздухе (или, как говорят в электронике, находятся в состоянии Hi-Z).

После того, как будет опрошен весь столбец, мы переходим к следующему, отпустив текущий выход и придавив к нулю очередной. Сканирование матрицы считается оконченным, когда будут опрошены все столбцы. Если всё делать достаточно быстро, то интервалы между опросами столбцов не заметит и самый быстрый наборщик. Даже имея микроконтроллер 16 МГц, мы легко сможем сканировать всю матрицу тысячи раз в секунду, тогда как самый быстрый наборщик в тесте на hi-games.net добился скорости 203 слова в минуту (wpm) - то есть, чуть меньше, чем 17 нажатий в секунду.

Проектируя клавиатуру с использованием матрицы, мы уменьшаем количество выводов, требуемых для подключения всех клавиш. Но для того, чтобы свести число выводов к минимально возможному, нам надо составить матрицу таким образом, чтобы количество столбцов было как можно ближе к количеству строк. В идеальной ситуации, если количество кнопок равно , то лучшее, чего мы сможем добиться при помощи матрицы - это 2n занятых выводов микроконтроллера. Однако сегодня при составлении матриц редко кто стремится максимально уменьшить количество задействованных ног, ведь современные микроконтроллеры, как правило, обладают достаточным количеством свободных выводов. Вдобавок, максимальная оптимизация матрицы может впоследствии привести к неудобствам - заметно усложнится разводка платы или распределение проводов в конечном устройстве. Поэтому стоит пойти более удобным путём: при составлении матрицы пытаться следовать физическому расположению кнопок. В таком случае, для стандартной компьютерной клавиатуры самая простая матрица будет иметь всего 6 строк и некоторое количество столбцов, в зависимости от желаемой компоновки. Конечно, с точки зрения количества задействованных выводов это решение - не самое оптимальное, но зато в дальнейшем хотя бы упростится разводка.

А что, если выходов с открытым стоком у нас нет?

Вы можете спросить: а как нам быть, если в выбранном микроконтроллере всё-таки нет режима ОС? Ну, мы уже выяснили, какая неприятность может случиться, и что подтягивать выходы к VCC (то есть, «соединять» их с питанием) - не самая лучшая идея. Существует множество способов решения этой проблемы; среди них встречаются не только специальные выходные буферы ОС, но даже сдвиговые регистры с ОС-выходами - для ещё большей минимизации количества задействованных ног. Но есть и ещё один очень популярный приём, который довольно часто применяется в конструкциях компьютерных клавиатур (на самом деле, широко он применялся в былые времена).

Проблема подключённых к двухтактным выходам столбцов проявляется в тот момент, когда вместе нажимаются две кнопки, находящиеся в одной строке, причём одновременно с этим нажатием происходит опрос столбца, в котором расположена одна из кнопок.


Проблема двухтактных выходов

Из выхода, который подтянут к «1» (а не висит в состоянии Hi-Z), начинает течь ток. Он проходит через ближайшую замкнутую кнопку, затем - через замкнутую кнопку в опрашиваемом столбце, и, наконец, втекает прямиком в выход, установленный в «0». Это может привести к чему угодно - начиная с невозможности надёжного считывания состояния клавиатуры и заканчивая выходом из строя самого микроконтроллера.

Но раз уж мы вынуждены как-то бороться с этой проблемой, то можем применить отличный трюк: превратить двухтактный выход в подобие выхода с открытым стоком. Я часто сталкивался с этим решением в конструкциях старых клавиатур. Учитывая, что ток должен только втекать в выходы (подключённые к столбцам), но никогда не вытекать из них, мы можем ограничить направление тока при помощи диодов. Диод - это простое устройство, которое позволяет току течь только в одном направлении. В изображении диода на электрической схеме треугольник символизирует стрелку, которая указывает это направление. Если поставить по диоду между каждым выходом микроконтроллера и проводником соответствующего столбца матрицы, то мы добьёмся поставленной цели - теперь ток может только втекать в выходы, ведь указанные проводники дотягиваются до каждой кнопки своего столбца. Получается, что из выхода, установленного в «1», ток никуда не потечёт, а это почти что превращает его в выход с открытым стоком. Конечно, до настоящего ОС он не дотягивает, но зато решает нашу проблему замкнутого токового контура в клавиатурной матрице. Вернитесь к предпоследнему рисунку матрицы, но на этот раз примите во внимание зелёные диоды , чтобы понять, как работает этот трюк.

Естественно, имеет смысл минимизировать количество диодов. Для этого можно уменьшить число столбцов, увеличив количество строк. А если получившийся результат плохо вписывается в реальную компоновку клавиатуры, то можно «развернуть» матрицу на 90° (поменять местами строки со столбцами). Возможности безграничны. Но в наши дни появилось огромное количество микроконтроллеров, которые просты в использовании и удобны для хоббистов, поэтому сегодня в проектах доморощенных клавиатур описанный приём уже практически не используется. К счастью.

Фантомные нажатия (Ghosting)

Если вы интересуетесь клавами, то, должно быть, уже встречались с этим термином. К сожалению, в мире клавиатур его часто интерпретируют неправильно.

Мы уже знакомы с ситуацией, когда одновременное нажатие нескольких кнопок, находящихся в одной строке, может помешать нормальному считыванию матрицы. И эта проблема, можно сказать, нами решена. А теперь давайте посмотрим, что случится, если нажать несколько кнопок, находящихся одновременно в одной строке и в одном столбце.


Пример фантомного нажатия

На рисунке три кнопки нажаты одновременно. Две из них находятся в столбце «C2», и две - в строке «Rm». Это значит, что одна из нажатых кнопок делит строку с другой нажатой кнопкой, а столбец - с третьей нажатой кнопкой. Именно в такой ситуации и происходит фантомное нажатие . Представьте, что в данный момент мы опрашиваем столбец «C1» (то есть, он придавлен к земле - находится в состоянии «0»). Такой характерный аккорд нажатых кнопок приводит к следующему: даже несмотря на то, что левая верхняя кнопка не нажата, строка «R2» находится в состоянии «0», потому что она придавлена к земле столбцом «C1» (находящемся в «0») через три нажатые кнопки. В результате клавиатурный контроллер считывает левую верхнюю кнопку, как «нажатую», вне зависимости от того, нажата она на самом деле или нет. Описанная ситуация называется фантомным нажатием (ghosting ), потому что некоторые комбинации одновременно нажатых кнопок вызывают фантомные срабатывания других кнопок (ghost keypresses), хотя физически эти другие кнопки и не нажаты.

Конечно, существуют способы оградить наборщиков и геймеров от фантомных срабатываний, и эти способы широко применяются в современных компьютерных клавиатурах. Можно поймать момент возникновения фантомного нажатия и заблокировать его. Обычный человек не в состоянии одновременно нажать или отпустить две клавиши с идеальной точностью. Поэтому, сканируя матрицу достаточно быстро, мы можем предположить, что между двумя проходами по матрице изменить своё состояние может не больше одной кнопки. В таком случае, контроллер принимает одиночные нажатия и следит за возникновением ситуаций, когда между проходами матрицы оказываются нажатыми две кнопки или более. Учитывая, что сканирование матрицы происходит со скоростью, при которой штатное возникновение таких ситуаций крайне маловероятно, можно заключить, что одна из только что нажатых кнопок - фантом. Поэтому контроллер должен проигнорировать все эти нажатия. Кроме того, безопаснее сразу не сообщать компьютеру об изменениях статуса клавиатуры - сначала имеет смысл подождать, пока все эти срабатывания не пропадут.

Есть и другой подход. Можно выявить ситуацию, когда срабатывает «третья» кнопка, и заблокировать как это нажатие, так и все последующие. Блокировку не снимать до тех пор, пока фантомное срабатывание не пропадёт, и ситуация опять не станет нормальной. Для реализации этого подхода программа должна помнить, какие именно кнопки сейчас нажаты (а обычно она это помнит и так), чтобы отклонять последующие срабатывания кнопок, в строках и в столбцах которых уже зафиксированы одновременные нажатия. Если написать программу с умом, то блокироваться будут только проблемные срабатывания, а все последующие будут приниматься как обычно - кроме тех, что снова нарушат правила. Раз контроллер отвергает нажатие каждой кнопки, уже имеющей одновременные срабатывания в своей строке и столбце, то выходит, что в зависимости от статуса одних кнопок, другие могут не регистрироваться вообще. Эта ситуация широко известна как блокирование (jamming ). То есть кнопки, которые препятствуют одновременным срабатываниям других кнопок, получается, «блокируют» часть клавиатуры.

С точки зрения пользователя, можно одновременно нажать все кнопки из одного столбца (не нажимая кнопок из другого), но одновременно нажать все кнопки из одной строки можно только в том случае, если в столбце у каждой из этих кнопок зафиксировано не более одного срабатывания. То же самое относится и к нажатию кнопок из одного столбца - дополнительные срабатывания фиксируются только в том случае, если кнопки находятся в строках, которые «не заняты».

Люди часто путают «фантомное срабатывание » и «блокирование срабатывания » («ghosting » и «jamming »), что лично для меня является загадкой - по-моему, эти термины вполне интуитивны.

В клавиатурах с использованием таких матриц, как мы только что рассмотрели, невозможно избежать ни фантомных срабатываний, ни блокирования. Поскольку фантомные срабатывания в повседневной работе недопустимы, то для борьбы с ними практически все производители резинокупольных клавиатур пускают в ход различные ухищрения, и в игру вступает блокирование. Вопрос: как составить матрицу таким образом, чтобы блокирование возникало как можно реже и не вызывалось бы распространёнными клавиатурными комбинациями? На самом деле, это - хорошая тема для целой книги; именно поэтому матрицы ширпотребовских клавиатур такие запутанные и всегда блокируют хорошее настроение (типа, каламбур).

Диоды на все кнопки - кардинальное решение

Если вы ещё раз взглянете на картинку про фантомные нажатия, то сможете заметить, что во всём виновата правая нижняя кнопка.
А ведь эта кнопка - единственная, через которую ток в данной ситуации течёт «вверх». Так что, если мы не хотим, чтобы текущие «вверх» токи мешали нам нормально считывать матрицу, то давайте введём диоды, чтобы ток мог идти по столбцам строго сверху вниз, втекая в выходы микроконтроллера.

К сожалению, сэкономить тут не получится - придётся ставить по диоду на каждую кнопку. Если же говорить о полярности, то вы уже должны были разобраться, что в данном конкретном случае диоды должны пропускать ток «сверху вниз», то есть их катоды («кончики стрелок») должны смотреть на выходы микроконтроллера (столбцы), тогда как аноды должны быть обращены ко входам (строкам).


Итоговая матрица

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

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

Ролловер (Rollover)

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

xKRO

KRO означает клавишный ролловер (key rollover ), и обычно эта аббревиатура озаглавлена каким-то числом. Например, 2KRO означает двухклавишный ролловер. Клавиатура обладает x -клавишным ролловером тогда и только тогда, когда она способна зарегистрировать x одновременных нажатий, причём - вне зависимости от того, какие кнопки и в какой последовательности были задействованы. Большинство современных резинокупольных клавиатур обладают 2KRO. Из этого, однако, не следует, что допустимое количество нажатий у этих клавиатур всегда будет ограничено числом x . На самом деле это означает, что поддержка x одновременных нажатий гарантируется точно.

В зависимости от конструкции матрицы и от типа контроллера, две клавиатуры 2KRO от разных производителей могут вести себя совершенно по-разному. Одна может всегда воспринимать только два одновременных нажатия, а другая с лёгкостью переварит и больше. Думается, последняя клавиатура была заявлена 2KRO потому, что некоторые комбинации клавиш (скорее всего, маловероятные) всё-таки будут вызывать у неё блокирование нажатий других кнопок. А так как это означает, что при работе с данной клавиатурой определённые комбинации из трёх клавиш и более срабатывать не будут, то компания и объявила её 2KRO.

NKRO

Термин NKRO означает N-клавишный ролловер , и его используют для обозначения клавиатур, поддерживающих, несмотря ни на что, любую комбинацию одновременно нажатых клавиш. Но имейте в виду, что NKRO матрицы и NKRO клавиатуры - это две большие разницы. К примеру, если итоговая реализация матрицы, рассмотренная нами в статье, поддерживает NKRO (с учётом корректно написанной прошивки), то из этого совсем не следует, что клавиатура, использующая данную матрицу, тоже будет поддерживать NKRO. Это может происходить из-за ограничений, накладываемых коммуникационными портами, к которым подключается клавиатура; другой причиной может стать бережливость производителей, вечно экономящих то здесь, то там. Проблему NKRO при соединении с PS/2 и USB я попытаюсь разъяснить в следующих частях.

Итог

Конечно, простыня вышла изрядная, но ведь концепция не такая уж и простая - особенно для читателя, который не является инженером-электронщиком. Надеюсь, мне удалось всё объяснить; как бы то ни было, писать я старался как можно понятнее. Поэтому кому-то из вас статья могла показаться довольно скучной. Ну, а если вы шарите в электронике, то, скорее всего, читать вам её вообще не стоило;)
В любом случае, пожалуйста,