plik


Programowanie glosniczka w assemblerze Autor: Bogdan Drozdowski, bogdandr (at) op.pl Czy nie myslicie czasem, jakby to bylo, gdyby mozna bylo wzbogacic swoj program oprocz efektu wizualnego, takze o efekt dzwiekowy? Programowanie kart dzwiekowych (zwlaszcza tych nowoczesnych) moze sprawiac niemale klopoty. Stary, poczciwy PC-Speaker jest jednak urzadzeniem wzglednie prostym w programowaniu. I to wlasnie tutaj udowodnie. Najpierw troszke teorii, potem - do dziela! Sporo urzadzen w komputerze ma wlasne porty, przez ktore mozna sie z nimi komunikowac. Jednak glosniczek komputerowy nie ma wlasnego portu. Jest tak przede wszystkim ze wzgledu na oszczednosci w budowie pierwszych PC-tow. Zamiast dac osobny port na glosnik, firmy produkujace komputery wcisnely go "pod opieke" dwoch innych urzadzen: - czasomierza systemowego, ktory posluzy nam do wytworzenia impulsow odpowiedniej czestotliwosci - kontrolera klawiatury, ktory kontroluje, czy jest otwarty "kanal" z czasomierza do glosniczka, tzn. czy mozna bedzie wysylac informacje. Podstawowe porty czasomierza to porty od 40h do 43h (caly zakres to 40h - 5fh, h = szestnastkowo), kontrolera klawiatury zas - 60h do 64h (caly zakres: 60h - 6fh). Nie bedziemy ich jednak wszystkich uzywac. Beda na interesowac tylko porty 42h, 43h i 61h. Zacznijmy wiec cos pisac: in al,61h or al,3 out 61h,al Co zrobilismy? W spisie portow (Listy Przerwan Ralfa Brown'a) czytamy: =========================== 0061 R- KB controller port B control register (ISA, EISA) 0061 -W KB controller port B (ISA, EISA) (R - czytanie (read) , W - pisanie (write)) =========================== oraz: =========================== Bitfields for KB controller port B (system control port) [output]: Bit(s) Description (Table P0392) 7 pulse to 1 for IRQ1 reset (PC,XT) 6-4 reserved 3 I/O channel parity check disable 2 RAM parity check disable 1 speaker data enable 0 timer 2 gate to speaker enable =========================== Komenda "in al,61h" czyta biezacy status kontrolera, "or al,3" ustawia (wlacza) bity 0 (wlaczenie bramki do glosniczka) oraz 1 (wlaczenie mozliwosci wysylania danych do glosniczka), "out 61h,al" zapisuje nowy status do kontrolera. Glosniczek jest wlaczony. Trzeba mu podac jakis sygnal. Do tego posluzy nam czasomierz. W spisie portow czytamy: =========================== 0042 RW PIT counter 2, cassette & speaker 0043 RW PIT mode port, control word register for counters 0-2 Once a control word has been written (43h), it must be followed immediately by performing the corresponding action to the counter registers (40h-42h), else the system may hang!! =========================== Do portow tych nie bedziemy wysylac jednak czestotliwosci, ktora chcemy uzyskac. Czasomierz pracuje na czestotliwosci 1193181 (1234DDh) Hz i to te wartosc dzielimy przez zadana czestotliwosc. Wynik wysylamy do odpowiednich portow. Piszmy wiec: mov bx,440h ; Standardowe "A", 440 Hz mov dx,12h ; gorna czesc "1234dd" mov ax,34ddh ; dolna czesc "1234dd" div bx ; ax = wartosc do wyslania push ax mov al,0b6h out 43h,al pop ax out 42h,al mov al,ah out 42,al No i co my tutaj znowu zrobilismy? 4 pierwsze komendy to oczywiscie uzyskanie wartosci do wyslania na port, ale reszta? Najpierw: 0b6h = 1011 0110 =========================== Bity 7 i 6 = 10 = wybierz (standardowo niezajety) czasomierz nr 2 (lacznie sa 3: zegar czasu rzeczywistego, czasomierz odswiezania pamieci RAM i ten trzeci, nieuzywany) Bity 5 i 4 = 11 = zapisujemy do czasomierza najpierw mlodsze bity (0-7) wartosci, potem starsze (8-15) Bity 3-1 = 011 = wybierz tryb nr 3, czyli generator fali kwadratowej Bit 0 = 0 = licznik binarny 16-bitowy. =========================== Zgodnie z tym, najpierw wysylamy mlodszy bajt, AL a potem starszy, AH. Skoro na port mozna wyslac najwieksza wartosc 0ffffh (teoretycznie najwieksza jest 10000h, obcinana do 0000h), to jakiej odpowiada to czestotliwosci? 1234dd / 10000h to ok. 12h, czyli 18. A dokladniej jest to cos okolo 18,2 Hz - standardowa czestotliwosc zegara w komputerze (tj. aby odmierzyc 1 sekunde trzeba ok 18 tykniec tego zegara) Nasz glosniczek juz gra. Teraz trzeba sprawic, bo to troszke potrwalo. Pomocne bedzie przerwanie 15h, funkcja 86h: mov cx,0fh mov dx,4240h mov ah,86h int 15h ; pauza o dlugosci CX:DX mikrosekund I dzwiek trwa 1 sekunde (F4240h = 1.000.000). Teraz trzeba go wylaczyc. Nic prostszego. Po prostu zamkniemy przejscie miedzy czasomierzem a glosniczkiem: in al,61h and al,not 3 ; zerujemy bity 0 i 1 ; NASM: "and al,~3" out 61h,al Mam nadzieje, ze podalem wystarczajaco informacji, abyscie samodzielnie zaczeli programowac glosniczek. Jesli mi sie nie udalo, to zawsze mozecie skorzystac z gotowej procedury z mojej biblioteki. To juz koniec. Milej zabawy!

Wyszukiwarka