基于51单片机的密码锁Proteus仿真

文章目录

  • 一、密码锁
    • 1.题目要求
    • 2.思路
    • 3.仿真图
      • 3.1 未仿真时
      • 3.2 初始界面
      • 3.3 输入密码界面
      • 3.4 开锁成功界面
      • 3.5 修改密码界面
      • 3.6 输入密码错误界面
    • 4.仿真程序
      • 4.1 矩阵按键
      • 4.2 液晶显示1602
      • 4.3 存储模块2402
  • 二、总结


一、密码锁

1.题目要求

以51单片机为核心,设计并制作密码锁

基本功能如下:

  1. 设置6位初始密码,密码输入正确时,液晶显示屏上会显示密码正确;
  2. 当输入密码错误时能够删除和清零,如果密码输入错误次数达到3次,将会进行蜂鸣器报警;
  3. 密码能够掉电保存,可通过功能按键"“修改密码”键来重新设置密码。
  4. 要求用户输入密码时,不可直接显示输入的值,要求用显示“*”代替。

2.思路

首先先画个51单片机:

这里的P0为什么需要画上拉排阻呢?

主要原因是因为P0口是开漏输出的,即集电极开路输出(OC门)。这种输出结构没有内置的上拉电阻,因此不能直接输出高电平。当P0口需要输出高电平时,必须通过外部电路提供驱动电流,这时就需要加上拉电阻来实现。上拉电阻的作用是将电平拉高,通常连接到电源正极(VCC),以便在需要时提供电流给负载,从而确保P0口能够正确地输出高电平信号。

在这里插入图片描述

要使用到多个按键进行设置密码,又不想浪费IO资源,第一时间想到的是用矩阵按键,不懂的小伙伴可以看看之前的介绍基于51单片机的矩阵按键扫描的proteus仿真(附源码)

在这里插入图片描述

显示的话,液晶显示屏想到的是LCD1602,但是在Proteus仿真里面叫做LM016L,不懂的小伙伴可以看看之前的介绍基于51单片机的LCD1602显示的proteus仿真(附源码)

在这里插入图片描述
要求断电能够保存密码,那就是要用到EEPROM芯片,这里用个简单的24C02来进行存储,,不懂的小伙伴可以看看之前的介绍基于51单片机的AT24C02存储的proteus仿真(附源码)

报警的话,用个蜂鸣器进行报警即可。
在这里插入图片描述
既然是密码锁,那肯定能模拟开锁,这里选用继电器来驱动电机转动达到一个模拟的效果。

在这里插入图片描述

3.仿真图

3.1 未仿真时

在这里插入图片描述

3.2 初始界面

在这里插入图片描述

3.3 输入密码界面

在这里插入图片描述

3.4 开锁成功界面

在这里插入图片描述

3.5 修改密码界面

在这里插入图片描述

3.6 输入密码错误界面

在这里插入图片描述

4.仿真程序

4.1 矩阵按键

/*******************************************************************************
* 函 数 名         : Key_Check()
* 函数功能		   : 检测有矩阵按键按下并读取键值
* 输    入         : 无
* 输    出         : KeyValue:按键值,无按键按下返回20
*******************************************************************************/
uchar Key_Check(void)
{
	static bit flag_key=0;
	uchar KeyValue=20; //无按键按下返回20
	uchar a=0;
	GPIO_KEY=0x0f;
	if(GPIO_KEY!=0x0f)  	 //读取按键是否按下
	{
		if(!flag_key){				//判断之前的按键状态
			flag_key=1;				//按键状态1,按下状态
			Delay_Us(1000);		 //延时10ms进行消抖
			if(GPIO_KEY!=0x0f)	 //再次检测键盘是否按下
			{		
				GPIO_KEY=0x0f;	//测试列
				switch(GPIO_KEY)
				{
					case(0X07):	KeyValue=0;break;
					case(0X0b):	KeyValue=1;break;
					case(0X0d): KeyValue=2;break;
					case(0X0e):	KeyValue=3;break;
				}			
				GPIO_KEY=0xf0;	//测试行
				switch(GPIO_KEY)
				{
					case(0X70):	KeyValue=KeyValue;break;
					case(0Xb0):	KeyValue=KeyValue+4;break;
					case(0Xd0): KeyValue=KeyValue+8;break;
					case(0Xe0):	KeyValue=KeyValue+12;break;
				}		
			}
		}
	}else flag_key=0;
	return KeyValue;	//返回按键值
}

4.2 液晶显示1602

/*******************************************************************************
* 函 数 名         : Read_Busy()
* 函数功能		     : 忙检测函数,判断bit7是0,允许执行;1禁止
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void Read_Busy()           
{
    unsigned char sta;     
    LCD1602_DB = 0xff;
    LCD1602_RS = 0;
    LCD1602_RW = 1;
    do
    {
        LCD1602_EN = 1;
        sta = LCD1602_DB;
        LCD1602_EN = 0;    //使能,用完就拉低,释放总线
    }while(sta & 0x80);
}

/*******************************************************************************
* 函 数 名         : Lcd1602_Write_Cmd()
* 函数功能		     : LCD写命令
* 输    入         : cmd:命令
* 输    出         : 无
*******************************************************************************/
void Lcd1602_Write_Cmd(unsigned char cmd)     
{
    Read_Busy();
    LCD1602_RS = 0;
    LCD1602_RW = 0;
    LCD1602_DB = cmd;
    LCD1602_EN = 1;
    LCD1602_EN = 0;    
}

/*******************************************************************************
* 函 数 名         : Lcd1602_Write_Data()
* 函数功能		     : LCD写数据
* 输    入         : dat: 数据
* 输    出         : 无
*******************************************************************************/
void Lcd1602_Write_Data(unsigned char dat)   
{
      Read_Busy();
      LCD1602_RS = 1;
      LCD1602_RW = 0;
      LCD1602_DB = dat;
      LCD1602_EN = 1;
      LCD1602_EN = 0;
}

/*******************************************************************************
* 函 数 名         : LcdSetCursor()
* 函数功能		     : 设置坐标
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void LcdSetCursor(unsigned char x,unsigned char y)  
{
    unsigned char addr;
    if(y == 0)
        addr = 0x00 + x;
    else
        addr = 0x40 + x;
    
    Lcd1602_Write_Cmd(addr|0x80);
}

/*******************************************************************************
* 函 数 名         : DisplayOneChar()
* 函数功能		     : 按指定位置显示一个字符
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData)
{
	Y &= 0x1;
	X &= 0xF; //限制X不能大于15,Y不能大于1
	if (Y) X |= 0x40; //当要显示第二行时地址码+0x40;
	X |= 0x80; //算出指令码
	Lcd1602_Write_Cmd(X); //发命令字
	Lcd1602_Write_Data(DData); //发数据
}

/*******************************************************************************
* 函 数 名         : LcdShowStr()
* 函数功能		     : 显示字符串
* 输    入         : x,y:当前字符的坐标;*str:字符串
* 输    出         : 无
*******************************************************************************/
void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str)     
{
    LcdSetCursor(x,y);      //当前字符的坐标
    while(*str != '\0')
    {
        Lcd1602_Write_Data(*str++);
    }
}

/*******************************************************************************
* 函 数 名         : Lcd1602_Init()
* 函数功能		     : LCD1602初始化
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void Lcd1602_Init()              //
{
    Lcd1602_Write_Cmd(0x38);    //打开,5*8,8位数据
    Lcd1602_Write_Cmd(0x0c);
    Lcd1602_Write_Cmd(0x06);
    Lcd1602_Write_Cmd(0x01);    //清屏   
}

4.3 存储模块2402

//IIC启动
void Start(void)
{
	SDA1=1;
	Delay_Us(2);
	SCL1=1;
	Delay_Us(2);//建立时间是SDA保持时间>4.7us
	SDA1=0;
	Delay_Us(2);//保持时间是>4us
	SCL1=0;			
	Delay_Us(2);
}

//IIC停止
void Stop(void)
{
	SDA1=0;
	Delay_Us(2);
	SCL1=1;
	Delay_Us(2);//建立时间大于4.7us
	SDA1=1;
	Delay_Us(4);		
}

//IIC发送字节
//dat:要发送的字节
void Send_Byte(unsigned char dat)
{
	unsigned char a=0,b=0;
	for(a=0;a<8;a++)//要发送8位,从最高位开始
	{
		SDA1=dat>>7;	 //起始信号之后SCL=0,所以可以直接改变SDA信号
		dat=dat<<1;
		Delay_Us(2);
		SCL1=1;
		Delay_Us(2);//建立时间>4.7us
		SCL1=0;
		Delay_Us(2);//时间大于4us
	}	
}

//IIC检查应答
bit Check_Ack(void)
{
	//unsigned char t;
	SCL1=0;
	SDA1=1;
	Delay_Us(2);
	SCL1=1;
	Delay_Us(2);
	CY=SDA1;
	SCL1=0;
	Delay_Us(2);	
	return(CY);
}

//IIC应答
void Ack(void)
{ 
	SDA1=0;   //EEPROM通过在收到每个地址或数据之后
	SCL1=1;   //置SDA低电平的方式确认表示收到读SDA口状态
	Delay_Us(1);
 	SCL1=0;
	Delay_Us(1);
	SDA1=1;
}

//IIC无应答
void NoAck(void)
{
	SDA1=1;
	SCL1=1;
	Delay_Us(1);
	SCL1=0;
}

//IIC接收字节
unsigned char Receive_Byte(void)
{
	unsigned char a=0,dat=0;
	SDA1=1;			//起始和发送一个字节之后SCL都是0
	Delay_Us(2);
	for(a=0;a<8;a++)//接收8个字节
	{
		SCL1=1;
		Delay_Us(2);
		dat<<=1;
		dat|=SDA1;
		Delay_Us(2);
		SCL1=0;
		Delay_Us(2);
	}
	return dat;		
}

//At24cxx读写数据
//addr:要读/写数据的地址
//*dat:要读/写的数据
//length;数据的长度
//RW:1:写,0:读
void At24c02_RW(unsigned char addr,unsigned char *dat,unsigned char length,bit RW)
{
	Start();
	Send_Byte(0xa0);//发送写器件地址
	Check_Ack();
	Send_Byte((unsigned char)addr);//发送要写入内存地址
	Check_Ack();
	if(RW)		 //写
	{	while(length--)
		{
			Send_Byte(*dat++);
			Check_Ack();	
		}
	}
	else
	{
		Start();
		Send_Byte(0xa1);
		Check_Ack();
		while(--length)
		{
			*dat++=Receive_Byte();
			 Ack();
		}
		*dat=Receive_Byte();//读取最后一个字节
		NoAck();
	}
	Stop();
	if(RW)
	Delay_Us(1000);
}

二、总结

今天主要讲了基于51单片机的密码锁Proteus仿真

感谢你的观看!

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/757992.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OFDM的基本原理

OFDM技术使用相互正交的子载波组成多载波传输数据&#xff0c;此时不存在子载波间干扰和符号间干扰。设采样间隔为 &#xff0c;正交子载波可以表示为 基带信号a(n)采用矩形脉冲&#xff0c;则OFDM信号用公式可以表示 OFDM信号的N个采样点数据 可以用IFFT简化上述计算&#xf…

01:PCB板的介绍

PCB板的介绍 1、PCB的层叠结构1.1&#xff1a;单层板1.2&#xff1a;2层板1.3&#xff1a;4层板 2、封装简介 在1936年&#xff0c;奥地利人&#xff08;保罗爱斯勒&#xff09;使用箔膜技术&#xff0c;发明了第一个印刷电路板&#xff08;PCB板&#xff09;。使用减去法实现的…

Qt之饼图(Pie Graph)

[TOC](Qt之饼图(Pie Graph)) 饼图名为Pie Graph&#xff0c;用于显示一个数据系列中各项的大小与各项总和的比例。本文基于QtCharts实现饼图的显示。 1.实现过程 1.1环境配置 &#xff08;1&#xff09;首先想要使用QtCharts模块&#xff0c;需要在安装qt时选择勾选安装QtCha…

MySQL高级-SQL优化-insert优化-批量插入-手动提交事务-主键顺序插入

文章目录 1、批量插入1.1、大批量插入数据1.2、启动Linux中的mysql服务1.3、客户端连接到mysql数据库&#xff0c;加上参数 --local-infile1.4、查询当前会话中 local_infile 系统变量的值。1.5、开启从本地文件加载数据到服务器的功能1.6、创建表 tb_user 结构1.7、上传文件到…

华为RH2288H V2服务器,远程端口安装Linux操作系统

1、管理口 每台服务器的管理口不一样的&#xff0c;假如我的管理IP地址为&#xff1a;192.168.111.201 使用网线&#xff0c;将管理口和自己电脑连接起来&#xff0c;自己ip地址设置成和管理ip同一网段。 使用 ie 浏览器&#xff0c;如果是Edge&#xff0c;必须在Internet Exp…

Java教程之IO模式精讲,NIO+BIO

第一章 BIO、NIO、AIO介绍 背景 在java的软件设计开发中&#xff0c;通信架构是不可避免的&#xff0c;我们在进行不同系统或者不同进程之间的数据交互&#xff0c;或 者在高并发下的通信场景下都需要用到网络通信相关的技术&#xff0c;对于一些经验丰富的程序员来说&#x…

岗位实习最终篇(汇总)——人力资源管理系统(包含DDL,DML,视图,简单/复杂查询,触发器语句和存储过程语句)

DDL CREATE TABLE users (user_id INT AUTO_INCREMENT PRIMARY KEY COMMENT 员工ID,username VARCHAR(50) NOT NULL UNIQUE COMMENT 用户名,password VARCHAR(255) NOT NULL COMMENT 密码,first_name VARCHAR(50) NOT NULL COMMENT 名,last_name VARCHAR(50) NOT NULL COMMENT…

【数据结构|C语言版】四大排序(算法)

前言1. 插入排序1.1 直接插入排序1.2 希尔排序 2. 选择排序2.1 选择排序2.2 堆排序 3. 交换排序3.1 冒泡排序冒泡排序的步骤 3.2 快速排序快速排序的步骤 4. 归并排序归并排序的步骤&#xff1a;代码解释&#xff1a;归并排序的性能&#xff1a; 上期回顾: 【数据结构|C语言版】…

【后端面试题】【中间件】【NoSQL】ElasticSearch面试基本思路和高可用方案(限流、消息队列、协调节点、双集群)

基本思路 业务开发面试Elasticsearch的时候基本问的是基础知识以及倒排索引。 Elasticsearch最基本的可用性保障就是分片&#xff0c;而且是主从分片&#xff0c;所以遇到Elasticsearch如何做到高可用这个问题的时候&#xff0c;首先要提到这一点。 Elasticsearch高可用的核心…

【理解】关于正点原子i.MX6ULL LCD计算式的理解

文章目录 1 描述2 疑问3 理解 1 描述 在《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.81.pdf》&#xff0c;P560页&#xff0c;第二十四章 RGBLCD显示实验中提到&#xff0c;LCD屏幕显示一行所需要的时间&#xff1a; t H S P W H B P H O Z V A L H F P ① t HSPW …

结构体 -------- 函数-------传参

在函数题中 return 只能传一个值 如果函数体&#xff08;struct fs a&#xff0c;struct fs b&#xff09;传来了两个值&#xff0c;怎么才能只输出一个值呢&#xff1f; 同样要定义一个struct fs 类型的变量 result&#xff1b; 这样不仅可以访问到结构体中的变量a&#…

【动态规划】2306. 公司命名

本文涉及知识点 动态规划汇总 LeetCode 2306. 公司命名 给你一个字符串数组 ideas 表示在公司命名过程中使用的名字列表。公司命名流程如下&#xff1a; 从 ideas 中选择 2 个 不同 名字&#xff0c;称为 ideaA 和 ideaB 。 交换 ideaA 和 ideaB 的首字母。 如果得到的两个新…

如何利用react框架快速创建一个electron项目

1、搭建electron项目 创建一个electron入门项目还是很容易的&#xff0c;基体方法可以参考&#xff1a;eletron入门教程 -- 快速写一个electron demo程序 但是如果要利用react框架搭建一个electron项目&#xff0c;但是有一点麻烦&#xff0c;不过可以利用工具包来进行创建&am…

寄存器相关知识点

文章目录 寄存器是什么&#xff1f;举例子—如何去看手册来配置寄存器寄存器地址知识点输出功能具体实现&#xff0c;在linux编写代码的话 其他 相关视频 寄存器是什么&#xff1f; 本质就是一个存储器&#xff0c;写内存和写指针都是一样的 寄存器里的值和RAM的值&#xff0c…

C++ | Leetcode C++题解之第206题反转链表

题目&#xff1a; 题解&#xff1a; class Solution { public:ListNode* reverseList(ListNode* head) {if (!head || !head->next) {return head;}ListNode* newHead reverseList(head->next);head->next->next head;head->next nullptr;return newHead;} …

Leetcode3192. 使二进制数组全部等于 1 的最少操作次数 II

Every day a Leetcode 题目来源&#xff1a;3192. 使二进制数组全部等于 1 的最少操作次数 II 解法1&#xff1a;遍历 由于 nums[i] 会被其左侧元素的操作影响&#xff0c;所以我们先从最左边的 nums[0] 开始思考。 分类讨论&#xff1a; 如果 nums[0]1&#xff0c;无需反…

Rust: duckdb和polars读csv文件比较

duckdb在数据分析上&#xff0c;有非常多不错的特质。1、快&#xff1b;2、客户体验好&#xff0c;特别是可以同时批量读csv&#xff08;在一个目录下的csv等文件&#xff09;。polars的性能比pandas有非常多的超越。但背后的一些基于arrow的技术栈有很多相同之类。今天想比较一…

YOLOv5改进 | 注意力机制 | 迈向高质量像素级回归的极化自注意力【全网独家】

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 专栏目录&#xff1a; 《YOLOv5入门 …

[数据集][目标检测]人员状态跑睡抽烟打电话跌倒检测数据集4943张5类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;4943 标注数量(xml文件个数)&#xff1a;4943 标注数量(txt文件个数)&#xff1a;4943 标注…

黑马点评DAY1|Redis入门、Redis安装

什么是Redis&#xff1f; redis是一种键值型数据库&#xff0c;内部所存的数据都是键值对的形式&#xff0c;例如&#xff0c;我们可以把一个用户数据存储为如下格式&#xff1a; 键值id$1600name张三age21 但是这样的存储方式&#xff0c;数据会显得非常松散&#xff0c;因…