'************************************************* ************
'* Name : garage door unlock *
'* Author : Fred *
'* Date : 07/12/2006 *
'* Version : 1.A.5 *
'* Notes : this code will unlock after the correct code *
'* : sequence. It will remember the code even if *
'* : power goes out by writing the unlock code to *
'* : EEPROM. It uses the standard 12 key - keypad *
'* : but can be easily modified to use any keypad. *
'* : There are a lot of LCD commands I used to *
'* : debug but they can be take out easily. If *
'* : someone improves this GREAT!! That's the idea *
'* : You enter the correct code then press * to *
'* : to unlock. # resets the sequence. You program *
'* : by grounding the PortA.2 pin then enter code *
'* : followed by * then unground pin. It makes a *
'* : relay for 1/2 second which connects to door *
'* : switch to open or close garage door when you *
'* : correct code number *
'************************************************* ************
'Pin 1 RA2 - Switch to progam code
'Pin 2 RA3 - Relay 1 output
'Pin 3 RA4 - Relay 2 output
'Pin 4 RA5/MCLR - Hard reset switch
'Pin 5 VSS - Grd
'Pin 6 RB0 - Row 1
'Pin 7 RB1 - Row 2
'Pin 8 RB2 - Row 3
'Pin 9 RB3 - Row 4
'Pin 10 RB4 - Col 1
'Pin 11 RB5 - Col 2
'Pin 12 RB6 - Col 3
'Pin 13 RB7 - LED output
'Pin 14 VDD - +5
'Pin 15 RA6 - Clock in
'Pin 16 RA7 - Clock
'Pin 17 RA0 - Serial data out
'Pin 18 RA1 - output to spkr connection
INCLUDE "modedefs.bas"

DEFINE OSC 20
Col VAR BYTE ' Keypad column
Row VAR BYTE ' Keypad row
Key VAR BYTE ' Key value
SerPin VAR PortA.0 ' Serial output pin
KeyCode var byte
LED VAr PortB.7
Relay1 var PortA.3
Relay2 var PortA.4
CMCON = 7 ' PortA = digital I/O
VRCON = 0 ' Voltage reference disabled
OPTION_REG.7 = 0 ' Enable PORTB pull-ups
SetCode VAR BYTE
OldCode VAR BYTE[11]
NewCode VAR BYTE[10]
LoopCount VAR BYTE
NumDig VAR BYTE
Unlock VAR BYTE
ProgramSwitch var PortA.2
input programswitch

Setcode = 1
unlock = 1
Read 100,numdig 'Read number of digits of unlock code from memory
For loopcount = 1 to numdig ' Read unlock code from memory
Read loopcount,oldcode[loopcount]
Next loopcount


Loop:
GOSUB getkey 'Get key from keypad
key = key - 1
LookUp key,["123456789*0#"],keycode ' Lookup table to decode key press

Newcode[setcode] = keycode

IF programswitch = 1 Then ' If this port high then program unlock code
high led

serout serpin,N9600,[254,1] 'keycode is the number
serout serpin,N9600,[254,128]
SEROUT serpin,N9600,["location is "]'Send key value out
serout serpin,N9600,[#setcode]
serout serpin,N9600,[254,192]
SEROUT serpin,N9600,["key is "]'Send key value out
serout serpin,N9600,[keycode]
IF keycode = "*" Then ' If key is a star end the program code
numdig = (setcode - 1)

serout serpin,N9600,[254,1] 'keycode is the number
serout serpin,N9600,[254,128]
SEROUT serpin,N9600,["numdig is "]'Send key value out
serout serpin,N9600,[#numdig]
pause 3000
Write 100,(numdig) 'setcode is number of digits of unlock number
for loopcount = 1 to Numdig
write loopcount,newcode[loopcount]
serout serpin,N9600,[254,1]
SEROUT serpin,N9600,[254,128] 'Send key value out
serout serpin,N9600,["loopcount is "]
SEROUT serpin,N9600,[#loopcount]'Send key value out
SEROUT serpin,N9600,[254,192] 'Send key value out
serout serpin,N9600,["new "]
SEROUT serpin,N9600,[(newcode[loopcount])]'Send key value out
oldcode[loopcount] = newcode[loopcount]
serout serpin,N9600,["-old "]
serout serpin,N9600,[(oldcode[loopcount])]
pause 3000
next
Setcode = 1
low led
GoTo loop
EndIF
Setcode = setcode + 1
GoTo Loop
EndIF



IF keycode = "#" Then ' Zero's the number of digits counter,
setcode = 1 'functions as a key reset
unlock = 1
serout serpin,N9600,[254,1]
goto loop
endif

IF keycode = "*" Then ' If key is a star try to unlock door
For loopcount = 1 to Numdig
IF Newcode[loopcount] = oldcode[loopcount] Then
unlock = unlock + 1
IF unlock = Numdig Then ' If code matches unlock the door
high led ' LED shows unlock status, 1=LED on
high relay1 ' unlock relay on
serout serpin,N9600,[254,1]
serout serpin,N9600,[254,128]
serout serpin,N9600,["Door Unlocked"]
serout serpin,N9600,[254,192]
SEROUT serpin,N9600,[keycode]'Send key value out
Pause 500
For Loopcount = 1 to 10 ' Zero out keycode
Newcode[loopcount] = "E"
Next Loopcount
unlock = 1 ' Reset unlock
setcode = 1 ' Reset digit codes
low led ' Unlock LED off
low relay1 ' unlock relay off
goto loop
EndIF
Else
Setcode = 1
Unlock = 1
GoTo loop
EndIF
Next Loopcount
EndIF

if setcode > numdig then setcode = 1

Setcode = setcode + 1

gosub send
GoTo loop

Send:
serout serpin,N9600,[254,128]
SEROUT serpin,N9600,[#setcode]'Send key value out
SEROUT serpin,N9600,[254,192]'Send key value out
SEROUT serpin,N9600,[#Numdig]'Send key value out
return

GetKey:
PAUSE 50 'Debounce key-input
GetKeyu:' Wait for all keys up
PORTB = 0 ' All output-pins low
TRISB = $f0 ' Bottom 4-pins out, top 4-pins in
IF ((PORTB >> 4) != $f) THEN getkeyu'If keys down, loop
PAUSE 50 ' Debounce key-input

GetKeyp:' Wait for keypress
FOR row = 0 TO 3 ' 4 rows in keypad
PORTB = 0 ' All output-pins low
TRISB = (DCD row) ^ $ff ' Set one row pin to output
col = PORTB >> 4 ' Read columns
IF col != $f THEN gotkey' If any keydown, exit
NEXT row
GOTO getkeyp ' No keys down, go look again

GotKey: ' Change row and column to key number 1 - 16
key = (row * 3) + (NCD (col ^ $f))
'NOTE: for 12-key keypad, change to key = (row * 3) 16 key * 4
RETURN ' Subroutine over
Resume
END