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 -
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 -
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 -
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 -
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 -
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
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -