基于单片机的电子密码锁设计

基于单片机的电子密码锁设计,第1张

功能键

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 dula=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=0n<mn++)

}

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=0i<8i++)

{

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=0nop()sda=1

for (i=0i<8i++)

{

nop()scl=1nop()

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=ij>0j--)

for(k=125k>0k--)

}

void display(uchar a,uchar b,uchar c,uchar d,uchar e,uchar f)

{

dula=0

P0=table[a]

dula=1

dula=0

wela=0

P0=0xfe

wela=1

wela=0

delay(5)

P0=table[b]

dula=1

dula=0

P0=0xfd

wela=1

wela=0

delay(5)

P0=table[c]

dula=1

dula=0

P0=0xfb

wela=1

wela=0

delay(5)

P0=table[d]

dula=1

dula=0

P0=0xf7

wela=1

wela=0

delay(5)

P0=table[e]

dula=1

dula=0

P0=0xef

wela=1

wela=0

delay(5)

P0=table[f]

dula=1

dula=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=0wei=0

genggai=0

old1=new1old2=new2old3=new3//此时,旧的密码将被代替

old4=new4old5=new5old6=new6

//新密码写入存储区。

write24c02(110,old1)

write24c02(111,old2)

write24c02(112,old3)

write24c02(113,old4)

write24c02(114,old5)

write24c02(115,old6)

a=16b=16c=16d=16e=16f=16

}

if(retry) //当重试按键S18被按下,retry会被置位

{

retry=0wei=0wanbi=0

a=16b=16c=16d=16e=16f=16

new1=0new2=0new3=0new4=0new5=0new6=0

}

if(close) //当关闭密码锁按键被按下,close会被置位

{

close=0genggai=0//所有变量均被清零。

wei=0 wanbi=0

allow=0

P1=0xff

a=16b=16c=16d=16e=16f=16

new1=0new2=0new3=0new4=0new5=0new6=0

}

display(a,b,c,d,e,f)//实时显示

}

}

对着代码自己做吧,,要是还做不出来,,那我就不说什么了,,

用STC52编的,下面是C程序,调试已经成功,自己看程序吧……

#include<reg52.h>

#include <intrins.h>

#define uchar unsigned char

#define uint unsigned int

#define LCD_data P0

sbit SDA=P3^5

sbit SCL=P3^4//24C08控制口设置

sbit LCD_RS = P3^3 //寄存器选择输入

sbit LCD_RW = P3^6 //液晶读/写控制

sbit LCD_EN = P3^7 //液晶使能控制

sbit LCD_PSB = P3^2 //串/并方式控制

sbit FM=P2^4//蜂鸣器控制口

sbit RS=P2^5

sbit T_CLK = P2^0//实时时钟时钟线引脚 //

sbit T_IO = P2^1//实时时钟数据线引脚 //

sbit T_RST = P2^2//实时时钟复位线引脚 //

sbit ds=P2^3

sbit EN=P2^6

sbit ZZ=P2^7

sbit FZ=P3^1

sbit ACC0=ACC^0

sbit ACC7=ACC^7

uint temp1,s_temp //定义整形变量

float f_temp //定义浮点型变量

uchar time[]=" : : "

uchar day[]=" 20 / / ( ) "

uchar temp0[]=" 温度: . 度 "

uchar num,num1,flag,count,a,b

uchar unlock_i//解密标志位

uchar t[4]

uchar t1[4]

void delay_ms(uint z)//长延时

{

uint x,y

for(x=zx>0x--)

for(y=110y>0y--)

}

void delay() //短延时,大约5us

{

}

void reshi()

{

if(RS==1)

{ unlock_i=1

}

else

{

unlock_i=0

}

}

uchar code mima[]={'0','1','2','3','4','5','6','7','8','9','0','*'}

void lcd_xieping0(uchar x,uchar y,uchar date)

void lcd_xieping(uchar x,uchar y,uchar *str)

//********************************************************

//开机显示

//********************************************************

void kjxs()

