单片机源程序如下:
- /*****************************************************************
-
- 名称:51单片机密码锁
- 说明:1、开锁:输入6位密码加#号,密码正确报警“滴......”显示OK并开锁,
- 不正确声音提示“滴...滴”显示ERROR,重新输入密码,五次输入不正确,
- 报警滴...滴滴、锁机10分钟。
- 2、更改密码:输入管理员密码090564加#号,报警“滴....”,显示
- NEW Password,输入6位新密码加#号,报警“滴......”,已修改开锁密码。
- 密码存储于单片机内部EEPROM中,可有3459.4560万种密码。
- 器件:使用STC90C58R单片机,利用P2口、4x4键盘做键盘扫描口,12M晶体
- 晶振:12MHZ
- 时间:2020.12.18
- ******************************************************************/
- #include<stc90c.h>
- #include<intrins.h>
- #include "string.h"
- #define uchar unsigned char
- #define uint unsigned int
- #define WaitTime 0x01
- #define RdCommand 0x01
- #define PrgCommand 0x02
- #define EraseCommand 0x03
- #define open 0
- #define clok 1
- /*
- sfr ISP_DATA = 0xe2; //声明特殊功能寄存器//stc90c.h中已声明过,这里不需在声明
- sfr ISP_ADDRH = 0xe3;
- sfr ISP_ADDRL = 0xe4;
- sfr ISP_CMD = 0xe5;
- sfr ISP_TRIG = 0xe6;
- sfr ISP_CONTR = 0xe7;*/
- sfr MDT_CONTR=0xe1;
- sbit lcdrw=P3^6;
- sbit lcdrs=P3^5;
- sbit lcden=P3^4;
- sbit dula=P2^6;
- sbit wela=P2^7;
- sbit scl=P2^1;
- sbit sda=P2^0;
- sbit FM=P2^3;
- sbit lock=P1^0; //开关锁
- sbit lcd_led=P1^1; //开关LCD背景灯
- sbit P_25=P2^5;
- void read_busy();
- void lcdrw_dat(unsigned char dat); //写数据
- void check_k(); //检测确认键(k12)是否按下
- void lcdrw_com(unsigned char com);
- uchar code table[]="0123456789 *#ABCD";
- uchar code table1[]=" Password";
- uchar code table3[]=" OK";
- uchar code table6[]=" New Password";
- uchar code error[]=" ERROR";
- uchar table4[6];
- uchar table_open_password[6]={0x01,0x02,0x03,0x04,0x05,0x06};//开锁密码
- uchar table_update_password[6]={0x0,0x9,0x0,0x05,0x06,0x04};//改密码密码
- // 0 9 0 5 6 4
- uchar num,numl,i,a,b=0;//
- uint t=0,t1=0;
- uchar key_num;
- bit flag=0,flag1=0,flag2=0,flag3=0;
- void delayms(uint xms)
- {
- uint i,j;
- for(i=xms;i>0;i--)
- for(j=110;j>0;j--);
- }
- void yanshi500us(uint x)
- {
- uchar y;
-
- for(x;x>0;x--)
- for(y=240;y>0;y--);
- }
- void FM_3()
- {
- FM=0;
- delayms(100);
- FM=1;
- delayms(100);
- FM=0;
- delayms(100);
- FM=1;
- delayms(100);
- FM=0;
- delayms(100);
- FM=1;
- }
- void FM_2()
- {
- FM=0;
- delayms(100);
- FM=1;
- delayms(100);
- FM=0;
- delayms(100);
- FM=1;
- }
- void FM_1() // 按键时短响一声
- {
- FM=0;
- delayms(100);
- FM=1;
- }
- void FM_11() // ok时长响一声
- {
- FM=0;
- delayms(500);
- FM=1;
- }
- void xianshi_password()
- {
- for(i=0;i<12;i++)
- {
- lcdrw_dat(table1[i]);
- }
- }
- void xianshi_ok()
- {
- for(i=0;i<3;i++)
- {
- lcdrw_dat(table3[i]);
- }
- }
- void xianshi_New_Password()
- {
- for(i=0;i<14;i++)
- {
- lcdrw_dat(table6[i]);
- }
- }
- void xiansh_error()
- {
- for(i=0;i<10;i++)
- {
- lcdrw_dat(error[i]);
- }
- }
- //==================以下是内部EEPROM操作================
- /*******************打开ISP/ISA功能*********************/
- void ISP_IAP_enable()
- {
- EA=0;
- ISP_CONTR=ISP_CONTR & 0x18; //ISP_CONTR复位
- ISP_CONTR=ISP_CONTR | WaitTime; //设置等待时间
- ISP_CONTR=ISP_CONTR | 0x80; //允许读/写/擦除
- }
- /*********************关闭ISP/ISA功能*******************/
- void ISP_IAP_disable()
- {
- ISP_CONTR=ISP_CONTR & 0x7f; //禁止读/写/擦除
- // ISP_TRIG=0x00;
- EA=1;
- }
- /*******************读/写/擦除的触发代码*****************/
- void ISPgoon()
- {
- ISP_IAP_enable(); //打开ISP/ISA功能
- ISP_TRIG=0x46; //写入0x46;0xb9;使命令生效
- ISP_TRIG=0xb9;
- _nop_ ();
- }
- /***********************读字节***************************/
- uchar byte_read(uint byte_addr)
- {
- ISP_ADDRH=(uchar)(byte_addr>>8); //设置读字节地址
- ISP_ADDRL=(uchar)(byte_addr & 0x00ff);
- ISP_CMD=ISP_CMD & 0xf8; //清除低三位
- ISP_CMD=ISP_CMD | RdCommand; //读命令0x01
- ISPgoon(); //开始读
- ISP_IAP_disable(); //关闭IAP功能
- return(ISP_DATA); //返回读出的数据
- }
- /*********************扇区擦除***********************/
- void SectorErase(uint Sector_addr)
- {
- ISP_ADDRH=(uchar)(Sector_addr>>8); //设置要擦除扇区地址
- ISP_ADDRL=0x00;
- ISP_CMD=ISP_CMD & 0xf8; //清除低三位
- ISP_CMD=ISP_CMD | EraseCommand; //删除命令0x03
- ISPgoon(); //开始删除
- ISP_IAP_disable(); //关闭IAP功能
- }
- /************************字节写*************************/
- void byte_write(uint byte_addr,uchar original_data)
- {
- ISP_ADDRH=(uchar)(byte_addr>>8); //取地址高八位
- ISP_ADDRL=(uchar)(byte_addr&0x00ff);//取地址低八位
- ISP_CMD=ISP_CMD & 0xf8; //清零低三位
- ISP_CMD=ISP_CMD | PrgCommand; //写命令0x02
- ISP_DATA=original_data; //数据放入ISP_DATA
- ISPgoon(); //开始写入
- ISP_IAP_disable(); //关闭IAP功能
- }
- //================以下是LCD操作=========================
- void read_busy() //LCD1602 忙等待
- {
- lcdrs = 0;
- lcdrw = 1;
- lcden = 1;
- P0 = 0xff;
- while (P0&0x80);
- lcden = 0;
- }
-
- void lcdrw_com(unsigned char com) //写命令
- {
- read_busy();
- lcdrw=0;
- lcdrs=0;
- P0=com;
- yanshi500us(1);
- lcden=1;
- yanshi500us(1);
- lcden=0;
- // lcdrs=1;
- yanshi500us(10);
- }
-
- void lcdrw_dat(unsigned char dat) //写数据
- {
- read_busy();
- lcdrw=0;
- lcdrs=1;
- P0=dat;
- yanshi500us(1);
- lcden=1;
- yanshi500us(1);
- lcden=0;
- // lcdrs=1;
- yanshi500us(10);
- }
-
- void lcdinit()
- {
- P0=0x0;
- dula=1;
- dula=0;
- P0=0xff;
- wela=1;
- wela=0;
-
- yanshi500us(30);
- lcdrw_com(0x38); //设置16*2屏显,5*7点阵,8位数据接口
- yanshi500us(10);
- lcdrw_com(0x38);
- yanshi500us(10);
- lcdrw_com(0x38);
- yanshi500us(10);
- lcdrw_com(0x08); //关闭显示
- lcdrw_com(0x01); //清屏
- lcdrw_com(0x06); //读写一个字符后指针加一光标加一
- lcdrw_com(0x0c); //开显示,显示光标,光标闪烁
- xianshi_password();
- }
-
- //==================键盘扫描=========================
-
- void keyscan()
- {
- uchar num1,num2,a1;
- if(flag==0)
- {
- P2=0x0f;
- delayms(1); //延时一下使IO口稳定
- {
- if(P2!=0x0f)
- {
- delayms(50);
- if(P2!=0x0f)
- {
- num1=P2;
- P2=0xf0; //反转P2口
- delayms(1); //延时一下使IO口稳定
- num2=P2;
- delayms(50);
- while((P2!=0xf0));
- a1=num1 | num2;
- lcd_led=0; //开LCD背景灯
- EA=0;
- t1=200; //设置定时器定时10秒
- t=0;
- EA=1;
- TR0 = 1; //开定时器
- switch(a1)
- {
- case 0xee: key_num =1; break; //1
- case 0xde: key_num =2; break; //2
- case 0xbe: key_num =3; break; //3
- case 0x7e: key_num =13; break; //A
- case 0xed: key_num =4; break; //4
- case 0xdd: key_num =5; break; //5
- case 0xbd: key_num =6; break; //6
- case 0x7d: key_num =14; break; //B
- case 0xeb: key_num =7; break; //7
- case 0xdb: key_num =8; break; //8
- case 0xbb: key_num =9; break; //9
- case 0x7b: key_num =15; break; //C
- case 0xe7: key_num =11; break; //*
- case 0xd7: key_num =0; break; //0
- case 0xb7: key_num =12; break; //#
- case 0x77: key_num =16; break; //D
- }
-
- if(b==0)
- {
- lcdrw_com(0x01); //lcd清零
- }
- if(key_num!=12)
- {
- table4[b]=key_num;
- FM_1();
- if(flag2==1) //标识位为1,可写入新密码
- {
- lcdrw_dat(table[key_num]); //显示输入密码
- if(b==5)
- {
- flag3=1; //flag3=1写新密码结束
- flag2=0;
- }
- }
- else
- lcdrw_dat('*'); //显示*号
- }
- b++; //按键次数
- if(b==6)
- {
- b=0;
- }
- }
- }
- }
- }
- }
- /*================判断确认键是否按下=========================
- 如果确认键(#)按下,再判断密码是否正确(是开锁密码还是
- 修改密码的密)若正确即开锁或修改密码,不正确返回 。
- //==========================================================*/
- void check_k() //检测是否#键按下
- {
- if(key_num==12)
- {
- if(flag3==1) //标识flag3为1,新密码更新完毕
- {
- delayms(100);
- lcdrw_com(0x01); //清屏
- FM_11();
- xianshi_ok(); //显示ok
- delayms(1000);
- lcdrw_com(0x01); //清屏
- xianshi_password(); //显示password
- SectorErase(0x8000); //擦除EEPROM扇区
- for(i=0;i<6;i++)
- {
- table_open_password[i]=table4[i]; //向 table_open_password[]写入新密
-
- byte_write((0x8000+i),table4[i]); //向 EEPROM 写入新密码
- }
- b=0;
- flag3=0; //新密码更新完毕,标识flag3复位
- key_num=0; //封锁check_k函数
- table4[5]=0xff; //更改密码后将输入的密码打乱
- }
- else if((memcmp(table4, table_open_password, 6))==0)//开锁密码正确(本句是数组比较语句)
- {
- flag=1; //屏蔽键盘,不允许输入
- xianshi_ok(); //显示ok
- lock=open; //开锁
- FM_11();
- lock=clok; //关锁
- table4[5]=0xff; //开完锁后将输入的密码打乱
- delayms(1500);
- lcdrw_com(0x01); //清屏
- xianshi_password(); //显示password
-
- a=0;
- flag=0; //打开键盘,允许输入
- key_num=0; //封锁check_k函数
- b=0;
- }
- else if((memcmp(table4, table_update_password, 6))==0)//修改密码的密码正确(本句是数组比较语句)
- {
- flag=1; //屏蔽键盘,不允许输入
- xianshi_New_Password(); //显示New Password
- FM_11();
- flag2=1; //标识位置1,可以输入新密码
- // SectorErase(0x8000); //擦除EEPROM扇区
- key_num=0; //封锁check_k函数
- b=0;
- table4[5]=0xff; //将输入密码打乱
- flag=0; //打开键盘,允许输入
- }
- else //如果密码错误
- {
- flag=1;
- lcdrw_com(0x01); //清屏
- xiansh_error(); //显示错误
- if(a==4) //密码输错5次
- {
- FM_3();
- // flag=1;
- TR0=0;
- EA=0;
- t1=12000; //设置定时器定时10分钟
- t=0;
- EA=1;
- TR0=1;
- }
- else
- {
- FM_2();
- delayms(500);
- lcdrw_com(0x01); //清屏
- xianshi_password(); //显示password
- delayms(10);
- flag=0;
- }
- key_num=0; //封锁check_k函数
- b=0;
- a++; //密码错误次数
- }
- // P3=0xff; //进入掉电模式前让p3口为高电位
- // PCON |=0x02; //进入掉电模式
- }
- }
- //================定时器T0设置===================
- void Timer0Init(void) //5ms@12.000MHz
- {
- TMOD = 0x01;
- // TL0 = 0xB0; //设置定时初值 12MHZ
- // TH0 = 0x3C; //设置定时初值
- TL0 = (65536-50000)%256;
- TH0 = (65536-50000)/256;
- ET0 = 1; //清除TF0标志
- TR0 = 0;
- EA=1; //定时器0开始计时
- }
- //================定时器T0=====================
- void T0_time() interrupt 1
- {
- TL0 = (65536-50000)%256;
- TH0 = (65536-50000)/256;
- t++;
- if(t>=200) //定时10秒
- {
- P_25=1; //因为键盘扫描程序等待时P2口为0x0f关闭了U3,这里打开U3
- lcd_led=1; //关LCD背景灯
- P_25=0; //关闭U3,如果键盘单独一个P口在不需要
- }
- if(t>=t1)
- {
- b=0;
- lcdrw_com(0x01); //清屏
- xianshi_password(); //显示password
- t=0;
- a=0;
- flag=0;
- flag2=0;
- flag3=0;
- table4[5]=0xff; //将上次输入的密码打乱
- TR0=0;
- }
- }
- /************外部中断1函数****************
- *
- *
- void EX1_int() //外部中断1初始化 *
- { *
- IT1=1; *
- EA=1; *
- EX1=1; *
- } *
- *
- void exint() interrupt 2 //外部中断 *
- { *
- PCON &=0xfd; //进入掉电模式 *
- } *
- *********************************************/
- //===============主函数===================
- void main()
- {
- MDT_CONTR=0x35; //启动看门狗
- a=b=flag=flag1=flag2=flag3=0;
- lcdinit();
- Timer0Init();
- // EX1_int(); //掉电模式
-
- for(i=0;i<6;i++)
- {
- table_open_password[i]=byte_read(0x8000+i);
- //上电时将EEPROM中的密码取出放入table_open_password[]
- }
-
- while(1)
- {
- keyscan();
- check_k();
- MDT_CONTR=0x35; // 喂狗
- }
- }
复制代码
|