old_4a hour db min db sec data stk |
dd 0 0,0,':' 0,0,':' 0,0 |
db ends segment stack dw 128 dup(') ends end main |
stk |
;Ячейка для исходного вектора;Поле для формирования;строки ASCII с текущим;временем
В примере 3-9 используются несколько команд, отсутствующих в МП 86: команды сохранения в стеке и восстановления всех регистров общего назначения pusha и рора, а также команда сдвига shl с числовым операндом. Для того, чтобы эти команды распознавались ассемблером, в про-
Команды и алгоритмы___________________________________________________ 145
грамму включена директива.586 (можно было бы обойтись и директивой.386). В этом случае необходимо оба сегмента объявить с описателем use!6.
Программа состоит из главной процедуры main, процедуры new_4a обработчика прерываний от будильника, а также трех вспомогательных процедур-подпрограмм addjime, add_unit и conv. Главная процедура сохраняет исходный вектор прерывания 4Ah, устанавливает новый обработчик этого прерывания, читает текущее время и устанавливает будильник на время, отстоящее от текущего на 1 секунду, а затем останавливается в ожидании нажатия любой клавиши. Пока программа стоит, обрабатываются прерывания от будильника и в правый верхний угол экрана каждую секунду выводится текущее время. После нажатия любой клавиши программа завершается, предварительно сбросив будильник и восстановив исходное содержимое вектора 4Ali.
Легко видеть, что в предложенном варианте программа имеет мало практического смысла, так как она не выполняет, кроме вывода времени, никакой полезной работы. В то же время, пока эта программа не завершилась, запустить другую программу нельзя, так как DOS является однозадачной системой. Если, однако, написать нашу программу в формате.СОМ и сделать ее резидентной, мы получим возможность запускать любые программы и одновременно наблюдать на экране текущее время. Такого средства в DOS нет, и в какой-то ситуации оно может оказаться полезным. Методика разработки резидентных программ описана выше; читатель может выполнить необходимые преобразования самостоятельно.
Рассмотрим теперь программу обработчика прерываний будильника. Прежде всего в нем командой pusha (push all, сохранить все) сохраняются все регистры общего назначения и, кроме того, два сегментных регистра DS и ES, которые будут использоваться в обработчике. Далее регистр DS настраивается на сегментный адрес того сегмента, в который входит ячейка hour, т.е. фактически на наш* сегмент команд. На первый взгляд это действие может показаться бессмысленным. Ведь в начале процедуры main в регистр DS уже был помещен адрес нашего сегмента данных data. Зачем же эту операцию повторять' Дело в том, что процедура new_4a, будучи формально обработчиком программного прерывания 4Ап, фактически представляет собой обработчик аппаратного прерывания от часов реального времени, которое, как и любое аппаратное прерывание, может придти в любой момент времени. В принципе прерываемая программа в этот момент может выполнять любые действия, и содержимое регистра DS может быть любым. Если же говорить о нашей программе, то она находится в цикле ожидания нажатия клавиши. Этот цикл организует функция ОШ DOS, которая, между прочим, время от времени обращается к своему Драйверу клавиатуры, а тот — к программам BIOS ввода символа с клавиатуры. Вполне вероятно (а на самом деле так оно и есть), что при выполнении упомянутых операций используется регистр DS, который в этом случае указывает уже не наш сегмент данных, а не различные системные области. Другими словами, при входе в обработчик прерывания содержимое регистра DS неизвестно, и его следует инициализировать заново, обязательно сохранив исходное значение. Если перед выходом из обра-
Глава '3
ботчика это исходное значение не восстановить, будет неминуемо разрух шсна DOS.
Сохранив регистры и настроив DS, мы вызываем функцию 02h прерывания 1АИ чтения текущего времени. Время возвращается, как уже говорилось, в упакованном двоично-десятичном формате (по две цифры в байте) в регистрах СН (часы), CL (минуты) и DH (секунды). Нам это время понадобится еще раз в конце обработчика для установки будильника заново, и чтобы второй раз не вызывать функцию 02h, полученное время (т.е. содержимое регистров СХ и DX) сохраняется в стеке.
Далее выполняется последовательное преобразование BCD-цифр, состашотощих время, в коды ASCII соответствующих символов. Число часов (две упакованные BCD-цифры) переносится в регистр AL, и вызывается подпрограмма conv, которая преобразует старшую цифру часов в код ASCII и возвращает его в регистре АН. Этот код помещается в объявленную в сегменте данных строку-шаблон hour, в которой заготовлены пустые пока места для символов цифр, составляющих время, а также имеются разделительные двоеточия. Для удобства обращения к элементам этой строки, она разделена на части и каждая часть снабжена собственным именем — min для поля минут и sec для поля секунд.
Подпрограмма conv преобразования BCD-цифры в код ASCII состоит всего из трех предложений, не считая заключительной команды rcl. Двух-разрядиос BCD-число перелается в подпрограмму в регистре AL. После обнуления регистра АН, который будет служить приемником для образования конечного результата, содержимое AL сдвигается командой shl влево на 4 бит, в результате чего старший полубайт регистра AL, т.е. старшая цифра числа, перемещается в регистр АН (рис. 3.10). Двоично-десятичная цифра представляет собой просто двоичное представление цифры; прибавление к се коду кода символа "О" (числа ЗОИ) дает код ASCII этой цифры. Мы преобразовали пока только старший полубайт регистра СН. Для выделения младшего полубайта на регистр СН накладывается маска OFh,
АН
AL
| 0101 | 0111 PerHcip.AX до сдвига
5 7 =57 (BCD)
АН
AL
0111 | |
Регистр.АХ после сдвига
ООП 0000
Прибавление '0'= 30h
АН
ООП I 0101 I Регистр АН после прибавления 'О'
3 5 35h = код ASCII цифры 5
Рис. ЗЛО. Алгоритм работы подпрограммы conv.
Командной алгоритмы___________________________________________________ 147
которая обнуляет старший полубайт, не затрагивая младшего. Прибавление кода ASCII нуля к коду десятичной цифры образует код' ASCII этой цифры, который и переносится затем в строку-шаблон. Описанная процедура повторяется затем для регистров CL (минуты) и DH (секунды).
Для вывода строки с временем на экран используется прямое обращение в видеопамяти. В регистр ES заносится сегментный адрес видеобуфера BSOOh, а в регистр DI — требуемое смещение видеопамяти к тому месту, начиная с которого мы хотим вывести строку. В регистр SI заносится адрес строки-источника, в регистр СХ — число шагов, а в регистр АН — выбранный нами атрибут символов (красные символы по синему полю). Поскольку перемещение и по строке-шаблону, и по экрану должно осуществляться вперед, командой eld сбрасывается флаг DF. Наконец, циклическое выполнение пары команд
lodsb stosw
приводит к выводу в заданное место экрана всей строки hour.
Выполнив вывод на экран текущего времени, надо снова установить будильник. Для этого сначала запрещается работа ранее установленного будильника, восстанавливается текущее время в регистрах DX и СХ, и вызовом процедуры add_time к текущему времени прибавляется 1 секунда. Далее вызовом функции 06h заново устанавливается будильник, восстанавливаются сохраненные в начале программы обработчика регистры, и, наконец, командой irct обработчик завершает свою работу.
Рассмотрим теперь процедуру прибавления 1 к текущему времени. Она состоит из двух компонентов — подпрограммы add_time, которая организует правильное сложение чисел, обозначающих время, чтобы прибавление I секунды к 59 секундам дало 0 секунд и увеличило на 1 число минут {и то же самое для минут) и подпрограммы add_unit, выполняющей прибавление 1 к упакованному коду BCD.
Подпрограмма add_time переносит число секунд из DH в AL, с помощью подпрограммы add_unit увеличивает его на 1 и возвращает в DH. Подпрограмма add_unit сигнализирует установкой флага CF о необходимости переноса 1 в следующий разряд времени (число секунд составляло 59). Поэтому после возврата из add_init проверяется флаг CF и, если он сброшен, т.е. следующий разряд времени модифицировать не надо, подпрограмма addjime завершается. Если же флаг CF устаноатсн, выполняется аналогичная процедура прибавления 1 к числу минут, которое находится в регистре CL. Дачсе опять анализируется флаг CF, и если он установлен (текущее время было 59 мин 59 с), прибавляется 1 к числу часов. Наконец, подпрограмма завершается командой ret.
Подпрограмма add_uuU получаст упакованное двоично-десятичное число, к которому надо прибавить 1, в регистре AL. Командой add к нему Прибавляется 1, после чего в некоторых случаях образуется правильная сумма, а в некоторых — неправильная. Так, I4h + 1 = I5h, что правильно, однако 19h + 1 = IAh, что неверно. Такого двоично-десятичного числа не существует, а после прибавления 1 к 19 должно получиться 20 (и записа-
148_______________________________________________________ Глава 3
но в виде 20h). Коррекцию после сложения BCD-чисел осуществляет команда daa, которая в приведенном примере преобразует lAh в 20h, и которая должна всегда следовать за командой сложения.
Наши двоично-десятичные числа специфичны в том отношении, что они не могут превышать 59. Поэтому после коррекции результат сравнивается с 60h. Если сумма меньше 60h, флаг CF сбрасывается и выполняется команда ret. Если сумма равна 60h, регистр AL обнуляется, флаг CF устанавливается, сигнализируя о переносе 1 в следующий разряд времени (минут или часов) и выполняется та же команда ret. Таким образом, флаг CF процессора в точке возврата из подпрограммы add_unit говорит не о начичии или отсутствии арифметического переноса, а выполняет роль флага «исключительной ситуации» — перехода времени на следующую минуту или на следующий час. Такое нестандартное использование флага CF является общеупотребительным приемом.
3.6. Программирование аппаратных средств
Программирование аппаратуры — как штатных периферийных устройств компьютера, таких, как видеосистема, клавиатура, последовательный или параллельный интерфейс и др., так и нестандартных измерительных или управляющих устройств, подключаемых к компьютеру, если он используется для автоматизации научных исследований или управления технологическим процессом — является одним из важнейших и наиболее оправданных применения языка ассемблера. Во-первых, от программ управления аппаратурой часто требуется максимальное быстродействие. Во-вторых, эти программы, призванные управлять аппаратурой на низком уровне, путем обращения к регистрам и их отдельными битам, часто ничего не выигрывают от использования языков высокого уровня, в которых тс же операции реализуются с помощью процедур языка, менее наглядных и эффективных, чем «чистые» команды процессора. В-третьих, при программировании аппаратуры, особенно, экспериментальной, важно жестко соблюдать временную и событийную последовательность команд и сигналов, воспринимаемых программируемым устройством, что естественным образом достигается при использовании языка ассемблера, в котором каждое предложение языка реализуется вполне определенной командой процессора.
В зависимости от назначения и способа функционирования аппаратуры, она может требовать различных режимов программного управления. В основном существуют три режима, или способа взаимодействия программы и аппаратуры: режим свободного доступа, режим ожидания готовности и режим прерываний.
Режим свободного доступа используется в тех случаях, когда момент обращения к устройству целиком определяется программой. Например, регистры, управляющие работой аппаратуры, обычно доступны в любой момент времени. Программа может в любой момент прочитать содержимое этих регистров и определить по нему текущий режим работы устройства, или, наоборот, послать в управляющие регистры требуемую последовательность команд с целью изменения рабочего режима.
Команды и алгоритмы___________________________________________________ 149
Режим ожидания готовности необходимо использовать в тех случаях, когда после приема некоторой команды устройству требуется определенное время для ее выполнения. Например, в последовательный порт, через который компьютер связывается с другими компьютерами или телефонной сетью, нельзя посылать следующую порцию информации (байт), пока устройствами последовательного интерфейса не будет отправлена в канал связи предыдущая порция. Режимом ожидания готовности часто пользуются для приема информации из измерительной аппаратуры, если требуется обеспечить максимальную скорость ее получения.
Режим прерываний является важнейшим способом связи с относительно медленным периферийным оборудованием. В этом случае устройство подключается не только к линиям адресов, данных и управления системной магистрали компьютера, но и к одной из специально выделенных линий прерываний. В режиме прерывания устройство само решает, когда ему требуется обслуживание, и посылкой в компьютер сигнала прерывания оповещает об этом процессор. Типичным примером является клавиатура, посылающая сигнал прерывания каждый раз, когда пользователь нажимает на ту или иную клавишу. Большая часть штатных устройств компьютера — мышь, диски, таймер и др. — используют режим прерываний. Типичен этот режим также и для связи с измерительной аппаратурой в тех случаях, когда аппаратура регистрирует относительно редкие события, или измерительные данные накапливаются в аппаратуре в течение заметного времени и затем пересылаются в компьютер сразу целой пачкой.
Как уже отмечалось в гл. 1, связь с аппаратными средствами самого компьютера, а также с подключаемыми к нему устройствами осуществляется главным образом через адресное пространство ввода-вывода. Это значит, что за каждым устройством закрепляется один или, чаще, несколько портов, и программирование устройства осуществляется исключительно с помощью команд in и ou.t (а также ins и outs, если программи-)уемое устройство может посылать данные потоком).
В простейшем случае программирование устройства сводится к вы-толнению единственной команды in в случае чтения из устройства, или out в случае записи в него. Рассмотрим, например, процедуры маскирования и размаскирования аппаратных прерываний. В каждом из двух контроллеров прерываний, включаемых в состав компьютера, имеется регистр маски (рис. 3.11). Значение 0 в бите маски разрешает прохождение сигнала прерывания, значение 1 запрещает. Пройдя через маску и через последующие узлы контроллера прерываний (не показанные на рис. 3.11), сигнал прерываний поступает на вход INT микропроцессора. Программирование регистров маски осуществляется через порт 21h для ведущего контроллера и Alh для ведомого.
Исходное значение маски устанавливается программами начальной загрузки компьютера в зависимости от конфигурации вычислительной системы. Типичным является значение A8h, показанное на рис. 3.11. При этом значении маски размаскированными оказываются системный таймер, клавиатура, мышь, подключенная к первому последовательному порту
Глава з
Ah |
Таймер. IRQO
Клавиатура. IRQ1
Выход ведомого. IRQ2
Последовательный порт COM2. IRQ3
Последовательны и портСОХП, IRQ4
Параллельный порт LPT2, IRQ5
Гибкий диск, IRQ6
Паралелльный порт LPT1, IRQ7
На вход IN Т процессора
Маска ведущего контроллера
прерываний, порт 21h
Рис. 3.11. Регистр маски ведущего контроллера прерываний.
СОМ1, гибкий диск, а также выход от ведомого контроллера, подключаемый ко входу IRQ2 ведущего. Замаскированы оба парачлельного порта (принтер, подключаемый к порту LPT1, обычно не использует прерываний, а второй параллельный порт часто просто отсутствует) и второй последовательный порт, к которому ничего не подключено. Другими словами, размаскировано все нужное, и замаскировано все ненужное.
В'ряде случаев возникает необходимость замаскировать прерывания от системного таймера, который является единственным постоянно активным источником прерываний. Такая ситуация типична, в частности, для автоматизированных измерительных систем, в которых недопустимо прерывать поток данных, поступающих от измерительной установки в компьютер. Любое прерывание процесса приема данных может привесит к потере части принимаемой информации и нарушению работы установки. Для запрета прерываний от таймера надо выполнить такую последовательность команд:
in AL,21h;Чтсние регистра маски
or AL,1;Установка I в битс О
out 21h,AL;3апись нового значения маски
Восстановление исходного состояния вычислительной системы с разрешенными прерываниями от таймера осуществляется следующим образом:-
in AL,21h.;Чтснис регистра маски, =
and AL,OFEh;Установка 0 в битс О
out 21h,AL;3апись нового значения;маски
Другим примером использования режима свободного доступа к устройству яштлстся программирование энергонезависимой КМОП-микро-схемы, включающей в себя часы реального времени, о которых уже говорилось в разделе 5 этой главы, а также информацию о конфигурации компьютера и в некоторых случаях пароль. Общий объем КМОП-памяти составляет 64 байт (от ООп до 3Fli); доступ к байтам КМОП-памяти осуществляется через порты 70h и 71h,
В КМОП-микросхеме реализован способ обращения к ее отдельным ячейкам, широко используемой в микропроцессорной технике. Если про-
манды и алгоритмы
траммировать КМОП-память прямым образом, для обращения к ее 64 ячейкам в адресном пространстве ввода-вывода пришлось бы выделить 64 адреса. Для сокращения числа используемых адресов в состав микросхемы введены два служебных регистра — адресный и данных. В адресный регистр (порт 70h) заносится номер той ячейки КМОП-памяти, к которой требуется обращение. После этого чтение регистра данных (порт 71h) позволяет прочитать содержимое выбранной ячейки, а запись в регистр данных выполняет передачу данного в эту ячейку. Приведем полный текст программы, которая читает содержимое ячейки с номером ODh. В ней хранится состояние батареи, питающей КМОП-микросхему. Если бит 7 этой ячейки установлен, батарея исправна; если этот бит сброшен, напряжение батареи упало ниже допустимого предела,.и ее надо менять.
ячейки КМОП-микросхемы cs:code ;Будем читать ячейку ODh;3адание номера ячейки;чтение из ячейки; Проверка бита 7;Бит 7=1, перейти на ОК;Бит 7 = 0, питания нет;Выведем в знак этого;Символ минус;Переход на завершение;Батарея в порядке,;выведем в знак этого;символ плюс |
;Пример 3-10. Чтение code segment
assume main proc
mov AL,ODh
out 70h,AL
in AL,71h
test AL,80h
jnz ok
mov AH,02h
mov DL,'-'
int 21 h
jmp exit ok: mov AH,02h
mov DL,*+*
int 2 Hi;3авершим программу exit: mov AX,4COOh
hit 21h main endp code ends
end main
Рассмотрим теперь программирование периферийного оборудования в режиме ожидания готовности на примере параллельного интерфейса. В стандартной конфигурации компьютера к параллельному' интерфейсу обычно подключается принтер, однако его можно использовать и для связи с нестандартным (измерительным или управляющим) оборудованием.
В компьютерах используется разновидность параллельного интерфейса под названием Centronics, отличающаяся относительно высокой скоростью передачи данных (до 150 Кбайт/с) и простотой программирования. Правда, Centronics позволяет передавать данные только в одном направлении — из компьютера в устройство, однако эту проблему- можно частично решить, сети воспользоваться для приема данных линиями состояния интерфейса.
Глава 3
Разумеется, в установке, подключаемой к компьютеру через параллельный интерфейс, должно быть предусмотрено устройство сопряжения, воспринимающее и вырабатывающее сигналы обмена с интерфейсом.
Интерфейс Centronics подключается к периферийному устройству (принтеру) с помощью кабеля, содержащего 17 сигнальных линий и несколько линий нуля. Управление интерфейсом осуществляется через три закрепленных за ним порта: порта данных с адресом 378И, порта состояния принтера с адресом 379h и порта управления принтером с адресом 37AU. Порты фактически предстаатяют собой 8-разрядные регистры, биты которых соответствуют сигнштам интерфейса. Некоторые из этих сигналов, конкретно, сигналы портов данных и управления, являются для интерфейса выходными; их должна устанавливать программа, упрашгяющая передачей информации. Другие сигначы, наоборот, поступают из периферийного устройства и отображаются в состоянии закрепленных за ними битов порта состояния; программа должна читать и анализировать эти биты.
На рис. 3.12 показаны порты интерфейса Centronics с указанием сигналов, соответствующим конкретным битам.
378Н Порт данных
379h Порт состояния 765432 10 | ||
1 1 1 | ||
| | ||
D7...DO Байт данных
ERROR' 0-ошибка
SLCT 1 = принтер выбран
РЕ 1 = нет бумаги
АСК' 1 = готов к приему следующего символа.
если BUSY сброшен BUSY* 0 = принтер занят, 1 = свободен
37Ah Порт управлсш!я
1 1
STROBE 1 = при посылке байта
AUTO I = LF после CR
INIT 0 = отключение принтера
SLCTIN 1 = выбор принтера
IRQ 1 = разрешение прерываний
Направление передачи
для двунаправленного интерфейса
Рис. 3.12. Порты интерфейса Centronics.
Команды и алгоритмы
Программирование параллельного интерфейса требует некоторых сведений о его протоколе, т.е. последовательности и взаимодействии сигна-юв, которыми интерфейс обменивается с подключенным к нему устрой->м. Некоторые из этих сигналов имеют узко специализированное на-шчение и возникают лишь в особых случаях (например, сигнал РЕ — >нец бумаги), другие же принимают обязательное участие в процедуре гередачи данных. К последним относятся 8 бит данных и три управляющих сигнала STROBE', BUSY и АСК" (рис. 3.13).
Интерфейс Г™"07 -принтер ISTROBE, |
|_ Принтер занят \ обработкой байта |
Принтер - I BUSY интерфейс
\__ Принтер готов
принять
следующий
байт
Рис. 3.13. Протокол передачи данных для интерфейса Centronics.
Сигнал BUSY считается активным, когда он имеет высокое значение. В противоположность этому активное состояние сигналов STROBE' и АСК' низкое, отчего они и обозначаются с тем или иным дополнительным значком (с чертой наверху, со знаком минус или с апострофом, как у нас). Прослеживая соответствие сигналов интерфейса состоянию битов его портов, необходимо иметь в виду, что для некоторых сигналов (SLCT, РЕ, STROBE) в порты записываются их прямые значения, а для других (ERROR, АСК, BUSY) — инверсные.
Вывод на принтер каждого байта данньгх состоит из трех этапов. Прежде всего программа должна дождаться неактивного состояния сигналов BUSY и АСК (это и есть ожидание готовности устройства). Убедившись, что биты 6 и 7 порта состояния 379h устаноатсны в 1 (см. рис. 3.12), программа посылает в порт данных 378h байт данных, что приводит к установке кода данных на линиях интерфейса D7...DO. Наконец, программа должна установить на короткое время сигнал STROBE, что реализуется путем установки и затем сброса бита 0 порта управления 37Ali. Следующие байты посылаются точно таким же образом.
Выполняя все эти операции, необходимо учитывать временные характеристики интерфейса. Сигнал STROBE можно посылать в порт управления не ранее, чем через 0,5 мкс после установки данных, что может потребовать введению в программу небольшой программной задержки {одной или нескольких команд jmp, см. приведенный ниже текст программы). То же относится и к длительности сигнала STROBE, которая не должна быть меньше той же величины 0,5 мкс. Практически программные задержки часто оказываются не нужны.
Глава J
Обратимся еще раз к рис. 3.13. Принтер, сняв с линий данных байт данных, и начав его обработку (вывод на печать или сохранение во внутренней памяти), устанавливает ответный сигнал BUSY, действующий все время, пока принтер занят обработкой байта данных. Закончив обработку байта, принтер на некоторое время устанавливает сигнал АСК и сбрасывает сигнал BUSY. Окончание сигнала АСК (при сброшенном состоянии сигнала BUSY) говорит интерфейсу об окончании данной операции обмена и о возможности посылки следующего байта данных. Ввиду краткости сигнала АСК часто оказывается, что ожидать его снятия нет необходимости; достаточно дождаться неактивного состояния сигнала BUSY (т.е. 1 в бите 7 порта состояния). Вообще следует заметить, что различные принтеры могут несколько по-разному выполнять свою часть протокола обмена. Рассмотренный ниже пример отлаживался на принтере Epson LQ-100.
Приведем текст программы, в которой принтер программируется, как говорят, на физическом уровне, т.е. путем обращения к его портам. Разумеется, в большинстве случаев для вывода на принтер текста из выполняемой программы проще воспользоваться функциями DOS. Однако в некоторых специальных случаях приходится прибегать и к программированию через порты, например, если принтер используется в нестандартном режиме, или параллельный интерфейс служит для связи с нестандартным устройством.
;Пример 3-11. Программирование параллельного интерфейса code segment
assume cs:code
main | proc | |
raov | CX,10 | |
mov | DX,379h | |
waitl: | : in | AL,DX |
and | AL,OCOh | |
cmp | AL,OCh | |
jne | waitl | |
sym: | mov | AL,**' |
mov | DX,378h | |
out | DX.AL | |
mov | DX,37Ah | |
in | AL,DX | |
jmp | S+2 | |
or | AL,1 | |
out | DX,AL | |
jmp | S+2 | |
and | AL,OFEh | |
out | DX,AL | |
loop | sym |
;3авершим программу
; Повторить 10 раз
;Порт состояния t
;Чтснис состояния
;Оставим только биты 7 (BUSY)
;и 6 (АСК), замаскировав бит 4 (SLCT)
;BUSY=ACK=1'
;Нст, продолжать опрос порта
;Символ для печати
;Порт данных
;Вывод символа
;Порт управления
;Читаем из порта. Лам CCh
;(SLCT IN =1, INIT=1)
;Нсбольшая задержка
Останавливаем сигнал STROBE
;Впорт
;Небольшая задержка
;Сбрасывасм сигнал STROBE
;Впорт
;Цикл
Команды и алгоритмы___________________________________________________ 155
В приведенном примере предполагается, что принтер выбран и установлен в исходное рабочее состояние, что обычно выполняется автоматически при его включении. Свидетельством этого будут установленные биты 2 и 3 (SLCT IN и INIT) в порте управления, а также бит 4 (SLCT) в порте состояния. В программе не выполняется анализ байта состояния на натачие ошибки или конца бумаги, что при работе с принтером, вообще говоря, следует предусматривать.
Третий метод программирования периферийного устройства — режим прерываний — рассмотрим на примере обработки прерывания от мыши. Как известно, мышь обычно подключается к первому последовательному порту СОМ1 и работает в режиме прерываний. Нажатие или отпускание любой клавиши, так же, как даже минимальное перемешение по столу, вырабатывает сигналы прерываний, сопровождаемые определенными кодами, которые поступают в порт данных интерфейса. Написав собственный обработчик прерываний для последовательного порта, мы получим возможность выполнять заданные действия, например, при нажатии левой и правой клавиш мыши. Следует подчеркнуть, что эти действия начнут выполняться практически в тот же момент, когда мы нажали на клавишу. В приведенной ниже программе при нажатии левой клавиши в центр экрана выводится цветная надпись «Левая!», а при нажатии правой клавиши — надпись «Правая» другого цвета.