{

uint i,j

lcd_xieping(0,0,"****************")

lcd_xieping(1,0,"欢迎进入")

lcd_xieping(2,0," 密码锁系统! ")

lcd_xieping(3,0,"****************")

delay_ms(4000)

lcd_xieping(0,0," 系统初始化中 ")

lcd_xieping(1,0,"请稍后…")

lcd_xieping(2,0,"————————")

lcd_xieping(3,0," ")

for(j=3j>0j--)

{

for(i=0i<8i++)

{

lcd_xieping(3,i,"*")

delay_ms(250)

}

lcd_xieping(3,0,"")

}

}

//********************************************************

//12864显示

//********************************************************

void write_cmd(uchar cmd)

{

LCD_RS = 0

LCD_RW = 0

LCD_EN = 0

P0 = cmd

delay_ms(5)

LCD_EN = 1

delay_ms(5)

LCD_EN = 0

}

void write_dat(uchar dat)

{

LCD_RS = 1

LCD_RW = 0

LCD_EN = 0

P0 = dat

delay_ms(5)

LCD_EN = 1

delay_ms(5)

LCD_EN = 0

}

void lcd_xieping0(uchar x,uchar y,uchar date)

{

switch(x)

{

case 0: write_cmd(0x80+y)break

case 1: write_cmd(0x90+y)break

case 2: write_cmd(0x88+y)break

case 3: write_cmd(0x98+y)break

}

write_dat(date)

}

void lcd_xieping(uchar x,uchar y,uchar *str)

{

switch(x)

{

case 0: write_cmd(0x80+y)break

case 1: write_cmd(0x90+y)break

case 2: write_cmd(0x88+y)break

case 3: write_cmd(0x98+y)break

}

while (*str)

{

write_dat(*str)

str++

}

}

void lcd_init()

{

LCD_PSB = 1//并口方式

write_cmd(0x30) //基本指令 *** 作

delay_ms(5)

write_cmd(0x0C) //显示开,关光标

delay_ms(5)

write_cmd(0x01) //清除LCD的显示内容

delay_ms(5)

}

//**************************************************************

// 键盘扫描函数

//**************************************************************

uchar keyscan1()//矩阵键盘扫描函数

{

uchar temp

while(!num)

{P1=0xfe//赋值

temp=P1//读回数据

temp=temp&0xf0 //与运算

if(temp!=0xf0) //判断

{

delay_ms(2) //延时消抖

temp=P1//读回数据

temp=temp&0xf0

if(temp!=0xf0)

{

switch(temp) //多分支选择

{

case 0x70:num=1break //跳出

case 0xb0:num=2break

case 0xd0:num=3break

case 0xe0:num=4break

}

while(temp!=0xf0)

{

temp=P1

temp=temp&0xf0

}//等待按键释放

}

}

P1=0xfd//赋值

temp=P1//读回数据

temp=temp&0xf0 //与运算

if(temp!=0xf0) //判断

{

delay_ms(2) //延时消抖

temp=P1//读回数据

temp=temp&0xf0

if(temp!=0xf0)

{

switch(temp) //多分支选择

{

case 0x70:num=5break //跳出

case 0xb0:num=6break

case 0xd0:num=7break

case 0xe0:num=8break

}

while(temp!=0xf0)

{

temp=P1

temp=temp&0xf0

}//等待按键释放

}

}

P1=0xfb//赋值

temp=P1//读回数据

temp=temp&0xf0 //与运算

if(temp!=0xf0) //判断

{

delay_ms(2) //延时消抖

temp=P1//读回数据

temp=temp&0xf0

if(temp!=0xf0)

{

switch(temp) //多分支选择

{

case 0x70:num=9break //跳出

case 0xb0:num=10break

case 0xd0:num=11break

case 0xe0:num=12break

}

while(temp!=0xf0)

{

temp=P1

temp=temp&0xf0

}//等待按键释放

}

}

}

return(num)//返回值

}

uchar keyscan2()

{

uchar temp

while(!num1)

{P1=0xf7//赋值

temp=P1//读回数据

temp=temp&0xf0 //与运算

if(temp!=0xf0) //判断

{

delay_ms(2) //延时消抖

temp=P1//读回数据

temp=temp&0xf0

if(temp!=0xf0)

{

switch(temp) //多分支选择

{

case 0x70:num1=1break //跳出

case 0xb0:num1=2break

case 0xd0:num1=3break

case 0xe0:num1=4break

}

while(temp!=0xf0)

{

temp=P1

temp=temp&0xf0

}//等待按键释放

}

}

}

return(num1)

}

//**************************************************************

//直流电机

//**************************************************************

void dianjiZZ()

{

EN=1

ZZ=1

FZ=0

}

void dianjiFZ()

{

EN=1

ZZ=0

FZ=1

}

void dianji_stop()

{

EN=0

}

//**************************************************************

//EPPROM

//**************************************************************

void start() //启动信号

{

SDA=1

delay()

SCL=1

delay()

SDA=0

delay()

}

void stop()//停止信号

{

SDA=0

delay()

SCL=1

delay()

SDA=1

delay()

}

void respons() //响应信号

{

uchar i

SCL=1

delay()

while((SDA==1)&&(i<250))

i++

SCL=0

delay()

}

void writebyte(uchar date) //写一个字节

{

uchar i,temp

temp=date

for(i=0i<8i++)

{

temp=temp<<1

SCL=0

delay()

SDA=CY

delay()

SCL=1

delay()

}

SCL=0

delay()

SDA=1//释放总线

delay()

}

uchar readbyte() //读一个字节

{

uchar i,k

SCL=0

delay()

SDA=1

for(i=0i<8i++)

{

SCL=1

delay()

k=(k<<1)|SDA

SCL=0

delay()

}

delay()

return(k)

}

void write(uchar add,uchar date) //在一个地址写一个字节

{

start()

writebyte(0xa0)

respons()

writebyte(add)

respons()

writebyte(date)

respons()

stop()

}

uchar read(uchar add) //在一个地址读一个字节

{

start()

writebyte(0xa0)

respons()

writebyte(add)

respons()

start()

writebyte(0xa1)

respons()

b=readbyte()

respons()

stop()

return(b)

}

//**************************************************************

//时间日期函数

//**************************************************************

void v_WTInputByte(uchar ucDa)

{

uchar i

ACC= ucDa

for(i=8i>0i--)

{

T_IO = ACC0//*相当于汇编中的 RRC

T_CLK = 1

T_CLK = 0

ACC =ACC>>1

}

}

uchar uc_RTOutputByte(void)

{

uchar i

for(i=8i>0i--)

{

ACC = ACC>>1//*相当于汇编中的 RRC

ACC7 = T_IO

T_CLK = 1

T_CLK = 0

}

return(ACC)

}

void v_W1302(uchar ucAddr, uchar ucDa)

{

T_RST = 0

T_CLK = 0

T_RST = 1

v_WTInputByte(ucAddr)/* 地址,命令 */

v_WTInputByte(ucDa)/* 写1Byte数据*/

T_CLK = 1

T_RST =0

}

uchar uc_R1302(uchar ucAddr)

{

uchar ucDa

T_RST = 0

T_CLK = 0

T_RST = 1

v_WTInputByte(ucAddr)// 地址,命令 //

ucDa = uc_RTOutputByte()// 读1Byte数据 //

T_CLK = 1

T_RST =0

return(ucDa)

}

void Init1302(void)

{

v_W1302(0x8e,0x00) //控制写入WP=0

v_W1302(0x80,0x80)

v_W1302(0x90,0xa9)

v_W1302(0x80,0x00) //秒

v_W1302(0x82,0x24) //分

v_W1302(0x84,0x12) //时

v_W1302(0x86,0x29) //日

v_W1302(0x88,0x10) //月

v_W1302(0x8a,0x05) //星期

v_W1302(0x8c,0x10) //年 //

v_W1302(0x8e,0x80)

}

void donetime(void)

