引言

背景

随着科技的不断进步,智能家居技术逐渐成为人们生活中的重要组成部分。在传统门锁存在的问题和需求的推动下,智能门锁作为一种创新的解决方案受到了广泛关注。智能门锁不仅提供了更高级别的安全性,还赋予了用户更便捷和智能化的门禁控制体验。

项目介绍

本实验报告旨在设计和实现一个智能门锁系统,该系统具备密码设定和重置功能,并在密码输入完成后给予反馈信息。我们将探索智能门锁在提供安全和便利性方面的潜力,并评估其性能和功能的可行性。

具体可用功能如下:

  • 门锁设定密码:用户可以通过设定密码来保护门锁的安全性。通过按键输入。

  • 密码验证:门锁可以对用户输入的密码进行验证,以确保只有授权用户可以进入。

  • 输错密码锁定:系统可以追踪用户输入的错误密码次数,当错误次数达到一定阈值时,智能门锁会自动锁定,以防止暴力破解。

  • 密码重置:用户可以选择重置密码,以便更换旧密码或恢复遗忘的密码。这个功能可以通过特定的操作流程或者按键组合来实现。

项目目标:

  • 提供高级别的安全性:智能门锁的主要目标是提供比传统门锁更高级别的安全性。通过使用密码验证和输错密码锁定功能,确保只有授权用户能够进入。

  • 提供便捷的门禁控制体验:智能门锁旨在提供便捷的门禁控制体验。用户可以通过设定和重置密码来管理门禁权限,而无需使用传统的钥匙。

  • 保护门锁免受暴力破解:通过输错密码锁定功能,智能门锁可以防止恶意攻击者通过暴力破解方式尝试多次密码,从而提高门锁的安全性。

  • 提供可定制的安全功能:智能门锁的设计允许用户根据自己的需求定制安全功能,如设定密码长度、锁定时间等,以满足不同环境和使用场景的要求。

Quartus

硬件设计原理图

首先是整体:

我们这里的电路首先大致上的思路是把显示器的电路和4*4键盘的电路所结合,它们各需要一个口进行数据的传输,因而确定了P0口用来进行显示器的相关数据的绑定,P3口用于进行4*4键盘的数据传输。

我们这里对P3和P1口进行处理,使得这两个I/O口成为双向口。

(如图为P3的处理,P1口的处理与其相同)

键盘帮助我们进行数据的输入,显示器用于相关信息的输出,为了实现多种功能,我们还需要其他的输出进行调控,这里我们使用了P2I,即P2口的输入。 P2的多位数值能够根据我们的需要随时修改为0或1。

这样我们还剩下一个P1口没有使用,P1可以帮助我们完成lcd显示的相关工作,还可以帮助完成蜂鸣器的发声。

我们这里P1的输出其中的声音信号以及控制lcd显示的相关信号。

关于这些P0,P1,P2,P3口的具体使用将在程序中介绍。

模式

我们选取的标准是存在扬声器并且尽可能拥有多的按键

于是最终采用的是存在扬声器且键1到键8均能控制一位数据的模式5

引脚说明

这里和我们功能密切相关的引脚有P1O[0..3],P2I[0..7],P0,P3

我们先说输入,

即P2I[0..6],本来可以使用8位,不过我们最后只使用了7位,这7个引脚对应的是键7到键1,每次键的按下都会改变P2I中对应的值。

然后是其他的引脚,

P0,P3以及P1O[1..3]都对应的是电路板上的系统扩展端口,绑定引脚之后我们就能在程序中控制这些数据的改变,同时实现键盘、显示器和芯片之间的数据传输,从而在程序中获取4*4键盘按下的哪个按键,以及将我们想要显示的内容显示在显示器上。

最后还有一个P1O[0]这一个是我们实现蜂鸣器的关键,绑定的是DA24口,让我们得以输出声音信号,并且程序中不断改变其值能够实现播放不同的歌曲。

软件设计

流程图

下面给出我们智能门锁设计流程图:

流程图描述

我们智能门锁一共分为两个部分,初始化模式和工作模式。两个模式可以相互转化,通过键5进行工作模式转化到初始化模式。

下面详细介绍两个模式:

初始化模式:

  • 该模式分为两个模块,录入密码长度和录入密码。

  • 首先,我们要求使用者录入密码长度(1-8位),当按下确定键后转入录入密码模块。

  • 当使用者设置好密码后,按下确定键,转化至工作模式。

工作模式:

  • 工作模式分为三个大块:输入密码,门铃模式,开锁模式。

  • 用户可以选择输入密码,然后按下确定开锁按钮,系统进行判断:1.当密码准确,开启门锁;2.当密码错误,但还有试错机会,回到输入密码模式;3.当试错机会使用完毕,门锁进入死锁模式,只有按下对应按钮解锁死锁模式。

  • 门铃模式则为按下按钮,蜂鸣器发出声音,即门铃功能。

C语言源代码

下面我们将详细讲述我们编写的C语言源代码。由于代码部分涵盖老师给的代码和一些标准引用,因此,在本环节我们只讲述实现项目的关键部分。

常量/变量部分

// 下面为实现功能所需的变量,全局变量存在ROM中,节省RAM 
uchar i; // 循环时的变量 
uchar pivot = 0; // 循环时的变量 
uchar keynum=16;        //两个全局变量
uchar now_pd[8]={0}; // 存放当前输入的密码 
uchar pass_pd[8] = {0}; // 存放设置好的密码 
uchar chances = 3;  // 代表试错机会一共有三次 
uchar flag_verifypd = 1; // 在初始化密码时候,代表是否确认密码 
uchar pd_len = 0; // 存储密码的长度 
uchar flag_init = 2; // 一个辅助标记变量,用在初始化中 

// 下面是将变量绑定各引脚 
sbit SPK = P1^0;
sbit pd7 = P2^0;
sbit pd6 = P2^1;
sbit pd5 = P2^2;
sbit pd4 = P2^3;
sbit pd3 = P2^4; 
sbit pd2 = P2^5;
sbit pd1 = P2^6;

uchar code song_tone[]=        // 存储音乐,下面三个同理 
{
         190,212,142,212,0
};

uchar code song_tone2[]=         
{
         212,212,190,0
};

uchar code song_long[]= 
{
         12,12,12,12,0
};
uchar code song_long2[]= 
{
         3,12,12,0
};

可以看到,常量/变量部分都是根据各功能所定义出来的,具体的功能已经给出,不再赘述。

工具函数



// 该方法转化uchar pd为str类型,可用于LED屏幕显示 
uchar *transpd(uchar pd){
        switch(pd)
  {
    case 0: return "0";
        case 1: return "1";
        case 2: return "2";
        case 3: return "3";
        case 4: return "4";
        case 5: return "5";
        case 6: return "6";
        case 7: return "7";
        case 8: return "8";
        case 9: return "9";
        case 10: return "A";
        case 11: return "B";
        case 12: return "C";
        case 13: return "D";
        case 14: return "E";
        case 15: return "F";
        default: return "0";//
  }
}

// 该方法为将三个按钮pd1,pd2,pd3表示二进制转化为十进制。 
uchar getNum(){ 
                if(pd1==0 && pd2==0 && pd3 ==0){
                        return 0;
                }
                else if(pd1==1 && pd2==0 && pd3 ==0){
                        return 1;
                }
                else if(pd1==0 && pd2==1 && pd3 ==0){
                        return 2;
                }
                else if(pd1==1 && pd2==1 && pd3 ==0){
                        return 3;
                }
                else if(pd1==0 && pd2==0 && pd3 ==1){
                        return 4;
                }
                else if(pd1==1 && pd2==0 && pd3 ==1){
                        return 5;
                }
                else if(pd1==0 && pd2==1 && pd3 ==1){
                        return 6;
                }
                else if(pd1==1 && pd2==1 && pd3 ==1){
                        return 7;
                }
        return 0;
}


// 检查now_pd即输入密码是否与pass_pd一致即设置密码 
uchar check_pd(){
        for (pivot=0;pivot<pd_len;pivot++){
                if (now_pd[pivot]!=pass_pd[pivot]){
                        return 0;
                }
        }
        return 1;
}

// 初始化密码,全部设为0 
void init_pd(){
        for (pivot=0;pivot<pd_len;pivot++){
                now_pd[pivot]=0;
                pass_pd[pivot] = 0;
                }
}

