
- •Аннотация
- •Введение
- •Благодарности
- •Авторский компакт-диск
- •Как связаться с авторами
- •1 Определение конфигурации компьютера
- •Определение конфигурации с помощьюBios
- •Наличие нмд
- •Наличие арифметического сопроцессора
- •Начальный режим работы видеоадаптера
- •Стандартная оперативная память
- •Расширенная оперативная память
- •ПрограммаHdwcfg
- •Код модели компьютера и версияBios
- •ПрограммаBiosinfo
- •Конфигурация в памяти cmos
- •00H - 0Dh - область часов реального времени
- •0Eh - байт диагностики
- •0Fh - байт отключения
- •10H - тип накопителей нгмд
- •11H - зарезервировано дляIbm pc/at, тип нмд дляIbm ps/2
- •12H - тип первого и второго нмд
- •13H - зарезервировано
- •14H - конфигурация оборудования
- •15H-16h - объем стандартной оперативной памяти
- •ПрограммаCmosshow
- •Определение типа центрального процессора
- •МоделиIntel 8086/8088
- •Модель Intel 80286
- •МодельIntel 80386
- •МодельIntel 80486
- •Команда cpuid
- •ПрограммаCpuinfo
- •2 Клавиатура
- •Как работает клавиатура
- •Клавиатурная матрица
- •Скан-код клавиши
- •КодAscii нажатой клавиши
- •Режим автоповтора
- •Типы клавиатур
- •Порты для работы с клавиатурой
- •КомпьютерIbm pc/xt
- •Современные компьютеры
- •ПрограммаKbdled
- •Аппаратное прерывание клавиатуры
- •Стандартный обработчик прерывания int 09h
- •Буфер клавиатуры
- •Переключающие клавиши
- •Средства bios для работы с клавиатурой
- •Чтение символа с ожиданием
- •ПрограммаKbdscan
- •Проверка буфера на наличие в нем символов
- •ПрограммаChkbuf
- •Получение состояния переключающих клавиш
- •Установка временных характеристик клавиатуры
- •Запись символов в буфер клавиатуры
- •Чтение символа с ожиданием для 101-клавишной клавиатуры
- •Проверка буфера на наличие в нем символов для 101-клавишной клавиатуры
- •Получение состояния переключающих клавиш для 101-клавишной клавиатуры
- •Режимы работы клавиатуры
- •Сравнение режимов
- •Изменение режима
- •Средства ms-dos для работы с клавиатурой
- •Буферизованный ввод с эхо-выводом
- •Буферизованный ввод без эхо-вывода
- •Нефильтрованный ввод без эхо-вывода
- •Вводс консоли и вывод на консоль
- •Ввод строки символов
- •Проверка состояния стандартного ввода
- •Сброс буфера клавиатуры
- •Клавиатурные функции стандартной библиотеки c
- •Функции getch и getche
- •ПрограммаKbdascii
- •Функцияkbhit
- •ПрограммаKbdhit
- •Функция cgets
- •Функция gets
- •Функция scanf
- •Как устроена мышь?
- •Драйверы мыши в ms-dos
- •Прерывание для обслуживания мыши
- •Инициализация мыши
- •Включить курсор мыши
- •Выключить курсор мыши
- •ПрограммаMscursor
- •Определить положение курсора
- •ПрограммаMsgcurs
- •Установить курсор
- •Определить положение курсора при нажатии клавиши
- •Определить положение курсора при отпускании клавиши
- •Задать диапазон движения курсора по горизонтали
- •Задать диапазон движения курсора по вертикали
- •Задать форму курсора в графическом режиме
- •ПрограммаMsgform
- •Задать форму курсора в текстовом режиме
- •ПрограммаMstform
- •Определить содержимое счетчиков перемещения
- •Установить драйвер событий
- •ПрограммаMsdriver
- •Включить эмуляцию светового пера
- •Выключить эмуляцию светового пера
- •Задать скорость перемещения курсора мыши
- •Установить область исключения для курсора
- •Задать увеличенный графический курсор
- •Определить порог удвоения скорости
- •Заменить драйвер событий
- •Определить размер буфера состояния драйвера
- •Сохранить состояние драйвера
- •Восстановить состояние драйвера
- •Установить альтернативный драйвер событий
- •Получить адрес альтернативного драйвера событий
- •Установить чувствительность мыши
- •Определить чувствительность мыши
- •Установить частоту прерываний для Inport Mouse
- •Установить номер страницы видеопамяти
- •Определить номер страницы видеопамяти
- •Отключить драйвер мыши
- •Восстановить драйвер мыши
- •Сбросить драйвер мыши
- •Определить тип мыши
- •МышьMicrosoft IntelliMouse
- •Проверка наличия мыши Microsoft IntelliMouse
- •Проверка в среде Microsoft Windows 95 и Microsoft Windows nt версии 3.51
- •Проверка в среде Microsoft Windows nt версии 4.0
- •Определение величины свертки
- •Определение величины свертки в среде Microsoft Windows 95 и Microsoft Windows nt версии 3.51
- •Определение величины свертки в среде Microsoft Windows nt версии 4.0
- •Сообщение msh_mousewheel
- •Сообщение wm_mousewheel
- •Другие сообщения от мыши Microsoft IntelliMouse
- •ПриложениеRtfpad
- •4 Часы реального времени
- •Регистры часов реального времени
- •Регистры счетчиков
- •Регистр состоянияA
- •Регистр состояния b
- •Регистр состояния c
- •Регистр состояния d
- •Прерывание от часов реального времени
- •Функции прерыванияInt 1Ah
- •Сброс будильника
- •ПрограммаRtcalarm
- •5 Системный таймер
- •Обработка прерываний таймера
- •Микросхемы таймера 8253 и 8254
- •Режимы работы таймера
- •Режим однократного выполнения функций
- •Работа с перезапуском
- •Формат управляющего регистра
- •Формат команды чтения слова состояния канала
- •Формат слова состояния канала
- •Последовательность действий
- •ПрограммаTimerst
- •Средства bios для работы с таймером
- •Чтение счетчика таймера
- •Установка счетчика таймера
- •Установка таймера с сигнализацией
- •Формирование задержки
- •Второй способ проигрывания музыки
- •Проигрывание музыки в фоновом режиме
- •ПрограммаTmsound
- •ПрограммаIosound
- •ПрограммаRandom
- •6 Асинхронный последовательный адаптер
- •Основные понятия и термины
- •Аппаратная реализация
- •МикросхемаUart
- •Разъемы адаптера
- •Порты асинхронного адаптера
- •Порт 3f8h
- •Порт 3f9h
- •Порт 3fAh
- •Порт 3fBh
- •Порт 3fCh
- •Порт 3fDh
- •Порт 3fEh
- •Функции bios для работы с последовательным асинхронным адаптером
- •Инииализация портов асинхронного адаптера
- •Передача байта
- •Прием байта
- •Определение состояния асинхронного адаптера
- •Программирование асинхронного адаптера
- •Инициализация асинхронного адаптера
- •Передача данных
- •Прием данных
- •ПрограммаComtest
- •Использование прерываний
- •7 Параллельный адаптер
- •Порты параллельного адаптера
- •Порт 378h
- •Порт 37Ah
- •Порт 379h
- •Разъем параллельного адаптера
- •Вывод байта на принтер через параллельный адаптер
- •Функции bios для работы с принтером
- •Печать символа
- •Инициализация принтера
- •Определение состояния принтера
- •ПрограммаPrintfl
- •Функции ms-dos для работы с принтером
- •ФункцияMs-dos для вывода на принтер
- •Система буферизованной печати
- •Проверка установки системы буферизованной печати
- •Запуск процесса печати файла
- •Отмена печати файла
- •Отмена печати всех файлов
- •Определение состояния и блокировка системы буферизованной печати
- •Разблокирование системы буферизованной печати
- •Коды ошибок
- •Программирование принтера
- •Подключение принтера к компьютеру
- •Установка переключателей конфигурации
- •Программирование режимов работы принтера
- •Инициализация принтера
- •Контроллер прямого доступа ibm pc/xt
- •Регистры каналов dma
- •Порты 00h - 07h
- •Порт 08h
- •Порт 09h
- •Порт 0Ah
- •Порт 0Bh
- •Порт 0Ch
- •Порт 0Dh
- •Порт 0Eh
- •Порт 0Fh
- •Порты 81h-8Fh
- •Инициализация канала dma
- •Контроллер прямого доступа ibm at
- •Регистры каналовDma
- •Регистры страниц
- •Порты 0c0h - 0dFh
- •Порты 0d0h-0dFh
- •9 Устройство чтения cd-rom
- •Драйвер устройства чтенияCd-rom
- •РасширениеMscdex
- •ФункцииMscdex
- •Определение количества устройствCd-rom
- •Получение списка устройств cd-rom
- •Получение имени файла прав собственности
- •Получение имени файла резюме
- •Получение имени файла библиографической документации
- •Чтение сектора оглавления компакт-диска
- •Чтение сектора по абсолютному адресу
- •Проверка устройства чтения cd-rom
- •Определение версии mscdex
- •Определение обозначения устройств чтения cd-rom
- •Вызов драйвера cd-rom
- •Работа через драйверCd-rom
- •Заголовок запроса
- •Команды драйвера cd-rom
- •Инициализация
- •ЧтениеIoctl Input
- •Определение адреса заголовка драйвера cd-rom
- •Определение положения головки
- •Получение информации о звуковых каналах
- •Чтение данных из устройства
- •Определение состояния устройства
- •Определение размера сектора
- •Определение размера тома
- •Проверка замены носителя данных
- •Получение информации о компакт-диске
- •Получение информации о дорожкекомпакт-диска
- •Получение информации о канале q
- •Получение информации о подканале
- •Получение штрих-кода изготовителя компакт-диска
- •Сброс входных буферов
- •ЗаписьIoctl Output
- •Извлечение компакт-диска
- •Блокирование и разблокирование компакт-диска в устройстве
- •Сброс устройства чтения cd-rom
- •Управление звуковыми каналами
- •Запись в устройство управляющей строки
- •Чтение длинное с предварительной выборкой
- •Проигрывание звуковой дорожки
- •Остановка проигрывания звуковой дорожки
- •Возобновление проигрывания звуковой дорожки
- •ПрограммаCdinfo
- •ПрограммаCdplay
- •10 Арифметический сопроцессор
- •Вещественные числа
- •Целые числа
- •Регистры сопроцессора
- •Численные регистры
- •Регистр тегов
- •Регистр управления
- •Регистр состояния
- •Регистры указателя команды и указателя операнда
- •Система команд сопроцессора
- •Команды пересылки данных
- •Запись в стек
- •Извлечение из стека
- •Копирование данных
- •Загрузка констант
- •Арифметические команды
- •Команды сравнений чисел
- •Трансцендентные команды
- •Управляющие команды
- •Программирование сопроцессора
- •ПрограммаNpu1
- •Обработка особых случаев
- •Неточный результат
- •Переполнение
- •Антипереполнение
- •Деление на нуль
- •Недействительная операция
- •Денормализованный операнд
- •Ошибка в процессореPentium
- •11 Расширенная память
- •Основные понятия
- •Установка драйвера himem.Sys
- •Спецификация xms
- •Проверка подключения драйвера
- •Получение адреса управляющей программы
- •Описание функций драйвера himem.Sys
- •Получить версию xms
- •Запросить область hma
- •Освободить область hma
- •Глобальное открывание линии a20
- •Глобальное закрывание линии a20
- •Освободить блок emb
- •Копирование блоков emb
- •Блокирование emb
- •Разблокирование emb
- •Получить информацию об идентификаторе блока emb
- •Изменить размер emb
- •Запросить область umb
- •Освободить область umb
- •Коды ошибок
- •Ограничения при использовании области hma
- •Примеры программ
- •ПрограммаTesthma
- •ПрограммаCallhma
- •Предметный указатель
- •Литература
- •Оглавление
- •1 Определение конфигурации компьютера 7
- •2 Клавиатура 38
- •3 Мышь 64
- •4 Часы реального времени 102
- •5 Системный таймер 113
- •6 Асинхронный последовательный адаптер 132
- •7 Параллельный адаптер 149
- •8 Контроллер прямого доступа к памяти 162
- •9 Устройство чтения cd-rom 170
- •10 Арифметический сопроцессор 216
- •11 Расширенная память 243
Функции прерыванияInt 1Ah
Для работы с часами реального времени вы можете обращаться непосредственно к перечисленным выше ячейкам памяти CMOS, используя порты 70h и 71h. Однако лучше всего воспользоваться функциями 2 - 7 прерывания INT 1Ah, описанными ниже.
Прочитать показания часов реального времени
Регистры на входе: |
AH= 02h |
Регистры на выходе: |
CH = часы в BCD-формате (например, 13h означает 13 часов); CL = минуты в BCD-формате; DH = секунды в BCD-формате; CF = CY = 1, если часы реального времени не установлены |
Установить часы реального времени
Регистры на входе: |
AH= 03h CH = часы в BCD-формате (например, 13h означает 13 часов); CL = минуты в BCD-формате; DH = секунды в BCD-формате; DL = 1, если необходимо использовать летнее время |
Регистры на выходе: |
Регистры не используются |
Прочитать дату из часов реального времени
Регистры на входе: |
AH= 04h
|
Регистры на выходе: |
CH = столетие в BCD-формате; CL = год в BCD-формате (например, CX=1997h означает 1997 год); DH = месяц в BCD-формате; DL = число в BCD-формате; CF = CY = 1, если часы реального времени не установлены |
Установить дату в часах реального времени
Регистры на входе: |
AH= 05h CH = столетие в BCD-формате; CL = год в BCD-формате (например, CX=1997h означает 1997 год); DH = месяц в BCD-формате; DL = число в BCD-формате; |
Регистры на выходе: |
Регистры не используются |
Установить будильник
Регистры на входе: |
AH= 06h CH = часы в BCD-формате; CL = минуты в BCD-формате; DH = секунды в BCD-формате |
Регистры на выходе: |
CF = CY = 1, если часы реального времени не установлены |
Эта функция позволяет установить будильник на заданное время. Когда будильник “зазвенит”, будет вызвано прерывание INT 4Ah (его вызывает BIOS после прихода аппаратного прерывания от часов реального времени IRQ8, то есть прерывания с номером 70h). Программа, использующая функцию будильника, должна подготовить обработчик прерывания INT 4Ah, завершающий свою работу выполнением команды IRET.
Заметим, что можно установить только один будильник.
Сброс будильника
Регистры на входе: |
AH= 07h |
Регистры на выходе: |
Регистры не используются |
Эта функция позволяет сбросить будильник, например, для того чтобы установить его на другое время.
ПрограммаRtcalarm
Вы можете применять часы реального времени для решения двух задач. Во-первых, часы позволяют определить текущую дату и время с точностью до секунды. Во-вторых, будильник можно использовать для выполнения каких-либо действий в заданное время или периодически.
Так как установленное время срабатывания будильника хранится в памяти CMOS, питающейся от аккумулятора, будильник не будет сброшен при случайном выключении компьютера.
Для иллюстрации основных приемов работы с часами мы подготовили программу RTCALARM (листинг 4.1), которая выводит на экран текущую дату и время. Затем программа устанавливает будильник, который должен сработать через одну минуту и подать звуковой сигнал.
Перед установкой будильника программа подключает свой обработчик прерывания 4Ah. Это прерывание вызывается при срабатывании будильника. Перед завершением работы программа сбрасывает будильник и восстанавливает вектор прерывания 4Ah.
Листинг 4.1. Файлrtcalarm\rtcalarm.с
// =====================================================
// Работа с часами реального времени
//
// (C) Фролов А.В, 1997
//
// E-mail: frolov@glas.apc.org
// WWW: http://www.glasnet.ru/~frolov
// или
// http://www.dials.ccas.ru/frolov
// =====================================================
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <dos.h>
typedef struct _SYSTIMER_
{
char hour; // часы
char min; // минуты
char sec; // секунды
unsigned year; // год
char month; // месяц
char day; // число
char daylight_savings; // флаг летнего времени
} SYSTIMER;
#define RTC_GET_TIME 2 // прочитать показания часов;
#define RTC_SET_TIME 3 // установить часы;
#define RTC_GET_DATE 4 // прочитать дату;
#define RTC_SET_DATE 5 // установить дату;
#define RTC_SET_ALARM 6 // установить будильник;
#define RTC_CLEAR_ALARM 7 // сбросить будильник.
int bcd1bin(char *bcd);
int bcd2bin(char *bcd);
void bin1bcd(int bin, char *bcd);
void _interrupt _far alarm(void);
int timer(char fn, SYSTIMER *tm);
// Выключаем проверку стека и указателей
#pragma check_stack( off )
#pragma check_pointer( off )
// Макро для выдачи звукового сигнала
#define BEEP() _asm { \
_asm mov bx,0 \
_asm mov ax, 0E07h \
_asm int 10h \
}
// Прототип программы-обработчика прерывания
// будильника
void _interrupt _far alarm(void);
// Переменная для хранения старого
// вектора будильника
void (_interrupt _far *old_4a)(void);
union REGS reg;
int main(void)
{
char *month_to_text[] =
{
"январь",
"февраль",
"март",
"апрель",
"май",
"июнь",
"июль",
"август",
"сентябрь",
"октябрь",
"ноябрь",
"декабрь"
};
SYSTIMER tmr;
// Определяем текущие дату и время
timer(RTC_GET_DATE, &tmr);
timer(RTC_GET_TIME, &tmr);
// Выводим дату и время на экран
printf("\nСейчас %d год, %s, %d число."
"\n",
bcd2bin((char*)&(tmr.year)),
month_to_text[bcd1bin(&(tmr.month)) - 1],
bcd1bin(&(tmr.day)));
printf("\nВремя - %02.2d:%02.2d:%02.2d"
"\n",
bcd1bin(&(tmr.hour)),
bcd1bin(&(tmr.min)),
bcd1bin(&(tmr.sec)));
// Для установки будильника увеличиваем
// счетчик минут на единицу. Для упрощения
// программы мы не проверяем счетчик на
// переполнение, поэтому если текущее
// значение счетчика минут равно 59,
// будильник не сработает. Вы можете сами
// немного усовершенствовать программу для
// проверки переполнения
bin1bcd(bcd1bin(&(tmr.min)) + 1, &(tmr.min));
// Выводим на экран время, когда сработает
// будильник.
printf("\nВремя срабатывания будильника"
"- %02.2d:%02.2d:%02.2d"
"\n",
bcd1bin(&(tmr.hour)),
bcd1bin(&(tmr.min)),
bcd1bin(&(tmr.sec)));
// Подключаем свой обработчик прерывания
// будильника, старое значение вектора
// 0x4a сохраняем
old_4a = _dos_getvect(0x4a);
_dos_setvect(0x4a, alarm);
// Устанавливаем будильник
timer(RTC_SET_ALARM, &tmr);
printf("\nБудильник установлен. Для отмены "
"и завершения программы нажмите"
"\nлюбую клавишу...");
getch();
// Сбрасываем будильник и восстанавливаем
// вектор прерывания будильника
timer(RTC_CLEAR_ALARM, &tmr);
_dos_setvect(0x4a, old_4a);
return 0;
}
// ----------------------------------
// Преобразование однобайтового
// числа из формата BCD в двоичный
// формат
// ----------------------------------
int bcd1bin(char *bcd)
{
return( ((*bcd) & 0x0f) +
10 * (((*bcd) & 0xf0) >> 4) );
}
// ----------------------------------
// Преобразование двухбайтового
// числа из формата BCD в двоичный
// формат
// ----------------------------------
int bcd2bin(char *bcd)
{
return( bcd1bin(bcd) +
100 * bcd1bin(bcd + 1) );
}
// ----------------------------------
// Преобразование однобайтового
// числа из двоичного формата
// формат BCD
// ----------------------------------
void bin1bcd(int bin, char *bcd)
{
int i;
i = bin / 10;
*bcd = (i << 4) + (bin - (i * 10));
}
// ----------------------------------
// Программа получает управление
// при срабатывании будильника.
// Ее назначение - выдать звуковой сигнал
// ----------------------------------
void _interrupt _far alarm(void)
{
BEEP();
BEEP();
BEEP();
BEEP();
BEEP();
BEEP();
BEEP();
}
/**
*.Name timer
*.Title Работа с часами реального времени
*
*.Descr Эта функция предназначена для обслуживания
* системных часов реального времени через
* прерывание INT 1Ah
*
*.Proto int timer(char fn, SYSTIMER *tm)
*
*.Params char fn - выполняемая функция:
*
* RTC_GET_TIME - прочитать показания часов;
* RTC_SET_TIME - установить часы;
* RTC_GET_DATE - прочитать дату;
* RTC_SET_DATE - установить дату;
* RTC_SET_ALARM - установить будильник;
* RTC_CLEAR_ALARM - сбросить будильник.
*
* SYSTIMER tm - структура, содержащая данные
* для установки часов или
* показания часов:
*
*.Return 0 - успешное выполнение функции;
* -1 - часы реального времени отсутствуют
* в компьютере;
**/
int timer(char fn, SYSTIMER *tm)
{
reg.h.ah = fn;
switch (fn)
{
case RTC_SET_TIME:
{
reg.h.ch = tm->hour;
reg.h.cl = tm->min;
reg.h.dh = tm->sec;
reg.h.dl = tm->daylight_savings;
break;
}
case RTC_SET_DATE:
{
reg.x.cx = tm->year;
reg.h.dh = tm->month;
reg.h.dl = tm->day;
break;
}
case RTC_SET_ALARM:
{
reg.h.ch = tm->hour;
reg.h.cl = tm->min;
reg.h.dh = tm->sec;
break;
}
}
int86(0x1a,®,®);
if(reg.x.cflag == 1)
return(-1);
switch (fn)
{
case RTC_GET_TIME:
{
tm->hour = reg.h.ch;
tm->min = reg.h.cl;
tm->sec = reg.h.dh;
break;
}
case RTC_GET_DATE:
{
tm->year = reg.x.cx;
tm->month = reg.h.dh;
tm->day = reg.h.dl;
break;
}
}
return 0;
}