;******************************************;
;    KEYBOARD SCANNER USING THE 83C751     ;
;   OUTPUT INTERFACE IS PC-AT COMPATABLE   ;
;     Date:  06-OCT-88                     ;
;   Edited:  14-OCT-88 (Key scan OK)       ;
;   Edited:  14-OCT-88 (Table scan OK)     ;
;   Edited:  28-OCT-88 (Serial Output)     ;
;                                          ;
;   Programmer-----> Jim Greene            ;
;       SIGNETICS CORPORATION              ;
;******************************************;
$MOD751
$DEBUG
$Title(83C751 PC-AT Keyboard Scanner)
; Port Usage:
; P1        COLUMN side of Matrix
; P3        ROW side of Matrix
; P0.0      Clock out
; P0.1      Serial Data out
;Register Usage
; R7    Column Offset Count
; R6    Debounce Hi count value
; R5    Bebounce Lo count value
;Internal RAM Usage
COLUMN       EQU     20H        ;Key pressed is in this COLUMN (P3)
ROW          EQU     21H        ;Contains ROW from P1
BUFFER       EQU     22H        ;Byte to be sent to GRID
TAB          EQU     23H        ;Holds pointer for table
;    TAB Contents  00-07H  (/;P0ZAQ1)
;                  10-17H  (.LO9XSW2)
;                  20-27H  (,KI8CDE3)
;                  30-37H  (MJU7VFR4)
;                  40-47H  (NHY6BGT5)
;                  50-57H  (=|space|enter|_|_|shift|ctrl|fct'n)
        ORG     00H             ;Power-on starts here
        AJMP    MAIN
        ORG     30H
MAIN:   MOV     SP, #07H
        MOV     PSW, #00H       ;RB 0
        MOV     P0, #0FFH       ;Set clock & data lines in 1 state
        ACALL LOOK              ;Scan the keyboard
DO:     MOV     DPTR, #TABLE    ;DPTR has base address of table
        MOV     A, TAB          ;Put offset in A
        MOVC    A, @A+DPTR      ;Get byte from TABLE
        MOV     BUFFER, A       ;Put hex byte in buffer 
        ACALL   SEND            ;Send it to the GRID
        JMP     MAIN
$EJECT
LOOK:   MOV     P1, #0FFH
        MOV     P3, #0H
        MOV     R0, #021H
LOOK1:  MOV     A,  P1
        JB      PSW.0, SEE_IT   ;CHECK PARITY, IF SET KEY DOWN
        JMP     LOOK1
SEE_IT: MOV     ROW, A          ;Save P1 row
        ACALL   DEBOUNCE        ;Let the key settle
        MOV     A, P1           ;Lets look again
        CJNE    A,P1, LOOK      ;If the same continue, else abort
        MOV     P3, #0FFH       ;
        JNB     ROW.0, SCAN0
        JNB     ROW.1, SCAN1
        JNB     ROW.2, SCAN2
        JNB     ROW.3, SCAN3
        JNB     ROW.4, SCAN4
        JNB     ROW.5, SCAN5
        JMP     LOOK1

;*********************************;
; DEBOUNCE SUBROUTINE STARTS HERE ;
;*********************************;
DEBOUNCE:
        MOV     R6,  #20H       ;THIS IS SUPPOSED TO BE
L0:     MOV     R5,  #20H       ;ABOUT 30ms OR SO.
L1:     DJNZ    R5,  L1         ;
        DJNZ    R6,  L0         ;
        RET                     ;We're done go back 
$EJECT
SCAN0:  MOV     P1, #0FEH       ;See if its column 0
        MOV     ROW, #00H
        ACALL    SEARCH         ;SEARCH examines row inputs
        JMP     DO
SCAN1:  MOV     P1, #0FDH       ;Scope out column  1
        MOV     ROW, #10H
        ACALL    SEARCH         ;
        JMP     DO
SCAN2:  MOV     P1, #0FBH       ;Column 2
        MOV     ROW, #20H
        ACALL    SEARCH         ;
        JMP     DO
SCAN3:  MOV     P1, #0F7H       ;# 3
        MOV     ROW, #30H
        ACALL    SEARCH
        JMP     DO
SCAN4:  MOV     P1, #0EFH       ;# 4
        MOV     ROW, #40H
        ACALL    SEARCH         ;
        JMP     DO
SCAN5:  MOV     P1, #0DFH       ;# 5
        MOV     ROW, #50H
        ACALL    SEARCH         ;
        JMP     DO
SEARCH: MOV     R7, #00H        ;R7 is row pointer
        MOV     A, P3           ;Is it this one? R7 starts at 0
        MOV     COLUMN, A       ;Save COLUMN-but it may not be valid
        JNB     COLUMN.0, IT_IS ;Lets try again
        INC     R7              ;
        JNB     COLUMN.1, IT_IS ;
        INC     R7              ;
        JNB     COLUMN.2, IT_IS ;
        INC     R7              ;
        JNB     COLUMN.3, IT_IS ;
        INC     R7              ;
        JNB     COLUMN.4, IT_IS ;
        INC     R7              ;
        JNB     COLUMN.5, IT_IS ;
        INC     R7              ;
        JNB     COLUMN.6, IT_IS ;
        INC     R7              ;
        JNB     COLUMN.7, IT_IS ;
        RET
IT_IS:  MOV     TAB, ROW        ;Put hi nibble in TAB
        MOV     COLUMN, R7      ;COLUMN now has offset
        MOV     A,   R7         ;Put row offset in A
        ORL     TAB, A          ;TAB is table pointer
        MOV     B, TAB          ;Put it here for emulation purposes
        RET
$EJECT
ORG     150H
;*******************************;
;   SEND SUBROUTINE STARTS      ;
;   HERE. BUFFER HAS BYTE       ;
;    TO BE SENT TO PC-AT        ;
;*******************************;
SEND:   MOV     PSW, #018H      ;RB 3
        MOV     R2, #00H        ;R2 IS CHAR COUNTER
S0:     MOV     A, BUFFER       ;CHAR IS IN A
S1:     MOV     R2, #00H
        MOV     R3, A           ;SAVE CHAR IN R3 FOR PARITY & KEY UP
        JNB     P0.1, SEND      ;Test data for a 1
        JNB     P0.0, SEND      ;Test clock for a 1
        CLR     C               ;GET SET TO SEND SPACE BIT
        MOV     P0.1, C         ;PUT IT ON DATA LINE  --____
        ACALL   PULSE           ;WAIT AND CLOCK       ---_--
BIT_LOOP:
        RRC     A               ;PUT "0 BIT" IN CARRY
        INC     R2              ;1st BIT IS IN CARRY
        MOV     P0.1, C         ;1st IS ON DATA LINE  --____----
        ACALL   PULSE           ;                     ---_---_--
        CJNE    R2, #08H, BIT_LOOP; SENT 8 BITS YET?
        MOV     R2, #00H
        MOV     A, R3           ;SET UP FOR PARITY
        MOV     C, PSW.0        ;DO IT
        CPL     C               ;PARITY+ACC=EVEN, WE NEED ODD
        MOV     P0.1, C         ;
        ACALL   PULSE           ;WAIT  AND CLOCK
        SETB    P0.1            ;DATA=1 FOR STOP BIT
        ACALL   PULSE           ;WAIT AND CLOCK
        MOV     P0, #0FFH       ;RAISE ALL LINES
        MOV     R6, #0FFH
A1:     MOV     R5, #0FFH
A2:     DJNZ    R5, A2
        DJNZ    R6, A1
ME:     JNB     P0.1, ME
YOU:    JNB     P0.0, YOU
        MOV     A, BUFFER
        CJNE    A, #0F0H, HA
        MOV     R6, #0FFH
I:      MOV     R5, #0FFH
THEY:   DJNZ    R5, THEY
        DJNZ    R6, I
        MOV     BUFFER, #059H
        AJMP    SEND
PULSE:  MOV     R5, #07H        ;WAIT 
U1:     DJNZ    R5, U1
        CLR     P0.0            ;CREATE FALLING EDGE OF CLOCK
        MOV     R5, #07H        ;WAIT SOME MORE
U2:     DJNZ    R5, U2          ;
        SETB    P0.0            ;CREATE RISING EDGE OF CLOCK
        RET
HA:     MOV A, #00H
        JMP     MAIN
$EJECT
;*******************************;
;       LOOK-UP TABLE           ;
;        STARTS HERE            ;
;*******************************;

ORG 300H
TABLE:  DB      04AH    ; /
        DB      04CH    ; :
        DB      04DH    ; P
        DB      045H    ; 0
        DB      01AH    ; Z
        DB      01CH    ; A
        DB      015H    ; Q
        DB      016H    ; 1
ORG 310H
        DB      049H    ; .
        DB      04BH    ; L
        DB      044H    ; O
        DB      046H    ; 9
        DB      022H    ; X
        DB      01BH    ; S
        DB      01DH    ; W
        DB      01EH    ; 2
ORG 320H
        DB      041H    ; ,
        DB      042H    ; K
        DB      043H    ; I
        DB      03EH    ; 8
        DB      021H    ; C
        DB      023H    ; D
        DB      024H    ; E
        DB      026H    ; 3
ORG 330H
        DB      03AH    ; M
        DB      03BH    ; J
        DB      03CH    ; U
        DB      03DH    ; 7
        DB      02AH    ; V
        DB      02BH    ; F
        DB      02DH    ; R
        DB      025H    ; 4
ORG 340H
        DB      031H    ; N
        DB      033H    ; H
        DB      035H    ; Y
        DB      036H    ; 6
        DB      032H    ; B
        DB      034H    ; G
        DB      02CH    ; T
        DB      02EH    ; 5
ORG 350H
        DB      055H    ; =
        DB      029H    ; space bar
        DB      05AH    ; enter key
        DB      000H    ; NO KEY ON BOARD
        DB      000H    ; NO KEY ON BOARD
        DB      059H    ; shift key
        DB      066H    ; control key SENDS BACK SPACE
        DB      0F0H    ; function SENDS UP KEY + FOLLOWING KEY

        END

