Sprawozdanie

  • June 2020
  • PDF

This document was uploaded by user and they confirmed that they have the permission to share it. If you are author or own the copyright of this book, please report to us by using this DMCA report form. Report DMCA


Overview

Download & View Sprawozdanie as PDF for free.

More details

  • Words: 3,990
  • Pages: 19
Politechnika Rzeszowska Wydział E i I Sprawozdanie z Laboratorium nr 3 Data wykonania 30-03.06.2007

ARCHITEKTURY KOMPUTERÓW

Grupa laboratoryjna L07

Łukasz Kozek, Jerzy Dudek, Jacek Miszczuk Obsługa klawiatury

Data oddania:

Ocena:

1. Analiza kodu programu zawartego w pliku lab3_0.c. #include <dos.h> #include <stdio.h> #include #define IRQ1_OFF outp(0x21,0x02) #define IRQ1_ON outp(0x21,0x00) void buf_wyj(void); void main(void) { unsigned char scan_code; IRQ1_OFF; clrscr(); printf("Nacisnij dowolny klawisz do { buf_wyj(); scan_code=inp(0x60); printf("\t%d",scan_code); } while (scan_code!=0x01); IRQ1_ON; }

ESC-Zakonczenie.\n\n\n");

void buf_wyj(void) { unsigned char rej_stanu; do rej_stanu=inp(0x64); while((rej_stanu & 0x01)!=0x01); } Tab1_1. Kod programu

Rys1_1. Okno CPU

Po wykonaniu programu zmianie uległy niektóre wartości rejestrów i flag procesora, ich wartość można było odczytać z okna Register CPU. Jak widać na rysunku Rys1_1 zmianie uległy rejestry CS=0x8d73, DS=0x8d63, ES=0x8d63, SP=0x9008 oraz flagi z=1, p=1, i=1. Na początku programu zostają dołączone pliki nagłówkowe bibliotek standardowych dos i stdio i conio. Które zawierają definicje funkcji wykorzystywanych w dalszej części programu np. standardowej funkcji wyjścia printf() biblioteka dos. Następnie

zdefiniowane zostają dwie makrodefinicje IRQ1_OFF i IRQ1_ON, które odpowiednio blokują i odblokowują przerwanie klawiatury IRQ1. W makrodefinicjach tych wykorzystana jest funkcja outp, która wpisuje 1 bajt do portu o zadanym numerze (przerwania maskujemy wykorzystując port 0x21). Następnie zapisana jest predefinicja funkcji buf_wyj. Funkcja ta w pętli pobiera 1 bajt z portu 0x64 do zmiennej typu rej_stanu wykorzystując w tym celu funkcje biblioteczną inp. Działanie to jest powtarzane aż bit 0 pobranego bajtu (informujący o stanie bufora wyjściowego klawiatury) ma wartość 0 co informuje, że bufor jest pusty. Funkcja main. W funkcji zdeklarowana jest jedna zmienna typu unsigned char scan_code, która przechowywać będzie wartość kodu ostatnio wciśniętego, bądź puszczonego klawisza pobrany z portu 0x60. Na początku wykorzystując makrodefinicje IRQ1_OFF maskowane jest przerwanie 1, przerwanie klawiatury. Czyścimy ekran i wypisujemy komunikat wykorzystując dwie funkcje biblioteczne odpowiednio clrscr i printf. W pętli wykonywanej aż odebranym kodem z portu 0x60 będzie kod 1, co odpowiada naciśnięciu klawisza ESC, odbierane i wypisywane są informacje z portu 0x60. Dzięki wywołanej wcześniej funkcji buf_wyj wypisywane są kody tylko, kiedy zostanie klawisz naciśniety, trzymany, bądź puszczony. Bez wywołania tej funkcji odczytywalibyśmy i wypisywali zawsze zawartość portu 0x60. Kod pojawiający się w buforze klawiatury: a) po naciśnięciu i puszczeniu klawisza, Po naciśnięciu klawisza standardowego w buforze klawiatury pojawia się jego Scan Code, który jest zależny od pozycji klawisza na klawiaturze. Gdy puszczamy klawisz w do bufora przesłany jest kod klawisza zwiększony o 128, co odpowiada ustawieniu 7 bitu. Dla przykładu naciskając klawisz ‘m’ w buforze znajdzie się wartość 50, a po jego puszczeniu 178. b) po naciśnięciu kombinacji klawiszy (nie puszczając pierwszego klawisza, wciskając, puszczając i przytrzymując drugi). Po wciśnięciu i przytrzymaniu kilku klawiszy do bufora klawiatury przesyłany jest kod ostatnio wciśniętego klawisza, puszczając jeden z klawiszy (trzymając wciśnięte pozostałe) do bufora przesłany jest jego scan code +128, a potem nie są przesyłane żadne informacje puszczając trzymane wcześniej klawisze wypisywane są ich scan code’y zwiększone o 128. c) po naciśnięciu klawisza funkcyjnego, Po wciśnięciu klawisza funkcyjnego do bufora klawiatury przesłany zostaje jego kod tak samo jak w przypadku zwykłych klawiszy. Np. wciskając F1 przesłany jest kod 60, F2 61, F3 62 itd. Po ich puszczeniu przesyłane są ich kody zwiększone o 128. d) porównanie kodów klawiszy 1,2...9,0 z klawiatury głównej (alfanumerycznej)i zestawu dodatkowego (numerycznej), opis klawisza

