www.aeom.ho.ua Розробили: проф. Сидоренко В.В., викл. Дóренський О.П., 2006-2011
ЛАБОPАТОPНА PОБОТА № 3
ТЕМА: Програмування годинника реального часу (RTC) в IBM PC.
МЕТА: Набути навичок з програмування годинника реального часу (RTC) та CMOS-пам’яті для розв’язку інженерних задач.
Короткі теоретичнi вiдомостi
Сучасні комп’ютери оснащено двома підсистемами таймерів, які паралельно відраховують поточний час. Один таймер розміщено у мікросхемі з низьким споживання енергії (КМОП-мікросхема), яка після вимкнення живлення комп’ютера продовжує працювати, отримуючи енергію від вбудованого у комп’ютер аккумулятора (батареї). Цей таймер, як правило, називають годинником реального часу (RTC); окрім кварцевого генератора і систем керування він має внутрішню пам’ять, у якій зберігається й постійно нарощується значення поточного часу. Оновлення часу здійснюється щосекунди, причому ця операція виконується на апаратному рівні, не задіюючи в даному процесі ні процесор, ні оперативну пам’ять.
Підсистема ГРЧ включає в себе контролер та невеликий блок пам’яті об’ємом 64 байт. Перші 14 байт використовються для відліку часу; решта 50 байт зберігають інформацію про конфігурацію системи. Підсистема забезпечує наступні функції:
відлік поточного часу з точністю до 1 с;
роботу будильника, який у встановлений час генерує сигнал переривання лінією IRQ8, закріпленним за вектором 70h;
режим періодичних переривань (лінією IRQ8), частоту яких можна програмно налаштовувати у межах від 2 Гц до 8 КГц;
зберігання даних про конфігурацію системи (об’єм базової та розширеної пам’яті, типи магнітних дисків і т.д.);
зберігання даних прикладних програм.
У таблиці 3.1 наведено призначення окремих байтів КМОП-пам’яті (0-3Fh).
Таблиця 3.1 – Адресний простір пам’яті КМОП-мікросхеми
Адреса
поля
Кількість байт
Призначення
1
2
3
00h
1
Секунди в BCD
01h
1
Секунди будильника в BCD
02h
1
Хвилини в BCD
03h
1
Хвилини будильника в BCD
04h
1
Години в BCD
05h
1
Години будильника в BCD
06h
1
День тижня (може бути відсутній)
07h
1
Число в BCD
Продовженя таблиці 3.1
1
2
3
08h
1
Місяць (січень – 1, лютий – 2 і т.д.) в BCD
09h
1
Рік, молодші дві цифри в BCD
0Ah
1
Регістр A
0Bh
1
Регістр В
0Ch
1
Регістр С
0Dh
1
Регістр D
0Eh
1
Байт діагностування
0Fh
1
Байт кода скиду процесора
10h
1
Типи HDD (якщо менше 15)
11h
1
Зарезервовано
12h
1
Типи дискет
13h
1
Зарезервовано
14h
1
Склад встановленого обладнання
15h
2
Об’єм базової пам’яті, Кбайт
17h
2
Об’єм розширеної пам’яті, Кбайт
19h, 1Ah
2
Тип першого HDD (якщо більше 15)
1Bh
14
Зарезервовано
2Eh
2
Контрольна сума байтів 10h-2Dh
30h
2
Об’єм розширеної пам’яті, Кбайт
32h
1
Рік, перші дві цифри в BCD
33h
1
Системна інформація
34h
12
Зарезервовано
Байти з номерами 0Ah, 0Bh, 0Ch та 0Dh виконують функції керуючих регістрів.
0Ah – регістр стану RTC:
7 6 5 4 3 2 1 0
0-3: швидкість відліку
4-6: дільник
7: прапор оновлення
0Bh – регістр стану RTC:
7 6 5 4 3 2 1 0
0: тип часу
1: 12- або 24-годинний формат часу
2: формат даних: 0=BCD,
1=двійковий;
3: 1=дозволити прямокутний імпульс
4: 1=дозволити переривання від
кінця оновлення
5: 1=дозволити переривання
будильника (сигнальне переривання)
6: 1= дозволити періодичне
переривання
7: прапор оновлення
0Ch – регістр стану RTC: біти стану переривання (тільки чатання).
0Dh – регістр стану RTC. Біт D7=1, якщо CMOS отримує живлення від автономного джерела; 0 – відсунє живлення від автононого джерела.
0Eh – байт байт результатів початкового тестування.
7 6 5 4 3 2 1 0
0 0
2: 1= формат поточного часу
3: 1=HDD не завантажується
4: 1=розмір ОЗП неправильний
5: 1=пристрій не відповідає
конфігурації CMOS
6: 1=неправильна контрольна сума CMOS
7: 1=не працює автономне джерело живлення
CMOS
0Fh – байт стану перезавантаження. Цей байт зчитується після скиду ЦП, щоб визначити, чи не було скиду, викликаного виведенням 80286 з захищеного режима. Він може мати наступні значення:
0 – гарячий рестарт (Ctrl-Alt-Del) або неочікувана зупинка;
1 – зупинка після визначення розміру ОЗП;
2 – зупинка після тестування пам’яті;
3 – зупинка після виявлення помилки паритета пам’яті;
4 – рестарт за запитом початкового завантажувача;
5 – рестарт за скидом контролера переривань та JMP FAR PTR [0:467h];
6, 7, 8 – зупинка після теста захищеного режиму;
9 – рестарт за JMP FAR PTR [0:467h].
Звертання до байтів КМОП-пам’яті здійснюється за допомогою портів 70h та 71h у два етапи: спочатку в порт 70h записується номер необхідного байта пам’яті; потім через порт 71h виконується читання (in) чи запис (out) байта пам’яті.
Наприклад, прочитаємо та виведемо на екран поточний рік. На лістингу 3.1 наведено вихідний текст програми.
Лістинг 3.1 – Програма читаня з RTC інформації про об’єм розширеної пам’яті
#include <stdio.h>
#include <dos.h>
int main (void)
{
unsigned char XMS_H,XMS_L;
int XMS;
outportb(0x70,0x17);
XMS_L=inportb(0x71);
outportb(0x70,0x18);
XMS_H=inportb(0x71);
XMS=XMS_H;
XMS=XMS>>8;
XMS+=XMS_L;
printf("Об’єм розширеної пам’яті = %dKb",XMS+1024);
return 0;
}
Після виконання програми 2-байтна змінна XMS матиме значення на 1024 менше, ніж повний об’єм пам’яті (у Кбайтах), встановленої на комп’ютері. Аналогічно можна отримати, наприклад, об’єм базової пам’яті (байти 15h та 16h).
Описаним вище способом можна звертатись до всіх чарунок CMOS-пам’яті, за винятком перших десяти. Справа в тому, що КМОП-мікросхема один раз за секунду виконує корекцію поточного часу та перевірку стану будильника. На час корекції ділянка КМОП-пам’яті, яка відноситься до годин, календаря та будильника, відключається від системної магістралі та стає недоступним для програмного звертання. На це й же час встановлюється біт D7 регістра А. Тому перед зверненням до адрес 00h-09h CMOS-пам’яті необхідно спочатку дочекатись скиду біта D7 регістра А, що вказує на завершення процесу корекції і тільки потім здійснювати зверення до пам’яті. В лістингах 3.2-3.3 продемонстровано читання чарунок КМОП-пам’яті з очікуванням закінчення цикла корекції.
Лістинг 3.2 – Програма читання з RTC та виведення на екран поточного року
#include <stdio.h>
#include <dos.h>
int main (void)
{
unsigned char YearH, YearL;
do{
outportb(0x70,0x0A);
}while ((inportb(0x71)&0x80)==1); //біт D7 рег. А
// встановлено?
outportb(0x70,0x32); //байт 32h - старші 2 цифри року
YearH=inportb(0x71);
outportb(0x70,0x09); //байт 9h - молодші 2 цифри року
YearL=inportb(0x71);
printf("Поточний рiк: %02x%02x",YearH,YearL);
return 0;
}
Лістинг 3.3 – Програма читання з RTC та виведення на екран поточної дати
#include <stdio.h>
#include <dos.h>
int main (void)
{
unsigned char Day, Mon;
do{
outportb(0x70,0x0A);
}while ((inportb(0x71)&0x80)==1); //корекцію завершено (D7 Ah)?
outportb(0x70,0x07); //07 – число в ВСD (з табл. 3.1)
Day=inportb(0x71);
outportb(0x70,0x08); //08 – місяць в ВСD (з табл. 3.1)
Mon=inportb(0x71);
printf("Поточна дата: %02x.%02x",Day,Mon);
return 0;
}
ГРЧ працює від внутрішнього кварцового генератора, частоту якого підібрано таким чином, щоб сигнали на його виході (після перерахунку) мають частоту точно 1 Гц (щосекунди). Ці сигнали використовуються для відліку поточного часу в байтах годин та календаря КМОП-пам’яті. Окрім постійного перерахунку, який забезпечує частоту 1 Г, в КМОП-схему включено ще вузол настроюваного перерахунку, вихідні сигнали якого поступають на лінію IRQ8, ініціалізуючи перілдичні переривання через вектор 70h. Коефіцієнт перерахунку і, відповідно, частоту періодичних переривань можна програмного налаштовувати, змінюючи біти D0-D3 регістра А. Для дозволу/заборони періодичних переривань використовується біт D6 регістра В.
Встановлення будильника здійснюється записом необхідного часу розбудження в байти секунд, хвилин та годин КМОП-пам’яті (див. таблицю 3.1). Під час запису в ці чарунки необхідно передбачити очікування кінця циклів корекції, як це показано у лістингу 3.2. Схеми таймера періодично порівнюють поточний час з часом, який записаний у байтах будильника, і при досягненні рівності збуджує сигнал сигнального переривання на лінії IRQ8. Для дозволу/заборони сигнальних переривань необхідно ініціалізувати біт D5 регістра В.
Якщо відповідні значення встановлено у всіх трьох байтах будильника, сигнальні переривання буде формуватись у вказаний час щодоби. Проте програмно можна встановити в одном або декількох байтах будильника “довільний” код – будь-яке число від C0h до FFh. Якщо довільний код встановлено у байті годин будильника, то сигнальні переривання збуджуються щогодини. Після запису довільного кода у байт годин та хвилин – сигнал генерується щохвилини, а за наявності довільного коду у всіх трьох чарунках – щосекунди.Особливість цього режима заключається в тому, що переривання формуються не просто заданої частоти, а у заданий момент кожної хвилини або кожної години. Наприклад, якщо у байті сукунди записано число 30h, а в байтах хвилин та годин – C0h, то переривання будуть збуджуватись точно на 30-й секунді кожної хвилини.
При обробці переивань від CMOS-мікросхеми необхідно враховувати, що сигнали, призначені для збудження переривань (сигнальних та періодичних), поступають на вхід контролера переивань не безпосередньо, а через розряд D7 регістра С, який виконує функції прапора переривань. Програма обробки переривань повинна скинути прапор переривання, інакше подальші надходження сигналів переривань будуть заблокованими. Скид прапора переривань здійснюється шляхом читання регістру С.
Для читання та зміни показників RTC передбачено переривання BIOS 1Ah, функції якого звертаються безпосереньо до КМОП-пам’яті і дозволяють не тільки отримати чи встановити час та дату, але й керувати будильником.
Основні функції переривання BIOS 1Ah:
00h – отримання системного часу;
01h – встановлення системного часу;
02h – отримання часу від CMOS-годинника реального часу;
03h – встановлення часу у CMOS-годиннику реального часу;
04h – отримання дати від CMOS-календаря реального часу;
05h – встановлення дати у CMOS-календаря реального часу;
06h – встановлення будильника у CMOS-годиннику реального часу;
07h – відміна будильника у CMOS-годиннику реального часу.
Є ще переривання 4Ah, яке служить для перехоплення прикладною програмою сигнала від будильника RTC. INT 4Ah включено у системний обробник переривання 70h від будильника в RTC. Системний обробник цього переривання фактично виконує лиш команду IRET; прикладна програма може встановити власний обробник переривання 4Ah, який буде активізуватись сигналом будильника.
Як видно з таблиці 3.1, адреси СMOS 10h-2Dh захищено контрольною сумою, яка зберігається за адресою 2Eh. Тому зміна вмісту даних чарунок пам’яті необхідно супроводжувати зміною і контрольної суми.
Порт 70h використовується не тільки для індексування адреси CMOS-чарунки, але й для дозволу/заборони NMI (немасковане переривання). Якщо біт D7 скинуто, то NMI дозволено, якщо втсановлено – NMI заборонено.
ЗАВДАННЯ
Розробити блок-схему алгоритма та програму, яка:
Виводить на екран інформацію про встановлений формат часу (12- чи 24-годинний) годинника реального часу (RTC).
Виводить з комірок RTC на екран поточні дату й час, при чому назву місяця – прописом (наприклад, “1 лютого 2013 року, 09:20:25”), а час має продовжувати йти до натиснення користувачем клавіші Esc.
Програмує будильник RTC на час, введений користувачем з клавіатури, та вмикає сигнальне переривання будильника (біт D5 регістра 0Вh).
Визначає, чи отримує CMOS-мікросхема живлення від автономного джерела (акумулятора) та виводить відповідну інформацію на екран.
Записує у комірки CMOS-пам’яті за адресами 34h-3Fh рядок символів – прізвище студента.
ПИТАННЯ ДЛЯ САМОКОНТРОЛЮ
Що таке годинник реального часу (RTC)? Чим забезпечується його енергоне-залежність?
Що таке CMOS-пам’ять? Який об’єм її пам’яті та особливості організації?
Яким чином здійснюється читання/запис CMOS-пам’яті ?
Яка кількість чарунок RTC?
Чому не бажано використовувати у прикладних програмах резерв CMOS-пам’яті для зберігання даних?
В якому форматі зберігаються дані RTC? Чому?
Поясніть функціональну взаємодію системного таймера, RTC та таймера ОС?
Що відбудеться, якщо акумулятор (батарея) RTC повністю розрядиться?
Яка особливість зберігання в RTC значення поточного року?
Чому чарунки CMOS з адресами 10h-2Dh захищені контрольною сумою, а решта – ні?
ПРИКЛАД ВИКОНАННЯ ЛАБОРАТОРНОЇ РОБОТИ №3
МЕТА: Набути навичок програмування та роботи з годинником реального часу (RTC).
ЗАВДАННЯ
Написати програму, яка виводить на екран встановлений час будильника RTC.
ВИКОНАННЯ
Для одержання значень годин, хвилин та секунд будильника RTC необхідно прочитати байти RTC 01h, 03h, 05h відповідно (табл. 3.1). Здійснюється доступ до даних КМОП-пам’яті за допомогою порту 70h та 71h за аглоритмом:
1) в порт 70h записати номер байта, з якогонеобхідно прочитати інформацію.
2) з порту 71h прочитати значення байта, номер якого записано в порт 70h.
Блок-схема алгоритму
Лістинг програми
#include <stdio.h>
#include <dos.h>
int main (void)
{
unsigned char Day, Mon;
do{
outportb(0x70,0x0A);
}while ((inportb(0x71)&0x80)==1); outportb(0x70,0x01);
printf("Час будильника RTC: %02x:",inportb(0x71));
outportb(0x70,0x03); printf("%02x:",inportb(0x71));
outportb(0x70,0x05); printf("%02x",inportb(0x71));
getch();
return 0;
}
Результат роботи програми:
Час будильника RTC: 00:00:00