Читайте также:
|
|
// ВКЛЮЧАЕМЫЕ ФАЙЛЫ ////////////////////////////////////////
#include <dos.h>
#include <bios.h>
#include <stdio.h>
#include <math.h>
#include <conio.h>
#include <graph.h>
// ОПРЕДЕЛЕНИЯ /////////////////////////////////
#define time_keeper_int 0x1C
// ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ /////////////////////////////////////////
void (_interrupt _far *01d_Isr)();
// хранит Старый обработчик прерывания
long time=0;
// функции //////////////////////////////////////////////
void _interrupt _far*Timer ()
{
// увеличивает глобальную переменную
// еще раз отметим, что мы можем это делать, так как при входе в
// процедуру обработки прерывания регистр DS указывает-на сегмент
// глобальных данных нашей программы
time++;
} // конец Timer
////////////////////////////////////////////
void Plot_Responder(void)
{
static int first_time=l;
static long old_time;
// проверка первого вызова
if (first_time)
{
//сброс флага первого вызова
first_time=0;
old_time = time;
} // конец оператора if else
(// не первый вызов
// прошло ли пять "тиков"?
if ((time-old_time)>=5)
{
old_time = time; // сохранить новую точку отсчета
// вывод пикселя на экран
_setcolor(rand()%16);
_setpixel(rand()%320,rand()%200);
} // конец оператора if
} // конец else
}// конец Plot_Responder,
// ОСНОВНАЯ ПРОГРАММА /////////////////////////////////////////////
main()
{
_setvideomode(_MRES256COLOR);
printf('Hit any key to exit...");
// установка процедуры обработки прерывания
0ld_Isr = _dos_getvect(TIME_KEEPER_INT);
_dos_setvect(TIME_KEEPER_INT, Timer);
// ожидание нажатия клавиши пользователем
while(!kbhit())
//... текст программы игры
// вызов всех функций ответа Plot_Responder();
//... текст программы игры
} // конец while
_setvideomode(_DEFAULTMODE);
// восстановление старого обработчика прерывания
_dos_setvect(TIME_KEEPER_INT, 01d_Isr);
} // конец функции main
В программе, приведенной в Листинге 12.4, функция ответа следит за временем и каждые пять «тиков» системных часов или 5х55.4 миллисекунды рисует на экране пиксель. Значение 55.4 получается из того, что системный таймер по умолчанию настроен так, что генерирует прерывание 18.2 раза в секунду или каждые 55.4 миллисекунды. Обратите внимание и на то, что функция ответа автономна.
Автономные функции и функции ответа могут быть использованы для самых разнообразных целей. Они позволяют выделить часть задач, не связанных с непосредственным ходом игры в отдельную группу и решать их отдельно. Логика игры и так достаточно сложна - поэтому не стоит ее без необходимости загромождать мерцающими огоньками и прочими мелкими деталями.
На персональных компьютерах следить за временем и,управлять событиями связанными с ним, можно только с помощью внутренних таймеров системы. К сожалению, большинство из них используется для других целей. Однако один применяется специально для внутренних часов компьютера. Он «тикает» со тростью 18.2 раза в секунду. Что и говорить, необычная отправная точка для вычислений и, честно говоря, я понятия не имею, почему создатели персональных компьютеров выбрали именно это значение. Но мы можем перепрограммировать его и задать более разумное число, например, 20, 30 или 60 «тиков» в секунду. Естественно, такие значения удобнее использовать в нашей компьютерной игре. Итак, давайте разберемся, как можно перепрограммировать внутренний таймер системы.
Программируем системные часы
Внутренние часы компьютера, следящие за временем, на самом деле вовсе никакие не часы. Это микросхема типа таймер/счетчик, которая просто в, зависимости от начальных настроек с определенной частотой изменяет значение счетчика. Эта микросхема называется микросхемой таймера 8253. В ней содержится три шестнадцатиразрядных счетчика. Эти счетчики можно программировать самыми разнообразными способами. В таблице 12.2 показано назначение каждого из них.
Таблица 12.2. Счетчики микросхемы таймера 8253.
Порт ввода/вывода | Номер счетчика | Назначение |
40h | Счетчик 0 | Таймер/Диск |
41h | Счетчик 1 | Обновление памяти |
42h | Счетчик 2 | Накопитель на магнитной ленте |
43h | Управляющий регистр | Управление таймером |
Доступ к микросхеме таймера осуществляется через порты 40h-43h. Как видите, мы можем использовать только счетчики 0 и 3. Связываться со счетчиком 1 нам определенно не стоит! Счетчик 0 уже используется DOS для системных часов. Так почему бы нам не использовать его, перепрограммировав на нужную частоту?
Это вполне можно сделать. И этот метод не вызовет неполадок в компьютере. Единственный недостаток такого подхода состоит в том, что изменится системное время. Мы можем обойти это, сохранив время, за которое изменяется значение частоты таймера и по ходу игры отслеживать время с учетом этого изменения. Затем, перед окончанием работы программы, следует восстановить прежнее значение частоты и изменить системное время. Для сохранения и восстановления системного времени можно использовать функции Си.
Изменение частоты таймера
Давайте поговорим о том, как изменять частоту таймера. Таймер генерирует прерывания следующим образом: заданное значение регистра счетчика таймера уменьшается на единицу каждый раз, когда приходит импульс от генератора. Когда значение счетчика становится равным нулю, таймер генерирует прерывание, после чего восстанавливает исходное значение счетчика. Затем процесс повторяется вновь. Счетчик 0 генерирует прерывания 18.2 раза в секунду или через каждые 55.4 миллисекунды. Это время задается следующим образом: на микросхему таймера подаются импульсы с частотой 1.19318МГц. В случае системного таймера в регистр помещается число 65536. Если взять 1.19318 и разделить па 65536 получится 18.206 циклов в секунду или 54.925 миллисекунд. Как видите, создатели персонального компьютера просто использовали максимально возможный делитель, который может поместиться в 16 битов: 65535. (На самом деле таймер «тикает» на один раз больше — вот откуда я взял число 65536).
Таким образом, все что нам следует сделать, это вычислить 16-разрядное число, при делении на которое 1.19318МГц даст нам нужную частоту. Для вашего удобства я рассчитал подходящие значения для наиболее часто встречающихся частот. Взгляните на таблицу 12.3
Таблица 12.3. 16-разрядные значения счетчика для наиболее употребительных частот таймера.
Шестандцатиричное Значение | Десятичное Значение | Частота |
4DAEh | 60Hz | |
965C | 30Hz | |
E90B | 20Hz |
Таким образом, нам следует перепрограммировать счетчик 0 таким образом, чтобы он генерировал прерывания с более подходящей для нашей игры частотой - так, чтобы наша игра могла контролировать события чаще чем 18.2 раза в секунду.
Давайте посмотрим, каким образом можно задать соответствующее значение счетчика. Нас интересуют порты ввода/вывода 40h и 43h (все, о чем мы будем говорить, относится к ним): счетчик 0 и соответствующий управляющий регистр. Значения битов управляющего регистра, показаны в таблице 12.4.
Из таблицы 12.4 видно, что в нашем распоряжении много параметров. Впрочем, нам сейчас все они не нужны, нам надо всего-навсего изменить начальное значение счетчика 0. При этом значения других битов должны быть следующими:
§ Режим работы - 2, генератор частоты;
§ Метод подсчета - двоичный;
§ Запись регистра счетчика осуществляется при помощи операции «Прочитать/записать младший байт, а затем старший байт счетчика».
Таким образом, все что мы должны сделать, это записать управляющее слово в порт 43h, а затем выполнить две операции записи в порт 40h. В ходе первой операции записи мы установим значение младшего байта нового значения счетчика, а при второй — значение старшего байта. В том, где какие байты аппаратные средства разберутся сами, поэтому вам об этом волноваться не надо. В Листинге 12.5 приведен текст функции, программирующей таймер.
Дата добавления: 2015-07-12; просмотров: 122 | Нарушение авторских прав
<== предыдущая страница | | | следующая страница ==> |
Листинг 12.3. Автономное управление светом. | | | Листинг 12.5. Перепрограммируем системные часы (OUTATIME.C). |