kod z klawiatury alfanumerycznej

kod klawisza z klawiatury numerycznej

0 1 2 3 4 5 6 7

82 79 80 81 75 76 77 71

11 2 3 4 5 6 7 8

8 9

72 73

9 10

Tab1_2. Zestawienie kodów klawiszy numerycznych

Oczywiście kody puszczenia przedstawionych tu klawiszy to po prostu ich kody zwiększone o 128. Jak widać przedstawione tu klawisze mają się do siebie jak piernik do wiatraka, ale są jednak interpretowane tak samo (jeżeli aktywny jest tryb Num Lock), interpretacje bowiem scan code’ów przeprowadza funkcja 0x09. Należy także, zauważyć, że po wciśnięciu klawisza Num Lock scan code’y klawiszy z klawiatury numerycznej nie zmieniają się, a mimo to zmienia się ich działanie. Można to porównać z dziewczyną, którą się poślubi przed ślubem i po ślubie niby to ta sama kobieta, ale jej działanie się zupełnie zmienia, tak samo jest z klawiszami z klawiatury numerycznej i z klawiszem Num Lock, który pełni tu role ślubu (fajnie by było, żeby ślub i rozwód był tak prosty jak wciśnięcie klawisza ;) ) e) kody klawiszy kursora, Osobny blok do sterowania kursorem został wprowadzony w klawiaturze począwszy od klawiatury PS/2. Nowe klawisze rozpoznawane są przez wysłanie przedrostka E0h (224) i taki właśnie przedrostek będzie poprzedzał wciśniecie i puszczenie klawiszy kursora. Dodatkowo w klawiaturze zachowana jest zgodność z klawiaturą AT, w której to jeżeli był wciśnięty tryb Num Lock, aby uniknąć wpisania cyfry naciskając klawisz ->(4) należało wcisnąć wcześniej klawisz Shift. Klawiatura PS/2 symuluje właśnie takie działanie nowych klawiszy kursora, sama dopisując kody wciśnięcia i puszczenia klawisza Shift w trybie Num Lock. Ciąg kodów odpowiadających wciśnięciu i puszczeniu klawisza Opis klawisza

→ ← ↑ ↓

w trybie z włączonym Num Lock’em

w trybie z wyłączonym Num Lock’em

224, 42, 224, 77, 224, 205, 224, 170 224, 42, 224, 75, 224, 203, 224, 170 224, 42, 224, 72, 224, 200, 224, 170 224, 42, 224, 80, 224, 208, 224, 170

224, 77, 224, 205 224, 75, 224, 203 224, 72, 224, 200 224, 80, 224, 208

Tab1_3. Zestawienie kodów klawiszy kursora

W powyższej tabeli przedstawiłem zestawienie kodów strzałek sterujących kursorem, jeśli chodzi o pozostałe klawisze z bloku do sterowania kursorem, jak: Insert, Delete, Home, End, Page Up, Page Down sytuacja wygląda analogicznie. f) kody zwracane przez klawisze podwójne, ENTER, Ctrl, Alt, Shift. Ponieważ klawisze prawy Ctrl, prawy Alt, prawy Enter zostały wprowadzone dopiero w klawiaturze PS/2 dlatego też mają takie same kody jak ich „lewi bracia” ;), aby je rozróżnić klawiatura przed kodem wciśnięcia i puszczenia przesyła przedrostek E0h (224). Klawisze lewy i prawy Shift wprowadzone zostały na już w klawiaturze PC/XT dlatego też posiadają różne kody. Ciąg kodów odpowiadających wciśnięciu i puszczeniu klawisza Opis klawisza

ENTER Ctrl Alt Shift

Lewego

Prawego

28,156 29,156 56,184 42,170

224, 28, 224,156 224,29, 224,156 224,56, 224,184 224,54, 224,182

Tab1_4. Zestawienie kodów klawiszy podwójnych

