image

Keyboard reader

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

The Code

;**************************************************************************
;
;	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