РадиоКот :: Что такое матрица и с кого все спросить
Например TDA7294

РадиоКот >Обучалка >Микроконтроллеры и ПЛИС >Микроконтроллеры AVR - пишем, компилируем, прошиваем... >

Теги статьи: КлавиатураТеорияДобавить тег

Что такое матрица и с кого все спросить

Автор:
Опубликовано 18.01.2006

Итак, господа хорошие, закончилась череда праздников: Новый Год, Рождество, Старый Новый Год… Вспомнить страшно сколько всего закончилось. Но мы, под чутким руководством Кота Пьющего Но Никогда Не Напивающегося, прошли сквозь все эти ужасы и испытания, и готовы снова трудиться во благо общества… Это была присказка.

Сказка.

В некотором царстве, в некотором государстве, а именно – у нас на форуме – неоднократно задавался вопрос: «Как подключить клавиатуру к контроллеру?»
Рассмотрением этого вопроса мы и начнем нашу первую постпраздничную публикацию.

Как вы поняли из предыдущей статьи, в борьбе за уменьшение проводов и выводов процессора, прогрессивное человечество придумало динамическую индикацию. Для подключения клавиатуры, хитрое человечество тоже кое-что придумало. Что? А вот чего: динамический опрос!

Сегодня, используя это замечательное изобретение, мы подключим к нашему контроллеру клавиатуру от кнопочного телефона и заставим контроллер увидеть эту клавиатуру.

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

Матричная организация клавиатуры

То что вы видите, называется «матрица». Этот чтоб у вас в дальнейшем не возникало вопроса «Что такое матрица?»… Так вот, почти все клавиатуры в этом мире имеют матричную структуру. Матрица имеет сколько-то строк и сколько-то столбцов. Количество строк и столбцов матрицы высчитывается исходя из количества кнопок в клавиатуре. Соотношение столбцов и строк при этом должно быть таким, чтобы их сумма была минимальной

Например, наш случай: есть 12 кнопок. Число 12 можно разложить на целые множители следующими способами:

12 = 1*12
12 = 2*6
12 = 3*4

Замечательно. Теперь посчитаем суммы множителей:

1+12 = 13
2+6 = 8
3+4 = 7

То есть, оптимальной для нашего варианта является матрица, у которой 4 строки и 3 столбца (или наоборот). Ну, собственно, что мы и видим на схеме.

Теперь осталось подключить сие к контроллеру. Ну что же – подключаем! За основу возьмем схему из предыдущей статьи:

Адресные входы клавиатуры (строки матрицы) подключаем к адресной шине индикаторов. Шина данных (столбцы) – подключаются к свободным выводам контроллера. Каждый провод шины данных подтянут к «плюсу» резистором 300 Ом. Это нужно для того, чтобы в случае, если ни одна кнопка не нажата, на входы контроллера приходила «1». Если этого не сделать – на входе будет так называемое 3-е состояние – не пойми чего. Это не пойми чего, контроллер может понять совершенно произвольно. Может посчитать «нулем», может – «единицей», что вызовет ложные «нажатия» клавиш.

Номинал резисторов – произвольный в пределах 200 Ом…2 кОм

Как вы поняли, опрос клавиатуры производится параллельно с индикацией. При написании программы, мы это учтем…

Итак, священный момент: пишем софт!

Для начала – пару слов о том, что и как мы будем писать:
В программе динамической индикации, цикл состоял из четырех почти одинаковых кусков. Вот пример такого куска:


              lds Temp1,Digit      ;загружаем ячейку с цифрой 

ldi Temp,0b00001110 ;выставляем адрес индикатора

out PortD,Temp ;выводим адрес индикатора

rcall Decoder ;вызываем 7-сегментный декодер

out PortB,Temp1 ;выводим полученный код

rcall Delay1 ;вызываем задержку

Теперь в этот кусок мы допишем две строки (перед вызовом задержки):


              in Temp,PinD         ;читаем порт D 

sts Line,Temp Temp ;записываем прочитанное в ОЗУ

Как видите, у нас появилась новая переменная Line . В ней хранится то, что мы читаем из порта D . То есть – состояние кнопок в строчках клавиатуры. В Line+0 лежит состояние 0-й (верхней) строчки, в Line+1 – первой, и т.д.

Эту переменную надо объявить. Объявляем ее в сегменте данных, после переменной Digit:


Digit:	.byte 4
Line:	.byte 4

Теперь после цикла индикации нужно дописать подпрограмму обработки всего того, что мы прочитали с клавиатуры, за проход индикации.

Назовем ее KeyRead:


KeyRead:

