;*********************************************************
; THIS PROGRAM SCANS THE KEYPAD AND RETURNS WITH 
; THE KEY PRESS IN THE 'KEY_PRESSED' REGISTER FOR PORTABILITY!
; RUN SCAN_PAD_ON TO SET UP AN INTERRUPT FOR THE PAD 
; OR RUN SCAN_PAD_OFF TO DISABLE THE INTERRUPT. 
; IN YOUR INTERRUPT SERVICE ROUTINE, CHECK FOR A PORT 
; CHANGE ON RB4-RB7 AND THEN CALL KEY_HIT_INT TO 
; SEE WHICH KEY WAS HIT!! 
;*********************************************************

SCAN_PAD_ON:
MOVLW B'11111111'         ;MAKE PORTB
TRIS PORTB                ;ALL INPUTS

BSF STATUS,RP0            ;SWITCH TO BANK 1
BCF OPTREG,RBPU           ;ENABLE WEAK PULLUPS
BCF STATUS,RP0            ;SWITCH TO BANK 0

BCF INTCON,RBIF           ;CLEAR INTERRUPT FLAG
BSF INTCON,GIE            ;ENABLE GLOBAL INTERRUPTS
BSF INTCON,RBIE           ;AND THE ONE WE NEED
RETURN


SCAN_PAD_OFF:
BSF STATUS,RP0            ;SWITCH TO BANK 1
BSF OPTREG,RBPU           ;DISABLE WEAK PULLUPS
BCF STATUS,RP0            ;SWITCH TO BANK 0
BCF INTCON,RBIE           ;DISABLE INTERRUPT
RETURN

;********************************************************
; IF A KEY IS HIT, YOUR PROGRAM GETS TO HERE 
;********************************************************

;********************************************************
; RB4 RB5 RB6 RB7 
; COL1 COL2 COL3 COL4 
; B0 ROW1 1 2 3 < 

; B1 ROW2 4 5 6 > 

; B2 ROW3 7 8 9 Y 

; B3 ROW4 * 0 # N 

;********************************************************


KEY_HIT_INT:
movfw cnt             ;get the cnt value
movwf temp_cnt        ;save it
movfw cnt2            ;get the cnt value
movwf temp_cnt2       ;save it
movfw cnt3            ;get the cnt value
movwf temp_cnt3       ;save it
movfw cnt4            ;get the cnt value
movwf temp_cnt4       ;save it


MOVFW PORTB ;MOVE PORTB VALUE TO W REG
;(THIS ENDS THE MISMATCH CONDITION)

MOVLW .250            ;DEBOUNCE DELAY TIME
CALL MDELAY           ;DEBOUNCE DELAY
call read_again       ;check for a reasonable key press

BTFSS TEMP_KEY2,4     ;WAS IT ON RB4?
GOTO COLUMN1          ;IT WAS ON COLUMN 1
BTFSS TEMP_KEY2,5     ;WAS IT ON RB5?
GOTO COLUMN2          ;IT WAS ON COLUMN 2
BTFSS TEMP_KEY2,6     ;WAS IT ON RB6?
GOTO COLUMN3          ;IT WAS ON COLUMN 3
BTFSS TEMP_KEY2,7     ;WAS IT ON RB7?
GOTO COLUMN4          ;IT WAS ON COLUMN 4
BCF INTCON,RBIF       ;CLEAR THE INTERRUPT FLAG
call finnish_pad      ;
RETFIE                ;RETURN FROM THE INTERRUPT

COLUMN1:
CLRF TEMP_KEY         ;SET KEY VALUE TO 0
MOVLW B'11101111'     ;SET THE COLUMN VALUE (RB4)
MOVWF COL             ;INTO COL REGISTER
CALL KEY_PRESS        ;GO SEE WHICH ROW IT IS ON
CALL KEY_DOWN?        ;MAKE SURE THE KEY IS RELEASED

MOVWF KEY_PRESSED     ;MOVE THE KEY PRESSED TO FILE REG

BCF INTCON,RBIF       ;CLEAR THE INTERRUPT FLAG
call finnish_pad      ;
RETFIE


COLUMN2:
MOVLW .4              ;OFFSET VALUE FOR KEY
MOVWF TEMP_KEY        ;STORE IN TEMP_KEY

MOVLW B'11011111'     ;SET THE COLUMN VALUE (RB5)
MOVWF COL             ;INTO COL REGISTER
CALL KEY_PRESS        ;GO SEE WHICH ROW IT IS ON
CALL KEY_DOWN?        ;MAKE SURE THE KEY IS RELEASED

MOVWF KEY_PRESSED     ;MOVE THE KEY PRESSED TO FILE REG

BCF INTCON,RBIF       ;CLEAR THE INTERRUPT FLAG
call finnish_pad      ;
RETFIE


