background image

http://www.easy-soft.tsnet.pl/

Podłączenie klawiatury PC do

mikrokontrolera

AT89S8252.

Do jednego z projektowanych urządzeń potrzebowałem klawiatury afanumerycznej. Mój wybór

padł na zwykłą klawiaturę do komputera PC z dwóch prostych powodów: dostępność i cena. Do

pełni zadowolenia wystarczyło dołączyć klawiaturę do mojego urządzenia i po prostu używać. I

to pojawił się pewien kłopot...

Chciałem skorzystać z jakiejś gotowej aplikacji, jednak 2 kompletne które udało mi się znaleźć

były   zupełnie   bezużyteczne.   Obie   ze   względu   na   użyty   język   programowania:   Bascom   i

mikrokontroler 8051 to nie najlepszy moim zdaniem pomysł a i o zmianie mikrokontrolera na

PIC nie mogło być mowy. Postanowiłem, wzorując się na obu rozwiązaniach, napisać program

w   języku   C,   dla   mikrokontrolera   AT89S8252.   Powstał   w   ten   sposób   driver   opisywany   w

niniejszym artykule.

Po skompilowaniu program zajmuje około 1,5kB pamięci ROM. Część procedur jest napisana w

języku asemblera, część w języku C. Oczywiście można wszystko napisać w C, jednak wiąże

się to z pewnymi (być może) utrudnieniami. Na przykład rozkazy przesunięć w języku C są

wykonywane w sposób zależny od typu użytej zmiennej. Odczyt danych z pinu procesora nie

był by więc tak prosty i szybki, jak w asemblerze. Oczywiście można całość napisać w C, ale

skoro w asemblerze można to zrobić wszystko nieco łatwiej a moduły w asemblerze można bez

problemu łączyć z językiem C, to dlaczego nie skorzystać z tej możliwości? 

W języku C jest „załatwiane” są przede wszystkim operacje, których implementacja zajmuje

mnóstwo czasu w asemblerze, czyli porównanie i rozpoznanie kodów, konwersja na ASCII i

tym podobne. W C wykonałem również driver do obsługi wyświetlacza LCD 4 linie x 20 znaków

w trybie 4 bity.

Większość   materiałów,   które   posłużyły   do   napisania   programu,   pochodzi   ze   strony   Adama

Chapweske. Strona dostępna jest pod adresem: 

http://govschl.ndsu.nodak.edu/~achapwes/

Interfejs elektryczny. Protokół komunikacyjny.

Napięcie zasilające zapewniane jest przez urządzenie, do którego dołączona jest klawiatura.

Większość   klawiatur   nie   pobiera   więcej,   niż   100   mA   prądu   przy   napięciu   zasilającym   5V.

Ogólna tendencja zmierza w kierunku obniżania poboru prądu przez klawiaturę.

Klawiatura   posiada   dwie   dwukierunkowe   linie   służące   do   transmisji   danych.   Obie   linie

interfejsu są typu otwarty kolektor lub  otwarty dren. W związku  z tym, patrząc od strony

urządzenia,  do którego dołączona jest klawiatura,  linia  jest  albo  zwierana  przez wyjściowy

tranzystor   do   masy,   albo   przechodzi   w   stan   wysokiej   impedancji.   W   związku   z   tym,   dla

zachowania   poprawności   stanów   logicznych,   konieczne   jest   użycie   po   stronie   urządzenia

rezystorów zasilających (tzw. pull-up) o wartości od 1 do 10kΩ.

Dane przesyłane są dwukierunkowo, do i z klawiatury, w rytm zmian sygnału zegarowego CLK.

Przed każdym opadającym zboczem sygnału zegarowego ustalony musi być stan linii danych.

Linia   zegara   służy   również   do   swego   rodzaju   arbitrażu.   Klawiatura   (identyczny   rodzaj

interfejsu posiada myszka!) po ustawieniu stanu wysokiego sprawdza, czy stan linii zegara nie

zmienia się na niski przez czas 50 mikrosekund. Jesli nie, to przesyłane są dane. Jeśli tak,

- strona 1/14 -

background image

http://www.easy-soft.tsnet.pl/

kontroler   klawiatury   oczekuje   na   zakończenie   transmisji.   W   związku   z   tym  host  może   w

dowolnym momencie zablokować lub wstrzymać transmisję utrzymując stan niski linii zegara

przez czas co najmniej 100 mikrosekund.

Częstotliwość sygnału zegarowego waha się w granicach od 10 do 16,7kHz. Czas pomiędzy

ustaleniem się danych a opadającym zboczem sygnału zegarowego powinien być nie mniejszy,

niż 5 mikrosekund.

Na rysunku 1 przedstawiono wygląd ramki transmisji. Jako pierwszy przesyłany jest bit startu,

który zawsze jest równy 0. Za nim następuje 8 bitów danych oraz 1 bit parzystości (ustawiony,

gdy liczba 1 w słowie jest parzysta, parzystość typu odd), 1 bit stopu (zawsze równy 1) i bit

potwierdzenia odbioru.

Rysunek 1. Ramka transmisji danych przesyłanych z klawiatury

Sygnał zegarowy zawsze generowany jest przez klawiaturę. Nie stwarza to żadnego problemu,

jeśli to klawiatura przesyła dane. Jednak na początku tego tekstu wspomniałem, że obie linie

są dwukierunkowe, przez co można wysnuć wniosek, że również  klawiatura może odbierać

dane od urządzenia hosta. W jaki sposób?

Jeśli urządzenie host chce przesłać dane, to wysyła specjalną sekwencję nazwaną Request to

Send. Wygląda ona następująco:

host utrzymuje stan niski linii zegarowej przez czas co najmniej 100 mikrosekund,

wysyła polecenie  Request to Send  ustawiając stan niski linii danych i zmieniając stan linii
zegara na wysoki.

Po   odebraniu   żądania   przesłania   danych,   klawiatura   utrzymując   stan   wysoki   linii   danych,

generuje sygnał zegarowy. W tak zmian tego sygnału, ustawiając właściwy stan linii danych,

gdy linia zegarowa ma stan niski,  host przesyła dane do klawiatury. Po odebraniu bitu stopu

kontroler klawiatury potwierdza fakt odbioru słowa danych ustawiając stan niski linii danych.

Rysunek 2. Ramka transmisji danych przesyłanych do klawiatury

- strona 2/14 -

background image

http://www.easy-soft.tsnet.pl/

Rysunek 3. Szczegóły transmisji danych z hosta do klawiatury (również myszki)

Skoro   klawiatura   odbiera   dane,   jakie   rozkazy   mogą   być   realizowane?   Oczywiście   oprócz

oczywistych, to jest zaświecania diod sygnalizacyjnych Num Lock, Caps Lock i Scroll Lock.

0xFF (Reset) – Klawiatura odpowiada kodem "ACK" (0xFA), a następnie realizuje polecenie
restartu ustawiając nastawy domyślne i zerując bufor.

0xFE (Resend) – Klawiatura odpowiada kodem ostatnio przesłanego znaku.

0xFD (Set Key Type Make*) - Wyłącza przesyłania kodów break. 

0xFC (Set Key Type Make/Break*) - Zbliżona w działaniu do poprzedniej komendy, jednak
wyłączane jest automatyczne powtarzanie wciśniętego klawisza.

0xFB (Set Key Type Typematic*) - Wyłącza wyłącznie kod Break.

0xFA   (Set   All   Keys   Typematic/Make/Break*)   –   Klawiatura   odpowiada   za   pomocą   ACK
ustawiając   domyślne   wartości   nastaw   dla  make,   break  i  automatycznego   powtarzania

klawisza.

0xF9 (Set All Keys Make*) - Klawiatura odpowiada wysyłając ACK. Działanie zbliżone do
0xFD z tym, że nastawa dotyczy wszystkich klawiszy.

0xF8 (Set All Keys Make/Break*) - Działanie zbliżone do 0xFC z uwagami j.w.

0xF7 (Set All Keys Typematic*) - Działanie zbliżone do 0xFB z uwagami j.w.

0xF6 (Set Default) – Przywrócenie nastaw  domyślnych (10.9cps / 500ms,  make/break),
zestaw scan code numer 2.

0xF5   (Disable)   –   Kontroler   klawiatury   przerywa   przeglądanie   klawiszy,   ładuje   nastawy
domyślne i oczekuje na następne polecenia.

0xF4 (Enable) – Przywraca normalne funkcjonowanie klawiatury po 0xF5.