{

uchar d

d=uc_R1302(0x87)

day[10]=(d&0x0f)+48

day[9]=((d>>4)&0x03)+48

d=uc_R1302(0x89)

day[7]=(d&0x0f)+48

day[6]=((d>>4)&0x01)+48

d=uc_R1302(0x8b)

day[13]=(d&0x07)+48

d=uc_R1302(0x8d)

day[4]=(d&0x0f)+48

day[3]=(d>>4)+48

d=uc_R1302(0x81)

time[15]=(d&0x0f)+48

time[14]=(d>>4)+48

d=uc_R1302(0x83)

time[12]=(d&0x0f)+48

time[11]=(d>>4)+48

d=uc_R1302(0x85)

time[9]=(d&0x0f)+48

time[8]=(d>>4)+48

}

//**************************************************************

//温度检测函数

//**************************************************************

void dsreset(void)//18B20复位,初始化函数

{

uint i

ds=0

i=103

while(i>0)i--

ds=1

i=4

while(i>0)i--

}

bit tempreadbit(void) //读1位函数

{

uint i

bit dat

ds=0i++ //i++ 起延时作用

ds=1i++i++

dat=ds//读数据

i=8while(i>0)i--

return (dat)

}

uchar tempread(void) //读1个字节

{

uchar i,j,dat

dat=0

for(i=1i<=8i++)

{

j=tempreadbit()

dat=(j<<7)|(dat>>1) //读出的数据最低位在最前面,这样刚好一个字节在DAT里

}

return(dat)

}

void tempwritebyte(uchar dat) //向18B20写一个字节数据

{

uint i

uchar j

bit testb

for(j=1j<=8j++)

{

testb=dat&0x01 //判断最后一位是1还是0

dat=dat>>1

if(testb) //写 1

{

ds=0

i++i++

ds=1

i=8while(i>0)i--

}

else

{

ds=0 //写 0

i=8while(i>0)i--

ds=1

i++i++

}

}

}

void tempchange(void) //DS18B20 开始获取温度并转换

{

dsreset()//初始化,每次对18B20的 *** 作都首先要初始化

delay_ms(1)

tempwritebyte(0xcc) // 写跳过读ROM指令

tempwritebyte(0x44) // 写温度转换指令

}

void get_temp() //读取寄存器中存储的温度数据

{

uchar a,b

dsreset() //初始化

delay_ms(1)

tempwritebyte(0xcc) // 写跳过读ROM指令

tempwritebyte(0xbe) //写读指令

a=tempread()//读低8位

b=tempread()//读高8位

temp1=b

temp1<<=8 //两个字节组合为1个字

temp1=temp1|a

f_temp=temp1*0.0625 //温度在寄存器中为12位 分辨率位0.0625°

}

//**************************************************************

//解密函数

//**************************************************************

void unlock()

{

uchar in,i

if(num==0)

{

lcd_xieping(0,0,"**密码锁系统**")

lcd_xieping(1,0,"—————————")

lcd_xieping(2,0," 请输入密码: ")

lcd_xieping(3,0,"")

for(i=0i<4i++)

{

t1[i]=keyscan1()

lcd_xieping(3,i,"*")

num=0

}//输密码

}

in=keyscan1()

if(in==12)//in-确定键标志位

{

in=0

num=0

if((t1[0]==t[0])&&(t1[1]==t[1])&&(t1[2]==t[2])&&(t1[3]==t[3]))

{

flag=1//解密成功与否标志位

//unlock_i=1

a=0//功能键标志

lcd_xieping(0,0,"**密码锁系统** ")

lcd_xieping(1,0,"——————————")

lcd_xieping(2,0,"密码正确!")

lcd_xieping(3,0," 您的身份已确认")

delay_ms(1500)

lcd_xieping(1,0,"————————")

lcd_xieping(2,0,"功能 I 开锁")

lcd_xieping(3,0," II修改密码")

}

else

{

flag=0

count++

if(count==3)

{

count=0

num=1

lcd_xieping(1,0,"——————————")

lcd_xieping(2,0,"您的机会已用完 ")

lcd_xieping(3,0,"对不起**无法进入")

FM=0

delay_ms(1000)

FM=1

}

}

}

}

//**************************************************************

// 修改密码函数

//**************************************************************

void xiugaimima()

