Pascal


Dostęp do ekranu z poziomu pamięci RAM

Zaprogramowanie wyświetlenia znaku na ekranie w dowolnej pozycji nie należy do czynności specjalnie trudnych. Wystarczy załadować moduł CRT i wykonać przykładowo poniższy kod.

TextColor(Yellow);
TextBackground(Blue);
GotoXY(10,10);
Write('A');

Spowodouje to wyświetlenie wielkiej litery "A" koloru żółtego na niebieskim tle w pozycji (10,10).

Co jednak jeśli zamiast wstawiać znak chcemy sprawdzić co znajduje się na konkretnej pozycji? Procedury modułu CRT nie dają nam takiej możliwości. Aby to zrobić możemy za to skorzystać z przydatnej własności. Otóż cała zawartość ekranu w DOS'ie jest przechowywana w pamięci RAM. Są tam trzymane informacje nie tylko o znaku na danej pozycji, ale także o jego kolorze i kolorze tła na danej pozycji.

Do zapisu informacji o jednej pozycji potrzebne są 2 bajty. Jeden bajt to kod znaku jaki znajduje się na ekranie, a drugi zawiera inforamcje o kolorze tła i kolorze znaku.

W jaki sposób zapisywana jest informacja o kolorze?

Jak wiadomo 1 bajt to 8 bitów. Cztery najmłodsze bity informują nas o kolorze znaku, kolejne 3 o kolorze tła, a najstarszy bit określa czy dany znak mam migać (tylko w trybie pełnego ekranu). Jak zapewne zauważyliście opis koloru tła zajmuje tylko 3, a opis koloru znaku 4 bity. Dlatego właśnie w Pascalu dostępnych jest tylko 8 kolorów tła przy 16 kolorach znaków. Dla przypomnienia przedstawiam tabelkę stałych kolorów w Pascalu:

Numer Kolor
0 Black - czarny.
1 Blue - niebieski.
2 Green - zielony.
3 Cyan.
4 Red - czerwony.
5 Magenta.
6 Brown - brązowy.
7 LightGray - szary jasny.
8 DarkGray - ciemny szary.
9 LightBlue - niebieski jasny.
10 LightGreen - zielony jasny.
11 LightCyan.
12 LightRed - czerwony szary.
13 LightMgenta.
14 Yellow.
15 White.

Przykład:

Mamy dany bajt w pamięci opisujący kolory na danej pozyji: 01100010. Rozbijamy ten bajt na grupy bitów dające nam poszczególne informacje:

0 110 0010

0 - najstarszy bit nie ustawiony - znak nie będzie migał,
110 - kolor tła ustawiony na wartość 3 - Brown (brązowy),
1010 - kolor znaku ustawiony na wartość 10 - LightGreen (jasny zielony).

A więc jest to informacja mówiąca, że na danej pozycji znak jest migający, koloru zielonego na brązowym tle.

Ekran standardowo ma 80x25 znaków, co daje razem 2000 znaków - a więc cała informacja o ekranie w pamięci RAM zajmie 4000 bajtów (2 bajty na jeden znak). Kolejne znaki (począwszy od pierwszego wiersza) zapisane są w pamięci pod adresem B800h, gdzie pierwsze 2 bajty pod tym adresem informują o znaku w lewym górnym rogu.

W jaki sposób odwołać się do pamięci?

Służy do tego instrukcja Mem. Użycie jej wygląda następująco:

Mem[Adres:Offset]

Jeśli offset ustawimy na 0 to będziemy mogli otrzmać informacje o pierwszym bajcie z danego adresu, offset 1 to drugi bajt, itd. Można powiedzieć, że Mem to tablica (pamiętaj o prostokątnych nawiasach!), a więc można zarówno odczytywać informacje jak i te informacje wproawdzać:

A := Mem[$B800:1];
Mem[$B800:6] := 7;

Zapis $B800

Mała dygresja na temat zapisu $B800 gdyż być może nie dla wszystich jest to jasne. W Pascalu przyjęte jest, że liczby w kodzie szesnastkowym zapisujemy ze znakiem dolara na początku, zatem zapis Mem[B800:1] jest niepoprawny! Należy zawsze pamiętać o znaku dolara jeśli zapisujemy liczby szesnastkowo!