// 改变密码,将输入的密码存为设置好的密码 
void change_pd(){
        for (pivot=0;pivot<pd_len;pivot++){
                pass_pd[pivot] = now_pd[pivot];
                }
}

这些工具函数在后续的编写有用,实现功能都较为简单,而且实现方法也较为简单,不再赘述。

主函数



void main(void){
        
        lcd_init();//初始化
        
        // 初始化模式 
        while(1){//循环执行 
                if (flag_init==2){ // 进入初态 
                lcd_init();//初始化
                while (1){
                        display(1,0,"set u pd length(1-8)");        
                        if (P3!=0xf0) key_scan();//判断按键是否按下,按下时扫描键盘获得按键序号
                        if (keynum!=16){
                                if (keynum<=8 && keynum>=0){
                                        pd_len = keynum; // 设置密码长度 
                                        flag_init--; // 更新状态 
                                        display(2,0,transpd(keynum)); // 在特定的LED屏幕位置进行展示,后面的类似,不再赘述 
                                        break;
                                }
                        }
                }
                if(flag_init==1){
                        display(3,0,"set u pd:");
                        while(1){
                                        P3=0xf0;
                                        if (P3!=0xf0) key_scan();//判断按键是否按下,按下时扫描键盘获得按键序号
                                        if (keynum!=16)
                                        {
                                                if (getNum()<pd_len && getNum()>=0){ // 密码只能设置1-8位 
                                                        now_pd[getNum()] = keynum; // 设置密码 
                                                }
                                        }
                                        for(pivot=0;pivot<pd_len;pivot++){
                                                display(4,pivot,transpd(now_pd[pivot]));
                                        }
                                        if (pd6 == 1){ // 确定设置密码 
                                                change_pd(); //改变密码 
                                                flag_init --; // 更改状态 
                                                break;
                                        }
                        }
                }
                lcd_init();//初始化
        }
        
        // 工作模式 
        display(1,0,"please entry pd:");        

        P3=0xf0;
        if (P3!=0xf0) key_scan();//判断按键是否按下,按下时扫描键盘获得按键序号
        if (keynum!=16)
        {
                if (getNum()<pd_len && getNum()>=0){
                        now_pd[getNum()] = keynum; // 获取当前输入密码 
                }
        }
        // 循环展示密码 
        for(pivot=0;pivot<pd_len;pivot++){
                display(2,pivot,transpd(now_pd[pivot]));
        }
        // 下面为验证密码 
        if (pd4==1 && chances>0 && flag_verifypd==1){
                // 成功 
                if (check_pd()==1){
                        display(3,0,"success!!         ");
                        display(4,0," ");
                        chances = 3;
                        playmusic(); // 播放音乐 
                }
                // 失败 
                else{
                        chances --;
                        flag_verifypd = 0;
                        display(3,0,"fail!! chance(s):");
                        display(4,0,transpd(chances));
                }
        }
        // 重置辅助修改密码的flag 
        if (pd4 == 0){
                flag_verifypd = 1;
        }
        // 下面回到初始化模式 
        if (pd5==1){
                init_pd();
                chances = 3;
                keynum = 16;
                flag_init = 2;
        }
        // 下面为重置修改次数,仍在工作模式 
        if(pd6==1){
                chances = 3;
                  lcd_init();//初始化
        }
        // 按门铃功能 
        if(pd7==1){
                playmusic2();
        }        
        delay_ms(500);        
}
}

简单来讲,在主函数存在两个模式:初始化模式和工作模式。在不同模式中,不同按钮、按键存在不同含义,同时不同模式可以切换,不同模式存在不同的具体功能。

初始化模式功能:设置密码长度,设置密码。

工作模式:输入密码,按门铃,重置密码,回到初始化模式。

代码没有完全给出,这是因为有些代码是冗余以保障功能健硕,有些代码是老师提供的。全部代码可以参考压缩包中的.c文件。

调试总结&实验过程

下面给出我们实验的全过程:

首先切换到模式5,将程序导入rom中,我们就会进入我们程序的初始化界面

在这个界面下,根据提示,我们需要使用4*4键盘输入我们设定密码的位数,数值必须在1~8以内,如果输入在这之外的数字是无效的,不会进入下一步。

我们这里输入数字2

这时候就需要我们设定密码了,默认密码的每一位都是0,我们这里没有进行改动。

使用左侧键6提交我们的初始密码,我们就能够进入我们程序的主要界面,并且刷新。

那么我们先尝试一下提交密码,看看是什么结果

当然00是正确的密码,这里会提示文字信息,并且还会播放一段音乐。

我们也可以尝试其他密码,比如这里我们修改一下第0位为6

(注释:如何修改其他位的密码?

这里我们就要使用左侧的键1到键3,它们各自对应一个二进制的值,现在全是0,那么就是000,对应的是第0位。

如果我们要修改第1位的密码,那么只需要将键1点亮,使得二进制对应为001,这样就可以修改第1位的密码。

假设要修改第3位的密码,只要键3不亮,键2点亮,键1点亮,即011,对应3即可使用4*4键盘修改对应位。

当然我们这里只设置了2位,只需要调整键1就可以全部控制了。)

如果继续提交两次。

我们只有三次错误机会,如果全部错误就会锁定,无法继续提交了。

那么最后总结一下左侧按键的功能:

键1~键3:调整4*4键盘对应密码的位数,000对应第0位,111对应第7位。

键4:在主界面确定密码并提交。

键5:重新进入初始化界面。

键6:在初始化界面确认设置密码并提交,在主界面是刷新显示界面。

键7:控制蜂鸣器的发声。

实验困难及解决

模式的选择难题

一开始我们是想在老师给的4×4key的样例的模式2上进行智能门锁的实现。

如图所示扩展了两个输出口,利用到了P0,P1,P2

事实证明,我们完成地也不错,我们将图示的三个显示屏用来展示密码

然后,用三个按钮控制密码输入输出和确定。

但是,我们接下来就遇到了巨大的问题:

每个显示屏需要7个引脚,这是难以忍受的:我们没有多余的引脚来实现其他功能了!!!

同时,我们注意到模式2没有蜂鸣器,这对于门铃来讲是巨大的挫折。

最后,我们舍弃了之前做过的工作,选择模式5,完成了较为完善的引脚配置和其他功能的结合。

引脚的配置难题

当我们从模式2转移到模式5,遇到的第一个问题就是硬件引脚的配置,尤其是4×4key键盘引脚的配置,不过好在通过耐心的查看老师样板引脚配置,最终理解了板子的引脚如何设置,我们完成了引脚的配置。

ROM内存难题

一开始编写C程序,由于我们不敢修改老师的代码和想要实现非常多的功能,因此导致编译后的内存超过了4K。我们一开始没有理解为什么程序跑不起来,后来仔细对比了程序编译后的字节和ROM的内存,才发现内存超出了。对此,我们进行了如下操作:

  1. 精简了功能实现的代码,尤其是对于一些变量的使用。

  2. 删改了老师的参考代码,比如对于歌曲,我们再理解频率等相关知识后,自己修改出来了一个更为短暂的门铃。

  3. 删除了部分非必要的功能。

实验结论

实验结果表明,智能门锁成功实现了密码设定和验证的基本功能。密码验证过程稳定可靠,能够准确判断用户输入的密码是否正确,并根据设定的要求进行相应的锁定操作。密码重置功能也得到了有效实现,用户可以通过特定的操作流程轻松重置密码。

在实验过程中,智能门锁系统表现出较高的安全性和便利性。输错密码锁定功能有效地防止了暴力破解的尝试,提高了门锁的安全性。同时,用户可以通过简单的操作来设定密码和重置密码,无需使用传统的钥匙,提供了更便捷的门禁控制体验。

心得

本次实验完成了一个智能电子门锁,过程可以说是非常曲折了,不过好在我们成功完成了一个具有实际意义的小应用。这次应用主要的创新点应该是我们想法的创新,软件的编写以及硬件模式的融合。

  1. 在硬件实现上虽然参照了老师给的样例,但我们也进行了模式融合的创新。

  2. 相较于其他队伍,我们选题独树一帜,也算是创新点。

  3. 软件即C语言编写,经过了许多版本迭代,最后在有限的内存中折中达成了设想的门锁功能。

当然,也要勇于承认自己的不足:

  1. 我们硬件调试依旧不是完美,有着部分缺陷,比如延迟过高,灵敏度不足;

  2. 软件代码的编写还是存在部分冗余,占用内存。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