2. Program wyświetlający na ekranie zawartość bufora klawiatury, odwołując się bezpośrednio do obszaru danych BIOS (BDA) (LAB3_1.c). #include <dos.h> #include #include <stdio.h> void main(void) { char koniec=0; unsigned int far *ptr0, far *ptr1; unsigned int far *ptr4, far *ptr5, far *ptr6; int c=0,i; clrscr(); _setcursortype(_NOCURSOR); ptr0 = MK_FP(0x0040,0x0080);// Bajt 40:80h (0x0480) - adres poczatku buforu ptr1 = MK_FP(0x0040,0x0082);// Bajt 40:82h (0x0482) - adres konca buforu ptr4 = MK_FP(0x0040,0x001A); // 40:1Ah (0x041A) - wskaznik odczytu ptr5 = MK_FP(0x0040,0x001C); // 40:1Ch (0x041C) - wskaznik zapisu ptr6 = MK_FP(0x0040,0x001E); // 40:1Eh (0x041E) - bufor printf("Adres poczatku bufora:40:%Xh\n",*ptr0); printf("Adres konca bufora:40:%Xh\n",*ptr1); gotoxy(25,24); printf("Nacisniecie ESC konczy program"); while(!koniec) { gotoxy(1,11); printf("Zawartosc bufora klawiatury:\n"); printf(" --------------------\n"); printf(" |ScanCode| ASCII | \n"); for(i=0;i<16;i++) { printf(" --------------------\n"); printf(" |%8i| '%c'=%3i | \n",ptr6[i]>>8,ptr6[i],ptr6[i]&0xFF); } printf(" --------------------\n"); //Ustawienie wskaznikow odczytu i zapisu gotoxy(1,(*ptr5-*ptr0)+15); printf("->"); gotoxy(23,(*ptr4-*ptr0)+15); printf("->"); gotoxy(1,10); printf("Wprowadzony znak: "); if(kbhit()) putchar(c=getch()); if(c==27) koniec=1; delay(500); } _setcursortype(_NORMALCURSOR); } Tab2_1. Kod programu

Rys2_1. Wynik działania programu

Program wyświetla zawartość bufora klawiatury odwołując się bezpośrednio do pamięci. Znak „->” oznacza pozycję wskaźnika zapisu natomiast znak „->” oznacza pozycję wskaźnika odczytu. W normalnej sytuacji, jeżeli odczytywalibyśmy funkcją getch() wciskany klawisz bez przerw, wskaźnik odczytu pokrywałby się ze wskaźnikiem zapisu (znaki były by odbierane bardzo szybko), dlatego, aby móc zauważyć jak zmieniają swoje położenie względem siebie wskaźniki zapisu i odczytu dodałem funkcję delay(500), która powoduje, że klawisz nie jest odczytywany częściej, niż, co 0,5 sekundy, na wpisywanie klawisza do buforu nie ma to wpływu, bo zajmuje się tym funkcja BIOS’u obsługująca przerwanie 09h, wiec klawisz trafia do bufora, (jeśli ten nie jest zapełniony) w chwili naciśnięcia. Dzięki takiej modyfikacji możliwe jest zaobserwowanie wszystkich stanów bufora klawiatury, a wiec bufor pusty (zrównanie wskaźników zapisu i odczytu), bufor częściowo zajęty, bufor przepełniony (Bufor przepełniony – wskaźnik zapisu odnosi się do znaku bezpośrednio poprzedzającego wskaźnik odczytu). Odpowiednio szybko naciskając klawisze na klawiaturze możemy doprowadzić do wszystkich stanów bufora. Należy także zauważyć, że dalsze naciskanie klawiszy na klawiaturze, gdy bufor jest przepełniony powoduje wygenerowanie krótkiego dźwięku „beep” z głośniczka systemowego. Sam kod programu jest niezwykle prosty. W funkcji main() zdeklarowane jest 5 dalekich wskaźników ptr0, ptr1, ptr4, ptr5, ptr6 na dwu bajtowe komórki, które po przypisaniu za pomocą makrodefinicji MK_FP tworzącej daleki wskaźnik z podanego segmentu i offsetu, wskazują odpowiednio na adres początku buforu, adres końca buforu, wskaźnik odczytu, wskaźnik zapisu, adres pierwszej komórki w bufora. Następnie w pętli while, wykonywanej

dopóty zmienna koniec jest różna od 0 wykonywana jest pętla for, która w każdej iteracji pętli while wyświetla zawartość bufora klawiatury. Bufor klawiatury zajmuje 32 bajty, czyli 16 komórek. Osiem bardziej znaczących bitów każdej komórki przechowuje scan kod znaku, natomiast osiem mniej znaczących bajtów przechowuje kod ASCII znaku. W każdej iteracji pętli for odczytujemy za pomocą wskaźnika ptr6 zawartość i’tej komórki bufora. Używając operatora >> wyłuskujemy scan cod i wyświetlamy go jako liczba całkowita, natomiast kod ASCII wyświetlamy jako znak oraz używając odpowiedniej maski jako liczba całkowita. Po wyświetleniu zawartości bufora wykorzystując wskaźniki ptr0 i ptr5 obliczamy przesunięcie wskaźnika zapisu względem początku bufora i używając funkcji gotoxy() wyświetlamy symbolizujący go znak „->” w odpowiednim miejscu na ekranie. Analogicznie wyświetlamy wskaźnik odczytu wykorzystując, do obliczenia przesunięcia, wskaźniki ptr0 i ptr4. Kiedy cała już zawartość bufora została wyświetlona wraz ze wskaźnikami zapisu i odczytu. Wykorzystując funkcję kbhit() sprawdzane jest czy bufor zawiera nieodczytany znak, jeżeli tak zostaje on odczytany funkcją getch(). Jeżeli odczytanym znakiem jest znak o kodzie ASCII 27 oznaczającym klawisz „Esc” zmienna koniec ustawiana jest na 1, przez co pętla while kończy swoje działanie. Gdy odczytanym znakiem nie jest znak „Esc” program odczekuje 0,5 sekundy, po czym przechodzi do kolejnej iteracji pętli while.

