微芯公司生产的PIC8位COMS单片机,采用类RISC指令集和哈弗总线结构,以及先进的流水线时序,与传统51单片机相比其在速度和性能方面更具优越性和先进性。 PIC单片机的另一个优点是片上硬件资源丰富,集成常见的EPROM、DAC、PWM以及看门狗电路。这使得硬件电路的设计更加简单,节约设计成本,提高整机性能。因此PIC单片机已成为产品开发,尤其是产品设计和研制阶段的首选控制器。 本文介绍用PIC16F84单片机制作的电子密码锁。PIC16F84单片机共18个引脚,13个可用I/O接口。芯片内有1K×14的FLASHROM程序存储器,36×8的静态RAM的通用寄存器,64×8的EEPROM的数据存储器,8级深度的硬堆栈。 硬件设计 电路原理见图1。Xx8位数据线接4x4键盘矩阵电路,面板布局见表1,A、B、C、D为备用功能键。RA0、RA7输出4组编码二进制数据,经74LS139译码后输出逐行扫描信号,送RB4-RB7列信号输入端。余下半个139译码器动扬声器。RB2接中功率三极管基极,驱动继电器动作。有效密码长度为4位,根据实际情况,可通过修改源程序增加密码位数。产品初始密码为3345,这是一随机数,无特殊意义,目的是为防止被套解。用户可按*号键修改密码,按#号键结束。输入密码并按#号确认之后,脚输出RB2脚输出高电平,继电器闭合,执行一次开锁动作。 若用户输入的密码正确,扬声器发出一声稍长的“滴”提示声,若输入的密码与上次修改的不符,则发出短促的“滴”声。连续3次输入密码错误之后,程序锁死,扬声器报警。直到CPU被复位或从新上电。 软件设计 软件流程图见图3。CPU上电或复位之后将最近一次修改并保存到EEPROM的密码读出,最为参照密匙。然后等待用户输入开锁密码。若5分钟以内没有接受到用户的任何输入,CPU自动转入掉电模式,用户输入任意值可唤醒CPU。 每次修改密码之后,CPU将新的密码存入内部4个连续的EEPROM单元,掉电后该数据任有效。每执行一次开锁指令,CPU将当前输入密码与该值比较,看是否真确,并给出相应的提示和控制。 布 局 所有元件均使用SMD表贴封装,缩小体积,便于产品安装,60X60双面PCB板,顶层是一体化输入键盘,底层是元件层。成型后的产品体积小巧,能很方便的嵌入防盗铁门、保险箱柜。 | COL0 | COL1 | COL2 | COL3 | ROW0 | 1 | 2 | 3 | A | ROW1 | 4 | 5 | 6 | B | ROW2 | 7 | 8 | 9 | C | ROW3 | * | 0 | # | D |
表1
源程序:- ;鉴于某些原因,本程序仅仅供参考,如有不便请谅解!
- ; HISTORY
- ;
- ; 002 - 2000 - original codelock source
- ; 003 - 2000 - serial terminal version
- ; 004 - 20010103 - cleaned up version without the serial junk, doesn't use EEPROM
- ;**********************************************************************
- ;
- ; Notes:
- ;
- ;PORTA<1:0> out row select (1-4) to MPX
- ;PORTA2 out LED control
- ;PORTB3 beeper control output
- ;PORTB<7:4> in keyboard column status
- ;PORTB2 relay output
- list p=16F84 ; list directive to define processor
- #include <p16F84.inc> ; processor specific variable definitions
- __CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC ;WDT=watchdog, PWRTE=power on timer, HS=high speed osc
- CBLOCK 0x0C
- ;***** VARIABLE DEFINITIONS
- row_cnt ;row counter
- column ;keyboard column status
- count1 ;column counter for the keyboard handler
- count2 ;row counter timing
- count3 ;row counter timing
- keycode
- prevcode
- led_ctl ; LED control bits <3:0>
- led_tmp ; working register for setting multiplexed LED control pin
- keybuf ; keyboard buffer, empty after reading out
- key_tmp ; keycode temporary storage
- bufptr ; buffer pointer
- buffer ; keyboard buffer
- buffer2
- buffer3
- buffer4
- buffer5
- beeper ; beep time countdown
- beepct ; beep
- beepcnt ; beep cnt
- count10
- count20
- count30
- pass1 ; password
- pass2
- pass3
- pass4
- pass5
- ;**********************************************************************
- ENDC
- ;****************************************************************************
- ORG 0 ;RESET
- Reset goto main
- ;****************************************************************************
- ORG 4 ;INT
- Interrupt retfie
- ;
- keytable ;determine pressed key's real code from scancode
- addwf PCL
- retlw 60
- retlw 31
- retlw 32
- retlw 33
- retlw 61
- retlw 34
- retlw 35
- retlw 36
- retlw 62
- retlw 37
- retlw 38
- retlw 39
- retlw 63
- retlw 90
- retlw 30
- retlw 91
- retlw 64
- ;
- main MOVLW 0c
- MOVWF PORTA
- MOVLW 0xe8 ; B?1101000?;SET PORT A 0-2,4 out
- TRIS PORTA
- MOVLW 0
- MOVWF PORTB
- MOVLW 0xf3 ;B11110011 ;SET PORT B4-7 AS INPUTS
- TRIS PORTB
- ;
- BSF STATUS, RP0 ;bank 1
- BCF OPTION_REG, NOT_RBPU ;internal pullups on port B enabled
- BCF STATUS, RP0 ;bank 0
- clrf row_cnt ;row counter ;clrf?
- clrf prevcode
- clrf keycode
- clrf beepct
- MOVLW 0xff
- MOVWF led_ctl
- MOVWF led_tmp
- movlw 1
- movwf count2
- movwf count3
- movlw 0xf0
- movwf beeper;generate beep on powerup
- movlw 0x33 ;inital password
- movwf pass1
- movwf pass2
- movlw 0x34
- movwf pass3
- movlw 0x35
- movwf pass4
- ;
- resetbuf movlw buffer
- movwf bufptr
- loop clrf keybuf
- CALL scantimer
- call beepgen;generate beepct if needed
- movf keybuf,W
- bz loopb
- movlw 20
- movwf beeper ;turn on soundgen
- loopb movf keybuf,W
- sublw 90
- btfsc STATUS,Z;if Z=0, skip
- ; goto resetbuf
- ;old function of key was reset, new function is change code
- goto chk0
- movf keybuf,W
- bz loop2 ;no key was pressed, skip
- sublw 91
- bnz loop5
- ;pressed enter, check code
- chk0 movf bufptr,W
- sublw buffer5
- bnz incorrect
- movf buffer,W
- subwf pass1,W
- bnz incorrect
- movf buffer2,W
- subwf pass2,W
- bnz incorrect
- movf buffer3,W
- subwf pass3,W
- bnz incorrect
- movf buffer4,W
- subwf pass4,W
- bnz incorrect
- ;
- ;check for the key pressed:enter=generate pulse, otherwise get new passwd
- ;
- movf keybuf,W
- sublw 0x90 ;new passwd?
- bz setpasswd
- movlw 4
- movwf PORTB
- movlw .30
- movwf count30
- ;
- delay21 movlw .250 ;decimal
- movwf count10
- delay0 movlw .250
- movwf count20
- delay1 decfsz count20, F
- goto delay1
- decfsz count10
- goto delay0
- decfsz count30
- goto delay21
- ;
- movlw 0
- movwf PORTB
- incorrect goto resetbuf
- loop5 movf bufptr,W ;store a char in buffer
- sublw buffer5 ;is there space for more characters?
- bnz loop7;yes
- ;no, shift all chars by one
- movf buffer2,W
- movwf buffer
- movf buffer3,W
- movwf buffer2
- movf buffer4,W
- movwf buffer3
- movf keybuf,W
- movwf buffer4
- goto loop2
- ;store character in the buffer
- loop7 movf bufptr,W
- movwf FSR
- movf keybuf,W
- movwf INDF
- incf bufptr,F
-
- loop2
- ; clrf keybuf ;loop will clear keybuf
- GOTO loop
- setpasswd ;set a new code
- ;
- movlw pass1
- movwf FSR
- setp0 clrf keybuf
- call scantimer
- call beepgen
- movf keybuf,W
- bz setp0
- sublw 0x90
- bz setp0
- movf keybuf,W
- sublw 0x91
- bz setp0
- movlw 99
- movwf beeper
- movf keybuf,W
- movwf INDF
- incf FSR,f
- movf FSR,W
- sublw pass5
- bnz setp0
- ;
- goto resetbuf
- ;
- scantimer decfsz count2,F ;if count2=0, skip next instr
- return
- movlw .20
- movwf count2;reload count2
- decfsz count3,F
- return
- movlw .50;could be commented
- movwf count3
- ;time to scan again...
- ;set column on port, set LED status
- ; movlw 4 ;LED status, ON
- movlw 0
- rrf led_tmp,F
- btfsc STATUS,C ;if C=0, skip
- movlw 4;ON
- iorwf row_cnt,W
- iorlw 08 ;serial TX bit latch should be 1!!!
- iorwf beepct,W ;beeper register
- MOVWF PORTA ;output row select, LED status and beeper control
- return
- ;get key status
- scanx MOVF PORTB,W ;get column status
- MOVWF column
- SWAPF column,W;swap nibbles
- ANDLW 0x0f ;lower 4 bits
- MOVWF column
- xorlw 0x0f ;check for pressed key
- btfsc STATUS,Z ;skip if Z = 0
- goto scan0
- movf row_cnt,W ; row_cnt->W
- movwf key_tmp ;W->key_tmp
- bcf STATUS,C
- rlf key_tmp, F
- rlf key_tmp, F ;row * 4->key_tmp
- incf key_tmp ;increase +1
- movlw .4 ;scan for 4 bits in the column file register
- movwf count1
- scan1 rrf column, F ;get the right bit & shift right
- btfss STATUS, C ;if 1, skip
- goto scan2;found a key pressed
-
- incf key_tmp
- decfsz count1, F
- goto scan1
- scan0 return;no key pressed in this row, code unchanged (init'd zero before first cycle)
- scan2 ;found a key pressed
- movf key_tmp,W;set keycode
- movwf keycode
- return;a key was pressed, code=keycode 1-16
- scany movf row_cnt,W
- sublw .3
- btfss STATUS,Z ;if Z=1 , skip (row_cnt=3)
- return
- ;a scan cycle is completed, test for keycode
- movf keycode,W
- btfsc STATUS,Z ;if Z=0, some key is pressed, skip
- ;Z=1, keycode=0, no key pressed
- goto keyb1
- ;W=keycode, not zero
- subwf prevcode,W;was this key pressed in the previous cycle?
- btfsc STATUS,Z ;if Z=0, previous cycle was other code, skip
- goto keyb3;same key, no action --but zero keycode for next cycle!!!
- ;a new key was pressed in the actual cycle
- ;should check if keybuf is empty, and zero prevkey if buffer full
- movf keycode,W
- call keytable
- movwf keybuf
-
- keyb1 movf keycode,W ;store previous keycode
- movwf prevcode
- keyb3 movlw 0
- movwf keycode ;zero actual keycode for next cycle
- ; swapf led_ctl,W
- ; movwf led_tmp ;led control shift register
- return
- ;
- beepgen movf beeper,W
- bz beepgen0
- decfsz beepcnt
- return
- movlw .40
- movwf beepcnt
- decf beeper,F
- movlw 08
- btfsc beeper,0
- movlw 0
- beepgen0 movwf beepct
- movwf PORTB
- return
- end ; directive 'end of program'
复制代码
|