0xF3 (Set Typematic Rate/Delay) – Nastawa czasu powtarzania i opóźnienia.

0xF2 (Read ID*) – Odczyt ID klawiatury; oryginalna klawiatura PS2 wysyła liczby 0xAB,
0x83. 

0xF0 (Set Scan Code Set*) -  Nastawa zestawu kodów skanowania. 

0xEE (Echo) – Klawiatura odpowiada wysyłając 0xEE.

0xED (Set/Reset LEDs) – Zaświecenie, gaszenie diod LED. Można znaleźć w przykładowym
programie z tego artykułu.

Każdy klawisz generuje dwa kody. Jeden z nich nazywany jest kodem  make  i wysyłany jest

przez   klawiaturę   po   wciśnięciu   klawisza,   poprzedzając   właściwy   numer   klawisza.   Drugi

nazywany jest  break i wysyłany jest po zwolnieniu klawisza. Po nim ponownie wysyłany jest

- strona 3/14 -

background image

http://www.easy-soft.tsnet.pl/

numer   klawisza.   W   tabeli   1,   2   i   3   zebrano   kody   wysyłane   przez   nowoczesne   klawiatury

mutlimedialne.   Starsze   modele   klawiatur   różnią   się   tym,   że   nie   przesyłają   kodów

rozszerzonych – podstawowe zostają takie same.

Implementacja. Wykonanie układu.

Na   rysunku   4   znajduje   się   układ   połączeń   konieczny   do   przetestowania   aplikacji   z   tego

artykułu.   Całość   zmontowana   była   z   użyciem   płytki   testowej   (opisywanej   na   stronie),

wyświetlacza LCD 4x20 i dwóch rezystorów zasilających. Używałem klawiatury ze złączem PS2.

Rysunek 4. Schemat aplikacji z artykułu.

Zadaniem aplikacji jest wyświetlenie odebranych kodów i zamiana ich na znaki ASCII. Jest to

prosty przykład programowania,  który można wykorzystać we własnej aplikacji  w dowolny,

ograniczony praktycznie tylko inwencją, sposób. Program zawiera liczne komentarze tak, że

uzbrojony w podstawy wiedzy Czytelnik nie powinien mieć problemu z analizą.

Po   skompilowaniu   program   zajmuje   około   1,5kB   w   pamięci.   W   związku   z   tym   bez   trudu

pomieści  go  również  malutki  AT89C2051.  Nie  bez  znaczenia  jest   również  fakt,  że  do   jego

kompilacji można użyć wersji demonstracyjnej pakietu Raisonance, której kompilator języka C

generuje kod do 4kB.

Jacek Bogusz

jacek.bogusz@easy-soft.tsnet.pl

- strona 4/14 -

background image

http://www.easy-soft.tsnet.pl/

KLA-

WISZ

WCIŚ-
NIĘTY

ZWOL-

NIONY

---

KLA-

WISZ

WCIŚ-
NIĘTY

ZWOL-

NIONY

---

KLA-

WISZ

WCIŚ-
NIĘTY

ZWOL-

NIONY

A

1C

F0,1C

9

46

F0,46