3. Program wyświetlający na ekranie aktualny stan klawiszy: Ctrl, Alt, Shift, Caps Lock. a) Odczytujący bezpośrednio pamięć danych BIOS-u (LAB3_2A.c), /*******************************************************************/ /* Wyswietlanie stanu klawiszy specjalnych: Alt, Ctrl, Shift, ... */ /*******************************************************************/ #include "dos.h" #include "conio.h" #include "stdio.h" char koniec=0; unsigned char far *ptr1, far *ptr2; unsigned char far *ptr3, far *ptr4; char LAlt, PAlt; // Lewy, Prawy Alt char LShift, PShift; // Lewy, Prawy Shift char LCtrl, PCtrl; // Lewy, Prawy Ctrl char NLck,CsLck,SrLck; // Num Lock, Caps Lock, Scroll Lock void main(void) { int c=0; clrscr(); _setcursortype(_NOCURSOR); gotoxy(25,24); printf("Nacisniecie ESC konczy program"); ptr1 = MK_FP(0x40,0x17); ptr2 = MK_FP(0x40,0x18); ptr3 = MK_FP(0x40,0x96); ptr4 = MK_FP(0x40,0x97);

// Bajt 40:17h (0x0417) - klawisze specjalne // Bajt 40:18h (0x0418) - klawisze specjalne // Bajt 40:96h (0x0496) - klawisze specjalne // Bajt 40:97h (0x0497) - klawisze specjalne

while(!koniec) { LAlt =(*ptr2&0x02)>>1; // Lewy Alt PAlt =(*ptr3&0x08)>>3; // Prawy Alt LCtrl =(*ptr2&0x01); // Lewy Ctrl

PCtrl =(*ptr3&0x04)>>2; // Prawy Ctrl LShift =(*ptr1&0x02)>>1; // Lewy Shift PShift =(*ptr1&0x01); // Prawy Shift NLck =(*ptr1&0x20)>>5; // Num Lock CsLck =(*ptr1&0x40)>>6; // Caps Lock SrLck =(*ptr1&0x10)>>4; // Scroll Lock gotoxy(1, 1); printf("40:17h => %4X 40:18h => %4X ", *ptr1, *ptr2); gotoxy(1, 2); printf("40:96h => %4X 40:97h => %4X ", *ptr3, *ptr4); gotoxy(1, 4); printf("Lewy Alt : %s", LAlt ? "Tak" : "Nie"); gotoxy(1, 5); printf("Prawy Alt : %s", PAlt ? "Tak" : "Nie"); gotoxy(1, 6); printf("Lewy Ctrl : %s", LCtrl ? "Tak" : "Nie"); gotoxy(1, 7); printf("Prawy Ctrl : %s", PCtrl ? "Tak" : "Nie"); gotoxy(1, 8); printf("Lewy Shift: %s", LShift ? "Tak" : "Nie"); gotoxy(1, 9); printf("Prawy Shift: %s", PShift ? "Tak" : "Nie"); gotoxy(1,10); printf("Num Lock : %s", NLck ? "Tak" : "Nie"); gotoxy(1,11); printf("Caps Lock : %s", CsLck ? "Tak" : "Nie"); gotoxy(1,12); printf("Scroll Lock: %s", SrLck ? "Tak" : "Nie"); if(kbhit()) c=getch(); if(c==27) koniec=1; } _setcursortype(_NORMALCURSOR); } Tab3_1. Kod programu

Rys3_1. Wynik działania programu

Dla PS/2 informacje o stanie klawiszy Alt, Ctrl, Shift, Num Lock, Caps Lock, Scroll Lock przechowywane są w 3 bajtach pamięci w obszarze zmiennych BIOS’u. Każdy bit z tych bajtów posiada znaczenie, aby odczytać stan klawiszy specjalnych musimy odczytać stan niektórych bitów z wymienionych wcześniej bajtów zawierających stan tych klawiszy. - Bajt 0040:0017h znaczenie bitów: Bit 7 jest aktywny tryb INSERT Bit 6 jest aktywny tryb CAPS LOCK Bit 5 jest aktywny tryb NUM LOCK Bit 4 jest aktywny tryb SCROLL LOCK Bit 3 naciśnięto klawisz ALT (lewy lub prawy) Bit 2 naciśnięto klawisz CTRL (lewy lub prawy) Bit 1 naciśnięto lewy klawisz SHIFT Bit 0 naciśnięto prawy klawisz SHIFT - Bajt 0040:0018h znaczenie bitów: Bit 7 naciśnięto klawisz INSERT Bit 6 naciśnięto klawisz CAPS LOCK

Bit 5 naciśnięto klawisz NUM LOCK Bit 4 naciśnięto klawisz SCROLL LOCK Bit 3 jest aktywny tryb PAUSE Bit 2 naciśnięto klawisz SysReq Bit 1 naciśnięto lewy klawisz ALT Bit 0 naciśnięto lewy klawisz CTRL -Bajt 0040:0096h znaczenie bitów: Bit 7 trwa odczyt kodu identyfikacyjnego Bit 6 ostatnim odebranym kodem był kod identyfikacyjny Bit 5 przy odczycie kodu identyfikacyjnego i kodu rozszerzonego nale-ży włączyć tryb NUM LOCK Bit 4 w systemie obecna jest klawiatura PS/2 Bit 3 naciśnięto prawy klawisz ALT Bit 2 naciśnięto prawy klawisz CTRL Bit 1 ostatnio odebranym znakiem był przedrostek E0h Bit 0 ostatnio odebranym znakiem był przedrostek E1h Interesujące nas bity zostały pogrubione! W kodzie programu na interesujące nas bajty wskazują dalekie wskaźniki ptr1, ptr2, ptr3, wskaźniki te inicjowane są za pomocą makrodefinicji MK_FP. Zdeklarowane są też odpowiednie zmienne LAlt, PAlt, LShift, PShif, LCtrl, PCtrl, NLck, CsLck, SrLck, przechowujące stan odpowiadającym im klawiszy specjalnych. Wartość 0 odpowiada braku aktywności, a 1 aktywności danego klawisza. Używając odpowiednich operatorów >>, & wyłuskujemy z danych bajtów bity, których stan odpowiada stanowi danego klawisza specjalnego i zapisujemy je pod daną zmienną. Po odpowiednim ustawieniu zmiennych pomocniczych wyświetlamy stan klawiszy specjalnych na ekranie. b) Wywołujący przerwanie INT 16H (LAB3_2B.c). /*******************************************************************/ /* Wyswietlanie stanu klawiszy specjalnych: Alt, Ctrl, Shift, ... */ /*******************************************************************/ #include "dos.h" #include "conio.h" #include "stdio.h" char koniec=0; unsigned char far *ptr1, far *ptr2; unsigned char far *ptr3, far *ptr4; char LAlt, PAlt; // Lewy, Prawy Alt char LShift, PShift; // Lewy, Prawy Shift char LCtrl, PCtrl; // Lewy, Prawy Ctrl char NLck,CsLck,SrLck; // Num Lock, Caps Lock, Scroll Lock void czytaj_klaw_dod(void) { union REGS regs; unsigned int ax; regs.h.ah = 0x12; // funkcja odczytu stanu klawiszy dodatkowych int86(0x16, ®s, ®s); ax=regs.x.ax; // 2 bajty statusu klawiszy dodatkowych (AH,AL)

