Here is code to scan a 5 column by 4 row keyboard for the PIC16C84 using port B.
I used a key pannel from a Tandy toy mobile phone. The code flashes out the key code on a bi colour LED, as about 1 or two flashes a seconds. The toy phone has been powered up for a couple of years on a pair of duracells, mainly in sleep mode. It is one of my early bits of code, but is still a demonstrator and I have not taken the code any further. However, it may be of interest to other piccy people.RB0 to RB3 are configured as outputs and pull the columns low.
The code below just uses PORTB. It would be better if these were 'open Collector' so only made outputs when pulled by using the TRISB register. See the Minidisc Controller code.RB4 to RB7 are inputs using weak pull up.
To find out which key is pressed, first see if any input is low, then repeat for each column.
If any input is found low, establish which row it is pulled low.
; Key matrix ; |1 |2 |3 |menu |send ; RB7 6 ->------+-------+-------+-------+-------+----- ; |4 |5 |6 |clr | ; RB6 7 ->------+-------+-------+-------+-------+----- ; |7 |8 |9 |rcl | ; RB5 8 ->------+-------+-------+-------+-------+----- ; |* |0 |# | |end ; RB6 9 ->------+-------+-------+-------+-------+----- ; | | | | | ; v v v v v ; | | | | | ; 1 2 3 4 5 ; RB0 RB1 RB2 RB3 Gnd ; ; Connection RB0, 1, 2, 3, 4, 5, 6, 7, gnd ; to a, b, c, d, e, f, g, h, i ; 000 00 00 not pressed ; 001 00 04 1 ; 001 01 05 4 ; 001 10 06 7 ; 001 11 07 * ; 010 00 04 2 ; 010 01 05 5 ; 010 10 06 8 ; 010 11 07 0 ; 011 00 04 3 ; 011 01 05 6 ; 011 10 06 9 ; 011 11 07 # ; 100 00 10 menu ; 100 01 11 clr ; 100 10 12 rcl ; 101 00 14 SEND ; 101 11 17 ENDpwr
;**************************************************************************
;
; NOTE THE DELAYS HAVE BEEN SHORTEND FOR DEBUGGING
;
; Keymat.ASM
;
; Description: Key Matrix Reader
;
; Author: Doug Rice
;
;
;
; I/O used:-
; PORTA<2> LED DUAL RED
; PORTA<1> LED DUAL GEEN
; PORTA<0> LED FLAG
;
; The Keyboard matrix can be 5 columns by 4 rows
; the 4 row inputs can go low when a switch to the currently
; low column output.
; If all columns are high, and a row input is low,
; the switch could be connected to ground.
;
; GND
; PORTB:0 Output column output
; PORTB:1 Output column output
; PORTB:2 Output column output
; PORTB:3 Output column output
; PORTB:4 Input row Input
; PORTB:5 Input row Input
; PORTB:6 Input row Input
; PORTB:7 Input row Input
;
; Look for a low input, if not low scan through columns in
; turn, until any row goes low. Then find out which row is
; low, and finish.
;
; Currently, this does not produce an event. It always reports
; if the key is pressed.
;
; It could pull all colums low, and look for a key press.
; If any are pressed then rescan.
; Or else it could scan, and if the new results = old key
; don't report new key.
;
; Using the bit array, such that when an event occurs
; the bit is set.
; Poll around the bit array and jump off to the corresponding
; event routine.
;
; The event routine clears the event bit.
;
;
;
;
; PIC16c84 Clocked using RC at ~ 125kHz ( 1Mhz / 8 )
; Instructions at 31.25 instructions per milli second.
;
; If internal Counter clocks then it times out 122 times per second
;
;
;
;**************************************************************************
LIST P=16C84, R=DEC
INCLUDE "p16f84.inc"
__idlocs 0x1000
; __config _XT_OSC&_PWRTE_ON
;--------------------------------------------------------------------------
;--------------------------------------------------------------------------
; Sec 1.0 Equates and Constants
;--------------------------------------------------------------------------
; The General Purpose Registers start at the end of the
; Special Purpose Registers.
ScratchPadRam EQU 0x0C
KBDmask EQU ScratchPadRam +0
KBDread EQU ScratchPadRam +1
LEDdisp EQU PORTA
KBDmatrix EQU ScratchPadRam +2
;KBDmatrix EQU PORTB
leakyBucket EQU ScratchPadRam +4
DelayMSB EQU ScratchPadRam +5
DelayLSB EQU ScratchPadRam +6
Count EQU ScratchPadRam +7
LastKey EQU ScratchPadRam +8
;--------------------------------------------------------------------------
; Sec 2.0 Variables
;--------------------------------------------------------------------------
;--------------------------------------------------------------------------
; Sec 3. Program Code
;--------------------------------------------------------------------------
ORG 0
GOTO Start
ORG 4
GOTO IntRtn
;--------------------------------------------------------------------------
; Sec 3.1 Main Program Init Code
;--------------------------------------------------------------------------
ORG H'08'
Start
; Enable Interupts, Disable General, but enable RB key Change Interupt
CLRF INTCON
BSF INTCON,RBIE
MOVLW 0xFF
MOVWF PORTB
; Set up Ports for inputs and output.
BSF STATUS, RP0
MOVLW 0xF0
MOVWF TRISB
MOVLW 0x00
MOVWF TRISA
BCF STATUS, RP0
; Change Prescaler
CLRWDT
; Configure Tmr 0
BSF STATUS,RP0
; Set up prescaller for 8192 / 4 = 2048 ticks per seconds.
; or overflow every 125 ms
MOVLW 0x0 + 1 ; For Tmr0 0=/2, 1=/4, 2=/8,3=/16
MOVWF OPTION_REG
BCF STATUS,RP0
CLRF KBDmatrix
CLRF KBDread
CLRF KBDmask
; GOTO MainLoop
MLinitLoop
MainLoop
; BCF INTCON,RBIF
MOVFW KBDmatrix
; BCF INTCON,RBIF
CLRWDT
SLEEP
NOP
BCF INTCON,RBIF
; GOTO MainLoop
KBDscan
; This routine establishes which key is currently pressed.
; It does not differentiate new keys.
;
; Work through 5 columns.
MOVLW 0x05
MOVWF KBDread
MOVLW 0xEF ; to produce sequence 1111,0111,1011,1101,1110
MOVWF KBDmask
; Check if any switch pressed.
MOVLW 0xF0 ; pull low all columns
MOVWF KBDmatrix
; 4 MSB are inputs, 4 LSB are outputs
; One of the 4 MSB will be pulled low by switch
; This will delay 3 cycles * 1/4 Clk Rate - for clk = 1/8 Mhz delay = 24 ms
CLRF DelayLSB
INCFSZ DelayLSB
KBDdebounceDelay1
DECFSZ DelayLSB,F ; 1 cycles
GOTO KBDdebounceDelay1 ; 2 cycles
XORWF KBDmatrix,w
BZ KBDnokeys
; This will delay 3 cycles * 1/4 Clk Rate - for clk = 1/8 Mhz delay = 24 ms
CLRF DelayLSB
; next is for debug to shorten the delay
INCFSZ DelayLSB,F ; 1 cycles
KBDdebounceDelay2
DECFSZ DelayLSB,F ; 1 cycles
GOTO KBDdebounceDelay2 ; 2 cycles
KBDloop
MOVFW KBDmask
IORLW 0xF0
MOVWF KBDmatrix
SETC
RRF KBDmask,f
; Now are any keys pressed?
; 4 MSB are inputs, 4 LSB are outputs
; One of the 4 MSB will be pulled low by switch
XORWF KBDmatrix,w
BNZ KBDanalyze
; No so prepare to look at next row
; copy mask onto keys
; inc Column Counter
DECFSZ KBDread,f
GOTO KBDloop
KBDnokeys
; No keys found pressed
CLRF KBDread
GOTO KBDnotFound
KBDanalyze
; quadruple Column Count, so that the row count
; can fill the bottom 2 bits
; 000CCCRR
CLRC
RLF KBDread,f
RLF KBDread,f
; The Column is held low, so which Row?
BTFSS KBDmatrix,4
GOTO KBDfound
INCF KBDread,f
BTFSS KBDmatrix,5
GOTO KBDfound
INCF KBDread,f
BTFSS KBDmatrix,6
GOTO KBDfound
INCF KBDread,f
BTFSS KBDmatrix,7
GOTO KBDfound
; No key is found
CLRF KBDread
KBDnotFound
; Turn Off Red all LEDS
MOVLW 1
MOVWF LEDdisp
; Instruction Rate = 32k
CALL Delay
; Now Flash out Key Code on DUAL LED
MOVLW 7
MOVWF LEDdisp
MOVLW 8
MOVWF Count
CALL Delay
MOVLW 1
MOVWF LEDdisp
; Instruction Rate = 32k
CALL Delay
CALL Delay
KBDnotFound1
MOVLW 1
MOVWF LEDdisp
; Test Most Significant Bit
BTFSC LastKey,7
BSF LEDdisp,1
BTFSS LastKey,7
BSF LEDdisp,2
;Rotate
RLF LastKey,f
; Instruction Rate = 32k
CALL Delay
; Turn Off LED
MOVLW 1
MOVWF LEDdisp
CALL Delay
DECFSZ Count,f
GOTO KBDnotFound1
; Turn Off LED
MOVLW 1
MOVWF LEDdisp
CLRF LastKey
GOTO MainLoop
Delay
; RETURN
; Instruction Rate = 32k
CLRF DelayMSB
CLRF DelayLSB
MOVLW 0x40
MOVWF DelayMSB
Delay1
DECFSZ DelayLSB,F
GOTO Delay1
Delay2
DECFSZ DelayMSB,F
GOTO Delay1
RETURN
KBDfound
MOVFW KBDread
MOVWF LastKey
; Turn On Red LED
MOVLW 0
MOVWF LEDdisp
; Do a bit of debounce
CALL Delay
GOTO MainLoop
IntRtn
RETFIE
;--------------------------------------------------------------------------
; Sec 5. End
;--------------------------------------------------------------------------
; Key matrix
; |1 |2 |3 |menu |send
; RB7 6 --------+-------+-------+-------+-------+-----
; |4 |5 |6 |clr |
; RB6 7 --------+-------+-------+-------+-------+-----
; |7 |8 |9 |rcl |
; RB5 8 --------+-------+-------+-------+-------+-----
; |* |0 |# | |end
; RB6 9 --------+-------+-------+-------+-------+-----
; | | | | |
; | | | | |
; 1 2 3 4 5
; RB0 RB1 RB2 RB3 Gnd
;
; Connection RB0, 1, 2, 3, 4, 5, 6, 7, gnd
; to a, b, c, d, e, f, g, h, i
; 000 00 00 not pressed
; 001 00 04 1
; 001 01 05 4
; 001 10 06 7
; 001 11 07 *
; 010 00 04 2
; 010 01 05 5
; 010 10 06 8
; 010 11 07 0
; 011 00 04 3
; 011 01 05 6
; 011 10 06 9
; 011 11 07 #
; 100 00 10 menu
; 100 01 11 clr
; 100 10 12 rcl
; 101 00 14 SEND
; 101 11 17 ENDpwr
END