[

54

FO,54

B

32

F0,32

`

0E

F0,0E

INSERT

E0,70

E0,F0,70

C

21

F0,21

-

4E

F0,4E

HOME

E0,6C

E0,F0,6C

D

23

F0,23

=

55

FO,55

PG UP

E0,7D

E0,F0,7D

E

24

F0,24

\

5D

F0,5D

DELETE

E0,71

E0,F0,71

F

2B

F0,2B

BKSP

66

F0,66

END

E0,69

E0,F0,69

G

34

F0,34

SPACE

29

F0,29

PG DN

E0,7A

E0,F0,7A

H

33

F0,33

TAB

0D

F0,0D

U ARROW

E0,75

E0,F0,75

I

43

F0,43

CAPS

58

F0,58

L ARROW

E0,6B

E0,F0,6B

J

3B

F0,3B

L SHFT

12

FO,12

D ARROW

E0,72

E0,F0,72

K

42

F0,42

L CTRL

14

FO,14

R ARROW

E0,74

E0,F0,74

L

4B

F0,4B

L GUI

E0,1F

E0,F0,1F

NUM

77

F0,77

M

3A

F0,3A

L ALT

11

F0,11

KP /

E0,4A

E0,F0,4A

N

31

F0,31

R SHFT

59

F0,59

KP *

7C

F0,7C

O

44

F0,44

R CTRL

E0,14

E0,F0,14

KP -

7B

F0,7B

P

4D

F0,4D

R GUI

E0,27

E0,F0,27

KP +

79

F0,79

Q

15

F0,15

R ALT

E0,11

E0,F0,11

KP EN

E0,5A

E0,F0,5A

R

2D

F0,2D

APPS

E0,2F

E0,F0,2F

KP .

71

F0,71

S

1B

F0,1B

ENTER

5A

F0,5A

KP 0

70

F0,70

T

2C

F0,2C

ESC

76

F0,76

KP 1

69

F0,69

U

3C

F0,3C

F1

05

F0,05

KP 2

72

F0,72

V

2A

F0,2A

F2

06

F0,06

KP 3

7A

F0,7A

W

1D

F0,1D

F3

04

F0,04

KP 4

6B

F0,6B

X

22

F0,22

F4

0C

F0,0C

KP 5

73

F0,73

Y

35

F0,35

F5

03

F0,03

KP 6

74

F0,74

Z

1A

F0,1A

F6

0B

F0,0B

KP 7

6C

F0,6C

0

45

F0,45

F7

83

F0,83

KP 8

75

F0,75

1

16

F0,16

F8

0A

F0,0A

KP 9

7D

F0,7D

2

1E

F0,1E

F9

01

F0,01

]

5B

F0,5B

3

26

F0,26

F10

09

F0,09

;

4C

F0,4C

4

25

F0,25

F11

78

F0,78

'

52

F0,52

5

2E

F0,2E

F12

07

F0,07

,

41

F0,41

6

36

F0,36

PRNT

SCRN

E0,12,

E0,7C

E0,F0,

7C,E0,

F0,12

.

49

F0,49

7

3D

F0,3D

SCROLL

7E

F0,7E

/

4A

F0,4A

8

3E

F0,3E

PAUSE

E1,14,7, 

E1,F0,1,

F0,77

-NONE-

Tabela 1. Wykaz kodów generowanych przez klawiaturę. Tabela zawiera liczby szesnastkowe. Jak łatwo

zauważyć, wciśnięcie niektórych klawiszy powoduje wysłanie nawet do 8 liczb!

- strona 5/14 -

background image

http://www.easy-soft.tsnet.pl/

Key

Make Code

Break Code

Power

E0, 37

E0, F0, 37

Sleep

E0, 3F

E0, F0, 3F

Wake

E0, 5E

E0, F0, 5E

Tabela 2. Kody generowane dla systemu zarządzania zasilaniem komputera PC.

Key

Make Code

Break Code

Next Track

E0, 4D

E0, F0, 4D 

Previous Track

E0, 15

E0, F0, 15

Stop

E0, 3B

E0, F0, 3B

Play/Pause

E0, 34

E0, F0, 34

Mute

E0, 23

E0, F0, 23

Volume Up

E0, 32

E0, F0, 32

Volume Down

E0, 21

E0, F0, 21

Media Select

E0, 50

E0, F0, 50

E-Mail

E0, 48

E0, F0, 48

Calculator

E0, 2B

E0, F0, 2B

My Computer

E0, 40

E0, F0, 40

WWW Search

E0, 10

E0, F0, 10

WWW Home

E0, 3A

E0, F0, 3A

WWW Back

E0, 38

E0, F0, 38

WWW Forward

E0, 30

E0, F0, 30

WWW Stop

E0, 28

E0, F0, 28

WWW Refresh

E0, 20

E0, F0, 20

WWW Favorites

E0, 18

E0, F0, 18

Tabela 3. Kody generowane dla aplikacji multimedialnych.

- strona 6/14 -

background image

http://www.easy-soft.tsnet.pl/

/***********************************
 Odczyt klawiatury PC
 (C) easy-soft 04/2002
 ***********************************
 RAISONANCE RC-51
 ***********************************/

#pragma

 SMALL

#include

 <reg51.h>

//port wy wietlacza LCD

ś

#define 

PORT P2

//bity steruj ce LCD

ą

sbit LcdEnable = PORT^0;
sbit LcdRead = PORT^3;
sbit LcdReg = PORT^1;

//definicje znaków specjalnych dla wyœwietlacza LCD

char

 code CGRom[65] = {

0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,

// "kratka" 0x00

0xC0,0xC0,0xFF,0xF1,0xF1,0xF1,0xFF,0xC0,

// pusty kwadrat 0x01

0xC0,0xC0,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,

// kwadrat zacz.0x02

0xE0,0xFF,0xFF,0xFF,0xE0,0xE0,0xE0,0xE0,

// linia 0x03

0xFF,0xFF,0xF9,0xF3,0xE7,0xF3,0xF9,0xFF,

// znak w lewo 0x04

0xFF,0xFF,0xF3,0xF9,0xFC,0xF9,0xF3,0xFF,

// znak w prawo 0x05

0xFF,0xFF,0xFB,0xF1,0xE4,0xEE,0xFF,0xFF,

// znak w górê 0x06

0xFF,0xFF,0xFF,0xEE,0xE4,0xF1,0xFB,0xFF,

// znak w dó  0x07

ł

0x00};

//bity statusu

bit Alt, Caps, Ctrl, CapsLock, Extended, Pause;

//status.0 = Scroll Lock, status.1=NumLock, status.2=CapsLock

char

 status = 0x02;

//linie danych klawiatury

sbit KbdData = P0^1;
sbit KbdClock = P0^0;

//bufor wci ni tego klawisza

ś

ę

char

 key;

//zmienne przeznaczone do ró nych operacji

ż

char

 temp, temp1;

//funkcje zewn trzne w j zyku asembler

ę

ę

//wys anie bajtu do klawiatury

ł

extern

 

void

 TX_byte(

char

 x);

//odbiór bajtu z klawiatury

extern

 

char

 RX_byte(

void

);

//opó nienie oko o  1 milisekundy dla 7,3728MHz

ź

ł

void

 Delay (

unsigned

 

int

 k) 

{

unsigned

 

int

 i,j;

for

 (j = 0; j < k; j++)

for

 (i = 0; i <= 296; i++);

}

void

 WriteByteToLcd(

char

 X)

{

char

 temp = X;

 

//przy wej ciu do procedury temp przyjmuje warto

 param.X

ś

ść

P2 |= 0xF0;

 

//ustawienie górnej po³ówki portu P2 na "1"

P2 &= (temp | 0x0F); 

//"bezkolizyjny" zapis 1-szej po³ówki bajtu 

 //(przez funkcj  logiczn )

ę

ą

LcdEnable = 0;

 

//zapis do wy wietlacza (opadaj ce zbocze sygna u  E)

ś

ą

ł

LcdEnable = 1;

//zapis 2-giej po ówki bajtu

ł

- strona 7/14 -

background image

http://www.easy-soft.tsnet.pl/

temp <<= 4;

//przesuni cie 4x w lewo

ę

temp |= 0x0F;

//maskowanie 4 m³odszych bitów

P2 |= 0xF0;

//ustawienie górnej po ówki portu P2 na "1"

ł

P2 &= temp;

//zapis 2-giej po ówki bajtu

ł

LcdEnable = 0;

//opadaj ce zbocze E - zapis do LCD

ą

Delay(1);

}

// zapis bajtu do rejestru kontrolnego LCD

void

 WriteToLcdCtrlRegister(

char

 X)

{

LcdReg = 0;

//ustawienie sygna ów  steruj cych

ł

ą

LcdRead = 0;
LcdEnable = 1;
WriteByteToLcd(X);

}

// write a unsigned character to lcd screen

void

 LcdWrite(

char

 X)

{

LcdReg = 1;
LcdRead = 0;
LcdEnable = 1;
WriteByteToLcd(X);

}

//czyszczenie ekranu LCD

void

 LcdClrScr(

void

)

{

WriteToLcdCtrlRegister(0x01);

}

//inicjalizacja wy wietlacza LCD w trybie 4 bity

ś

void

 LcdInitialize(

void

)

{

char

 i;

Delay(15);
P0 = 0x0F;

//wyzerowanie linii LcdReg,LcdRead,LcdEnable

for

 (i = 0; i<3; i++)

{

LcdEnable = 1;

//impuls na E

PORT &= 0x3F;

//ustawienie wart.inicjuj cej

ą

LcdEnable = 0;
Delay(5);

}
LcdEnable = 1;

//wpisanie warto ci 2 do rej.kontr.

ś

PORT &= 0x2F;

//tylko "górne" 4 bity

LcdEnable = 0;
Delay(1);
WriteToLcdCtrlRegister(0x28);

//interfejs 4 bity,znaki 5x7

WriteToLcdCtrlRegister(0x08);

//wy

czenie LCD

łą

WriteToLcdCtrlRegister(0x01);

//kasowanie ekranu,powrót do home

WriteToLcdCtrlRegister(0x06);

//przesuwanie kursora z inkrement.

WriteToLcdCtrlRegister(0x0C);

//za

czenie wyœwietlacza

łą

}

//ustawia kursor na wspó rz dnych x,y

ł

ę

void

 GotoXY(

char

 x, 

char

 y)

{

switch

 (y)

//obliczenie o ile nale y  zwi kszy  x w 

ż

ę

ć

//zale no ci  od warto ci y 

ż

ś

ś

{

case

 0:

- strona 8/14 -

background image

http://www.easy-soft.tsnet.pl/

x += 0x80;

//x = x + 0x80

break

;

case

 1:

x += 0xC0;

//x = x + 0xC0

break

;

case

 2:

x += 0x94;

//x = x + 0x94

break

;

case

 3:

x += 0xD4;

//x = x + 0xD4

break

;

}
WriteToLcdCtrlRegister(x);

}

//wy wietla tekst na wspó rz dnych x, y

ś

ł

ę

void

 WriteTextXY(

char

 x, 

char

 y, 

char

 *S)

{

while

 (*S)

//p tla dzia a  dot d,a  napotkany zostanie znak 

ż

ę

ł

ą

//ko ca  a cucha (/0)

ń

ł ń

{

GotoXY(x, y);

//wyliczenie adresu dla znaku

LcdWrite(*S);

//wy wietlenie pojedynczego znaku

ś

x++; 

//nast pna pozycja x na ekranie

ę

S++;

//nast pna pozycja wska nika,tzn.nast pny znak 

ę

ź

ę

//napisu

if

 (x > 19)

// je li x>19 to nast pna linia

ś

ę

{

x = 0; 
y++;

}

}

}

//wy wietla tekst na wspó rz dnych x, y

ś

ł

ę

void

 WriteText(

char

 *S)

{

while

 (*S)

//p tla dzia a  dot d,a  napotkany zostanie znak 

ż

ę

ł

ą

//ko ca  a cucha (/0)

ń

ł ń

{

LcdWrite(*S);

// wy wietlenie pojedynczego znaku

ś

S++;

}

}

//definiowanie znaków z tablicy CGRom

void

 DefineSpecialCharacters(

void

)

{

char

 *ptr = &CGRom;

//ptr wskazuje na tablic  CGRom

ę

WriteToLcdCtrlRegister(0x40);

//ustawienie trybu definicji

while

 (*ptr != 0)

//p tla wykonywana do napotkania znaku ko ca tablicy

ę

ń

{

LcdWrite(*ptr);

//zapis znaku do lcd cgram

ptr++;

//nast pna pozycja tablicy (wska nika)

ę

ź

}
WriteToLcdCtrlRegister(0x80);

//prze

czenie do trybu wy wietlania

łą

ś

}

//ustawienie statusu klawiatury
//x.0-scroll lock, x.1-num lock, x.2-caps lock

void

 Kbd_status(

char

 x)

{

TX_byte(0xED);

- strona 9/14 -

background image

http://www.easy-soft.tsnet.pl/

RX_byte();
TX_byte(x);
RX_byte();

}

//konwersja bajtu na warto

 hex,wy wietlenie na LCD

ść

ś

//przyk ad  procedury do interpratacji znaków odebranych z klawiatury

ł

char

 Hex2Ascii(

char

 x)

{

if

 (x < 10) x += 0x30; 

else

 x += 0x37;

return

(x);

}

//wy wietlenie szesnastkowego kodu klawisza

ś

void

 WriteKeyCode(

char

 x)

{

if

 (x != 0)

{

WriteTextXY(0,1,"k.code:");

if

 (Extended) WriteText("0xE0,");

WriteText("0x");
LcdWrite(Hex2Ascii(x / 16));
LcdWrite(Hex2Ascii(x % 16));
GotoXY(0,2);

if

 (Caps) WriteText("Shift ");

if

 (Ctrl) WriteText("Ctrl ");

if

 (Alt) WriteText("Alt");

if

 (Pause) WriteTextXY(0,3,"Paused "); 

else

 WriteTextXY(0,3,"       ");

else

{

WriteTextXY(7,1,"            ");
WriteTextXY(0,2,"                   ");

}

}

//program g ówny

ł

void

 main(

void

)

{

Delay(250);
LcdInitialize();
DefineSpecialCharacters();
LcdClrScr();

//reset klawiatury; klawiatura odpowiada wysy aj c  2 kody

ł

ą

TX_byte(0xFF);

//pierwszy z nich to 0xFA, drugi 0xAA

while

 (!(RX_byte() == 0xFA && RX_byte() == 0xAA));

//napis oznaczaj cy, e  inicjacja klawiatury by a  pomy lna

ż

ą

ł

ś

WriteTextXY(0,0,"Init OK! Welcome...");
WriteTextXY(0,1,"k.code:");

Kbd_status(status);

//za

czenie num lock

łą

while

 (1)

//g ówna p tla (niesko czona) programu

ł

ę

ń

{

key = RX_byte();

if

 (key == 0xE0)

//kody rozszerzone

{

//---------- 0xE0 ----------------------

key = RX_byte();

switch

 (key)

{

case

 0x14:

//R-Ctrl

- strona 10/14 -

background image

http://www.easy-soft.tsnet.pl/

Ctrl = 1;
key = 0;

break

;

case

 0x11:

//R-Alt

Alt = 1;
key = 0;

break

;

case

 0x1F:

//L-GUI

case

 0x27:

//R-GUI

case

 0x2F:

//Apps.

case

 0x70:

//Insert

case

 0x6C:

//Home

case

 0x7D:

//PgUp

case

 0x71:

//Delete

case

 0x69:

//End

case

 0x7A:

//PgDn

case

 0x75:

//Arrow Up

case

 0x6B:

//Arrow Left

case

 0x72:

//Arrow Down

case

 0x74:

//Arrow Right

case

 0x5A:

//Keypad-ENTER

case

 0x4A:

//Keypad-divide /

case

 0x37:

//Power

case

 0x3F:

//Sleep

case

 0x5E:

//Wake up

Extended = 1;

break

;

case

 0xF0:

//odebrano BREAK "rozszerzonego" klawisza

key = RX_byte();

//odbiór bajtu

if

 (key == 0x11) Alt = 0;

//R-Alt

else

 

if

 (key == 0x14) Ctrl = 0;

//R-Ctrl

key = 0;
Extended = 0;

break

;

//switch

//if (key == 0xE0)

//---------- default -------------------

else

 

if

 (key != 0xE0 && key != 0xF0 && key != 0xE1)

{

Extended = 0;

switch

 (key)

{

case

 0x12:

//L-Shift

case

 0x59:

//R-Shift

Caps = 1;
key = 0;

break

;

case

 0x58:

//Caps Lock

CapsLock = !CapsLock;
status ^= 0x04;
Kbd_status(status);
key = 0;

break

;

case

 0x14:

//L-Ctrl

Ctrl = 1;
key = 0;

break

;

case

 0x11:

//L-Alt

Alt = 1;
key = 0;

break

;

case

 0x77:

//Num Lock

- strona 11/14 -

background image

http://www.easy-soft.tsnet.pl/

status ^= 0x02;
Kbd_status(status);
key = 0;

break

;

case

 0x7E:

//Scroll Lock

status ^= 0x01;
Kbd_status(status);
key = 0;

break

;

//switch 

//else

//---------- pause ---------------------

else

 

if

 (key == 0xE1)

//klawisz Pause ma bardzo d ug  sekwencj  

ł

ą

ę

//i nie ma kodu BREAK

{

//0xE1 0x14 0x77 0xE1 0xF0 0x14 0xF0 0x77

RX_byte();
RX_byte();
RX_byte();
RX_byte();
RX_byte();
RX_byte();
RX_byte();
key = 0x77;
Pause = !Pause;

}

//---------- break ---------------------

if

 (key == 0xF0)

//odebrano BREAK "standardowego" klawisza

{

//wystarczy odebra  i kod zwolnionego klawisza

ć

key = RX_byte();

switch

 (key)

{

case

 0x12:

//L-Shift

case

 0x59:

//R-Shift

Caps = 0;

break

;

case

 0x14:

//L-Ctrl

Ctrl = 0;

break

;

case

 0x11:

//L-Alt

Alt = 0;

break

;

}
key = 0;

//if (key == 0xF0)

WriteKeyCode(key);

//while (1)

}

- strona 12/14 -

background image

http://www.easy-soft.tsnet.pl/

;---------------------------------
; modu  asemblera do pckeyb.c

ł

; odczyt/zapis klawiatury
;---------------------------------
; kompilator:RA-51 Raisonance
;---------------------------------

EQU

KbdData

P0.1

EQU

KbdClock

P0.0

pc_keyboard SEGMENT CODE
EXTRN DATA 
(temp)

;komórka "bufora" danych

EXTRN DATA (temp1)

; - / / -

EXTRN CODE (_Delay)
PUBLIC _TX_byte

;zapis bajtu do klawiatury

PUBLIC RX_byte

;odbiór bajtu

;--------------------------------
; program g ówny

ł

;--------------------------------
;

RSEG pc_keyboard
Low2High:

JNB

KbdClock,$

JB

KbdClock,$

RET

;wys anie bajtu do klawiatury, bajt przekazywany przez j zyk C w R7

ł

ę

_TX_byte:

MOV

B,#8

;liczba bitów do wys ania

ł

MOV

temp,R7

;zapami tanie parametru wywo ania

ę

ł

CLR

KbdClock

MOV

R7,#2

;opó nienie 2 ms

ź

MOV

R6,#0

CALL

_Delay

CLR

KbdData

;Request To Send

SETB

KbdClock

ACALL

Low2High

;oczekiwanie na potw.bit startu

MOV

A,temp

;odtworzenie zawarto ci A (tzn.znak do wysy ki)

ś

ł

TX_Loop:

RRC

A

;wys anie 8 bitów

ł

MOV

KbdData,C

ACALL

Low2High

DJNZ

B,TX_Loop

MOV

A,temp

;wys anie bitu parzysto ci

ł

ś

MOV

C,PSW.0

;(flaga PARITY)

CPL

C

MOV

KbdData,C

ACALL

Low2High

SETB

KbdData

;Stop Bit

ACALL

Low2High

ACALL

Low2High

;Keyboard Ack.

CLR

KbdClock

RET

;odczyt bajtu z klawiatury,bajt zwracany w R7

RX_byte:

SETB

KbdClock

JB

KbdClock,$

JNB

KbdData,RX_byte_Cont

SJMP

RX_byte_Error

RX_byte_Cont:

MOV

B,#8

;licznik odebranych bitów

RX_byte_Loop:

ACALL

Low2High

;odbiór 8 bitów

MOV

C,KbdData

RRC

A

DJNZ

B,RX_byte_Loop

MOV

temp,A

;zapami tanie odebranego znaku

ę

ACALL

Low2High

- strona 13/14 -

background image

http://www.easy-soft.tsnet.pl/

MOV

C,KbdData

;Parity Bit

RLC

A

ACALL

Low2High

MOV

C,KbdData

;Stop Bit

RLC

A

MOV

temp1,A

;zapami tanie bitu stopu i parzysto ci

ę

ś

ANL

A,#1

;sprawdzenie bitu stopu

JZ

RX_byte_Error

MOV

A,temp

;sprawdzenie parzysto ci (w temp odcz.liczba)

ś

MOV

C,PSW.0

;czy odczytana liczba ma parzyst  liczb  1?

ą

ę

RLC

A

ANL

A,#1

;maskowanie niepotrzebnych bitów

XCH

A,temp1

;zamiana miejscami odczytanego i wyliczonego 
;bitu parz.

ANL

A,#2

;maskowanie bitów

RR

A

;dopasowanie pozycji bitów

XRL

A,temp1

;porównanie bitów parzysto ci

ś

JZ

RX_byte_Error

SJMP

RX_byte_End

RX_byte_Error:

MOV

R7,#1

MOV

R6,#0

ACALL

_Delay

MOV

temp,#0

RX_byte_End:

MOV

R7,temp

CLR

KbdClock

RET

END

- strona 14/14 -