LAlt =(ax&0x0200)>>9; // Lewy Alt bit 9 PAlt =(ax&0x0800)>>11; // Prawy Alt LCtrl =(ax&0x0100)>>8; // Lewy Ctrl bit 8 PCtrl =(ax&0x0400)>>10; // Prawy Ctrl LShift =(ax&0x0002)>>1; // Lewy Shift bit 1 PShift =(ax&0x0001); // Prawy Shift bit 0 NLck =(ax&0x0020)>>5; // Num Lock bit 5 CsLck =(ax&0x0040)>>6; // Caps Lock SrLck =(ax&0x0010)>>4; // Scroll Lock

bit 11 bit 10

bit 6 bit 4

} void main(void) { int c=0; clrscr(); _setcursortype(_NOCURSOR); gotoxy(25,24); printf("Nacisniecie ESC konczy program"); ptr1 = MK_FP(0x40,0x17); // Bajt 40:17h (0x0417) - klawisze specjalne ptr2 = MK_FP(0x40,0x18); // Bajt 40:18h (0x0418) - klawisze specjalne ptr3 = MK_FP(0x40,0x96); // Bajt 40:96h (0x0496) - klawisze specjalne ptr4 = MK_FP(0x40,0x97); // Bajt 40:97h (0x0497) - klawisze specjalne while(!koniec) { czytaj_klaw_dod();

// czytaj stan klawiszy dodatkowych

gotoxy(1, 1); printf("40:17h => %4X 40:18h => %4X ", *ptr1, *ptr2); gotoxy(1, 2); printf("40:96h => %4X 40:97h => %4X ", *ptr3, *ptr4); gotoxy(1, 4); printf("Lewy Alt : %s", LAlt ? "Tak" : "Nie"); gotoxy(1, 5); printf("Prawy Alt : %s", PAlt ? "Tak" : "Nie"); gotoxy(1, 6); printf("Lewy Ctrl : %s", LCtrl ? "Tak" : "Nie"); gotoxy(1, 7); printf("Prawy Ctrl : %s", PCtrl ? "Tak" : "Nie"); gotoxy(1, 8); printf("Lewy Shift: %s", LShift ? "Tak" : "Nie"); gotoxy(1, 9); printf("Prawy Shift: %s", PShift ? "Tak" : "Nie"); gotoxy(1,10); printf("Num Lock : %s", NLck ? "Tak" : "Nie"); gotoxy(1,11); printf("Caps Lock : %s", CsLck ? "Tak" : "Nie"); gotoxy(1,12); printf("Scroll Lock: %s", SrLck ? "Tak" : "Nie"); if(kbhit()) c=getch(); if(c==27) koniec=1; } _setcursortype(_NORMALCURSOR); } Tab3_2. Kod programu

