МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ "ЛЬВІВСЬКА ПОЛІТЕХНІКА"
Кафедра САПР
ГРАФІЧНО-РОЗРАХУНКОВА РОБОТА
З курсу :
«Системне програмування»
(Варіант 14)
ЛЬВІВ – 2015
Робота з годинником реального часу.
Сучасні комп’ютери оснащено двома підсистемами таймерів, які паралельно відраховують поточний час. Один таймер розміщено у мікросхемі з низьким споживання енергії (КМОП-мікросхема), яка після вимкнення живлення комп’ютера продовжує працювати, отримуючи енергію від вбудованого у комп’ютер аккумулятора (батареї). Цей таймер, як правило, називають годинником реального часу (RTC); окрім кварцевого генератора і систем керування він має внутрішню пам’ять, у якій зберігається й постійно нарощується значення поточного часу. Оновлення часу здійснюється щосекунди, причому ця операція виконується на апаратному рівні, не задіюючи в даному процесі ні процесор, ні оперативну пам’ять.
Підсистема ГРЧ
Підсистема ГРЧ включає в себе контролер та невеликий блок пам’яті об’ємом 64 байт. Перші 14 байт використовються для відліку часу; решта 50 байт зберігають інформацію про конфігурацію системи. Підсистема забезпечує наступні функції:
відлік поточного часу з точністю до 1 с;
роботу будильника, який у встановлений час генерує сигнал переривання лінією IRQ8, закріпленним за вектором 70h;
режим періодичних переривань (лінією IRQ8), частоту яких можна програмно налаштовувати у межах від 2 Гц до 8 КГц;
зберігання даних про конфігурацію системи (об’єм базової та розширеної пам’яті, типи магнітних дисків і т.д.);
зберігання даних прикладних програм.
У таблиці наведено призначення окремих байтів КМОП-пам’яті (0-3Fh).
Адресний простір пам’яті КМОП-мікросхеми
Адреса
поля
Кількість байт
Призначення
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
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 наведено вихідний текст програми.
Програма читаня з 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 продемонстровано читання чарунок КМОП-пам’яті з очікуванням закінчення цикла корекції.
Програма читання з 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 заборонено.
Задача 1
Написати з використанням циклів і оформити згідно вимог програму на асемблері для рисування вказаним кольором прямокутника заданого розміру у місці екрану, заданому координатами лівої верхньої вершини за допомогою мишки.
Ширина - 75
Висота - 45
Колір – 5
Текст програми:
title first
sseg segment stack
db 256 dup(?)
sseg ends
dseg segment
pc dw ?
dseg ends
cseg segment
assume ss:sseg,cs:cseg,ds:dseg
start: jmp main
main: push ds
mov ax,0
push ax
mov ax,dseg
push ax
mov ax,12h
int 10h
mov ax,0
int 33h
p: mov ax,1
int 33h
d: mov ax,3
int 33h
test bx,10b
jnz ex
test bx,1b
jz d
mov ax,2
int 33h
mov si, cx
mov pc, si
add si,75
dec si
mov di, dx
add di,45
dec di
mov al,5
mov bh,0
mov ah,0ch
c1: mov cx, pc
c: int 10h
inc cx
cmp cx,si
jle c
inc dx
cmp dx,di
jle c1
ex: mov ax,4c00h
int 21h
cseg ends
end start
/
Задача 2
З використанням функції DOS написати програму для роботи з файлами та каталогами створити каталог (прізвище студента) , перейти в створений каталог, створити і відкрити файл ( ім’я студента ), записати й файл текст (ім’я батька), закрити файл і перейти в кореневий каталог.
sseg segment stack ; опис стеку
db 256 dup (?)
sseg ends
;------------------------------------------------------------
dseg segment ; опис даних
newcat db '\Lutsyshyn',0
newfile db 'Ihor',0
rootcat db 'c:\',0
poch db 'Vvedit imja batka: $'
buf db 15 dup(?)
c db 0
error db 'error$'
dseg ends
;-----------------------------------------------------------
cseg segment ; типовий початок програми
assume cs:cseg, ds:dseg, ss:sseg
start: jmp main
main: push ds
mov ax,0
push ax
mov ax,dseg
mov ds,ax
;-----------------------------------------------------------
mov dx, offset poch
mov ah, 9
int 21h
;----------------------------------------------------------
mov si, 0
c0: mov ah, 01h
int 21h
cmp al, 27
je c1
mov buf[si], al
inc si
inc c
jmp c0
;----------------------------------------------------------
c1: mov dx,offset newcat ; створення нового каталога
mov ah,39h
int 21h
jc erop
;-----------------------------------------------------------
mov dx,offset newcat ; перехід в створений каталог
mov ah,3bh
int 21h
jc erop
;-----------------------------------------------------------
mov dx,offset newfile ; створення і відкриття нового файлу
mov cx,0
mov ah,5bh
int 21h
jc erop
mov bx,ax ; пересилання ідентифікатора файлу
;--------------------------------------------------------------------
mov dx,offset buf ; запис у файл
mov cx,si
mov ah,40h
int 21h
jc erop
;--------------------------------------------------------------------
mov ah,3eh ; закриття файлу
int 21h
jc erop
;--------------------------------------------------------------------
mov dx,offset rootcat ; перехід в кореневий каталог
mov ah,3bh
int 21h
jc erop
;--------------------------------------------------------------------
exit: mov ax,4c00h ; вихід з програми
int 21h
;--------------------------------------------------------------------
erop: mov dx,offset error ; виведення повідомлення про помилку на екран
mov ah,9
int 21h
jmp exit
cseg ends
end start
/
Створений каталог
/
Створений файл з іменем батька
/
Задача 3
Перейти у каталог (прізвище студента), відкрити файл (ім’я студента), прочитати текст (ім’я батька), вивести текст на екран, закрити файл, знищити файл, перейти в кореневий каталог, знищити каталог( прізвище студента).
sseg segment stack ; опис стеку
db 256 dup (?)
sseg ends
;---------------------------------------------------------
dseg segment ; опис даних
cat db '\Lutsyshyn',0
file db 'Ihor',0
buf db 256 dup(?)
bufend db '$'
rootcat db 'c:\',0
error db 'error$'
dseg ends
;-------------------------------------------------------------
cseg segment ; типовий початок програми
assume cs:cseg;ds:dseg;ss:sseg
start: jmp main
main: push ds
mov ax,0
push ax
mov ax,dseg
mov ds,ax ; пересилання ідентифікатора файлу
;-----------------------------------------------------------
mov dx,offset cat ; перехід в існуючий каталог
mov ah,3bh
int 21h
jc erop
;-----------------------------------------------------------
mov dx,offset file ; відкриття існуючого файлу
mov al,0
mov ah,3dh
int 21h
jc erop
mov bx,ax
;-------------------------------------------------------
mov dx,offset buf ; читання байтів у буфер
mov cx,10
mov ah,3fh
int 21h
jc erop
;-------------------------------------------------------
mov ah,9 ; вивід вмісту буфера на екран
int 21h
;-------------------------------------------------------
mov ah,3eh ; закриття файлу
int 21h
jc erop
;--------------------------------------------------------
mov dx,offset file ; видалення файлу
mov ah,41h
int 21h
jc erop
;--------------------------------------------------------------------
mov dx,offset rootcat ; перехід в кореневий каталог
mov ah,3bh
int 21h
jc erop
;--------------------------------------------------------------------
mov dx,offset cat ; видалення каталога
mov ah,3ah
int 21h
jc erop
;--------------------------------------------------------------------
exit: mov ax,4c00h ; вихід з програми
int 21h
;-------------------------------------------------------------------
erop: mov dx,offset error ; вивід повідомлення про помилку на екран
mov ah,9
int 21h
jmp exit
cseg ends
end start
Каталог видалений
/ЛІТЕРАТУРА
Р. Джордейн. Справочник программиста персональных комп’ютеров типа IBM PC, XT и АТ.
Зубков С.В. Assembler для DOS, Windows и Unix.