Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: 16тикнопочная клавиатура и 80C552
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Все остальные микроконтроллеры > MCS51
lytdybr
Имеется клавиатура с цифрами 0-F, подключенная к порту P1 контроллера.
Изначально P1 = 11111111b.
Каждая клавиша кодируется двумя битами в P1 - один как бы обозначает ряд, другой - столбец. При нажатии кнопки соответствующие 2 бита сбрасываются в 0.
В этом случае определение нажатой кнопки - циклический перебор состояний P1.
Но появляются какие-то проблемы.
Стоит задача: при нажатии клавиши вывести сначала знак "*", потом - знак "#" каждую секунду, пока нажата клавиша, затем, когда клавиша отпущена - цифру, соответствующую клавише. Реализовать это надо с использованием прерываний.
Вот исходник:
Код
ORG 8000H
LJMP MAIN

ORG 8033H
LJMP P1HANDLE

ORG 803BH
LJMP P1HANDLE

ORG 8043H
LJMP P1HANDLE

ORG 804BH
LJMP P1HANDLE

MAIN:
TM2IR EQU   0C8h
CTCON EQU   0EBh
S0BUF EQU   099h
IEN1 EQU   0E8h
IEN0 EQU   0A8h
IP1  EQU   0F8h
TM2CON EQU   0EAh

MOV  A,   #00000000B
MOV  R1,   #11111111B
MOV  R2,   #11111111B
MOV  R3,   #00000000B
MOV  P1,   #00001111B
MOV  TM2IR,  #00000000B
MOV  TM2CON,  #00000011B
MOV  CTCON,  #10101010B
MOV  IP1,  #00000000B
MOV  IEN1,  #00001111B
MOV  IEN0,  #10000000B
SETB IE.7

LOOP:
NOP
JMP  LOOP


P1HANDLE:
MOV  R4,   P1
MOV  TM2IR,  #00000000B

CLR  TI
MOV  S0BUF,  #00101010B
JNB  TI,   $
CLR  TI
CLR  TI
MOV  S0BUF,  R4
JNB  TI,   $
CLR  TI
CALL  WAIT
CALL  WAIT

PRINT23H:
CLR  TI
MOV  S0BUF,  #00100011B
JNB  TI,   $
CLR  TI
CALL  WAIT

MOV  A,   P1
CJNE A,   #00001111B,  PRINT23H

<Определение нажатой клавиши и вывод соответствующего символа>

RETURN:
MOV  A,   #00000000B
MOV  R1,   #11111111B
MOV  R2,   #11111111B
MOV  R3,   #00000000B
MOV  P1,   #00001111B
MOV  TM2IR,  #00000000B
MOV  TM2CON,  #00000011B
MOV  CTCON,  #10101010B
MOV  IP1,  #00000000B
MOV  IEN1,  #00001111B
MOV  IEN0,  #10000000B
SETB IE.7
A1:
RETI

WAIT:
OUTER_CYCLE:
INNER_CYCLE:
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
DJNZ  R2,   INNER_CYCLE
DJNZ  R1,   OUTER_CYCLE
RET

DELAY:
JNB TI, WAIT
RET

END

Это - гарантированно рабочий код, возможно не оптимальный. Определение клавиши сделано так, но это не работает:
Код
GET_NUMBER:
MOV  P1,   #11011111B
MOV  A,   P1
CJNE  A,   #11011111B,  RECOGN0

MOV  P1,   #11101111B
MOV  A,   P1
CJNE  A,   #11101111B,  RECOGN0

MOV  P1,   #01111111B
MOV  A,   P1
CJNE  A,   #01111111B,  RECOGN0

MOV  P1,   #10111111B
MOV  A,   P1
CJNE  A,   #10111111B,  RECOGN0
JMP GET_NUMBER

RECOGN0:
MOV  A,   #11010000B
ORL  A,   R4
CJNE  A,   #11011101B,  RECOGN1
MOV  R3,   #00110001B
LJMP  OUTPUT

RECOGN1:
CJNE  A,   #11011110B,  RECOGN2
MOV  R3,   #00110010B
LJMP  OUTPUT

