close

Вход

Забыли?

вход по аккаунту

?

Текст.Лабор-я раб.№3

код для вставкиСкачать
1. Интерактивные устройства ввода
1.1. Основные определения
Американский стандартный код для обмена информацией (код ASCII, American Standart Code for Information Interchange)- стандартный код, в котором буквам, числам, управляющим символам и т.д. присваиваются соответствующие числовые значения.
Стандарт ASCII содержит лишь 128 символов, 7-разрядные коды которых обозначаются 0-127. В ПК обычно используется вдвое больше символов. Поэтому в настоящее время программистами принято считать стандартные коды 0-127 и 128-255 8-разрядными кодами ASCII.
Стандартные коды ASCII (0-127) состоят из двух частей. Первая часть включает 32 символа с кодами 0-31, которые используются для управления периферийными устройствами и не выводятся на экран дисплея. Например, для управления устройством печати используется код 13 (возврат каретки), код 10 (перевод строки), код 12 (перевод страницы) и т.д.
Вторая часть содержит коды 32-127, соответствующие буквам алфавита, цифрам и знакам препинания. Причем, для одинаковых букв верхнего и нижнего регистра соотносятся разные коды (например, букве В соответствует код 66, а букве b - код 98).
Расширенные коды ASCII - дополнительные коды от 128 до 255, которыми обозначены специальные (иностранные, научные и графические) символы. К группе иностранных символов (коды 128-154 и 160-167) относятся символы, применяемые в европейских языках, символы изображения знаков валюты разных стран и символы знаков пунктуации.
Символ - цифровое представление буквы, числа или какого-либо знака.
Скэн-код (Scan code) - порядковый номер клавиши, код которого генерируется при нажатии или отпускании клавиши клавиатуры. Прерывание клавиатуры вызывает преобразование скэн- кодов в коды ASCII или расширенные коды.
Формат скэн- кода содержит одинаковые по длительности: стартовый бит, байт данных, бит паритета и один стоповый бит.
Стартовый бит - нулевой бит, предшествующий последовательной передаче байта данных, указывает на прерывание маркерного единичного промежуточного состояния линии, устанавливаемое между передачами данных. Стартовый бит используется на приёмной стороне для запуска его синхронизатора.
Стоповый бит - бит завершения последовательной передачи формата скэн- кода, переводящий линию в единичное маркерное состояние. После стопового бита может быть возобновлена передача стартового бита очередного скэн- кода.
Бит паритета (чётности) - дополнительный бит, добавляемый к байту данных для обнаружения возможных ошибок.
Буфер клавиатуры - область памяти, отводимая для хранения и организации циклической очереди, в которую по прерыванию клавиатуры помещаются коды ASCII клавиш и их скэн- коды.
Код нажатия - тип скэн- кода, формируемый при нажатии клавиши.
Код отпускания - тип скэн- кода, генерируемый при отпускании клавиши.
Прерывание клавиатуры - аппаратное прерывание, формируемое при нажатии или отпускании клавиши. По прерыванию вызывается обработчик прерывания (драйвер), который помещает скэн- коды и соответствующие им коды ASCII в буфер клавиатуры.
Частота автоповтора - скорость повторной передачи последовательного кода при удержании нажатой клавиши.
1.2. Типы клавиш
Клавиатура РС/ХТ имеет 83 клавиши. Клавиатура АТ содержит 84 клавиши. Ее основное отличие от клавиатуры РС то, что она стала доступной со стороны системного процессора. Это техническое усовершенствование делает клавиатуру АТ несовместимой с клавиатурой РС, хотя и используются одни и те же разъемы.
Кроме того, фирма IBM изготавливает улучшенную клавиатуру, количество клавиш которой равно 101 (102). Эта клавиатура является модернизацией клавиатуры АТ, но также остается несовместимой с клавиатурой РС/ХТ. В улучшенной клавиатуре используется другое размещение клавиш.
Каждая клавиша имеет порядковый номер, и при ее нажатии клавиатурой генерируется однобайтное число, называемое скэн-кодом и соответствующее номеру клавиши. Например, в клавиатуре РС клавиша Esc имеет номер 1, клавиша цифры 1 - номер 2, ..., клавиша Del - номер 83.
Всю совокупность клавиш можно разделить на два типа. Клавишам первого типа после преобразования скэн-кодов соответствуют коды ASCII (клавиши ASCII), а клавишам второго типа - расширенные коды (специальные клавиши и их комбинации).
При одновременном нажатии клавиш Alt+F1 генерируется 2-байтный расширенный код 0:104. Младший байт расширенного кода всегда содержит нуль, а старший байт - скэн-код (код сканирования) клавиши. Каждой клавише (комбинации клавиш) поставлен в соответствие номер, по которому формируется скэн-код. Например, клавиша F1 имеет номер 59 и ей соответствует расширенный код 0:59. Функциональные клавиши наиболее часто используются командами операционной системы.
Каждая клавиша содержит переключатель, который может быть механического (мембранного) типа или бесконтактного типа. В механических (контактного типа) клавишах возникает эффект дребезга контакта, требующий своего устранения. В бесконтактных клавишах используется емкостная или индуктивная технология. При нажатии клавиши в емкостной клавиатуре изменяется емкость этой клавиши. Допустим, в отпущенном состоянии емкость равна 20-24 пФ, а при нажатии уменьшается до 2-6 пФ. Изменение емкости вызывает поток заряда в цепях, связанных с клавишей. В клавиатуре, использующей индуктивный принцип, каждая клавиша содержит индуктивный датчик, работа которого заключается в следующем. При нажатии клавиши подвижная часть датчика (металлическая пластина) приближается к неподвижной части (индуктивности), выполненной печатным монтажом, и вызывает изменение индуктивности, в результате чего формируется сигнал срабатывания датчика. Возвращение клавиши в исходное состояние выполняется с помощью пружины.
1.3. Клавиатура PC/XT
Информация, вводимая с клавиатуры при нажатии клавиши, подвергается нескольким преобразованиям до получения ее соответствующей программой. Рассмотрим вопросы ввода, синхронизации и преобразования информации клавиш на программном и аппаратном уровнях.
При нажатии или отпускании клавиши клавиатурой формируется и передается байтный код, называемый скэн-кодом. В скэн-коде нажатия 7 разряд равен 0, а в скэн-коде отпускания 7 разряд равен 1. Младшие 7 бит (разряды 0-6) скэн-кода определяют номер, присвоенный каждой клавише. Клавиша символа А имеет порядковый номер 30 (16-ричное значение 1Е), поэтому скэн-код нажатия этой клавиши равен 00011110, а скэн-код отпускания - 10011110. В ПК IBM AT принят другой формат представления скэн-кода клавиши. Если клавиша выполняет отжатие, то перед скэн-кодом передается код F0H. Рассмотрим принцип работы клавиатуры РС/ХТ.
Из клавиатуры скэн-код клавиши выводится последовательным кодом в адаптер клавиатуры, который преобразует его в параллельный код и передает в порт А (адрес 60Н, где Н - 16-ричное значение) микросхемы Intel 8255 (КР580 ВВ55), содержащей три порта: А, В и С. Одновременно с передачей кода в порт А адаптер клавиатуры формирует сигнал прерывания IRQ1 (второй по приоритетности сигнал прерывания), поступающий в программируемый контроллер прерывания, в микросхему Intel 8259 (КР1810 ВН59А). Наивысший по приоритету сигнал прерывания IRQ0 формирует таймер, чтобы сохранить верными показания системных часов.
Контроллер прерывания передает в процессор код типа (номера) прерывания (прерывание 9, прерывание от клавиатуры), который вызывает программу обработки прерывания (драйвер), выполняющий чтение скэн-кода из порта А, чтобы определить, какая клавиша нажата (отпущена). Каждому прерыванию (внешнему или внутреннему) поставлено в соответствие число (номер прерывания), например, прерыванию от клавиатуры - 9, для управления устройством печати - 15 и так далее. Кроме того, любому прерыванию соответствуют два слова (ячейки) памяти, в которых хранится вектор прерывания. В первом слове хранится значение IP (указателя команды), а во втором - CS (сегмент кода), определяющие адрес программы, обслуживающей прерывание. Чтобы найти место вектора прерывания в памяти, необходимо номер прерывания умножить на 4, так как под каждый вектор отводится 4 байта. Например, для прерывания 9 вектор имеет адрес 9´4=36 (0024Н). Таким образом, стартовый адрес подпрограммы обработки прерывания от клавиатуры хранится в двух ячейках памяти, адрес первой из которых - 0024Н.
Из подпрограммы обработки прерывания скэн-код передается в ROM-BIOS (базовую систему ввода-вывода), в которой подпрограммы, обслуживающие клавиатуру, переводят его в 2-байтный код. Для клавиш первого типа (клавиш ASCII) младший байт 2-байтного кода содержит код ASCII, а старший - скэн-код нажатой клавиши (скэн-код отжатой клавиши отбрасывается). Например, клавише Р, порядковый номер которой 25, 2-байтный код равен 80:25, где 80 - код ASCII символа Р, а 25 - скэн-код клавиши Р. Специальным клавишам второго типа (комбинациям клавиш) соответствуют 2-байтные расширенные коды. Например, клавише Del, порядковый номер которой 83, соответствует 2-байтный расширенный код 0:83, где 83 - скэн-код клавиши Del. При преобразовании скэн-кода решается задача нахождения соответствующего ему кода ASCII или расширенного кода. Задача поиска кода ASCII решается с помощью таблицы, размещенной в сегменте данных. Если скэн-код был равен 32, то из 256-байтной таблицы берется байт номер 32, равный 68 (44Н) и соответствующий D.
Затем подпрограммы ROM-BIOS помещают 2-байтный код в буфер клавиатуры (область памяти с младшими адресами 0000:041Е), имеющий емкость до 15 вводимых символов. В буфере коды ожидают своей очереди, пока не будут запрошены программой, ожидающей ввода информации с клавиатуры.
Перевод (трансляция) скэн-кода выполняется не для всех клавиш. При поступлении скэн-кодов от клавиш регистров Shift, Alt, Ctrl и клавиш переключателей (Caps Lock, Scroll Lock, Num Lock) в байты памяти с адресами 417Н и 418Н записывается информация о состоянии этих клавиш. Например, в байте состояния с адресом 417Н, если разряд 3 равен 1, это указывает на активное состояние клавиши Alt (клавиша нажата). Если разряд 3 равен 0, то это соответствует неактивному (отжатому) состоянию клавиши Alt.
При поступлении скэн-кода ROM-BIOS сначала анализирует состояние клавиш регистров и переключателей, чтобы определить код а или А, и только после этого код символов помещается в буфер клавиатуры.
Кроме того, ROM-BIOS при трансляции скэн-кодов проверяет их на различные комбинации клавиш переключателей и регистров, например, Ctrl-Alt-Del, Ctrl-Num Lock и Shift-Prt Sc.
Эти клавишные наборы заставляют ROM-BIOS выполнить определенные действия без записи скэн-кодов в буфер клавиатуры. Так, комбинация Ctrl-Alt-Del, как известно, выполняет перезагрузку DOS, комбинация Ctrl-Num Lock - приостановку работы программы (фиксация клавиатуры) до тех пор, пока не будет нажата клавиша с печатаемым символом, комбинация Shift-Prt Sc выводит содержимое экрана на устройство печати. Если клавиша нажата больше полсекунды, то клавиатура, следящая за длительностью нажатия, с частотой 10 раз в секунду, генерирует скэн-код нажатия этой клавиши без промежуточных скэн-кодов отжатия, что позволяет упростить драйвер, который распознает разницу между нажатием и автоматическим повторением. Если, например, клавиша С удерживается долго, то ROM-BIOS формирует серию символов С, которые будут переданы программе. С другой стороны, если удерживается долго клавиша регистра, то ROM-BIOS анализирует только первый скэн-код этой клавиши, а все остальные коды она игнорирует.
Клавиатура имеет много повторяющихся клавиш: две клавиши Shift, по две цифры, два плюса (минуса), две точки и т.д.
Скэн-коды повторяющихся клавиш разные, но ROM-BIOS транслирует их (скэн-коды) в одни и те же коды ASCII, и для их различия в старшем (вспомогательном) байте сохраняется значение скэн-кода. Только для клавиш Shift в байте состояния с адресом 417Н отмечается в разряде 1 состояние левой клавиши Shift, а в разряде 0 - состояние правой клавиши Shift. На рис. 1.1 показана схема связи клавиатуры и процессора.
Рис. 1.1. Схема связи клавиатуры и процессора
Клавиатура содержит контроллер i8048, представляющий собой однокристальную микроЭВМ, в состав которой входят внутренние ОЗУ емкостью 64 байта, 8-разрядное АЛУ, ППЗУ и три 8-разрядных порта с тремя состояниями. Перед установкой в клавиатуру микроЭВМ программируется и обеспечивает: управление схемой опроса матрицы клавиш, прием и анализ состояния опрашиваемой клавиши, устранение эффекта дребезга контактов, буферизацию кодов клавиш, выполнение протокола связи; осуществление автотестирования матрицы клавиш с целью обнаружения залипших клавиш и контроля ОЗУ. В ПК АТ используют другой контроллер i8042, который выполняет почти те же функции, что и контроллер ПК РС/ХТ.
В работе схемы (см. рис. 1.1) можно выделить следующие основные моменты (цифры показывают последовательность действий в схеме).
Процессор осуществляет прием скэн-кода и после этого производит сброс регистра адаптера клавиатуры и сигнала прерывания IRQ1. Этот сброс процессор выполняет с помощью разряда 7 порта В (B[7]=1) микросхемы 8255 (580 ВВ55), называемой иногда трехканальным портом. Процессор сначала устанавливает B[7]=1, а затем сбрасывает этот разряд B[7]=0 (разрешает работу адаптера клавиатуры). Порт В имеет адрес 061h. Кроме того, процессор через разряд 6 порта В (B[6]=1) разрешает формирование сигналов синхронизации со стороны клавиатуры.
Процессор выполняет по таблице преобразование скэн-кода в 2-байтный код с кодом ASCII или расширенным кодом или установку соответствующих бит в байтах состояния для клавиш регистров и переключателей. Процессор записывает 2-байтный код клавиши в буфер клавиатуры, если имеется свободное место.
Между прерываниями клавиатуры процессор может выполнять десятки тысяч команд, так что прерывания не отнимают у него слишком много времени. Хорошая машинистка способна вводить до 400 символов в минуту, т.е. через каждые 150 мс процессор должен успевать считывать и запоминать символ. Благодаря механизму прерывания, процессор выполняет чтение скэн-кода из регистра адаптера за 10 мкс, а в оставшееся от 150 мс время он осуществляет другие действия.
В клавиатуре ПК РС/АТ управление ее работой выполняется через порт ввода-вывода (64Н или 60Н), предназначенный для вывода команд и данных и для чтения состояния клавиатуры. Приведем некоторые команды контроллера клавиатуры: сброс и запуск теста (0FFН), привести клавиатуру в исходное состояние и разрешить сканирование (0F6Н), запись в порт вывода (0D1Н), чтение порта ввода (0С0Н) и так далее.
1.4. Клавиатура PC/AT
Клавиатура является основным устройством ввода алфавитно-цифровых и управляющих данных, необходимых для функционирования ПК. Известны несколько типов клавиатур с различными функциональными возможностями. Например, 83-клавишная клавиатура РС/ХТ, реализованная на базе контроллера 8048, имеет ограниченные средства по диагностике и обнаружению ошибок. В РС/АТ 84-клавишная клавиатура использует микросхему 8042 с расширенными функциями. Эта клавиатура характеризуется другим расположением отдельных клавиш, наличием программного доступа и дополнительных средств по обнаружению и анализу ошибок. Расширенная 101-клавишная клавиатура использует также микросхему I8042 и употребляется в ПК РС/АТ и PS/2. Дальше будет рассматриваться только 101(102)-клавишная клавиатура.
На рис. 1.2 изображена схема связи клавиатуры и контроллера (I8042), размещенного на системной плате.
Рис. 1.2. Схема связи клавиатуры и контроллера
Клавиатура подключена к контроллеру системной платы 4-проводным экранированным кабелем. Два двунаправленных провода предназначены для передачи синхросигналов (CLK) и данных (DATA). Третий провод является сигнальным заземлением (GND), а четвертый - линией питания (5В).
По линии DATA передаются данные в виде последовательных кодовых посылок (команды, параметры, коды нажатия и отжатия, коды подтверждения), причем каждый бит данных сопровождается битом синхронизации по линии CLK.
Для управления работой клавиатуры контроллер посылает по линии DATA команды (установки и сброса индикаторов состояния, прочитать индикатор задания частоты повтора клавиши и т.д.). Клавиатура после приема команды отвечает кодом подтверждения, т.е. обмен осуществляется по принципу запрос-ответ. Если после команды со стороны контроллера поступает параметр, то клавиатура также устанавливает код подтверждения. Аналогичным образом клавиатура передает в контроллер по линии DATA код нажатия (отжатия) клавиши с обратным получением кода подтверждения. Обмен данными между клавиатурой (контроллером) и системным процессором выполняется в режимах прерывания (IRQ1) и опроса битов готовности, размещенных в байте по адресу 0040:0097h, в котором значение 10h означает полученное подтверждение, а значение 20h - повторение передачи.
Расширенная клавиатура имеет 3 режима работы, каждый из которых устанавливается с помощью соответствующих команд. Режим 1 задается командой F0h с байтом конфигурации (параметром) 01h. В этом режиме используются 9-битовые коды нажатия (отжатия) клавиш клавиатуры PC/XT, которые не требуют преобразования и используются непосредственно процедурой INT 16h BIOS c функциями 00h, 01h и 02h.
Режим 2 устанавливается по умолчанию и употребляет 11-битовые последовательные кодовые посылки нажатия (отжатия), которые преобразуются контроллером в корды, необходимые BIOS. Для обработки данных новых клавиш, которых нет в клавиатуре PC/XT, следует использовать функции 10h, 11h и 12h процедуры INT 16h BIOS. Режим 3 использует специальные коды клавиш, которые могут быть преобразованы только прикладными программами. Этот режим устанавливается командой F0h с байтом конфигурации 3.
Конструктивно клавиатура выполнена в виде отдельного устройства, содержащего набор клавиш, матрицу переключателей клавиш, микропроцессор (МП), буфер (FIFO) на 17 байтов, генератор синхросигналов (ГС), индикацию и интерфейс связи с контроллером (I8042), размещенных на системной плате (рис. 1.3).
Рис. 1.3. Структурная схема клавиатуры
Данные в режиме 2 передаются по линии DATA 11-битной последовательной кодовой посылкой, имеющей стартстопный формат, причем каждый бит данных сопровождается синхросигналом на линии CLK. В кодовой посылке 1 бит является стартовым, затем следует 8 битов данных, которые замыкают биты паритета (нечет) и стоповый (рис. 1.4).
Рис. 1.4. Формат 11-битовой кодовой посылки данных
В режиме 1 используется 9-битовая кодовая посылка без битов паритета и стопового, а стартовый бит равен 1.
Если клавиша нажата, то клавиатура передает в контроллер скэн-код этой клавиши. Скэн-код - это порядковый номер нажатой клавиши. Кроме того, клавиатура выводит этот же скэн-код при отпускании клавиши, но предварительно передается код F0h.
Кроме того, если клавиша удерживается нажатой, то клавиатура генерирует скэн-код с программируемой скоростью и задержкой повторения.
Микропроцессор (МП) клавиатуры (I8042) выполняет следующие основные функции:
- автотестирование матрицы переключателей клавиш, внутренних ПЗУ и ОЗУ с передачей кода ААh в системную плату при успешном результате или кода FCh - в случае ошибки;
- опрос состояний DATA и CLK, чтобы определить отсутствие запрета;
- сканирование переключателей клавиш с целью установления факта нажатия или отпускания какой либо клавиши;
- выбор таблицы скэн-кодов;
- реализацию протокола связи с контроллером;
- буферизацию кодов клавиш;
- формирование последовательных кодовых посылок при нажатии или отпускании клавиш;
- задание частоты повтора кода клавиши.
Буфер FIFO ("первый вошел - первый ушел") предназначен для временного хранения кодов нажатия и отжатия до принятия их контроллером. При переполнении буфера в его фиксированную ячейку помещается код FFh в режиме 1 или код 00h - в режимах 2 и 3, и очередной скэн-код в этом случае не выводится. Светодиоды индикации отображают состояние, например, включения клавиш Num Lock (блокировки цифр), Caps Lock (блокировки прописных букв) или Scroll Lock (блокировки прокрутки). Генератор синхросигналов используется для синхронизации работы МП клавиатуры. Клавишам соответствует определенный тип переключателя. Различают механические переключатели, электрические, использующие эффект Холла, индуктивные, сенсорные, емкостные и мембранного типа. Переключатели представлены в виде матрицы, которую МП последовательно опрашивает с целью обнаружения нажатия какой либо клавиши. На рис. 9.5 показана схема взаимодействия компонентов, связанных с обработкой клавиатурных данных. Клавиатура имеет собственное программное обеспечение, выполняющее перечисленные выше функции МП. При выводе данных клавиатура опрашивает состояние линий DATA и CLK с открытым коллектором. Если на линии CLK установлен контроллером запрещающий низкий уровень, то данные, например, коды нажатия, не передаются в контроллер, а посылаются в буфер FIFO на временное хранение (см. рис. 1.3). Коды нажатия (отжатия) из буфера FIFO посылаются в контроллер при возникновении на линии CLK высокого разрешающего уровня напряжения.
Рис. 1.5. Схема взаимодействия компонентов ПК
Так достигается согласование во времени работы клавиатуры и контроллера, связанной с обменом данными. Если данные клавиатуры получены с ошибкой паритета, то контроллер автоматически посылает команду RESEND (повторить). В свою очередь, когда контроллер готов к передаче данных в клавиатуру, он устанавливает на линии DATA низкий уровень стартового бита и разрешает (увеличением уровня напряжения) формирование синхросигналов CLK со стороны клавиатуры.
При включении питания или поступлении команды контроллера FFh (сброс) клавиатура выполняет базовый тест, связанный с проверкой переключателей клавиш, внутренних ОЗУ и ПЗУ. Если базовый тест завершен успешно, то в контроллер передается код Aah (код ответа) и осуществляется сканирование переключателей клавиш. И наоборот, в случае ошибки в контроллер выводится код FCh. Контроллер представляет собой однокристальный микрокомпьютер, взаимодействующий с процессором с помощью портов и аппаратного прерывания IRQ1. Доступ к портам выполняется по адресным сигналам А0 (младший бит адреса), (выбор кристалла) и сигналам управления (чтения порта), (запись в порт), а также с помощью команд. Передача данных между контроллером и процессором осуществляется по внутренней шине данных XD0-XD7, подключенной к системной шине данных SD0-SD7 через приемопередатчик (на см. рис. 1.5 это соединение не показано). Контроллер выполняет преобразование полученных от клавиатуры кодов нажатия (отжатия) клавиш в системные (стандартные для обработчика прерываний) скэн-коды, причем 2-байтовый код отпускания клавиши заменяется байтовым, у которого бит D7=1. Процессор устанавливает наличие в контроллере кодов нажатия (отпускания) через прерывание IRQ1, по которому определяется адрес вектора прерывания (36 или 24h, т. е. номер прерывания 9 умножается на 4), указывающий на фиксированную ячейку оперативной памяти (0000:0024), хранящую 4-байтовый вектор прерывания (стартовый адрес обработчика прерывания). Кроме того, процессор с помощью обработчика прерывания выполняет анализ системного скэн-кода нажатия и преобразование его в 2-байтовый код, помещаемый в буфер клавиатуры (FIFO) оперативной памяти (RAM). Буфер клавиатуры RAM реализует режим кольцевой очереди и может хранить 15 двухбайтовых кодов нажатия, причем для обычных клавиш (алфавитно-цифровых), которым соответствуют коды ASCII, в буфере клавиатуры отводится два байта, первый из которых является кодом ASCII, а второй - скэн-кодом (порядковым номером этой клавиши). Второй байт необходим для различения одинаковых клавиш.
При нажатии специальных клавиш, например, F1-F12, INS, DEL и т. д., которым присвоен двухбайтный расширенный код, в буфер клавиатуры RAM помещается также 2 байта, первый из которых равен 00, а второй содержит порядковый номер этой клавиши (скэн-код). Буфер клавиатуры представлен на рис. 1.6.
Рис. 1.6. Циклический буфер клавиатуры RAM
Начальный адрес буфера клавиатуры - 0040:001Е, а конечный адрес - 0040:003С. Буферу клавиатуры RAM соответствуют все 2-байтовые ячейки памяти с адресами 0040:001А и 0040:001С, первая из которых является указателем головы заносимых данных (определяет первые введенные 2 байта данных), а вторая - указателем хвоста (см. рис. 1.6). В этих ячейках обычно используется только младший байт. По мере занесения данных в сторону увеличения адреса буфера клавиатуры RAM меняется соответственно и значение указателя хвоста. После заполнения конца буфера клавиатуры данные заносятся в его начальные ячейки памяти, если они были удалены при чтении данных из буфера клавиатуры, приводящим к изменению значения (позиции) указателя головы. В результате подобных действий значения указателя хвоста оказываются меньше значения указателя головы. Кроме того, в буфере клавиатуры используется дополнительная 2-байтовая ячейка (пустая позиция), которая содержит код возврата каретки (13) и код ввода (28) и предшествует ячейке буфера, соответствующей указателю головы.
Если значения указателей головы и хвоста равны, то буфер клавиатуры пуст. Поэтому для очистки буфера клавиатуры следует установить равные значения в указателях головы и хвоста. В том случае, если буфер клавиатуры уже заполнен, а поступают другие данные, вырабатывается звуковой сигнал переполнения. Наличие данных в буфере клавиатуры с целью их ввода можно определить по неравенству значений в указателях головы и хвоста. Состояния нажатия и отпускания переключательных клавиш Caps Lock, Num Lock, Scroll Lock, Ins, Shift и т.д. отражаются в фиксированных ячейках RAM (байтах состояния), имеющих адреса 0040:0017 и 0040:0018. Кроме того, информация о состоянии расширенной клавиатуры отмечается в ячейках с адресами 0040:0096 и 0040:0097. В этих ячейках задается состояние правых клавиш Ctrl, Alt и состояние индикаторов. При прерывании клавиатуры, если была нажата переключательная клавиша, устанавливается соответствующий бит одного из байтов состояния. Обработчик прерывания INT9h проверяет каждый раз состояние переключательных клавиш, чтобы правильно интерпретировать вводимый код клавиши, например, "С" или "с". При нажатии (отпускании) клавиши аппаратное прерывание IRQ1 вызывает обработчик прерывания INT09h, который выполняет следующие основные функции:
- сохранение содержимого регистров процессора;
- считывание и анализ номера клавиши из контроллера;
- преобразование этого номера с использованием таблиц в код ASCII и системный скэн-код;
- оповещение контроллера о завершении чтения номера клавиши;
- сбрасывание запроса в контроллере прерывания;
- передачу двухбайтного кода в буфер клавиатуры RAM;
- управление динамиком и буфером клавиатуры RAM и восстановление регистров процессора.
Кроме того, для некоторых комбинаций клавиш: Ctrl_Alt_Del (перезагрузка операционной системы), Ctrl_Break (формирование прерывания INT1Bh с установкой бита D7 в байте 0040:0071h), Alt_SysRq (вызов подфункции 85h прерывания INT15h) и т. д., выполняющих специальные функции, обработчик прерывания INT09h не использует скэн-коды в буфере клавиатуры RAM. Для других переключательных клавиш: Caps Lock, Num Lock и т. д. при их нажатии (отпускании) обработчик прерывания INT09h изменяет содержимое байтов состояния, размещенных в фиксированных ячейках RAM.
Обработчик (драйвер) программного прерывания INT16h употребляет функции:
- чтение кода нажатой клавиши (00h);
- проверка состояния буфера клавиатуры (01h);
- чтение байта состояния клавиатуры (02h);
- установка скорости повторения кода клавиши (03h);
- считывание кода нажатой клавиши (10h);
- проверка состояния буфера клавиатуры (11h);
- чтение байтов состояния клавиатуры (12h).
Функции 00h-02h предназначены для старой клавиатуры. Функция 00h по значению указателя головы удаляет 2-байтный код из буфера клавиатуры, причем первый байт (код ASCII) помещается в регистр AL, а второй байт (скэн-код) - в регистр AH процессора. Если буфер клавиатуры пуст, то функция 00h ожидает нажатия клавиши (появления 2-байтного кода) и только потом передает управление программе.
Функция 01h позволяет исключить время ожидания нажатия клавиши путем проверки нажатия 2-байтных кодов в буфере клавиатуры. Эта функция сообщает только о готовности ввода с клавиатуры (устанавливает признак ZF=1, если буфер клавиатуры пуст).
Функция 02h предназначена для чтения байта состояния клавиатуры, который помещается в регистр AL.
Формат байта состояния (0040:0017) изображен на рис. 1.7.
биты
D71- включен режим Insert
D61- включен режим Caps Lock
D51- включен режим Num Lock
D41- включен режим Scroll Lock
D31- нажата клавиша Alt
D21- нажата клавиша Ctrl
D11- нажата левая клавиша Shift
D01- нажата правая клавиша Shift
Рис. 1.7. Формат байта состояния
Функция 03h управляет задержкой и частотой (скоростью) повторения кода клавиши. Значение частоты повторения (число из диапазона 0-31) задается в регистре BL, а в регистре BH - задержка повторения (0-250 мс, 1-500 мс, ..., 3-1000 мс).
В новой клавиатуре, имеющей 101 (102) клавишу, используется функция 00h, 01h и 02h старой клавиатуры. Эта расширенная клавиатура, как уже отмечалось, применяется в ПК РС/АТ и PS/2.
Функция 10h используется вместо функции 00h, если расширенная клавиатура работает в режиме 2, что позволяет получить коды для дополнительных клавиш. Общее назначение, входные и выходные параметры функций 00h и 10h совпадают. Аналогичным образом используется функция 11h вместо 01h. Функция 12h заменяет функцию 02h, если расширенная клавиатура работает в режиме 2. При выполнении функции 12h байты состояния размещаются в регистрах AL и АН, причем в регистре AL хранится первый байт состояния (см. рис. 8.7), а в регистре АН - второй байт состояния (0040:0018), формат которого показан на рис. 1.8.
биты
D71- включен режим Insert
D61- включен режим Caps Lock
D51- включен режим Num Lock
D41- включен режим Scroll Lock
D31- включен режим "пауза"
D21- нажата клавиша Sys Req
D11- нажата правая клавиша Alt
D01- нажата правая клавиша Ctrl
Рис. 1.8. Формат второго байта состояния
Рассмотрим структурную схему контроллера, показанную на рис. 1.9.
Рис. 1.9. Структурная схема контроллера
Входной буфер подключается к шине XD0 -XD7 и содержит два 8 - битовых регистра данных и команд, доступных по записи и имеющих соответственно адреса 60h и 64h. Информация записывается во входной буфер, если сброшен бит D1 регистра состояния (64h), содержащего флаг входного буфера (IBF), который устанавливается в единицу при записи информации во входной буфер. Данные из входного буфера (регистра данных) передаются в клавиатуру и выполняется автоматический сброс IBF.
Выходной буфер включает 8-битовый регистр, адрес которого 60h. Содержимое этого регистра считывается, если бит DO регистра состояния (64h) равен единице (установлен флаг выходного буфера OBF), что указывает на наличие данных в выходном буфере (выходной буфер полон). При чтении выходного буфера бит DO (OBF) регистра состояния (64h) автоматически сбрасывается.
Читаемый регистр состояния (64h) предназначен для хранения информации о состоянии контроллера и интерфейса. Формат регистра состояния (64h) представлен на рис. 1.10.
биты
D71- ошибка нечетного паритета
D61- прием байта из клавиатуры не завершен
D51- передача байта в клавиатуру не завершена
D40- клавиатура заблокирована (защитный замок закрыт)
D30- в выходном буфере данные
1- в выходном буфере команда
D20- сброс по включению питания
1- программный сброс
D10- входной буфер пуст (IBF)
D01- выходной буфер полон (OBF)
Рис. 1.10. Формат регистра состояния
Доступ к другим портам контроллера выполняется с помощью специальных команд, так как из-за ограниченного числа контактов микросхемы I8042 они не имеют адресов. Команды C0h(R), D0h(R), D1h(W), и Е0h(R) (см. рис. 9.9) используются соответственно для чтения входного и выходного портов, записи в выходной порт и чтение порта Т0, Т1 (чтение состояния линий CLK и DATA интерфейса клавиатуры). Эти команды должны быть переданы в регистр команд входного буфера по адресу 64h.
Входной порт контроллера предназначен для чтения информации о конфигурации системы, используемой программами BIOC. Формат входного порта показан на рис. 1.11.
биты
D70- клавиатура заблокирована ключом
D60- цветной адаптер
1- монохромный адаптер
D50- переключатель установлен
- переключатель не установлен
D40- не используются вторые 256К RAM
- используются вторые 256К RAM
D3, D2,D1, D0- резерв
Рис. 1.11. Формат входного порта
Выходной порт доступен по записи (W) и чтению (R) и хранит значения выходных линий. Формат выходного порта представлен на рис. 1.12.
биты
D7- значение линии DATA при передаче данных в клавиатуру
D6- значение линии CLK при передаче данных в клавиатуру
D51- входной буфер пуст
D41- выходной буфер полон
D3, D2- резерв
D1- состояние адресной линии А20
D00- системный сброс
Рис. 1.12. Формат выходного порта
Значения порта состояния линий Т0 и Т1 считываются командой E0h(R), причем бит Т0 соответствует входному значению линии CLK, а бит Т1 - входному значению линии DATA.
Кроме того, контроллер содержит управляющий байт, доступный по чтению с помощью команды 20h(R) и по записи с использованием команды 60h(W). Для считывания управляющего байта необходимо вначале записать команду 20h(R) в регистр команды (64h), а затем получить управляющий байт из выходного буфера (60h). Запись управляющего байта выполняется следующим образом. Предварительно в регистр команд (64h) входного буфера заносится команда 60h(W), а после этого содержимое управляющего байта - в регистр данных (60h) входного буфера. Формат управляющего байта изображен на рис. 1.13.
биты
D70- резерв
D61- режим совместимости клавиатуры с IBM PC
(вызывает преобразование 2-байтовых кодов отпускания в 1-байтовые)
D51- используются коды клавиатуры IBM PC/XT
0- используются 2-битовые коды АТ
D41- отключение клавиатуры
0- разрешение
D31- запрещается защитный замок
D2- значение этого бита записывается в бит D2 регистра состояния
D10- резерв
D01- разрешение прерывания, если выходной буфер полон
Рис. 1.13. Формат управляющего байта
Различают команды контроллера (некоторые из них были уже рассмотрены: C0h(R), D0h(R), D1h(W) и т.д.), команды управления клавиатурой и коды ответов клавиатуры.
Команда контроллера выводится процессором в регистр команд (64h) входного буфера и если у команды есть байт данных, то он загружается сразу после команды в регистр данных (60h) входного буфера.
Команды контроллера приведены в табл. 1.1.
Таблица 1.1.
КодНазначение команды20h Чтение управляющего байта60h Запись управляющего байтаAAh Выполнение внутреннего тестаABh Тест интерфейсаADh Отключение (блокировка) клавиатурыAEh Разрешение (деблокирование) клавиатурыC0h Чтение входного портаD0h Чтение выходного портаD1h Запись в выходной портE0h Чтение порта Т0, Т1F0h - FFh Сброс выходного порта Рассмотрим назначение команд контроллера. Команда ААh вызывает выполнение внутреннего теста контроллера. Если тест завершается успешно, то в выходной буфер (60h) помещается код 55h. Тест интерфейса (линий CLK и DATA) осуществляется командой AВh и в выходном буфере хранится результат тестирования (00 - ошибок нет, 01(03) - линия CLK(DATA) имеет нулевой уровень, 02(04) - на линии CLK(DATA) установлен высокий уровень. По команде ADh производится отключение клавиатуры (данные не передаются и не принимаются), а по команде AЕh - разрешается работа клавиатуры (сбрасывается бит D4 управляющего байта). Команда C0h осуществляет чтение входного порта и занесение его содержимого в выходной буфер (60h). Предварительно следует убедиться, что выходной буфер пуст, т.е. проверить бит D0(0BF) регистра состояния (64h). Чтение выходного порта исполняется командой D0h, которая помещает его содержимое в выходной буфер, если он пуст. Запись в выходной порт выполняется по команде D1h, за которой следует вывести байт по адресу 60h регистра данных, причем бит 0 выходного порта не должен быть равным нулю, иначе будет системный сброс. Для считывания значений порта Т0 и Т1 (значений входных линий CLK и DATA) в выходной буфер употребляется команда E0h. Команды F0h - FFh указывают своим кодом, какие четыре младших бита выходного порта следует сбросить, причем значение 0 определяет сброс бита.
Команды управления клавиатурой выводятся системным процессором как данные в регистр данных (60h) входного буфера контроллера, откуда передаются затем в клавиатуру. Клавиатура обязательно подтверждает прием команды управления, кроме команд EEh и FEh.
Команды управления клавиатурой представлены в табл. 1.2.
Таблица 1.2.
КодНазначение командыEDh Установить индикаторы состоянияEEh Эхо (диагностика)F0h Установка таблицы скэн-кодовFFh, F1h Холостые (недействительные) командыF2h Чтение идентификатораF3h Задание частоты повтора и задержкиF4h Разрешение клавиатурыF5h Блокировка клавиатурыF6h Установка значения по умолчаниюF7h, FAh Определение действий всех клавишFBh, FDh Определение действий отдельных клавишFEh Повторить передачуFFh Сброс клавиатуры Команда "установить индикатор состояния" (EDh) является 2-байтовой командой, изменяющей состояние индикаторов клавиатуры.
Первый байт (EDh) поступает в клавиатуру, которая прекращает сканирование переключателей клавиш, передает код подтверждения приема (FAh) и ожидает поступления второго байта конфигурации параметра, задающего установку индикатора. Второй байт имеет формат, изображенный на рис. 1.14.
Клавиатура, получив второй байт, подтверждает его прием ответным кодом FAh, устанавливает индикаторы и начинает сканирование переключателей клавиш. Диагностическая команда эхо (EEh) вызывает обратную передачу клавиатурой этого же кода EEh.
биты
D7-D30- резерв
D21- включен индикатор Caps Lock
D11- включен индикатор Num Lock
D01- включен индикатор Scroll Lock
Рис. 1.14. Формат второго байта
При получении клавиатурой одной из холостых команд EFh или F1h, она направляет в контроллер "код повтора" (FEh).
В клавиатуре хранятся таблицы кодов клавиш различных режимов. Для выбора одной из трех таблиц в клавиатуру посылается 2-байтная команда. Первый байт F0h указывает на соответствующую операцию и настраивает клавиатуру на прием второго байта. Клавиатура отвечает кодом подтверждения ( FAh), принимает второй байт, содержащий одно из трех значений 01, 02 или 03 для выбора набора кодов клавиш. Если второй байт имеет код 00, то клавиатура отвечает кодом подтверждения(FAh) и посылает байт, указывающий на текущий режим (номер таблицы кодов клавиш). Команда "чтение идентификатора" (F2h) поступает в клавиатуру и вызывает последовательную ответную передачу кода подтверждения (FAh) и двух байтов идентификатора (83AВh).
Задание частоты повтора кода клавиши и времени задержки после первой передачи кода клавиши осуществляется 2-байтной командой F3h. Клавиатура, получив эту команду (первый байт), прекращает сканирование переключателей клавиш, отвечает кодом подтверждения (FAh) и ожидает поступление второго байта с заданными параметрами. Для продолжения сканирования переключателей клавиш в клавиатуру передается команда F4h (разрешение клавиатуры), получение которой подтверждается кодом FAh, сбрасывается выходной буфер и выполняется сканирование переключателей клавиш.
Команда F5h (блокировка клавиатуры) при поступлении в клавиатуру вызывает следующие ее действия:
- возвращение кода повторения (FAh);
- сбрасывание выходного буфера;
- установление набора кодов клавиш для режима 3;
- прекращение сканирования и ожидание очередных команд.
Для установок начальных значений (по умолчанию) применяется команда F6h, которая по действию напоминает команду F5h, за исключением того, что клавиатура не блокируется и продолжает сканирование.
С поступлением команды определения действий всех клавиш клавиатура реализует следующие функции: - передачу кода "подтверждение" (FAh);
- сброс выходного буфера и соответствующую установку клавиш для режима 3 (F7h - все клавиши только повторяемые, F8h - все клавиши посылают только коды нажатия (отпускания), F9h - все клавиши генерируют только коды нажатия, FAh - все клавиши повторяемые и посылают коды нажатия (отпускания)).
Определение действий отдельных клавиш осуществляется 2-байтными командами (FBh, FCh, FDh). Первый байт является байтом команды для клавиатуры, которая возвращает код подтверждения (FAh), сбрасывает выходной буфер и ожидает поступления второго байта идентификации клавиши (кода сканирования позиции клавиши). Команда FBh делает клавишу повторяемой, FCh - определяет для клавиши только коды нажатия (отпускания), а FDh - для клавиши только коды нажатия.
Команда FEh (повторить передачу) посылается в клавиатуру, если произошла ошибка. По команде FEh клавиатура повторяет передачу последнего байта, переданного в контроллер.
Сброс клавиатуры выполняется командой FFh. В этом случае клавиатура посылает код подтверждения (FAh) и осуществляет внутренний тест. Если тест завершен успешно, то в контроллер направляется код AAh, в противном случае - код FCh. Коды ответов клавиатуры представлены в табл. 1.3.
Таблица 1.3.
КодНазначение команды00h, FFh Ошибка клавиши, переполнение буфера клавиатурыFAh Подтверждение83ABh Идентификатор клавиатурыEEh Эхо (диагностический код)AAh, FCh Завершение тестаFEh Повторить передачу Коды ответов клавиатуры вводятся в системный процессор из выходного буфера (60h) контроллера. В случае переполнения 16-байтного буфера клавиатура посылает в контроллер код 00h, если выполняется режим 2 или 3, или код FFh, если установлен режим 1. Кроме того, клавиатура направляет код ошибки 00h в режиме 2 или 3 при обнаружении неисправного переключателя клавиши или код ошибки FFh, если выполняется режим 1.
Код подтверждения передается в контроллер клавиатуры при получении команд управления, кроме EEh или FEh.
Идентификатор клавиатуры содержит два байта, которые посылаются как ответ при получении команды F2h (чтение идентификатора), причем первым посылается младший байт. Диагностический код EEh (эхо) направляется клавиатурой при получении команды EEh контроллера.
Если внутренний тест клавиатуры завершен успешно, то в контроллер посылается код AAh, если с ошибкой, то код FCh.
При получении клавиатурой неправильных данных или с ошибкой паритета в контроллер передается код FEh (повторить передачу).
1.5.Манипулятор мышь
Манипулятор мышь [2]относится к устройствам интерактивной связи человека с машиной.
При перемещении мыши по плоской поверхности выполняется движение курсора по экрану монитора, т.е. курсор отслеживает перемещение "мыши" с помощью выполнения соответствующей программы. Манипуляторы мышь получили широкое распространение при работе с программами, содержащими машинную графику (Windows, AutoCAD и т.п.). Подключение манипулятора мышь к ПК выполняется либо с помощью специальной платы (шинная мышь), либо через последовательный порт (СОМ). Различают следующие типы манипуляторов этого класса: механические, оптомеханические и оптические. На рис. 1.15 показано условное изображение механического (а) и оптического (б) манипуляторов мышь, поясняющее принцип их работы.
Серые
Линии Y
Рис. 1.15. Условное изображение механической и оптической
мыши
Рассмотрим принцип работы механической мыши. При перемещении мыши по столу (специальному коврику) начинает вращаться каучуковый шар, размещенный в основании корпуса. С шаром соприкасаются два вращающихся ролика (Р1 и Р2), установленные под углом 900 друг к другу. При движении "мыши" в горизонтальном направлении (по оси Х) вращается ролик Р2, а при движении в вертикальном направлении (по оси У) - ролик Р1. Детекторы Д1 и Д2 вращения роликов передают соответствующие импульсы на плату с электронной схемой, сигналы кодов с которой поступают в ПК. Как уже указывалось, большинство манипуляторов используют последовательный порт RS-232C. Кроме того, имеются беспроводные (бесхвостые) мыши, использующие инфракрасное излучение для передачи кодов в приемник, подключенный к последовательному порту. На корпусе мыши находится одна или несколько клавиш (Кi), код которых также поступает в ПК. Обслуживающая программа определяет текущее положение мыши относительно известных положений и состояние ее клавиш и выполняет соответствующие действия. Нажатие одной клавиши мыши может быть эквивалентно нажатию клавиши Enter клавиатуры, нажатие другой - клавиши Esc клавиатуры. Программные файлы представляются на экране в виде картинок (пиктограмм), которые выбираются путем подвода курсора на их место и нажатия клавиши мыши. В WINDOWS устанавливается чувствительность мыши и время двойного щелчка, используемого для запуска программы. Кроме того, выпускаются специализированные многокнопочные мыши.
Принцип действия оптической мыши, в которой подвижный шарик отсутствует, заключается в следующем. Такая мышь содержит два фотодатчика ФД1 и ФД2, каждый из которых содержит фотоэлемент (фотоприемник) и светодиод (фотопередатчик). Один светодиод излучает красный свет, а другой инфракрасный. Кроме того, фотодатчик ФД1 принимает только красный свет, а ФД2 - только инфракрасный. Фотоэлемент и светодиод ФДi размещены под углом друг к другу, так, чтобы отраженный от поверхности свет попадал на фотоэлемент. Светодиоды освещают двухцветную сетку, нанесенную на специальную подложку. При перемещении мыши происходит отражение света, интенсивность которого меняется в зависимости от приближения (удаления) к линии (от линии). Изменение интенсивности одного или другого света показывает направление движения мыши по оси Х или У. Схема платы мыши передает соответствующие сигналы Х и У фотоэлементов в ПК, в котором драйвер мыши их анализирует и управляет движением курсора на экране.
Кроме того, выпускаются оптомеханические мыши, содержащие шарик и фотооптические датчики, которые являются как бы частью клавиатуры (подключаются через специальный блок). Сигналы мыши воспринимаются как сигналы клавиатуры. В этом случае не используется последовательный порт и упрощается некоторым образом программа обработки сигналов мыши.
1.6. Шаровые манипуляторы
Шаровой манипулятор (трекбол) [2] иногда называют перевернутой механической мышью, так как перемещение курсора связано с ручным вращением выступающего над поверхностью шарика, расположенного в верхней части корпуса манипулятора. Трекболы применяются в системах автоматического проектирования, обработки изображений и управления игровыми программами. Движение шарика в трекболе преобразуется в сигналы отсчетов по осям Х и У. По каждому из направлений формируется до 480 импульсов на один оборот шарика, частота импульсов пропорциональна скорости вращения. Трекбол является оптомеханическим устройством, содержащим оптические датчики с фотодиодами (приемниками света), расположенными так, чтобы определить каким образом вращается шарик: вверх, вниз, влево или вправо. Датчик формирует сигналы с уровнем ТТЛ: +Х, -Х, +У, -У. На рис. 1.16 представлена упрощенная схема интерфейса шарового манипулятора (ШМ).
Рис. 1.16. Упрощенная схема интерфейса ШМ
В схеме интерфейса трекбола содержится два реверсивных счетчика СчХ и СчУ, содержимое которых может быть считано через шинные буферы (ШБ) на шину данных (ШД) соответственно сигналами чтения ЧтХ и ЧтУ. Для запрещения переполнения счетчиков при вращении шарика в одном и том же направлении применяются дешифраторы предельных значений (переходов от 0 к 255 и от 255 к 0), ДПЗ1 и ДПЗ2.
В других шаровых манипуляторах используются два потенциометра. При вращении шарика происходит изменение значений сопротивлений потенциометров, которое пропорционально влияет на длительность сигналов. Некоторые фирмы выпускают мини-трекболы для портативных ПК, устанавливаемые сбоку от клавиатуры.
1.7. Ручки управления
Ручки управления (джойстики) [2] курсором делятся на два основных типа: потенциометрические и контактные. В потенциометрических ручках применяются 2 потенциометра, подвижные контакты которых связаны универсальным шарниром с ручкой. Если ручка находится в правом верхнем углу, то это соответствует наибольшим значениям сопротивлений, а если ручка помещена в нижний левый угол - минимальным значениям сопротивлений. При центральном положении ручки подвижные контакты устанавливаются посредине потенциометров, и значения сопротивлений равны середине диапазона (рис. 1.17).
Рис. 1.17. Положения подвижных контактов потенциометров
Для ввода значений R ручки в ПК может быть использована следующая структурная схема адаптера (рис. 1.18).
Рис. 9.18. Структурная схема адаптера
Структурная схема адаптера игрового порта содержит дешифратор адреса (ДшА), который при опознании собственного адреса (201H) формирует сигнал SEL. Шинный буфер (ШБ) используется для согласования с электрическими параметрами шины управления (ШУ). Таймер содержит 4 ждущих мультивибратора и позволяет одновременно принимать значения R от двух ручек. Длительность сигнала на каждом i-ом выходе таймера (i=1,...,4) связана определенным соотношением с величиной соответствующего R. Приемопередатчик предназначен для согласования с электрическими параметрами шины данных (ШД) интерфейса и для передачи сигналов от кнопок и таймера в ПК при наличии сигнала "чтение" (ЧТ). Работа адаптера заключается в следующем. Командой OUT с адресом 201Н запускаются по сигналу запись (ЗП) все четыре мультивибратора таймера. После чего командой IN с этим же адресом осуществляется ввод сигналов от кнопок пуска ручек и сигналов с переменной длительностью соответствующих R. Длительность сигналов преобразуется в ПК в цифровой код с помощью таймеров и регистров и используется в игровой программе. Каждая ручка содержит два потенциометра Х и У и две кнопки, подключаемые непосредственно к 15-штырьковому разъему DB-15 ПК. Кроме таймера для преобразования сигналов от потенциометров можно использовать многоканальный аналогово-цифровой преобразователь (АЦП), формирующий на выходах цифровой код одного из потенциометров, который в данный момент времени подключен к АЦП.
Ручка управления контактного типа содержит 4 переключателя (верхний, нижний, левый и правый), которые замыкаются при переводе ручки в соответствующее положение. Если ручка перемещается в диагональном направлении, то замыкается надлежащая пара контактов. Сигналы от четырех переключателей и от кнопки запуска поступают через 9-штырьковый разъем на вход адаптера, принцип построения которого аналогичен адаптеру потенциометрической ручки.
1.8. Программа "Коды клавиатуры"
Формулировка задания
Целью настоящей работы является практическое закрепление знаний по организации ввода информации с клавиатуры с помощью языка ассемблера и прерываний MS-DOS и BIOS.
Необходимо написать программу, отображающую на экране 16-разрядные коды вводимых с клавиатуры символов, используя соответствующие методы преобразования и функции программных прерываний.
Основные сведения
Программные прерывания позволяют получить доступ к различным процедурам, существенно облегчающим работу программиста. Эти процедуры при задании соответствующих функций выполняют вывод информации на дисплей, принтер, ввод данных с клавиатуры и т.д.
Программирование с помощью прерываний иногда называют программированием на среднем уровне. Существуют различные типы прерываний. Основное внимание в этой работе уделяется прерыванию int 16h (int 10h) и int 21h. Прерывание int 16h вызывает служебные функции BIOS для стандартной клавиатуры, а int 10h вызывает служебные функции BIOS по выдаче изображения. Такие же по возможности функции обеспечивает и DOS. Так, прерывание int 21h осуществляет вызов всех служебных функций DOS. Код требуемой функции необходимо задать в регистре AH. Данные, которые следует вывести с помощью DOS, заносятся в DL (DX), а введенная DOS информация помещается в регистр AL. В табл.1.4 приведены некоторые функции прерывания DOS INT 21h. Таблица 1.4.
AHВыводВводФункции01ALВвод с клавиатуры в режиме ЭХО02DLВывод 1 символа на экран дисплея06DLALНепосредственный ввод-вывод с использованием пульта управления08Ввод с клавиатуры с отображением процесса без ЭХА09DXВывод последовательности символов на экран дисплея
Для функций 1, 2 и 8 при нажатии клавиш Ctrl + C управление возвращается DOS.
Программа вывода символа А на экран дисплея содержит 3 команды:
MOV DL,'A'; загрузка А
MOV AH,2 ; вывод 1 символа на экран
INT 21h ; вызов процедуры
Следующий фрагмент программы выполняет запись в регистр AL считываемого символа с клавиатуры. Если DL равен 0FFh, то AL готов для приема символа. Кроме того, флаг ZF, равный 0, указывает на завершение ввода с клавиатуры байта в AL. Next:
MOV DL,0FFh ; условие готовности
MOV AH,6 ; ввод с клавиатуры
INT 21h JZ Next ; если ZF=1
CALL Display ; переход на подпрограмму
Прерывание INT 10h выполняет 16 функций выдачи изображения на экран дисплея. Функция 00 устанавливает режим выдачи изображения. Загрузка кода этой функции выполняется в регистр AH, а задание текстового или графического режимов выполняется в регистре AL. Функция 03 определяет 16-цветный текстовый режим при выводе символа на экран в формате 80 строк ´25 символов.
Эту установку функции и режима выполняет следующая программа:
MOV AH,00 ;задание функции 00
MOV AL,03 ;загрузка режима 80x25
INT 10h При установке режима, кроме того, BIOS очищает и буфер памяти экрана. Для различных типов адаптеров дисплея выбираются режимы из диапазона 0-15.
Информацию о текущем видеорежиме можно получить (прочитать) с помощью следующих команд:
MOV AH,15 ;установка функции 15
INT 10h
При этом в AL помещается текущий режим дисплея, в AH - число символов в строке, а в BH - номер активной страницы.
Функция 14 осуществляет запись символа в режиме телетайпа. Символ помещается на текущее место курсора, а курсор сдвигается на одну позицию. В регистре AH задается код 14, в регистре AL - записываемый символ ASCII и в регистре BH - номер активной страницы для текстового режима.
Программа вывода символа на экран дисплея имеет вид:
MOV AL,'B' ;загрузка В
MOV AH,14 ;режим телетайпа
MOV BH,0 ;страница 0
MOV DX,0 ;строка 0, столбец 0
INT 10h
Процедура для работы с клавиатурой вызывается с помощью прерывания int 16h. Этих процедур три (0-2). Для вызова процедуры номер ее (номер функции) задается в регистре AH.
Функция 0 осуществляет чтение с клавиатуры очередного символа. Каждый символ клавиатуры в буфере представляется в виде двух байтов. Первый (главный) байт, записываемый в AL равен 0 для специальных клавиш (например, F1-F10) либо коду ASCII для обычных. Второй (вспомогательный) байт, находящийся в регистре AH, равен номеру расширенного кода специальных клавиш либо скэн-коду стандартных клавиш для ASCII-символов. Если символа нет в буфере, то процедура ждет его появления.
Рассмотрим программу, которая ждет от клавиатуры появления символа в AL. Если в AL код 0, то в AH находится номер расширенного кода.
mov ah,0 ;ожидание символа
int 16h
cmp al,0 ;проверка на расширенный код je ext_cod ;переход на подпрограмму Функция 1 выполняет проверку о наличии символа в буфере. Если ZF= 1, то это указывает на отсутствие символа, а 0 - на его наличие. При наличии символа он размещается в регистрах AL и AH так же, как и для функции 0.
Например,
mov ah, 1;проверяем наличие символа
int 16h
jz no_cod;переход, если нет символа
cmp al, 0;проверка на расширенный код
je ext_cod;переход на подпрограмму
Функция 1 позволяет получить состояние регистровых клавиш, которое берется из ячейки памяти с адресом 417 и помещается в AL.
При нажатии любой из клавиш клавиатура передает в адаптер клавиатуры код, равный порядковому номеру клавиши и называемый скэн-кодом (кодом сканирования). Например, при нажатии клавиши А клавиатурой посылается код 30 (1Eh). Этот код преобразуется BIOS в 2-байтовый. Для обычных клавиш первый байт содержит код ASCII, а второй - скэн-код. Например, для клавиши А первый байт имеет код 41h (верхний регистр), а второй байт - код 1Eh.
Скэн-код специальной клавиши преобразуется BIOS в 2-байтный код, первый байт которого содержит 0, а второй байт - номер расширенного кода. Например, нажатию клавиши F1 соответствует 2-байтоый код 00h; 3Bh (59 = 3Bh).
Пример выполнения варианта задания
Code Segment para 'code'
Assume cs: code, ds: code
org 100h
begin:
mov ah,00 ; ввод кода
int 16h
push ax
cmp al,0
jne go1
push ax
mov dl,'0' ; вывод символа 0
mov ah,2
int 21h
mov dl,' ' ; вывод пробела
int 21h
pop ax
jmp begin
go1:
mov dh,al
mov cl,4 ; выделение старшей тетрады
shr al,cl
add al,30h
cmp al,39h ; преобразование
jbe go2
add al,7
go2:
mov dl,al ; вывод символа
mov ah,2
int 21h
mov dl,dh ; выделение младшей тетрады
and dl,0Fh
add dl,30h
cmp dl,39h ; преобразование
jbe go3
add dl,7
go3:
mov ah,2 ; вывод символа
int 21h
mov dl,10 ; перевод строки
int 21h
mov dl,13
int 21h
pop ax
cmp al,27 ; код ESC
jne begin
mov ax,4C00h ; завершить процесс
int 21h
Code Ends
end begin
Одним из вариантов задания может служить модификация введенной программы путем ввода подпрограмм преобразования и вывода кода на заданное место экрана дисплея. Кроме того, вместо COM-программы можно написать EXE-программу.
1.9. Варианты заданий
На рис.1.19 изображен функциональный граф, задающий в минимальном объеме 36 вариантов решения задачи определения шестнадцатеричных кодов клавиш клавиатуры с выводом этих кодов на экран дисплея. Первый уровень (вершины 1-3) является системным уровнем.
Вершина 1 определяет функцию BIOS, вершины 2 и 3 - функции DOS, используемые в программе. Второй уровень (вершины 4-6) соответствует уровню преобразования кода клавиатуры в шестнадцатеричную форму.
Вершина 4 указывает на алгоритм перекодировки, использующий таблицу 0-F и индекс.
Применению команды XLAT в программе перевода соответствует вершина 5.
Рис.1.19. Функциональный граф вариантов решения задачи
Арифметический метод преобразования определяет вершина 6.
Вариант задания определяется маршрутом, соединяющим четыре вершины (по одной из каждого уровня), например, вариант задания 1, 4, 7, 9.
Рассмотрим подробнее определение вершин морфологического графа.
Необходимые функции BIOS и DOS, соответствующие вершинам 1-3, изложены в разделе 1.2.
Вершине 4 соответствует алгоритм перекодировки, использующий таблицу и индекс.
В морфологическом графе вершина 5 определяет применение команды преобразования XLAT. Эта команда использует содержимое регистра AL, как смещение относительно начала 256-байтовой таблицы TABLE, перемещаемый адрес начала которой задается регистром BX. Байт таблицы, определяемый этим смещением, заменяет исходное содержимое AL. Смещение 0 определяет начальный байт таблиц. В качестве примера использования команды XLAT рассмотрим фрагмент программы преобразования десятичных чисел от 0 до 15 в соответствующие им шестнадцатеричные числа от 0 до F. TABLEdb'0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F'
mov ax, cs
movds, ax
mov si, 0
movcx, 16
movbx, offset table
NEXT:movax, si
XLAT
movdl, al
call displ AY
incsi
loop next
В этой программе выполняются следующие действия.
Содержимое DS помещается в CS, так как область TABLE находится в сегменте кодов.
Для выполнения команды XLAT необходимо поместить в BX адрес начала таблицы. Затем содержимое SI пересылается в AX (AL) и по команде XLAT происходит преобразование десятичного числа в шестнадцатеричное. Преобразованное значение формируется в AL. Содержимое AL перезаписывается в DL и выводится на экран дисплея. Команда INC увеличивает содержимое SI на 1. Затем при выполнении команды LOOP содержимое регистра CX уменьшается на 1. Если CX = 0, то управление передается на метку NEXT, а если CX = 0, то это конец выполнения программы. Вершина 6 морфологического графа соответствует арифметическому преобразованию двоичных кодов в шестнадцатеричную форму без применения таблицы. Алгоритм заключается в выделении старшей тетрады. Если старшая тетрада меньше или равна 9, то к ней добавляется 30h, а если больше, то добавляется 37h. Аналогичным образом обрабатывается младшая тетрада. Определение кода нажатой клавиши возможно с помощью прерывания BIOS int 16h с функцией AH = 00 и прерывания DOS int 21h с функцией AH = 06 или AH = 08.
Прерывание int 16h c функцией AH = 00 помещает в регистр AL код ASCII нажатой клавиши, причем если нажата функциональная (специальная) клавиша, то в регистре AL содержится нуль, а в регистре AH - скэн-код нажатой клавиши. Прерывание int 21h с функцией AH = 06 возвращает в AL код нажатой клавиши. Если клавиша не была нажата (буфер клавиатуры пуст), то устанавливается флаг нуля (ZF = 1). В случае AL = 0 (нажата функциональная клавиша) необходимо повторить вызов функции.
Процедура прерывания int 21h с функцией AH = 08 ждет, пока не будет нажата клавиша (флаг ZF не устанавливается) и возвращает ее код в регистр AL.
Вывод символа на экран выполняется с помощью прерывания DOS int 21h с функцией AH = 2 или с помощью прерывания BIOS int 10h (AH = 14).
1.10. Преобразование кодов
Известны ассемблерные программы, преобразующие 2-е (двоичные) коды вводимых с клавиатуры символов, в 16-ричные (шестнадцатеричные) коды, с отображением их на экран дисплея.
При нажатии любой из клавиш клавиатура передаёт в контроллер клавиатуры двоичный код, равный порядковому номеру клавиши и называемый скэн-кодом.
Например, при нажатии клавиши А клавиатурой посылается двоичный код, равный 30 (1Eh), где h обозначает 16-ричное значение.
Этот код преобразуется в двухбайтовый код, хранимый в буфере клавиатуры. Для обычной клавиши первый байт содержит код ASCII, а второй - скэн-код. Так, для клавиши А первый байт имеет код 41h (верхний регистр), а второй байт - код 1Eh. Коду 41h соответствует двоичный эквивалент двух тетрад 0100 0001, где 0100 старшая, а 0001 - младшая тетрада (четыре бита).
Ассемблерные команды, используя различные методы, преобразуют 2-ичный код ASCII в 16-ричные с отображением их на экран монитора.
Рассмотрим один из методов. Анализ таблицы кодов ASCII (таблица размещена в конце книги) показывает, что если старшая тетрада двоичного кода ASCII меньше или равна 9, то к ней следует добавить 30h, а если больше, то необходимо прибавить 37h. Аналогичным образом обрабатывается младшая тетрада.
Действительно, в таблице кодов ASCII символу 0 соответствует 16-ричный код 30, символу 1 - код 31, символу 2 - код 32, символу 3 - код 33, символу 4 - код 34, символу 5 - код 35, символу 6 - код 36, символу 7 - код 37, символу 8 - код 38, символу 9 - код 39. После этого указанный порядок нарушается и необходимо прибавлять к тетраде не 30(h), а 37(h).
На рис. 1.20 представлена блок-схема программы преобразования 2-го кода в 16-ричный и таблица ASCII (0-D).
Рис. 120. Блок-схема программы и таблица ASCII (0-D)
Существует авторитетное мнение (Эйрис Р. "Проектирование СБИС") о необходимости "отказываться от неестественного разделения наших вычислительных средств на противопоставляемые друг другу технические и программные средства ЭВМ. Это приближает нас к универсальному представлению о неразрывной связи информации с её обработкой".
Другими словами, один и тот же алгоритм можно реализовать как аппаратным, так и программным способами.
В этой связи покажем, как выполнить блок-схему ассемблерной программы преобразования 2-го кода в 16-ричный с помощью соответствующих схем (рис. 1.21).
Обозначения:
RG- регистр; LB- младшая тетрада (MT); LH- старшая тетрада(CT); ELB- сигнал выделения ИТ;EHB-сигнал выделения СТ ;BD-шинный драйвер; СМ- сумматор ;X/Y-преобразователь 2-го кода в 16- ричный; 1-элемент ИЛИ.
Рис. 1.21. Устройство преобразования 2 - го кода в 16- ричный
Принцип работы устройства следующий:
1. В RG1 заносится символ в виде 2-го кода, содержащего младшую (LB) и старшую (HB) тетрады.
2. Сигналом EHB выделяем старшую тетраду, которая через драйвер BD поступает на входы схемы сравнения.
3. Схема сравнения сопоставляет старшую тетраду с константой 1001(9). Если старшая тетрада ≤ константе, то с помощью сумматора CM1 к ней прибавляется константа 0011 0000(30h), а если нет, то сумматор CM2 прибавляет к константе 0011 0011 (37h) старшую тетраду.
4. Результат суммирования через регистр RG2 или RG3 поступает на соответствующий преобразователь x/y и выводится на индикатор.
Аналогичным образом обрабатывается младшая тетрада.
Модель программы преобразования кодов, соответствующая структурной схеме устройства, представлена на рис. 1.22.
Рис. 1.22. Схема модели преобразователя
Приведём некоторые значения свойств компонентов, используемых в программе.
Форма Form1: TForm1
BorderStyle := bsSingle ( чтобы не было возможности изменять размеры формы во время выполнения программы);
BorderIcons.biMaximize:= False;
Color:= clWhite;
Position:= poDesktopCenter.
Надпись "Струтурная схема преобразователя 2-го кода в 16-ричный" устанавливается с помощью компонента Label11: TLabel, имеющего свойства:
Font.Name = Arial,
Font.Size = 16.
Компонент Image используется для отображения рисунка .bmp. Кроме размеров все свойства выбираются по умолчанию.
Две кнопки ButtonEHB и ButtonELB относятся к объекту TSpeedButton,
значение свойства Flat которого - True.
Поле для ввода - EdtInput: TEdit.
BorderStyle:= bsNone;
Font.Name:= Courier New;
Font.Size:= 14;
MaxLength:= 1.
Все остальные поля (EdtHB, EdtLB, Edt9h, Edt30h, Edt37h, EdtRG21, EdtRG22) предназначены для отображения информации, имеют следующие общие свойства:
Ctl3D:= False;
Font.Name:= Courier New;
Font.Size:= 14; Для полей EdtRG2x Font.Size:= 10;
MaxLength:= 4-8;
ReadOnly:= True;
TabStop:= False.
unit FormUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, Buttons, Math;
type
TForm1 = class(TForm)
Image: TImage;
EdtInput: TEdit;
ButtonELB: TSpeedButton;
ButtonEHB: TSpeedButton;
Label1: TLabel;
EdtHB: TEdit;
EdtLB: TEdit;
Edt9h: TEdit;
Edt30h: TEdit;
Edt37h: TEdit;
EdtRG21: TEdit;
EdtRG22: TEdit;
EdtScreen: TEdit;
procedure EdtInputChange(Sender: TObject);
procedure ButtonELBClick(Sender: TObject);
procedure ButtonEHBClick(Sender: TObject);
private
function BinToDec(Value: string): integer;
function DecToBin(Value, Count: integer): string;
function DivaceComparison(Kod: string): char;
function SumCM1(Kod, E: string): string;
function SumCM2(Kod, E: string): string;
function XslashY(Kod: string): string;
public
end;
const
C9h = 9;
C30h = 48;
C37h = 55;
var
Form1: TForm1;
implementation
{$R *.dfm}
{Преобразование двоичного числа в десятичное}
function TForm1.BinToDec(Value: string): integer;
var i: byte;
Len: integer;
begin
Result:= 0;
//Цикл - длина входного массива
Len:= Length(Value);
for i:= 1 to Len do
if Value[i] = '1' then
Result:= Result + round(Power(2, Len - i))
end;
{Преобразование десятичного числа в двоичное}
function TForm1.DecToBin(Value, Count: integer): string;
var i: byte;
tmp: integer;
begin
Result:= '';
//Преобразование
tmp:= Value;
while tmp <> 0 do
begin
if tmp mod 2 = 1 then
Result:= '1' + Result
else
Result:= '0' + Result;
tmp:= tmp div 2
end;
//Count - количество разрядов
if Length(Result) < Count then
for i:= Length(Result) + 1 to Count do
Result:= '0' + Result
end;
{Схема сравнения}
function TForm1.DivaceComparison(Kod: string): char;
var Value: integer;
begin
//Преобразуем входной сигнал в десятичное число
Value:= BinToDec(Kod);
//Сравниваем входной сигнал с константой
if Value > C9h then
Result:= '>'
else if Value = C9h then
Result:= '='
else if Value < C9h then
Result:= '<'
end;
{Сумматор CM1}
function TForm1.SumCM1(Kod, E: string): string;
var Sum: integer;
begin
//Сиганал разрешения работы
if E = '1' then
begin
Sum:= BinToDec(Kod) + C30h;
Result:= DecToBin(Sum, 8)
end;
end;
{Сумматор CM2}
function TForm1.SumCM2(Kod, E: string): string;
var Sum: integer;
begin
//Сиганал разрешения работы
if E = '1' then
begin
Sum:= BinToDec(Kod) + C37h;
Result:= DecToBin(Sum, 8)
end;
end;
{Получение 16-ричного числа}
function TForm1.XslashY(Kod: string): string;
var tmp: integer;
begin
//Перевод из двоичного в десятичное
tmp:= BinToDec(Kod);
//Результат в 16-ричное
Result:= char(tmp)
end;
{Ввод символа}
procedure TForm1.EdtInputChange(Sender: TObject);
var tmp: byte;
Kod: string;
begin
//Получение десятичного кода символа
tmp:= byte(EdtInput.Text[1]);
//Перевод в двоичное представление
Kod:= DecToBin(tmp, 8);
//Выделение старшей и младшей части
EdtHB.Text:= Copy(Kod, 1, 4);
EdtLB.Text:= Copy(Kod, 5, 4)
end;
{Разрешение младшей части}
procedure TForm1.ButtonELBClick(Sender: TObject);
var comp: char;
sum: string;
x16: string;
begin
//Работа схемы сравнения
comp:= DivaceComparison(EdtLB.Text);
//Обработка результата сравнения
case comp of
'=', '<':
begin
//Получение суммы на CM1
sum:= SumCM1(EdtLB.Text, '1');
//Вывод суммы
EdtRG21.Text:= sum;
//Получение 16-ричного числа
x16:= XslashY(sum);
EdtScreen.Text:= EdtScreen.Text[1] + x16
end;
'>':
begin
//Получение суммы на CM1
sum:= SumCM2(EdtLB.Text, '1');
//Вывод суммы
EdtRG22.Text:= sum;
//Получение 16-ричного числа
x16:= XslashY(sum);
EdtScreen.Text:= EdtScreen.Text[1] + x16
end;
end;
end;
{Разрешение старшей части}
procedure TForm1.ButtonEHBClick(Sender: TObject);
var comp: char;
sum: string;
x16: string;
begin
//Работа схемы сравнения
comp:= DivaceComparison(EdtHB.Text);
//Обработка результата сравнения
case comp of
'=', '<':
begin
//Получение суммы на CM1
sum:= SumCM1(EdtHB.Text, '1');
//Вывод суммы
EdtRG21.Text:= sum;
//Получение 16-ричного числа
x16:= XslashY(sum);
EdtScreen.Text:= x16 + EdtScreen.Text[2]
end;
'>':
begin
//Получение суммы на CM1
sum:= SumCM2(EdtHB.Text, '1');
//Вывод суммы
EdtRG22.Text:= sum;
//Получение 16-ричного числа
x16:= XslashY(sum);
EdtScreen.Text:= x16 + EdtScreen.Text[2]
end;
end;
end;
end.
1.11. API - функции. Варианты заданий
Для управления работой современного компьютера используются API-функции, которых насчитывается около тысячи. API-функции в какой - то мере соответствуют функциям программных прерываний DOS, определяющих средний уровень программирования между языком высокого уровня и языком низкого уровня (ассемблером).
Поэтому рекомендуется в качестве другого альтернативного задания написать программу на языке Delphi, осуществляющую работу API-функций с клавиатурой и мышью с последующим выводом результатов этой работы на экран. Отчет должен содержать подробное описание API-функции, блок-схему, программу с комментариями и выводы. Вариант задания определяется преподавателем.
Варианты заданий
Варианты заданий получаются из морфологического графа, содержащего три уровня (рис. 1.23:
1. Действия, выполняемые при обработке сигнала клавиатуры.
2. Действия, осуществляемые при поступлении сигнала от мыши.
3. Индикация нажатой клавиши сдвига.
Рис. 1. 23 Граф вариантов заданий
Вариант задания определяется следующим образом.
В зависимости от последовательности цифр, записанных на трёх уровнях, выбирается соответствующий вариант, например 1 - 5 - 8.
1. Вывод ASCII-кода нажатой клавиши. Если это несимвольная клавиша, то вывести сообщение об этом.
2. Вывод Unicode нажатой клавиши. При нажатии несимвольной клавиша на экране монитора отмечается этот факт.
3. Вывод SCAN-кода нажатой клавиши.
4. Индикация координат мыши.
5. Индикация нажатия кнопки мыши, причем указать, если был двойной щелчок.
6. Индикация нажатия левой, правой или центральной кнопки мыши.
7. Индикация нажатия правого или левого CTRL.
8. Индикация нажатия ALT или SHIFT.
9. Индикация нажатия NUM LOCK, CAPS LOCK или SCROLL LOCK.
1.12. Основные сведения
Предлагаемые варианты заданий лабораторной работы посвящены обработке команд мыши и клавиатуры в консольном приложении. Возможность такой обработки делает консольные приложения весьма гибкими, расширяя круг задач, которые можно решить в этом режиме.
Прежде рассмотрим одну весьма необычную, но чрезвычайно полезную API-функцию wsprintfA. Это АР1-функция, которая предоставляется системой приложению. Она является неким аналогом библиотечной СИ-функции - sprintf. Первым параметром функции является указатель на буфер куда помещается результат форматирования. Второй параметр - указатель на форматную строку, например: "Числа: %lu, %lu". Затем идут указатели на параметры (либо сами параметры, если это числа), число которых определено только содержимым форматной строки. Поскольку количество параметров не определено, то необходимо освободить стек. Пример использования этой функции будет дан ниже. Заметим также, что прототипом этой функции для библиотеки import32.1ib (TASM32) будет не wsprintfA, a jwsprintfA (!). Наконец отметим, что если функция выполнена успешно, то в регистр процессора ЕАХ будет возвращена длина скопированной строки.
В основе получения информации о клавиатуре и мыши в консольном режиме является функция ReadConsolelnput. Параметры этой функции:
1-й - дескриптор входного буфера консоли;
2-й - указатель на структуру (или массив структур), в которой содержится информация о событиях, происшедших с консолью. Ниже мы подробно рассмотрим эту структуру;
3-й - количество получаемых информационных записей (структур);
4-й - указатель на двойное слово, содержащее количество реально полученных записей;
Рассмотрим структуру, в которой содержится информация о консольном событии. Прежде всего заметим, что в Си эта структура записывается с помощью типа данных UNION. При описании этой структуры мы обойдемся без STRUCT и UNION. В начале этого блока данных идет двойное слово, младшее слово которого определяет тип события. В зависимости от значения этого слова последующие байты (максимум 18) будут трактоваться, так или иначе. Те, кто уже знаком с различными структурами, используемыми в Си и Макроассемблере, теперь должны понять, почему UNION здесь весьма подходит.
Но вернемся к типу события. Всего системой зарезервировано пять типов событий:
KEY_EVENT equ lh ;клавиатурное событие
MOUSE_EVENTequ 2h /событие с мышью
WINDOW_BUFFER_SIZE_EVENTequ 4h /изменился размер окна
MENU_EVENTequ 8h /зарезервировано
FOCUS_EVENTequ lOh;зарезервировано
Разберем значение других байт структуры в зависимости от проистекшего события.
Событие KEY_EVENT Смещениещение Длина Значение +4 4 При нажатии клавиши значение поля больше нуля. +8 2 Количество повторов при удержании клавиши. +10 2 Виртуальный код клавиши. +12 2 Скан-код клавиши. +14 2 Для функции ReadConsolelnputA - младший байт равен ASCII-коду клавиши. Для функции ReadConsolelnputW слов содержит код клавиши в двухбайтной кодировке (Unicode). +16 4Содержится состояния управляющих клавиш.
Может являться суммой следующих констант: RIGHT_ALT_PRESSED equ lh LEFT_ALT_PRESSED equ 2h RIGHT_CTRL_PRESSED equ 4h LEFT_CTRL_PRESSED equ 8h SHIFT_PRESSED equ 1 Oh NUMLOCK_ON equ20h SCROLLLOCK_ON equ40h CAPSLOCK_ON equ80h ENHANCED_KEY equ lOOh Смысл констант очевиден.
Событие MOUSE_EVENT
Смещение Длина Значение +4 4 Младшее слово - Х-координата курсора мыши, старшее слово - Y-координата мыши. +8 4 Описывает состояние кнопок мыши. Первый бит - левая кнопка, второй бит - правая кнопка, третий бит - средняя кнопка. Бит установлен - кнопка нажата. +12 4 Состояние управляющих клавиш. Аналогично предыдущей таблице. +16 4Может содержать следующие значения: MOUSE_MOV equ lh; было движение мыши DOUBLE CL equ 2h; был двойной щелчокСобытие WINDOW_BUFFER_SIZE_EVENT
По смещению +4 находится двойное слово, содержащее новый размер консольного окна. Младшее слово - это размер по X, старшее слово - размер по Y. Да, когда речь идет о консольном окне, все размеры и координаты даются в "символьных" единицах.
Далее приведен пример универсальной программы (рис.1.23).
Алгоритм:
Рис. 1.23. Алгоритм универсальной программы
Функция ReadConsoleInput может быть использована для прямого доступа к буферу ввода с консоли. Когда консоль создана, ввод мыши разрешен и оконный ввод запрещен. Для того, чтобы убедиться, что процесс отправляет все типы событий, используют функцию SetConsoleMode для разрешения окна и ввода мыши. Далее это заворачивается в цикл, который читает и обрабатывает события ввода консоли.
program P1_v3;
{$APPTYPE CONSOLE}
uses Windows, SysUtils;
var MyMessage : string;{ переменная для ввода текста }
hStdin : THandle;{ дескриптор консоли }
i : integer;{ вспомогательная переменная }
cNumRead : DWORD;
fdwMode : DWORD;{ режим }
fdwSaveOldMode : DWORD;{ переменная для сохранения предыдущего режима }
irInBuf : array [1..128] of TInputRecord; { массив для записей в буфер ввода}
buf : ^Byte;{ указатель на буфер ввода }
CurCursorPos : TCoord;{ переменная для отображения координат кукрсора }
{
Дальнейшие комментарии взяты из примера, описанного в "HELPе"
1)
PInputRecord = ^TInputRecord;
_ INPUT_RECORD = record
EventType: Word;
Reserved: Word;
Event: Record case Integer of
0: (KeyEvent: TKeyEventRecord);
1: (MouseEvent: TMouseEventRecord);
2: (WindowBufferSizeEvent: TWindowBufferSizeRecord);
3: (MenuEvent: TMenuEventRecord);
4: (FocusEvent: TFocusEventRecord);
end;
end;
TInputRecord = _INPUT_RECORD;
2) из helpa:
typedef struct _INPUT_RECORD { // ir
WORD EventType;
union
KEY_EVENT_RECORD KeyEvent;
MOUSE_EVENT_RECORD MouseEvent;
WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
MENU_EVENT_RECORD MenuEvent;
FOCUS_EVENT_RECORD FocusEvent;
Event;
INPUT_RECORD;
Members
EventTypeОпределяет тип введенного события и запись события, хранящуюся в Event member Эта часть (member) может содержать одну из следующих величин:
ValueMeaning
KEY_EVENTЧасть события содержит структуру KEY_EVENT_RECORD с информацией о событии с клавиатуры.
MOUSE_EVENT Часть события содержит структуру MOUSE_EVENT_RECORD с информацией о
перемещении курсора или событии нажатия клавиши.
WINDOW_BUFFER_SIZE_EVENT Часть события содержит структуру
WINDOW_BUFFER_SIZE_RECORD с информацией о новом размере буфера экрана.
MENU_EVENT Часть события содержит структуру MENU_EVENT_RECORD. Это событие
используется из вне. Их следует игнорировать.
FOCUS_EVENT Часть события содержит структуру FOCUS_EVENT_RECORD. Это событие
используется из вне. Их следует игнорировать.
События содержат KEY_EVENT_RECORD, MOUSE_EVENT_RECORD, WINDOW_BUFFER_SIZE_RECORD,
MENU_EVENT_RECORD, или структуру FOCUS_EVENT_RECORD, взависимости от типа события описанного в EventType member.
3) из windows.pas
KEY_EVENT = 1; Событие содержит запись о ключе события.
_MOUSE_EVENT = 2; Событие содержит запись о событии от мыши. WINDOW_BUFFER_SIZE_EVENT = 4; Событие содержит запись о событии об изменении
размера окна.
MENU_EVENT = 8; Событие содержит запись о событии меню.
FOCUS_EVENT = $10; Событие содержит изменение фокуса.
По умолчанию величины в структурированном типе выстроены в линию по границе слова или двойного слова для более быстрого доступа. Когда объявляется структурированный тип, используется зарезервированное слово для сжатого хранения данных.
Например,
type TNumbers = packed array[1..100] of Real;
Используя доступ с медленной выборкой данных и в выборе символьного массива оказывает влияние на совместимость типов.
PKeyEventRecord = ^TKeyEventRecord;
_KEY_EVENT_RECORD = packed record
bKeyDown: BOOL; // 4 байта
wRepeatCount: Word; // 2 байта
wVirtualKeyCode: Word; // 2 байта
wVirtualScanCode: Word; // 2 байта
case Integer of
0: (
UnicodeChar: WCHAR; // Символы WideChar используют более чем 1 байт //для представления каждого символа. В текущих //исполнениях, WideChar - 16-ти битные символы, //записанные в наборе символов Unicode
//(в других приложениях может быть длиннее).
//Первые 256 символов Unicode
//соответствуют символам ANSI.
dwControlKeyState: DWORD); //longword unsigned 4 байта
1: (
AsciiChar: CHAR);
end;
TKeyEventRecord = _KEY_EVENT_RECORD;
KEY_EVENT_RECORD = _KEY_EVENT_RECORD;
}
// ========================================================================
Procedure KeyEventProc (KeyEvent : TKeyEventRecord);
var i : integer;
begin
Write ('bKeyDown = ', KeyEvent.bKeyDown);
if KeyEvent.bKeyDown = TRUE then Writeln (' - Key is pressed')
else Writeln (' - Key is NOT pressed');
Writeln ('wRepeatCount = ', KeyEvent.wRepeatCount);
Writeln ('wVirtualKeyCode = ', KeyEvent.wVirtualKeyCode,
' (',IntToHex(KeyEvent.wVirtualKeyCode, 2), 'h)' );
Writeln ('wVirtualScanCode = ', KeyEvent.wVirtualScanCode,
' (',IntToHex(KeyEvent.wVirtualScanCode, 2), 'h)');
i := integer (KeyEvent.UnicodeChar);
Writeln ('UnicodeChar = ', KeyEvent.UnicodeChar,
' (',IntToHex(i, 2), 'h)');
// WideCharLenToString(@KeyEvent.UnicodeChar, 1));
// ' (',IntToHex(int(KeyEvent.UnicodeChar), 2), 'h)');
//WideCharToMultiByte ???
//WideCharLenToString(Source: PWideChar; SourceLen: Integer):
Write ('dwControlKeyState = ', KeyEvent.dwControlKeyState,
' (',IntToHex(KeyEvent.dwControlKeyState, 4), 'h)');
if (KeyEvent.dwControlKeyState AND $1) <> 0 then Write (' RIGHT_ALT pressed');
if (KeyEvent.dwControlKeyState AND $2) <> 0 then Write (' LEFT_ALT pressed');
if (KeyEvent.dwControlKeyState AND $4) <> 0 then Write (' RIGHT_CTRL pressed');
if (KeyEvent.dwControlKeyState AND $8) <> 0 then Write (' LEFT_CTRL pressed');
if (KeyEvent.dwControlKeyState AND $10) <> 0 then Write (' SHIFT pressed');
if (KeyEvent.dwControlKeyState AND $20) <> 0 then Write (' NUMLOCK_ON pressed');
if (KeyEvent.dwControlKeyState AND $40) <> 0 then Write (' SCROLLLOCK_ON pressed');
if (KeyEvent.dwControlKeyState AND $80) <> 0 then Write (' CAPSLOCK_ON pressed');
if (KeyEvent.dwControlKeyState AND $100) <> 0 then Write (' ENHANCED_KEY pressed');
Writeln;
i := integer (KeyEvent.AsciiChar);
Writeln ('AsciiChar = ', KeyEvent.AsciiChar,
' (',IntToHex(i, 2), 'h)');
Writeln ;
end;
// ========================================================================
{ _MOUSE_EVENT_RECORD = packed record
dwMousePosition: TCoord;
dwButtonState: DWORD;
dwControlKeyState: DWORD;
dwEventFlags: DWORD;
end;
TMouseEventRecord = _MOUSE_EVENT_RECORD;
MOUSE_EVENT_RECORD = _MOUSE_EVENT_RECORD;
}
Procedure MouseEventProc (MouseEvent : TMouseEventRecord);
begin
Writeln ('x = ', MouseEvent.dwMousePosition.x,
' y = ', MouseEvent.dwMousePosition.y);
Write ('dwButtonState = ', MouseEvent.dwButtonState,
' (',IntToHex(MouseEvent.dwButtonState, 4), 'h)');
if (MouseEvent.dwButtonState AND $1) <> 0 then Write (' LEFT_Button pressed');
if (MouseEvent.dwButtonState AND $2) <> 0 then Write (' RIGHT_Button pressed');
if (MouseEvent.dwButtonState AND $4) <> 0 then Write (' MIDDLE_Button pressed');
Writeln;
Write ('dwControlKeyState = ', MouseEvent.dwControlKeyState,
' (',IntToHex(MouseEvent.dwControlKeyState, 4), 'h)');
if (MouseEvent.dwControlKeyState AND $1) <> 0 then Write (' RIGHT_ALT pressed');
if (MouseEvent.dwControlKeyState AND $2) <> 0 then Write (' LEFT_ALT pressed');
if (MouseEvent.dwControlKeyState AND $4) <> 0 then Write (' RIGHT_CTRL pressed');
if (MouseEvent.dwControlKeyState AND $8) <> 0 then Write (' LEFT_CTRL pressed');
if (MouseEvent.dwControlKeyState AND $10) <> 0 then Write (' SHIFT pressed');
if (MouseEvent.dwControlKeyState AND $20) <> 0 then Write (' NUMLOCK_ON pressed');
if (MouseEvent.dwControlKeyState AND $40) <> 0 then Write (' SCROLLLOCK_ON pressed');
if (MouseEvent.dwControlKeyState AND $80) <> 0 then Write (' CAPSLOCK_ON pressed');
if (MouseEvent.dwControlKeyState AND $100) <> 0 then Write (' ENHANCED_KEY pressed');
Writeln;
Write ('dwEventFlags = ', MouseEvent.dwEventFlags);
if (MouseEvent.dwEventFlags AND $01) <> 0 then Write (' Move');
if (MouseEvent.dwEventFlags AND $02) <> 0 then Write (' Dubl click ');
Writeln;
Writeln ;
end;
// ===========================================================================
begin
{ TODO -oUser -cConsole Main : Insert code here }
// Writeln ('Клавиатура или мышь. Выход по ^С');
// FreeConsole;
// AllocConsole;
// Захватить обработчик стандартного ввода.
hStdin := GetStdHandle (STD_INPUT_HANDLE);
if (hStdin = INVALID_HANDLE_VALUE) then begin
MyMessage := 'ERR hStdin!';
Writeln(MyMessage);
Exit;
end;
SetConsoleTitle (' My Console App');
// Сохранить текущий режим ввода, чтобы восстановить его перед выходом.
// function GetConsoleMode(hConsoleHandle: THandle; var lpMode: DWORD): BOOL; stdcall;
if (NOT GetConsoleMode(hStdin, fdwSaveOldMode) ) then begin
Writeln ('ERR GetConsoleMode!');
Exit;
end;
Writeln ('fdwSaveOldMode = ', fdwSaveOldMode,
' (',IntToHex(fdwSaveOldMode, 4), 'h)');
Writeln;
// функция SetConsoleCursorPosition (hConsoleOutput: THandle;
// dwCursorPosition: TCoord): BOOL;
CurCursorPos.X := 0;
CurCursorPos.Y := 10;
SetConsoleCursorPosition (hStdin, CurCursorPos);
// Разрешить события ввода с мыши и клавиатуры.
// функция SetConsoleMode(hConsoleHandle: THandle; dwMode: DWORD): BOOL; stdcall;
fdwMode := ENABLE_WINDOW_INPUT OR ENABLE_MOUSE_INPUT;
if (NOT SetConsoleMode(hStdin, fdwMode) ) then begin
Writeln ('ERR GetConsoleMode!');
Exit;
end;
Writeln ('fdwMode = ', fdwMode,
' (',IntToHex(fdwMode, 4), 'h)');
Writeln;
// Зациклить для чтения обработчика событий ввода.
repeat
// Ожидание события.
if (NOT ReadConsoleInput(
hStdin, // обработчик буфера ввода
irInBuf[1], // буфер для считывания
128, // размер буфера чтения
cNumRead) ) // число записей чтения
then begin
{
function ReadConsoleInput (hConsoleInput: THandle;
var lpBuffer: TInputRecord;
nLength: DWORD;
var lpNumberOfEventsRead: DWORD): BOOL; stdcall;
}
Writeln ('ERR ReadConsoleInput!');
Exit;
end;
// Отправка событий соответствующему обработчику.
for i := 1 to cNumRead do begin
case irInBuf[i].EventType of
KEY_EVENT:
begin // ввод с клавиатуры
Writeln('keyboard input ', irInBuf[i].EventType);
KeyEventProc (irInBuf[i].Event.KeyEvent);
end;
_MOUSE_EVENT:
begin // ввод с мыши
Writeln ('mouse input ', irInBuf[i].EventType);
MouseEventProc(irInBuf[i].Event.MouseEvent);
end;
WINDOW_BUFFER_SIZE_EVENT: begin// изменение размера буфера экрана
//ResizeEventProc(irInBuf[i].Event.WindowBufferSizeEvent);
Writeln ('scrn buf resizing ', irInBuf[i].EventType);
end;
FOCUS_EVENT: // игнорировать события фокуса
begin
//Writeln ('События изменения фокуса не обрабатываются');
Writeln ('disregard focus events ', irInBuf[i].EventType);
end;
MENU_EVENT: // игнорировать события меню
begin
Writeln ('disregard menu events ', irInBuf[i].EventType);
end;
else begin
Writeln (' ', irInBuf[i].EventType);
Writeln ('ERR unknown event type!');
end;
end;
end;
until irInBuf[1].Event.KeyEvent.wVirtualScanCode = 1; //27;
// Сохранить текущий режим ввода для сохранения при выходе.
if (NOT SetConsoleMode(hStdin, fdwSaveOldMode) ) then begin
Writeln ('ERR SetConsoleMode!');
Exit;
end;
// FreeConsole;
End.
1.13. Таблица кодов ASCII
Продолжение таблицы кодов ASCII
Продолжение таблицы кодов ASCII
Продолжение таблицы кодов ASCII
Контрольные вопросы
1. Стандартные коды ASCII содержат символы...
1.0-127
2.0-31
3.128-256 4.0-255
2. Дайте определение скан-коду.
1.Код ASCII
2.Расширенный код 3.Код сканирования
4.Порядковый номер клавиши
3. Укажите технологию, неиспользуемую в переключателях клавиш.
1.Емкостная
2.Индуктивная
3.Механическая
4.Акустическая.
4. Назовите количество проводов, которое содержит кабель клавиатуры.
1. 3
2. 4
3. 5
4. 6
5. Укажите количество битов, которое содержит по умолчанию кодовая посылка, передаваемая от клавиатуры к контроллеру.
1.9
2. 10 3. 11
4. 12.
6. Определите функцию, не выполняемую контроллером, к которому подключена клавиатура.
1.Сканирование переключателей клавиш.
2.Формирование сигналов прерывания.
3.Передачу номера прерывания.
4.Преобразование кодов нажатия (отжатия).
7. Кажите функцию, невыполняемую клавиатурой.
1.Автотестирование матрицы переключателей клавиш.
2.Формирование последовательных кодовых посылок при нажатии (отпускании) клавиш.
3.Опрос состояний линий data и clk.
4.Анализ системного скан-кода и преобразование его в 2х-байтный код.
8. Укажите тип временного согласования клавиатуры и контроллера.
1.Синхронный
2.Асинхронный
3.Синхронно-асинхронный.
9. Назовите два байта, хранимые в буфере клавиатуры, соответствующие обычной (символьной) клавише.
1.Код ASCII, скан-код
2.Скан-код, код ASCII
3.Код 00, скан-код
4.Код 00, код ASCII
10. Определите содержимое буфера клавиатуры при нажатии специальной клавиши, например F1.
1.Код ASCII, скан-код
2.Код ASCII, код 00
3.Код 00, кодASCII
4.Код 00, скан-код
11. Укажите функцию, не выполняемую обработчиком прерывания Int 9h.
1.Передачу 2х-байтного кода в буфер клавиатуры
2.Сохранение содержимого регистров процессора
3.Сбрасывание запроса прерывания
4.Вычисление адреса вектора прерывания.
Литература
1. Авдеев В.А. Периферийные устройства: интерфейсы, схемотехника, программирование Учеб. пособие. М.: ДМК Пресс , 2009.-848 с.: ил.
2. Сопряжение датчиков и устройств ввода данных с компьютерами IBM PC: Пер. с англ./ Под ред. У. Томпкинса, Дж. Уэбстера.-М.: Мир, 1992.-592с. :ил.
Документ
Категория
Рефераты
Просмотров
38
Размер файла
1 022 Кб
Теги
лабор, раб, текст
1/--страниц
Пожаловаться на содержимое документа