Rys3_2. Wynik działania programu

Stan klawiszy specjalnych możemy także odczytać odwołując się do przerwania BIOS’u 16h. Przerwanie to wywołujemy wykorzystując funkcję int86(), wcześniej odpowiednio inicjując unie REGS, przez którą zostają przekazany numer funkcji obsługującej przerwanie (funkcja o numerze 12h w rejestrze ax zwraca 2 bajty informacji o stanie klawiszy dodatkowych), przez tą też unie zostaje zwrócona wartość rejestru ax. Watrość rejestru ax przekazana jest przez strukturę REGS i zapisana jest pod zmienną ax typu unsigned char (2 bajty). Każdy bit zmiennej ax oznacza stan klawiszy dodatkowych: bit 0 prawy Shift bit 1 lewy Shift bit 2 Ctrl bit 3 Alt bit 4 Scroll Lock bit 5 Num Lock bit 6 Caps Lock bit 7 Insert bit 8 lewy Ctrl bit 9 lewy Alt bit 10 prawy Ctrl bit 11 prawy Alt bit 12 Scroll Lock bit 13 Num Lock bit 14 Caps Lock bit 15 SysReq (1-aktywny, 0-nie aktywny). Używając odpowiednich operatorów >>, & możemy wyłuskać wartości interesujących nas bitów, przez co odczytujemy stan interesujących nas klawiszy specjalnych.

4. Program modyfikujący funkcję obsługi przerwania INT 9H tak, by kod ASCII naciskanego klawisza przybierał wartość o 1 większą od pierwotnej (LAB3_3.c). /*******************************************************************/ /* Przykladowy program obslugi klawiatury z wykorzystaniem INT 9 */ /*******************************************************************/ #include "dos.h" #include "conio.h"

#include "stdio.h" void interrupt (*old_int_09)(void); // wskaznik na funkcje przerwania void interrupt kbd_int(void) // przerwaniowy odbior klawiszy { static unsigned char offset, znak; disable(); old_int_09();

// zablokuj przerwania // stara funkcja obslugi przerwania

offset = peek(0x40,0x1A); znak = peekb(0x40,offset); if(znak>=32) pokeb(0x40,offset,znak+1);

// offset do odczytu znaku w buforze // odczytaj bajt z bufora klawiatury // jesli kod ASCII >= 32 // podmien kod ASCII w buforze

enable();

// odblokuj przerwania

} void main(void) { char tab[85]; clrscr(); disable(); old_int_09 = getvect(0x09); setvect(0x09, kbd_int); enable();

// wyczysc ekran // zablokuj przerwania // wskaznik do starego przerwania // instaluj nowe przerwanie // odblokuj przerwania

printf("Wprowadz ciag znakow zakonczony Enterem (max 80 znakow)\n"); gets(tab); // wczytaj lancuch znakow disable(); setvect(0x09, *old_int_09); enable();

// wyczysc ekran // przywroc stare przerwanie // odblokuj przerwania

// keep(0,1300);

// pozostaw program jako rezydentny

} Tab4_1. Kod programu

Rys4_1. Wynik działania programu

Na rysunku 4_1 można zaobserwować wynik działania programu dla wprowadzonych z klawiatury znaków „abcd123” jak widzimy program działa zgodnie z oczekiwaniem, czyli do bufora klawiatury trafia znak o kodzie ASCII zwiększonym o 1. Program na początku swego działania zapisuje adres funkcji obsługującej przerwanie INT 09h pod wskaźnik old_int_09 wykorzystując funkcję biblioteczną getvect() przyjmującą za parametry nr przerwania i wskaźnik, pod jaki zostaje zapisany adres funkcji obsługującej

to przerwanie. Następnie podmienia wskaźnik na tą funkcję, która jest wywoływana w chwili nadejścia przerwania 09h, czyli w chwili naciśnięcia klawisza na klawiaturze, na wskaźnik do funkcji kbd_int() wykorzystuje w tym celu funkcje biblioteczną setvect(), która jako parametry przyjmuje nr przerwania i wskaźnik do funkcji. Funkcja kbd_int() na początku blokuje przerwania następnie wywołuje starą funkcję obsługującą przerwanie 09h old_int_09(), która wstawia do bufora odczytany z portu klawiatury znak odpowiednio go interpretując. Następnie w funkcji kbd_int() pobierany jest ten znak z bufora klawiatury i jeżeli jego kod ASCII jest większy od 31, zwiększa jego wartość o 1 i zapisuje w tym samym miejscu w buforze. Na końcu odblokowuje przerwania. W programie wczytywany jest łańcuch znaków, aż do naciśnięcia enter’a, a następnie zostaje przywrócony wskaźnik na starą funkcję obsługującą przerwanie.