RECOGN2:
CJNE  A,   #11010111B,  RECOGN3
MOV  R3,   #00110011B
LJMP  OUTPUT

RECOGN3:
CJNE  A,   #11011011B,  RECOGN4
MOV  R3,   #00110100B
LJMP  OUTPUT

RECOGN4:
MOV  A,   #11100000B
ORL  A,   R4
CJNE  A,   #11101101B,  RECOGN5
MOV  R3,   #00110101B
LJMP  OUTPUT

RECOGN5:
CJNE  A,   #11101110B,  RECOGN6
MOV  R3,   #00110110B
LJMP  OUTPUT

RECOGN6:
CJNE  A,   #11100111B,  RECOGN7
MOV  R3,   #00110111B
LJMP  OUTPUT

RECOGN7:
CJNE  A,   #11101011B,  RECOGN8
MOV  R3,    #00111000B
LJMP  OUTPUT

RECOGN8:
MOV  A,   #01110000B
ORL  A,   R4
CJNE  A,   #01111101B,  RECOGN9
MOV  R3,   #00111001B
LJMP  OUTPUT

RECOGN9:
CJNE  A,   #01111110B,  RECOGN10
MOV  R3,   #00110000B
LJMP  OUTPUT

RECOGN10:
CJNE  A,   #01110111B,  RECOGN11
MOV  R3,   #01000001B
LJMP  OUTPUT

RECOGN11:
CJNE  A,   #01111011B,  RECOGN12
MOV  R3,   #01000010B
LJMP  OUTPUT

RECOGN12:
MOV  A,   #10110000B
ORL  A,   R4
CJNE  A,   #10111101B,  RECOGN13
MOV  R3,   #01000011B
LJMP  OUTPUT

RECOGN13:
CJNE  A,   #10111110B,  RECOGN14
MOV  R3,   #01000100B
LJMP  OUTPUT

RECOGN14:
CJNE  A,   #10110111B,  RECOGN15
MOV  R3,   #01000101B
LJMP  OUTPUT

RECOGN15:
CJNE  A,   #10111011B,  NOT_RECOGN
MOV  R3,   #01000110B
LJMP  OUTPUT

NOT_RECOGN:
CJNE  A,   #10111011B,  RETURN

OUTPUT:
CLR  TI
MOV  S0BUF,   R3
JNB  TI,   $
CLR  TI


Этот код почему-то определяет только верхние 4 кнопки, выводя цифры 1-4, если нажимать остальные - то выводит тоже 1-4.
Палыч
Как всё запущено... Ну, если "в лоб", то что-то такое:
Код
GET_NUMBER:
MOV  P1,   #11011111B
MOV  A,   P1
CJNE  A,   #11011111B,  L1
MOV  P1,   #11101111B
MOV  A,   P1
CJNE  A,   #11101111B,  L2
MOV  P1,   #01111111B
MOV  A,   P1
CJNE  A,   #01111111B,  L3
MOV  P1,   #10111111B
MOV  A,   P1
CJNE  A,   #10111111B,  L4
JMP GET_NUMBER

L1: ; наверное у Вас это считается первой строкой? или третьей?
CJNE  A,   #11011101B,  L1C2; константа = что выдали в порт, но с одним нулём в одной колонке
MOV  R3,   #00110001B; наверное - это код строки/столбца?
LJMP  OUTPUT
L1C21:
CJNE  A,   #11011110B,  L1C3
MOV  R3,   #00110010B
LJMP  OUTPUT
L1C32:
CJNE  A,   #11010111B,  L1C4
MOV  R3,   #00110011B
LJMP  OUTPUT
L1C4:
CJNE  A,   #11011011B,  LXX; Переходим на LXX если нажали две или больше клавиш
MOV  R3,   #00110100B
LJMP  OUTPUT

L2:
аналогично, но меняются константы
L3:
и здесь - аналогично, но др. константы
L4:
и здесь...
lytdybr
Цитата(Палыч @ Jun 19 2008, 14:47) *
Как всё запущено... Ну, если "в лоб", то что-то такое:
Код
...

