ЗМІСТ
ВСТУП. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Практичне завдання 1. Представлення інформації у цифровому вигляді. . . . 6
Практичне завдання 2. Програмування мовою Assembler. . . . . . . . . . .9
Практичне завдання 3. Порівняння мов програмування С/С++ та Паскаль. . . 13
Практичне завдання 4. Використання функцій ВІOS. . . . . . . . . . . . . . .25
Практичне завдання 5. Використання портів для обміну даними. . . . . . . . 38
Практичне завдання 6. Використання можливостей Win-32 API. . . . . . . . .52
Практичне завдання 7. Використання функцій вводу-виводу. . . . . . . . . . 62
Практичне завдання 8. Використання функції DeviceIoControl. . . . . . . . . 66
Практичне завдання 9. Використання драйвера. . . . . . . . . . . . . . . . . .71
Практичне завдання 10. Недокументований доступ до портів. . . . . . . . . .75
Додаток А. Програмні коди функцій користувача, які можуть використовуватися при читанні і записі інформації на зовнішніх пристроях. .82
Додаток Б. Функції користувача для читання сектора з диску і запису на диск
з використанням функції DeviceIoControl. . . . . . . . . . . . . . . . . . . . . 85
Додаток В. Класи для читання і запису інформації з використанням драйвера для роботи в Windows 98/ME з портами. . . . . . . . . . . . . . . . . . . . . . 88
Додаток Г. Приклади програм класів недокументованого доступу до портів в операційних системах Windows 95/98/ME. . . . . . . . . . . . . . . . . . . . . 91
Список використаних джерел. . . . . . . . . . . . . . . . . . . . . . . . . . . .96
Вступ
Перед тим, як приступити до курсу практичних робіт з системного програмування, перейти до програмування системних функцій та апаратного програмування пристроїв в операційних системах сімейства Windows, потрібно насамперед розібратися в основних принципах доступу до апаратної частини комп’ютера під цими системами. А вони, на превеликий жаль, досить дещо збіднені і, я б сказав, однобокі. Існують як мінімум чотири офіційних способи прямого доступу до комп’ютерного устаткування, якщо так можна назвати на даному рівні:
Перший полягає в звичайному використанні набору функцій вводу-виводу: _outp, _outpw, _outpd, _inp, _inpw, _inpd. Вони входять до складу бібліотеки часу виконання, але їх використання досить сильно залежить від операційної системи. Практично всі нові системи Windows не дозволяють працювати з цими функціями в вільно доступному режимі програмування.
Другий спосіб базується на застосуванні універсальної ресурсної функції вводу-виводу DeviceIoControl. Головна перевага при її застосуванні полягає в однозначній підтримці даної функції всіма системами Windows, починаючи Windows95 і закінчуючи останніми версіями - Windows SR3 Windows Vista. Але у цієї функції є один серйозний недолік – це дуже обмежений діапазон її застосування. Не дивлячись на те, що вона дозволяє здійснювати роботу з дисковою системою і з новітніми інтерфейсами передачі даних, отримати прямий доступ до пристроїв за її допомогою не вдається.
Третій спосіб полягає в банальному створенні драйвера (наприклад, віртуального драйвера пристрою), що дозволяє отримати необмежений доступ до всіх пристроїв в системі. Крім того, даний варіант прекрасно буде працювати у всіх операційних системах Windows. Основний недостаток цього методу полягає у відносній складності написання програмного коду самого драйвера, а також необхідність створення окремого варіанта драйвера для кожної операційної системи зокрема. Наприклад, якщо програма написана під Windows 98 і Windows 2000, то доведеться писати два різні драйвери під кожну систему.
Останній спосіб полягає в використанні «вмонтованого» в (Visual) C++ макроасемблера. Він не дозволяє застосовувати переривання, тому що Windows буде зависати, проте зовсім непогано працює з апаратними портами.
Оскільки кожен із підходів заслуговує уваги в області системного програмування, розробляючи наш курс методичного посібника, ми будемо посилатися на усі ці підходи. Зразу слід відмітити, що вибір того чи іншого підходу із вищепредставлених варіантів буде цілком залежати, в першу чергу, від версії операційної системи, а потім тільки від поставлених завдань програмування. Із цим потрібно примиритися, так як обійти його практично неможливо. Це полягає в тому, що фірма Microsoft з кожним роком, розробляючи нові версії операційної системи Windows, все менше і менше залишає можливостей прямого доступу до пристроїв. Це можна зрозуміти, знаючи, що такий підхід веде до підвищення надійності операційної системи, з однієї сторони, але з іншої сторони,- блокується розвиток конкурентного і часто більш якісного програмного забезпечення.
Протягом висвітлення методичного матеріалу ми розберемо базові підходи самих інструментів системного програмування на практиці, тобто елементи асемблера, базові знання з мови програмування С/С++ та їх застосування на практиці програмування, а потім звернемося до альтернативних варіантів програмування апаратних засобів за допомогою уже згаданих інструментів програмування, можливостей операційної системи Windows та її базових понять. Слід наголосити, що ця задача не буде виконуватися в широкомасштабному варіанті програмування для всіх зовнішніх пристроїв, так як такий курс є набагато тривалішим в розподілі часу, а тільки для пристрою клавіатури як одного із головних терміналів вводу інформації. Додамо, що інші пристрої апаратури комп’ютера програмуються такими ж підходами із застосуванням тих же мовних інструментів програмування, набору ресурсів та функції.
Практичне завдання 1
Тема: Виконання переведення чисел в двійкову та шістнадцяткову системи числення
Мета: навчитися переводити числа в двійкову та шістнадцяткову системи числення та виконувати математичні дії.
Теоретичні відомості викладені в розділі 1 методичного посібника з системного програмування для самостійних робіт.
Хід роботи.
Виконайте математичні обчислення, імітуючи роботу процесора. Задані два числа: 308 та 241. Для даних двох чисел виконайте переведення у двійкову систему числення, математичні дії додавання та віднімання. Задайте вихідні два числа в шістнадцятковій системі числення.
1. Переводимо обидва числа з десяткового у шістнадцяткове числення.
Визначаємо шістнадцяткове значення числа 308
308 | 16
залишок 4 | 19| 16
залишок 3 | 1| 16
залишок 1 |
дорівнює 134h
Відповідно шістнадцяткове значення числа 241
241 | 16
залишок 1 | 15| 16
залишок 15 | 0
дорівнює F1h
2. Застосовуємо таблицю відповідності шістнадцяткових цифр двійковим тетрадам для переведення отриманих значень у двійкове числення:
134h = 000100110100b
F1h = 000011110001b
3. Аналогічним чином переводимо два числа у двійкове значення для перевірки перетворення тетраедр, наприклад як число 124 у двійкову систему числення:
124 | 2
залишок 0 | 62 | 2
залишок 0 | 31| 2
залишок 1 | 15 | 2
залишок 1 | 7 | 2
залишок 1 | 3 | 2
залишок 1 | 1 | 2
залишок 1 | 0
Значення числа 124 у двійковій системі числення 1111100b.
4. Виконаємо додавання у двійковому численні:
000100110100b
+ 000011110001b
001000100101b
5. Здійснюємо перевірку результату додавання, виконавши дії переведення результату у десяткову систему (через визначення шістнадцяткових значень тетрад):
001000100101b = 225h
2*162 + 2*161 + 5*160 = 549
308 +241 = 549
6. Виконаємо віднімання меншого за значенням числа від більшого через застосування операції інверсії:
(-241) = 111100001110b + 1b = 111100001111b
000100110100b
+ 111100001111b
(1) 000001000011b
7. Здійснюємо перевірку результату віднімання, виконавши дію переведення результату у десяткову систему (через визначення шістнадцяткових значень тетрад).
000001000011b = 43h
4*161 + 3*160 = 67
308 +241 = 67
Математичні обчислення виконані правильно.
8. Робимо висновок проведеної лабораторної роботи і, закінчивши оформлення, здаємо викладачу на перевірку.
Варіанти завдань:
Варіант |
Перше число |
Друге число |
Варіант |
Перше число |
Друге число |
1. |
754 |
325 |
16. |
829 |
422 |
2. |
980 |
200 |
17. |
763 |
137 |
3. |
675 |
433 |
18. |
561 |
279 |
4. |
834 |
481 |
19. |
696 |
417 |
5. |
755 |
301 |
20. |
691 |
279 |
6. |
995 |
447 |
21. |
836 |
426 |
7. |
902 |
307 |
22. |
647 |
287 |
8. |
787 |
479 |
23. |
818 |
479 |
9. |
979 |
187 |
24. |
773 |
273 |
10. |
821 |
299 |
25. |
907 |
403 |
11. |
647 |
511 |
26. |
674 |
172 |
12. |
589 |
375 |
27. |
852 |
631 |
13. |
788 |
237 |
28. |
893 |
241 |
14. |
844 |
164 |
29. |
846 |
349 |
15. |
947 |
405 |
30. |
649 |
472 |
Практичне завдання 2
Тема: Виведення символьної стрічки на екран за допомогою мови Asembler
Мета: навчитися (згадати) методи програмування в мові Асемблер, застосовуючи команди вводу-виводу та відповідні регістри і функції.
Теоретичні відомості викладені в розділі 2 методичного посібника з системного програмування для самостійних робіт.
Хід роботи:
1. Розробити програму для введення - виведення стрічкових написів на екран монітора, застосовуючи різні функції операційної системи (DOS).
2. Формуємо функціональне наповнення.
Найбільш поширеними діями у будь-яких прикладних програмах є операції введення – виведення. Мовою Assembler, окрім виклику функції самої операції, необхідно здійснити ряд додаткових дій, наприклад перевірити готовність відповідного пристрою. У зв'язку з цим, для типових пристроїв розроблені стандартні програми організації введення - виведення, які викликаються разом із функціями переривання, що звертаються до операційної системи INT 21h.
Перелік основних функцій DOS для реалізації підпрограмам введення–виведення наведені у таблиці нижче. Код будь-якої функції завжди повинен передаватися у підпрограму через старший байт AH регістра AX.
Код функції |
Функція |
01h |
Введення з клавіатури та виведення на монітор одного символу (переривання функції Ctrl-Break) |
02h |
Виведення одного символу на екран дисплея з регістра DL (переривання функції Ctrl-Break) |
07h |
Введення в регістр AL (без переривання функції Ctrl-Break, з очікуванням) |
09h |
Виведення рядка на екран (DS:DX - адреса рядка, який повинен завершуватися символом "$") |
0Ah |
Введення рядка до буфера з виведенням на монітор (DS:DX - адреса буфера, перший байт якого повинен містити розмір символів буфера, далі резервний байт та поле буфера) |
3. Формуємо мову завдань.
Синтаксис мови завдань буде представлений такими поняттями:
Адреса – величина, що визначає розміщення даних.
Адреса команди – адреса пам’яті, зайнятої командою.
Поле – ділянка носія інформації, або пам’яті, яка використовується для особливого класу елементів даних.
Символьний рядок – рядок, який містить виключно символи.
4. Системне наповнення. До системного наповнення програми відносимо ресурси операційної системи Windows 9X-XP, транслятор Assembler.
5. Послідовність створення програми. Кодування здійснюється згідно з таким лістингом:
data segment ; початок сегменту даних (; позначає опис-коментар)
;----------- резервуємо п’ять рядків напису для подальшого виведення
str0 db 'Програма для функцій введення-виведення',13, 10,'$'
str1 db 'Функція 01h (одночасне виведення на екран символу з клавіатури)- символ-$'
str2 db 'Функція 07h (введення з клавіатури через регістр AL без виведення на екран)',13,10, '$' ; запис повинен бути в один рядок без перенесення
str3 db 'Функція 02h (виведення на екран символу з регістра AL) - символ - $'
str4 db 'Функція 0Ah (одночасне введення-виведення через буфер 10-ти символів)-$'
;----------- резервуємо порожній рядок за рахунок кодів 13 (введення каретки) ;та 10 (перехід на початок рядка)
ent db 13,10,'$' ; резервуємо коди для переведення курсора на новий рядок
;----------------- початок структури буфера
max db 10 ;максимальна кількість символів
len db ? ;резервний байт
bufer db 11 dup (?) ;буфер для розміщення кодів символів
db ? ;байт для розміщення знаку $
;----------------- кінець структури буфера
data ends ;кінець сегмента даних
code segment ; початок сегмента коду (коментар)
assume cs:code, ds:data ;директива assume повідомляє значення
;сегментних регістрів
begin: ; мітка початку виконавчого коду
mov ax, data ; налаштовуємо регістр даних, вміщуємо адресу сегменту
mov ds, ax ;даних до регістру AX.
; -------------- конструктори функції 09h.
lea dx,ent ;вказуємо зміщення на рядок - зарезервоване поле ent.
mov ah,09h ;функцію виведення рядка на екран 09h вміщуємо до ah.
int 21h ;виконується переривання DOS.
lea dx,str0 ;вказуємо зміщення на зарезервований рядок str0.
mov ah,09h ;функцію виведення рядка на екран 09h вміщуємо до ah.
int 21h ;виконується переривання DOS.
lea dx,str1
mov ah,09h ;виведення рядка str1.
int 21h
; ----------------конструктор функції 01h
mov ah,01h ;функцію одночасного виведення на екран символу з клавіатури
;поміщаємо до ah
int 21h ;виконується переривання DOS
; ----------------конструктори функції 09h
lea dx, ent
mov ah,09h ;виведення порожнього рядка
int 21h
lea dx,str2
mov ah,09h ;виведення рядка str2
int 21h
lea dx,str3
mov ah,09h ;виведення рядка str3
int 21h
; ----------------конструктор функції 07h
mov ah,07h ;функція введення з клавіатури без виведення на екран
;код символу заноситься до регістра AL
int 21h
; --------------конструктор функції 02h
mov dl,al ;код символу переміщається до регістра DL
mov ah,02h ;функція виведення на екран символу
int 21h ;виконується переривання DOS
; --------------конструктори функції 09h
lea dx,ent ;виведення порожнього рядка
mov ah,09h
int 21h
lea dx,str4
mov ah,09h ;виведення рядка
int 21h
; ------------------конструктор функції 0Ah
mov ah,0ah ;функція введення-виведення через буфер символів
lea dx, max ;вказуємо зміщення на структуру буфера
int 21h
mov bl, len ;формування адреси у регістрі BX
mov bh,0
mov [bx+bufer+1],'$' ;додавання знака $ у кінець буферу шляхом
; непрямої адресації пам’яті
; ------------------конструктор функції 4Ch
mov ah, 4ch ;функція завершення програми з виходом у DOS
int 21h
code ends ;кінець сегмента коду
end begin ;кінець коду програми
6. Реалізація програми. Вікно виконаної програми наведене на рис.1.
Рис.1. Програма практичного завдання 2 після виконання
7. Дооформіть свою практичну роботу і здайте її на перевірку, зробивши висновок.
Варіанти виконання практичної роботи:
Варіант |
Набір символів |
Варіант |
Набір символів |
1. |
qwaszxcvdf |
16. |
vbasdpofgh |
2. |
qwertyuiop |
17. |
qawszxderf |
3. |
poiuytrewq |
18. |
lopkmjyhtv |
4. |
trewqpoiuy |
19. |
egauehgfdl |
5. |
opiutyreqw |
20. |
dfvghbjkma |
6. |
wqopiuerty |
21. |
bgtyhnmkop |
7. |
asdfghjklq |
22. |
xswedcvfrq |
8. |
lkjhgfdsap |
23. |
mjnhbgvfcdx |
9. |
asdlkjhgfe |
24. |
zsxdcfvgbh |
10. |
dfasghklji |
25. |
cvdbngmhxa |
11. |
hjkgfdlsaw |
26. |
czxbmnfvgp |
12. |
kjlhfgdasr |
27. |
cbnxmzvfgq |
13. |
hjdkhgasdl |
28. |
xzmncvbgwo |
14. |
kalshdjfgt |
29. |
zxcmnbfgvy |
15. |
mnbvcxzert |
30. |
ercvtybvnu |
Практичне завдання 3
Тема: Аналіз відмінностей мов програмування C/Сі++ та Паскаль
Мета: одержання практичних навичок при створенні програм із застосуванням мови Сі.
Теоретичні відомості.
Поняття про мову програмування. Класифікація мов програмування. Основні поняття мови. Основні елементи мови программування.
Мова — це сукупність засобів фіксації повідомлень для накопичення, передачі та обробки інформації. Мови можуть мати як природне, так і штучне походження. Штучні мови, як правило, будуються у вигляді формальної граматики, і тому їх називають формальними. До формальних мов належать алгоритмічні мови та мови програмування.
Алгоритмічні мови призначені для подання алгоритмів у вигляді деякої послідовності повідомлень з метою їх передачі виконавцеві алгоритмів. Якщо алгоритмічна мова використовується для запису алгоритмів, які будуть реалізовані (виконані) за допомогою обчислювальної машини, то такі мови називають мовами програмування (МП).
Залежно від ступеня відповідності між системою вказівок МП і системою команд центрального процесора комп'ютера МП поділяють на:
• машинно-орієнтовні (низького рівня);
• машинно-незалежні (високого рівня).
До машинно-орієнтовних МП відносять мову машинних команд та мови символьного програмування, такі, наприклад, як мова Асемблер. У мові машинних команд кожна команда відповідає одній з операцій, яку на своєму фізичному рівні здатний виконати процесор обчислювальної машини певної моделі. Тому можна сказати, що мова машинних команд — це мова команд процесора обчислювальної машини. Усі команди процесора мають свої числові коди. Після коду команди вказують, звідки потрібно взяти дані для її виконання (із комірок пам'яті, із портів зовнішніх пристроїв, регістрів самого мікропроцесора) і куди помістити результати виконання команди.
У мовах високого рівня формальний запис вказівок (операторів) наближений до логічних конструкцій, які притаманні людському мисленню. Такі вказівки (оператори) задають певні логічно завершені етапи обробки даних. Перед виконанням кожна з таких вказівок замінюється послідовністю відповідних машинних команд, які в сукупності замінюють одну вказівку мови програмування високого рівня. Типовими вказівками (операторами) в мовах високого рівня є вказівка присвоєння змінним значень певних виразів, вказівка розгалуження, вказівка організації циклів, вказівки введення, виведення даних. До мов високого рівня належать мови Фортран, Бейсик, Паскаль, Сі та інші.
Мови машинних команд Асемблер, Фортран, Бейсик, Паскаль, Ада, Сі та ін. належать до мов процедурного типу. У мовах процедурного типу обов'язково потрібно вказати послідовність дій, виконання яких призведе до отримання розв'язку.
З формальної точки зору МП — це набір вихідних символів (алфавіт) разом із системою правил утворення з цих символів формальних конструкцій (синтаксис) та системою правил тлумачення (інтерпретації) цих конструкцій (семантика), за допомогою яких описуються алгоритми.
Алфавіт, синтаксис та семантика — це три основні складові частини МП. В алфавіт МП, як правило, входять: літери латинського алфавіту, арабські цифри, знаки арифметичних операцій, розділові знаки, спеціальні символи. Із символів алфавіту будують послідовності, які називають словами. Кожне слово в МП має своє змістовне призначення. Правила синтаксису пояснюють, як потрібно будувати ті чи інші мовні повідомлення для задання всіх понять мови, здійснення описів та запису вказівок. Правила семантики пояснюють, яке призначення має кожний опис та які дії повинна виконати обчислювальна машина під час виконання кожної із вказівок. Вказівки на виконання конкретних дій називають ще командами або операторами мови.
Усі слова, з яких складають тексти програм, поділяють на службові (зарезервовані), стандартні ідентифікатори та ідентифікатори користувача. Імена (позначення) для програмних об'єктів (типів даних, констант, змінних, підпрограм тощо) формують у вигляді ідентифікаторів.
Ідентифікатор — це послідовність латинських літер, цифр і знаку підкреслення, яка розпочинається з латинської літери.
Службові слова мають наперед визначене призначення і використовуються для формування структури програми, здійснення описів, позначення операцій, формування керуючих конструкцій (вказівок).
Наприклад, службовими словами є: для мови Паскаль
and — і mod — остача
array — масив nil — нуль
begin — початок not — ні
case — вибір of — з
const — сталі or — або
div — ділення без остачі packed — стиснутий
do — виконати procedure — процедура
downto — униз до program — програма
else — інакше record — запис
end — кінець repeat — повторювати
file — файл set —, множина
for — для then — то
function — функція to — до
goto — перейти до type — тип
if — якщо until — доки
in — в var — змінні
label — позначка while — доки та інші.
для мови Сі
asm double mutable switch
auto else new template
bool enum operator this
break explicit private throw
case extern protected try
batch float public typedef
char for register typename
class friend return union
const goto short unsigned
continue if signed virtual
default inline sizeof void
delete int static volatile
do long struct while
Стандартні ідентифікатори використовуються як імена для стандартних (передбачених авторами мови програмування) типів даних, констант, підпрограм (зокрема, стандартних математичних функцій).
Ідентифікатори користувача є іменами тих програмних об'єктів (констант, змінних, підпрограм тощо), які створює сам користувач. Службові слова та ідентифікатори користувача не повинні збігатися.
Вираз — це конструкція мови програмування, за допомогою якої задають процес перетворення одних даних в інші. Елементами виразів є константи, змінні, функції, операції та дужки.
Структура програми: на мові Паскаль
Програма складається із заголовка
program <ім'я програми>;
розділів описової частини
uses — приєднання бібліотек та модулів;
label — оголошення міток (позначок);
const — оголошення сталих;
type — опис типів;
var — оголошення змінних;
procedure — оголошення процедур користувача;
function — оголошення функцій користувача
та виконуваної частини
begin
<розділ команд> end.
program Trykutnyk;
uses Crt; {Приєднуємо модуль Crt}
const a=5; b=3.6; c=4.2; {Вводимо довжини сторін}
var
p,s: real; {Оголошуємо змінні для}
{периметра та площі}
begin
clrscr; {Очищуємо екран}
р:=а+b+с; {Обчислюємо периметр}
writeln ('p=’, p:5:2); {Виводимо значення периметра}
s := a*b/2; {Визначаємо площу}
writeln('p=', p:5:2); {Виводимо значення площі}
writeln('s=', s:5:2); {Виводимо значення площі}
writeln('Виконав студент');
readln;
end.
на мові С/С++
// коментарі
#include <назва бібліотечного файлу 1>
…
#include <назва бібліотечного файлу N>
< інші директиви препроцесора>
…
< оголошення глобальних змінних>;
<оголошення глобальних сталих>;
<оголошення прототипів функцій користувача>;
…
<тип результату функції> main (опис формальних параметрів)
{
< оголошення локальних змінних>;
< оголошення локальних сталих>;
<команди>;
}
// Програма Трикутники
#include <iostream.h>
#include <math.h>
void main()
{
int a = 3, b = 4, c, p, s; // Задаємо довжини сторін
cout << “ Введіть гіпотенузу \n";
cin >> c; // Обчислюємо гіпотенузу
p = a + b + c; // Обчислюємо периметр
s = a*b/2; // Обчислюємо площу
cout << “p = “ << p<< "\n"; // Виводимо значення периметра
cout << “s = “ << s << "\n"; // та площі на екран
cout << "Виконав студент"
}
Директива #include <iostream.h> під'єднує бібліотечний файл iostream.h. Саме у цьому файлі описані функції, які дають змогу виконувати операції введення-виведення даних.
int main (void)
{
тіло функції з командою
return 0;
}
У програмі може бути записана обов'язкова функція main(). Ключове слово int означає, що функція main() повертатиме у точку виклику результат цілого типу. main() - заголовок функції. Ключове слово void означає, що функція не залежить від параметрів, його записувати не обов'язково.
У тілі функції містяться команди та виклики інших функцій. Команди одну від одної відокремлюють символом ";" (крапка з комою). Текст функції закінчується командою повернення return. Тіло функції (усі команди після заголовка) записується у фігурних дужках { } .
Команда return слугує для виходу з функції main(). Числовий параметр після return є результатом (значенням) функції (у цій програмі - 0).
Може бути записана функція
void main()
{
тіло функції;
}
Така функція називається функцією main() типу void. Вона не повертає у програму жодних значень, тому команду return писати не треба.
Конструкція cout << забезпечує виведення на екран монітора повідомлення. Операнд містить керуючу послідовність “\n”. Керуючі послідовності - це комбінації спеціальних символів, які використовуються для введення та виведення даних. Керуюча послідовність складається із символу слеш "\" і спеціально означеного символу. Вони призначені для форматованого виведення результатів обчислень на екран, наприклад, для переходу на новий рядок, подання звукового сигналу, а також для виведення на екран деяких спеціальних символів: апострофа, лапок тощо. Основні керуючі послідовності наведені у таблиці нижче:
Символи керуючих послідовностей |
Коментар |
\а,\7 |
Подати звуковий сигнал |
\b |
Повернути курсор на один символ назад (знищити попередній символ) |
\f |
Перейти на нову сторінку |
\n |
Перейти на новий рядок |
\r |
Повернути курсор на початок рядка |
\t |
Перевести курсор до наступної позиції табуляції |
\v |
Вертикальна табуляція |
\\ |
Вивести символ похилої риски |
\’ |
Вивести символ апострофа |
\” |
Вивести символ лапок |
\? |
Вивести знак запитання |
Директива #define має подвійне значення. По-перше, вона може задати стале значенню (оголошує сталу). Наприклад, якщо у програмі задано #define N 25, то N під час виконання програми матиме значення 25. По-друге, вона дає змогу описати макроси - короткі команди (переозначити команди) чи записати функції, наприклад, так:
#define D(a, b, c) ((b) * (b) - 4 * (a) * (c))
Тепер скрізь для обчислення дискримінанта замість команди
d=b*b-4*a*c
можна записувати
d = D(a, b ,c).
Директива #undef скасовує дію директиви #define.
Наприклад,
#define D (a,b,c) ((b) * (b) - 4 * (a) * (c))
#undef D
#define D(a,b,c) ((a) * (b) * (c))
Для мови Паскаль цей порядок старшинства (пріоритети) операцій задаються наступною таблицею:
-
№ групи операцій
Операції
1.
@, not
2.
shr
3.
+, -, or, xor,
4.
<, >, =, <>, <=, >=, in
Операції нижчої групи мають нижчий пріоритет (зв'язують свої аргументи слабше) порівняно з операціями вищої групи. Наприклад, вирази (А+В)*С і А+В*С задають різні порядки виконання операцій. Якщо підряд слідують операції з однаковим пріоритетом, то порядок їх виконання у випадку потреби задають за допомогою дужок. Наприклад, вирази А/В*С та А/(В*С) є різними.
Пріоритет |
Операції |
Зміст операції |
1 |
+, - |
Присвоєння знака |
2 |
*. /, % |
Множення, ділення, остача від ділення |
3 |
+, - |
Додавання, віднімання |
4 |
==, !=. <, <=, >, >= |
Порівняння (відношення) |
Розглянемо операції порівняння.
Операція = = означає дорівнює, != - не дорівнює,
<= - менше або дорівнює, >= -більше або дорівнює.
Виконання кожної операції здійснюється з урахуванням їхніх пріоритетів (тут 1 - найвищий). Для зміни звичайного порядку виконання операцій використовують круглі дужки.
Розглянемо результати виконання операцій
2*-5+ 4 =-6; 12/4-2=1;
2* (-5+ 4) = -2; 12/(4-2) = 6;
7 % 3 = 1; 7 % 3 * -5 = -5.
Нехай х = 3, у = 5. Дано вираз х = = у. Значенням цього виразу буде false (хибність), оскільки значення змінних х та у не рівні між собою, а значенням виразу х != у - true (істина), значеннями виразів х> у, х <= (у - 2) - відповідно false та true.
Операції інкременту (++) та декременту (--). Операції інкременту і декременту існують у двох формах - префіксній та постфіксній. Якщо символи ++ (—) записані перед змінною, то це інкремент (декремент) у префіксній формі, а якщо після змінної - у постфіксній. Операція інкременту має такий вигляд:
++<змінна> або <змінна>++
Дія операції. Значення змінної збільшується на одиницю. Команди ++а, а++ рівносильні команді а = а + 1. Форма інкременту (декременту) впливає на порядок виконання операцій у виразах.
Розглянемо це на прикладах.
Результати виконання команд
а = 2;
b = 3 * ++а;
будуть такими: а — З, b = 3 • 3 = 9. Тут використано операцію інкркменту у префіксній формі: спочатку збільшується значення змінної а на одиницю, а пізніше обчислюється вираз.
Розглянемо команди
с = 5; d = (C++) + 4;
Тут спочатку обчислюється вираз (для d) з с = 5, а потім збільшується значення змінної с на одиницю. Тобто
d = с + 4 = 5 + 4 = 9, с=с+1=5+1=6 (це операція інкременту у постфіксній формі).
Оскільки у виразі записано три знаки плюс "+" підряд, то для однозначного задання порядку операцій використано круглі дужки.
Аналогічно операція декременту.
Поняття про системи програмування. Поняття про інтерпретацію та компіляцію описів програм. Інтегровані середовища програмування
Текст алгоритму, записаний засобами конкретної мови програмування, називають програмою.
Процес програмування не зводиться лише до написання програми. Кожну програму потрібно відлагодити (виявити та виправити в ній синтаксичні та логічні помилки), перевести в машинні коди (відтранслювати), протестувати (виконати програму декілька разів, вводячи при цьому такі набори вхідних даних, які дозволяють отримати різні варіанти відповідей), зберегти програму у вигляді файла для її подальшого використання. Для автоматизації усіх цих етапів розробки програми використовують системи програмування. Для кожної мови програмування високого рівня існує своя система програмування. Відомими сьогодні є такі системи програмування як GW-Basic, Quick-Basic, Turbo-Pascal, Turbo-C, C++, Delphi, Java. У склад системи програмування входить екранний редактор, засоби відлагодження та трансляції програми в машинні коди, запуску програм на виконання, запису їх на диски та ряд інших засобів для реалізації різних сервісних функцій. З метою об'єднання всіх інструментальних засобів, необхідних для розробки програм, у рамках одного середовища сучасні системи програмування будуються як інтегровані середовища програмування. Інтегровані середовища програмування володіють багатовіконним інтерфейсом, керування яким здійснюється за принципом меню. Усі команди системи програмування та інструментальні засоби об'єднані за цільовою ознакою в окремі групи, які є пунктами головного меню системи. Наприклад, більшість інтегрованих середовищ програмування містять такі меню, як Files та Edit, перше меню містить команди для створення нових вікон, відкриття вікон для програм, які зберігаються на дисках, збереження програм, які містяться в вікнах, роздрукування текстів програм, друге меню містить, як правило, команди контекстного пошуку та заміни, копіювання, вирізання, вставки, знищення фрагментів тексту та інше. Для виконання найбільш часто вживаних команд використовують гарячі клавіші або кнопки панелей інструментів.
Переведення програм в машинні коди та їх виконання може здійснюватися шляхом інтерпретації та компіляції.
Під час інтерпретації кожна вказівка (команда) програми аналізується на предмет виявлення в ній синтаксичних та логічних помилок, переводиться в машинні коди, а потім виконується. Так відбувається з кожною командою, до якої в програмі доходить виконання.
Під час компіляції в усьому тексті програми виявляються синтаксичні та логічні помилки, після цього вся програма переводиться в машинні коди і лише тоді виконується.
Перевагами систем програмування, які побудовані на базі компіляторів, є висока швидкість виконання програм та можливість збереження відкомпільованої програми у вигляді виконуваних файлів (exe-файлів).
Типи даних
Тип даних характеризує внутрішнє уявлення, множину припустимих значень для цих даних, а також сукупність операцій над ними. Серед типів даних розрізняють стандартні (визначені розроблювачами мови) і типи користувача (обумовлені програмістом у своїй програмі). Розглянемо наступні стандартні типи: ціле число, дійсне число, логічний, символьний і строковий типи.
Цілі типи даних Паскаль
В мові Паскаль є 5 цілих типів:
Shortint (-128 ... 127, 1 байт),
Integer (-32767 ... 32768, 2 байт),
Longint (-2147483648 ... 2147483647, 4 байт),
Byte (0 ... 255, 1 байт),
Word (0 ... 65535, 2 байт).
Цілі типи даних Сі
|
|
||
Назва типу |
Обсяг, байтів |
Діапазон допустимих значень |
|
int |
2 або 4 |
-32768 ... 32767 або -2147483648 ... 2147483647 |
|
short int |
2 |
-32768 ... 32767 |
|
unsigned short int |
2 або 4 |
0 ... 65635 або 0 ... 4294967295 |
|
long int |
4 |
-2147483648 ... 2147483647 |
|
unsigned long int |
4 |
0 ... 4294967295 |
Оголосимо три змінні цілого типу:
Int х, у;
short int z;
Сталі цілого типу можна оголосити так:
const inta= 145;
const long int b = 365978;
Для цілих чисел визначені наступні операції: унарні: + , - ; бінарні: додавання, віднімання, множення, одержання цілого (div) і залишку (mod) при цілочисельному діленні та інші. З цілими числами також можна робити операції, результати яких не є цілим числом. Цей звичайне ділення і операції відношення. Крім цього, існує велика кількість вмонтованих функцій для роботи з цілими числами: abs, sqr, sqrt, sin, cos, exp, ln та ін.
Дійсні типи даних
В Паскалі є 5 типів дійсних даних.
Real (займає 6 байт, діапазон від 2. 9E-39 до 1. 7E+38 по модулю, точність 11-12 значущих цифр)
Single (займає 4 байт, діапазон від 1. 5E-45 до 3. 4E+38 по модулю, точність 7-8 значущих цифр)
Double (займає 8 байт, діапазон від 5. 0Е-324 до 1. 7Е+308 по модулю, точність 15-16 значущих цифр)
Extended (займає 10 байт, діапазон від 3. 4E-4932 до 1. 1E+4932 по модулю, точність19-20 значущих цифр).
Comp (займає 8 байт, діапазон від -9. 2E-18 до 9. 2E+18, зберігаються точно, оскільки це цілі числа)
Дійсні типи.
|
||
Назва типу |
Обсяг, байтів |
Діапазон значень |
float |
4 |
±3,410 -38 ... ±3.410 38 ; 0 |
double |
8 |
±1.710-308 ... ±1,710308; 0 |
long double |
10 |
±1,1810-4932 ... ±1,18104932 ; 0 |
Оголосимо змінні
float h, pi = 3.1415926;
double v = 365.976;
const float w = -12, h = 23.4;
Тут оголошено дві змінні (h, pi) типу float і змінну v типу double, а також сталі w = -12; h = 23.4 типу float.
Теоретичні відомості також викладені в розділі 3 і 4 методичного посібника з системного програмування для самостійних робіт.
Послідовність виконання:
1. Ознайомитись із синтаксисом мови Сі.
2. Порівняти службові слова мов програмування Паскаль та Сі. Визначити, які службові слова є спільними для цих мов програмування.
3. Розглянути структури програм на мовах Паскаль та Сі. Визначити відмінність структур.
4. Написати програму на мові Сі для обчислення математичного виразу.
Варіанти виконання практичної роботи:
Номер варіанта |
Вихідні дані
|
Вхідні дані
|
|||
|
|
|
|||
1 |
|
12
|
-30,4
|
4,7
|
|
2 |
|
4,9
|
8,7
|
2,2
|
|
3 |
|
3,9
|
-1,4
|
5.4
|
|
4 |
|
7,2
|
5,3
|
-3,6
|
|
5
|
|
14,4
|
3,8
|
-7,6
|
|
6 |
|
9,6
|
20,4
|
-7,7
|
|
7 |
|
2,5 |
13,7 |
4,9 |
|
8 |
|
6,8 |
20,5 |
4,3 |
|
9 |
|
17,7 |
8,2 |
2,5 |
|
10 |
|
3,1 |
-14,3 |
-3,9 |
|
11 |
|
2,3 |
8,5 |
3,6 |
|
12 |
|
4,9 |
17,4 |
4,7 |
|
13 |
|
5,7 |
9,1 |
3,8 |
|
14 |
|
3,8 |
4,3 |
7,6 |
|
15 |
|
4,5 |
0,1 |
-9,4 |
|
16 |
|
9,7 |
2,9 |
-5,8 |
|
17 |
|
4,9 |
3,9 |
2,4 |
|
18 |
|
7,9 |
7,2 |
3,5 |
|
19 |
|
5,4 |
6,5 |
4,1 |
|
20 |
|
2,3 |
6 |
4 |
|
21 |
|
0,3 |
4,2 |
5,3 |
|
22 |
|
6,3 |
4,5 |
7,9 |
|
23 |
|
4,5 |
3,7 |
5 |
|
24 |
|
8,7 |
4,9 |
-2,4 |
|
25 |
|
3,9 |
4,5 |
-6,3 |
|
26 |
|
2,1 |
5,3 |
5,8 |
|
27 |
|
2,3 |
7,4 |
9,9 |
|
28 |
|
7,7 |
0,1 |
-5,4 |
|
29 |
|
6,4 |
-2,5 |
-1 |
|
30 |
|
3,1 |
4,2 |
1 |
Практичне завдання 4
Тема: Використання функцій ВІOS при програмуванні системи клавіатури
Мета: навчитися використовувати функції BIOS для програмування робочих операцій клавіатури.
Теоретичні відомості.
Даний спосіб базується на стандартному наборі функцій ВІOS, що використовують переривання – int 16h. Список всіх функцій представлений в табл. 3.1. Слід відмітити, що для підтримки 84-клавішеих клавіатур використовуються тільки ВІOS функції 00h, 01h i 02h. Функції 10h, 11h i 12h підтримують 83-клавішні і 102-клавішні пристрої. Функції 20h, 21h i 22h підтримують всі види клавіатур.
Код функції |
Опис |
00h 01h 02h 03h 04h 05h 09h 0Ah 10h 11h 12h 20h
21h
22h FFh |
Отримати скан-код і ASCII-код клавіш. Перевірити, чи була натиснута клавіша. Отримати стан спеціальних клавіш. Управління режимом автоповтору. Використати звуковий сигнал. Зберегти код клавіші в буфері клавіатури. Отримати інформацію про можливості клавіатури. Отримати ідентифікатор клавіатури. Прочитати код клавіші для розширеної клавіатури. Отримати стан спеціальних клавіш на розширеній клавіатурі. Перевірити, чи була натиснута клавіша на розширеній клавіатурі. Отримати скан-код і ASCII-код клавіші 122-клавішної клавіатури. Перевірити, чи була натиснута клавіша на122-клавішній клавіатурі. Отримати стан спеціальних клавіш122-клавішної клавіатурі. Добавити код клавіші в кінець буфера клавіатури. |
Таблиця 3.1. Список функцій ВІOS
Функція 00h– дозволяє отримати скан-код і ASKII-код натисненої клавіші. За допомогою даної функції неможливо отримати код додаткових клавіш на розширеній клавіатурі. Для цього потрібно примінити функцію 10h, яка буде розглянута пізніше. Функція зчитує символ з буфера клавіатури, потім очищає його. При отриманні коду управляючих клавіш, наприклад – пробіл, в регістр AL буде записаний рівний 0.
Використання: при використанні функції в регістр AH потрібно помістити код функції 00h; викликати переривання int 16h.
Після виконання в регістр АН буде записаний скан-код ВІOS символу, а в регістр AL - ASKII-код символу. Стандартний набір значень скан-кодів символів представлений в табл.3.2, а розширений – в табл.3.3.
Клавіша |
Код |
Клавіша |
Код |
Клавіша |
Код |
Esc 1 i ! 2 i @ 3 i # 4 i $ 5 i % 6 i ^ 7 i & 8 i * 9 i ( 0 i ) - i _ = i + BackSpace Tab Q W E R T Y U I O P [ i { ] i } Insert |
01h 02h 03h 04h 05h 06h 07h 08h 09h 0Ah 0Bh 0Ch 0Dh 0Eh 0Fh 10h 11h 12h 13h 14h 15h 16h 17h 18h 19h 1Ah 1Bh 52h |
Enter Ctrl A S D F G H J K L ; i : ‘ i « ‘ i ~ Left Shift \ i | Z X C V B N M , i < . i > / i ? Right Shift Delete |
1Ch 1Dh 1Eh 1Fh 20h 21h 22h 23h 24h 25h 26h 27h 28h 29h 2Ah 2Bh 2Ch 2Dh 2Eh 2Fh 30h 31h 32h 33h 34h 35h 36h 53h |
* Alt Space Caps Lock F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 NumLock ScrollLock Home Arrow Up Page Up ArrowLeft 5 ArrowRight + End ? PageDown
|
37h 38h 39h 3Ah 3Bh 3Ch 3Dh 3Eh 3Fh 40h 41h 42h 43h 44h 45h 46h 47h 48h 49h 4Ah 4Bh 4Ch 4Dh 4Eh 4Fh 50h 51h |
Таблиця 3.2. Скан-коди клавіатури
Клавіші |
Код |
Клавіші |
Код |
Клавіші |
Код |
Клавіші |
Код |
F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 |
3Bh 3Ch 3Dh 3Eh 3Fh 40h 41h 42h 43h 44h 85h 86h |
Alt+F1 Alt+F2 Alt+F3 Alt+F4 Alt+F5 Alt+F6 Alt+F7 Alt+F8 Alt+F9 Alt+F10 Alt+F11 Alt+F12 |
68h 69h 6Ah 6Bh 6Ch 6Dh 6Eh 6Fh 70h 71h 88h 8Ch |
Shift+F1 Shift+F2 Shift+F3 Shift+F4 Shift+F5 Shift+F6 Shift+F7 Shift+F8 Shift+F9 Shift+F10 Shift+F11 Shift+F12 |
54h 55h 56h 57h 58h 59h 5Ah 5Bh 5Ch 5Dh 87h 88h |
Ctrl+F1 Ctrl+F2 Ctrl+F3 Ctrl+F4 Ctrl+F5 Ctrl+F6 Ctrl+F7 Ctrl+F8 Ctrl+F9 Ctrl+F10 Ctrl+F11 Ctrl+F12 |
5Eh 5Fh 60h 61h 62h 63h 64h 65h 66h 67h 89h 8Ah |
Таблиця 3.3. Коди для розширеної клавіатури
Код |
Назва |
Опис |
0 1 2 3 4 5 6 7 8 9 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 7F |
NUL SON STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US SP DEL |
Кінець лінійки або пустий символ Початок заголовку Початок тексту Кінець тексту Кінець передачі Запит підтвердження Підтвердження Звуковий сигнал Повернення на 1 позицію вліво Горизонтальна табуляція Перевід лінійки Вертикальна табуляція Перехід на нову сторінку Повернення каретки Нижній регістр Верхній регістр Звільнити канал зв’язку Управління пристроєм 1 Управління пристроєм 2 Управління пристроєм 3 Управління пристроєм 4 Підтвердження помилки передачі Синхронізація Кінець блоку передачі Відмінити Кінець носія Заміна Вихід або перехід Розділювач файлів Розділювач груп Розділювач записів Розділювач полів Пробіл Видалення |
Таблиця 3.4. Символи управління ASCII
Покроковий хід роботи для написання програми функції 00h на мові Асемблер, яка допомагає визначити, чи була натиснута клавіша управління:
Організація циклового повторення @repeat для умовного натискання клавіші управління.
Помістити в регістр AH код функції 00h.
Виклик переривання int 16.
Перевіряємо регістр AL.
Якщо натиснута не клавіша управління, повторяємо.
Переписуємо код управління в регістр AL з регістра АН.
Функція 01h – дозволяє перевірити натиснення клавіші на клавіатурі. Якщо клавіша була натиснута, функція запише скан-код і ASKII-код у відповідні регістри. Буфер клавіатури не очищається.
Використання: регістр AH потрібно помістити код функції 01h; визвати переривання Int 16h.
Після виконання функції в регістр AH буде записано скан-код BIOS символу, а в регістр AL - ASKII-код символу. Крім того, якщо не було натиснення клавіші символу, то прапор ZF буде встановлений в 1. Якщо клавіша була натиснута, то прапор ZF буде скинутий, (0). Приклад з натисканням клавіші <ESC>.
Покроковий хід роботи для написання програми функції 01h на мові Асемблер, яка дозволяє перевірити натиснення клавіші на клавіатурі.
Організація циклового повторення @repeat для умовного натискання клавіші управління.
Записуємо в регістр АН код функції 01h.
Викликаємо переривання int 16h.
Натиснення клавіші не було, повторюємо запит.
Клавіша натиснута, читаємо код клавіші.
Викликаємо переривання int 16h.
Порівнюємо отриманий ASKII-код з кодом ESC (1Bh).
Якщо ASKII-код не відповідає клавіші ESC, повторяємо.
Функція 02h – дозволяє перевірити стан спеціальних клавіш на клавіатурі: <Shift>, <Ctrl>, <Alt>, <Num Lock>, <Scroll Lock>, <Caps Lock> i <Insert>.
Використання: регістр AH потрібно помістити код функції 02h; визвати переривання іnt 16h.
Після виконання функції в регістр AL буде зберігати стан спеціальних клавіш. Формат цього байта представлений в табл.3.5.
Біт |
Опис |
0 1 2 3 4 5 6 7 |
Права клавіша Shift (1-натиснена, 0-ненатиснена) Ліва клавіша Shift (1-натиснена, 0-ненатиснена) Люба клавіша Ctrl (1-натиснена, 0-ненатиснена) Люба клавіша Alt (1-натиснена, 0-ненатиснена) Перемикач Scroll Lock (1-включений, 0-виключений) Перемикач Num Lock (1-включений, 0-виключений) Перемикач Caps Lock (1-включений, 0-виключений) Перемикач Insert (1-включений, 0-виключений) |
Таблиця 3.5. Формат байта стану клавіатури
Покроковий хід роботи для написання програми функції 02h на мові Асемблер, яка дозволяє перевірити стан спеціальних клавіш на клавіатурі.
Очікування прийняття натискання спеціальних клавіш на клавіатурі.
Записати в регістр AH код функції 02h.
Викликаємо переривання int 16h.
Перевіряємо в регістрі AL нижній біт (8).
Жодна клавіша Alt не була натиснута, повторити процедуру натискання.
Функція 03h – дозволяє встановити режим автоповторення і час затримки.
Використання: в регістр AH потрібно розмістити код функції 03h; в регістр AL потрібно записати 3 операції: 00h значення по замовчуванню для автоповторення і часу затримки; 04h відключення автоповтору (тільки для деяких клавіатур РS/2; 05h встановлення кількості повторень і часу затримки для всіх стандартних клавіатур; 06h отримання текучого значення частоти повторень і часу затримки (для деяких нових клавіатур РS/2). В регістр ВН необхідно записати значення коду затримки (табл.3.6). В регістр ВL – значення коду частоти повторення (табл.3.7). Викликати переривання int 16h.
Після виконання функції регістр ВL буде зберігати значення частоти повторення, а регістр ВН – час затримки. Вхідні параметри дійсні тільки для типу операції з кодом 06h.
-
Значення коду
Час затримки, мс
00h
01h
02h
03h
250
500
750
1000
Таблиця 3.6. Код затримки
Значення коду |
Частота символів/с |
Значення коду |
Частота символів/с |
00h 01h 02h 03h 04h 05h 06h 07h 08h 09h 0Ah 0Bh 0Ch 0Dh 0Eh 0Fh |
30,0 26,7 24,0 21,8 20,0 18,5 17,1 16,0 15,0 13,2 12,0 10,9 10,0 9,2 8,6 8,0 |
10h 11h 12h 13h 14h 15h 16h 17h 18h 19h 1Ah 1Bh 1Ch 1Dh 1Eh 1Fh |
7,5 6,7 6,0 5,5 5,0 4,6 4,3 4,0 3,7 3,3 3,0 2,7 2,5 2,3 2,1 2,0 |
Таблиця 3.7. Код частоти повторень
Покроковий хід роботи для написання програми функції 03h на мові Асемблер, яка дозволяє встановити режим автоповторення і час затримки.
Записуємо в регістр AH код функції 03h.
Записуємо в регістр AL тип операції (5).
Записуємо в регістр ВН час затримки 750 мс з кодом 2 наприклад.
Запис в регістр ВL операції повторення частоти 20 символів/с з кодом 4.
Викликаємо переривання int 16h.
Функція 04h – дозволяє управляти установкою звукового сигналу для натиснення клавіш (як сигнал клацання). При активізації сигналу кожне натискання буде супроводжуватися характерним сигналом клацання.
Використання: в регістр AH потрібно розмістити код функції 04h; в регістр AL потрібно записати код операції управління (1-включити звуковий сигнал, 0-відключити звуковий сигнал). Викликати переривання int 16h.
Функція не має спеціальних вихідних параметрів.
Покроковий хід роботи для написання програми функції 04h на мові Асемблер, яка дозволяє управляти установкою звукового сигналу для натиснення клавіш.
Записуємо в регістр AH код функції 04h.
Включаємо в регістр AL звуковий сигнал (код 1).
Викликаємо переривання int 16h.
Функція 05h – дозволяє записати визначений символ в буфер клавіатури. Особливість функції в тому, що вона дозволяє імітувати натискування клавіш. Використання: регістр AH потрібно помістити код функції 05h; в регістр СН потрібно занести скан-код потрібної клавіші; в регістр СL – записати ASKII-код тієї ж клавіші; викликати переривання int 16h.
Після виконання цієї функції регістр AL буде зберігати результат операції: 00h – функція успішно завершена, 01h – функція не виконана із-за переповнення буфера клавіатури. Якщо функція не завершена, буде встановлений прапор СF. Запишемо символ «а» в буфер клавіатури:
Покроковий хід роботи для написання програми функції 05h на мові Асемблер, яка дозволяє записати необхідний символ в буфер клавіатури.
Записуємо в регістр AH код функції 05h.
Вписуємо в регістр СН скан-код букви 'а' рівний 1Еh (код 30).
Записуємо в регістр СL ASKII-код букви 'а'.
Викликаємо переривання int 16h.
Дану функцію можна використовувати для запису в буфер клавіатури любої команди DOS (наприклад DATE), використовуючи тільки ASKII-коди:
Покроковий хід роботи для написання програми функції 05h на мові Асемблер, яка дозволяє записати необхідну команду в буфер клавіатури.
Записуємо в регістр СL ASKII-код букви ‘d’.
Відправляємо її в буфер клавіатури.
Записуємо в регістр СL ASKII-код букви ’а’.
Відправляємо її в буфер клавіатури.
Записуємо в регістр СL ASKII-код букви ‘t’.
Відправляємо її в буфер клавіатури.
Записуємо в регістр СL ASKII-код букви ‘e’.
Відправляємо її в буфер клавіатури.
Записуємо в регістр СL ASKII-код переводу лінійки 0Ah.
Відправляємо її в буфер клавіатури.
Записуємо в регістр СL ASKII-код повернення каретки 0Dh.
Відправляємо її в буфер клавіатури.
Виходимо з програми командою ret.
Процедура для запису байту в буфер клавіатури.
Записуємо в регістр АН код функції 05h.
Записуємо в регістр CН скан-код 0 (не використовуємо).
Викликаємо переривання int 16h.
Закінчення процедури.
Функція 09h – дозволяє визначити набір функцій, які підтримуються клавіатурою, і, відповідно, взнати їx тип (84, 102 або 122 клавіші). Визначити, чи підтримується дана функція BIOS, можна за допомогою функції С0h переривання int 15h.
Використання: регістр АН потрібно помістити код функції 09h; викликати переривання int 16h.
Після виконання функції регістр АL буде зберігати бітову маску функцій підтримки. Формат бітової маски представлений в табл. 3.8.
Біт |
Опис |
0
1
2
3
4
5
6
7 |
Підтримка функції 0300h переривання int 16h (1-підтримується, 0-не підтримується) Підтримка функції 0304h переривання int 16h (1-підтримується, 0-не підтримується) Підтримка функції 0305h переривання int 16h (1-підтримується, 0-не підтримується) Підтримка функції 0306h переривання int 16h (1-підтримується, 0-не підтримується) Підтримка функції 0Аh переривання int 16h (1-підтримується, 0-не підтримується) Підтримка функцій 10h, 11h і 12h переривання int 16h (1-підтримується, 0-не підтримується) Підтримка функцій 20h, 21h і 22h переривання int 16h (1-підтримується, 0-не підтримується) Резерв |
Таблиця 3.8. Бітова маска набору функцій.
Наприклад, щоб взнати, чи підтримуються функції 20h, 21h і 22h клавіатурою (122 клавіш), потрібно написати відповідний код:
Покроковий хід роботи для написання програми функції 09h на мові Асемблер, яка дозволяє визначити набір функцій, які підтримуються клавіатурою, і вказати їx тип (кількість клавіш).
Записуємо в регістр AH код функції 09h.
Викликаємо переривання int 16h.
Перевіряємо біт 6 в регістрі AL командою 40h.
Функції не підтримуються. Видання помилки ErrorHnd.
Функція 0Аh – дозволяє прочитати ідентифікатор установленої клавіатури. Перед викликом цієї функції потрібно викликати функцію 09h, щоб переконатися в її підтримці BIOS.
Використання: в регістр АН потрібно помістити код функції 0Аh; викликати переривання int 16h.
Після виконання функції регістр ВХ буде зберігати ідентифікатор клавіатури: 0000h-клавіатура відсутня, 41АВh, 54АВh, 83АВh, 84АВh-японська клавіатура, 86АВh - 122-клавішна клавіатура. Розглянемо приклад отримання ідентифікатора підключеної клавіатури.
Покроковий хід роботи для написання програми функції 0Аh на мові Асемблер, яка дозволяє прочитати ідентифікатор установленої клавіатури.
Записуємо в регістр AH код функції ОАh.
Викликаємо переривання int 16h.
Перевіряємо в регістрі BX наявність клавіатури (0).
Клавіатура не підключена (NoKeyb).
Порівнюємо в регістрі BX код 86ABh - 122 клавішна клавіатура.
Порівнюємо NoKeyb_122 не 122-клавішна клавіатура.
Функція 10h – дозволяє прочитати любий символ з розширеної клавіатури. Вона подібна на функцію 00h і підтримує розширений набір символів.
Використання: в регістрі АН потрібно помістити код функції 10h; викликати переривання int 16h.
Після виконання функції в регістр АН буде розміщений скан-код BIOS символу із розширеного набору, а в регістр АL - ASKII-код символу.
Покроковий хід роботи для написання програми функції 10h на мові Асемблер, яка дозволяє записати необхідний символ в буфер клавіатури.
Записуємо в регістр AH код функції 10h.
Вписуємо в регістр СН скан-код букви на розширеній клавіатурі.
Записуємо в регістр СL ASKII-код букви.
Викликаємо переривання int 16h.
Функція 11h – дозволяє перевірити натискування клавіші на розширеній клавіатурі. Якщо клавіша була натиснута, функція записує скан-код і ASKII-код клавіші у відповідні регістри. Вона подібна на функцію 00h тільки підтримує розширений набір символів.
Використання: в регістр АН потрібно розмістити код функції 11h; викликати переривання int 16h.
Після виконання функції в регістр АН буде розміщено розширений скан-код BIOS символу, а в регістр АL - ASKII-код символу. Якщо ж натискування клавіші не було, прапор ZF буде встановлений в 1, в протилежному випадку буде скинутий.
Покроковий хід роботи для написання програми функції 11h на мові Асемблер, яка допомагає визначити, чи була натиснута клавіша управління:
Організація циклового повторення @repeat для умовного натискання клавіші управління.
Помістити в регістр AH код функції 11h.
Виклик переривання int 16.
Перевіряємо регістр AL.
Якщо натиснута не клавіша управління, повторяємо.
Переписуємо код клавіші управління в регістр AL з регістра АН.
Функція 12h – дозволяє отримати стан спеціальних клавіш, отриманих на розширеній клавіатурі: <Shift>, <Ctrl>, <Alt>, <Num Lock>, <Scroll Lock>, <Caps Lock> i <Insert>.
Використання: в регістр АН потрібно розмістити код функції 12h; викликати переривання int 16h.
Після виконання функції в регістр АН буде розміщено значення спеціальних клавіш. Формат значень повернення викладений в табл.3.9.
Біт |
Опис |
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Права клавіша Shift (1-натиснута, 0-не натиснута) Ліва клавіша Shift (1-натиснута, 0-не натиснута) Люба клавіша Сtrl (1-натиснута, 0-не натиснута) Люба клавіша Alt (1-натиснута, 0-не натиснута) Перемикач Scroll Lock (1-включений, 0-не включений) Перемикач Num Lock (1-включений, 0-не включений) Перемикач Caps Lock (1-включений, 0-виключений) Перемикач Insert (1-включений, 0-виключений) Ліва клавіша Сtrl (1-натиснута, 0-не натиснута) Ліва клавіша Alt (1-натиснута, 0-не натиснута) Права клавіша Сtrl (1-натиснута, 0-не натиснута) Права клавіша Alt (1-натиснута, 0-не натиснута) Клавіша Scroll Lock (1-натиснута, 0-не натиснута) Клавіша Num Lock (1-натиснута, 0-не натиснута) Клавіша Caps Lock (1-натиснута, 0-не натиснута) Клавіша SysReq (1-натиснута, 0-не натиснута) |
Таблиця 3.9. Формат значення про стан розширеної клавіатури
Покроковий хід роботи для написання програми функції 12h на мові Асемблер, яка дозволяє перевірити стан спеціальних клавіш на розширеній клавіатурі.
Очікування натискання спеціальних клавіш на розширеній клавіатурі.
Записати в регістр AH код функції 12h.
Викликаємо переривання int 16h.
Перевіряємо в регістрі AL нижній біт (8).
Ні одна клавіша не була натиснута, повтор.
Функція 20h – дозволяє прочитати любий символ з розширеної клавіатури. Вона подібна на функцію 10h і підтримує 122-клавішні клавіатури.
Використання: в регістр АН потрібно розмістити код функції 20h; викликати переривання int 16h.
Після виконання функції в регістр АН буде розміщено скан-код BIOS символу з розширеного набору, а в регістр АL - ASKII-код символу.
Покроковий хід роботи для написання програми функції 20h на мові Асемблер, яка дозволяє прочитати будь-який символ з розширеної клавіатури.
Записуємо в регістр AH код функції 20h.
Вписуємо в регістр СН скан-код букви на розширеній клавіатурі.
Записуємо в регістр СL ASKII-код букви.
Викликаємо переривання int 16h.
Функція 21h – дозволяє перевірити натискування клавіші на розширеній клавіатурі. Якщо клавіша була натиснута, функція записує скан-код і ASKII-код клавіші у відповідні регістри. Вона подібна на функцію 11h, тільки підтримує 122-клавішні клавіатури.
Використання: в регістр АН потрібно розмістити код функції 21h; викликати переривання int 16h.
Після виконання функції в регістр АН буде розміщено скан-код BIOS символу, а в регістр АL - ASKII-код символу. Якщо ж натискування клавіші не було, прапор ZF буде встановлений в 1, якщо клавіша булла натиснута, прапор ZF буде скинений.
Покроковий хід роботи для написання програми функції 21h на мові Асемблер, яка допомагає визначити, чи була натиснута клавіша на розширеній клавіатурі.
Організація циклового повторення @repeat для умовного натискання клавіші управління.
Помістити в регістр AH код функції 21h.
Виклик переривання int 16.
Перевіряємо регістр AL.
Якщо натиснута не клавіша управління, повторяємо.
Переписуємо код управління в регістр AL з регістра АН.
Функція 22h – дозволяє отримати стан спеціальних клавіш на розширеній клавіатурі: <Shift>, <Ctrl>, <Alt>, <Num Lock>, <Scroll Lock>, <Caps Lock> i <Insert>. Подібна на функцію 11h тільки підтримує 122-клавішні клавіатури.
Використання: в регістр АН потрібно розмістити код функції 22h; викликати переривання int 16h.
Після виконання функції в регістр АХ буде розміщено значення спеціальних клавіш. Формат значень повернення був викладений в табл.3.9.
Покроковий хід роботи для написання програми функції 22h на мові Асемблер, яка дозволяє отримати стан спеціальних клавіш на розширеній 122- клавішній клавіатурі.
Очікування натискання спеціальних клавіш на розширеній клавіатурі.
Записати в регістр AH код функції 22h.
Викликаємо переривання int 16h.
Перевіряємо в регістрі AL нижній біт (8).
Ні одна клавіша не була натиснута, повтор.
Функція FFh – дозволяє добавити символ в кінець буфера клавіатури.
Використання: в регістр АН потрібно розмістити код функції FFh; в регістр DX потрібно записати скан-код бажаного символу; викликати переривання int 16h.
Після виконання функції регістр AL буде зберігати результат операції: 00h – функція успішно завершена, 01h – виникла помилка. Запишемо скан-код букви «Q» в буфер клавіатури:
Записуємо в регістр AH код функції 0FFh.
Заносимо в регістр DX скан-код букви «Q» (10h).
Викликаємо переривання int 16h.
Перевіряємо регістр AL на 0
Виникла помилка ErrorHnd
На цьому і розглянуто основні функції BIOS і перейдемо до самостійних варіантів їх програмування. Самостійно виконайте програму функцій вашого варіанта на мові асемблер:
Варіант |
Завдання 1 |
Завдання 2 |
Завдання 3 |
1 |
00h |
12h |
05h-для запису команд |
2 |
01h |
20h |
09h |
3 |
02h |
21h |
0Аh |
4 |
03h |
22h |
10h |
5 |
04h |
FFh |
11h |
6 |
05h |
00h |
12h |
7 |
05h-для запису команд |
01h |
20h |
8 |
09h |
02h |
21h |
9 |
0Аh |
03h |
22h |
10 |
10h |
04h |
FFh |
11 |
11h |
05h |
00h |
12 |
12h |
05h-для запису команд |
01h |
13 |
20h |
09h |
02h |
14 |
21h |
0Аh |
03h |
15 |
22h |
10h |
04h |
16 |
FFh |
11h |
05h |
17 |
00h |
12h |
05h-для запису команд |
18 |
01h |
20h |
09h |
19 |
02h |
21h |
0Аh |
20 |
03h |
22h |
10h |
21 |
04h |
FFh |
11h |
22 |
05h |
00h |
12h |
23 |
05h-для запису команд |
01h |
20h |
24 |
09h |
02h |
21h |
25 |
0Аh |
03h |
22h |
26 |
10h |
04h |
FFh |
27 |
11h |
05h |
00h |
28 |
12h |
05h-для запису команд |
01h |
29 |
20h |
09h |
02h |
30 |
21h |
0Аh |
03h |
Практичне завдання 5
Тема: Використання портів для обміну даними
Мета: ознайомитися і навчитися використовувати порти, призначені для обміну інформації; вміти використовувати їх при написанні программ-драйверів для обміну інформації.
Теоретичні відомості.
Як відомо, клавіатура і миша працюють по протоколу PS/2 і підключаються до одного і того ж контроллера клавіатури (наприклад, Intel 8042), інтегрованого в чіпі на материнській платі. Для клавіатури контроллер генерує переривання IRQ1. Контроллер може працювати в 2 режимах: PS/2- сумісному і АТ- сумісному. Перший режим передбачає підтримку двох пристроїв. Доступ до контроллера клавіатури здійснюється через порти 60h і 64h. Порт 60h в режимі читання отримує дані із буфера клавіатури, а в режимі запису – поміщає дані в буфер клавіатури. Порт 64h теж працює в 2-х режимах: в режимі читання він являється регістром стану, а в режимі запису – виконує роль регістра команд. В табл.3.10 представлений формат регістра стану порту 64h. В табл.3.11 представлений формат регістра команд порту 64h.
Біт |
Опис |
0
1
2 3 4 5 6 7 |
Наявність даних в вихідному буфері клавіатури (0- вихідний буфер пустий, 1- в буфері наявні дані) Наявність даних у вхідному буфері клавіатури (0- вхідний буфер пустий, 1- в буфері наявні дані) Результат самотестування: (0- зрив, 1- тест пройшов успішно) Порт, що використовується для останньої операції (0- 60h, 1- 64h) Стан клавіатури (0- заблокована, 1- включена) Помилка передачі (0- помилок немає, 1- клавіатура не включена) Помилка Тайм-Аута (0- помилка відсутня, 1- помилка) Помилка парності (0- помилка відсутня, 1- помилка) вказує на останню помилку, яка виникла при передачі даних. |
Таблиця 3.10. регістр стану (64h)
Біт |
Опис |
0 1 2
3 4 5 6 7 |
Переривання для клавіатури (0- відключити, 1- включити) Переривання для миші (0- відключити, 1- включити) Системний прапор (1- ініціалізація через само тестування, 0- ініціалізація по живленню) Не використовується Доступ до клавіатури (0- відкритий, 1- закритий) Доступ до миші (0- відкритий, 1- закритий) Трансляція скан-кодів (0- не використовувати, 1- використовувати) Резерв. |
Таблиця 3.11. Регістр команд (64h)
Перед початком роботи потрібно перевірити 0-й біт регістру статусу в буфері клавіатури. Цю перевірку потрібно здійснювати перед наступними операціями запису. Після перевірки буфера в регістр 64h записується код необхідної команди (табл.3.12). Якщо команда має додаткові параметри, то їх необхідно записати в регістр даних (60h). Після виконання команди в регістр даних 60h буде записаний результат.
Код команди |
Опис |
20h 60h A1h A4h
A5h A6h
AAh
ABh
ADh AEh AFh C0h D0h D1h D2h E0h |
Прочитати байт із регістра команд Записати байт в регістр команд Отримати номер версії виробника Отримати пароль (повернення FAh, якщо пароль існує, і F1h- в протилежному випадку) Встановити пароль (засилає лінійку з нульовим символом вкінці) Перевірити пароль (порівнює введений з клавіатури пароль з текучим) Виконати само тестування контроллера (у випадку успіху поверне 55h) Перевірка інтерфейсу клавіатури (00h- все добре, 01h-низький рівень сигналу синхронізації, 02h- високий рівень сигналу синхронізації, 03h- низький рівень сигналу на лінії даних, 04h- високий рівень сигналу на лінії даних) Відключити інтерфейс клавіатури (встановлює біт 4 в регістрі команд) Включити інтерфейс клавіатури (очищає біт 4 в регістрі команд) Отримати версію Прочитати вхідний порт Прочитати значення із вихідного порту Записати параметр у вихідний порт Записати параметр в буфер клавіатури Тестування порту (повертає тестове значення для порту) |
Таблиця 3.12. команди управління контроллером клавіатури
Код помилки |
Опис |
00h AAh EEh FAh FCh FEh FFh |
Помилка переповнення (дуже багато натискань клавіш) Само тестування контроллера успішно завершено Результат ехо-режиму ініційованого командою EEh Підтвердження успішного виконання команди Помилка само тестування клавіатури Запит на повторну передачу даних (команда Resend) Помилка клавіатури |
Таблиця 3.13. Коди помилок клавіатури
Розглянемо приклади для використання команд управління. Спочатку представимо код перевірки інтерфейсу (команда ABh) клавіатури.
Покроковий хід роботи для написання програми функції ABh на мові Асемблер для перевірки наявності клавіатури:
Чекаємо звільнення вхідного буфера клавіатури.
Запитуємо регістр стану AL про код 64.
Тестуємо, якщо буфер зайнятий (010b).
Повторюємо запит.
Записуємо команду тестування інтерфейсу 0ABh в регістр AL.
Записуємо код (64h) в порт AL.
Покроковий хід роботи для написання програми функції АВh на мові С++ для перевірки наявності клавіатури.
Ініціалізуємо змінну dwResult типу DWORD для збереження результату.
Об’являємо змінну занчення затримки iTimeWait цілого типу, яка дорівнює 50000. Може бути і інший час затримки.
Перевіряємо наявність даних у вхідному буфері клавіатури.
Організовуємо цикл «поки» по змінній iTimeWait до 0:
Читаємо стан порта за допомогою бібліотечної функції inPort з аргументами 0x64, &dwResult, 1.
Якщо dwResult & 0x02 = 0, - виходимо.
Закінчуємо час очікування. Перевіряємо, якщо iTimeWait<1, то повертаємо значення MY_ERROR_TIME.
Записуємо в порт команду перевірки інтерфейсу.
Тепер попробуємо відключити клавіатуру. Для цього застосуємо команду управління з кодом ADh.
Покроковий хід роботи для написання програми функції ADh на мові Асемблер для відключення клавіатури:
Чекаємо звільнення вхідного буфера клавіатури.
Запитуємо регістр стану AL про код 64.
Тестуємо якщо буфер AL зайнятий (010b).
Повторюємо запит.
Заносимо в регістр AL команду 0ADh- відключення клавіатури.
Записуємо в порт AL код команди 64h.
Покроковий хід роботи для написання програми функції АDh на мові С++ для відключення клавіатури.
Ініціалізуємо змінну dwResult типу DWORD для збереження результату.
Задаємо змінну iTimeWait =50000 (може бути і інше значення) типу іnt.
Перевіряємо наявність даних у вхідному буфері клавіатури:
Організовуємо цикл «поки» по змінній iTimeWait.
Читаємо стан порту бібліотечною функцією inPort за адресою 0x64 і двома іншими параметрами &dwResult і 1.
Порівнюємо, якщо dwResult і 0x02 дорівнюють нулю, виходимо з програми.
Закінчимо час очікування:
Якщо змінна iTimeWait<1, повертаємо код помилки MY_ERROR_TIME.
Записуємо в порт 0x64 команду відключення клавіатури 0xAD із третім параметром 1.
Для відновлення роботи клавіатури потрібно в регістр команд записати код AEh. Список інших команд представлений в таблиці 3.14. команди можуть мати додаткові параметри, які передаються у виді додаткового байту. Команди потрібно записати в порт 60h. Після посилання кожної команди потрібно перевірити біт 1 для порту 64h і тільки при його зануленні передавати додатковий параметр. Крім того, можна перевірити додатковий біт в порту 60h. Після виконання кожної команди крім EEh і FEh повертається код підтвердження FАh (читається з порту 60h). Якщо значення коду команди або параметра неприпустимі, клавіатура поверне код FEh. Якщо замість додаткового байту параметра заслати код нової команди, клавіатура її виконає, але про попередню забуде.
Код команди |
Опис |
EDh EEh F0h F2h F3h F4h F5h F6h F7h F8h F9h FAh
FBh
FCh
FDh FEh FFh |
Встановити або скинути стан індикатора Виконати ехо-діагностику клавіатури Вибрати набір скан-кодів (перший, другий або третій) Отримати ідентифікатор клавіатури Настроїти параметри автоповтору і часу затримки Включити клавіатуру (буфер буде очищений) Відключити клавіатуру і завантажити значення по замовчуванню Встановити параметри по замовчуванню (10 символів/с, 500 мс) Встановити режим автоповтору для всіх клавіш Встановити для всіх клавіш передачу кодів натискання і відпускання Встановити для всіх клавіш передачу кодів натискання Встановити для всіх клавіш передачу кодів натискання відпускання і режим автоповтору Встановити для вказаної клавіші передачу кодів натискання і режим автоповтору Встановити для вказаної клавіші передачу кодів натискання і відпускання Встановити для вказаної клавіші передачу кодів натискання Виконати повторну передачу останнього переданого байту Скидання клавіатури |
Таблиця 3.14. Набір команд для клавіатури
Деякі команди потребують додаткового опису, а тому розглянемо їх більш детально.
Команда EDh дозволяє управляти станом індикаторів на клавіатурі, розмір її – 2 байти. Перший із них розміщує код команди, а другий – бітову маску для налаштування індикаторів.
Біт |
Опис |
0 1 2 3-7 |
Індикатор Scroll Lock (1- включений, 0- виключений) Індикатор Num Lock (1- включений, 0- виключений) Індикатор Caps Lock (1- включений, 0- виключений) Резерв |
Таблиця 3.15. Біт стану індикаторів
Покроковий хід роботи для написання програми функції ЕDh на мові Асемблер. Наведемо простий приклад для управління індикатором Num Lock:
Чекаємо звільнення вхідного буфера клавіатури.
Запитуємо регістр стану AL про код 64.
Тестуємо, якщо буфер AL зайнятий (010b).
Повторюємо запит.
Заносимо в регістр AL команду управління індикаторами 0ЕDh.
Записуємо в порт даних 60h значення з порта AL.
Організовуємо очікування
Запитуємо регістр стану AL про код 64.
Тестуємо, якщо буфер AL зайнятий (010b).
Повторюємо запит.
Включаємо в буфер AL клавішу «Num Lock» (010b).
Записуємо в порт 60h значення буфера AL.
Покроковий хід роботи для написання програми функції ЕDh на мові С++ для управління індикатором Num Lock.
Ініціалізуємо змінну dwResult типу DWORD для збереження результату.
Об’являємо змінну очікування iTimeWait типу int рівну 50000 (можна вибрати і інше значення).
Перевіряємо наявність даних у вхідному буфері клавіатури:
Організовуємо цикл «поки» по змінній iTimeWait.
Читаємо стан порту бібліотечною функцією inPort за адресою 0x64 і двома іншими параметрами &dwResult і 1.
Порівнюємо, якщо dwResult і 0x02 дорівнюють нулю виходимо з програми.
Закінчимо час очікування:
Якщо змінна iTimeWait<1, повертаємо код помилки MY_ERROR_TIME.
Записуємо в порт 0x64 команду відключення клавіатури 0xЕD із третім параметром 1.
Відновлюємо змінну iTimeWait =50000 того ж типу, що і раніше.
Перевіряємо наявність даних у вхідному буфері клавіатури:
Організовуємо цикл «поки» по змінній iTimeWait.
Читаємо стан порту бібліотечною функцією inPort за адресою 0x64 і двома іншими параметрами &dwResult і 1.
Порівнюємо, якщо dwResult і 0x02 дорівнюють нулю, виходимо з програми.
Закінчимо час очікування:
Якщо змінна iTimeWait<1, повертаємо код помилки MY_ERROR_TIME.
Записуємо в порт 0x64 команду відключення клавіатури 0xЕD із третім параметром 1.
Команда EEh дозволяє протестувати клавіатуру на предмет роботоздатності. Якщо в клавіатурі були збої, потрібно здійснити скидання (команда FFh) і послати цю команду. Значення повернення, відмінне від EEh, явно вкаже на збої клавіатури. Можливо, потрібно виключити і включити електросітку для відновлення роботоздатності пристрою.
Команда F2h дозволяє отримати ідентифікатор клавіатури і переконатися в її наявності. Після її виконання клавіатура поверне код підтвердження FАh, а потім ідентифікатор: для більшості клавіатур – це 2 коди – АВh і 83h (для окремих клавіатур 41h). Розглянемо приклад отримання ідентифікатора клавіатури нижче.
Покроковий хід роботи для написання програми функції F2h на мові Асемблер для отримання ідентифікатора клавіатури:
Чекаємо звільнення вхідного буфера клавіатури.
Запитуємо регістр стану AL про код 64.
Тестуємо, якщо буфер AL зайнятий (010b).
Повторюємо запит.
Заносимо в регістр AL команду управління індикаторами 0F2h.
Записуємо в порт даних 60h значення з порта AL
Організовуємо очікування:
Отримуємо підтвердження з регістра стану AL про код 60h.
Виконання команди: буфер AL, команда 0FFh.
Виникла помилка.
Організовуємо очікування:
Отримуємо підтвердження в буфер AL вмістиме порта 60h.
Зчитуємо перший байт ідентифікатора (0АВh) в буфер AL.
Виникла помилка (ErrorHnd).
Організовуємо очікування:
Отримуємо підтвердження в буфер AL вмістиме порта 60h.
Зчитуємо перший байт ідентифікатора (83h) в буфер AL.
Виникла помилка (ErrorHnd).
Здійснюємо повернення.
Організовуємо очікування:
Запитуємо регістр стану AL про код 64.
Тестуємо, якщо буфер AL зайнятий (код 01b).
Повторюємо опитування.
Здійснюємо повернення.
В даному прикладі ми послали команду F2h контроллеру клавіатури і послідовно отримали три байти: байт підтримки і два ідентифікатори клавіатури. Аналогічно цей приклад можна привести на С++.
Покроковий хід роботи для написання програми функції F2h на мові С++ для отримання ідентифікатора клавіатури:
Для зручності напишемо окрему функцію запиту даних в буфері.
Функція WaitData () для реалізації затримки приймає значення true i falce.
Задаємо ініціалізацію змінної dwResult типу DWORD для збереження результату.
Задаємо змінну довжини затримки iTimeWait типу int рівну 50000.
Перевіряємо наявність даних у вхідному буфері клавіатури:
Організовуємо цикл «поки» по змінній iTimeWait> 0.
Читаємо стан порту функцією inPort з адресою порту 0x64 і значення ложимо в змінну dwResult через операцію «взяття адреси» посилання на змінну, третій аргумент задаємо 1.
Порівнюємо, якщо значення dwResult і біта 1 на 0 вірне, то повертаємо значення true.
Закінчуєм час затримки:
Порівнюємо, якщо значення iTimeWait < 1, повертаємо false.
При інших варіантах вирішення функції WaitData () повертаємо false;
Основна програма:
Задаємо ініціалізацію змінної dwResult типу DWORD для збереження результату.
Задаємо змінну довжини затримки iTimeWait типу int рівну 50000.
Перевіряємо наявність даних у вхідному буфері клавіатури:
Організовуємо цикл «поки» по змінній iTimeWait> 0.
Читаємо стан порту функцією inPort з адресою порту 0x64 і значення ложимо в змінну dwResult через операцію «взяття адреси» посилання на змінну, третій аргумент задаємо 1.
Порівнюємо, якщо значення dwResult і біта 2 на 0 вірне, то виходимо з програми.
Закінчився час затримки:
Перевіряємо, якщо значення змінної часу затримки iTimeWait < 1, то повертаємо код помилки системний MY_ERROR_TIME.
Записуємо в порт 0x60 код команди 0xF2 з (перевіркою 1-го біта) параметром 1.
Чекаємо отримання першого байта:
Знову задаємо змінну затримки iTimeWait рівну 50000.
Перевіряємо, чи отриманий байт функцією WaitData ().Отриманий!
Записуємо в порт з адресою 0x60 значення dwResult через операцію взяття адреси по посиланню і перевіряємо біт 1.
Перевіряємо на рівність змінної dwResult коду FАh.
Якщо не рівна FАh, то повертаємо код помилки MY_ERROR.
Інакше – даних немає, повертаємо код помилки MY_ERROR.
Чекаємо отримання другого байта:
Знову задаємо змінну затримки iTimeWait рівну 50000.
Перевіряємо, чи отриманий байт функцією WaitData (). Отриманий!
Записуємо в порт з адресою 0x60 значення dwResult через операцію взяття адреси по посиланню і перевіряємо біт 1.
Перевіряємо на рівність змінної dwResult коду АВh.
Якщо не рівна АВh, то повертаємо код помилки MY_ERROR.
Інакше – даних немає, повертаємо код помилки MY_ERROR.
Чекаємо отримання третього байта:
Знову задаємо змінну затримки iTimeWait рівну 50000.
Перевіряємо чи отриманий байт функцією WaitData (). Отриманий!
Записуємо в порт з адресою 0x60 значення dwResult через операцію взяття адреси по посиланню і перевіряємо біт 1.
Перевіряємо на рівність змінної dwResult коду 83h.
Якщо не рівна АВh, то повертаємо код помилки MY_ERROR.
Інакше – даних немає, повертаємо код помилки MY_ERROR.
Ідентифікатор клавіатури успішно отриманий.
Команда F3h - дозволяє встановити частоту і час затримки для автоматичного повтору набраного на клавіатурі символу. Розмір команди рівний 2 байти, де 1-й – код команди, 2-й – опис параметрів налаштування автоповтору.
Біти |
Опис |
0-4 5-6 7 |
Код значення частоти автоповтору Код значення часу затримки резерв |
Таблиця 3.16. Зміст байту настройки автоповтору
Коди значень частоти автоповтору і часу затримки були представлені відповідно в табл.3.7 і табл.3.6. Приклад використання команди F3h показаний в наступному фрагменті програми.
Покроковий хід роботи для написання програми функції F3h на мові Асемблер для встановлення частоти і часу затримки автоповтору:
Чекаємо звільнення вхідного буфера клавіатури.
Запитуємо регістр стану(в AL про код 64).
Тестуємо, якщо буфер AL зайнятий (010b).
Повторюємо запит.
Заносимо в регістр AL команду управління індикаторами 0F3h.
Записуємо в порт даних 60h значення з буфера AL.
Організовуємо цикл затримки data_wait.
Запитуємо регістр стану AL про код 64.
Тестуємо, якщо буфер AL зайнятий (010b).
Повторюємо запит.
Отримуємо в буфері AL підтвердження стану регістра 60h.
Заносимо в буфер AL виконання команди 0FAh.
Виникла помилка ErrorHnd.
Організовуємо цикл затримки keyb_wait.
Запитуємо регістр стану AL про код 64.
Тестуємо, якщо буфер AL зайнятий (010b).
Повторюємо запит.
Заносимо в регістр стану AL частоту 28h: 15 символів/с і 750 мс.
Записуємо в порт даних 60h значення регістра стану AL.
Аналогічний код для установки параметрів автоповтору (частота 15 символів/с і час 750 мс) може бути представлений в С++.
Покроковий хід роботи для написання програми функції F3h на мові С++ для встановлення частоти і часу затримки автоповтору:
Задаємо ініціалізацію змінної dwResult типу DWORD для збереження результату.
Задаємо змінну довжини затримки iTimeWait типу int рівну 50000.
Перевіряємо наявність даних у вхідному буфері клавіатури:
Організовуємо цикл «поки» по змінній часу затримки iTimeWait> 0.
Читаємо стан порту функцією inPort з адресою порту 0x64 і значення ложимо в змінну dwResult через операцію «взяття адреси» посилання на змінну, третій аргумент задаємо 1.
Порівнюємо, якщо значення dwResult і біта 2 на 0 вірне, то виходимо з програми.
Закінчився час затримки:
Перевіряємо, якщо значення змінної часу затримки iTimeWait < 1, то повертаємо системний код помилки MY_ERROR_TIME.
Записуємо в порт 0x60 код команди 0xF3 з (перевіркою 1-го біта) параметром 1.
Задаємо змінну довжини затримки iTimeWait типу int рівну 50000.
Перевіряємо наявність даних у вхідному буфері клавіатури:
Організовуємо цикл «поки» по змінній часу затримки iTimeWait> 0.
Читаємо стан порту функцією inPort з адресою порту 0x64 і значення ложимо в змінну dwResult через операцію «взяття адреси» посилання на змінну, третій аргумент задаємо 1.
Порівнюємо, якщо значення dwResult і біта 2 на 0 вірне, то виходимо з програми.
Закінчився час затримки:
Перевіряємо, якщо значення змінної часу затримки iTimeWait < 1, то повертаємо системний код помилки MY_ERROR_TIME.
Записуємо в порт 0x60 значення змінної dwResult через операцію «взяття адреси» посилання на змінну з (перевіркою 1-го біта) параметром 1.
Перевіряємо dwResult на рівність коду FAh; якщо не дорівнює, то повертаємо код помилки MY_ERROR.
Задаємо змінну довжини затримки iTimeWait типу int рівну 50000.
Перевіряємо наявність даних у вхідному буфері клавіатури:
Організовуємо цикл «поки» по змінній часу затримки iTimeWait> 0.
Читаємо стан порту функцією inPort з адресою порту 0x64 і значення ложимо в змінну dwResult через операцію «взяття адреси» посилання на змінну, третій аргумент задаємо 1.
Порівнюємо, якщо значення dwResult і біта 2 на 0 вірне, то виходимо з програми.
Закінчився час затримки:
Перевіряємо, якщо значення змінної часу затримки iTimeWait < 1, то повертаємо системний код помилки MY_ERROR_TIME.
Записуєм в порт 0x60 значення частоти і часу затримки з кодом 0x28 і з третім (перевіркою 1-го біта) параметром 1.
Якщо порівняти програмування клавіатури з використанням переривання int 16h і безпосередньо портів, то перший спосіб виявиться зручнішим. Однак доступ через апаратні порти дає виграш дещо в швидкості і дозволяє застосовувати весь набір команд для будь-яких випадків. Приведемо скан-коди команд, які використовуються у всіх клавіатурах (табл.3.17).
Клавіша |
Код натискання |
Код відпускання |
Клавіша |
Код натискання |
Код відпускання |
F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 0 1 2 3 4 5 6
7 8
9 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z (IE) Search (IE) Home (IE) Stop (IE) Refresh (IE) Forward (IE) Back (IE) Favorites Volume Up Volume Dwn Mute Play Stop |
05 06 04 0C 03 0B 83 0A 01 09 78 07 45 16 1E 26 25 2E 36
3D 3E
46 1C 32 21 23 24 2B 34 33 43 3B 42 4B 3A 31 44 4D 15 2D 1B 2C 3C 2A 1D 22 35 1A E0, 10 E0, 3A E0, 28 E0, 20 E0, 30 E0, 38 E0, 18 E0, 32 E0, 21 E0, 23 E0, 34 E0, 3B |
F0, 05 F0, 06 F0, 04 F0, 0C F0, 03 F0, 0B F0, 83 F0, 0A F0, 01 F0, 09 F0, 78 F0, 07 F0, 45 F0, 16 F0, 1E F0, 26 F0, 25 F0, 2E F0, 36
F0, 3D F0, 3E
F0, 46 F0, 1C F0, 32 F0, 21 F0, 23 F0, 24 F0, 2B F0, 34 F0, 33 F0, 43 F0, 3B F0, 42 F0, 4B F0, 3A F0, 31 F0, 44 F0, 4D F0, 15 F0, 2D F0, 1B F0, 2C F0, 3C F0, 2A F0, 1D F0, 22 F0, 35 F0, 1A E0, F0, 10 E0, F0, 3A E0, F0, 28 E0, F0, 20 E0, F0, 30 E0, F0, 38 E0, F0, 18 E0, F0, 32 E0, F0, 21 E0, F0, 23 E0, F0, 34 E0, F0, 3B |
‘ - = Bachspace Tab Space Caps Lock Esc Enter Left Ctrl Right Ctrl Left Alt Right Alt Left Shift Right Shift Left Win Right Win Apps Print Screen
Scroll Lock Pause
[ ] ; | , . / Insert Home Delete End Page Up Page Down Up Arrow Down Arrow Left Arrow Right Arrow Num Lock (+) Enter (+) / (+) * (+) – (+) + (+) . (+) 0 (+) 1 (+) 2 (+) 3 (+) 4 (+) 5 (+) 6 (+) 7 (+) 8 (+) 9 Next Track Prevs Track Wake Power Sleep |
0E 4E 55 66 0D 29 58 76 5A 14 E0, 14 11 E0, 11 12 59 E0, 1F E0, 27 E0, 2F E0, 12; E0, 7C 7E E1, 14, 77 E1, F0, 14 F0, 77 54 5B 4C 52 41 49 4A E0, 70 E0, 6C E0, 71 E0, 69 E0, 7D E0, 7A E0, 75 E0, 72 E0, 6B E0, 74 77 E0, 5A E0, 4A 7C 7B 79 71 70 69 72 7A 6B 73 74 6C 75 7D E0, 4D E0, 15 E0, 5E E0, 37 E0, 3F |
F0, 0E F0, 4E F0, 55 F0, 66 F0, 0D F0, 29 F0, 58 F0, 76 F0, 5A F0, 14 E0, F0, 14 F0, 11 E0, F0, 11 F0, 12 F0, 59 E0, F0, 1F E0, F0, 27 E0, F0, 2F EO, FO, 7C E0, F0, 12 F0, 7E Нема
F0, 54 F0, 5B F0, 4C F0, 52 F0, 41 F0, 49 F0, 4A E0, F0, 70 E0, F0, 6C E0, F0, 71 E0, F0, 69 E0, F0, 7D E0, F0, 7A E0, F0, 75 E0, F0, 72 E0, F0, 6B E0, F0, 74 F0, 77 E0, F0, 5A E0, F0, 4A F0, 7C F0, 7B F0, 79 F0, 71 F0, 70 F0, 69 F0, 72 F0, 7A F0, 6B F0, 73 F0, 74 F0, 6C F0, 75 F0, 7D E0, F0, 4D E0, F0, 15 E0, F0, 5E E0, F0, 37 E0, F0, 3F |
Таблиця 3.17. Другий набір скан-кодів клавіатури
Існує ще один порт 61h, який використовується в сьогоднішніх комп’ютерах для управління вмонтованим динаміком (спікером). Він служить для читання і запису і дозволяє управляти деякими функціями клавіатури (для співставлення зі старими моделями). Формат регістра 61h представлений в табл. 3.18.
-
Біт
Опис
0-5
6
7
Для клавіатури не використовуються
Низький рівень сигналу
Відключення клавіатури (1- включити, 0- відключити
Таблиця.3.18. Формат регістра 61h
Як видно, для клавіатури відведені тільки 2 біти: 6-й і 7-й. Щоб відключити і включити клавіатуру, потрібно написати код програми, скориставшись покрочною схемою нижче.
Покроковий хід роботи для написання програми на мові Асемблер для відключення і включення клавіатури:
Прочитати стан порту 61h в буфер AL.
Виконати побітову операцію «АБО» - 80h в AL.
Виключити клавіатуру записавши в порт 61h стан буфера AL.
Прочитати в буфер AL стан порту 61h.
Обнулити в AL 7 біт (код 01111111h) для включення клавіатури.
Включити клавіатуру, занести в порт 61h значення буфера AL.
Покроковий хід роботи для написання програми на мові С++ для відключення і включення клавіатури:
Напишемо окрему функцію управління клавіатурою:
Функція LockUnlockKeyboard для включення і виключення клавіатури з аргументом bLock типу bool.
Ініціалізуємо змінну dwResult типу DWORD.
Якщо змінна bLock не 0 – блокувати клавіатуру.
Записуємо в порт з адресою 0x61 значення dwResult і перевіряємо 1-й біт.
Виконуємо побітове додавання dwResult і 0x80.
Записуємо в порт 0x61 значення dwResult і перевіряємо 1-й біт.
Інакше – розблокувати клавіатуру:
Записуємо в порт з адресою 0x61 значення dwResult і перевіряємо 1-й біт.
Виконуємо побітове додавання dwResult і 0x7F.
Записуємо в порт 0x61 значення dwResult і перевіряємо 1-й біт.
Кінець функції.
Варіанти для практичного завдання: скласти програми поваріантно поданих функцій на відповідних мовах програмування.
Варіант |
Асемблер |
С++ |
Варіант |
Асемблер |
С++ |
1 |
ABh |
Виключення івключення клавіатури |
15 |
Виключення івключення клавіатури |
ABh |
2 |
ADh |
F3h |
16 |
F3h |
ADh |
3 |
EDh |
F2h |
17 |
F2h |
EDh |
4 |
EEh |
EEh |
18 |
EEh |
EEh |
5 |
F2h |
EDh |
19 |
EDh |
F2h |
6 |
F3h |
ADh |
20 |
ADh |
F3h |
7 |
Виключення івключення клавіатури |
ABh |
21 |
ABh |
Виключення івключення клавіатури |
8 |
ABh |
EDh |
22 |
EDh |
ABh |
9 |
ADh |
ADh |
23 |
ADh |
ADh |
10 |
EDh |
ABh |
24 |
ABh |
EDh |
11 |
EEh |
Виключення івключення клавіатури |
25 |
Виключення івключення клавіатури |
EEh |
12 |
F2h |
F3h |
26 |
F3h |
F2h |
13 |
F3h |
F2h |
27 |
F2h |
F3h |
14 |
Виключення івключення клавіатури |
EEh |
28 |
EEh |
Виключення івключення клавіатури |
15 |
EDh |
F3h |
28 |
F3h |
EDh |
Практичне завдання 6
Тема: Використання можливостей Win-32 API
Мета: ознайомитися з можливостями WIN-32 API. Вивчити підходи до прикладного застосування можливостей WIN-32 API при написанні програм.
Теоретичні відомості.
Можливості інтерфейсу Win-32 API "традиційно" скромні і обмежені, їх можна розділити на декілька частин:
Налаштування клавіатури.
Використання "гарячих " клавіш і акселераторів.
Підтримання різних мов.
Підтримка клавіатури в операційних системах Windows здійснюється незалежно від типу підключеного пристрою і мови використання. Будь-які натиснення клавіш перетворюються (в виді скан-кодів) системою (драйвером клавіатури) і відтворюються в вікні завантаженої програми. Кожній мові відповідає свій набір символів, а драйвер сам виконує всі необхідні перетворення. Програміст повинен знати тільки універсальний набір скан-кодів віртуальних клавіш (див.табл.3.19), кожна із яких має своє ім’я і числове значення. Для буквенно-цифрових клавіш існують тільки числові коди.
Клавіша |
Опис |
Клавіша |
Опис |
Tab Backspace Enter Shift Alt Ctrl Caps Lock Esc Space Left Arrow Right Arrow Up Arrow Down Arrow (+) 0 (+) 1 (+) 2 (+) 3 (+) 4 (+) 5 (+) 6 (+) 7 (+) 8 (+) 9 Left Alt Right Alt F1 F2 F3 F4 F5 |
VK_TAB VK_BACK VK_RETURN VK_SHIFT VK_MENU VK_CTRL VK_CAPITAL VK_ESCAPE VK_SPACE VK_LEFT VK_RIGHT VK_UP VK_DOWN VK_NUMPAD0 VK_NUMPAD1 VK_NUMPAD2 VK_NUMPAD3 VK_NUMPAD4 VK_NUMPAD5 VK_NUMPAD6 VK_NUMPAD7 VK_NUMPAD8 VK_NUMPAD9 VK_LMENU VK_RMENU VK_F1 VK_F2 VK_F3 VK_F4 VK_F5 |
Print Screen Scrool Lock Pause Insert Delete Home End Page Up Page Down Left Win Right Win Apps Sleep * + \ - /(ділення) Num Lock Left Shift Right Shift Left Ctrl Right Ctrl F6 F7 F8 F9 F10 F11 F12 |
VK_SNAPSHOT VK_SCROOL VK_PAUSE VK_INSERT VK_DELETE VK_HOME VK_END VK_PRIOR VK_NEXT VK_LWIN VK_RWIN VK_APPS VK_SLEEP VK_MULTIPLY VK_ADD VK_SEPARATOR VK_SUBSTRACT VK_DIVIDE VK_NUMLOCK VK_LSHIFT VK_RIGHTSHIFT VK_LCONTROL VK_RCONTROL VK_F6 VK_F7 VK_F8 VK_F9 VK_F10 VK_F11 VK_F12 |
Таблиця 3.19. Віртуальні клавіші