5. Program modyfikujący funkcję obsługi przerwania INT 9H tak, aby każdorazowe naciśnięcie klawisza F12 generowało krótki sygnał dźwiękowy. (LAB3_4.c). /*******************************************************************/ /* Przykladowy program obslugi klawiatury z wykorzystaniem INT 9 */ /*******************************************************************/ #include "dos.h" #include "conio.h" #include "stdio.h" #define HOT_KEY 0x58 #define EXIT_KEY 0x57

// F12 // F11

void interrupt (*old_int_09)(void); // wskaznik na funkcje przerwania volatile unsigned char quit=0,beep=0; // koniec programu volatile unsigned int tbkl; // stan klawiszy panelu unsigned char stat; // status portu klawiatury /* "1" "2" "3" "4" "5" "6" "7" "8"*/ const unsigned int TBKEYS[] = { 0,0,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80, 0,0,0,0,0,0 }; void interrupt kbd_int(void) { disable();

// przerwaniowy odbior klawiszy

if((stat=inportb(0x60)) & 0x80) // gdy klawisz puszczany { stat &= 0x7F; tbkl &= ~TBKEYS[(stat>15)?0:stat]; // klawisze: Esc,1,2,..9,0,-,=,Bsp } else // gdy klawisz naciskany { tbkl |= TBKEYS[(stat>15)?0:stat]; } if(stat == EXIT_KEY) quit = 1; if(stat == HOT_KEY) beep=1; /* konieczne uaktywnienie klawiatury */ stat = inportb(0x61); outportb(0x61, stat | 0x80); outportb(0x61, stat); outportb(0x20, 0x20); old_int_09(); enable(); }

// End-Of-Interrupt (dla 8259) // stara funkcja obslugi przerwania

/*******************************************************************/ /* Przykladowy program obslugi klawiatury z wykorzystaniem INT 9 */ /*******************************************************************/ #include "dos.h" #include "conio.h" #include "stdio.h" #define HOT_KEY 0x58

// F12

void interrupt (*old_int_09)(void); // wskaznik na funkcje przerwania volatile unsigned char beep=0; unsigned char stat, quit=0;

// byl wcisniety F12 // koniec programu

void interrupt kbd_int(void) { disable();

// przerwaniowy odbior klawiszy

stat=inportb(0x60); if(stat==(HOT_KEY|0x80))beep=0; if((stat == HOT_KEY)&&(beep==0)) beep=1; outportb(0x20, 0x20); old_int_09(); enable();

// End-Of-Interrupt (dla 8259) // stara funkcja obslugi przerwania

} void inst_kbd(void) { disable(); old_int_09=getvect(0x09); setvect(0x09, kbd_int); enable(); }

// instaluj nowe przerwanie

void rest_kbd(void) { disable(); setvect(0x09, *old_int_09); enable(); }

// przywroc stare przerwanie

void main(void) { int c=0; clrscr();

inst_kbd(); _setcursortype(_NOCURSOR); gotoxy(22,24); printf("Nacisniecie ESC konczy program"); while(!quit) { if(kbhit()) (c=getch()); if(beep == 1) { beep=2; sound(1000); delay(1000); nosound(); } if(c==27) quit=1; } _setcursortype(_NORMALCURSOR); rest_kbd(); } Program działa podobnie do programu LAB3_3.c jednak nowa funkcja obsługująca przerwanie 09h kbd_int() przed wywołaniem starej funkcji pobiera wartość portu klawiatury o numerze 60h do zmiennej stat. Odczytana wartość jest scan code’em naciśniętego klawisza. Jeżeli ta wartość wynosi 0x58 (co odpowiada scan code klawisza F12) zmienna beep ustawiona zostaje na 1.W funkcji main() w pętli while sprawdzana jest wartość zmiennej beep w przypadku, gdy zmienna beep ustawiona jest na wartość jeden wywołana jest funkcja biblioteczna sound() generująca dźwięk o określonej częstotliwości odczekana jest 1 sekunda i zmienna beep ustawiona zostaje na wartość 0. W pętli tej sprawdzane są również kody ASCII naciśniętych klawiszy. Jeżeli naciśnięty zostanie klawisz „Esc” zmienna quit ustawiona jest na wartość 1 i program kończy działanie.