Jedyne o czym jeszcze należy wspomnieć to, że najpierw zapisywany jest znak, a potem opis koloru zatem:

Mem[$B800:0] - znak na pozycji (1,1) - lewy górny róg ekranu,
Mem[$B800:1] - kolor znaki na pozycji (1,1),
Mem[$B800:2] - znak na pozycji (2,1),
...
Mem[$B800:160] - znak na pozycji (1,2)

Dla ułatwienia możemy skorzystać z takich wzorów:

Mem[$B800:160*(y-1)+2*(x-1)] - do ustawiania znaków na pozycji (x,y),
Mem[$B800:160*(y-1)+2*(x-1)+1] - do ustawiania kolorów na pozycji (x,y),
Pamiętajmy, że lewy górny róg ma pozycję (1,1), a nie (0,0)!

Właściwie wszystkie informacje już mamy, teraz spróbuję przedstawić to ze strony bardziej praktycznej.

Wróćmy to przykładu z początku tekstu. Spróbujemy wstawić literę "A" (koloru żółtego, na niebieskim tle) w pozycji (10,10). Najpierw, korzystając ze wzroru wrzucamy literkę na odpowiednią pozycję:

Mem[$B800:160*(10-1)+2*(10-1)] := ord('A');

Zwracam tu uwagę na zapis ord('A'), który zwraca kod znaku podanego jako argument. Do pamięci wrzucamy bajty, nie znaki! Zatem zapis Mem[...] := 'A' NIE JEST poprawny - trzeba skorzystać z procedury ord().

A teraz ustawimy kolor

Żółty ma kod 14, binarnie 1110.
Niebieski to kod 1, czyli binarnie 001
Miganie ustawiamy tym razem na aktywne czyli 1

Teraz sklejamy to wszystko razem i wychodzi: 10011110 czyli 158 dziesiętne i taką wartość wstawiamy:

Mem[$B800:160*(10-1)+2*(10-1)+1] := 158;

Po tych instrukcjach na ekranie pojawi się na pozycji (10,10) migająca, wielka litera "A". Należy pamiętać jednak, że litery będą migać tylko trybie pełnego ekranu.

A teraz spróbujmy napisać procedury, które ułatwią nam pracę:

Procedura wstawiająca znak na danej pozycji

Procedure UstawZnak(Znak :Char; X, Y :Byte);
Begin
Mem[$B800:160*(Y-1)+2*(X-1)] := ord(Znak);
End;

Ustawienie kolorów na danej pozycji

Procedure UstawKolory(KolorTekstu, KolorTla, X, Y :Byte);
Begin
Mem[$B800:160*(Y-1)+2*(X-1)+1] := KOlorTekstu + 16 * KolorTla;
End;

Funkcja odczytujaca znak na danej pozycji

Function CzytajZnak(X, Y :Byte) :Char;
Begin
CzytajZnak := Chr(Mem[$B800:160*(Y-1)+2*(X-1)]);
End;

I na koniec procedura do odczytania kolorów z danej pozycji (dwa pierwsze argumenty to zmienne!)

Procedure CzytajKolory(var KolorTekstu, KolorTla :Byte; X, Y :Byte);
Var
    Tmp :Byte;
Begin
Tmp := Mem[$B800:160*(Y-1)+2*(X-1)+1];
KolorTekstu := Tmp mod 16;
KolorTla := Tmp shr 4;
End;

Wszystkie te procedury znajdują się w pliku ekran.pas.
Dołączam także dwa proste efekty - blink.pas i lustro.pas.

Dodał: ifrost​, www
Dział: Pascal


 

ComputerSun.pl na FaceBooku
Polecamy lekturę:

Fotografia cyfrowa. Pierwsza pomoc



X

Zapisz się na biuletyn serwisu ComputerSun.pl, aby otrzymać poradnik:

Zabezpieczanie sieci bezprzewodowych. Przydatne wskazówki jak chronić sieć domową przed intruzami

Imię:  
Email:
Tak, akceptuję Politykę Prywatności