COLUMN3:
MOVLW .8              ;OFFSET VALUE FOR KEY
MOVWF TEMP_KEY        ;STORE IN TEMP_KEY

MOVLW B'10111111'     ;SET THE COLUMN VALUE (RB6)
MOVWF COL             ;INTO COL REGISTER
CALL KEY_PRESS        ;GO SEE WHICH ROW IT IS ON
CALL KEY_DOWN?        ;MAKE SURE THE KEY IS RELEASED

MOVWF KEY_PRESSED     ;MOVE THE KEY PRESSED TO FILE REG

BCF INTCON,RBIF       ;CLEAR THE INTERRUPT FLAG
call finnish_pad      ;
RETFIE


COLUMN4:
MOVLW .12             ;OFFSET VALUE FOR KEY
MOVWF TEMP_KEY        ;STORE IN TEMP_KEY

MOVLW B'01111111'     ;SET THE COLUMN VALUE (RB7)
MOVWF COL             ;INTO COL REGISTER
CALL KEY_PRESS        ;GO SEE WHICH ROW IT IS ON
CALL KEY_DOWN?        ;MAKE SURE THE KEY IS RELEASED

MOVWF KEY_PRESSED     ;MOVE THE KEY PRESSED TO FILE REG

BCF INTCON,RBIF       ;CLEAR THE INTERRUPT FLAG
call finnish_pad      ;
RETFIE


KEY_PRESS:
MOVFW COL             ;GET THE COLUMN VALUE
TRIS PORTB            ;MAKE THE COLUMN AN OUTPUT

COMF COL,0            ;INVERT THE COL REGISTER
MOVWF PORTB           ;MAKE THE LINE HIGH ON YOUR COLUMN

call read_again       ;check the port for valid data

BTFSC temp_key2,0     ;WAS IT ON ROW 1?
GOTO KEY              ;YEP
INCF TEMP_KEY,1       ;INCREMENT KEY VALUE
BTFSC temp_key2,1 ,1  ;WAS IT ON ROW 2?
GOTO KEY              ;YEP
INCF TEMP_KEY,1       ;INCREMENT KEY VALUE
BTFSC temp_key2,2     ;WAS IT ON ROW 3?
GOTO KEY              ;YEP
INCF TEMP_KEY,1       ;INCREMENT KEY VALUE
BTFSC temp_key2,3     ;WAS IT ON ROW 4?
GOTO KEY              ;YEP


BCF INTCON,RBIF       ;CLEAR THE INTERRUPT FLAG
call finnish_pad      ;
RETFIE                ;RETURN FROM INTERRUPT


KEY:
MOVFW TEMP_KEY                ;CALL OUT THE VALUE OF THE KEY
ADDWF PCL                     ;ADD IT TO THE PROGRAM COUNTER
RETDATA "147*2580369#<>YN"    ;RETURNS WITH THE KEY PRESSED


;**************************************************************
; THIS CHECKS FOR A KEY DOWN!! 
;**************************************************************

KEY_DOWN?:
MOVWF TEMP_KEY         ;STORE THE KEY PRESS

CHECK_AGAIN:
MOVLW B'11110000'      ;CHECK IF BACK TO NORMAL
SUBWF PORTB,W          ; '' '' ''
BTFSS STATUS,Z         ;CHECK IF ZERO
GOTO CHECK_AGAIN       ;IF NOT THEN LOOP AGAIN

MOVLW B'11111111'      ;RESTORE THE KEYPAD TRIS REGISTER
TRIS PORTB             ; '' '' ''
MOVFW TEMP_KEY         ;RESTORE THE KEY PRESS
RETURN



;************************************************************
; This routine checks the pad for a valid key press
;************************************************************
read_AGAIN:
MOVFW PORTB             ;MOVE PORTB VALUE TO W REG

MOVWF TEMP_KEY2         ;SAVE THE PORT READING
MOVLW .250              ;DELAY TIME
CALL MDELAY             ;DELAY
MOVLW .250              ;DELAY TIME
CALL MDELAY             ;DELAY
MOVLW .250              ;DELAY TIME
CALL MDELAY             ;DELAY
MOVFW PORTB             ;READ PORT AGAIN
SUBWF TEMP_KEY2,W       ;SEE IF IT WAS THE SAME AS A MOMENT AGO
SKPZ                    ;SKIP NEXT INSTRUCTION IF ZERO
GOTO read_AGAIN         ;LOOP UNTIL A BETTER READING IS PRESENT
return



;*****************************************************
; this restores the counters 
;******************************************************

finnish_pad:
movfw temp_cnt         ;get the cnt value
movwf cnt              ;resore it
movfw temp_cnt2        ;get the cnt value
movwf cnt2             ;resore it
movfw temp_cnt3        ;get the cnt value
movwf cnt3             ;resore it
movfw temp_cnt4        ;get the cnt value
movwf cnt4             ;resore it
return                 ;return