4. Клавиатура IMB PC. Использование прерываний
.docxМИНИСТЕРСТВО НАУКИ И ВЫСШЕГО ОБРАЗОВАНИЯ РФ
Санкт-Петербургский государственный
электротехнический университет
«ЛЭТИ» им. В.И. Ульянова (Ленина)
отчЁт
по лабораторной работе №4 (вариант 7)
по дисциплине «Организация ЭВМ и систем»
Тема: Клавиатура IMB PC. Использование прерываний.
Студент гр. 9300 |
ФИО |
Преподаватель |
Лебедев С. В. |
Санкт-Петербург
2020
Цель работы.
Изучить работу с клавиатурой, ознакомиться со стандартными средствами библиотеки C++ и средствами системы прерываний DOS и BIOS, обслуживающих клавиатуру.
Задание.
Разработать, написать и отладить две версии программы управления постоянным перемещением символа «X» в пределах окна с параметрами 20, 8, 60, 18. Для управления использовать клавиши F9, F10, F11, F12.
Первую версию программы написать с использованием стандартных функций ввода языка C++. Вторую версию — с использованием прерывания INT 16h.
Краткие сведения.
Подсистема ввода информации с клавиатуры.
Клавиатура содержит специальный встроенный микропроцессор. Он при каждом нажатии и отпускании клавиши определяет её скэн-код и помещает его в порт 60h ППИ. Скэн-код в первых 7 битах содержит порядковый номер нажатой клавиши, а восьмой бит равен 0, если клавиша была нажата, и равен 1, если клавиша была отпущена. Когда скэн-код записан в порт 60h, ППИ выдаёт сигнал «подтверждения», уведомляя микропроцессор о принятии кода.
Если клавиша остаётся нажатой дольше некоторого времени задержки, микропроцессор клавиатуры начинает генерировать с заданной частотой прямой скэн-код нажатой клавиши. Когда скэн-код принят схемой ППИ, аппаратура компьютера генерирует аппаратное прерывание с номером 9.
Используемые прерывания.
MS-DOS имеет целую группу функций прерывания 21h для выполнения ввода информации с клавиатуры. Функция MS-DOS вызывает драйвер клавиатуры, передавая ему запрос на ввод одного символа из буфера клавиатуры. Драйвер, выполняя запрос, обращается к нужной функции прерывания 16h BIOS. ISR BIOS прерывания 16h читает из буфера клавиатуры нужное слово и передаёт в драйвер. Драйвер возвращает байт (обычно младший) в MS-DOS.
Буфер клавиатуры.
Буфер занимает 32 байта оперативной памяти с адреса 40:1Eh до 40:3Eh. Запись информации в буфер выполняет ISR BIOS прерывания 9, чтение — функции ISR BIOS прерывания 16h. Буфер имеет 30 байт для кодов клавиш и ещё два дополнительных байта, которые резервируются под двухбайтовый код для клавиши ENTER. Буфер организуется как кольцевая очередь, доступ к которой осуществляется с помощью указателя «головы», адрес которого 40:1Ah, и указателя «хвоста», адрес которого 40:1Ch. Указатель «хвоста» задают смещение до первого свободного слова буфера. Указатель «головы» задаёт смещение слова, которое будет возвращено запросу буферизованного ввода с клавиатуры.
Функции обслуживания ввода с клавиатуры.
int getch();
Выполняет ввод с клавиатуры через функцию MS-DOS АН=07h без «эха».
int getche();
Выполняет ввод с клавиатуры через функцию MS-DOS АН=07h с «эхом».
char* getpass(char* prompt);
Выводит на экран ASCII-строку, на начало которой указывает prompt, a затем принимает с клавиатуры без «эха» строку символов. Вводимые символы помещаются во внутреннюю статическую память. Функция возвращает указатель на внутреннюю статическую строку, переопределяемую каждым новым обращением к функции.
int kbhit();
Проверяет, пуст ли буфер клавиатуры. Если в буфере есть символы, возвращает ненулевое значение, в противном случае возвращает 0.
int bioskey(int cmd);
Обращается в зависимости от значения в cmd к функциям АН = 00–02h прерывания 16h. Возвращаемое функцией значение повторяет значение регистра АХ при выходе из прерывания.
Текст программы.
#include <CONIO.H>
#include <DOS.H>
#define UP 1
#define DOWN 2
#define LEFT 3
#define RIGHT 4
#define WX0 20
#define WY0 8
#define WX1 60
#define WY1 18
#define F9 67
#define F10 68
#define F11 133
#define F12 134
#define FREQ 10
int getSpecialScan() {
int scan, ascii;
union REGS regs;
regs.h.ah = 0x10;
int86(0x16, ®s, ®s);
scan = regs.x.ax >> 8;
ascii = regs.x.ax & 0xFF;
if (ascii == 0) return scan;
return 0;
}
int mykbhit() {
_asm {
mov ah, 11h
int 16h
jz end // переходит в конец функции, если ZF = 1
}
return 1;
end: return 0;
}
int main() {
int direction = RIGHT;
int x = 1, y = 1;
int timer = 0;
union REGS regs;
regs.h.ah = 1;
regs.h.ch = 1 << 5;
int86(0x10, ®s, 0);
clrscr();
window(WX0, WY0, WX1, WY1);
textattr((BLUE << 4) | WHITE);
clrscr();
while (1) {
if (timer == 0) {
timer = FREQ;
gotoxy(x, y);
cprintf(" ");
switch (direction) {
case UP: if (--y < 1) y = WY1 - WY0 + 1; break;
case DOWN: if (++y > WY1 - WY0 + 1) y = 1; break;
case LEFT: if (--x < 1) x = WX1 - WX0 + 1; break;
case RIGHT: if (++x > WX1 - WX0 + 1) x = 1; break;
}
gotoxy(x, y);
cprintf("X");
}
// Вторая версия получается снятием комментария со следующей
// строки и наложением комментария на последующую:
// if (mykbhit()) switch (getSpecialScan()) {
if (kbhit()) switch (getch()) {
case F9: direction = LEFT; break;
case F10: direction = UP; break;
case F11: direction = DOWN; break;
case F12: direction = RIGHT; break;
}
timer--;
delay(10);
}
return 0;
}
Блок-схема.
Рисунок 1. Блок-схема программы.
Структурная схема аппаратных средств.
Рисунок 2. Структурная схема аппаратных средств.
Вывод.
Была изучена работа с клавиатурой; освоено использование стандартных средств библиотеки C++ и средств системы прерываний, обслуживающих клавиатуру; написаны две версии программы, использующие их.