非常适合单片机新手,需要可来下载。
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机源程序如下(代码注释非常详细):
- #include <reg52.h>
- #include <intrins.h>
- #define uchar unsigned char // 以后unsigned char就可以用uchar代替
- #define uint unsigned int // 以后unsigned int 就可以用uint 代
- sbit SDA_P = P2^1; // 定义了AT24C02的SCL引脚
- sbit SCL_P = P2^0; // 定义了AT24C02的SDA引脚
- sbit LcdEn_P = P2^5; // 1602液晶的EN管脚
- sbit LcdRw_P = P2^6; // 1602液晶的RW管脚
- sbit LcdRs_P = P2^7; // 1602液晶的RS管脚
- sbit Beep_P = P3^3; // 蜂鸣器引脚
- sbit Relay_P = P3^2; // 继电器引脚
- uchar ArrCodeBuff[6]; // 密码输入缓冲区
- uchar ArrCodeUnlock[6]; // 解锁密码
- uchar ArrCodeTemp[6]; // 临时数组(修改密码时会用到)
- uchar ArrCodeAdmin[6]={1,2,3,1,2,3}; // 管理员密码
- uchar row,column; // 液晶的当前行列坐标
- uchar inputNum=0; // 输入的密码位数
- uchar inputMode=1; // =1输入解锁密码,=2输入修改密码1,=3输入解锁密码2
- uchar errTime=0; // 密码输入错误的次数
- /*********************************************************/
- // 毫秒级的延时函数,time是要延时的毫秒数
- /*********************************************************/
- void DelayMs(uint time)
- {
- uint i,j;
- for(i=0;i<time;i++)
- for(j=0;j<112;j++);
- }
- /*********************************************************/
- // 延时6微秒
- /*********************************************************/
- void Delay6us()
- {
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- }
- /*********************************************************/
- // 1602液晶写命令函数,cmd就是要写入的命令
- /*********************************************************/
- void LcdWriteCmd(uchar cmd)
- {
- LcdRs_P = 0;
- LcdRw_P = 0;
- LcdEn_P = 0;
- P0=cmd;
- DelayMs(2);
- LcdEn_P = 1;
- DelayMs(2);
- LcdEn_P = 0;
- }
- /*********************************************************/
- // 1602液晶写数据函数,dat就是要写入的数据
- /*********************************************************/
- void LcdWriteData(uchar dat)
- {
- LcdRs_P = 1;
- LcdRw_P = 0;
- LcdEn_P = 0;
- P0=dat;
- DelayMs(2);
- LcdEn_P = 1;
- DelayMs(2);
- LcdEn_P = 0;
- }
- /*********************************************************/
- // 1602液晶初始化函数
- /*********************************************************/
- void LcdInit()
- {
- LcdWriteCmd(0x38); // 16*2显示,5*7点阵,8位数据口
- LcdWriteCmd(0x0C); // 开显示,不显示光标
- LcdWriteCmd(0x06); // 地址加1,当写入数据后光标右移
- LcdWriteCmd(0x01); // 清屏
- }
- /*********************************************************/
- // 液晶光标定位函数
- /*********************************************************/
- void LcdGotoXY(uchar y, uchar x)
- {
- // 第一行
- if(y==0)
- LcdWriteCmd(0x80+x);
- // 第二行
- if(y==1)
- LcdWriteCmd(0x80+0x40+x);
- row=y;
- column=x;
- }
- /*********************************************************/
- // 液晶输出字符串函数
- /*********************************************************/
- void LcdPrintStr(uchar *str)
- {
- while(*str!='\0')
- LcdWriteData(*str++);
- }
- /*********************************************************/
- // IIC起始函数
- /*********************************************************/
- void IIcStart()
- {
- SDA_P=1;
- Delay6us();
- SCL_P=1;
- Delay6us();
- SDA_P=0;
- Delay6us();
- }
- /*********************************************************/
- // IIC终止函数
- /*********************************************************/
- void IIcStop()
- {
- SDA_P=0;
- Delay6us();
- SCL_P=1;
- Delay6us();
- SDA_P=1;
- Delay6us();
- }
- /*********************************************************/
- // IIC写一个字节
- /*********************************************************/
- void IIcWriteByte(uchar dat)
- {
- uchar i;
- for(i=0;i<8;i++)
- {
- dat=dat<<1;
- SCL_P=0;
- Delay6us();
- SDA_P=CY;
- Delay6us();
- SCL_P=1;
- Delay6us();
- }
- SCL_P=0;
- Delay6us();
- SDA_P=1;
- Delay6us();
- }
- /*********************************************************/
- // IIC读一个字节
- /*********************************************************/
- uchar IIcReadByte()
- {
- uchar i,temp,dat=0;
-
- SCL_P=0;
- Delay6us();
- SDA_P=1;
- Delay6us();
-
- for (i=0;i<8;i++)
- {
- SCL_P=1;
- Delay6us();
- temp=SDA_P;
- Delay6us();
- dat=(dat<<1)|temp;
- SCL_P=0;
- Delay6us();
- }
- return(dat);
- }
- /*********************************************************/
- // IIC总线响应
- /*********************************************************/
- void IIcRespons()
- {
- uchar i=0;
-
- SCL_P=1;
- Delay6us();
-
- while((SDA_P==1)&&(i<250))
- {
- i++;
- }
- SCL_P=0;
- Delay6us();
- }
- /*********************************************************/
- // IIC读出数据
- /*********************************************************/
- uchar IIcReadDat(uchar addr)
- {
- uchar dat;
- IIcStart(); // 开始信号
- IIcWriteByte(0xa0); // 写芯片地址(写)
- IIcRespons(); // 等待应答
- IIcWriteByte(addr); // 写内存地址(0-255)
- IIcRespons(); // 等待应答
- IIcStart(); // 开始信号
- IIcWriteByte(0xa1); // 写芯片地址(读)
- IIcRespons(); // 等待应答
- dat=IIcReadByte(); // 读取一个字节数据
- IIcRespons(); // 等待应答
- IIcStop(); // 结束信号
-
- DelayMs(2); // 简短延时
- return dat; // 返回读取到的数据
- }
- /*********************************************************/
- // IIC写入数据
- /*********************************************************/
- void IIcWriteDat(uchar addr,uchar dat)
- {
- IIcStart(); // 开始信号
- IIcWriteByte(0xa0); // 写芯片地址(写)
- IIcRespons(); // 等待应答
- IIcWriteByte(addr); // 写内存地址(0-255)
- IIcRespons(); // 等待应答
- IIcWriteByte(dat); // 写入数据
- IIcRespons(); // 等待应答
- IIcStop(); // 结束信号
- DelayMs(2); // 简短延时
- }
- /**********************************************************
- 矩阵键盘扫描程序.
- -----------------
- 如果扫描到有按键按下,则返回按键值,返回值情况如下所示:
- ----------------------------------
- | 第1列 第2列 第3列 第4列 |
- |第1行 1 2 3 12 |
- |第2行 4 5 6 13 |
- |第3行 7 8 9 14 |
- |第4行 10 0 11 15 |
- --------------------------------
- 如果扫描不到有按键按下,则返回99
- **********************************************************/
- uchar KeyScanf()
- {
- uchar ret,temp1,temp2;
-
- P1=0x0f;
- if(P1!=0x0f)
- {
- DelayMs(15);
- if(P1!=0x0f)
- {
- temp1=P1; // 判断出是哪一行按键按下
- P1=0xf0;
- DelayMs(5);
- temp2=P1; // 判断出是哪一列按键被按下
- ret=temp1|temp2; // 通过行和列的值,确定是哪个按键被按下
- switch(ret)
- {
- case 0xe7: return 1;
- case 0xd7: return 2;
- case 0xb7: return 3;
- case 0x77: return 12;
-
- case 0xeb: return 4;
- case 0xdb: return 5;
- case 0xbb: return 6;
- case 0x7b: return 13;
-
- case 0xed: return 7;
- case 0xdd: return 8;
- case 0xbd: return 9;
- case 0x7d: return 14;
-
- case 0xee: return 10;
- case 0xde: return 0;
- case 0xbe: return 11;
- case 0x7e: return 15;
- }
- return ret;
- }
- }
- return 99;
- }
- /*********************************************************/
- // 液晶显示密码
- /*********************************************************/
- void LcdPrintCode(uchar num)
- {
- LcdGotoXY(row,column); // 液晶显示定位
- LcdWriteData(num+0x30); // 显示输入的密码
- DelayMs(150); // 等待150毫秒
- LcdGotoXY(row,column); // 重新回到刚刚的显示位置
- LcdWriteData('*'); // 显示“*”替换刚刚显示的数字
- column++; // 液晶显示光标的纵坐标加1
- }
- /*********************************************************/
- // 蜂鸣器鸣叫
- /*********************************************************/
- void MingJiao(uint time)
- {
- Beep_P=0; // 蜂鸣器开始鸣叫
- DelayMs(time); // 延时
- Beep_P=1; // 蜂鸣器停止鸣叫
- }
- /*********************************************************/
- // 清除密码输入缓冲区的内容
- /*********************************************************/
- void ClearCodeBuff()
- {
- uchar i;
- for(i=0;i<6;i++) // 循环执行6次
- {
- ArrCodeBuff[i]=' '; // 每次清除一位密码缓冲区
- }
- inputNum=0; // 输入的密码位数为0
- }
- /*********************************************************/
- // 密码输入初始化
- /*********************************************************/
- void inputInit()
- {
- LcdGotoXY(0,0); // 光标定位
- LcdPrintStr(" State:lock "); // 液晶第0行显示" State:lock "
- LcdGotoXY(1,0); // 光标定位
- LcdPrintStr("Password: ");
- LcdGotoXY(1,9); // 液晶第1行显示"Password: "
- ClearCodeBuff(); // 清除密码缓冲区
- }
- /*********************************************************/
- // 密码初始化
- /*********************************************************/
- void CodeInit()
- {
- uchar dat,i;
- dat=IIcReadDat(10);
- if(dat!=88) // 如果是第一次使用AT24C02芯片
- {
- IIcWriteDat(0,1); // 给AT24C02第0个内存写入第一个密码“1”
- IIcWriteDat(1,2); // 给AT24C02第1个内存写入第二个密码“2”
- IIcWriteDat(2,3); // 给AT24C02第2个内存写入第三个密码“3”
- IIcWriteDat(3,4); // 给AT24C02第3个内存写入第四个密码“4”
- IIcWriteDat(4,5); // 给AT24C02第4个内存写入第五个密码“5”
- IIcWriteDat(5,6); // 给AT24C02第5个内存写入第六个密码“6”
- IIcWriteDat(10,88); // 给AT24C02第10个内存写入数字“88”,代表密码初始化好了
- }
- for(i=0;i<6;i++) // 从AT24C02读取6个密码,赋值给密码数组ArrCode
- {
- ArrCodeUnlock[i]=IIcReadDat(i);
- }
- }
- /*********************************************************/
- // 主函数,程序从这里开始执行
- /*********************************************************/
- void main()
- {
- uchar i; // 临时变量
- uchar keyVal; // 按键扫描的返回值
-
- uchar ArrCodeTemp[6]; // 临时数组
-
- LcdInit(); // 液晶初始化
- inputInit(); // 密码输入初始化
- CodeInit(); // 密码初始化
-
- while(1)
- {
-
- if(inputNum==6) // 如果输入了6位密码了
- LcdWriteCmd(0x0c); // 关闭光标闪烁
- else // 如果输入不够6位密码
- LcdWriteCmd(0x0f); // 开启光标闪烁
-
-
- keyVal=KeyScanf(); // 扫描按键是否有按键
- if(keyVal!=99) // 如果有按键被按下了
- {
- MingJiao(50); // 那么蜂鸣器鸣叫50毫秒
- }
-
-
- /* 0-9 数字 */
- if(keyVal<10) // 如果数字键被按下
- {
- if(inputNum<6) // 如果输入的密码不到6位
- {
- ArrCodeBuff[inputNum]=keyVal; // 给ArrCodeBuff缓冲区加入一个新的密码记录
- inputNum++; // inputNum加1,代表当前的密码输入多了一位
- LcdPrintCode(keyVal); // 将输入的密码显示出来
- }
- while(KeyScanf()!=99); // 等待按键释放
- }
-
-
- /* 删除一个密码 */
- if(keyVal==10) // 如果删除键被按下
- {
- if(inputNum>0) // 如果当前已经有输入密码了
- {
- column--; // 光标退回上一个位置
- LcdGotoXY(row,column);
- LcdWriteData(' '); // 显示空格
- LcdGotoXY(row,column); // 光标退回上一个位置
- inputNum--; // inputNum减1,代表当前的密码删掉了一位
- ArrCodeBuff[inputNum]=' '; // 清除一位密码缓冲区
- }
- while(KeyScanf()!=99); // 等待按键释放
- }
-
-
- /* 清除全部密码 */
- if(keyVal==11) // 如果取消键被按下
- {
- ClearCodeBuff(); // 清除密码缓冲区
-
- if(inputMode==1) // 如果当前正在输入解锁密码
- {
- LcdGotoXY(1,0); // 光标定位
- LcdPrintStr("Password: "); // 液晶第1行显示“Password: ”
- LcdGotoXY(1,9); // 光标定位
- }
-
- if(inputMode==2) // 如果当前正在输入修改密码1
- {
- LcdGotoXY(0,0); // 光标定位
- LcdPrintStr(" input1: "); // 液晶第0行显示“input1: ”
- LcdGotoXY(0,8); // 光标定位
- }
-
- if(inputMode==3) // 如果当前正在输入修改密码2
- {
- LcdGotoXY(1,0); // 光标定位
- LcdPrintStr(" input2: "); // 液晶第1行显示“input1: ”
- LcdGotoXY(1,8); // 光标定位
- }
- while(KeyScanf()!=99); // 等待按键释放
- }
-
-
- /* 手动关锁 */
- if(keyVal==12)
- {
- while(KeyScanf()!=99); // 等待按键释放
- }
-
- /* 取消密码修改 */
- if(keyVal==13) // 如果修改密码按键被按下
- {
- if((inputMode==2)||(inputMode==3)) // 如果当前正在输入修改密码
- {
- inputInit(); // 输入初始化(退出修改)
- Relay_P=1; // 继电器闭合
- inputMode=1; // 改为输入解锁密码模式
- }
- while(KeyScanf()!=99);
- }
-
-
- /* 管理员密码 */
- if(keyVal==14)
- {
- for(i=0;i<6;i++)
- {
- if(ArrCodeBuff[i]!=ArrCodeAdmin[i])
- break;
- }
- if(i<6)
- {
- LcdGotoXY(1,0);
- LcdPrintStr(" ERROR ");
- MingJiao(5000);
- }
- else
- {
- LcdGotoXY(1,0);
- LcdPrintStr("Password Init OK");
- MingJiao(3000);
- IIcWriteDat(10,' ');
- CodeInit();
- }
- inputInit();
- }
-
- /* 确认按键 */
- if(keyVal==15) // 如果确定键被按下
- {
- /*解锁密码*/
- if(inputMode==1) // 如果当前正在输入解锁密码
- {
- for(i=0;i<6;i++) // 把密码缓冲区的内容和解锁密码进行6次比较
- {
- if(ArrCodeBuff[i]!=ArrCodeUnlock[i])
- break;
- }
-
- if(i<6) // 如果密码错误
- {
- errTime++; // 错误次数加1
- LcdGotoXY(1,0); // 光标定位
- LcdPrintStr(" ERROR "); // 第1行显示" ERROR "
- LcdGotoXY(1,11); // 光标定位
- LcdWriteData(errTime+0x30); // 显示错误的次数
- LcdWriteCmd(0x0c); // 关闭光标闪烁
- MingJiao(3000); // 蜂鸣器鸣叫3秒
- if(errTime==3) // 如果错误了3次
- {
- LcdGotoXY(1,0); // 光标定位
- LcdPrintStr("Password:lock "); // 第1行显示"Password:locd "
- errTime=0; // 密码错误次数清零
- DelayMs(60000); // 延时60秒
- }
- }
- else // 如果密码正确
- {
- errTime=0; // 密码错误次数清零
- Relay_P=0; // 打开继电器
- LcdGotoXY(0,0); // 光标定位
- LcdPrintStr(" State:open "); // 第0行显示" State:open "
- LcdGotoXY(1,0); // 光标定位
- LcdPrintStr(" "); // 第1行显示" "
-
- for(i=0;i<100;i++) // 进行10秒等待,执行100次循环
- {
- keyVal=KeyScanf(); // 扫描按键
- DelayMs(100); // 等待100毫秒
-
- if(keyVal==12) // 如果手动关锁按键被按下
- break; // 退出for循环,结束开始等待
-
- if(keyVal==13) // 如果按下修改密码键
- {
- LcdGotoXY(0,0); // 光标定位
- LcdPrintStr(" input1: "); // 第0行显示" input1: "
- LcdGotoXY(1,0); // 光标定位
- LcdPrintStr(" input2: "); // 第1行显示" input2: "
- LcdGotoXY(0,8); // 光标定位
- inputMode=2; // 切换密码输入模式
- ClearCodeBuff(); // 清除密码缓冲区
- while(KeyScanf()!=99); // 等待按键释放
- break; // 退出for循环,进入密码修改
- }
- }
- }
-
- if(inputMode==1) // 如果当前处于输入解锁密码状态
- {
- Relay_P=1; // 闭合继电器
- inputInit(); // 密码输入初始化
- }
- }
-
- /*修改密码1*/
- else if(inputMode==2) // 如果当前正在输入修改密码1
- {
- for(i=0;i<6;i++) // 将输入的密码暂时存入ArrCodeTemp数组
- {
- ArrCodeTemp[i]=ArrCodeBuff[i];
- }
- LcdGotoXY(1,8); // 光标定位
- inputMode=3; // 改为输入 修改密码2
- ClearCodeBuff(); // 清除密码缓冲区
- while(KeyScanf()!=99); // 等待按键释放
- }
-
- /*修改密码2*/
- else
- {
- for(i=0;i<6;i++) // 将2次输入的密码进行比较
- {
- if(ArrCodeBuff[i]!=ArrCodeTemp[i])
- break;
- }
-
- if(i<6) // 密码修改错误
- {
- LcdGotoXY(0,0); // 光标定位
- LcdPrintStr("Password Modify "); // 第0行显示"Password Modify "
- LcdGotoXY(1,0); // 光标定位
- LcdPrintStr("-----failed-----"); // 第1行显示"-----failed-----"
- MingJiao(3000); // 蜂鸣器鸣叫3秒
- }
- else // 密码修改成功
- {
- LcdGotoXY(0,0); // 光标定位
- LcdPrintStr("Password Modify "); // 第0行显示"Password Modify "
- LcdGotoXY(1,0); // 光标定位
- LcdPrintStr("---Successful---"); // 第1行显示"---Successful---"
- MingJiao(2000); // 蜂鸣器鸣叫2秒
- for(i=0;i<6;i++)
- {
- IIcWriteDat(i,ArrCodeTemp[i]); // 将新的密码存入EEPROM芯片
- ArrCodeUnlock[i]=ArrCodeTemp[i]; // 将新的密码存入解锁密码数组
- }
- }
- Relay_P=1; // 继电器闭合
- inputMode=1; // 改为输入解锁密码模式
- for(i=0;i<6;i++) // 清空修改密码缓冲区
- {
- ArrCodeTemp[i]=' ';
- }
- inputInit(); // 输入初始化
- while(KeyScanf()!=99); // 等待按键释放
- }
- }
- }
- }
-
复制代码
所有资料51hei提供下载:
07、单片机程序(先解压,后查看).rar
(294.84 KB, 下载次数: 92)
08、电路图(原理图和PCB图).rar
(317.92 KB, 下载次数: 57)
09、仿真图.rar
(896.85 KB, 下载次数: 98)
|