毕业设计 基于单片机的智能蓝牙密码锁设计与实现

news/2024/10/30 9:31:26/

文章目录

  • 0 前言
  • 1 简介
  • 2 主要器件
  • 3 实现效果
  • 4 设计原理
    • 4.1 硬件部分
    • 4.2 软件设计
  • 5 部分核心代码
  • 6 最后


0 前言

🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。

为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天要分享的是

🚩 基于单片机的智能蓝牙密码锁设计与实现

🥇学长这里给一个题目综合评分(每项满分5分)

  • 难度系数:4分
  • 工作量:4分
  • 创新点:3分

🧿 选题指导, 项目分享:

https://gitee.com/dancheng-senior/project-sharing-1/blob/master/%E6%AF%95%E8%AE%BE%E6%8C%87%E5%AF%BC/README.md


1 简介

基于51单片机的按键蓝牙密码锁,可通过LCD1602显示屏显示密码信息。利用矩阵按键输入密码,当输入密码次数达到上限后蜂鸣器模块进行报警

2 主要器件

  • STC89C52单片机
  • 4×4矩阵键盘
  • LCD1602显示

3 实现效果

在这里插入图片描述

4 设计原理

4.1 硬件部分

硬件电路主要分为STC89C51单片机、AT24C02存储模块、按键电路、报警电路、继电器驱动模块五个部分。该控制系统的硬件设计以STC89C51单片机为主控芯片,利用单片机丰富的I/O端口将各个外围电路连接起来构成主系统,可以利用矩阵键盘实现密码输入与修改、关锁、复位等功能,并且通过单片机外接 LCD1602 液晶显示屏提示用户进行下一步操作。系统的硬件电路设计如图所示:

在这里插入图片描述
STC89C52单片机的最小系统

STC89C52单片机共有40只管脚,分为电源、时钟、控制和I/O引脚四类,它的优点是容易操作,原有程序可直接使用,硬件也无须改动,运行速度快且功耗低,而且成本低,抗干扰能力强,可提升产品性能,这使得在操作与成本方面都有极大的优势。单片机最小系统的工作由电源、晶振电路以及复位电路构成。

AT24C02存储模块

AT24C02存储器的数据传送率高且能与IIC总线兼容,功耗低,数据保存时间较长,还有一个专门的防误擦除写保护功能。芯片工作时有读和写两种操作,执行读操作时有当前地址读、随机读和顺序读三种方法;执行写操作时可根据数据量的大小选择字节写还是页写。在本设计中可直接将存储芯片的A0、A1、A2三个引脚连接至GND,为了方便读/写操作,将WP写保护引脚也连接到GND,最后将SDA、SCL两引脚分别接到单片机对应的两个引脚。

按键电路

该设计在操作过程中所需按键数目较多,所以采用矩阵式扫描的方法来作为键盘的输入形式且用4×4矩阵键盘可满足该设计所设定的功能。使用矩阵扫描法不仅可以减少单片机I/O端口的占用,也会降低电路连接的复杂程度。根据具体要实现的功能,密码锁的按键分布为数字键0-9、输入密码键、退格键、退出输入键、密码修改键、重置键、确认键。用户根据定义的按键功能实现输入,矩阵键盘直接连接单片机的P1口进行输入,通过输入高低电平判断键盘是否按下。

报警电路
报警电路由 LED 灯和蜂鸣报警器组成。这样可直观地观察密码锁的工作情况。本设计选用5V电磁式有源蜂鸣器,因为蜂鸣器工作时所需的电流较大,无法驱动单片机的I/O接口,电路中需要用一个三极管来驱动。当输入低电平时,三极管导通,蜂鸣器发出报警同时连接的红色LED灯亮;当输入高电平时,三极管截止,蜂鸣器停止鸣叫。

4.2 软件设计

电子密码锁控制系统的软件设计主要分为主程序、LCD1602显示程序、AT24C02存储程序、矩阵按键电路及中断服务程序的设计。为了实现密码锁的预期功能,软件设计部分以 STC89C51 单片机为核心编写程序,首先对整个系统程序进行初始化设置,开启电子密码锁的功能,采用4×4矩阵式键盘扫描方法来判断是否已按下按键,可通过LCD1602液晶显示屏清楚地看出当前已输入的密码位数,输入完成后按下确认键,密码锁会将输入的密码与事先存储在AT24C02芯片中的原密码进行比对,若密码一致则打开锁,若密码不一致则蜂鸣器报警且LED 灯亮,可选择重新输入,当密码错误三次则键盘将被锁定且报警。
软件设计流程如图所示:

在这里插入图片描述

5 部分核心代码

//MatrixKey.c文件
#include <REGX52.H>
#include "Delay.h"
#define FULL 4	//密码锁密码位数为4位
#define KEY_SCAN P1	//定义P1口/*** @brief  传回输入键值0-10,及输入的有效密码位数* @param  *keyValue:0-11,*times:1-4* @retval 无*/void MatrixKey(unsigned char* keyValue,unsigned char* times)
{KEY_SCAN = 0X0F;	//置行为0,进行列扫描if(KEY_SCAN!=0X0F)	//若有键按下{Delay(10);	//消抖KEY_SCAN = 0X0F;	//再次进行列扫描switch(KEY_SCAN){	//若有某一列值为0,表示该列有按键按下case 0X07:*keyValue = 0;break;case 0X0B:*keyValue = 1;break;case 0X0D:*keyValue = 2;break;case 0X0E:*keyValue = 3;break;}KEY_SCAN = 0XF0; //行扫描switch(KEY_SCAN){	//若某行有值为0表示该行有键按下case 0X70:*keyValue = *keyValue;break;case 0XB0:*keyValue += 4;break;case 0XD0:*keyValue += 8;break;case 0XE0:*keyValue += 12;break;}if(*keyValue>=0 && *keyValue<=9){	//按下为有效密码*times = *times % 4 + 1;}while(KEY_SCAN!=0XF0){	//检测到按键松开时,退出循环Delay(10);}}	
}
#include <REGX52.H>//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_E=P2^7;
#define LCD_DataPort P0//函数定义:
/*** @brief  LCD1602延时函数,12MHz调用可延时1ms* @param  无* @retval 无*/
void LCD_Delay()		//@12.000MHz  1ms 如果是更快的单片机,这里延时要长一点
{unsigned char i, j;i = 2;j = 239;do{while (--j);} while (--i);
}/*** @brief  LCD1602写命令* @param  Command 要写入的命令* @retval 无*/
void LCD_WriteCommand(unsigned char Command)
{LCD_RS=0;//写指令LCD_RW=0;LCD_DataPort=Command;LCD_E=1;//这里置高又置低,高电平速度太快,反应不过来,因此进行延时LCD_Delay();LCD_E=0;LCD_Delay();
}/*** @brief  LCD1602写数据* @param  Data 要写入的数据* @retval 无*/
void LCD_WriteData(unsigned char Data)
{LCD_RS=1;//写数据LCD_RW=0;LCD_DataPort=Data;LCD_E=1;//这里置高又置低,高电平速度太快,反应不过来,因此进行延时LCD_Delay();LCD_E=0;LCD_Delay();}/*** @brief  LCD1602初始化函数* @param  无* @retval 无*/
void LCD_Init(void)
{LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵LCD_WriteCommand(0x0C);//显示开,光标关,闪烁关LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动LCD_WriteCommand(0x01);//清屏}/*** @brief  LCD1602设置光标位置* @param  Line 行位置,范围:1~2* @param  Column 列位置,范围:1~16* @retval 无*/
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{if(Line==1){LCD_WriteCommand(0x80|(Column-1));//0x80是确定光标位置的指令,A0-A6是确定地址}else{LCD_WriteCommand(0x80|(Column-1)+0x40);//换行所以要加一个基地址0x40}	
}/*** @brief  在LCD1602指定位置上显示一个字符* @param  Line 行位置,范围:1~2* @param  Column 列位置,范围:1~16* @param  Char 要显示的字符* @retval 无*/
void LCD_ShowChar(unsigned char Line,unsigned char Column,unsigned char Char)
{LCD_SetCursor(Line,Column);LCD_WriteData(Char);       //char x=‘A’;(等效于char x=0x41;)
}/*** @brief  在LCD1602指定位置开始显示所给字符串* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  String 要显示的字符串* @retval 无*/
void LCD_ShowString(unsigned char Line,unsigned char Column,unsigned char String[])
{//这里用到指针的作用,String[]指针指向该字符组的第一个地址,依次显示出来,直到'\0'的出现unsigned char i;LCD_SetCursor(Line,Column);for(i=0;String[i]!='\0';i++){LCD_WriteData(String[i]);}
}/*** @brief  返回值=X的Y次方*/
int LCD_Pow(int X,int Y)//x的y次方
{unsigned char i;int Result=1;for(i=0;i<Y;i++){Result*=X;}return Result;
}
/*i
789/100%10    7     3     10^(3-1)
789/10%10     8     2     10^(2-1)
789/1%10      9     1     10^(1-1)
*/
/*** @brief  在LCD1602指定位置开始显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:0~65535* @param  Length 要显示数字的长度,范围:1~5* @retval 无*/
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{unsigned char i;LCD_SetCursor(Line,Column);//根据长度确定所要显示的位数,通过计算将Number中从高位到低位依次显示出来,对照ASCII码表0的基地址//为0x30,显示几就在这个地址上加几就可以for(i=Length;i>0;i--){LCD_WriteData(0x30+Number/LCD_Pow(10,i-1)%10);//将数字转化为ASCII码表}
}/*** @brief  在LCD1602指定位置开始以有符号十进制显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:-32768~32767* @param  Length 要显示数字的长度,范围:1~5* @retval 无*/
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column, int Number,unsigned char Length)
{unsigned char i;unsigned int Number1;LCD_SetCursor(Line,Column);if(Number>=0){LCD_WriteData('+');Number1=Number;}else{LCD_WriteData('-');Number1=-Number;}for(i=Length;i>0;i--){LCD_WriteData(0x30+Number1/LCD_Pow(10,i-1)%10);//将数字转化为ASCII码表}
}/*
输入0xA0                   i
160/16%16     10     2     16^(2-1)
160/1%16       0     1     16^(1-1)
*/
/*** @brief  在LCD1602指定位置开始以十六进制显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:0~0xFFFF* @param  Length 要显示数字的长度,范围:1~4* @retval 无*/
void LCD_ShowHexNum(unsigned char Line,unsigned char Column, int Number,unsigned char Length)
{unsigned char i;unsigned char SingleNumber;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){SingleNumber=Number/LCD_Pow(16,i-1)%16;//将16进制转化为ASCII码表,这里输入16进制,但进行计算的是十进制if(SingleNumber<10){LCD_WriteData('0'+SingleNumber);}else{LCD_WriteData('A'+SingleNumber-10);//这里的‘A’相当于是一个基地址}}	
}/*** @brief  在LCD1602指定位置开始以二进制显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:0~1111 1111 1111 1111* @param  Length 要显示数字的长度,范围:1~16* @retval 无*/
void LCD_ShowBinNum(unsigned char Line,unsigned char Column, int Number,unsigned char Length)
{unsigned char i;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){LCD_WriteData(0x30+Number/LCD_Pow(2,i-1)%2);//将数字转化为ASCII码表}
}
//main.c文件
#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
#include "MatrixKey.h"#define DEL 10	//矩阵键盘键值为10的键表示删除键
#define SURE 11	//矩阵键盘键值为11的键表示确认键
#define TRUE 1	//真值
#define FALSE 0	//假值
#define NONE 20	//初始化键值,用非0-9数字表示无效值unsigned char value = NONE;	//键值,并初始化为无效值NONE
unsigned char times;	//输入有效的密码位数unsigned char password[] = {0,1,0,0,7};	//密码“1007”,第0位不用
unsigned char identify = TRUE;	//用于判断密码是否输入正确
unsigned char input[5]={0,0,0,0,0};	//用于存放输入的密码void main()
{LCD_Init();	//初始化LCD屏幕LCD_ShowString(1,1,"Password:");LCD_ShowString(2,1,"XXXX");while(1){MatrixKey(&value,&times);	//获得输入的键值和输入密码位数if(value>=0 && value <=9){	//判断是否为有效键值(密码)LCD_ShowNum(2,times,value,1);	//对应位输出密码input[times] = value;	//保存输入密码if(times==FULL){	//输入密码为4位时,判断是否密码正确unsigned int i;for(i=1; i<=4; i++){	//遍历密码password进行判断if(input[i] != password[i])identify = FALSE;}}}if(value == DEL){	//若输入删除键LCD_ShowString(2,times,"X");	//在删除位输出X表示对应位删除times--;	//清空删除的密码,表示当前输入密码位数value = NONE;	//调用前value=10,执行后value值为无效值}if(identify==FALSE && times==FULL && value==SURE ){	//输入4位密码不正确LCD_ShowString(1,12,"Error");LCD_ShowString(2,1,"XXXX");identify = TRUE;value = NONE;}else if(identify==TRUE && times==FULL && value==SURE){	//输入4位密码正确LCD_ShowString(1,12,"Right");}}
}

6 最后


http://www.ppmy.cn/news/307931.html

相关文章

EFM32智能门锁应用案例

转载自http://www.elecfans.com/analog/20111024225773.html 概述 智能门锁是指区别于传统机械锁具&#xff0c;在用户识别、安全性、管理性方面更加智能化的锁具。它是智能门禁系统中锁门的执行部件。目前应用中常见的智能锁具可以按照其用户识别技术进行分类&#xff1a; …

智能门锁的千亿市场,为何迟迟不来?

文|佘凯文 来源|智能相对论&#xff08;aixdlun&#xff09; 智能门锁自出世以来&#xff0c;各种新闻就没断过一直未断&#xff0c;一方面是舆论鼓吹“千亿市场”潜力巨大&#xff0c;一方面是资本青睐不断加码&#xff0c;最终落地到市场却是“只闻雷&#xff0c;不见雨”。…

酒店智能门锁方案功能及其特点介绍

世界上自有门锁以来&#xff0c;门锁的变革经历了&#xff1a;机械锁—光孔锁—磁片锁—电子锁—智能感应卡锁&#xff0c;门锁不断地更新换代。进入九十年代后&#xff0c;智能卡锁以其无余伦比的优势创建了门锁新概念。计算机、电子机械和智能卡的诞生&#xff0c;门锁形成了…

从智能锁谈STM32安全技术

一. 智能锁的安全分析 1.1 安全的概念与保护的对象 1.1.1 什么是安全 安全分为2类&#xff1a; 功能安全 Functional Safety 保护系统不受那些随机故障或者系统设计缺陷的影响 信息安全 Information Security 保护系统不受恶意威胁而受损失 本教程讲的安全都指信息安全&…

使用Arduino和ESP8266制作一款智能门锁

在本篇文章中&#xff0c;您将学习如何基于Arduino开发板制作一款智能门锁&#xff0c;并能够通过手机解锁。在本文结束时&#xff0c;您将可以&#xff1a; ● 学习到如何生成特定的QR码。 ● 学习如何通过ESP8266制作一个登录页面。 ● 学习通过手机解锁门锁。 智能门锁的…

智能门锁的优劣,我们应该如何有效识别?

随着物联网的发展&#xff0c;智能家居越来越受到人们的欢迎&#xff0c;作为家庭的第一道安全保障&#xff0c;门锁是每个家庭都会用到的设备&#xff0c;门锁智能也是一种趋势。记得《欢乐颂》有一集安迪打不开自己的智能门锁&#xff0c;那么智能门锁的优劣如何识别&#xf…

动能方案|智能门锁超低功耗读卡方案

传统的机械锁具已走过了近百年历史&#xff0c;其功能及性能几乎已诠释到了极致。但仍不能满足现代人们对锁具有高可靠性、高安全性、信息化、智能化的要求&#xff0c;自50年代末&#xff0c;半导体技术问世后&#xff0c;人们便将该技术应用于锁具上&#xff0c;衍生出了形形…

家用智能门锁常见的开锁方式,主要有哪些?

随着智能家居越来越受到人们欢迎&#xff0c;许多厂商纷纷加入到这片蓝海之中&#xff0c;产品也逐渐丰富起来。在品类众多的智能锁中&#xff0c;开锁方式自然也是五花八门。今天就来总结一下家用智能锁常见的开锁方式吧。 密码锁 密码是最常见的一种开锁方式。小到抽屉锁&a…