
МИНОБРНАУКИ РОССИИ
Санкт-Петербургский государственный
электротехнический университет
«ЛЭТИ» им. В.И. Ульянова (Ленина)
Кафедра вычислительной техники
отчет
по лабораторной работе №4
по дисциплине «Организация ЭВМ и систем»
Тема: клавиатура ibm pc. Использование прерываний
Студенты гр. 3352 |
|
|
Преподаватель |
|
|
Санкт-Петербург
2024
Краткие сведения о подсистеме ввода информации с клавиатуры, используемых прерываниях, буфере клавиатуры и функциях обслуживания ввода с клавиатуры
1.1
Большинство программ осуществляют ввод данных с клавиатуры. Этот процесс может быть реализован на трех уровнях: через функции MS-DOS, функции BIOS или с помощью прямого доступа к аппаратным средствам.
Ввод на уровне MS-DOS позволяет обрабатывать клавиатурный ввод через драйверы, отслеживать нажатия комбинаций клавиш Ctrl-C (Ctrl-Break), стандартную для MS-DOS обработку ошибок. Доступ на уровне BIOS даёт возможность отслеживать нажатия всех клавиш и управлять аппаратурой клавиатуры. Функция bioskey() в Turbo C обеспечивает интерфейс с BIOS.
Прямой доступ к буферу клавиатуры значительно увеличивает производительность программ. В некоторых случаях требуется имитировать нажатия клавиш, записывая коды напрямую в буфер, при этом физическое нажатие клавиш не происходит. Это принцип, на котором основаны демонстрационные программы, открывающие или закрывающие меню и выполняющие выборы в «автоматическом» режиме. Также к этому подходу относятся программы, которые позволяют переносить текст одним нажатием клавиши. Пример такой программы — входящая в Turbo С резидентная Help-система THELP.COM в Turbo C.
1.2
Клавиатура ПК оснащена встроенным микропроцессором, который при каждом нажатии и отпускании клавиши определяет её порядковый номер и отправляет его в порт 60h программируемого периферийного интерфейса (ППИ). Этот код называется скэн-кодом. Первые 7 бит скэн-кода представляют номер клавиши, а восьмой бит указывает, была ли клавиша нажата (0) или отпущена (1). После записи скэн-кода в порт 60h ППИ отправляет сигнал "подтверждения" микропроцессору клавиатуры.
Если клавиша удерживается дольше времени задержки (delay value), микропроцессор клавиатуры начинает генерировать прямой скэн-код с заданной частотой (typematic rate). Параметры задержки и частоты повторения можно установить через порты клавиатуры или с помощью функции АН = 03h прерывания 16h BIOS. Когда скэн-код принят ППИ, компьютер генерирует аппаратное прерывание с номером 9.
Стандартный обработчик прерывания 9 входит в состав BIOS (BIOS ISR), который анализирует скэн-код и преобразует его по определённым правилам. По скэн-коду можно определить, вызвано ли прерывание нажатием или отпусканием клавиши.
Клавиши в зависимости от алгоритма обработки их скэн-кода можно разделить на:
шифт-клавиши (Right-Shift, Left-Shift, Alt, Ctrl);
триггерные клавиши (NumLock, ScrollLock, CapsLock);
клавиши с буферизацией расширенного кода;
специальные клавиши (клавиша PrnScr, комбинация Alt-Ctrl-Del, комбинация Ctrl-C (Ctrl-Break)).
За каждой шифт- или триггерной клавишей закреплен свой бит в ячейках памяти по адресам 40: 17h и 40: 18h. При каждом нажатии или отпускании шифт-клавиши ISR BIOS инвертирует соответствующий бит. Таким образом, текущее состояние бита шифт-клавиши говорит о том, нажата она в данный момент или отпущена. За триггерными клавишами закреплены два бита: один из них инвертируется только при нажатии клавиши ("фиксирует" состояние "Вкл/Выкл"), другой - при нажатии и отпускании, отслеживая текущее состояние клавиши.
Текущее состояние шифт- и тригтерных клавиш используется BIOS-обработчиком прерывания от клавиатуры при определении правил преобразования скэн-кодов от других клавиш. Большинство клавиш и их комбинаций с шифт-клавишами - это клавиши с буферизацией расширенного кода: при их нажатии в специальный буфер памяти помещается двухбайтовый код, называемый BIOS-кодом клавиши. Младший байт этого кода равен ASCII-коду символа, либо нулю. Старший байт равен скэн-коду клавиатуры, либо так называемому расширенному скэн-коду.
Двухбайтовый BIOS-код вида “0 / расширенный скэн-код” генерируется и записывается в буфер клавиатуры при нажатии клавиш Fl - F12, Ins, Del, клавиш управления курсором Home, Up, PgUp, Left, Right, End, Down, PgDn и их комбинации с клавишами Alt, Ctrl, Shift, а также при нажатии комбинации Alt-ASCII-клавиша. Значение расширенного скэн-кода определяется технической документацией BIOS, причём по правилам BIOS расширенный скэн-код и скэн-код от клавиатуры не совпадают.
Особым образом обрабатывается так называемый Alt-ввод. Если нажимается и удерживается нажатой клавиша Alt и на цифровой клавиатуре набираются цифры, то после отпускания клавиши Alt в буфер клавиатуры помещается двухбайтовый код, старший байт которого равен нулю, а младший байт содержит набранный цифрами код. Если набранный код больше 256, младший байт равен остатку от деления набранного кода на 256. Большинство прикладных программ обрабатывают ASCII-коды, сгенерированные простым нажатием клавиши и Alt-вводом одинаково, несмотря на различные старшие байты двухбайтового кода в буфере клавиатуры. Например, при нажатии клавиши 'Z' в буфер клавиатуры записывается "ASCII-код/скэн-код": 90/44, а при нажатии Alt-90 - "ASCII-код/0": 90/0. Alt-ввод очень удобен для ввода ASCII-символов, не имеющих соответствующих клавиш, например символов псевдографики.
1.3
Буфер BIOS для записи кодов клавиш занимает 32 байта оперативной памяти по адресам 40:1Eh до 40:3Eh. Запись осуществляет ISR BIOS прерывания 9, а чтение — ISR прерывания 16h. Буфер вмещает 15 нажатий клавиш с двухбайтовыми кодами (30 байт) и 2 байта для кода клавиши ENTER.
Буфер реализован как кольцевая очередь с указателями «головы» (head pointer) по адресу 40:1Ah и «хвоста» (tail pointer) по адресу 40:1Ch. Указатель «хвоста» указывает на позицию, куда будет записан код клавиши, а указатель «головы» — на слово, которое вернёт запрос на ввод.
При каждом нажатии клавиши с двухбайтовым кодом ISR прерывания 9 записывает код в память и увеличивает указатель «хвоста» на 2. Если указатель «хвоста» достигает конца буфера (40:3Eh), он возвращается к началу (40:1Eh). В случае, если указатели «головы» и «хвоста» равны, буфер переполнен, и дальнейшие нажатия игнорируются, при этом звучит сигнал.
Указатель «головы» используется при чтении буфера через ISR прерывания 16h. Если происходит чтение с разрушением информации (функция АН = 0 прерывания 16h), считываются 2 байта, и указатель «головы» увеличивается на 2. Если указатели равны, буфер пуст, и ISR прерывания 16h заходит в бесконечный цикл ожидания, прерываемый нажатиями клавиш. При чтении без разрушения информации (функция АН = 1) указатель «головы» не изменяется, и код передаётся, если буфер не пуст. Если он пуст, устанавливается флаг переноса CF, и обработка завершается.
Таким образом, буфер клавиатуры демонстрирует использование кольцевого буфера для асинхронного взаимодействия между двумя программами: производителем (ISR BIOS прерывания 9) и потребителем (функция АН = 00h прерывания 16h). Это взаимодействие асинхронно, что предотвращает перезапись непрочитанных данных.
1.4
Функции библиотеки С++ (см. табл. 1):
int getch (void)
Выполняет ввод с клавиатуры через функцию MS-DOS АН=07h. Она не выполняет "эхо" вывода на экран. В этой связи полезна для организации интерфейса с пользователем, при котором нажатие той или иной клавиши вызывает немедленную реакцию программы без отображения введенного символа на экране.
int getche (void)
Выполняет небуферизуемый ввод с клавиатуры через функцию MS-DOS AH=07h, но в отличие от предыдущей функции обеспечивает вывод введенного символа на экран. Перевод строки происходит при достижении правой вертикальной границы текущего активного окна.
char *getpass(char * prompt)
Выводит на экран ASCII-строку, на начало которой указывает prompt, a затем принимает с клавиатуры без "эха" строку символов. Вводимые символы (не более 7) помещаются во внутреннюю статическую память. Функция возвращает указатель на внутреннюю статическую строку, переопределяемую каждым новым обращением к функции. Основное назначение данной функции - ввод паролей в программе без отображения их на экран.
int kbhit (void)
Проверяет, пуст ли буфер клавиатуры. Если в буфере есть символы, функция возвращает ненулевое значение, в противном случае она возвращает 0. Использует функцию 0Bh MS-DOS. Является удобным средством предотвращения "зацикливания" при ожидании невозможного в данный момент события. Кроме того, при выполнении функции 0Bh осуществляется проверка нажатия комбинации клавиш Ctrl-Break, что позволяет выполнить аварийное завершение программы.
1.5
Интерфейсом программ в персональном компьютере с клавиатурой является прерывание 16h BIOS. Eго функции описываются следующим образом.
АН = 00h - чтение с ожиданием двухбайтового кода из буфера клавиатуры. Прочитанный код возвращается в регистре АХ: младший байт - в регистре AL, старший - в АН. Если нажата ASCII-клавиша, в AL помещается ASCII-код символа, в АН - скэн-код. При нажатии специальных клавиш AL равен 0, а в АН возвращается расширенный скэн-код.
АН = 0lh - чтение без ожидания двухбайтового кода из буфера клавиатуры. Если буфер пуст, в 1 выставляется флаг нуля ZF. В противном случае в АХ возвращается двухбайтовый код из буфера клавиатуры, но продвижение указателя "головы" буфера не производится, т.е. код "остается" в буфере.
АН = 02h - определение состояния шифт- и триггерных клавиш. В регистре AL возвращается содержимое байта по адресу 40:17h.
Функция АН = 05h не имеет аналогов в библиотеке Turbo С и может использоваться для имитации нажатии клавиш в демонстрационных программах, программах переноса текста и т.д.
Функции АН = 10 - 12h являются аналогами функций 00 - 02h, но предназначены для использования в компьютерах с клавиатурой 101 /102 клавиши.
Функции АН = 00 - 02h прерывания 16h BIOS положены в основу функции bioskey() библиотеки Turbo С. Далее следует описание этой функции.
int bioskey(int cmd)
Обращается в зависимости от значения в cmd к функциям АН = 00 - 02h прерывания 16h. Возвращаемое функцией значение повторяет значение регистра АХ при выходе из прерывания.
Таблица 1 - Функции для работы с вводом/выводом
getch (void) |
Считать клавишу без «эха» |
getche (void) |
Считать клавишу |
kbhit (void) |
Проверка, пуст ли буфер |
bioskey(int cmd) |
Считывание через прерывания |