[ главная ]   [ рейтинг статей ]   [ справочник радиолюбителя ]   [ новости мира ИТ ]



Ответов: 0
25-02-12 07:01







   Web - программирование
PHP


ASP






XML



CSS

SSI





   Программирование под ОС











   Web - технологии








   Базы Данных









   Графика






Данные




Программирование под ОС / Assembler /

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

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

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

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




Комментарии

 Ваш комментарий к данному материалу будет интересен нам и нашим читателям!



Последние статьи: Программирование под ОС / Assembler /

Первая программа на linux
23-05-2010   

Ассемблер, который я буду использовать - NASM (Netwide Assembler, nasm.2y.net). Этот выбор объясняется тем, что: Во первых, он мультиплатформенный, т.е. для портирования программы на разные ОС достаточно только изменить код взаимодействия с системой, а всю программу переписывать не нужно... подробнее

Кол. просмотров: общее - 3884 сегодня - 0

Использование пакета NuMega Driver Studio для написания WDM - драйверов устройств
17-05-2010   

Разработка WDM - драйвера с использованием только DDK является сложной и трудоемкой задачей. При этом приходится выполнять много однотипных операций: создание скелета драйвера, написание inf - файла для его установки, создание приложения для тестирования и т.п... подробнее

Кол. просмотров: общее - 3580 сегодня - 1

Система классов DriverWorks
17-05-2010   

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

Кол. просмотров: общее - 3577 сегодня - 0

Объект устройства device object
17-05-2010   

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

Кол. просмотров: общее - 3627 сегодня - 1

Объекты для управления оборудованием
17-05-2010   

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

Кол. просмотров: общее - 3821 сегодня - 1



  WWW.COMPROG.RU - 2009-2012 | Designed and Powered by Zaipov Renat | Projects