background image

Zad 1

mamy 2 funkcje obsługi przerwań: recv() i disp(). Pierwsza wywoływana w chwili skończenia 
odbierania pakietu, druga w chwili skończenia jego przetwarzania. Mamy napisać je w ten sposób 
żeby wyłączyć obsługę przerwań jeśli odebrano i nie przetworzono więcej niż 16 pakietów. Oraz 
mamy ustawiać flagę „zero” za każdym razem jak odebrano nieparzysty pakiet (jeśli przerwanie nie 
jest zamaskowane).

a)

idea jest taka, że tworzymy zmienną zliczającą nasze pakiety odebrane i nie przetworzone. Powinna 
ona być inkrementowana za każdym razem jak pakiet odbierzemy, a dekrementowana jeśli go 
przetworzyliśmy. Następnie trzeba tylko wstawić warunek sprawdzający czy licznik przekroczył 
wartość 16 a w nim ustawienie flagi rejestru maskującą przerwania. Z tego co pamiętam był to 7 bit 
(od zera licząc, flaga „IRQ disable”) 0x80. 

Int liczba_pakietow = 0; 
void recv()
{

liczba_pakietow = liczba_pakietow + 1;
if(liczba_pakietow > 16) 
{

CMSR = CMSR | 0x80; // ustawia 7 bit

}

}

void disp()
{

liczba_pakietow = liczba_pakietow – 1;

}

i tyle :D

b)

tutaj potrzebujemy zmiennej zliczającej wszystkie pakiety odebrane. Potem, jeśli nie zamaskowano 
w międzyczasie przerwania, sprawdzamy czy jest to pakiet nieparzysty, i jeśli jest ustawiamy flagę 
zero (bit 30. CMSR) a jeśli jest parzysty to ją 
zerujemy. 

Int liczba_pakietow = 0; 
int wszystkie = 0;
void recv()
{

wszystkie = wszystkie + 1;
liczba_pakietow = liczba_pakietow + 1;
if(liczba_pakietow > 16) 
{

CMSR = CMSR | 0x80; // ustawia 7 bit

} else if(wszystkie % 2 == 1)
{

CMSR = CMSR | (1<<30);

background image

} else {

CMSR = CMSR & (~(1<<30));

}

}

void disp()
{

liczba_pakietow = liczba_pakietow – 1;

}

krótki komentarz dla tych co operacji logicznych w C nie pamiętają: 
„zmienna = zmienna | (1<<x)” => ustawienie x-tego bitu zmiennej 
„zmienna = zmienna & (~(1<<x))” => zerowanie x-tego bitu zmiennej
warunek Liczba % 2 == 1 sprawdza czy liczba jest nie parzysta jak by ktoś nie wiedział to to jest 
dzielenie modulo ;)

Zad 2.

Mamy dany mniej więcej taki kod asemblera, z wartościami rejestrów po każdej instrukcji:

mov ax, 0x1AF4 

; ax = 0x1AF4, bx = ???, cx = ???

mov bx, 8

; ax = 0x1AF4, bx = 8, cx = ???

xor cx

; ax = 0x1AF4, bx = 8, cx = 0

push bx
push ax
push cx
add ax, 0xFF

; ax = 0x1BF5, bx = 8, cx = 0

or cx, 0x10

; ax = 0x1BF5, bx = 8, cx = 0x10

mul ax, cx

; ax = 0xBF50, bx = 8, cx = 0x10

add cx, bx

; ax = 0xBF50, bx = 8, cx = 0x10

pop bx
pop ax
pop cx
and ax, 0

; ax = 0, bx = 0, cx = 8

co najmniej jednej instrukcji nie pamiętam bo było 9 z uzupełnieniem wartości rejestrów, chyba że 
na push/pop było.

Stos po 8 instrukcji:

???

->SP

0

0x1AF4

8

???
???
???

??? = wartość niezdefiniowana.

background image

Zad 3

baudrate = 19200
data = 8
2 bity stopu
kontrola parzystości ODD

prędkość transmisji w bajtach na sekundę : prawdopodobnie 200 :p
bo: (baudrate/wielkosc_ramki)/8
wielkość ramki to 12 bitów : bit startu, 8 bitów danych, bit parzystości, 2 bity stopu (tak chyba 
miała być narysowana ta ramka)
czyli 19200/12 = 1600, a że wynik w bajtach ma być to jeszcze 1600/8 = 200 B/s

mamy rejestr SSR którego 7 bit oznacza gotowość wysłania danych, i rejestr bufora nadajnika TDR.
Programik ma wysyłać 8 bajtów z tablicy buf[] oraz liczyć ich sumę kontrolną i potem ją też 
wysłać.

Void fun()
{

for(int i = 0; i < 8; i++)
{

while(!(SSR&0x80));
TDR = buf[i];

}
for(int i = 0; i < 8; i++)
{

suma = suma + buf[i];

}
suma = ~suma + 1;
TDR = suma;

}
to prawdopodobnie jest trochę naciągana wersja ale powinno być za to sporo punktów :D

Zad 4.

łączymy to tak:
generator->wejscie CLK pierwszego timera
wyjście pierwszego timera -> wejście CLK drugiego
i na wyjściu drugiego mamy mieć 8Hz przy generatorze 5.242880 MHz
timery pracują jako zliczacze więc sygnał na wyjścia generowany jest po przepełnieniu rejestru 
OCR , który jest dekrementowany z każdym taktem wejścia CLK. Z tego wynika, że potrzebujemy 
zliczyć do 5242880/8 = N taktów
N = 655360, jest większe niż 2^16=65536 stąd to połączenie w kaskadę.
Czyli reasumując nasz pierwszy timer liczy do swojego maksimum czyli 65536 i na jego wyjściu 
jest 80 Hz, które biegnie jako taktowarka do drugiego licznika, który musi zliczyć do 10 żeby na 
jego wyjściu było 8 Hz. Innymi słowy te timery pracują jak dzielniki częstotliwości podanej na 
CLK gdzie dzielnik = OCR 
odp :
OCR1 = 65536 OCR2 = 10

teraz jeśli wiemy że timer 2 pracuje z częstotliwością 8 Hz, i że za każdym jego taktem 
wywoływana jest procedura obsługi przerwania timer2() to żeby wywołać funkcję KeyCheck() co 

background image

125 ms, wystarczy jej wywołanie tam wpisać, bo 1/8 = 0.125 = 125ms. Co do LCDUpdate() 
wywoływanej co 500 ms, trzeba ją wywoływać w co czwartym takcie więc:

int cnt = 0;
void timer2()
{

KeyCheck();
if(cnt % 4 == 0)
{

LCDUpdate();

}
cnt = cnt + 1;

}

funkcja obsługi pierwszego przerwania nic nie musi robić :)

i to by było na tyle :D 
Jeśli ktoś uważa że coś z tego jest źle, to proszę mi nie psuć mi humoru przed końcem łikendu. A 
tak serio to zgłaszać wszelkie nieścisłości :)