- •Определение конфигурации компьютера программными средствами.
- •Лекция №6. Функции bios.
- •00HЗадание видеорежима
- •0Fh Чтение текущего состояния дисплея
- •Выбор режима работы - функция 00h
- •Определение типа центрального процессора
- •Функции прерывания dos int 21h
- •2А Получение даты (cx-год,dh-месяц,dl-день).
- •2С Получение времени (ch-час,cl-мин,dh-с,dl-1/100с).
- •2F Получение адреса dta в регистровой паре es:bx.
- •38 Получение государственно зависимых форматов.
- •Прерывание для обслуживания мыши
- •Часы реального времени
Часы реального времени
(слайд №69)
Все соверменные компьютеры оснащены часами реального времени. Эти часы работают от аккумулятора, поэтому их показания не пропадают при выключении электропитания.
Доступ к часам реального времени из программы возможен либо через ячейки памяти CMOS, либо через специальные функцииBIOS(что более предпочтительно с точки зрения независимости программы от особенностей аппаратуры).
Регистры часов реального времени
Использование регистров памяти CMOS часами реального времени приведено ниже.
Регистры счетчиков
В регистрах 0, 2, 4, 6 и 8 хранится текущее значение времени и дата.
Регистры с номерами 1, 3, 5, 7 и 9 – это регистры будильника. То есть можно установить будильник, и когда он сработает, произойдет прерывание.
Регистр |
Счетчик, который содержится в регистре |
0 |
Секунды |
1 |
Секунды будильника |
2 |
Минуты |
3 |
Минуты будильника |
4 |
Часы |
5 |
Часы будильника |
6 |
День недели (1 - воскресенье) |
7 |
День месяца |
8 |
Номер месяца |
9 |
Последние две цифры текущего года |
Регистр состояния A
Адрес первого регистра состояния – 0Ah. Формат битовых полей представлен ниже:
Биты регистра |
Описание |
0-3 |
Переключатель скорости. По умолчанию установлен в 0110 |
4-6 |
22-разрядный делитель. По умолчанию установлен в 010 |
7 |
Флаг обновления. Значение 0 означает готовность данных для чтения |
Регистр состояния B
Адрес второго регистра состояния – 0Bh:
Биты регистра |
Описание |
0 |
Летнее или стандартное время: 1 - летнее время; 0 – стандартное время |
1 |
12 или 24-часовой режим: 0 - 12-часовой режим 1 – 24-часовой режим (установлен по умолчанию) |
2 |
Формат данных: 1 – двоичный; 0 - BCD (установлен по умолчанию) |
3 |
Разрешение прямоугольного сигнала: 1 – включение сигнала, частота которого определяется разрядами 0-3 первого регистра состояния; 0 – сигнал выключен |
4 |
Разрешение прерывания по окончанию изменения данных (по умолчанию сброшен) |
5 |
Разрешение прерывания будильника (по умолчанию сброшен) |
6 |
Разрешение периодических прерываний (по умолчанию сброшен) |
7 |
Запрет счета: 1 – счетчик остановлен; 0 – счетчик запущен |
Регистр состояния C
Адрес третьего регистра состояния – 0Сh. Этот регистр доступен только для чтения исодержит биты состояния прерывания.
Регистр состояния D
Адрес четвертого регистра состояния – 0Dh. Если бит 7 этого регистра сброшен, это означает, что разрядился аккумулятор, питающий памятьCMOS.
Прерывание от часов реального времени
Часы реального времени вырабатывают аппаратное прерывание IRQ8, которому соответствует прерывание с номером70h. Это прерывание можетвырабатываться по трем причинам:
прерывание по окончанию изменения данных; вырабатывается при установленном бите 4 регистра состояния Bпосле каждого обновления регистров часов;
прерывание будильника; вырабатывается при совпадении регистров часов и регистров будильника и при установленном бите 5 регистра состояний B;
периодическое прерывание; вырабатывается с интервалом примерно 1 мс при установленном бите 6 регистра состояний B.
При срабатывании будильника BIOSвырабатывает прерываниеINT 4Ah. Программа может подготовить собственный обработчик для этого прерывания.
(слайд №70)
Функции прерывания 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, если часы реального времени не установлены |
(слайд №71)
Установить дату в часах реального времени
На входе: |
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 |
На выходе: |
Регистры не используются |
Эта функция позволяет сбросить будильник, например, для того чтобы установить его на другое время.
Пример:
// ===================================
// Работа с часами реального времени
// ===================================
#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;
#defineRTC_GET_TIME2 // прочитать
// показания часов;
#defineRTC_SET_TIME3 // установить
// часы;
#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 )
// Макро для выдачи звукового сигнала
#defineBEEP() _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;
}
Программа чтения времени и даты:
(слайд №72)
#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;
#defineGET_TIME2 // прочитать показания часов;
#define GET_DATE 4 // прочитать дату;
int bcd1bin(char *bcd);
int bcd2bin(char *bcd);
int timer(char fn, SYSTIMER *treal);
// Выключаем проверку стека и указателей
#pragma check_stack( off )
#pragma check_pointer( off )
union REGS reg;
int main(void)
{
char *month_to_text[] =
{ "январь",
"февраль",
"март",
"апрель",
"май",
"июнь",
"июль",
"август",
"сентябрь",
"октябрь",
"ноябрь",
"декабрь" };
SYSTIMER timereal;
// Определяем текущие дату и время
timer(GET_DATE, &timereal);
timer(GET_TIME, &timereal);
// Выводим дату и время на экран
printf("\nСейчас %d год, %s, %d число."
"\n",
bcd2bin((char*)&(timereal.year)),
month_to_text[bcd1bin(&(timereal.month)) - 1],
bcd1bin(&(timereal.day)));
printf("\nВремя - %02.2d:%02.2d:%02.2d"
"\n",
bcd1bin(&(timereal.hour)),
bcd1bin(&(timereal.min)),
bcd1bin(&(timereal.sec)));
getch();
return 0;
}
// Преобразование однобайтового числа из формата BCD в двоичный формат
intbcd1bin(char*bcd)
{
return( ((*bcd) & 0x0f) +10 * (((*bcd) & 0xf0) >> 4) );
}
// Преобразование двухбайтового числа из формата BCD в двоичный формат
int bcd2bin(char *bcd)
{
return( bcd1bin(bcd) +100 * bcd1bin(bcd + 1) );
}
int timer(char fn, SYSTIMER *treal)
{ reg.h.ah = fn;
int86(0x1a,®,®);
if(reg.x.cflag == 1)
return(-1);
switch (fn)
{ case GET_TIME:
{ treal->hour = reg.h.ch;
treal->min = reg.h.cl;
treal->sec = reg.h.dh;
break; }
case GET_DATE:
{ treal->year = reg.x.cx;
treal->month = reg.h.dh;
treal->day = reg.h.dl;
break; }
}
return 0;
}