Лабораторная работа № 9-10. «Изучение функций системного таймера». Краткие теоретические и учебно-методические материалы
Лабораторная работа № 9-10 «Изучение функций системного таймера» Цель работы: изучение функций системного таймера и закрепление практических навыков работы с ним. Образовательные результаты, заявленные во ФГОС третьего поколения: Студент должен уметь: - осуществлять разработку кода программного модуля на современных языках программирования; - создавать программу по разработанному алгоритму как отдельный модуль; - выполнять отладку и тестирование программы на уровне модуля знать: - основные этапы разработки программного обеспечения; - основные принципы технологии структурного и объектно-ориентированного программирования; - основные принципы отладки итестирования программных продуктов. Краткие теоретические и учебно-методические материалы по теме лабораторной работы Микросхема таймера генерирует импульсы частоты 1193180 гц. Эта последовательность импульсов поступает на три канала таймера. В каждом канале есть свой счетчик, работающий как делитель частоты, максимальное число которое может быть записано в счетчике (коэффициент деления) - 655357. Счетчики каналов таймера независимы друг от друга и доступны для программиста. Назначение каналов таймера следующее: · канал 0 используется для системной службы времени. При инициализации системы BIOS записывает в счетчик этого канала максимально возможное число, таким образом, импульсы на выходе делителя выдаются с частотой около 18. 2 гц (период этой частоты - около 55 мсек - программисты иногда называют " тиком" таймера). Выход делителя этого канала поступает на контроллер прерываний и вызывает прерывание с номером 8;
· выход канала 1 используется схемами регенерации памяти, поэтому программисты с этим каналом не работают; · выход канала 2 поступает на динамик ПЭВМ, этот канал используется для генерации звука. Каждый канал может работать в одном из 6 режимов, но программисты, как правило, используют его в режиме 3 (генератор меандра). Программирование канала таймера представляет собой запись числа в счетчик канала. Имеется один управляющий порт - 0x43 для всех каналов и по одному порту данных для каждого канала - 0x40, 0x41, 0x42. При программировании следует записать в порт 0x43 управляющий байт, который обычно имеет вид: x x 1 1 0 1 1 0, где xx - номер канала таймера, а затем послать в порт данных выбранного канала сначала младший, а затем старший байт счетчика.
Пример: Дана функция - y=50*(sin(x/10)+cos(x/8))+R+150; R - в диапазоне 0 - 10; частота - 36. 4 Гц. Программа состоит из основной программы и трех функций. void *readvect(int in) - функция читает вектор прерывания с номером in и возвращает его значение. void writevect (int in, void *h) - функция устанавливает новый вектор прерывания in на новый обработчик этого прерывания по адресу h. void interrupt newtime() - процедура нового обработчика прерывания таймера. В этой программе применяются две константы: TIMEINT=8 - номер прерывания таймера; NN=100 - максимальное число показаний АЦП. Переменные, глобальные для всей программы: y - массив показаний АЦП; ny - текущий индекс в массиве показаний; yc - текущее значение функции; kf - счетчик вызовов oldtime (oldtime вызывается каждые второй раз); rr и sr - переменные, которые используются для задания значений регистров общего назначения и сегментных регистров, соответственно при вызове прерывания. Переменные главной программы: oldtic - старый коэффициент деления; newtic - новый коэффициент деления (применяется для увеличения частоты вызова прерываний таймера); x - аргумент заданной функции F(x);
dd - тип графического адаптера; m - режим графики; errorcode - код результата инициализации графики. Главная программа постоянно вычисляет значения заданной функции F(x) при переменном аргументе, что имитирует непрерывный сигнал, а обработчик прерывания 8 имитирует преобразователь с постоянным шагом дискретизации по времени. Перед началом работы канал 0 таймера программируется на частоту в 2 рази большую обычной (записью в порт 43h управляющего байта 00110110b=36h, а потом посылкой в порт 40h нового значения коэффициента деления), таким образом, " частота дискретизации" составляет около 36. 4 Гц. При поступлении следующего прерывания запоминается текущее значение функции F(x), старый обработчик прерывания oldtime вызывается не при кожному прерывании, а лишь один раз из двух (переменная kf - счетчик по модулю 2), когда oldtime не вызывается, наш обработчик сам сбрасывает контроллер прерываний посылкой значения 20h в порт 20h. После набора 100 " показаний АЦП" восстанавливается старый вектор обработчика таймера, а результат аналого-цифрового преобразование выводится на терминал в графическом режиме в виде решетчатой функции. Функция readvect() читает вектор заданного прерывания. Для чтения вектора применяется функция 35h DOS (прерывания 21h): Вход: AH = 35h; AL = номер вектора прерывания. Выход: ES: BX = адрес программы обработки прерывания. Функция writevect() устанавливает новый вектор прерывания по заданному адресу. Для записи вектора применяется функция 25h DOS: Вход: AH = 25h; AL = номер вектора прерывания; DS: BX = 4-байтный адрес нового обработчика прерывания. * Подключение стандартных заголовков */ #include < dos. h> #include < math. h> #include < stdlib. h> #include < graphics. h> #include < time. h> #include < conio. h> #define TIMEINT 8 /* Прерывание таймера */ #define NN 100 /* Максимальное количество показаний */
void interrupt (*oldtime)(); /* Новый обpаботчик */ /* пpеpываний таймеpа */
void interrupt newtime(); /* Старый обpаботчик */ /* пpеpываний таймеpа */ static int y[NN]; /* Накопитель показаний */ static int ny; /* Индекс в массиве y */ static int yc; /* Текущее значение */ static int kf; /* Счетчик вызовов oldtime */ union REGS rr; /* Запись нового вектора */ struct SREGS sr; void *readvect(int in); /* Получение старого вектора */
void writevect(int in, void *h); /* Запись нового вектора */ /*--------------------------------------------------------*/ void main() { unsigned oldtic=65535u; /* Старый коэфф. деления */ unsigned newtic=32768u; /* Новый коэфф. деления */ int dd, /* Графический драйвер */ m, /* Графический режим */ errorcode; /* Код ошибки */ double x; /* Аргумент функций sin и cos */ textbackground(0); clrscr(); textattr(0x0a); cprintf(" Лабораторная работа N6 " ); cprintf(" \n Управление таймером " ); textattr(0x8e); gotoxy(35, 12); cprintf(" Please wait" ); /* Программирование канала 0 */ outportb(0x43, 0x36); /* Управляющий байт */ outportb(0x40, newtic& 0x00ff); /* Младший байт счетчика */ outportb(0x40, newtic> > 8); /* Старший байт счетчика */ ny=-1; /* Признак того, что АЦП еще не началось */ kf=15; /* Подключение к вектору */ oldtime=readvect(TIMEINT); writevect(TIMEINT, newtime); /* Запуск " непрерывного процесса" */ randomize(); for (x=ny=0; ny< NN; x+=1) yc=(int)(50*(sin(x/10)+cos(x/8))+random(11)+150); /* Восстановление вектора */ writevect(TIMEINT, oldtime); /* Восстановление канала 0 */ outportb(0x43, 0x36); /* Управляющий байт */ outportb(0x40, oldtic& 0x00ff); /* Младший байт счетчика */ outportb(0x40, oldtic> > 8); /* Старший байт счетчика */ /* Вывод запомненных результатов */ dd=3; /* EGA, 16 цветов */ m=1; /* Режим 640*350 */ initgraph(& dd, & m, " " ); /* проверка результата инициализации */ errorcode = graphresult(); if (errorcode! = grOk) /* ошибка графического режима */ { printf(" Graphics error: %s\n", grapherrormsg(errorcode)); printf(" Press any key to halt: " ); getch(); exit(1); /* аварийное завершение */} setcolor(10); settextstyle(0, 0, 2); outtextxy(15, 10, " Результати аналого-цифрового преобразования: " ); setcolor(9); rectangle(15, 40, 624, 330); setcolor(11); for(ny=0; ny< NN; ny++) { circle(22+ny*6, 330-y[ny]*1, 2); line(22+ny*6, 330, 22+ny*6, 330-y[ny]*1); } setcolor(12); settextstyle(0, 0, 1); outtextxy(260, 340, " Нажмите любую клавишу... " ); getch(); closegraph(); }
/* Новый обpаботчик пpеpиваний таймеpа */ void interrupt newtime() { if (--kf< 0) { /* Виклик oldtime - на 2-й раз */ (*oldtime)(); kf=1; } else /* иначе - сброс контроллера */ outportb(0x20, 0x20); if ((ny> =0) /* Если АЦП началось, */
& & (ny< NN)) /* и NN показаний еще не набрано, */ y[ny++]=yc; /* запоминание очередного показания *} /* Получение старого вектора */ void *readvect(int in) { rr. h. ah=0x35; rr. h. al=in; intdosx(& rr, & rr, & sr); return(MK_FP(sr. es, rr. x. bx)); } /* Запись нового вектора */ void writevect(int in, void *h) { rr. h. ah=0x25; rr. h. al=in; sr. ds=FP_SEG(h); rr. x. dx=FP_OFF(h); intdosx(& rr, & rr, & sr); } Результат работы представляется в графическом режиме в виде решетчатой функции на экране терминала.
Задания для лабораторной работы: Таблица 1 – варианты индивидуальных заданий
Построить модель аналого-цифрового преобразователя (АЦП), которая работает в реальном времени. Процесс, который дискретизуется, моделируется программой (программным блоком), который выполняет циклическое вычисление функции y=F(x), где x - номер итерации. Преобразователь моделируется программой, которая выполняет с заданной частотой (в реальном времени) прерывание процесса, считывание и запоминание текущего значения функции. Запомнить не меньше 80 значений функции. Обеспечить наглядное представление результатов работы " АЦП". Примечание: R - случайное вещественное число из последовательности, равномерно распределенной в указанном интервале. Контрольные вопросы: 1. Назовите функции таймера. 2. Назовите назначение каналов таймера.
3. Что представляет собой программирование канала таймера. 4. Какаим образом происходит доступ к счетчику времени. 5. Какой частоты таймер генерирует импульсы?
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|