|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?注册
x
本人做了一个LCD密码锁程序,但有点问题,请大哥大姐门指教
;===========电子密码锁程序==============================
;
KA EQU 0AH ;按键定义
KB EQU 0BH
KC EQU 0CH
KD EQU 0DH
KE EQU 0EH
KF EQU 0FH
PASS EQU 30H ;密码存储位置30到33H
PASSNEW EQU 34H ;存放新的密码
BUF_KEY EQU 4AH ;按键数据缓冲区
KEY_NO EQU 4BH ;按键编号
CO EQU 4CH ;计数变量
LCDE EQU 4DH ;LCD延迟变量
X EQU 53H ;LCD显示地址
FKEY EQU 20H.0 ;按键标志
EN EQU P0.1 ;LCD的引脚定义
RS EQU P0.0
SPK EQU P3.6 ;剌叭的引脚定义
REL EQU P3.5 ;继电器的引脚定义
WLED EQU P3.7 ;工作指示灯的定义
ORG 00H
JMP BEGIN ;程序开始
BEGIN:
CALL INIT_PORT
CALL LED_BL ;LED闪烁,程序开始
CALL BZ
CALL SET_LCD ;LCD初始化
CALL MLOOP ;执行主控程序
JMP $
MESS: DB "LP1.ASM 8051 PASSWORD WITH LCD"
PASS0: DB 1,2,3,4 ;内设的四位密码
;延迟子程序
DELAY:
MOV R6,#50
D1: MOV R7,#100
DJNZ R7,$
DJNZ R6,D1
DJNZ R5,DELAY
RET
;==========LED工作闪烁灯=--------------
LED_BL:
MOV R4,#6
LE0:
CPL WLED ;位取反
MOV R5,#30 ;延迟的时间为30ms
CALL DELAY
DJNZ R4,LE0
RET
;=====键盘按键编码====================
TABLE_DIG:
DB 0FH,0BH,0AH,00H
DB 0EH,03H,02H,01H
DB 0DH,06H,05H,04H
DB 0CH,09H,08H,07H
;============键盘的扫描子程序================
SCAN:
MOV R3,#0FEH ;加载扫描信号初值1111 1110
MOV R1,#4 ;执行一次循环四次
CLR PSW.5 ;psw.5=0表示没有键按下
L1:
MOV A,R3 ;将扫描信号的值放入累加器中
MOV P2,A ;将其值由P2口输出
MOV A,P2
MOV R5,#1 ;延迟10MS
CALL DELAY
MOV A,P2 ;读取P2数据以便判断是否有键按下
ANL A,#0F0H ;取得高四位值
MOV R2,#4 ;循环2执行四次
L2:
JB ACC.4,N1 ;累加器A位1若为1表示没按键
MOV KEY_NO,R4 ;加载按键编号
SETB PSW.5 ;按键标志设为1
N1: INC R4 ;按键编号加1
RR A ;累加器A右移一位扫描下一个按键
DJNZ R2,L2 ;判断行是否扫描完成,未扫描完成则继续
MOV A,R3 ;扫描完成则重新加载初值
RL A ;左移一位,则左移一位后变成0111,1111
MOV R3,A ;将变化后的的值放入R3中
DJNZ R1,L1 ;循环1判断是否继续执行
; 按键标志
BACK:
JNB PSW.5,NO_KEY ;设置是否按键
SETB FKEY ;若有按键则设其为1
RET
;没有按键则清标志
NO_KEY:
CLR FKEY
RET
;扫描键盘是否按下,然后
SCAN_KEY:
CLR FKEY ;清除按键标志
CALL SCAN ;执行按键扫描
JB FKEY,WAIT_OFF ;测试按键标志
RET
WAIT_OFF:
CALL SCAN ;执行按键扫描
JB FKEY,WAIT_OFF ;若有按键等待按键放开
RET
;等 待按键并传回按键码
GET_KEY:
CLR FKEY ;清标志
CALL SCAN
JB FKEY,G1 ;测试按键标志
JMP GET_KEY ;没有按下则继续扫描
G1:
CALL SCAN
JB FKEY,G1 ;按键是否放开
MOV A,KEY_NO
MOV DPTR,#TABLE_DIG ;经过取表找出按键码
MOVC A,@A+DPTR
RET
;显示新的密码
LOOK:
MOV CO,#4 ;显示输入的密码
MOV R0,#PASSNEW ;指向密码存放的变量区
L01:
MOV A,@R0 ;取出密码值
INC R0 ;指向下一个变量区
DJNZ CO,L01 ;是否完成四位
RET
;===密码比较程序=================
CHECK_PASS:
CALL IP_PASS ;取得要比较的密码
CALL LOOK ;显示要输入的密码
MOV CO,#4
MOV R0,#PASS
MOV DPTR,#PASS0
CH1:
MOV A,#0
MOVC A,@A+DPTR
MOV B,@R0
CJNE A,B,CH2
INC DPTR
INC R0
DJNZ CO,CH1
CALL OK
CALL LED_BL
CALL LED_BL
RET
CH2:
JMP COMP ;继续比较内部所设置的密码
ERROR:
CALL ERR ;密码错误处理
CALL LED_BL
RET
COMP:
MOV CO,#4
MOV R0,#PASS
MOV R1,#PASSNEW
C1:
MOV A,@R0
MOV B,@R1
CJNE A,B,ERROR
INC R0
INC R1
DJNZ CO,C1
CALL OK
RET
;===输入四位密码值
IP_PASS:
MOV DPTR,#M_IP
MOV A,#2
CALL LCD_PRINT ;在LCD上执行显示信息
MOV B,#9 ;设置LCD的位置
MOV CO,#4
MOV R0,#PASS
I1: CALL GET_KEY
MOV @R0,A
ADD A,#30H ;转换字符
CALL LCDP2
INC B
INC R0
DJNZ CO,I1
RET
OK: MOV DPTR,#M_OK
MOV A,#2
CALL LCD_PRINT
CALL DOOR_OPEN
RET
ERR:
MOV DPTR,#M_ERR
MOV A,#2
CALL LCD_PRINT
CALL ALARM
RET
SLINE2: ;在第二行上显示信息
MOV DPTR,#LMESS2
MOV A,#2
CALL LCD_PRINT
RET
;-----设置新的密码===========
SET_PASS:
MOV DPTR,#M_IP_NEW
MOV A,#2
CALL LCD_PRINT
MOV B,#12
MOV CO,#4
MOV R0,#PASSNEW
S1:
CALL GET_KEY
MOV @R0,A
ADD A,#30H
CALL LCDP2
INC B
INC R0
DJNZ CO,S1
RET
M_IP: DB "I/P PASS : .... ",0
M_OK: DB "PASSWORD OK !!! ",0
M_ERR: DB "PASSWORD ERROR !",0
M_IP_NEW: DB"I/P NEWPASS:...",0
;显示内部密码在LCD上
LOOK_PASS:
MOV B,#0
MOV CO,#4
MOV R0,#PASSNEW
LL:
MOV A,@R0
ADD A,#30H
CALL LCDP2
INC R0
INC B
DJNZ CO,LL
MOV R5,#100
CALL DELAY
CALL SLINE2
RET
;继电器开,关
REL_ON:
SETB REL
RET
REL_OFF:
CLR REL
RET
;初始化输入输出口
INIT_PORT:
CALL REL_OFF
RET
;继电器开启
DOOR_OPEN:
MOV R5,#200
CALL DELAY
CALL REL_OFF
RET
;警告声
ALARM:
MOV R2,#3
AL1:
CALL LED_BL
CALL BZ
DJNZ R2,AL1
RET
;蜂鸣器响
BZ: MOV R6,#0
B1: CALL DEL
CPL SPK
DJNZ R6,B1
RET
DEL: MOV R7,#180
DE1: NOP
DJNZ R7,DE1
RET
;主程序控制
MLOOP:
CALL GET_KEY
CJNE A,#KA,M1
CALL SET_PASS
CALL SLINE2
JMP MLOOP
M1: CJNE A,#KB,M2
CALL CHECK_PASS
CALL SLINE2
JMP MLOOP
M2: JMP MLOOP
RET
;LCD初始化
SET_LCD:
CLR EN ;启用失效
CALL INIT_LCD
MOV R5,#10
CALL DELAY
MOV DPTR,#LMESS1
MOV A,#1
CALL LCD_PRINT
MOV DPTR,#LMESS2
MOV A,#2
CALL LCD_PRINT
RET
LMESS1: DB "8051 PASSWORD ",0
LMESS2: DB "A OR B KEY ....",0
;初始化LCD
INIT_LCD1:
MOV A,#28H ;双列显示
CALL WCOM ;调用写命令
MOV A,#0CH ;光标移动不闪烁
CALL WCOM
MOV A,#0EH ;每次向右移动一位,显示屏不移动
CALL WCOM
MOV A,#01H ;清除LCD显示屏
CALL WCOM
RET
LCD_PRINT:
CJNE A,#1,LINE2 ;判断第一行是否显示完
LINE1:
MOV A,#80H ;设置第一行显示地址
CALL WCOM ;调用写地址
CALL CLR_LINE ;清除该行字符数据
MOV A,#80H ;写入命令
CALL WCOM
JMP FILL
LINE2:
MOV A,#0C0H ;设置第二行显示地址
CALL WCOM
CALL CLR_LINE ;调用清除命令
MOV A,#0C0H
CALL WCOM
FILL: ;填入字符
CLR A ;
MOVC A,@A+DPTR ;由消息区取出字符
CJNE A,#0,LC1 ;决断是否为结束码
RET
LC1:
CALL WDATA ;写入数据
INC DPTR ;数据指针加1
JMP FILL
RET
;************************************行清除***************************************
CLR_LINE:
MOV R0,#24 ;清除该行LCD字符
CL1: MOV A, #' ' ;填上空格字符
CALL WDATA ;调用写入数据
DJNZ R0,CL1 ;判断计数器是否满
RET
DE: MOV R7,#5 ;短暂延迟
DJNZ R7,$
RET
;*************************************短暂脉冲产生启用信号****************************
EN1:
SETB EN ;启用E
CALL DE
CLR EN
CALL DE
RET
;*********************************LCD初始化******************************************
INIT_LCD:
MOV P0,#30H ;4位数据输入输出口初始化D7_D4
CALL EN1
MOV P0,#30H
CALL EN1
MOV P0,#30H
CALL EN1
MOV P0,#20H
CALL EN1
CALL INIT_LCD1
RET
;*******************************写入指令**********************************************
WCOM:
MOV P0,A ;以四位从P0口输出
CLR RS ;写指令
CALL EN1
RLC A ;左移四位
RLC A
RLC A
RLC A
MOV P0,A ;从P0口输出
CLR RS
CALL EN1
RET
;**************************写入数据***************************************************
WDATA:
MOV P0,A ;从P0口输出数据
SETB RS ;设置写数据
CALL EN1
RLC A ;左移四位
RLC A
RLC A
RLC A
MOV P0,A
SETB RS
CALL EN1
RET
;**********************************************************************************
;***************************在LCD第一行显示字符************************************
LCDP1:
PUSH ACC ;将A放入堆栈
MOV A,B
ADD A,#80H
CALL WCOM
POP ACC
CALL WDATA
RET
;****************************************************************************
;*********************888888LCD第二行显示字符*********************************
LCDP2:
PUSH ACC
MOV A,B
ADD A,#0C0H
CALL WCOM
POP ACC
CALL WDATA
RET
END |
|