A. 基于51单片机的密码锁
基于51单片机的密码锁的话其实我是不知道是什么意思的 所以说不好意思咯(๑ó﹏ò๑)
B. 求AT89C51单片机控制电子密码锁的程序 最好是C语言
;完成功能说明:
; 基本功能以及OK,可以在线修改密码Ok,开机默认密码:123456,在线可修改
;功能改进说明:
; 将代码继续优化,将其中的清楚按键设置成具有连按功能的按键,对于SET和SET_OUT利用一个按键来做(利用按键的3S长按进入重新设置密码模式,利用相同按键的短击退出密码设置模式),设置报警模式以及退出报警设置,利用剩余的按键来做。;===============================================
;==============MCU:AT89C52=====================
;============名称:电子密码锁===================
;===========程序编写人:DAIVD===================
;=========程序编写时间:2010年8月3日============
;=功能描述:六位数码管显示,4*4矩阵键盘作为外设=
;=====通过矩阵键盘可以输入密码以及修改密码======
;=====通过数码管以及LED显示当前密码锁状态=======
;===============版本:V1.0======================
;=====项目完成时间: ==========
;===============================================
BT0 EQU 20H.0 ;节拍法标志位每个节拍为20MS
CHANGE_PW_FLAG EQU 20H.1 ;重新设置密码标志位
OK_FLAG EQU 20H.2 ;确认密码输入标志位
CLR_FLAG EQU 20H.3 ;清楚输入密码标志位
KEY_REG EQU 20H.4 ;按键按下标志位
FLASHING_FLAG EQU 20H.5 ;闪烁标志位
ONCE_TIME EQU 20H.6 ;第一次进入标志位
MEMORY_FLAG EQU 20H.7 ;修改密码是两次输入第一次需要记忆
DIGITAL_FLAG EQU 21H.0 ;是否需要键入数字标志位
NUM_FLAG EQU 21H.1 ;数字键标核瞎志位
;FUNCTION_FLAG EQU 21H.2 ;功能键标志位
D_DONG_FLAG EQU 21H.3 ;消抖标志位
KEY_HAVE_REG EQU 21H.4 ;一次按键多次响应标志位
SET_OUT EQU 21H.5 ;设置密码状态退出标志位
OTI EQU 21H.6 ;第一次进入重置密码模式标志位
COMPARE_EN EQU 21H.7
OTII EQU 22H.0
ALARM EQU 22H.1 ;报警标志位
ALARM_OUT EQU 22H.2 ;报警退出标志枯中位
ORIGINAL_PW_1 EQU 30H ;原始密码存储寄存器
ORIGINAL_PW_2 EQU 31H
ORIGINAL_PW_3 EQU 32H
ORIGINAL_PW_4 EQU 33H
ORIGINAL_PW_5 EQU 34H
ORIGINAL_PW_6 EQU 35H
CURRENT_PW_1 EQU 40H ;当前改败空密码存储器
CURRENT_PW_2 EQU 41H
CURRENT_PW_3 EQU 42H
CURRENT_PW_4 EQU 43H
CURRENT_PW_5 EQU 44H
CURRENT_PW_6 EQU 45H
CURRENT_PW_1_REG EQU 46H ;当前密码暂存器
CURRENT_PW_2_REG EQU 47H ;用于密码修改时比较两次输入是否相同
CURRENT_PW_3_REG EQU 48H
CURRENT_PW_4_REG EQU 49H
CURRENT_PW_5_REG EQU 4AH
CURRENT_PW_6_REG EQU 4BH
DISPLAY_REG_0 EQU 36H ;显示寄存器
DISPLAY_REG_1 EQU 37H
DISPLAY_REG_2 EQU 38H
DISPLAY_REG_3 EQU 39H
DISPLAY_REG_4 EQU 3AH
DISPLAY_REG_5 EQU 3BH
COUNT_0 EQU 3CH ;用于闪烁标志位的计数200MS
TH0_BUFFER EQU 3DH ;定时器赋初值寄存器
TL0_BUFFER EQU 3EH
MAZHI_REG EQU 3DH ;4*4矩阵键盘扫描得到的码值
COUNT_1 EQU 3FH ;用于设置密码标志位的计数超过3S则置一
COUNT_2 EQU 51H ;用于输入密码次数是否超过3次
R2_REG EQU 50H
CHIP_SELECT EQU P1 ;P1作为片选口
OUTPUT EQU P0 ;P0口作为输出口
GREEN_LED EQU P3.4 ;绿灯代表输入密码正确
YELLOW_LED EQU P3.3 ;黄灯代表正在输入密码过程中
RED_LED EQU P3.2 ;红灯代表输入密码错误
SPK EQU P3.1 ;蜂鸣器代表输入密码超过3次报警
ORG 0000H
LJMP START
ORG 0003H ;中断入口地址写RETI防止出现误判对程序影响
RETI
ORG 000BH
LJMP T0_SER
ORG 0013H
RETI
ORG 001BH
RETI
ORG 0023H
RETI
ORG 002BH
RETI
ORG 0030H
START: MOV ORIGINAL_PW_1,#01 ;设置初始密码
MOV ORIGINAL_PW_2,#02
MOV ORIGINAL_PW_3,#03
MOV ORIGINAL_PW_4,#04
MOV ORIGINAL_PW_5,#05
MOV ORIGINAL_PW_6,#06
MOV TMOD,#01H ;设置定时器0工作方式1采用中断方式
SETB EA
SETB ET0
MOV DPTR,#65536-20000
MOV TH0,DPH
MOV TL0,DPL
MOV TH0_BUFFER,DPH
MOV TL0_BUFFER,DPL
SETB TR0
MOV R0,#CURRENT_PW_1 ;对当前密码以及当前密码暂存器赋初值
REFRESH_PW: MOV @R0,#0B9H ;其中当前密码暂存器用于修改密码时
INC R0 ;比较两次重新输入的密码是否相等用
CJNE R0,#04CH,REFRESH_PW
MOV 20H,#00H
MOV 21H,#00H
MOV 22H,#00H
MOV COUNT_0,#00H
MOV COUNT_1,#00H
MOV COUNT_2,#00H
;=========================================
MAIN: JNB BT0,MAIN
CLR BT0
JNB CHANGE_PW_FLAG,LOOP ;判断是否需要修改密码
;===============修改原始密码模式========== ;当CHANGE_PW_FLAG=1表明进入修改密码模式
JB OTII,LP0
SETB OTII
MOV R2,#0
LP0: JNB SET_OUT,LP
MOV R2,#0
LJMP LP4
LP: JNB OK_FLAG,LOOP1 ;判断是否输入密码完成
CLR OK_FLAG
JNB OTI,LP1 ;判断是不是第一次进入要在输入密码正确的前提下
JNB COMPARE_EN,SAVE_MODE ;记录两次输入的密码是否一致才确定是否需要重置
CALL COMPARE_CODE
LJMP LOOP1
SAVE_MODE: CALL SAVE_CODE
LJMP LOOP1
LP1: CALL ENTER_PW_MODE
CJNE R2,#0,LP2
LJMP LOOP1
LP2: CJNE R2,#7,LP3 ;等于7代表原始密码输入正确,下一步记忆新密码
SETB OTI
MOV R2,#0
LJMP LOOP1
LP3: MOV R2,#8
LP4: CLR ALARM_OUT
CLR SET_OUT
CLR OTI ;清零所有内容恢复等待密码输入状态
CLR OTII
CLR COMPARE_EN
CLR CHANGE_PW_FLAG
LJMP LOOP1
;===============常规输入密码模式==========
LOOP: CLR SET_OUT ;非设置密码格式下也会扫描到SET_OUT
;防止程序进入设置密码状态下直接退出
JNB ALARM,L1
JB ALARM_OUT,L2
CLR SPK
LJMP LOOP3
L2: SETB SPK
CLR ALARM_OUT
CLR ALARM
LJMP LOOP1
L1: JNB OK_FLAG,LOOP1 ;判断是否输入密码完成
CLR OK_FLAG
CALL ENTER_PW_MODE
;==========================================
LOOP1: JNB CLR_FLAG,LOOP2 ;判断是否需要清除所输入密码
CLR CLR_FLAG
LCALL CLR_INPUT_PW
LOOP2: JNB DIGITAL_FLAG,LOOP3 ;判断是否需要输入密码
CLR DIGITAL_FLAG
LCALL INPUT_PW
LJMP LOOP3
;=========================================
LOOP3: LCALL DISPLAY
LCALL KEY_SCAN
INC COUNT_0
MOV A,COUNT_0
CJNE A,#5,LOOP4
MOV COUNT_0,#0
CPL FLASHING_FLAG
LOOP4:
LJMP MAIN
;=============下面是具体的子程序===========
;================检测密码是否正确==========
ENTER_PW_MODE:
CLR OK_FLAG ;比较是否为零,为零的时候
CJNE R2,#0,ENTER_PW_MODE_0 ;代表还没密码输入,直接跳出
LJMP ENTER_PW_MODE_OUT
ENTER_PW_MODE_0:
CJNE R2,#7,$+3 ;用来比较R2是否为7或者8
JC ENTER_PW_MODE_2
MOV R2,#00 ;如果8在BAD的模式下切换到输入密码状态
LJMP ENTER_PW_MODE_OUT ;如果7在GOOD的模式下切换到输入密码状态
ENTER_PW_MODE_2:
CJNE R2,#6,ENTER_PW_MODE_3 ;如果R2里的数字不为6代表密码位数不够,肯定错
MOV R0,#ORIGINAL_PW_1 ;如果R2里的数字等于6那么在比较是否相同
MOV R1,#CURRENT_PW_1
ENTER_PW_MODE_4:
MOV A,@R0
XRL A,@R1 ;相异或内容相同为0
CJNE A,#00H,ENTER_PW_MODE_3
INC R0
INC R1
CJNE R0,#36H,ENTER_PW_MODE_4
MOV R2,#7 ;如果相同代表密码输入正确GOOD
MOV COUNT_2,#0
LJMP ENTER_PW_MODE_OUT
ENTER_PW_MODE_3:MOV R2,#8 ;如果不相同则代表密码不正确BAD
INC COUNT_2
MOV A,COUNT_2
CJNE A,#3,$+3
JC KK
FUZHI: MOV COUNT_2,#00H
SETB ALARM
KK: MOV R0,#CURRENT_PW_1 ;对当前密码以及当前密码暂存器赋初值
REF_PW: MOV @R0,#0B9H ;其中当前密码暂存器用于修改密码时
INC R0 ;比较两次重新输入的密码是否相等用
CJNE R0,#04CH,REF_PW
ENTER_PW_MODE_OUT:
RET
;==========================================
;=============清除所输入的密码=============
CLR_INPUT_PW:
CLR CLR_FLAG
CJNE R2,#0,CLR_INPUT_PW_0 ;如果为零则不操作
LJMP CLR_INPUT_PW_OUT
CLR_INPUT_PW_0:
CJNE R2,#7,$+3 ;用来比较R2是否为7或者8
JC CLR_INPUT_PW_1
MOV R2,#00 ;如果8在BAD的模式下切换到输入密码状态
LJMP CLR_INPUT_PW_OUT ;如果7在GOOD的模式下切换到输入密码状态
CLR_INPUT_PW_1:
DEC R2 ;正常模式下将R2减一
CLR_INPUT_PW_OUT:
RET
;==========================================
;============输入单位密码子程序============
INPUT_PW: JB NUM_FLAG,INPUT_PW_0
LJMP INPUT_PW_OUT
INPUT_PW_0: CLR NUM_FLAG
CJNE R2,#7,$+3 ;比较R2是否大于7,大于C=0
JC INPUT_PW_2
MOV R2,#01 ;数字键按下输入密码
LJMP INPUT_PW_3_3
INPUT_PW_2: CJNE R2,#6,INPUT_PW_3 ;如果当前R2等于则6位密码已经输满则不操作
LJMP INPUT_PW_OUT
INPUT_PW_3: INC R2
INPUT_PW_3_3: MOV R1,#01
MOV R2_REG,R2 ;根据R2的给相应的位送密码
MOV R0,#CURRENT_PW_1
JMP I_LOOP
I_LOOP1: INC R0
INC R1
I_LOOP: MOV A,R1
CJNE A,R2_REG,I_LOOP1
MOV A,R3
MOV @R0,A
INPUT_PW_OUT: RET
;==========================================
;===============SAVE_CODE==================
SAVE_CODE: CJNE R2,#6,SAVE_CLR ;如果R2不等于6代表密码输入错误直接退出
SAVE_IN: MOV R0,#CURRENT_PW_1_REG ;将输入的新密码先保存在密码暂存区
MOV R1,#CURRENT_PW_1 ;46H
SAVE_IN_LOOP: MOV A,@R1
MOV @R0,A
INC R0
INC R1
MOV A,R1
CJNE A,#46H,SAVE_IN_LOOP
SETB COMPARE_EN
MOV R2,#0 ;密码输入正确则程序处于等待输入状态
LJMP SAVE_OUT
SAVE_CLR: MOV R2,#8
CLR SET_OUT
CLR OTI ;清零所有内容恢复等待密码输入状态
CLR OTII
CLR COMPARE_EN
CLR CHANGE_PW_FLAG
SAVE_OUT: RET
;===========================================
;=================COMPARE_CODE==============
COMPARE_CODE: CJNE R2,#6,COMPARE_FAIL ;如果R2不等于6代表上次输入密码数不足6位
COMPARE_IN: MOV R0,#CURRENT_PW_1_REG
MOV R1,#CURRENT_PW_1 ;46H
COMPARE_IN_LOOP:
MOV A,@R1
XRL A,@R0
CJNE A,#00H,COMPARE_FAIL
INC R0
INC R1
MOV A,R1
CJNE A,#46H,COMPARE_IN_LOOP
MOV R0,#ORIGINAL_PW_1
MOV R1,#CURRENT_PW_1 ;46H
TIHUAN_LOOP: MOV A,@R1
MOV @R0,A
INC R0
INC R1
MOV A,R1
CJNE A,#46H,TIHUAN_LOOP
MOV R2,#7
CLR SET_OUT
CLR OTI ;清零所有内容恢复等待密码输入状态
CLR OTII
CLR COMPARE_EN
CLR CHANGE_PW_FLAG
LJMP COMPARE_OUT
COMPARE_FAIL: MOV R2,#8
CLR SET_OUT
CLR OTI ;清零所有内容恢复等待密码输入状态
CLR OTII
CLR COMPARE_EN
CLR CHANGE_PW_FLAG
COMPARE_OUT: RET
;===========================================
;==================显示子程序==============
DISPLAY: MOV R4,#0
MOV DPTR,#TAB_0
MOV A,R2
RL A
JMP @A+DPTR
TAB_0: AJMP DISPLAY_0
AJMP DISPLAY_1
AJMP DISPLAY_2
AJMP DISPLAY_3
AJMP DISPLAY_4
AJMP DISPLAY_5
AJMP DISPLAY_6
AJMP DISPLAY_7
AJMP DISPLAY_8
DISPLAY_0: MOV DPTR,#TAB_1
LJMP REFRESH_DISPLAY
DISPLAY_1: MOV DPTR,#TAB_2
LJMP REFRESH_DISPLAY
DISPLAY_2: MOV DPTR,#TAB_3
LJMP REFRESH_DISPLAY
DISPLAY_3: MOV DPTR,#TAB_4
LJMP REFRESH_DISPLAY
DISPLAY_4: MOV DPTR,#TAB_5
LJMP REFRESH_DISPLAY
DISPLAY_5: MOV DPTR,#TAB_6
LJMP REFRESH_DISPLAY
DISPLAY_6: MOV DPTR,#TAB_7
LJMP REFRESH_DISPLAY
DISPLAY_7: MOV DPTR,#TAB_8
LJMP REFRESH_DISPLAY
DISPLAY_8: MOV DPTR,#TAB_9
REFRESH_DISPLAY:
MOV R0,#DISPLAY_REG_0
DISPLAY_LOOP:
MOV A,R4
MOVC A,@A+DPTR
MOV @R0,A
INC R4
INC R0
MOV A,R0
CJNE A,#3CH,DISPLAY_LOOP ;此时表明数码管显示的数值已送完
DISPLAY_SHOW:
MOV R0,#DISPLAY_REG_0 ;数码管动态显示
MOV R5,#0FEH
NEXT_0: MOV CHIP_SELECT,R5
MOV A,@R0
MOV OUTPUT,A
LCALL DELAY
MOV OUTPUT,#0FFH
INC R0
MOV A,R5
RL A
MOV R5,A ;片选
CJNE R0,#3CH,NEXT_0
CJNE R2,#0,NEXT_6
MOV P3,#0FFH
LJMP DISPLAY_OUT
NEXT_6: CJNE R2,#7,NEXT_1
CLR GREEN_LED
SETB YELLOW_LED
SETB RED_LED
LJMP DISPLAY_OUT
NEXT_1: CJNE R2,#8,NEXT_2
SETB YELLOW_LED
SETB GREEN_LED
CLR RED_LED
LJMP DISPLAY_OUT
NEXT_2: JNB CHANGE_PW_FLAG,NEXT_3
JNB FLASHING_FLAG,NEXT_4
MOV P3,#0FFH
LJMP DISPLAY_OUT
NEXT_4: MOV P3,#00H
LJMP DISPLAY_OUT
NEXT_3: JNB FLASHING_FLAG,NEXT_5
MOV P3,#0F7H
LJMP DISPLAY_OUT
NEXT_5: MOV P3,#0FFH
DISPLAY_OUT: RET
;=======================================
;============按键扫描程序===============
KEY_SCAN: MOV R3,#00H ;对码表扫描进行初始化可以访问到第一位
JNB D_DONG_FLAG,PANDUAN ;判断是否进行过消抖
LCALL FANZHUAN_SCAN ;反转扫描确定码值
CJNE A,#0FFH,L4 ;如果码值等于0FFH可能是抖动或者按键抬起
L3: CLR D_DONG_FLAG ;表明是按键抬起,此时要对D_DONG_FLAG/
CLR KEY_HAVE_REG ;KEY_HAVE_REG进行清零;;;;;;;;;;
CLR COUNT_1
LJMP KEY_SCAN_OUT
L4: JNB ALARM,KEY_SCAN_1
CJNE A,#0B7H,L3
SETB ALARM_OUT
CLR D_DONG_FLAG
LJMP KEY_SCAN_OUT
PANDUAN: LCALL FANZHUAN_SCAN ;第一次进入没有经过消抖判断是否有按键按下
CJNE A,#0FFH,KEY_SCAN_0 ;对所扫描的码值进行比较如果为0FFH没按键按下
LJMP KEY_SCAN_OUT
KEY_SCAN_0: SETB D_DONG_FLAG ;所扫到的码值不等于0FFH可能是按键按下
LJMP KEY_SCAN_OUT
KEY_SCAN_1:
JNB KEY_HAVE_REG,KEY_SCAN_1_1;一次按键多次响应标志位
CJNE A,#0E7H,KEY_SCAN_1_1_1
INC COUNT_1 ;长按处理
MOV A,COUNT_1
CJNE A,#150,KEY_SCAN_1_1_1
MOV COUNT_1,#00H
SETB CHANGE_PW_FLAG
CLR D_DONG_FLAG
CLR KEY_HAVE_REG
KEY_SCAN_1_1_1:
LJMP KEY_SCAN_OUT
KEY_SCAN_1_1: MOV MAZHI_REG,A
KEY_SCAN_LOOP:
MOV DPTR,#TAB_10
MOV A,R3
MOVC A,@A+DPTR
CJNE A,#0FFH,KEY_SCAN_2 ;如果查出的码表值为0FFH代表已经查完了
MOV R3,#0 ;但是没有符合的就代表是乱码不处理
CLR D_DONG_FLAG
CLR KEY_HAVE_REG
LJMP KEY_SCAN_OUT
KEY_SCAN_2: CJNE A,MAZHI_REG,KEY_SCAN_3 ;比较是哪个键按下
CJNE R3,#10,$+3 ;通过比较后形成小于等于9或者大于9两种情况
JNC COMPARE
SHUZI_MODE: SETB KEY_HAVE_REG
SETB NUM_FLAG
SETB DIGITAL_FLAG
LJMP KEY_SCAN_OUT
COMPARE: SETB KEY_HAVE_REG
CJNE R3,#10,COMPARE_0 ;此时R3内的数值大于9则CY=1
SETB OK_FLAG ;等于10为OK键按下
LJMP KEY_SCAN_OUT
COMPARE_0: CJNE R3,#11,COMPARE_1 ;等于11为清除按键按下
SETB CLR_FLAG
LJMP KEY_SCAN_OUT ;等于12为设置密码按键在长按里面加处理
COMPARE_1: CJNE R3,#13,COMPARE_2 ;等于13为设置密码跳出标志
SETB SET_OUT
LJMP KEY_SCAN_OUT
;COMPARE_2: CJNE R3,#14,COMPARE_3
; SETB ALARM
; LJMP KEY_SCAN_OUT
COMPARE_2: CJNE R3,#14,COMPARE_4
SETB ALARM_OUT
LJMP KEY_SCAN_OUT
COMPARE_4: LJMP KEY_SCAN_OUT ;按键加功能
KEY_SCAN_3: INC R3
LJMP KEY_SCAN_LOOP
KEY_SCAN_OUT:
RET
;=======================================
FANZHUAN_SCAN: MOV P2,#0F0H ;反转扫描确定码值
MOV A,P2
ANL A,#0F0H
MOV B,A
MOV P2,#0FH
MOV A,P2
ANL A,#0FH
ORL A,B
RET
;===============显示的码表==============
TAB_1: DB 0BFH,0BFH,0BFH,0BFH,0BFH,0BFH ;------
TAB_2: DB 0B9H,0BFH,0BFH,0BFH,0BFH,0BFH ;+-----
TAB_3: DB 0B9H,0B9H,0BFH,0BFH,0BFH,0BFH ;++----
TAB_4: DB 0B9H,0B9H,0B9H,0BFH,0BFH,0BFH ;+++---
TAB_5: DB 0B9H,0B9H,0B9H,0B9H,0BFH,0BFH ;++++--
TAB_6: DB 0B9H,0B9H,0B9H,0B9H,0B9H,0BFH ;+++++-
TAB_7: DB 0B9H,0B9H,0B9H,0B9H,0B9H,0B9H ;++++++
TAB_8: DB 090H,0A3H,0A3H,0A1H,0FFH,0FFH ;good
TAB_9: DB 083H,0A0H,0A1H,0FFH,0FFH,0FFH ;bad
TAB_10: DB 0EEH,0DEH,0BEH,07EH,0EDH,0DDH,0BDH,07DH ;4*4矩阵键盘的码表
DB 0EBH,0DBH,0BBH,07BH,0E7H,0D7H,0B7H,77H,0FFH
;=======================================
;==============延时子程序===============
;输入:无
;输出:无
;功能:延时一段时间稳定数码管的显示2.4MS
DELAY:
MOV R7,#30
DL: MOV R6,#40
DJNZ R6,$
DJNZ R7,DL
RET
;=======================================
;============定时器中断服务程序=========
T0_SER:
MOV TMOD,#01H
SETB BT0
MOV TH0,TH0_BUFFER
MOV TL0,TL0_BUFFER
RETI
;=======================================
END
C. 怎么设计一个由51单片机控制的电子密码锁
#include<reg51.h>
#defineuintunsignedint
charleab[]={0x7f,0x7f,0x7f,0x7f,0x7f,0x7f};
delay(uintz)
{
uintx;
for(;z<0;z--)
for(x=0;x<10;x++);//1ms
}
disp()
{
charx,y;
for(x=5;x>=0;x--)
{for(y=0;y<10;y++)
{P0=0;
P2=x;
P0=leab[x];
delay(10);
P0=0;}
}
}
charsao(charg)
{chard;
switch(g)
{
case1:d=1;break;
case2:d=2;break;
case4:d=3;break;
case8:d=4;break;
default:d=0;break;
}
returnd;
}
charkey()
{
charH=0,L=0,d,d1,d2;
while(1)
{d=0;
P1=0xf0;
if(P1!=0xf0)
{
delay(10);
if(P1!=0xf0)
{
H=(~(P1^0x0f))>>4;
P1=0xff;
P1=0x0f;
L=~(P1^0xf0);
d2=sao(L);
d1=sao(H);
d=(d1-1)*4+d2;
P2=d;
}}
if(d!=0)break;
disp();
}
returnd;
}
main()
{
charleab1[]={0x00,0x00,0x00,0x00,0x00,0x00};
charleab2[]={0x09,0x08,0x00,0x06,0x01,0x01};
chara,b,d,e=0;
intf;
while(1)
{
P3=0xff;
for(a=0;a<6;a++)
{
leab[a]=0x7f;
leab1[a]=0x00;
}
for(b=0;b<100;b++)
{
disp();
}
//for(c=0;c<6;c++)
//{
//leab[c]=0x00;
//}
while(1)
{
for(d=0;d<6;d++)
{
e=key();
if((e>=1)&(e<=10))
{
leab[d]=0x71;
disp();
leab1[d]=e-1;
}
else
{d=d-1;disp();}
if(e==15)break;
}
if(e==15)break;
while(e!=16)
{disp();
e=key();
if(e==16)break;
if(e==15)break;
}
if(e==15)break;
if((leab1[0]==leab2[0])&(leab1[0]==leab2[0])&
(leab1[0]==leab2[0])&(leab1[0]==leab2[0])&
(leab1[0]==leab2[0])&(leab1[0]==leab2[0]))
{
for(f=0;f<800;f++)
{P3=0x02;
delay(100);
disp();
}
}
else
{for(f=0;f<800;f++)
{P3=0x01;
delay(100);
disp();
}}
break;
}
}}
D. 单片机指纹密码锁的特色与创新
随着人民生活水平的提高,如何实现家庭防盗这一问题也变得尤其突出,传统的机械锁由于其构造简单,安全性低,无法满足人们的需求。随着电子产品向智能化和微型化的不断发展,单片机已成为电子产品研制和开发中首选的控制器,所以具有防盗报警功能的电子密码锁控制系统逐渐代替传统的机械式密码控制系统,克服了机械式密码锁控制的密码量少,安全性能差的缺点。
在传统的身份认证中,我们往往使用密码加密法,但是这种方法只是"防君子不防小人"。在高明的黑客眼里,由几个字符组成的密码脆弱得不堪一击。现在,科技的发展让我们有了新的选择——生物识别技术。将生物识别技术应用于笔记本、门锁等方面,可以对文件、财产起保护作用,并且可以进行身份识别。生物识别技术的发展主要起始于指纹研究,它亦是目前应用最为广泛的生物识别技术。
本设计开发了一款基于单片机的指纹识别电子密码锁系统。该系统以STC89C52单片机作为模块核心,通过串口通信控制ZFM-60指纹模块实现录取指纹并存储指纹数据,并通过HS12864-15C液晶显示比对流程及比对结果,辅以直流继电器与发光二极管模拟开锁的动作。本系统具有体积小、性价比高、传输速度快、适合家庭及单位使用。
关键词:单片机,密码锁,指纹识别
E. 求51单片机C语言编的简易密码锁程序
首先得说明我这个可是自己原创手打的,但是没去仿真了,程序可能有错误,你自己修改下吧
#include<reg52.h>
typedef unsigned char uchar;
typedef unsigned int uint;
sbit key1=P0^0;
sbit key2=P0^1;
sbit key3=P0^2;
sbit key4=P0^3;
sbit wela=P2^0;//位锁存端
#define SMG P1
sbit LED=P3^0;//低电平亮
uchar code table[]={0x8d,0x86};//共阳数码管 P,E
uchar chushi_mima[]={2,1,3};
uchar shuru_mima[3];
uchar index;//控制输入密码的位数
uchar flag_3s=0;//3s标志位
uchar keydown;//确定按键变量
#define times 15//去抖时间15Ms
uchar key1_count,key2_count,key3_count,key4_count;
void init()
{
wela=0;
SMG=0xff;
TMOD=0x01;
TH0=(65536-1000)/256;
TL0=(65536-1000)%256;
ET0=1;
EA=1;
TR0=1;
LED=1;
}
void main()
{
init();
while(1)
{
switch(keydown)
{
if(index>2)index=0;
case 1:
shuru_mima[index]=0;
index++;
break;
case 2:
shuru_mima[index]=1;
index++;
break;
case 3:
shuru_mima[index]=2;
index++;
break;
case 4:
shuru_mima[index]=3;
index++;
break;
}
flag_3s=0;
for(i=0;i<3;i++)
{
if(shuru_mima[i]==chushi_mima[i])
{
LED=0;
wela=1;
SMG=table[0];
if(flag_3s)
{
flag_3s=0;
wela=0;
}
}
else
{
LED=1;
wela=1;
SMG=table[1];
if(flag_3s)
{
flag_3s=0;
wela=0;
}
}
}
}
}
void timer0() interrupt 1
{
uchar count;
TH0=(65536-1000)/256;
TL0=(65536-1000)%256;
if(++count>=600)
{
count=0;
flag_3s=1;
}
/*********1ms中断扫描按键(包含去抖程序)********/
if(!key1&&key1_count!=0)
{
key1_count--;
if(key1_count==0)
{
keydown=1;
}
}
else if(!key1) key1_count=times;
// key2,key3,key4你自己写吧
}
F. 基于单片机的电子密码锁设计
功能键
S6---S15 数字键0-9
S16---更改密码 S17---更改密码完毕后确认
S18---重试密码、重新设定 S19---关闭密码锁
初始密码:000000 密码位数:6位
注意:掉电后,所设密码会丢失,重新上点时,密码恢复为原始的000000
与P1相连的8位发光LED点亮代表锁被打开;熄灭代表锁被锁上
程序功能: 本程序结合了24C02存储器的存储功能,可以掉电保存密码。
第一次运行时,若输入000000原始密码后无反应,可以试验着将主程序中前面的
一小段被注释线屏蔽的程序前的注释线删掉,然后重新编译下载(可以将密码还原为000000)。
此后,再将这小段程序屏蔽掉,再编译下载。方可正常使用。
1、开锁:
下载程序后,直接按六次S7(即代表数字1),8位LED亮,锁被打开,输入密码时,
六位数码管依次显示小横杠。
2、更改密码:
只有当开锁(LED亮)后,该功能方可使用。
首先按下更改密码键S16,然后设置相应密码,此时六位数码管会显示设置密码对应
的数字。最后设置完六位后,按下S17确认密码更改,此后新密码即生效。
3、重试密码:
当输入密码时,密码输错后按下键S18,可重新输入六位密码。
当设置密码时,设置中途想更改密码,也可按下此键重新设置。
4、关闭密码锁:
按下S19即可将打开的密码锁关闭。
推荐初级演示步骤:输入原始密码000000---按下更改密码按键S16---按0到9设置密码---按S17
确认密码更改---按S18关闭密码锁---输入新的密码打开密码锁
*******************************************************************************/
#include<reg52.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
uchar old1,old2,old3,old4,old5,old6; //原始密码000000
uchar new1,new2,new3,new4,new5,new6; //每次MCU采集到的密码输入
uchar a=16,b=16,c=16,d=16,e=16,f=16; //送入数码管显示的变量
uchar wei,key,temp;
bit allow,genggai,ok,wanbi,retry,close; //各个状态位
sbit la=P2^6;
sbit wela=P2^7;
sbit beep=P2^3;
sbit sda=P2^0; //IO口定义
sbit scl=P2^1;
unsigned char code table[]=
{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,
0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00,0x40};
/*****************IIC芯片24C02存储器驱动程序************************************/
void nop()
{
_nop_();
_nop_();
}
/////////24C02读写驱动程序////////////////////
void delay1(unsigned int m)
{ unsigned int n;
for(n=0;n<m;n++);
}
void init() //24c02初始化子程序
{
scl=1;
nop();
sda=1;
nop();
}
void start() //启动I2C总线
{
sda=1;
nop();
scl=1;
nop();
sda=0;
nop();
scl=0;
nop();
}
void stop() //停止I2C总线
{
sda=0;
nop();
scl=1;
nop();
sda=1;
nop();
}
void writebyte(unsigned char j) //写一个字节
{
unsigned char i,temp;
temp=j;
for (i=0;i<8;i++)
{
temp=temp<<1;
scl=0;
nop();
sda=CY; //temp左移时,移出的值放入了CY中
nop();
scl=1; //待sda线上的数据稳定后,将scl拉高
nop();
}
scl=0;
nop();
sda=1;
nop();
}
unsigned char readbyte() //读一个字节
{
unsigned char i,j,k=0;
scl=0; nop(); sda=1;
for (i=0;i<8;i++)
{
nop(); scl=1; nop();
if(sda==1)
j=1;
else
j=0;
k=(k<<1)|j;
scl=0;
}
nop();
return(k);
}
void clock() //I2C总线时钟
{
unsigned char i=0;
scl=1;
nop();
while((sda==1)&&(i<255))
i++;
scl=0;
nop();
}
////////从24c02的地址address中读取一个字节数据/////
unsigned char read24c02(unsigned char address)
{
unsigned char i;
start();
writebyte(0xa0);
clock();
writebyte(address);
clock();
start();
writebyte(0xa1);
clock();
i=readbyte();
stop();
delay1(100);
return(i);
}
//////向24c02的address地址中写入一字节数据info/////
void write24c02(unsigned char address,unsigned char info)
{
start();
writebyte(0xa0);
clock();
writebyte(address);
clock();
writebyte(info);
clock();
stop();
delay1(5000); //这个延时一定要足够长,否则会出错。因为24c02在从sda上取得数据后,还需要一定时间的烧录过程。
}
/****************************密码锁程序模块********************************************************/
void delay(unsigned char i)
{
uchar j,k;
for(j=i;j>0;j--)
for(k=125;k>0;k--);
}
void display(uchar a,uchar b,uchar c,uchar d,uchar e,uchar f)
{
la=0;
P0=table[a];
la=1;
la=0;
wela=0;
P0=0xfe;
wela=1;
wela=0;
delay(5);
P0=table[b];
la=1;
la=0;
P0=0xfd;
wela=1;
wela=0;
delay(5);
P0=table[c];
la=1;
la=0;
P0=0xfb;
wela=1;
wela=0;
delay(5);
P0=table[d];
la=1;
la=0;
P0=0xf7;
wela=1;
wela=0;
delay(5);
P0=table[e];
la=1;
la=0;
P0=0xef;
wela=1;
wela=0;
delay(5);
P0=table[f];
la=1;
la=0;
P0=0xdf;
wela=1;
wela=0;
delay(5);
}
void keyscan()
{
{
P3=0xfe;
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0)
{
delay(10);
if(temp!=0xf0)
{
temp=P3;
switch(temp)
{
case 0xee:
key=0;
wei++;
break;
case 0xde:
key=1;
wei++;
break;
case 0xbe:
key=2;
wei++;
break;
case 0x7e:
key=3;
wei++;
break;
}
while(temp!=0xf0)
{
temp=P3;
temp=temp&0xf0;
beep=0;
}
beep=1;
}
}
P3=0xfd;
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0)
{
delay(10);
if(temp!=0xf0)
{
temp=P3;
switch(temp)
{
case 0xed:
key=4;
wei++;
break;
case 0xdd:
key=5;
wei++;
break;
case 0xbd:
key=6;
wei++;
break;
case 0x7d:
key=7;
wei++;
break;
}
while(temp!=0xf0)
{
temp=P3;
temp=temp&0xf0;
beep=0;
}
beep=1;
}
}
P3=0xfb;
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0)
{
delay(10);
if(temp!=0xf0)
{
temp=P3;
switch(temp)
{
case 0xeb:
key=8;
wei++;
break;
case 0xdb:
key=9;
wei++;
break;
case 0xbb:
genggai=1;
wei=0;
break;
case 0x7b:
if(allow)
ok=1;
break;
}
while(temp!=0xf0)
{
temp=P3;
temp=temp&0xf0;
beep=0;
}
beep=1;
}
}
P3=0xf7;
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0)
{
delay(10);
if(temp!=0xf0)
{
temp=P3;
switch(temp)
{
case 0xe7:
retry=1;
break;
case 0xd7:
close=1;
break;
}
while(temp!=0xf0)
{
temp=P3;
temp=temp&0xf0;
beep=0;
}
beep=1;
}
}
}
}
void shumima() //对按键采集来的数据进行分配
{
if(!wanbi)
{
switch(wei)
{
case 1:new1=key;
if(!allow) a=17;
else a=key; break;
case 2:new2=key;
if(a==17) b=17;
else b=key; break;
case 3:new3=key;
if(a==17) c=17;
else c=key; break;
case 4:new4=key;
if(a==17) d=17;
else d=key; break;
case 5:new5=key;
if(a==17) e=17;
else e=key; break;
case 6:new6=key;
if(a==17) f=17;
else f=key;
wanbi=1; break;
}
}
}
void yanzheng() //验证密码是否正确
{
if(wanbi) //只有当六位密码均输入完毕后方进行验证
{
if((new1==old1)&(new2==old2)&(new3==old3)&(new4==old4)&(new5==old5)&(new6==old6))
allow=1; //当输入的密码正确,会得到allowe置一
}
}
void main()
{
init(); //初始化24C02
/*********下面的一小段程序的功能为格式化密码存储区。************
******当24c02中这些存储区由于其他程序的运行而导致***************
*******所存数据发生了变化,或者密码遗忘时, ********************
******可以删掉其前面的注释线,然后重新编译下载。****************
******而将密码还原为000000后,请将下面的程序用******************
******注释屏蔽掉,重新编译、下载,方可正常使用****************/
// write24c02(110,0x00);
// write24c02(111,0x00);//24c02的第110到115地址单元作为密码存储区
// write24c02(112,0x00);
// write24c02(113,0x00);
// write24c02(114,0x00);
// write24c02(115,0x00);
/*******************************************************************/
old1=read24c02(110);
old2=read24c02(111);
old3=read24c02(112);
old4=read24c02(113);
old5=read24c02(114);
old6=read24c02(115);
while(1)
{
keyscan();
shumima();
yanzheng();
if(allow) //验证完后,若allow为1,则开锁
{
P1=0x00;
if(!genggai)
wanbi=0;
}
if(genggai) //当S16更改密码键被按下,genggai会被置一
{
if(allow) //若已经把锁打开,才有更改密码的权限
{
while(!wanbi) //当新的六位密码没有设定完,则一直在这里循环
{
keyscan();
shumima();
if(retry|close) //而当探测到重试键S18或者关闭密码锁键S19被按下时,则跳出
{ wanbi=1;
break;
}
display(a,b,c,d,e,f);
}
}
}
if(ok) //更改密码时,当所有六位新密码均被按下时,可以按下此键,结束密码更改
{ //其他时间按下此键无效
ok=0; wei=0;
genggai=0;
old1=new1;old2=new2;old3=new3; //此时,旧的密码将被代替
old4=new4;old5=new5;old6=new6;
//新密码写入存储区。
write24c02(110,old1);
write24c02(111,old2);
write24c02(112,old3);
write24c02(113,old4);
write24c02(114,old5);
write24c02(115,old6);
a=16;b=16;c=16;d=16;e=16;f=16;
}
if(retry) //当重试按键S18被按下,retry会被置位
{
retry=0; wei=0;wanbi=0;
a=16;b=16;c=16;d=16;e=16;f=16;
new1=0;new2=0;new3=0;new4=0;new5=0;new6=0;
}
if(close) //当关闭密码锁按键被按下,close会被置位
{
close=0;genggai=0;//所有变量均被清零。
wei=0; wanbi=0;
allow=0;
P1=0xff;
a=16;b=16;c=16;d=16;e=16;f=16;
new1=0;new2=0;new3=0;new4=0;new5=0;new6=0;
}
display(a,b,c,d,e,f); //实时显示
}
}
对着代码自己做吧,,要是还做不出来,,那我就不说什么了,,
G. 求51单片机C语言编的密码锁程序
#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
#define BIN(a,b,c,d,e,f,g,h) ((a<<7)+(b<<6)+(c<<5)+(d<<4)+(e<<3)+(f<<2)+(g<<1)+(h<<0))
//下面的code表示数组存放在ROM中,因为这个数组的值不需要改写
uchar code KeyCode[16]={15,14,12,8,30,28,24,16,60,56,48,32,120,112,96,64};//值为m*(n+1)的乘积,用于Key()
uchar dis[6];
msdelay(uint x)//延时子函数
{uchar j;
while(x--)
{for(j=0;j<125;j++){;}
}
}
//键盘子程序一,键盘值与数组值对比得到
uchar Key(void)
{uchar temp,m,n,i,j,matrix,k;
P1=0xF0; /*行线电平为高,列线为低*/
temp=P1&0xf0;
if (temp==0xf0) return(16); /*行仍为高,无按健,退出*/
else msdelay(10);
for(i=1;i<16;i=i*2)
{m=i;
for(j=1;j<16;j=j*2)
{n=(~j)&0x0f;
P1=(m<<4)|n; /*m为P1的行值由i循环得到,n为列值,由j循环并取反得到*/
temp=P1&0xf0;
if (!temp)
{do{temp=P1&0xf0;}while(!temp);
matrix=m*(n+1);/*为避免乘积重复,n+1*/
for(k=0;k<16;k++){if (matrix==KeyCode[k]) return(k);} //KeyCode:见前
return(16);
} //if loop
}//j loop
}//i loop
}//Key end
//用Switch...case语句得到键盘值*/
uchar Key1(void)
{uchar temp,m,n,i,j,matrix;
P1=0xF0; /*行线电平为高,列线为低*/
temp=P1&0xf0;
if (temp==0xf0) return(16); /*行仍为高,无按健,退出*/
else msdelay(10);
for(i=1;i<16;i=i*2)
{m=i;
for(j=1;j<16;j=j*2)
{n=(~j)&0x0f;
P1=(m<<4)|n;/*m为P1的行值由i循环得到,n为列值,由j循环并取反得到*/
temp=P1&0xf0;
if (!temp)
{do{temp=P1&0xf0;}while(!temp);
matrix=m*(n+1);
switch(matrix) //此方法的基本思路:
{case 15:return(1); break; //由循环得到的m,n值赋于P1端口实现逐个键扫描
case 14:return(2); break; //同时由m,n+1的值相乘得到对应键点de的积
case 12:return(3); break; //m*(n+1)值扫描键点对应而得出键值
case 8:return(4); break; //
case 30:return(5); break; //
case 28:return(6); break; //
case 24:return(7); break; //
case 16:return(8); break;
case 60:return(9); break;
case 56:return(0); break;
case 48:return(10); break;
case 32:return(11); break;
case 120:return(12); break;
case 112:return(13); break;
case 96:return(14); break;
case 64:return(15); break;
default:return(16);
} //switch end
} //if loop
}//j loop
}//i loop
}//Key end
//依次扫描16个按键
uchar Key2(void)
{uchar temp;
P1=0xF0; /*使P1=1111 0000,行线电平为高,列线为低*/
temp=P1&0xf0;
if (temp==0xf0) return(16); /*读P1=1111 xxxx,表示行仍为高,无按健,退出(x表示不关心)?/
else msdelay(10);
P1=0x1e; /*P1=0001 1110,行一为高,列一为低,扫描第一个按键*/
temp=P1&0xf0;
if (!temp) {do{temp=P1&0xf0;}while(!temp);
return(1);}
P1=0x1d; /*P1=0001 1101,行一为高,列二为低,扫描第二个按键,下面扫描其余按键*/
temp=P1&0xf0;
if (!temp) {do{temp=P1&0xf0;}while(!temp);
return(2);}
P1=0x1b;
temp=P1&0xf0;
if (!temp) {do{temp=P1&0xf0;}while(!temp);
return(3);}
P1=0x17;
temp=P1&0xf0;
if (!temp) {do{temp=P1&0xf0;}while(!temp);
return(4);}
P1=0x2e;
temp=P1&0xf0;
if (!temp) {do{temp=P1&0xf0;}while(!temp);
return(5);}
P1=0x2d;
temp=P1&0xf0;
if (!temp) {do{temp=P1&0xf0;}while(!temp);
return(6);}
P1=0x2b;
temp=P1&0xf0;
if (!temp) {do{temp=P1&0xf0;}while(!temp);
return(7);}
P1=0x27;
temp=P1&0xf0;
if (!temp) {do{temp=P1&0xf0;}while(!temp);
return(8);}
P1=0x4e;
temp=P1&0xf0;
if (!temp) {do{temp=P1&0xf0;}while(!temp);
return(9);}
P1=0x4d;
temp=P1&0xf0;
if (!temp) {do{temp=P1&0xf0;}while(!temp);
return(0);}
P1=0x4b;
temp=P1&0xf0;
if (!temp) {do{temp=P1&0xf0;}while(!temp);
return(10);}
P1=0x47;
temp=P1&0xf0;
if (!temp) {do{temp=P1&0xf0;}while(!temp);
return(11);}
P1=0x8e;
temp=P1&0xf0;
if (!temp) {do{temp=P1&0xf0;}while(!temp);
return(12);}
P1=0x8d;
temp=P1&0xf0;
if (!temp) {do{temp=P1&0xf0;}while(!temp);
return(13);}
P1=0x8b;
temp=P1&0xf0;
if (!temp) {do{temp=P1&0xf0;}while(!temp);
return(14);}
P1=0x87;
temp=P1&0xf0;
if (!temp) {do{temp=P1&0xf0;}while(!temp);
return(15);}
return(16); //扫描all按键都未按下,则输出16
}//Key2 end.
////////时钟中断显示子程序
void T0_int() interrupt 1
{static uchar i;
if (i==6){i=0;}
P0=5-i;
P0=P0|(dis[i]<<4);
i++;
TL0=0;
TH0=252;}
void distri(uint disnum)
{uint temp;
dis[0]=0;
dis[1]=disnum/10000;
temp=disnum%10000;
dis[2]=temp/1000;
temp=temp%1000;
dis[3]=temp/100;
temp=temp%100;
dis[4]=temp/10;
dis[5]=temp%10;
}
Main()
{uchar KeyVal,i=0;
TMOD=0x01;
IE=0x82;
TH0=252;
TL0=0;
TR0=1;
distri(0);
do{
KeyVal=Key();
if (KeyVal!=16) dis[1]=KeyVal; //注意:当有按键时才赋于显示位dis[1],否则出错,请分析!
}while(1);
}