В R3 я кладу ASCII код символа, который будет выведен.
Физически на клавиатуре L1 - первая. По распайке - не знаю.
Вопрос такой: перед тем, как определять клавишу - нужно выключать прерывания?
Проверил на эмуляторе, вроде работает, только с косяком. Попробую разобраться сам.
Палыч
Чтобы ответить на Ваши вопросы, нужно разбираться в том, что Ваша программа и в каком месте делает. Ваш стиль написания программ - как бы это по-мягче сказать ? - не информативен... И коментарии отсутствуют. Вряд ли кто-то что-то разберёт... Если Вы текст своей программы не поправите, получить советы вряд ли сможите. Например

Цитата(lytdybr @ Jun 19 2008, 14:56) *
В R3 я кладу ASCII код символа, который будет выведен.
Более понятно, это записывается так (в R3 положить код символа 1)
mov R3, #'1'
Цитата(lytdybr @ Jun 19 2008, 14:56) *
Вопрос такой: перед тем, как определять клавишу - нужно выключать прерывания?
Речь идёт о той части программы, которая начинается с метки get_number? Если, да, то не вижу смысла это делать...
lytdybr
Код


ORG 8000H
LJMP MAIN

ORG 8033H
LJMP P1HANDLE

ORG 803BH
LJMP P1HANDLE

ORG 8043H
LJMP P1HANDLE

ORG 804BH
LJMP P1HANDLE

MAIN:
TM2IR EQU   0C8h
CTCON EQU   0EBh
S0BUF EQU   099h
IEN1 EQU   0E8h
IEN0 EQU   0A8h
IP1  EQU   0F8h
TM2CON EQU   0EAh

MOV  A,   #00000000B
MOV  R1,   #11111111B
MOV  R2,   #11111111B
MOV  R3,   #00000000B
MOV  P1,   #11111111B
; Сбрасываем флаги прерываний T2
MOV  TM2IR,  #00000000B
: Включаем таймер
MOV  TM2CON,  #00000011B
; Реагируем на перепад 1->0 на p1.0 - p1.3
MOV  CTCON,  #10101010B
MOV  IP1,  #00000000B
; Включаем прерывания от регистров захвата (capture register)
MOV  IEN1,  #00001111B
; Включаем прерывания вообще
MOV  IEN0,  #10000000B

LOOP:
; Ожидание прерываний
NOP
JMP  LOOP

; Обработка прерываний от регистров захвата 0-3
P1HANDLE:
;сохраняем P1
MOV  R4,   P1
;Сброс флагов прерыаний
MOV  TM2IR,  #00000000B

; выводим "*"
CLR  TI
MOV  S0BUF,  #00101010B
JNB  TI,   $
CLR  TI

; Пока клавиша не отпущена - выводим "#"
PRINT23H:
CLR  TI
MOV  S0BUF,  #00100011B
JNB  TI,   $
CLR  TI
CALL  WAIT

MOV  A,   P1
CJNE A,   #11111111B,  PRINT23H

; Выводим на экран символ соответствующий нажатой клавише
GET_NUMBER:
; Линия 1
    MOV     P1,            #11011111B
    MOV     A,            P1
    CJNE     A,            #11011111B,        RECOGN0
; Линия 2
    MOV     P1,            #11101111B
    MOV     A,            P1
    CJNE     A,            #11101111B,        RECOGN4
; Линия 3
    MOV     P1,            #01111111B
    MOV     A,            P1
    CJNE     A,            #01111111B,        RECOGN8
; Линия 4
    MOV     P1,            #10111111B
    MOV     A,            P1
    CJNE     A,            #10111111B,        RECOGN12
JMP GET_NUMBER

RECOGN0:
    CJNE     A,            #11011101B,        RECOGN1
    MOV     R3,            #'1'
    LJMP     OUTPUT

RECOGN1:
    CJNE     A,            #11011110B,        RECOGN2
    MOV     R3,            #'2'
    LJMP     OUTPUT

RECOGN2:
    CJNE     A,            #11010111B,        RECOGN3
    MOV     R3,            #'3'
    LJMP     OUTPUT

RECOGN3:
    CJNE     A,            #11011011B,        RECOGN4
    MOV     R3,            #'4'
    LJMP     OUTPUT

