开篇先说一句废话····
本旺名字叫萨摩耶,,Please 叫我旺财,,,哈哈,招财进宝嘛!
开篇
其实这个项目很早之前就想做的,当时有个新闻上讲有个学校的同学在自家宿舍门上安装了电子密码锁,当时就想着等自己学习了一定要做出来玩玩,之前看到蓝桥杯单片机组有一道试题和那个新闻差不多,也就是这篇文章写的《智能门锁》。
项目要求
直接上图。
以下内容都截取自模拟试题文件,完整内容和工程文件会打包上传,键总结处。阅读建议,先滑到最后下载上传文件,阅读完整项目要求后再阅读此篇,效果会更好。还要注意的就是说明过程中代码都是拼接到一起的,使用的时候一定要注意。
项目分析
完成项目的每一步在那个试题文件里都告诉了,咱干的事就是按照它说的每一步完成对应功能即可。
3.2初始状态说明
- 指示灯全部熄灭
- 数码管全部熄灭
- 继电器关闭
指示灯就是led,继电器的使用和led差不多,本篇中继电器原本由直流电机代替,后来由于引脚冲突,也换为led。所以指示灯熄灭和继电器关闭就是给对应引脚给高电平(led共阳极)。而数码管全部熄灭也就是给每个数码管段选信号为0x00.(数码管共阴极)
u8 DisPlay[8]; //数码管显示数组
u8 j;
//数码管全灭
for(j=0;j<8;j++)
DisPlay[j]=0x00;
//指示灯全灭
led1=1;
led7=1;
led8=1;
//电机关闭
moto=1;
//数码管显示
void Showsmg(){
u8 i;
for(i=0;i<8;i++){
switch(i){
case 0: LSA=0;LSB=0;LSC=0;break;
case 1: LSA=1;LSB=0;LSC=0;break;
case 2: LSA=0;LSB=1;LSC=0;break;
case 3: LSA=1;LSB=1;LSC=0;break;
case 4: LSA=0;LSB=0;LSC=1;break;
case 5: LSA=1;LSB=0;LSC=1;break;
case 6: LSA=0;LSB=1;LSC=1;break;
case 7: LSA=1;LSB=1;LSC=1;break;
}
P0=DisPlay[i];
Delay(1);
P0=0x00;
}
}
3.3设置按键功能即对应处理
按键检测和按键处理
既然有了按键功能,按一定有按键检测和按键处理了。
#define GPIO_KEY P1
u8 KeyVal;
bit flag;//按键检测,检测是否有按键按下
void KeyDown(){
char a=0;
GPIO_KEY=0x0f;
if(GPIO_KEY!=0x0f){
Delay(10);
if(GPIO_KEY!=0x0f){
GPIO_KEY=0x0f;
switch(GPIO_KEY){
case 0x07:KeyVal=0;flag=1;break;
case 0x0b:KeyVal=1;flag=1;break;
case 0x0d:KeyVal=2;flag=1;break;
case 0x0e:KeyVal=3;flag=1;break;
}
GPIO_KEY=0xf0;
switch(GPIO_KEY){
case 0x70:KeyVal=KeyVal;break;
case 0xb0:KeyVal=KeyVal+4;break;
case 0xd0:KeyVal=KeyVal+8;break;
case 0xe0:KeyVal=KeyVal+12;break;
}
}while((a<150)&&(GPIO_KEY!=0xf0)){
Delay(1);
a++;
}
}
}
//按键处理
void Keypross(){
if(flag==1){
switch(KeyVal){
case 0:Numpross(0);break;
case 1:Numpross(1);break;
case 2:Numpross(2);break;
case 3:Numpross(3);break;
case 4:Numpross(4);break;
case 5:Numpross(5);break;
case 6:Numpross(6);break;
case 7:Numpross(7);break;
case 8:Numpross(8);break;
case 9:Numpross(9);break;
case 10:break;
case 11:break;
case 12:break;
case 13:Delpross();break; //进入删除函数设置
case 14:Modpross();break; //进入修改函数设置
case 15:Pripross();break; //进入输入模式函数
}
}
}
输入模式设置
按照文件步骤,接下来是输入模式设置
这块有三个part,一个是进入密码输入模式,也就是Pripross()函数设置 首先是页面显示 – ,还有就是要设置一个标志位,来允许数字按键输入的有效与无效。
u8 PassFlag; //密码标志
//输入功能处理
void Pripross(){
u8 j;
KeyVal=0xff;
DisPlay[7]=0x40; // 显示“-”
for(j=0;j<7;j++)
DisPlay[j]=0x00;
PassFlag=1; //允许输入密码
}
第二就是数字按键的处理,如果允许数字按键输入有效,首先把密码存放在用户输入密码数组中,接着就是数码管的显示,因为数码管显示最后是根据一个数组DisPlay[]的,所以只需控制DisPlay[]的元素即可。
因为每按下一个按键,新的数据显示在最后面,之前的数据依次往左移一位,也就是先把前一个数组的数据传给后面的数组(DisPlay[0]是最前面,DisPlay[7]是最后)而传多少次也就是PassPriFlag这个标志位来控制,最后就是把新的数据存放到最前面的数组中。
其实这个数码管显示数组和蛇的移动差不多,蛇移动的过程分解开的话,就是蛇头在不断添加新的数据,(它来控制新的位置信息),而蛇身的运动就是除了蛇头意外,其他的每一节都走前一节的位置(除蛇头以外,每一节都保存前一节的数据),和数码管数组作比较,蛇身的运动,就是除了蛇头外,其他的是把一个数组的数据传给后一个数组中;蛇头就是DisPlay[0],用来保存新的数据,而循环的次数,对于蛇是它的节数,对于数码管就是输入的位数PassPriFlag
三是如果输入完得给一个标志位来判断密码是否输完,注意这里只是是否输完,不是密码是否正确。如果输完,不能接着输入密码,也就是数字按键输入是无效.
u8 PassFlag; //密码标志
u8 PassPriFlag; //密码自加标志
u8 PrintFlag; //输入结束标志
u8 UserPassword[6]; //用户输入的密码数组
u8 AdminPassword[6]; //系统保存的密码数组
//数字按键处理
void Numpross(u8 dat){
u8 i,j;
KeyVal=0xff;
if(PassFlag==1){
UserPassword[PassPriFlag]=dat;
for(i=PassPriFlag;i>0;i--){ //先传蛇身的数据
DisPlay[i]=DisPlay[i-1];
}
DisPlay[i]=smgduan[dat]; //传完后加载蛇头的数据
PassPriFlag++;
if(PassPriFlag==6){
PassPriFlag=0;
PassFlag=0; //如果接着输入,数字按键输入失效
PrintFlag=1;
}
}
}
判断密码与对应处理
密码输入完成后就是回到主函数中判断密码正确与否和对应的处理了。
首先就是密码判断,直接循环6次,判断用户输入密码数组和系统密码数组是否正确,如果正确,给一个标志位,,如果不正确,给一个标志位并退出判断循环。
if(PrintFlag==1){ //输入结束开始判断密码是否正确
PrintFlag=0;
for(i=0;i<6;i++){
if(UserPassword[i]==AdminPassword[i]){
PassRE=1;
}
else{
PassRE=2;
break; //密码错误退出
}
}
}
根据要求,密码正确或者密码错误都有一个相同点就是倒计时5s,首先就是定时器的设置,要注意的是初始化的时候要关闭定时器。
//定时器0初始化
void Time0Init(){
TMOD=0x01;
TH0=(65536-9174)/256; //10ms
TL0=(65536-9174)%256;
EA=1;
ET0=1;
TR0=0;
}
void Time0() interrupt 1{
TH0=(65536-9174)/256; //10ms
TL0=(65536-9174)%256;
tt++;
if(tt==100){
tt=0;
time++;
}
}
接着,因为都有倒计时,所以无论密码正确与否,都开启定时器,并把按键标志归零,来判断密码正确时是否有按键操作。
flag=0; //检测是否有按键按下
TR0=1;
然后就是,密码正确或者密码错误的分别处理了
- 密码正确 :继电器打开,然后就是数码管的显示,直接赋给段选信号即可。因为密码正确或者错误后5s后结果不同,还要设置一个标志位来区别。
- 密码错误 :L1指示灯亮,同样,设置一个标志位。
u8 PassRE; //密码正确错误标志
u8 DoLapFlag; //门或灯状态标志
if(PassRE==1){
moto=0; //开启电机
DisPlay[7]=smgduan[0]; //第一位显示O
DisPlay[6]=0x00;
DisPlay[5]=0x00;
DisPlay[4]=0x00;
DisPlay[3]=smgduan[0]; //显示O
DisPlay[2]=smgduan[16]; //显示P
DisPlay[1]=smgduan[14]; //显示E
DisPlay[0]=smgduan[17]; //显示N
DoLapFlag=1;
}
if(PassRE==2){
led1=0; //L1指示灯亮
DoLapFlag=2;
}
不同的结果处理完就要处理定时5s后的操作了
- 门状态,如果5s到了,而且没有按键按下,进入初始化状态,如果有按键按下,标志归零,(因为有按键的话,在按键处理中就进入功能了)
- 等状态,如果5s到了,指示灯熄灭,进入初始化状态等待
因为最后除了有按键按下时进入函数了,其他情况都是进入初始化状态,所以分别把定时器关闭。
if(DoLapFlag==1){
if(time==5){
if(flag==0){
time=0;
TR0=0;
Init(); //进入初始化状态
}
else{
flag=0; //归零
time=0;
}
}
}
if(DoLapFlag==2){
if(time==5){
time=0;
TR0=0;
led1=1;
Init(); //进入初始化状态
}
}
修改函数步骤
接着按照步骤,密码正确的情况下,按S12按键可以修改,这是修改函数即可。
在修改函数中,首先就是页面的显示,对数码管显示函数赋对应的段选信号。设置一个标志位,允许修改密码,要注意的就是,因为输入密码和修改密码处理不同的数组(用户输入密码数组和系统密码数组),所以当修改密码就不能输入密码,输入密码就不能修改密码。
//修改功能处理
void Modpross(){
u8 j;
KeyVal=0xff;
if((PassRE==1)){
PassRE=0;
DisPlay[7]=smgduan[12];
for(j=0;j<7;j++)
DisPlay[j]=0x00;
ModFlag=1; //允许修改密码
PassFlag=0; //不允许输入密码
DoLapFlag=0; //既不是门状态也不是灯状态,避免在修改密码数字按键过程中进入if条件恢复初始化状态
TR0=0; //关闭定时器
time=0;
}
}
接着就是数字按键,这里数字按键控制系统密码数组
保存到数组后,也是数码管显示,和输入密码差不多,如果密码输入六位,保存密码到AT24C02中,退出修改密码界面,也就是数码管显示数组修改为别的数据,这里全部关闭,要求又要计时5s,那启动定时器,重新计算时间(门状态,因为5s没操作门关闭)
if(ModFlag==1){
AdminPassword[PassPriFlag]=dat;
for(i=PassPriFlag;i>0;i--){
DisPlay[i]=DisPlay[i-1];
}
DisPlay[i]=smgduan[dat];
PassPriFlag++;
if(PassPriFlag==6){
PassPriFlag=0;
ModFlag=0;
//写入AT24C02
for(j=0;j<6;j++)
Write(j,AdminPassword[j]);
DoLapFlag=1; //重新计算时间
TR0=1;
moto=0; //开启电机
for(j=0;j<8;j++)
DisPlay[j]=0x00;
}
}
删除函数步骤
修改完,就是清除密码了,对删除函数处理
删除处理,有两部分,
- 第一就是输入密码模式下,首先先恢复密码输入状态,并重新统计密码位数(没有初始化用户输入密码数组,直接重新输入赋值)
- 第二就是修改密码下,这里因为数组被改变,必须重新从AT24c02中读取系统密码,数码管显示数组复位。
//清除功能处理
void Delpross(){
u8 k;
KeyVal=0xff;
if(PassFlag==1){ //输入密码模式下允许清除
//重新恢复输入密码状态
Pripross();
PassPriFlag=0; //重新统计密码位数
}
if(ModFlag==1){ //修改密码模式下允许清除
for(k=0;k<6;k++){
AdminPassword[k]=Read(i);
DisPlay[k]=0x00;
}
PassPriFlag=0; //重新统计密码位数
DisPlay[6]=0x00;
DisPlay[7]=smgduan[12];
}
}
结尾
最后剩下一些结尾。
led1指示灯功能已经设置了(在密码错误处)
led7指示灯是密码输入状态亮,其余不亮,led8指示灯是修改密码状态下亮,其余不亮,那结合起来,在参数设置的时候外加led即可
//输入模式
PassFlag=1; //允许输入密码
led7=0;
ModFlag=0; //不允许修改密码
led8=1;
//修改密码下
ModFlag=1; //允许修改密码
led8=0;
PassFlag=0; //不允许输入密码
led7=1;
最后就是主函数中的一些设置了
第一次烧录程序之前,先的往AT24c02中写入密码(888888),以后就把这些都注释了即可。
u8 AdminPassword[6]={8,8,8,8,8,8};
for(i=0;i<6;i++)
Write(i,AdminPassword[i]);
首先初始化和读取At24c02中的密码,不断地按键检测,按键处理,数码管显示,如果输入结束开始判断密码是否正确,最后就是5s计时后不同的处理了。
总结
大致步骤就是这样啦,因为我的水平有限,所以一定要下载pdf文件,先自己阅读一遍项目对项目有所了解,然后在根据步骤阅读这篇文章,这样效果会好点。
同样,完整代码和完整项目要求贴在这不方便,所以我打包上传了,链接在下面,为了避免掏钱,我设置了粉丝可下载,如果你觉得我写的还不错,还看得过去,就点个赞关注一下,就可以下载了;如果不想这样,也可以先关注然后下载后取关就好,都是为了学习知识。谢谢各位。