📄 mplxkey.asm
字号:
;*********************************************************************
;This program is to demonstrate how to multiplex four 7 segment LED
;digits and a 4X4 keypad using a PIC16C71.
;The four digits will start as '0000' and when a key is hit
;it is displayed on the 7 segment leds as a hex value 0 to F. The last
;digit hit is always displayed on the right most led with the rest of
;the digits shifted to the left. The left most digit is deleted.
;The LEDs are updated every 20mS, the keypad is scanned at a rate of 20 mS.
;The RTCC timer is used in internal interrupt mode to generate the
;5 mS.
;
; Stan D'Souza 5/8/93
;
; Program: MPLXKEY.ASM
; Revision Date:
; 1-15-97 Compatibility with MPASMWIN 1.40
;
;**********************************************************************
LIST P=16C71
ERRORLEVEL -302
;
include <p16c71.inc>
;
TempC equ 0x0c ;temp general purpose regs
TempD equ 0x0d
TempE equ 0x0e
PABuf equ 0x20
PBBuf equ 0x21
Count equ 0x0f ;count
MsdTime equ 0x10 ;most significant Timer
LsdTime equ 0x11 ;Least significant Timer
KeyFlag equ 0x12 ;flags related to key pad
keyhit equ 0 ;bit 0 --> key-press on
DebnceOn equ 1 ;bit 1 --> debounce on
noentry equ 2 ;no key entry = 0
ServKey equ 3 ;bit 3 --> service key
Debnce equ 0x13 ;debounce counter
NewKey equ 0x14
WBuffer equ 0x2f
StatBuffer equ 0x2e
OptionReg equ 1
PCL equ 2
;
;
push macro
movwf WBuffer ;save w reg in Buffer
swapf WBuffer, F ;swap it
swapf STATUS,W ;get status
movwf StatBuffer ;save it
endm
;
pop macro
swapf StatBuffer,W ;restore status
movwf STATUS ; /
swapf WBuffer,W ;restore W reg
endm
;
org 0
goto Start ;skip over interrupt vector
;
org 4
;It is always a good practice to save and restore the w reg,
;and the status reg during a interrupt.
push
call ServiceInterrupts
pop
retfie
;
Start
call InitPorts
call InitTimers
loop
btfsc KeyFlag,ServKey ;key service pending
call ServiceKey ;yes then service
goto loop
;
;ServiceKey, does the software service for a keyhit. After a key service,
;the ServKey flag is reset, to denote a completed operation.
ServiceKey
movf NewKey,W ;get key value
movwf TempE ;save in TempE
swapf MsdTime,W ;move MSD out
andlw B'11110000' ;clr lo nibble
movwf MsdTime ;save back
swapf LsdTime,W ;get Lsd
andlw B'00001111' ;mask off lsd
iorwf MsdTime, F ;and left shift 3rd
swapf LsdTime,W ;get Lsd again
andlw B'11110000' ;mask off 2nd
iorwf TempE,W ;or with new lsd
movwf LsdTime ;make Lsd
bcf KeyFlag,ServKey ;reset service flag
return
;
InitPorts
bsf STATUS,RP0 ;select pg 1
movlw 3 ;make RA0-3 digital I/O
movwf ADCON1 ; /
clrf TRISA ;make RA0-4 outputs
clrf TRISB ;make RB0-7 outputs
bcf STATUS,RP0 ;select page 0
clrf PORTA ;make all outputs low
clrf PORTB ; /
bsf PORTA,3 ;enable MSB digit sink
return
;
;
;The clock speed is 4.096Mhz. Dividing internal clk. by a 32 prescaler,
;the rtcc will be incremented every 31.25uS. If rtcc is preloaded
;with 96, it will take (256-96)*31.25uS to overflow i.e. 5mS. So the
;end result is that we get a rtcc interrupt every 5mS.
InitTimers
clrf MsdTime ;clr timers
clrf LsdTime ; /
clrf KeyFlag ;clr all flags
bsf STATUS,RP0 ;select pg 1
movlw B'10000100' ;assign ps to rtcc
movwf OptionReg ;ps = 32
bcf STATUS,RP0 ;select pg 0
movlw B'00100000' ;enable rtcc interrupt
movwf INTCON ;
movlw .96 ;preload rtcc
movwf TMR0 ;start counter
retfie
;
ServiceInterrupts
btfsc INTCON,T0IF ;rtcc interrupt?
goto ServiceTMR0 ;yes then service
clrf INTCON ;else clr all int
bsf INTCON,T0IE
return
;
ServiceTMR0
movlw .96 ;initialize rtcc
movwf TMR0
bcf INTCON,T0IF ;clr int flag
btfsc PORTA,0 ;if msb on then do
call ScanKeys ;do a quick key scan
call UpdateDisplay ;update display
return
;
;
;ScanKeys, scans the 4X4 keypad matrix and returns a key value in
;NewKey (0 - F) if a key is pressed, if not it clears the keyhit flag.
;Debounce for a given keyhit is also taken care of.
;The rate of key scan is 20mS with a 4.096Mhz clock.
ScanKeys
btfss KeyFlag,DebnceOn ;debounce on?
goto Scan1 ;no then scan keypad
decfsz Debnce, F ;else dec debounce time
return ;not over then return
bcf KeyFlag,DebnceOn ;over, clr debounce flag
return ;and return
Scan1
call SavePorts ;save port values
movlw B'11101111' ;init TempD
movwf TempD
ScanNext
movf PORTB,W ;read to init port
bcf INTCON,RBIF ;clr flag
rrf TempD, F ;get correct column
btfss STATUS,C ;if carry set?
goto NoKey ;no then end
movf TempD,W ;else output
movwf PORTB ;low column scan line
nop
btfss INTCON,RBIF ;flag set?
goto ScanNext ;no then next
btfsc KeyFlag,keyhit ;last key released?
goto SKreturn ;no then exit
bsf KeyFlag,keyhit ;set new key hit
swapf PORTB,W ;read port
movwf TempE ;save in TempE
call GetKeyValue ;get key value 0 - F
movwf NewKey ;save as New key
bsf KeyFlag,ServKey ;set service flag
bsf KeyFlag,DebnceOn ;set flag
movlw 4
movwf Debnce ;load debounce time
SKreturn
call RestorePorts ;restore ports
return
;
NoKey
bcf KeyFlag,keyhit ;clr flag
goto SKreturn
;
;GetKeyValue gets the key as per the following layout
;
; Col1 Col2 Col3 Col3
; (RB3) (RB2) (RB1) (RB0)
;
;Row1(RB4) 0 1 2 3
;
;Row2(RB5) 4 5 6 7
;
;Row3(RB6) 8 9 A B
;
;Row4(RB7) C D E F
;
GetKeyValue
clrf TempC
btfss TempD,3 ;first column
goto RowValEnd
incf TempC, F
btfss TempD,2 ;second col.
goto RowValEnd
incf TempC, F
btfss TempD,1 ;3rd col.
goto RowValEnd
incf TempC, F ;last col.
RowValEnd
btfss TempE,0 ;top row?
goto GetValCom ;yes then get 0,1,2&3
btfss TempE,1 ;2nd row?
goto Get4567 ;yes the get 4,5,6&7
btfss TempE,2 ;3rd row?
goto Get89ab ;yes then get 8,9,a&b
Getcdef
bsf TempC,2 ;set msb bits
Get89ab
bsf TempC,3 ; /
goto GetValCom ;do common part
Get4567
bsf TempC,2
GetValCom
movf TempC,W
addwf PCL, F
retlw 0
retlw 1
retlw 2
retlw 3
retlw 4
retlw 5
retlw 6
retlw 7
retlw 8
retlw 9
retlw 0a
retlw 0b
retlw 0c
retlw 0d
retlw 0e
retlw 0f
;
;SavePorts, saves the porta and portb condition during a key scan
;operation.
SavePorts
movf PORTA,W ;Get sink value
movwf PABuf ;save in buffer
clrf PORTA ;disable all sinks
movf PORTB,W ;get port b
movwf PBBuf ;save in buffer
movlw 0xff ;make all high
movwf PORTB ;on port b
bsf STATUS,RP0 ;select page 1
bcf OptionReg,7 ;enable pull ups
movlw B'11110000' ;port b hi nibble inputs
movwf TRISB ;lo nibble outputs
bcf STATUS,RP0 ;page 0
return
;
;RestorePorts, restores the condition of porta and portb after a
;key scan operation.
RestorePorts
movf PBBuf,W ;get port n
movwf PORTB
movf PABuf,W ;get port a value
movwf PORTA
bsf STATUS,RP0 ;select page 1
bsf OptionReg,7 ;disable pull ups
clrf TRISA ;make port a outputs
clrf TRISB ;as well as PORTB
bcf STATUS,RP0 ;page 0
return
;
;
UpdateDisplay
movf PORTA,W ;present sink value in w
clrf PORTA ;disable all digits sinks
andlw 0x0f
movwf TempC ;save sink value in tempC
bsf TempC,4 ;preset for lsd sink
rrf TempC, F ;determine next sink value
btfss STATUS,C ;c=1?
bcf TempC,3 ;no then reset LSD sink
btfsc TempC,0 ;else see if Msd
goto UpdateMsd ;yes then do Msd
btfsc TempC,1 ;see if 3rdLsd
goto Update3rdLsd ;yes then do 3rd Lsd
btfsc TempC,2 ;see if 2nd Lsd
goto Update2ndLsd ;yes then do 2nd lsd
UpdateLsd
movf LsdTime,W ;get Lsd in w
andlw 0x0f ; /
goto DisplayOut
Update2ndLsd
swapf LsdTime,W ;get 2nd Lsd in w
andlw 0x0f ;mask rest
goto DisplayOut ;enable display
Update3rdLsd
movf MsdTime,W ;get 3rd Lsd in w
andlw 0x0f ;mask low nibble
goto DisplayOut ;enable display
UpdateMsd
swapf MsdTime,W ;get Msd in w
andlw 0x0f ;mask rest
DisplayOut
call LedTable ;get digit output
movwf PORTB ;drive leds
movf TempC,W ;get sink value in w
movwf PORTA
return
;
;
LedTable
addwf PCL, F ;add to PC low
retlw B'00111111' ;led drive for 0
retlw B'00000110' ;led drive for 1
retlw B'01011011' ;led drive for 2
retlw B'01001111' ;led drive for 3
retlw B'01100110' ;led drive for 4
retlw B'01101101' ;led drive for 5
retlw B'01111101' ;led drive for 6
retlw B'00000111' ;led drive for 7
retlw B'01111111' ;led drive for 8
retlw B'01100111' ;led drive for 9
retlw B'01110111' ;led drive for A
retlw B'01111100' ;led drive for b
retlw B'00111001' ;led drive for C
retlw B'01011110' ;led drive for d
retlw B'01111001' ;led drive for E
retlw B'01110001' ;led drive for F
;
;
end
;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -