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