{ uchar i,j,l,im,ib

uchar t2[4]

uchar t3[4]

num=0

lcd_xieping(1,0,"————————")

lcd_xieping(2,0,"请输入新密码: ")

lcd_xieping(3,0,"")

for(i=0i<4i++)

{

t2[i]=keyscan1()

lcd_xieping0(3,i,mima[num])

num=0

}

im=keyscan1()

if(im==12)//im,in,ib,同为确定键标志位

{

im=0

num=0

lcd_xieping(1,0,"————————")

lcd_xieping(2,0,"请再次输入新密码")

lcd_xieping(3,0,"")

for(i=0i<4i++)

{

t3[i]=keyscan1()

lcd_xieping0(3,i,mima[num])

num=0

}

}

ib=keyscan1()

if(ib==12)

{

ib=0

num=0

if(t2[0]==t3[0]&&t2[1]==t3[1]&&t2[2]==t3[2]&&t2[3]==t3[3])

{

t[0]=t3[0]

t[1]=t3[1]

t[2]=t3[2]

t[3]=t3[3]

lcd_xieping(1,0,"————————")

lcd_xieping(2,0,"祝贺您!")

lcd_xieping(3,0," 密码修改成功 ")

flag=0

for(j=0j<4j++)

{

l=j+1

write(l,t[j])

delay_ms(10)

}//24C08写数据

delay_ms(1000)

}

else

{

lcd_xieping(2,0,"两次输入密码不同")

lcd_xieping(3,0," 密码修改失败 ")

flag=1

delay_ms(500)

}

}

}

//**************************************************************

//显示函数

//**************************************************************

void xianshi()

{

donetime()

tempchange()

get_temp()

s_temp=f_temp*100

temp0[7]=(s_temp/1000)+48

temp0[8]=(s_temp%1000/100)+48

temp0[10]=(s_temp%100/10)+48

temp0[11]=(s_temp%10)+48

lcd_xieping(0,0,"**密码锁系统** ")

lcd_xieping(1,0,temp0)

lcd_xieping(2,0,day)

lcd_xieping(3,0,time)

num=0

}

//**************************************************************

//开锁函数

//**************************************************************

void kaisuo()

{

uchar i

lcd_xieping(2,0,"开锁中…… ")

lcd_xieping(3,0,"——耐心等待——")

for(i=3i>0i--)

{

FM=0

delay_ms(100)

FM=1

delay_ms(100)

flag=0

}

dianjiZZ()

delay_ms(10000)

dianji_stop()

lcd_xieping(2,0,"—开锁过程结束—")

lcd_xieping(3,0,"请开门")

delay_ms(5000)

dianjiFZ()

delay_ms(10000)

dianji_stop()

flag=0

}

//**************************************************************

//主函数

//**************************************************************

void main()

{

uchar m

unlock_i=1

lcd_init() //液晶初始化

//Init1302()

kjxs() //开机显示

for(m=0m<4m++)

{

t[m]=read(m+1)

delay_ms(10)

}//24C08读数据

while(1)

{

reshi()

if(!unlock_i)

{

unlock()//解密函数

}

else

{

xianshi()//时间、日期、温度显示函数

}

if(flag==1)

{

num1=0

a=keyscan2()

if(a==1)

{

kaisuo()//开锁函数

}

if(a==2)

{

xiugaimima()//修改密码函数

}

}

}

}

完成功能说明:

基本功能以及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

ALARMEQU22H.1 报警标志位

ALARM_OUTEQU22H.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 EQU51H 用于输入密码次数是否超过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 红灯代表输入密码错误

SPKEQU 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

CJNEA,#00H,ENTER_PW_MODE_3

INC R0

INC R1

CJNER0,#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 片选

CJNER0,#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

DJNZR6,$

DJNZR7,DL

RET

=======================================

============定时器中断服务程序=========

T0_SER:

MOV TMOD,#01H

SETB BT0

MOV TH0,TH0_BUFFER

MOV TL0,TL0_BUFFER

RETI

=======================================

END


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/10965043.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-12
下一篇 2023-05-12

发表评论

登录后才能评论

评论列表(0条)

保存