Итак, двигаемся дальше. Буквы в терминале - хорошо, красивая картинка на экране - ещё лучше! Но хочется какого-то интерактива. И вот здесь не всё так просто, как хотелось бы. Но об этом чуть ниже. А пока предлагаю вам текст короткой программы, которая опрашивает клавиатуру и выводит в терминал код нажатой клавиши:
Код:
org 0x6001000
blx start
thumb
start:
; Опрашиваем клавиатуру
movw r0,0x6004 ; Keyboard Status Register
movt r0,0x1000
ldrb r1,[r0]
and r1,0x10
cmp r1,0x10
bne finish
movw r0,0x6008 ; Keyboard Data
movt r0,0x1000
ldrb r1,[r0]
and r1,0xff
; Преобразуем байт в ASCII-строку в HEX-представлении
adr r2,key_code+1
mov r3,2
mov r0,r1
hex_convert:
and r1,0xf
cmp r1,0xa
addcs r1,0x7
add r1,0x30
strb r1,[r2]
sub r2,1
lsr r1,r0,4
subs r3,1
bne hex_convert
; Выводим строку в консоль
movw r0,0x9000 ; Адрес консоли 0x10009000
movt r0,0x1000
ldrb r1,[key_code]
strb r1,[r0]
ldrb r1,[key_code+1]
strb r1,[r0]
ldrb r1,[key_code+2]
strb r1,[r0]
finish:
b start
key_code:
db "00 "
Результат работы программы:
В эмулируемом компьютере клавиатура подключена с помощью MMIO (Memory-mapped I/O) контроллера PL050, порты которого смотрят прямо в память, а базовым является адрес 0x10006000:
Address |
Type |
Description |
Base + 0x00 |
rw |
Control register. |
Base + 0x04 |
r |
Status register. |
Base + 0x08 |
rw |
Received data (read)/ Data to be transmitted (write). |
Base + 0x0c |
rw |
Clock divisor register. |
Base + 0x10 |
r |
Interrupt status register. |
А это значения битов статусного регистра:
Bits |
Name |
Description |
0 |
KMID |
This bit reflects the status of the KMIDATAIN line after synchronizing. |
1 |
KMIC |
This bit reflects the status of the KMICLKIN line after synchronizing and sampling. |
2 |
RXPARITY |
This bit reflects the parity bit for the last received data byte (odd parity). |
3 |
RXBUSY |
This bit indicates that the PrimeCell KMI is currently receiving data. 0 = idle, 1 = receiving data. |
4 |
RXFULL |
This bit indicates that the receiver register is full and ready to be read. 0 = receive register empty, 1 = receive register full, ready to be read. |
5 |
TXBUSY |
This bit indicates that the PrimeCell KMI is currently sending data. 0 = idle, 1 = currently sending data. |
6 |
TXEMPTY |
This bit indicates that the transmit register is empty and ready to transmit. 0 = transmit register full, 1 = transmit register empty, ready to be written. |
7 |
- |
Reserved. Read unpredictable. |
Здесь используется стандартный набор 2 скан-кодов AT-клавиатуры:
PS/2 keyboard scan codes (scan code set 2)
KEY |
MAKE |
BREAK |
----- |
KEY |
MAKE |
BREAK |
----- |
KEY |
MAKE |
BREAK |
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 WIN |
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 WIN |
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,77,
E1,F0,14,
F0,77 |
-NONE- |
|
|
|
|
[свернуть]
То есть каждая клавиша имеет скан-коды для нажатия (make) и для отпускания (break). Так, при нажатии клавиши "A" мы получаем скан-код 0x1C, и продолжаем получать его вплоть до отпускания клавиши. А в момент отпускания генерируется двухбайтный скан-код 0xF0, 0x1C.
Теперь для тренировки вы можете попробовать подправить программу таким образом, чтобы она выводила не скан-код клавиши, а непосредственно её значение.