RECOGN4:
    CJNE     A,            #11101101B,        RECOGN5
    MOV     R3,            #'5'
    LJMP     OUTPUT

RECOGN5:
    CJNE     A,            #11101110B,        RECOGN6
    MOV     R3,            #'6'
    LJMP     OUTPUT

RECOGN6:
    CJNE     A,            #11100111B,        RECOGN7
    MOV     R3,            #'7'
    LJMP     OUTPUT

RECOGN7:
    CJNE     A,            #11101011B,     RECOGN8
    MOV     R3,            #'8'
    LJMP     OUTPUT

RECOGN8:
    CJNE     A,            #01111101B,        RECOGN9
    MOV     R3,            #'9'
    LJMP     OUTPUT

RECOGN9:
    CJNE     A,            #01111110B,        RECOGN10
    MOV     R3,            #'0'
    LJMP     OUTPUT

RECOGN10:
    CJNE     A,            #01110111B,        RECOGN11
    MOV     R3,         #'A'
    LJMP     OUTPUT

RECOGN11:
    CJNE     A,            #01111011B,     RECOGN12
    MOV     R3,            #'B'
    LJMP     OUTPUT

RECOGN12:
    CJNE     A,            #10111101B,        RECOGN13
    MOV     R3,            #'C'
    LJMP     OUTPUT

RECOGN13:
    CJNE     A,            #10111110B,        RECOGN14
    MOV     R3,            #'D'
    LJMP     OUTPUT

RECOGN14:
    CJNE     A,            #10110111B,     RECOGN15
    MOV     R3,            #'E'
    LJMP     OUTPUT

RECOGN15:
    CJNE     A,            #10111011B,        NOT_RECOGN
    MOV     R3,            #'F'
    LJMP     OUTPUT

; Клавиша не распознана
NOT_RECOGN:
    CJNE     A,            #10111011B,        RETURN
; выводим символ
OUTPUT:
    CLR        TI
    MOV     S0BUF,         R3
    JNB     TI,            $
    CLR     TI
; Восстанавливаем состояние регистров перед возвратом из прерывания
RETURN:
MOV  A,   #00000000B
MOV  R1,   #11111111B
MOV  R2,   #11111111B
MOV  R3,   #00000000B
MOV  P1,   #00001111B
MOV  TM2IR,  #00000000B
MOV  TM2CON,  #00000011B
MOV  CTCON,  #10101010B
MOV  IP1,  #00000000B
MOV  IEN1,  #00001111B
MOV  IEN0,  #10000000B

; Возврат из прерывания
A1:
RETI

; Пауза примерно 1 сек.
WAIT:
OUTER_CYCLE:
INNER_CYCLE:
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
DJNZ  R2,   INNER_CYCLE
DJNZ  R1,   OUTER_CYCLE
RET

END

Исправил, добавил комменты.
Палыч
Цитата(lytdybr @ Jun 19 2008, 16:16) *
Код
; Восстанавливаем состояние регистров перед возвратом из прерывания
RETURN:
MOV  A,   #00000000B
MOV  R1,   #11111111B
MOV  R2,   #11111111B
MOV  R3,   #00000000B
MOV  P1,   #00001111B
MOV  TM2IR,  #00000000B
MOV  TM2CON,  #00000011B
MOV  CTCON,  #10101010B
MOV  IP1,  #00000000B
MOV  IEN1,  #00001111B
MOV  IEN0,  #10000000B
; Возврат из прерывания
A1:
RETI
Вот этот кусок кода У Вас зачем нужен? R1 и R2 в этом прерывании не используются... Да и регистры устройств разве портятся? А если желаете сохранять значения аккумулятора и регистров, то, обычно, используют команды POP/PUSH: в начале прерывания сохраняемые регистры заталкивают в стек, перед выходом из прерывания - извлекают. В микроконтроллерах МК51 для этой же цели есть специальная фишка - банки регистров (их аж 4), которые можно переключать (это удобно, если в прерывании используется много регистров R0-R7), при этом в основной программе используют банк 0, в одном прерывании - банк 1, в другом прерывании - банк 2, и т.д.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.