Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка2_дрВ.doc
Скачиваний:
1
Добавлен:
19.08.2019
Размер:
851.97 Кб
Скачать

ЗМІСТ

ВСТУП. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 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, потрібно насамперед розібратися в основних принципах доступу до апаратної частини комп’ютера під цими системами. А вони, на превеликий жаль, досить дещо збіднені і, я б сказав, однобокі. Існують як мінімум чотири офіційних способи прямого доступу до комп’ютерного устаткування, якщо так можна назвати на даному рівні:

  1. Перший полягає в звичайному використанні набору функцій вводу-виводу: _outp, _outpw, _outpd, _inp, _inpw, _inpd. Вони входять до складу бібліотеки часу виконання, але їх використання досить сильно залежить від операційної системи. Практично всі нові системи Windows не дозволяють працювати з цими функціями в вільно доступному режимі програмування.

  2. Другий спосіб базується на застосуванні універсальної ресурсної функції вводу-виводу DeviceIoControl. Головна перевага при її застосуванні полягає в однозначній підтримці даної функції всіма системами Windows, починаючи Windows95 і закінчуючи останніми версіями - Windows SR3 Windows Vista. Але у цієї функції є один серйозний недолік – це дуже обмежений діапазон її застосування. Не дивлячись на те, що вона дозволяє здійснювати роботу з дисковою системою і з новітніми інтерфейсами передачі даних, отримати прямий доступ до пристроїв за її допомогою не вдається.

  3. Третій спосіб полягає в банальному створенні драйвера (наприклад, віртуального драйвера пристрою), що дозволяє отримати необмежений доступ до всіх пристроїв в системі. Крім того, даний варіант прекрасно буде працювати у всіх операційних системах Windows. Основний недостаток цього методу полягає у відносній складності написання програмного коду самого драйвера, а також необхідність створення окремого варіанта драйвера для кожної операційної системи зокрема. Наприклад, якщо програма написана під Windows 98 і Windows 2000, то доведеться писати два різні драйвери під кожну систему.

  4. Останній спосіб полягає в використанні «вмонтованого» в (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 на мові Асемблер, яка допомагає визначити, чи була натиснута клавіша управління:

  1. Організація циклового повторення @repeat для умовного натискання клавіші управління.

  2. Помістити в регістр AH код функції 00h.

  3. Виклик переривання int 16.

  4. Перевіряємо регістр AL.

  5. Якщо натиснута не клавіша управління, повторяємо.

  6. Переписуємо код управління в регістр AL з регістра АН.

Функція 01h дозволяє перевірити натиснення клавіші на клавіатурі. Якщо клавіша була натиснута, функція запише скан-код і ASKII-код у відповідні регістри. Буфер клавіатури не очищається.

Використання: регістр AH потрібно помістити код функції 01h; визвати переривання Int 16h.

Після виконання функції в регістр AH буде записано скан-код BIOS символу, а в регістр AL - ASKII-код символу. Крім того, якщо не було натиснення клавіші символу, то прапор ZF буде встановлений в 1. Якщо клавіша була натиснута, то прапор ZF буде скинутий, (0). Приклад з натисканням клавіші <ESC>.

Покроковий хід роботи для написання програми функції 01h на мові Асемблер, яка дозволяє перевірити натиснення клавіші на клавіатурі.

  1. Організація циклового повторення @repeat для умовного натискання клавіші управління.

  2. Записуємо в регістр АН код функції 01h.

  3. Викликаємо переривання int 16h.

  4. Натиснення клавіші не було, повторюємо запит.

  5. Клавіша натиснута, читаємо код клавіші.

  6. Викликаємо переривання int 16h.

  7. Порівнюємо отриманий ASKII-код з кодом ESC (1Bh).

  8. Якщо 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 на мові Асемблер, яка дозволяє перевірити стан спеціальних клавіш на клавіатурі.

  1. Очікування прийняття натискання спеціальних клавіш на клавіатурі.

  2. Записати в регістр AH код функції 02h.

  3. Викликаємо переривання int 16h.

  4. Перевіряємо в регістрі AL нижній біт (8).

  5. Жодна клавіша 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 на мові Асемблер, яка дозволяє встановити режим автоповторення і час затримки.

  1. Записуємо в регістр AH код функції 03h.

  2. Записуємо в регістр AL тип операції (5).

  3. Записуємо в регістр ВН час затримки 750 мс з кодом 2 наприклад.

  4. Запис в регістр ВL операції повторення частоти 20 символів/с з кодом 4.

  5. Викликаємо переривання int 16h.

Функція 04h дозволяє управляти установкою звукового сигналу для натиснення клавіш (як сигнал клацання). При активізації сигналу кожне натискання буде супроводжуватися характерним сигналом клацання.

Використання: в регістр AH потрібно розмістити код функції 04h; в регістр AL потрібно записати код операції управління (1-включити звуковий сигнал, 0-відключити звуковий сигнал). Викликати переривання int 16h.

Функція не має спеціальних вихідних параметрів.

Покроковий хід роботи для написання програми функції 04h на мові Асемблер, яка дозволяє управляти установкою звукового сигналу для натиснення клавіш.

  1. Записуємо в регістр AH код функції 04h.

  2. Включаємо в регістр AL звуковий сигнал (код 1).

  3. Викликаємо переривання int 16h.

Функція 05h дозволяє записати визначений символ в буфер клавіатури. Особливість функції в тому, що вона дозволяє імітувати натискування клавіш. Використання: регістр AH потрібно помістити код функції 05h; в регістр СН потрібно занести скан-код потрібної клавіші; в регістр СL – записати ASKII-код тієї ж клавіші; викликати переривання int 16h.

Після виконання цієї функції регістр AL буде зберігати результат операції: 00h – функція успішно завершена, 01h – функція не виконана із-за переповнення буфера клавіатури. Якщо функція не завершена, буде встановлений прапор СF. Запишемо символ «а» в буфер клавіатури:

Покроковий хід роботи для написання програми функції 05h на мові Асемблер, яка дозволяє записати необхідний символ в буфер клавіатури.

  1. Записуємо в регістр AH код функції 05h.

  2. Вписуємо в регістр СН скан-код букви 'а' рівний 1Еh (код 30).

  3. Записуємо в регістр СL ASKII-код букви 'а'.

  4. Викликаємо переривання int 16h.

Дану функцію можна використовувати для запису в буфер клавіатури любої команди DOS (наприклад DATE), використовуючи тільки ASKII-коди:

Покроковий хід роботи для написання програми функції 05h на мові Асемблер, яка дозволяє записати необхідну команду в буфер клавіатури.

  1. Записуємо в регістр СL ASKII-код букви ‘d’.

  2. Відправляємо її в буфер клавіатури.

  3. Записуємо в регістр СL ASKII-код букви ’а’.

  4. Відправляємо її в буфер клавіатури.

  5. Записуємо в регістр СL ASKII-код букви ‘t’.

  6. Відправляємо її в буфер клавіатури.

  7. Записуємо в регістр СL ASKII-код букви ‘e’.

  8. Відправляємо її в буфер клавіатури.

  9. Записуємо в регістр СL ASKII-код переводу лінійки 0Ah.

  10. Відправляємо її в буфер клавіатури.

  11. Записуємо в регістр СL ASKII-код повернення каретки 0Dh.

  12. Відправляємо її в буфер клавіатури.

  13. Виходимо з програми командою ret.

  14. Процедура для запису байту в буфер клавіатури.

  15. Записуємо в регістр АН код функції 05h.

  16. Записуємо в регістр CН скан-код 0 (не використовуємо).

  17. Викликаємо переривання int 16h.

  18. Закінчення процедури.

Функція 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 тип (кількість клавіш).

  1. Записуємо в регістр AH код функції 09h.

  2. Викликаємо переривання int 16h.

  3. Перевіряємо біт 6 в регістрі AL командою 40h.

  4. Функції не підтримуються. Видання помилки ErrorHnd.

Функція 0Аh – дозволяє прочитати ідентифікатор установленої клавіатури. Перед викликом цієї функції потрібно викликати функцію 09h, щоб переконатися в її підтримці BIOS.

Використання: в регістр АН потрібно помістити код функції 0Аh; викликати переривання int 16h.

Після виконання функції регістр ВХ буде зберігати ідентифікатор клавіатури: 0000h-клавіатура відсутня, 41АВh, 54АВh, 83АВh, 84АВh-японська клавіатура, 86АВh - 122-клавішна клавіатура. Розглянемо приклад отримання ідентифікатора підключеної клавіатури.

Покроковий хід роботи для написання програми функції h на мові Асемблер, яка дозволяє прочитати ідентифікатор установленої клавіатури.

  1. Записуємо в регістр AH код функції ОАh.

  2. Викликаємо переривання int 16h.

  3. Перевіряємо в регістрі BX наявність клавіатури (0).

  4. Клавіатура не підключена (NoKeyb).

  5. Порівнюємо в регістрі BX код 86ABh - 122 клавішна клавіатура.

  6. Порівнюємо NoKeyb_122 не 122-клавішна клавіатура.

Функція 10h – дозволяє прочитати любий символ з розширеної клавіатури. Вона подібна на функцію 00h і підтримує розширений набір символів.

Використання: в регістрі АН потрібно помістити код функції 10h; викликати переривання int 16h.

Після виконання функції в регістр АН буде розміщений скан-код BIOS символу із розширеного набору, а в регістр АL - ASKII-код символу.

Покроковий хід роботи для написання програми функції 10h на мові Асемблер, яка дозволяє записати необхідний символ в буфер клавіатури.

  1. Записуємо в регістр AH код функції 10h.

  2. Вписуємо в регістр СН скан-код букви на розширеній клавіатурі.

  3. Записуємо в регістр СL ASKII-код букви.

  4. Викликаємо переривання int 16h.

Функція 11h дозволяє перевірити натискування клавіші на розширеній клавіатурі. Якщо клавіша була натиснута, функція записує скан-код і ASKII-код клавіші у відповідні регістри. Вона подібна на функцію 00h тільки підтримує розширений набір символів.

Використання: в регістр АН потрібно розмістити код функції 11h; викликати переривання int 16h.

Після виконання функції в регістр АН буде розміщено розширений скан-код BIOS символу, а в регістр АL - ASKII-код символу. Якщо ж натискування клавіші не було, прапор ZF буде встановлений в 1, в протилежному випадку буде скинутий.

Покроковий хід роботи для написання програми функції 11h на мові Асемблер, яка допомагає визначити, чи була натиснута клавіша управління:

  1. Організація циклового повторення @repeat для умовного натискання клавіші управління.

  2. Помістити в регістр AH код функції 11h.

  3. Виклик переривання int 16.

  4. Перевіряємо регістр AL.

  5. Якщо натиснута не клавіша управління, повторяємо.

  6. Переписуємо код клавіші управління в регістр 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 на мові Асемблер, яка дозволяє перевірити стан спеціальних клавіш на розширеній клавіатурі.

  1. Очікування натискання спеціальних клавіш на розширеній клавіатурі.

  2. Записати в регістр AH код функції 12h.

  3. Викликаємо переривання int 16h.

  4. Перевіряємо в регістрі AL нижній біт (8).

  5. Ні одна клавіша не була натиснута, повтор.

Функція 20h дозволяє прочитати любий символ з розширеної клавіатури. Вона подібна на функцію 10h і підтримує 122-клавішні клавіатури.

Використання: в регістр АН потрібно розмістити код функції 20h; викликати переривання int 16h.

Після виконання функції в регістр АН буде розміщено скан-код BIOS символу з розширеного набору, а в регістр АL - ASKII-код символу.

Покроковий хід роботи для написання програми функції 20h на мові Асемблер, яка дозволяє прочитати будь-який символ з розширеної клавіатури.

  1. Записуємо в регістр AH код функції 20h.

  2. Вписуємо в регістр СН скан-код букви на розширеній клавіатурі.

  3. Записуємо в регістр СL ASKII-код букви.

  4. Викликаємо переривання int 16h.

Функція 21h дозволяє перевірити натискування клавіші на розширеній клавіатурі. Якщо клавіша була натиснута, функція записує скан-код і ASKII-код клавіші у відповідні регістри. Вона подібна на функцію 11h, тільки підтримує 122-клавішні клавіатури.

Використання: в регістр АН потрібно розмістити код функції 21h; викликати переривання int 16h.

Після виконання функції в регістр АН буде розміщено скан-код BIOS символу, а в регістр АL - ASKII-код символу. Якщо ж натискування клавіші не було, прапор ZF буде встановлений в 1, якщо клавіша булла натиснута, прапор ZF буде скинений.

Покроковий хід роботи для написання програми функції 21h на мові Асемблер, яка допомагає визначити, чи була натиснута клавіша на розширеній клавіатурі.

  1. Організація циклового повторення @repeat для умовного натискання клавіші управління.

  2. Помістити в регістр AH код функції 21h.

  3. Виклик переривання int 16.

  4. Перевіряємо регістр AL.

  5. Якщо натиснута не клавіша управління, повторяємо.

  6. Переписуємо код управління в регістр AL з регістра АН.

Функція 22h – дозволяє отримати стан спеціальних клавіш на розширеній клавіатурі: <Shift>, <Ctrl>, <Alt>, <Num Lock>, <Scroll Lock>, <Caps Lock> i <Insert>. Подібна на функцію 11h тільки підтримує 122-клавішні клавіатури.

Використання: в регістр АН потрібно розмістити код функції 22h; викликати переривання int 16h.

Після виконання функції в регістр АХ буде розміщено значення спеціальних клавіш. Формат значень повернення був викладений в табл.3.9.

Покроковий хід роботи для написання програми функції 22h на мові Асемблер, яка дозволяє отримати стан спеціальних клавіш на розширеній 122- клавішній клавіатурі.

  1. Очікування натискання спеціальних клавіш на розширеній клавіатурі.

  2. Записати в регістр AH код функції 22h.

  3. Викликаємо переривання int 16h.

  4. Перевіряємо в регістрі AL нижній біт (8).

  5. Ні одна клавіша не була натиснута, повтор.

Функція FFh дозволяє добавити символ в кінець буфера клавіатури.

Використання: в регістр АН потрібно розмістити код функції FFh; в регістр DX потрібно записати скан-код бажаного символу; викликати переривання int 16h.

Після виконання функції регістр AL буде зберігати результат операції: 00h – функція успішно завершена, 01h – виникла помилка. Запишемо скан-код букви «Q» в буфер клавіатури:

  1. Записуємо в регістр AH код функції 0FFh.

  2. Заносимо в регістр DX скан-код букви «Q» (10h).

  3. Викликаємо переривання int 16h.

  4. Перевіряємо регістр AL на 0

  5. Виникла помилка 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 на мові Асемблер для перевірки наявності клавіатури:

  1. Чекаємо звільнення вхідного буфера клавіатури.

  2. Запитуємо регістр стану AL про код 64.

  3. Тестуємо, якщо буфер зайнятий (010b).

  4. Повторюємо запит.

  5. Записуємо команду тестування інтерфейсу 0ABh в регістр AL.

  6. Записуємо код (64h) в порт AL.

Покроковий хід роботи для написання програми функції АВh на мові С++ для перевірки наявності клавіатури.

  1. Ініціалізуємо змінну dwResult типу DWORD для збереження результату.

  2. Об’являємо змінну занчення затримки iTimeWait цілого типу, яка дорівнює 50000. Може бути і інший час затримки.

  3. Перевіряємо наявність даних у вхідному буфері клавіатури.

  4. Організовуємо цикл «поки» по змінній iTimeWait до 0:

  5. Читаємо стан порта за допомогою бібліотечної функції inPort з аргументами 0x64, &dwResult, 1.

  6. Якщо dwResult & 0x02 = 0, - виходимо.

  7. Закінчуємо час очікування. Перевіряємо, якщо iTimeWait<1, то повертаємо значення MY_ERROR_TIME.

  8. Записуємо в порт команду перевірки інтерфейсу.

Тепер попробуємо відключити клавіатуру. Для цього застосуємо команду управління з кодом ADh.

Покроковий хід роботи для написання програми функції ADh на мові Асемблер для відключення клавіатури:

  1. Чекаємо звільнення вхідного буфера клавіатури.

  2. Запитуємо регістр стану AL про код 64.

  3. Тестуємо якщо буфер AL зайнятий (010b).

  4. Повторюємо запит.

  5. Заносимо в регістр AL команду 0ADh- відключення клавіатури.

  6. Записуємо в порт AL код команди 64h.

Покроковий хід роботи для написання програми функції АDh на мові С++ для відключення клавіатури.

  1. Ініціалізуємо змінну dwResult типу DWORD для збереження результату.

  2. Задаємо змінну iTimeWait =50000 (може бути і інше значення) типу іnt.

  3. Перевіряємо наявність даних у вхідному буфері клавіатури:

  4. Організовуємо цикл «поки» по змінній iTimeWait.

  5. Читаємо стан порту бібліотечною функцією inPort за адресою 0x64 і двома іншими параметрами &dwResult і 1.

  6. Порівнюємо, якщо dwResult і 0x02 дорівнюють нулю, виходимо з програми.

  7. Закінчимо час очікування:

  8. Якщо змінна iTimeWait<1, повертаємо код помилки MY_ERROR_TIME.

  9. Записуємо в порт 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:

  1. Чекаємо звільнення вхідного буфера клавіатури.

  2. Запитуємо регістр стану AL про код 64.

  3. Тестуємо, якщо буфер AL зайнятий (010b).

  4. Повторюємо запит.

  5. Заносимо в регістр AL команду управління індикаторами 0ЕDh.

  6. Записуємо в порт даних 60h значення з порта AL.

  7. Організовуємо очікування

  8. Запитуємо регістр стану AL про код 64.

  9. Тестуємо, якщо буфер AL зайнятий (010b).

  10. Повторюємо запит.

  11. Включаємо в буфер AL клавішу «Num Lock» (010b).

  12. Записуємо в порт 60h значення буфера AL.

Покроковий хід роботи для написання програми функції ЕDh на мові С++ для управління індикатором Num Lock.

  1. Ініціалізуємо змінну dwResult типу DWORD для збереження результату.

  2. Об’являємо змінну очікування iTimeWait типу int рівну 50000 (можна вибрати і інше значення).

  3. Перевіряємо наявність даних у вхідному буфері клавіатури:

  4. Організовуємо цикл «поки» по змінній iTimeWait.

  5. Читаємо стан порту бібліотечною функцією inPort за адресою 0x64 і двома іншими параметрами &dwResult і 1.

  6. Порівнюємо, якщо dwResult і 0x02 дорівнюють нулю виходимо з програми.

  7. Закінчимо час очікування:

  8. Якщо змінна iTimeWait<1, повертаємо код помилки MY_ERROR_TIME.

  9. Записуємо в порт 0x64 команду відключення клавіатури 0xЕD із третім параметром 1.

  10. Відновлюємо змінну iTimeWait =50000 того ж типу, що і раніше.

  11. Перевіряємо наявність даних у вхідному буфері клавіатури:

  12. Організовуємо цикл «поки» по змінній iTimeWait.

  13. Читаємо стан порту бібліотечною функцією inPort за адресою 0x64 і двома іншими параметрами &dwResult і 1.

  14. Порівнюємо, якщо dwResult і 0x02 дорівнюють нулю, виходимо з програми.

  15. Закінчимо час очікування:

  16. Якщо змінна iTimeWait<1, повертаємо код помилки MY_ERROR_TIME.

  17. Записуємо в порт 0x64 команду відключення клавіатури 0xЕD із третім параметром 1.

Команда EEh дозволяє протестувати клавіатуру на предмет роботоздатності. Якщо в клавіатурі були збої, потрібно здійснити скидання (команда FFh) і послати цю команду. Значення повернення, відмінне від EEh, явно вкаже на збої клавіатури. Можливо, потрібно виключити і включити електросітку для відновлення роботоздатності пристрою.

Команда F2h дозволяє отримати ідентифікатор клавіатури і переконатися в її наявності. Після її виконання клавіатура поверне код підтвердження FАh, а потім ідентифікатор: для більшості клавіатур – це 2 коди – АВh і 83h (для окремих клавіатур 41h). Розглянемо приклад отримання ідентифікатора клавіатури нижче.

Покроковий хід роботи для написання програми функції F2h на мові Асемблер для отримання ідентифікатора клавіатури:

  1. Чекаємо звільнення вхідного буфера клавіатури.

  2. Запитуємо регістр стану AL про код 64.

  3. Тестуємо, якщо буфер AL зайнятий (010b).

  4. Повторюємо запит.

  5. Заносимо в регістр AL команду управління індикаторами 0F2h.

  6. Записуємо в порт даних 60h значення з порта AL

  7. Організовуємо очікування:

  8. Отримуємо підтвердження з регістра стану AL про код 60h.

  9. Виконання команди: буфер AL, команда 0FFh.

  10. Виникла помилка.

  11. Організовуємо очікування:

  12. Отримуємо підтвердження в буфер AL вмістиме порта 60h.

  13. Зчитуємо перший байт ідентифікатора (0АВh) в буфер AL.

  14. Виникла помилка (ErrorHnd).

  15. Організовуємо очікування:

  16. Отримуємо підтвердження в буфер AL вмістиме порта 60h.

  17. Зчитуємо перший байт ідентифікатора (83h) в буфер AL.

  18. Виникла помилка (ErrorHnd).

  19. Здійснюємо повернення.

  20. Організовуємо очікування:

  21. Запитуємо регістр стану AL про код 64.

  22. Тестуємо, якщо буфер AL зайнятий (код 01b).

  23. Повторюємо опитування.

  24. Здійснюємо повернення.

В даному прикладі ми послали команду F2h контроллеру клавіатури і послідовно отримали три байти: байт підтримки і два ідентифікатори клавіатури. Аналогічно цей приклад можна привести на С++.

Покроковий хід роботи для написання програми функції F2h на мові С++ для отримання ідентифікатора клавіатури:

  1. Для зручності напишемо окрему функцію запиту даних в буфері.

  2. Функція WaitData () для реалізації затримки приймає значення true i falce.

  3. Задаємо ініціалізацію змінної dwResult типу DWORD для збереження результату.

  4. Задаємо змінну довжини затримки iTimeWait типу int рівну 50000.

  5. Перевіряємо наявність даних у вхідному буфері клавіатури:

  6. Організовуємо цикл «поки» по змінній iTimeWait> 0.

  7. Читаємо стан порту функцією inPort з адресою порту 0x64 і значення ложимо в змінну dwResult через операцію «взяття адреси» посилання на змінну, третій аргумент задаємо 1.

  8. Порівнюємо, якщо значення dwResult і біта 1 на 0 вірне, то повертаємо значення true.

  9. Закінчуєм час затримки:

  10. Порівнюємо, якщо значення iTimeWait < 1, повертаємо false.

  11. При інших варіантах вирішення функції WaitData () повертаємо false;

  12. Основна програма:

  13. Задаємо ініціалізацію змінної dwResult типу DWORD для збереження результату.

  14. Задаємо змінну довжини затримки iTimeWait типу int рівну 50000.

  15. Перевіряємо наявність даних у вхідному буфері клавіатури:

  16. Організовуємо цикл «поки» по змінній iTimeWait> 0.

  17. Читаємо стан порту функцією inPort з адресою порту 0x64 і значення ложимо в змінну dwResult через операцію «взяття адреси» посилання на змінну, третій аргумент задаємо 1.

  18. Порівнюємо, якщо значення dwResult і біта 2 на 0 вірне, то виходимо з програми.

  19. Закінчився час затримки:

  20. Перевіряємо, якщо значення змінної часу затримки iTimeWait < 1, то повертаємо код помилки системний MY_ERROR_TIME.

  21. Записуємо в порт 0x60 код команди 0xF2 з (перевіркою 1-го біта) параметром 1.

  22. Чекаємо отримання першого байта:

  23. Знову задаємо змінну затримки iTimeWait рівну 50000.

  24. Перевіряємо, чи отриманий байт функцією WaitData ().Отриманий!

  25. Записуємо в порт з адресою 0x60 значення dwResult через операцію взяття адреси по посиланню і перевіряємо біт 1.

  26. Перевіряємо на рівність змінної dwResult коду FАh.

  27. Якщо не рівна FАh, то повертаємо код помилки MY_ERROR.

  28. Інакше – даних немає, повертаємо код помилки MY_ERROR.

  29. Чекаємо отримання другого байта:

  30. Знову задаємо змінну затримки iTimeWait рівну 50000.

  31. Перевіряємо, чи отриманий байт функцією WaitData (). Отриманий!

  32. Записуємо в порт з адресою 0x60 значення dwResult через операцію взяття адреси по посиланню і перевіряємо біт 1.

  33. Перевіряємо на рівність змінної dwResult коду АВh.

  34. Якщо не рівна АВh, то повертаємо код помилки MY_ERROR.

  35. Інакше – даних немає, повертаємо код помилки MY_ERROR.

  36. Чекаємо отримання третього байта:

  37. Знову задаємо змінну затримки iTimeWait рівну 50000.

  38. Перевіряємо чи отриманий байт функцією WaitData (). Отриманий!

  39. Записуємо в порт з адресою 0x60 значення dwResult через операцію взяття адреси по посиланню і перевіряємо біт 1.

  40. Перевіряємо на рівність змінної dwResult коду 83h.

  41. Якщо не рівна АВh, то повертаємо код помилки MY_ERROR.

  42. Інакше – даних немає, повертаємо код помилки MY_ERROR.

  43. Ідентифікатор клавіатури успішно отриманий.

Команда F3h - дозволяє встановити частоту і час затримки для автоматичного повтору набраного на клавіатурі символу. Розмір команди рівний 2 байти, де 1-й – код команди, 2-й – опис параметрів налаштування автоповтору.

Біти

Опис

0-4

5-6

7

Код значення частоти автоповтору

Код значення часу затримки

резерв

Таблиця 3.16. Зміст байту настройки автоповтору

Коди значень частоти автоповтору і часу затримки були представлені відповідно в табл.3.7 і табл.3.6. Приклад використання команди F3h показаний в наступному фрагменті програми.

Покроковий хід роботи для написання програми функції F3h на мові Асемблер для встановлення частоти і часу затримки автоповтору:

  1. Чекаємо звільнення вхідного буфера клавіатури.

  2. Запитуємо регістр стану(в AL про код 64).

  3. Тестуємо, якщо буфер AL зайнятий (010b).

  4. Повторюємо запит.

  5. Заносимо в регістр AL команду управління індикаторами 0F3h.

  6. Записуємо в порт даних 60h значення з буфера AL.

  7. Організовуємо цикл затримки data_wait.

  8. Запитуємо регістр стану AL про код 64.

  9. Тестуємо, якщо буфер AL зайнятий (010b).

  10. Повторюємо запит.

  11. Отримуємо в буфері AL підтвердження стану регістра 60h.

  12. Заносимо в буфер AL виконання команди 0FAh.

  13. Виникла помилка ErrorHnd.

  14. Організовуємо цикл затримки keyb_wait.

  15. Запитуємо регістр стану AL про код 64.

  16. Тестуємо, якщо буфер AL зайнятий (010b).

  17. Повторюємо запит.

  18. Заносимо в регістр стану AL частоту 28h: 15 символів/с і 750 мс.

  19. Записуємо в порт даних 60h значення регістра стану AL.

Аналогічний код для установки параметрів автоповтору (частота 15 символів/с і час 750 мс) може бути представлений в С++.

Покроковий хід роботи для написання програми функції F3h на мові С++ для встановлення частоти і часу затримки автоповтору:

  1. Задаємо ініціалізацію змінної dwResult типу DWORD для збереження результату.

  2. Задаємо змінну довжини затримки iTimeWait типу int рівну 50000.

  3. Перевіряємо наявність даних у вхідному буфері клавіатури:

  4. Організовуємо цикл «поки» по змінній часу затримки iTimeWait> 0.

  5. Читаємо стан порту функцією inPort з адресою порту 0x64 і значення ложимо в змінну dwResult через операцію «взяття адреси» посилання на змінну, третій аргумент задаємо 1.

  6. Порівнюємо, якщо значення dwResult і біта 2 на 0 вірне, то виходимо з програми.

  7. Закінчився час затримки:

  8. Перевіряємо, якщо значення змінної часу затримки iTimeWait < 1, то повертаємо системний код помилки MY_ERROR_TIME.

  9. Записуємо в порт 0x60 код команди 0xF3 з (перевіркою 1-го біта) параметром 1.

  10. Задаємо змінну довжини затримки iTimeWait типу int рівну 50000.

  11. Перевіряємо наявність даних у вхідному буфері клавіатури:

  12. Організовуємо цикл «поки» по змінній часу затримки iTimeWait> 0.

  13. Читаємо стан порту функцією inPort з адресою порту 0x64 і значення ложимо в змінну dwResult через операцію «взяття адреси» посилання на змінну, третій аргумент задаємо 1.

  14. Порівнюємо, якщо значення dwResult і біта 2 на 0 вірне, то виходимо з програми.

  15. Закінчився час затримки:

  16. Перевіряємо, якщо значення змінної часу затримки iTimeWait < 1, то повертаємо системний код помилки MY_ERROR_TIME.

  17. Записуємо в порт 0x60 значення змінної dwResult через операцію «взяття адреси» посилання на змінну з (перевіркою 1-го біта) параметром 1.

  18. Перевіряємо dwResult на рівність коду FAh; якщо не дорівнює, то повертаємо код помилки MY_ERROR.

  19. Задаємо змінну довжини затримки iTimeWait типу int рівну 50000.

  20. Перевіряємо наявність даних у вхідному буфері клавіатури:

  21. Організовуємо цикл «поки» по змінній часу затримки iTimeWait> 0.

  22. Читаємо стан порту функцією inPort з адресою порту 0x64 і значення ложимо в змінну dwResult через операцію «взяття адреси» посилання на змінну, третій аргумент задаємо 1.

  23. Порівнюємо, якщо значення dwResult і біта 2 на 0 вірне, то виходимо з програми.

  24. Закінчився час затримки:

  25. Перевіряємо, якщо значення змінної часу затримки iTimeWait < 1, то повертаємо системний код помилки MY_ERROR_TIME.

  26. Записуєм в порт 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-й. Щоб відключити і включити клавіатуру, потрібно написати код програми, скориставшись покрочною схемою нижче.

Покроковий хід роботи для написання програми на мові Асемблер для відключення і включення клавіатури:

  1. Прочитати стан порту 61h в буфер AL.

  2. Виконати побітову операцію «АБО» - 80h в AL.

  3. Виключити клавіатуру записавши в порт 61h стан буфера AL.

  1. Прочитати в буфер AL стан порту 61h.

  2. Обнулити в AL 7 біт (код 01111111h) для включення клавіатури.

  3. Включити клавіатуру, занести в порт 61h значення буфера AL.

Покроковий хід роботи для написання програми на мові С++ для відключення і включення клавіатури:

  1. Напишемо окрему функцію управління клавіатурою:

  2. Функція LockUnlockKeyboard для включення і виключення клавіатури з аргументом bLock типу bool.

  3. Ініціалізуємо змінну dwResult типу DWORD.

  4. Якщо змінна bLock не 0 – блокувати клавіатуру.

  5. Записуємо в порт з адресою 0x61 значення dwResult і перевіряємо 1-й біт.

  6. Виконуємо побітове додавання dwResult і 0x80.

  7. Записуємо в порт 0x61 значення dwResult і перевіряємо 1-й біт.

  8. Інакше – розблокувати клавіатуру:

  9. Записуємо в порт з адресою 0x61 значення dwResult і перевіряємо 1-й біт.

  10. Виконуємо побітове додавання dwResult і 0x7F.

  11. Записуємо в порт 0x61 значення dwResult і перевіряємо 1-й біт.

  12. Кінець функції.

Варіанти для практичного завдання: скласти програми поваріантно поданих функцій на відповідних мовах програмування.

Варіант

Асемблер

С++

Варіант

Асемблер

С++

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 "традиційно" скромні і обмежені, їх можна розділити на декілька частин:

  1. Налаштування клавіатури.

  2. Використання "гарячих " клавіш і акселераторів.

  3. Підтримання різних мов.

Підтримка клавіатури в операційних системах 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. Віртуальні клавіші

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]