Professional Documents
Culture Documents
version 2, 2001/10/22
designed by Jap
NOTE for beginners: PICs are general purpose microcontrollers which have to be programmed
before you can use them in the actual circuit! Check out this link to learn more.
description
This is my electronic codelock to use with an outdoor gate. The lock itself is implemented in
software. It operates a relay (for example to open a door) for a few seconds if someone enters
the valid code. This relay can operate a power-to-open type electric strike with a shorting
contact or a power-to-hold type electromagnetic lock with a breaking contact (these usually
work with AC, not DC). The secret code can be changed any time after entering the current
code. Note that in this application it's not necessary to make an exact clock frequency with
crystal (as seen on the schematic diagram), you can also use an RC type oscillator or other
crystals.
I have the codelock design on my webpage for long and it is really poular. But it had some
weaknesses like source code complexity, it needed an external 74LS138 and diodes because it
was built on a general protoboard. Therefore I totally rewrote and redesigned it with simplicity
in mind. The old design is still available here.
software
The source code is freely downloadable. This is written for the PIC16F84, but you can easily
adapt it to newer controllers like the 16F628, OTP versions with or without internal EEPROM.
The first few lines contain the definitions of changeable parameters. If you are lazy, here is a
compiled HEX file of the source intended to use with 10MHz crystal and P16F84(A). The
codelock will work fine regardless of the actual frequency (the crystal you use) of PIC running,
but the timing loop is calibrated to the frequency defined in the code (10MHz). More details on
the source code can be found here.
operation
FAQ
troubleshooting
schematic diagram
CODIGO FUENTE
;**********************************************************************
; *
; Filename: cl2.asm *
; Date: *
; File Version: Codelock rewritten *
; *
; Author: el@jap.hu *
; http://jap.hu/electronic/ *
;**********************************************************************
;NOTES
;
; the rewritten codelock has the following changes:
;
; - no multiplexer is needed (the old version used a generic devboard)
; - no row diodes needed (rows are never driven HIGH)
; - low power consumption due to keyboard wake-up
; - stores the code in the internal EEPROM
; - user defined codelength and pulse output
; - user adjustable running frequency
; - improved code changing function with a "change" indicator LED
;
; PIC ports used:
;
; PA0-3 outputs: row select pulldown outputs (tristate or driven LOW)
; PB1 output: code change indicator LED
; PB2 output: output pulse to control a relay
; PB3 output: piezo beeper output
; PB4-PB7 inputs: column inputs with internal pullup
;
;**********************************************************************
;HISTORY
;
; 020-20010929 rewrite started
; 021-20011022 udelay calibrated to 100 usec (4, 10 MHz)
; 022-20011022 scan, input and compare functions work
; 023-20011022 code change function works
;
;**********************************************************************
list p=16f84a
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC
#include <p16F84a.inc>
; EEPROM contents
ORG 0x2100
de "123456" ; default code (clen chars are used)
; which is stored in EEPROM
; RAM registers
ram_start EQU 0x0c
dcnt0 EQU ram_start+1 ; delay counter 0
dcnt1 EQU ram_start+2 ; delay counter 1
dcnt2 EQU ram_start+3 ; delay counter 2
beepcnt EQU ram_start+4 ; beep cycle counter
keycode EQU ram_start+5
rowcnt EQU ram_start+6
colcnt EQU ram_start+7
colstatus EQU ram_start+8
cod EQU ram_start+9 ; actual code
cod_end EQU cod+clen
vectors ORG 0
goto main
nop
nop
nop
retfie
incf FSR, F
incf EEADR, F
movlw cod_end
subwf FSR, W
bnz eep_0
return
incf FSR, F
incf EEADR, F
movlw cod_end
subwf FSR, W
bnz eep_1
return
decfsz dcnt0, F
goto udelay0
return
movlw 0xfe
tris PORTA ; select row 0
movlw 4
movwf colcnt
decfsz colcnt, F
goto colscan
bsf STATUS, C
decfsz rowcnt, F
goto rowscan
retlw 0 ; no key was found
movlw '*'
subwf keycode, W ; * changes code
bz codechange
movlw pulsewidth
movwf dcnt2
goto loop
movlw cod
call copybuf ; copy new code into cod
key_pressed
call keyscan
andlw 0xff
movwf keycode
bz readloop
read_notenter
; buffer is full, but more characters entered
; shift the buffer
movlw readbuf+1
movwf FSR
decf readlen, F
movlw 0x40
call beep
movlw readbuf
addwf readlen, W
movwf FSR
movf keycode, W
movwf INDF
incf readlen, F
goto readloop
movf tmptr, W
addwf readlen, W
movwf FSR
movf INDF, W ; the byte readbuf is compared to
subwf tmbyte, W
btfss STATUS, Z
return ; Z=0: the code is different
incf readlen, F
movlw clen
subwf readlen, W
bnz comp0 ; compare next character
; Z=1: the code is the same
return
movf tmptr, W
addwf readlen, W
movwf FSR
movf tmbyte, W ; the byte from readbuf
movwf INDF
incf readlen, F
movlw clen
subwf readlen, W
bnz copy0 ; copy next character
return
end
keytable: subroutine 82-89
input = scancode of key ( = row * 4 + column + 1) in keycode
output = ASCII code of key
keycode = 0, rowcnt = 4
select row 0 (pull PA0 pin low, float PA1, PA2, PA3)
rowscan: scan a selected keyboard row for a pressed key
delay 100 ms (debounce delay & charge row)
read PB4-PB7 pins as column inputs from the row into colstatus
colcnt = 4
colscan: keycode = keycode + 1 (keycode is the scancode of the actual key checked)
rotate right colstatus bits
if the lowest bit was 0, a pressed key is found: exit with sub keytable
otherwise colcnt = colcnt - 1
if colcnt > 0, goto label colscan
otherwise select next row (pull the according PA# pin low, float others)
rowcnt = rowcnt - 1
if rowcnt > 0, goto label rowscan
return with 0: no key found pressed
main: 208-217
program execution starts here
setup PORTA, PORTB pin states
warm: 219-221
generate a beep, indicating that the program is running
call subroutine eep_read to read the actual code from EEPROM
loop: 223-
program main loop
clear all PORTB pins
call subroutine read to read a code from the keyboard
call subroutine compbuf to compare the code read in with the actual code
if combuf returned with * as last character entered, goto codechange
otherwise
pulseout: send out a pulse on PB2 pin. Use the defined pulsewidth variable as
delay in 20 ms steps. Go back to loop when finished
compare the read buffer with the given buffer, set flag Z