;блок проверки строки (всего их 4)
              lds Temp,Line         ;читаем состояние строки
              rcall KeyTest         ;вызываем программу проверки
                                    ;программа возвращает номер кнопки: 0..2
                                    ;или -1 - если нет нажатых кнопок

              ldi Temp,0            ;загружаем код текущей строки
              ;код текущей строки - это номер кнопки,
              ;с которой начинается эта строка
              cpi Temp1,255         ;если ничего не нажато - идем дальше
              brne SetKey           ;иначе - переходим на обработку
;конец 0-го блока

              lds Temp,Line+1
              rcall KeyTest
              ldi Temp,3
              cpi Temp1,255
              brne SetKey

              lds Temp,Line+2
              rcall KeyTest
              ldi Temp,6
              cpi Temp1,255
              brne SetKey

              lds Temp,Line+3
              rcall KeyTest
              ldi Temp,9
              cpi Temp1,255
              brne SetKey

              ldi Temp,0


SetKey:       add Temp,Temp1        ;прибавляем номер кнопки
                                    ;к коду строчки
              lds Temp1,Key         ;грузим код кнопки,
                                    ;прочитанный в прошлый раз
              andi Temp1,0b00001111 ;"чистим" его по маске
              cp Temp,Temp1         ;если в прошлый раз
              brne EndKeyRead       ;была нажата не та же кнопка
                                    ;выходим

              ori Temp,0b10000000   ;иначе - пишем флажок "повтор"

EndKeyRead:   sts Key,Temp          ;сохраняем код кнопки в ОЗУ

              ret                   ;выходим


;*********************************************************

KeyTest:      andi Temp,0b01110000  ;обрезаем по маске
              ldi Temp1,0b01110000
              eor Temp,Temp1        ;инвертируем биты по маске
              breq NoButtons        ;если все нули (нет нажатых)
                                    ;переходим по метке

              ldi Temp1,0           ;инициализируем счетчик

              cpi Temp,0b00010000   ;проверяем 0-ю кнопку
              breq EndKeyTest       ;нажато - выход
              inc Temp1             ;иначе - инкремент счетчика

              cpi Temp,0b00100000   ;проверка 2 кнопки
              breq EndKeyTest
              inc Temp1

              cpi Temp,0b01000000   ;проверка 3 кнопки
              breq EndKeyTest

NoButtons:    ldi Temp1,255         ;если ничего не нажато -
                                    ;возвращаем 255

EndKeyTest:   ret

Эта программа будет вызываться из цикла Main сразу же после индикации. Она читает ячейки переменной Line на предмет информации о нажатых кнопках. Если ни одна кнопка не нажата – программа возвращает -1 (или 255 – одно и то же). Если нажата хоть одна кнопка – возвращается ее значение. Если при предыдущей проверке была нажата та же кнопка – ставим флажок «повтор» (старший бит возвращаемого значения). Этот флажок нужен для предотвращения повторного выполнения одной и той же операции (которая закреплена за данной кнопкой).

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


Keyboard:
;запускает выполнение операции, закрепленной за кнопкой


              lds Temp,Key          ;загружаем переменную Key
              mov Temp1,Temp        ;проверяем на наличие флажка
              andi Temp1,0b10000000 ;"повтор" или -1
              brne EndKeyboard      ;если повтор или -1 - выходим


              ldi ZH,High(KeysLUT*2);загружаем таблицу
              ldi ZL,Low (KeysLUT*2);истинности
                                    ;(клавиша -> значение)

              ldi Temp1,0           ;смещаемся на номер клавиши
              add ZL,Temp
              adc ZH,Temp1

              lpm                   ;загружаем значение элемента
              mov Temp,R0

              lds Temp1,Digit+2      ;сдвигаем разряды индикатора
              sts Digit+3,Temp1      ;на один влево
              lds Temp1,Digit+1
              sts Digit+2,Temp1
              lds Temp1,Digit
              sts Digit+1,Temp1

              sts Digit,Temp        ;пишем в млад. разряд
                                    ;индикатора текущее значение



EndKeyboard:  ret

;*********************************************************
KeysLUT:
.db  1,2,3,4,5,6,7,8,9,10,0,11      ;массив
;(таблица истинности клавиатуры)

Эта программа читает переменную Key, и если она равна 255 или стоит флаг повтора – ничего не делаем и выходим. Иначе – загружаем таблицу истинности (попросту - массив), в которой коду каждой клавиши соотнесено определенное число.

Наша программа будет брать значение этого числа, и записывать его в младший разряд индикатора, перед этим сдвинув предыдущее значение индикатора на 1 разряд влево.

Вот так хитро, и в то же время – просто. Теперь – вникаем в прогу целиком. Сразу скажу, что я добавил в массив 7-сегментного декодера символы шестнадцатеричной системы: a, b, c, d, e, f. Не удивляйтесь :)

Полный текст программы - "indicate+keyboard.asm"

Все вопросы, как всегда – на форум.




Как вам эта статья?

Заработало ли это устройство у вас?

56 5 1
11 5 0

Эти статьи вам тоже могут пригодиться: