Большой архив статей, книг, документации по программированию, вебдизайну, компьютерной графике, сетям, операционным системам и многому другому
 
<Добавить в Избранное>    <Сделать стартовой>    <Реклама на сайте>    <Контакты>
  Главная Документация Программы Обои   Экспорт RSS E-Books
 
Поиск по сайту

 

   Программирование -> Assembler -> Динамический опрос клавиатуры


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

Сильно умных названий приводить не буду. Не способствуют они пониманию у новичков, да я этих названий и сам не очень знаю.
Речь пойдёт о том, как реализовать клавиатуру на микроконтроллере (в примерах используется МК AT90S1200 фирмы Atmel) и какие при этом могут возникнуть трудности.
Сначала о железе. Способ подключения кнопок к портам МК выбирается на усмотрение разработчика в зависимости от требуемого количества кнопок и от количества выводов портов. Ниже описаны только два способа.


Рисунок 1.

При небольшом количестве кнопок и равном или большем количестве пинов (пин - вывод) МК, кнопки подключаются непосредственно к входам. На рисунке 1 - схема подключения кнопки, при которой в ненажатом положении на вход подаётся логическая единица (напряжение 5 вольт относительно общего провода), а в нажатом - логический ноль (уровень напряжение 0 вольт относительно общего провода). Резистор "подтягивает" вход МК к единице. Это делается для того, чтобы избежать т.н. третьего состояния (состояние "Z" или просто "обрыв") на входе. При Z на входах возникают помехи - очень короткие импульсы тока, которые могут свести систему с ума. Помехи возникают от статического электричества, от прикосновения пальцами к проводникам, от работающих поблизости приборов. Подтяжка работает так: в ненажатом состоянии сопротивление между нулём и входом очень велико, и через резистор на входе создаётся потенциал, воспринимаемый МК как лог. 1. При нажатии картина меняется - теперь резистор - относительно бесконечное сопротивление, а на пине - потенциал нуля.


Рисунок 2.

Матрица кнопок позволяет использовать кнопок вдвое больше количества доступных пинов портов(если матрица квадратная). На рисунке 2 изображена матрица для клавиатуры из 11 кнопок, взятая из реального устройства. Для работы с ней используется 7 пинов порта B. Четыре пина (PB0-PB3) программно сконфигурированы как выхода и три пина (PB4-PB6) - как входы.
Резисторы показаны как внешние, но имеется возможность программно подключить внутренние подтягивающие к единице резисторы, а внешние при этом можно убрать.
Принцип опроса матрицы таков.
Группы кнопок условно разбиты на "линейки" и "колонки". Сначала программно на выходах PB1-PB3 выставляются единицы, а на PB0 - ноль. При этом включена первая колонка. Если сейчас нажать в любом сочетании кнопки этой колонки, то на входах сформируется трёхбитный код, который программа сохраняет в массиве. Затем первая колонка отключается, и подключается следующая, и т.д.
Также полезно избавляться от дребезга контактов. Это не требуется тогда, когда нужно, к примеру, просто зажечь светодиод. Но необходимо, если считанный сигнал МК использует для управления какой-либо логикой. Дребезг - это механическое отскакивание металлических контактов при замыкании, при этом формируется пачка коротких импульсов, что не есть хорошо. Для формирования "чистого" фронта из аппаратных средств чаще всего используются повторители с гистерезисом (здесь о нём не будем). Если время исполнения программы некритично, то от дребезга можно избавиться программно, что здесь и сделано. Применённый здесь алгоритм защиты от дребезга таков: перед опросом клавиатуры сбрасывается некоторый флаг, показывающий изменение текущего состояния клавы по с равнению с предыдущим. Каждый считанный бит перед записью в массив сравнивается со старым значением это бита в массиве, и если они не равны, то флаг устанавливается. Если после опроса всей клавиатуры флаг установлен, то, возможно был дребезг, и опрос начинается заново. Если состояние кнопок не поменялось N раз, то считается, что дребезг окончился. N - подбирается экспериментально.
Вот код, осуществляющий опрос клавиатуры. Синим цветом выделены участки кода, которые относятся к избавлению от дребезга.


.include "1200def.inc"
;16...31 можно загружать ldi
.DEF line1=r16 ;--
.DEF line2=r17 ; -- массив битов для хранения нажатых кнопок
.DEF line3=r18 ;--
.DEF inmask=r19 ;маска ввода
.DEF Nc=r20 ;счётчик повторений сканирования матрицы кнопок
.DEF temp=r21 ;--
.DEF temp1=r22 ; -- врЕменные регистры
.DEF temp2=r23 ;--
.DEF inside_pushed=r24 ;триггер нажатия кнопки "внутр"
.DEF groupnum_port_bit=r25 ;номер группы столбца(номер бита порта) и
.DEF line_num_integer=r26 ;адрес соответствующего регистра line
.EQU safecount=255 ;количество повторений опроса для устранения дребезга
.EQU subsafecount=150 ;дополнительная задержка на каждое повторение

;-------------------------------------------------------------------------
;векторА прерывания
.org 0x00
rjmp start
rjmp start
rjmp start
rjmp start
;запрет прерываний
start: cli
;инициализация защёлок портов
; 76543210
ldi temp,0b10001111
out ddrb,temp
ldi temp,0b01111111
out ddrd,temp
;инициализация портов
; 76543210
ldi temp,0b11110000
ldi temp2,0b00001111 ;!!!
eor temp,temp2 ;!!!
ori temp,0b01110000 ;!!!***
out portb,temp
ldi temp,0b00001110
out portd,temp
;инициализация массива кнопок
8 4 2 1
ldi line1,0+0+0+1 ;line1<4,0>= 1кГц |100Гц |10Гц |1Гц
ldi line2,8+0+0+0 ;line2<4,0>= sin |1МГц |100кГц |10кГц
ldi line3,0+4+0+0 ;line3<4,1>= 0 |внут |треуг |прямоуг
ldi inside_pushed,0 ;до включения кнопка была отжата
;-----------------------------------------------------------------------
opros: ;опрос матрицы кнопок
;установить номер группы столбца =1
ldi groupnum_port_bit,0b00000001
setmask:
;задать 3-битную маску ввода для опроса 1-й кнопки текущей группы кнопок
ldi inmask,0b00010000
ldi line_num_integer,16 ;адрес line1
;--------------
curropros:
;опрос состояния текущей кнопки с защитой от дребезга
;и сохранением данных о состоянии кнопки
safeopros1:
;установить содержимое счётчика опросов равным safecount
ldi Nc,safecount

safeopros2:
;опрос сотояния текущей кнопки
in temp,pinb
andi temp,0b10000000 ;оставляем "внутр (сигн)" неизменённым
or temp,groupnum_port_bit
ldi temp2,0b00001111 ;!!!
eor temp,temp2 ;!!!
ori temp,0b01110000 ;!!!***
out portb,temp
nop ;задержка для выполнения записи в порт
nop
in temp,pinb
ldi temp2,0b01110000 ;!!!
eor temp,temp2 ;!!!
and temp,inmask ;temp - состояние кнопки (bool)
;проверка: состояние кнопки изменилось?
mov r30,line_num_integer
ld temp1,z
and temp1,groupnum_port_bit ;temp1 - старое сотояние (бит из массива)
;проверка temp==temp1
cpi temp,0
brne safeopros4
cpi temp1,0
brne safeopros_false
rjmp safeopros_true
safeopros4:
;temp!=0
cpi temp1,0
breq safeopros_false

safeopros_true:
rjmp safeopros3 ;да: переход safeopros3
safeopros_false:
ld temp2,z ;нет: установить значение предыдущего
eor temp2,groupnum_port_bit ;состояния равным текущему(инверт)
st z,temp2
rjmp safeopros1 ;переход safeopros1
safeopros3:
;задержка перед уменьшением содержимого счётчика опросов
ldi temp2,subsafecount
safeopros5:
dec temp2
brne safeopros5
;уменьшить содержимое счётчика опросов на 1
dec Nc
;проверка:содержимое счётчика стало равным нулю?
brne safeopros2 ;нет: переход safeopros2
;да: данные о состоянии кнопки сохранены, дребезга нет

;задать значение 3-битной маски ввода для опроса
;следующей кнопки текущей группы
;проверка:маска ввода настроена на последнюю (3)кнопку группы?
cpi inmask,0b01000000
breq endgroup ;да: переход endgroup
lsl inmask ;нет: задать значение 3-битной маски ввода ля опроса
inc line_num_integer ;следующей кнопки текущей группы (сдвинуть влево)
rjmp curropros
endgroup:
;проверка: проверена последняя группа (4-я)?
cpi groupnum_port_bit,0b00001000
breq setsignals ;да: переход setsignals
lsl groupnum_port_bit ;нет: "увеличить на 1" содержимое счётчика групп
rjmp setmask
;--------------------------------
setsignals:
;выставить выходные сигналы в выходном порту
;в соответствии с состоянием клавиатуры
...
...
...
end_of_set:
;переход opros
rjmp opros


Возможно вы заметите некоторую нелогичность - в массиве нажатая кнопка - это 1, отпущ
енная - 0, хотя должно, вроде бы быть наоборот. Это связано с моей ошибкой при разработке - программа была написаны для входов, подтянутых к нулю (тогда ещё использовались внешние резисторы).
Когда программа заработала правильно, я стал подключать внутренние резисторы. Обратите внимание на строки, отмеченные ";!!!***":


ori temp,0b01110000 ;!!!***


Так перед выводом регистра temp в порт B обеспечивается постоянное подключение внутренних резисторов.
Но, убрав внешние резисторы, я получил фигню. Позже выяснилось, что у AT90S1200 внутренние резисторы притянуты к 1...
Т.к. при притяжке к нулю столбцы включаются единицей, то при притяжке к нулю были вставлены строки, отмеченные ";!!!":

	;инициализация портов

...
ldi temp2,0b00001111 ;!!!
eor temp,temp2 ;!!!

...
...
ldi temp2,0b00001111 ;!!!
eor temp,temp2 ;!!!
ori temp,0b01110000 ;!!!***
out portb,temp
nop ;задержка для выполнения записи в порт
nop
in temp,pinb
ldi temp2,0b01110000 ;!!!
eor temp,temp2 ;!!!


Таким образом перед выводом в порт четыре бита для включения столбцов
инвертировались, а при чтении из порта инвертировались три бита линеек - и старая теперь программа работала правильно.
То есть изменения программы минимальны, что, несомненно, радует ленивого программиста :) .
Комментарии к коду. Всего в AT90S1200 тридцать два регистра общего назначения (РОН). В качестве "переменных" (написано в кавычках, т.к. название не совсем применимо к регистрам) выбраны регистры с r16 по r31, так как их можно загружать непосредственно, тогда как остальные - только через аккумулятор W. Им присваиваем понятные нам идентификаторы.
В младших тетрадах line1, line2 и line3 расположен массив битов (соответственно для трёх линеек). Инициализация массива кнопок - по весАм битов. Назначение битов:


весА битов|___8__|__4_____|__2_______|__1_____
___________________________________________
line1<4,0>_|_1кГц_|_100Гц_|__10Гц___|_1Гц____
line2<4,0>_|_sin___|_1МГц_|__100кГц_|_10кГц__
line3<4,0>_|_0____|_внут__|___треуг__|_прямоуг


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

1) опрос клавы с защитой от дребезга
2) установка выходных сигналов (бит 7 порта B и весь порт D)
3) переход к 1)

Nc - счётчик повторений опроса. Регистр groupnum_port_bit ("номер" активного столбца) содержит бит-указатель на выходной бит порта активного столбца и одновременно на соотв. бит регистра активной линейки. Регистр inmask ("номер" активной линейки) содержит бит-маску для входного бита активной линейки. Регистр line_num_integer в некотором смысле дублирует inmask и содержит адрес регистра активной линейки для доступа по косвенной адресации. Вот некий эквивалент опроса на C++


bool prev; //этой переменной в проге на ассемблере нет
for(Nc=255; Nc; Nc--)
{
for(groupnum_port_bit=0; groupnum_port_bit<4; groupnum_port_bit++)
{
for(inmask=0; inmask<3; inmask++)
{
prev=line123[inmask *4+ groupnum_port_bit];
if (prev== line123[inmask *4+ groupnum_port_bit]= клава[inmask *4+ groupnum_port_bit] )
Nc=255;
}
}
}
// здесь установка сигналов.
// далее цикл замыкается


Автор: Алексей1153
Источник: www.realcoding.net

 
фреон 22
 
Интересное в сети
10 новых программ
CodeLobster PHP Edition 3.7.2
WinToFlash 0.7.0008
Free Video to Flash Converter 4.7.24
Total Commander v7.55
aTunes 2.0.1
Process Explorer v12.04
Backup42 v3.0
Predator 2.0.1
FastStone Image Viewer 4.1
Process Lasso 3.70.4
FastStone Image Viewer 4.0
Xion Audio Player 1.0.125
Notepad GNU v.2.2.8.7.7
K-Lite Codec Pack 5.3.0 Full

Наши сервисы
Рассылка новостей. Подпишитесь на рассылку сейчас и вы всегда будете в курсе последних событий в мире информационных технологий.
Новостные информеры. Поставьте наши информеры к себе и у вас на сайте появится дополнительный постоянно обновляемый раздел.
Добавление статей. Если вы являетесь автором статьи или обзора на тему ИТ присылайте материал нам, мы с удовольствием опубликуем его у себя на сайте.
Реклама на сайте. Размещая рекламу у нас, вы получите новых посетителей, которые могут стать вашими клиентами.
 
Это интересно
 

Copyright © CompDoc.Ru
При цитировании и перепечатке ссылка на www.compdoc.ru обязательна. Карта сайта.
 
Rambler's Top100