6. Program zakładający alternatywny bufor klawiatury, pozwalający pomieścić większą ilość znaków niż standardowy (15) (LAB3_5.c). #include <dos.h> unsigned int far *ptr0, far *ptr1; unsigned int far *ptr4, far *ptr5, far *ptr6; //Bufor 52 bajtowy, mogacy pomiesic 25 znakow void zmienbufor() { disable(); ptr0 = MK_FP(0x0040,0x0080); // Bajt 40:80h (0x0480) - adres poczatku buforu ptr1 = MK_FP(0x0040,0x0082); // Bajt 40:82h (0x0482) - adres konca buforu ptr4 = MK_FP(0x0040,0x001A); // 40:1Ah (0x041A) - wskaznik odczytu ptr5 = MK_FP(0x0040,0x001C); // 40:1Ch (0x041C) - wskaznik zapisu *ptr0=0x00A4; *ptr1=0x00D8; *ptr4 =0x00A4; *ptr5 =0x00A4; enable(); }

7. Program zawierający i testujący funkcję, która nie tylko odnotowuje naciśnięcie klawisza, lecz sprawdza jak długo jest on naciśnięty (LAB3_6.c). #include #include <stdio.h> #include #include <dos.h> void interrupt (*old_int_09)(void); // wskaznik na funkcje przerwania volatile unsigned char przy=0; unsigned char stat,klaw, quit=0; clock_t start, end;

// byl wcisniety klawisz, jaki kod klawisza // koniec programu

void interrupt kbd_int(void) { disable();

// przerwaniowy odbior klawiszy

stat=inportb(0x60); if((przy==0)&&((stat&0x80)==0)) { klaw=stat; przy=1; } if((przy==2)&&((klaw|0x80)==stat)) przy=3;

// pobranie scan code z portu klawiatury

outportb(0x20, 0x20);

// End-Of-Interrupt (dla 8259)

old_int_09(); enable();

// stara funkcja obslugi przerwania

} void inst_kbd(void) { disable(); old_int_09=getvect(0x09); setvect(0x09, kbd_int); enable(); }

// instaluj nowe przerwanie

void rest_kbd(void) { disable(); setvect(0x09, *old_int_09); enable(); }

// przywroc stare przerwanie

void czas() { int c=0;

clrscr(); inst_kbd(); _setcursortype(_NOCURSOR); printf("Nacisniecie ESC konczy program\n"); while(!quit) { if(kbhit()) (c=getch()); if(przy==1) { start = clock(); przy=2; } if(przy==3) { end = clock(); printf("Klawisz o Scan Code=%i byl wcisniety: %fs\n",klaw,(end - start)/CLK_TCK); przy=0; } if(c==27) quit=1; } _setcursortype(_NORMALCURSOR); rest_kbd(); } void main(void) { clrscr(); czas(); }

8. Program generujący sygnał dźwiękowy w przypadku jednoczesnego naciśnięcia trzech klawiszy, np. ‘f’+’d’+’2’ (LAB3_5.c). (LAB3_7.c). #include "dos.h" #include "conio.h" #include "stdio.h" #define m_f 33 #define m_d 32 #define m_2 3

// przycisk f // przycisk d // przycisk 2

void interrupt (*old_int_09)(void); // wskaznik na funkcje przerwania volatile unsigned char p_f=0,p_d=0,p_2=0; // byl wcisniety F12 unsigned char stat, quit=0; // koniec programu

void interrupt kbd_int(void) { disable(); stat=inportb(0x60); if(stat==m_f) p_f=1; if(stat==m_d) p_d=1; if(stat==m_2) p_2=1; if(stat==(m_f|0x80)) p_f=0; if(stat==(m_d|0x80)) p_d=0; if(stat==(m_2|0x80)) p_2=0; outportb(0x20, 0x20); old_int_09(); enable();

// przerwaniowy odbior klawiszy

// wcisnal klawisz 'f' // wcisnal klawisz 'd' // wcisnal klawisz '2' // puscil klawisz 'f' // puscil klawisz 'd' // puscil klawisz '2' // End-Of-Interrupt (dla 8259) // stara funkcja obslugi przerwania

} void inst_kbd(void) { disable(); old_int_09=getvect(0x09); setvect(0x09, kbd_int); enable(); }

// instaluj nowe przerwanie

void rest_kbd(void) { disable(); setvect(0x09, *old_int_09); enable(); }

// przywroc stare przerwanie

void main(void) { int c=0; clrscr(); inst_kbd(); _setcursortype(_NOCURSOR); gotoxy(25,25);printf("Nacisniecie ESC konczy program\n"); gotoxy(25,26);printf("Nacisnij 'f'+'d'+'2'"); while(!quit)

{ if(kbhit()) (c=getch()); while(p_f&&p_d&&p_2) { sound(1000); if(kbhit()) (c=getch()); } nosound(); if(c==27) quit=1; } _setcursortype(_NORMALCURSOR); rest_kbd(); }

Do sprawozdania dołączone są wszystkie opisane w nim kody programów!

Related Documents

Sprawozdanie
June 2020 3
Sprawozdanie
June 2020 8
Sprawozdanie Z Praktyk
November 2019 4
Sprawozdanie Esp Acca 2
November 2019 8