Программа для управления кнопками блока ЭПС-103 (и управления моторами)
Замечательно иметь возможность написать любую надпись на дисплее. EPS-103 может сказать нам, что делает наша программа. Еще одно периферийное устройство, которое необходимо освоить, — это клавиатура. EPS-103 имеет в общей сложности 16 переключателей. Прежде всего, две большие кнопки Вверх и Вниз. Под открывающейся дверью мы находим кнопки от 0 до 9 и кнопку E. И трехпозиционный переключатель MODE, который фактически работает как три отдельных переключателя, один из которых всегда постоянно замкнут.
16 переключателей подключены к матрице 4 x 4 провода. Вход в матрицу подключен к порту А схемы 8255А, т.е. по адресу 5800h. Активна только нижняя половина порта. Старшие четыре бита по схеме не используются. Здесь будет возможность расширить клавиатуру дополнительными пользовательскими кнопками. Выход с матрицы направляется на порт В схемы 8255А, т.е. на адрес 5801h. Опять же, активны только младшие четыре бита. В верхней половине порта внутренние перемычки W1, W2 и W3 с маркировкой Test подключены в соответствии со схемой.
Пользоваться матричной клавиатурой довольно просто. На вход записывается двоичное число 1110 (1101, 1011, 0111), а затем на выходе считывается матрица. По его двоичному значению (1111, 1110, 1101, 1011, 0111) мы знаем, какой переключатель был активирован. Значение 1111 означает, что ни одна кнопка не нажата. В следующей таблице показаны значения каждого переключателя. Звездочка заменяет биты, не влияющие на работу клавиатуры. Программа обычно перезаписывает их всеми единицами.
Write Address 5800h |
Read Address 5801h |
Button EPS-103 |
MyCode | ||||
bin | hex | bin | hex | 4600h | 4601h | ||
Group 0 | 1111 1110 | 0FE | **** 1110 | 0*E | 1 | 01h | |
**** 1101 | 0*D | 2/E | 02h | ||||
**** 1011 | 0*B | 3/U | 03h | ||||
**** 0111 | 0*7 | 4/W | 04h | ||||
Group 1 | 1111 1101 | 0FD | **** 1110 | 0*E | 5 | 05h | |
**** 1101 | 0*D | 6 | 06h | ||||
**** 1011 | 0*B | 7 | 07h | ||||
**** 0111 | 0*7 | 8/D | 08h | ||||
Group 2 | 1111 1011 | 0FB | **** 1110 | 0*E | 9 | 09h | |
**** 1101 | 0*D | 0 | 0Ah | ||||
**** 1011 | 0*B | E | 0Bh | ||||
**** 0111 | 0*7 | Not used | - | - | |||
Group 3 | 1111 0111 | 0F7 | **** 1110 | 0*E | PRG | 10h | |
**** 1101 | 0*D | TCH | 20h | ||||
**** 1011 | 0*B | RUN + Up | 30h | 0Ch | |||
**** 0111 | 0*7 | RUN + Down | 30h | 0Dh |
Переключатель RUN подключен немного иначе, чем другие переключатели. Он последовательно с кнопками вверх и вниз. Это означает, что использование переключателя PRG или TCH отключает кнопки «Вверх» и «Вниз». Поэтому необходимо сначала идентифицировать эти три кнопки и кнопки «Вверх» и «Вниз» с ними в первом цикле. Только впоследствии во втором цикле сканируем остальные кнопки. После определения нажатой клавиши мы можем начать действие. Например, написать на дисплее, какая клавиша нажата.
Для работы этой программе потребуется оперативная память. Мы будем использовать пространство, выделенное под стек. Стек начинается с адреса 4700h и заполняется в сторону меньших значений. Вот почему я выбрал адреса с 4600h по 4603h. Они довольно близки к стеку, поэтому оригинальная прошивка определенно не использует их ни для чего другого. При этом они находятся достаточно далеко от начала стека, чтобы наша программа не перезаписывала их другими данными при использовании стека.
По адресу 4600h пишем код нажатой клавиши из тройки PRG, TCH, RUN. Если какая-то из оставшихся клавиш нажата, пишем ее код по адресу 4601h. Выводить название нажатой кнопки на дисплей имеет смысл только тогда, когда оно изменилось. Поэтому также используются управляющие адреса 4602h и 4603h. Копируем в них значения основных адресов 4600h и 4601h. Сравнив оригиналы и копии, мы можем увидеть, изменилось ли состояние клавиатуры.
Сканирование клавиатуры может быть частью основной программы. Но обычно повторяющиеся действия обрабатываются каким-то прерыванием. EPS-103 имеет генерируемое аппаратное прерывание RST7.5 от генератора импульсов NE555. Период импульса и, следовательно, повторение прерывания составляет 4 мс. Это может быть использовано для работы с клавиатурой. Нам просто нужно убедиться, что наш обработчик завершится до того, как прерывание снова сработает. Например, согласно документации очистка ЖК-дисплея занимает 15 мс. Это означает, что мы не сможем управлять дисплеем во время перерыва.
В целях изучения мы будем использовать прерывание RST7.5, но только для сканирования клавиатуры. Записываем результат сканирования в оперативную память по адресам 4600h и 4601h. В основной программе будет цикл, который будет считывать эти адреса и выполнять обработку на основе содержимого, включая запись на дисплей.
Введение в программу такое же, как и в программу Hello world. Сначала мы устанавливаем адрес стека в ОЗУ на 4700h, а затем инициализируем схему 8255A. Затем нам нужно правильно установить прерывание. RST7.5 необходимо включить, записав 0 в бит 2 регистра маски прерывания. Это делается по инструкции SIM. Затем мы можем вызвать прерывание с помощью инструкции EI. Бесконечный цикл будет многократно считывать адреса 4600h и 4601h и сравнивать их с копиями по адресам 4602h и 4603h. Если они отличаются, мы сначала обновляем копии. Затем стираем весь дисплей и пишем на нем настройку переключателя MODE, а затем название нажатой кнопки. Программа не обрабатывает возможность одновременного нажатия нескольких кнопок.
Чтобы программа имела определенную функцию, мы можем активировать двигатели в соответствующем направлении, нажимая кнопки 2/E, 3/U, 4W и 8/D. Отпустив кнопку, глушим двигатель. Если кто-то модифицирует программу, чтобы отслеживать большее количество одновременных нажатий кнопок, он должен тщательно продумать, как реагировать на них. Например, можно одновременно запускать двигатели азимута и угла места. Нет смысла активировать вращение одного мотора с обеих сторон одновременно. Изменение направления вращения при работающем двигателе может повредить двигатель.
Интерфейс двигателей подключен к порту C схемы 8255A, то есть по адресу 5802h. Двигатели управляются записью управляющего байта в этот порт. Значение отдельных битов следующее:
Биты адреса 5802h | Функция |
0 | Направление возвышения: 0 = Up; 1 = Down |
1 | Подъемный двигатель: 0 = Off; 1 = On |
2 | High Speed: 0 = Off; 1 = On |
3 | Азимутальное направление: 0 = West; 1 = East |
4 | Азимутальный двигатель: 0 = Off; 1 = On |
5 | Nepoužito |
6 | Nepoužito |
7 | Nepoužito |
Соответствующая программа может выглядеть так:
jmp Start
.ORG 003Ch
jmp IntRST75
.ORG 0040h
.dseg
nokey .text "and no other key is pressed"
key1 .text "and Key 1 is pressed"
key2 .text "and Key 2/E is pressed"
key3 .text "and Key 3/U is pressed"
key4 .text "and Key 4/W is pressed"
key5 .text "and Key 5 is pressed"
key6 .text "and Key 6 is pressed"
key7 .text "and Key 7 is pressed"
key8 .text "and Key 8/D is pressed"
key9 .text "and Key 9 is pressed"
keyA .text "and Key 0 is pressed"
keyE .text "and Key E is pressed"
keyup .text "and Key Up is pressed"
keydn .text "and Key Down is pressed"
keyprg .text "MODE PRG "
keytch .text "MODE TCH "
keyrun .text "MODE RUN "
.cseg
Start: lxi sp, 4700h ; Set Stack Address
mvi a, 82h ; CW
sta 5803h ; 8255A Write Control Word
xra a ; 0 -> a
sta 5802h ; 0 -> port C: stop motors
mvi a, 0Ch ; LCD Command: Display on, cursor off
call sub_1B70 ; Command -> LCD
mvi a, 00h
sta 4600h ; Initialization RAM
sta 4601h ; Initialization RAM
sta 4602h ; Initialization RAM
sta 4603h ; Initialization RAM
mvi a, 0Bh ; Mask interrupt, 0000 1011, 0 -> bit2
sim ; Set mask
ei ; Enable Interrupt
TestKey: lxi h, 4600h ; Source RAM
mov a, m ; value -> a
lxi h, 4602h
cmp m ; Compare the value with the copy
jnz TestCont ; if value 4600h <> value 4602h, jump
lxi h, 4601h ; Source RAM
mov a, m ; Compare the value with the copy
lxi h, 4603h
cmp m ; Compare the value with the copy
jz TestKey ; if value 4601h = value 4603h, nothing changed, test again
TestCont: lxi h, 4600h ; Source RAM
mov a, m ; value -> a
sta 4602h ; copy
lxi h, 4601h ; Source RAM
mov a, m ; value -> a
sta 4603h ; copy
mvi a, 01h ; LCD Command: Clear Display
call sub_1B70 ; Command -> LCD
lxi h, 4600h ; Mode switch MyCode
mov a, m ; Switch status
cpi 10h ; Is the PRG key?
jnz Test20 ; If not, jump
lxi h, keyprg ; Address of text
mvi b, 09h ; Number of characters
call WrStr ; Text -> LCD
jmp Test01
Test20: lxi h, 4600h ; Mode switch MyCode
mov a, m ; Switch status
cpi 20h ; Is the TCH key?
jnz Test30 ; If not, jump
lxi h, keytch ; Address of text
mvi b, 09h ; Number of characters
call WrStr ; Text -> LCD
jmp Test01
Test30: lxi h, keyrun ; Address of text
mvi b, 09h ; Number of characters
call WrStr ; Text -> LCD
Test01: lxi h, 4601h
mov a, m ; Key MyCode
cpi 01h ; Is the 1 key?
jnz Test02 ; If not, jump
lxi h, key1 ; Address of text
mvi b, 14h ; Number of characters
call WrStr ; Text -> LCD
jmp TestKey ; Neverending loop
Test02: lxi h, 4601h
mov a, m ; Key MyCode
cpi 02h ; Is the 2/E key?
jnz Test03 ; If not, jump
lxi h, key2 ; Address of text
mvi b, 16h ; Number of characters
call WrStr ; Text -> LCD
mvi a, 18h ; 0001 1000 East = On
sta 5802h
jmp TestKey ; Neverending loop
Test03: lxi h, 4601h
mov a, m ; Key MyCode
cpi 03h ; Is the 3/U key?
jnz Test04 ; If not, jump
lxi h, key3 ; Address of text
mvi b, 16h ; Number of characters
call WrStr ; Text -> LCD
mvi a, 02h ; 0000 0010 Up = On
sta 5802h
jmp TestKey ; Neverending loop
Test04: lxi h, 4601h
mov a, m ; Key MyCode
cpi 04h ; Is the 4/W key?
jnz Test05 ; If not, jump
lxi h, key4 ; Address of text
mvi b, 16h ; Number of characters
call WrStr ; Text -> LCD
mvi a, 10h ; 0001 0000 West = On
sta 5802h
jmp TestKey ; Neverending loop
Test05: lxi h, 4601h
mov a, m ; Key MyCode
cpi 05h ; Is the 5 key?
jnz Test06 ; If not, jump
lxi h, key5 ; Address of text
mvi b, 14h ; Number of characters
call WrStr ; Text -> LCD
jmp TestKey ; Neverending loop
Test06: lxi h, 4601h
mov a, m ; Key MyCode
cpi 06h ; Is the 6 key?
jnz Test07 ; If not, jump
lxi h, key6 ; Address of text
mvi b, 14h ; Number of characters
call WrStr ; Text -> LCD
jmp TestKey ; Neverending loop
Test07: lxi h, 4601h
mov a, m ; Key MyCode
cpi 07h ; Is the 7 key?
jnz Test08 ; If not, jump
lxi h, key7 ; Address of text
mvi b, 14h ; Number of characters
call WrStr ; Text -> LCD
jmp TestKey ; Neverending loop
Test08: lxi h, 4601h
mov a, m ; Key MyCode
cpi 08h ; Is the 8/D key?
jnz Test09 ; If not, jump
lxi h, key8 ; Address of text
mvi b, 16h ; Number of characters
call WrStr ; Text -> LCD
mvi a, 03h ; 0000 0011 Down = On
sta 5802h
jmp TestKey ; Neverending loop
Test09: lxi h, 4601h
mov a, m ; Key MyCode
cpi 09h ; Is the 9 key?
jnz Test0A ; If not, jump
lxi h, key9 ; Address of text
mvi b, 14h ; Number of characters
call WrStr ; Text -> LCD
jmp TestKey ; Neverending loop
Test0A: lxi h, 4601h
mov a, m ; Key MyCode
cpi 0Ah ; Is the 0 key?
jnz Test0B ; If not, jump
lxi h, keyA ; Address of text
mvi b, 14h ; Number of characters
call WrStr ; Text -> LCD
jmp TestKey ; Neverending loop
Test0B: lxi h, 4601h
mov a, m ; Key MyCode
cpi 0Bh ; Is the E key?
jnz Test0C ; If not, jump
lxi h, keyE ; Address of text
mvi b, 14h ; Number of characters
call WrStr ; Text -> LCD
jmp TestKey ; Neverending loop
Test0C: lxi h, 4601h
mov a, m ; Key MyCode
cpi 0Ch ; Is the Up key?
jnz Test0D ; If not, jump
lxi h, keyup ; Address of text
mvi b, 15h ; Number of characters
call WrStr ; Text -> LCD
jmp TestKey ; Neverending loop
Test0D: lxi h, 4601h
mov a, m ; Key MyCode
cpi 0Dh ; Is the Down key?
jnz TestNoK ; If not, jump
lxi h, keydn ; Address of text
mvi b, 17h ; Number of characters
call WrStr ; Text -> LCD
jmp TestKey ; Neverending loop
TestNoK: lxi h, nokey ; Address of text
mvi b, 1Bh ; Number of characters
call WrStr ; Text -> LCD
mvi a, 00h
sta 5802h ; 0 -> PortC: stop motors
jmp TestKey ; Neverending loop
hlt ; For sure
; Write 1 byte command
sub_1B70: call sub_1B7E ; Wait for LCD ready
sta 4802h ; Write command byte
ret
; Write 1 byte data
sub_1B77: call sub_1B7E ; Wait for LCD ready
sta 4803h ; Write data byte
ret
; Wait for LCD ready
sub_1B7E: push psw
loc_1B7F: lda 4800h ; Read LCD status
ani 80h ; Test bit 7: 0 = ready
jnz loc_1B7F ; if not, repeat
pop psw
ret
; Write string on LCD
WrStr: mov a, m
call sub_1B77 ; Character -> LCD
inx h ; Address of next characters
dcr b ; Decrement counter
jnz WrStr
ret
; Interrupt handling RST7.5
IntRST75: push psw ; Save the contents of the registers to the stack
push b
push d
push h
mvi a, 0F7h
sta 5800h ; Scan Group 3
lda 5801h
ori 0F0h
cpi 0FEh ; Is the PRG key?
jnz TCH_20 ; If not, jump
mvi a, 10h ; The key is PRG, MyCode = 10h
sta 4600h
jmp ScanGr0 ; Go scan group 0
TCH_20: cpi 0FDh ; Is the TCH key?
jnz RUN_30 ; If not, jump
mvi a, 20h ; The key is TCH, MyCode = 20h
sta 4600h
jmp ScanGr0 ; Go scan group 0
RUN_30: cpi 0FBh ; Are the RUN + Up keys?
jnz RUN_31 ; If not, jump
mvi a, 30h ; The key is RUN, MyCode = 30h
sta 4600h
mvi a, 0Ch ; and the key is Up, MyCode = 0Ch
sta 4601h
jmp EndISR ; Finish scanning
RUN_31: cpi 0F7h ; Are the RUN + Down keys?
jnz RUN_32 ; If not, jump
mvi a, 30h ; The key is RUN, MyCode = 30h
sta 4600h
mvi a, 0Dh ; and the key is Up, MyCode = 0Dh
sta 4601h
jmp EndISR ; Finish scanning
RUN_32: mvi a, 30h ; The key must be RUN
sta 4600h
ScanGr0: mvi a, 0FEh ; Mask Group 0
sta 5800h ; Write mask
lda 5801h ; Scan Group 0
ori 0F0h
cpi 0FEh ; Is the 1 key?
jnz Gr0_2 ; If not, jump
mvi a, 01h ; The key is 1, MyCode = 01h
sta 4601h
jmp EndISR ; Finish scanning
Gr0_2: cpi 0FDh ; Is the 2/E key?
jnz Gr0_3 ; If not, jump
mvi a, 02h ; The key is 2/E, MyCode = 02h
sta 4601h
jmp EndISR ; Finish scanning
Gr0_3: cpi 0FBh ; Is the 3/U key?
jnz Gr0_4 ; If not, jump
mvi a, 03h ; The key is 3/U, MyCode = 03h
sta 4601h
jmp EndISR ; Finish scanning
Gr0_4: cpi 0F7h ; Is the 4/W key?
jnz Gr1_1 ; If not, jump
mvi a, 04h ; The key is 4/W, MyCode = 04h
sta 4601h
jmp EndISR ; Finish scanning
Gr1_1: mvi a, 0FDh ; Mask Group 1
sta 5800h ; Write mask
lda 5801h ; Scan Group 1
ori 0F0h
cpi 0FEh ; Is the 5 key?
jnz Gr1_2 ; If not, jump
mvi a, 05h ; The key is 5, MyCode = 05h
sta 4601h
jmp EndISR ; Finish scanning
Gr1_2: cpi 0FDh ; Is the 6 key?
jnz Gr1_3 ; If not, jump
mvi a, 06h ; The key is 6, MyCode = 06h
sta 4601h
jmp EndISR ; Finish scanning
Gr1_3: cpi 0FBh ; Is the 7 key?
jnz Gr1_4 ; If not, jump
mvi a, 07h ; The key is 7, MyCode = 07h
sta 4601h
jmp EndISR ; Finish scanning
Gr1_4: cpi 0F7h ; Is the 8/D key?
jnz Gr2_1 ; If not, jump
mvi a, 08h ; The key is 8/D, MyCode = 08h
sta 4601h
jmp EndISR ; Finish scanning
Gr2_1: mvi a, 0FBh ; Mask Group 2
sta 5800h ; Write mask
lda 5801h ; Scan Group 2
ori 0F0h
cpi 0FEh ; Is the 9 key?
jnz Gr2_2 ; If not, jump
mvi a, 09h ; The key is 9, MyCode = 09h
sta 4601h
jmp EndISR ; Finish scanning
Gr2_2: cpi 0FDh ; Is the 0 key?
jnz Gr2_3 ; If not, jump
mvi a, 0Ah ; The key is 0, MyCode = 0Ah
sta 4601h
jmp EndISR ; Finish scanning
Gr2_3: cpi 0FBh ; Is the E key?
jnz NoKeyIs ; If not, jump
mvi a, 0Bh ; The key is E, MyCode = 0Bh
sta 4601h
jmp EndISR ; Finish scanning
NoKeyIs: mvi a, 00h ; no key is pressed, MyCode = 00h
sta 4601h
; Finish scanning
EndISR: pop h ; Restore the contents of the registers from the stack
pop d
pop b
pop psw
ei ; Enable Interrupt
ret
.END
Полученный двоичный файл загружается программистом в стертую память EPROM и может быть протестирован. Я считаю, что информация, представленная в этой программе, поможет всем, кто хотел бы исследовать оригинальную прошивку EPS-103. Вы можете скачать исходный текст указанной программы в файле KeyboardEPS103.asm.