找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 21742|回复: 14
收起左侧

基于51单片机的电子密码锁综合课程设计报告,含源码和接线图

  [复制链接]
ID:369006 发表于 2018-7-10 21:03 | 显示全部楼层 |阅读模式
这是我的单片机结课项目
原理比较简单,主要使用80C51单片机,加一个lcd屏

接线图

接线图

按键

按键

信息与机电工程学院
《单片机原理及应用》课程设计报告

课题名称       基于51单片机的电子密码锁设计  
专业班级         2016级电子信息工程国内班      


基于51单片机的电子密码锁设计

在日常的生活和工作中,住宅安全,文件资料的保护都需要用锁来保证。传统往往使用机械式钥匙开锁,但钥匙丢失会使锁的安全性大打折扣。随着科学技术的不断发展,电子密码锁应运而生,而密码锁也具有安全性高、成本低、功耗低、易操作等优点。

本设计是基于51单片机,并结合液晶显示LCD1602,以及矩阵键盘输入、复位、电源等电路组合而成。系统能够完成开锁、修改密码等基本功能。整个设计在Keil开发环境下,用C语言编写主控芯片的控制程序来实现具有多功能的电子密码锁。


一、绪论

1.1电子密码锁的背景

  随着社会不断进步,人民生活水平不断提高,安全成为现代居民最关心的问题之一。从古至今,锁一直就是保护人们财产的必不可少的工具。目前,我们最常用的锁就是圆柱形销栓的弹子锁,其机构简单,使用方便,价格便宜,但在使用中暴露了很多缺点:1、容易被开启;2、内部机械结构复杂、故障率高;3、换锁麻烦;4、互开率高;5、易被破坏;6、带钥匙的烦恼;7、钥匙开门的烦恼。

电子密码锁是一种通过密码输入来控制电路或是芯片工作,从而控制机械开关的闭合,完成开锁、闭锁任务的电子产品。它的种类很多,有简易的电路产品,也有基于芯片的性价比较高的产品。现在应用较广的电子密码锁是以芯片为核心,通过编程来实现的。其性能和安全性已大大超过了机械锁。所以,研究电子密码锁,符合现在主流发展趋势,具有极大的研究意义和现实意义,也具有经济可行性。

1.2电子密码锁的特点

1.保密性好,编码量多,远远大于弹子锁。随机开锁成功率几乎为零。

2.密码可变。 用户可以经常更改密码,防止密码被盗,同时也可以避免因人员的更替而使锁的密级下降。

3.误码输入保护。当输入密码多次错误时,报警系统自动启动。

4. 电子密码锁操作简单易行,一学即会。

5.干扰码功能。在输入正确密码前可输入任意码。

6.安保功能。如果连续输错4次密码将会自动断电3分钟。

7.紧急开启功能(Panic Open)。出门时无需其他操作,只需一次的把手动作,可机械的开启门,所以遇到火灾等应急状况下也迅速,安全的开启门。

8.入侵感应功能。在门上锁的状态下,有人破锁而入时,会发出强力的报警音。

9.火灾报警功能。在室内如果温度达到75°左右,将会发出强力的报警音,同时锁会自动开启。

10.双重锁定功能。外部强制锁定:在内部不能开启,适用于外出时,防止有人入侵。内部强制锁定:在外部不能开启,让您在家时更安心、安全。

11.弱电提醒功能。弱电提醒当电量不足时,在启动开门时,会有美妙的音乐提示您及时更换电池。

12.自动上锁功能。采用全自动锁芯,门关后6秒内自动上锁,外出更加安全。

13.外部显示功能。当密码输入错误,锁舌没正常锁到位,室内反锁,弱电等情况下,外部都有提示功能。

1.3电子密码锁的设计意义

单片机是典型的嵌入式微控制器(Microcontroller Unit),由运算器,控制器,存储器,输入输出设备等构成,相当于一个微型的计算机。与应用在个人电脑中的通用型微处理器相比,它更强调自供应(不用外接硬件)和节约成本。它的最大优点是体积小,可放在仪表内部,但存储量小,输入输出接口简单,功能较低。由于其发展非常迅速,旧的单片机的定义已不能满足,所以在很多应用场合被称为范围更广的微控制器;从上世纪80年代,由当时的4位、8位单片机,已经发展到现在的32位300M的高速单片机。

单片机相当于一个微型的计算机(最小系统),和计算机相比,单片机缺少了外围设备等。概括的讲:一块芯片就成了一台计算机。它的体积小、质量轻、价格便宜、为学习、应用和开发提供了便利条件。同时,学习使用单片机是了解计算机原理与结构的最佳选择。它最早是被用在工业控制领域。

在很多方面单片机比专用处理器更适合应用于嵌入式系统,因此它得到了广泛的应用。事实上单片机是世界上数量最多处理器,随着单片机家族的发展壮大,单片机和专用处理器的发展便分道扬镳。
现代人类生活中所用的几乎每件有电子器件的产品中都会集成有单片机。手机、电话、计算器、家用电器、电子玩具、掌上电脑以及鼠标等电子产品中都含有单片机。

基于单片机的电子密码锁设计,只需在单片机外围接简单的接口电路,核心部分由人为写入程序即可,这样不仅易于操作,也可使产品成本大大降级,且容易进行升级改善。该种电子密码锁设计方法合理,简单易行,成本低,符合人们需求,具有一定的商业价值和市场推广性。

二、实验原理

2.1单片机开发系统主要硬件简介

单片机开发系统的硬件采用的是普中科技的HC6800EM3单片机开发试验仪,它是具有“实验、编程、ISP下载线”多功能合一的新一代单片机开发系统。该51单片机学习实验板支持STC的增强型51单片机的实验、编程功能,同时也兼容AVR系列单片机的烧写和实验。

  • 硬件布局

2、实验板端口资源

整个板子采取功能模块化设计,也就是说每个功能模块都是独立,端口之间都未连接,因此做实验时候需要学习者自己先进行硬件电路的设计与连接来搭建。详细见实验板原理图和每个实验的内容。下表为部分引脚和外围IC的接口对照表:

外围IC与单片机接口对照表

74HC165

并入串出锁存器

CLOCK

P3.6

74HC595

串入并出锁存器

MISO

P3.4(有短路帽)

INDAT

P1.7(有短路帽)

SCK

P3.6

SH/LD

P1.6

RCK

P3.5

74HC138

138译码器

A

P2.2

DS1302

实时时钟

SCK

P3.6

B

P2.3

I/O

P3.4(有短路帽)

C

P2.4

RST

P3.5

AT24C02

EEPROM

SCL

P2.1

PCF8591

数模/模数转换

SCL

P2.1

SDA

P2.0

SDA

P2.0

继电器


P1.4(有短路帽)

蜂鸣器


P1.5(有短路帽)

红外接收头


P3.2(有短路帽)

温度检测


P3.7

步进马达


P1.0-P1.3

串口通信


P3.0  P3.1

1602/12864/彩屏8位数据接口


P0.0-P0.7

NE555

555定时器


P3.5(有短路帽)

2.2单片机开发软件简介

KeilC51软件开发系统简介

单片机开发中除必要的硬件外,同样离不开软件,汇编语言源程序要变为CPU可以执行的机器码有两种方法,一种是手工汇编,另一种是机器汇编,目前已极少使用手工汇编的方法了。

单片机在发展了这么多年来,出现了各种各样的编译软件,Keil C51是美国Keil Software公司出品的51系列兼容单片机C语言软件开发系统,是目前开发51系列单片机的主流工具。与汇编相比,C语言在功能上、结构性、可读性、可维护性上有明显的优势,因而易学易用。用过汇编语言后再使用C来开发,体会更加深刻。

C语言是一个通用的编程语言,它提供高效的代码、结构化的编程和丰富的操作符。C语言不是一种大语言,不是为任何特殊应用领域而设计,它一般来说限制较少,可以为各种软件任务提供方便和有效的编程。许多应用用C比其他语言编程更方便和有效。

优化的Cx51的C编译器完整的实现了ANSI的C语言标准,对8051来说,Cx51不是一个通用的C编译器,它首先的目标是生成针对8051的最快和最紧凑的代码。Cx51具有C编程的弹性和高效的代码和汇编语言的速度。

C语言不能执行的操作如输入和输出,需要操作系统的支持的一部分提供,因为这些函数和语言本身无关,所以C特别适合对多平台提供代码。

8051系列是增长最快的微处理器构架之一,从不同的芯片厂家提供了400多种新扩展的8051芯片,如PHILIPS的8051MX有几M字节的代码和数据空间大的应用中。为了支持这些不同的8051芯片,Keil提供了几种开发工具输出文件格式,OMF2允许支持最多16MB代码和数据空间的PHILIPS 8051MX结构。

Keil C51软件提供丰富的库函数和功能强大的集成开发调试工具,全Windows界面。另外重要的一点,只要看一下编译后生成的汇编代码,就能体会到Keil C51生成的目标代码效率非常之高,多数语句生成的汇编代码很紧凑,容易理解。在开发大型软件时更能体现高级语言的优势。

2.3程序烧录

程序烧录有两种方法:

  • 使用普中科技的程序下载软件
  • 使用STC官方软件下载

三、系统总体方案设计

3.1电子密码锁功能简介

电子密码锁由机械模块、集成线路、电子元件、运行算法等多部分组成,其核心为芯片,通过程序算法下达各种指令,由其他部分配合完成密码的设置、存贮、识别和显示、驱动电磁执行器并检测其驱动电流值、接收传感器送来的报警信号、发送数据等工作。

密码锁的核心原理也很容易让人理解,单片机接收用户输入的指令(密码),与存贮在EEPROM中的密码进行对比。若指令相同,则驱动电机开锁;若指令不同,则提示错误和重新输入密码。同时芯片会记录用户操作的指令以及芯片做出的反应状态,作为后续智能化分析单依据。

3.2 STC15W4K32S4系列单片机简介

STC15W4K32S4系列单片机是 单片机是STC生产的单时钟/机器周期(1T)的单片机,是宽电压/高速/高可靠/低功耗/超强抗干扰的新一代8051单片机,采用STC第九代加密技术,无法解密,指令代码完全兼容传统8051,但速度快8-12倍。内部集成高精度R/C时钟(±0.3%),±1%温飘(-40℃~+85℃),常温下温飘±0.6%(-20℃~+65℃),ISP编程时5MHz~30MHz宽范围可设置,可彻底省掉外部昂贵的晶振和外部复位电路(内部已集成高可靠复位电路,ISP编程时16级复位门槛电压 可选)。8路10位PWM,8路高速10位A/D转换(30万次/秒),内置4K字节大容量SRAM,4组独立 的高速异步串行通信端口(UART1/UART2/UART3/UART4),1组高速同步串行通信端口SPI, 针对多串行口通信/电机控制/强干扰场合。内置比较器,功能更强大。

现STC15系列单片机采用STC-Y5超高速CPU内核,在相同的时钟频率下,速度又比STC早期的1T系列单片机(如STC12系列/STC11系列/STC10系列)的速度快20%。

1.增强型 8051 CPU,1T,单时钟/机器周期,速度比普通8051快8-12倍

2.工作电压:2.5V - 5.5V

3.16K/32K/40K/48K/56K/58K/61K/63.5K字节片内Flash程序存储器,擦写次数10万次以上

4.片内大容量4096字节的SRAM,包括常规的256字节RAM <idata> 和内部扩展的3840字节 XRAM <xdata>

5.大容量片内EEPROM,擦写次数10万次以上 EEPROM,擦写次数10万次以上,擦写次数10万次以上

6.ISP/IAP,在系统可编程/在应用可编程,无需编程器/仿真器

7.共8通道10位高速ADC,速度可达30万次/秒,8路PWM还可当8路D/A使用

8.6通道15位专门的高精度PWM(带死区控制)+2通道CCP(利用它的高速脉冲输出功能可实现11~16位PWM)----可用来再实现8路D/A或2个16位定时器,或2个外部中断(支持上升沿/下降沿中断)与STC15W4K32S4系列单片机的6路增强型PWM相关的端口.上电后默认为高阻输入,上电前用户须在程序中将该些端口设置为其他模式(如准双向口或强推挽模式);注意该些端口进入掉电模式时不能为高阻输入,否则需外部加上拉电阻。
9.内部高可靠复位,ISP编程时16级复位门槛电压可选,可彻底省掉外部复位电路

10.工作频率范围: 5MHz~28MHz, 相当于普通8051的60MHz~336MHz

11.内部高精度R/C时钟(+0.3%),+1%温飘( 40°C~+85*C),常温下温飘+0.6%(-20*C~+65*C)

12.不需外部晶振和外部复位,还可对外输出时钟和低电平复位信号

13.四组完全独立的高速异步串行通信端口,分时切换可当9组串口使用:串口1(RxD/P3.0,TxD/P3.1)可以切换到(RxD_2/P3.6,TxD_2/P3.7),还可以切换到(RxD_3/P1.6,TxD_3/P1.7);串口2(RxD2/P1.0,TxD2/P1.1)可以切换到(RxD2_ 2/P4.6,TxD2_2/P4.7);串口3(RxD3/P0.0,TxD3/P0.1)可以切换到(RxD3_ 2/P5.0,TxD3_ 2/P5.1);串口4(RxD4/P0.2, TxD4/P0.3)可以切换到(RxD4_ 2/P5.2, TxD4_ _2/P5.3)

注意:建议用户将串口1放在P3.6/P3.7或P1.6/ P1.7 (P3.0/P3.1作下载/仿真用);若用户不想切换,坚持使用P3.0/P3.1或作为串口1进行通信,则务必在下载程序时,在软件上勾选“下次冷启动时,P3.2/P3.3为0/0时才可以下载程序”。

14.一组高速同步串行通信端口SPI.

15.支持程序加密后传输,防拦截

16.支持RS485下载
17.低功耗设计:低速模式,空闲模式,掉电模式/停机模式.
18.可将掉电模式/停机模式唤醒的定时器:有内部低功耗掉电唤醒专用定时器。
19.共7个定时器,5个16位可重装载定时器/计数器(TO/T1/T2/T3/T4,其中T0/T1兼容普通8051的定时器/计数器),并均可独立实现对外可编程时钟输出(5通道),另外管脚SysClkO可将系统时钟对外分频输出(+1或+2或+4或+16),2路CCP还可再实现2个定时器

20.定时器/计数器2,也可实现1个16位重装载定时器/计数器,定时器/计数器2也可产生时钟输出T2CLKO

单片机引脚说明

单片机的40个引脚大致可分为4类:电源、时钟、控制和I/O引脚。
⒈ 电源:
⑴ VCC - 芯片电源,接+5V;
⑵ VSS - 接地端;

⒉ 时钟:XTAL1、XTAL2 - 晶体振荡电路反相输入端和输出端。

⒊ 控制线:控制线共有4根,
⑴ ALE/PROG:地址锁存允许/片内EPROM编程脉冲
① ALE功能:用来锁存P0口送出的低8位地址
② PROG功能:片内有EPROM的芯片,在EPROM编程期间,此引脚输入编程脉冲。
⑵ PSEN:外ROM读选通信号。
⑶ RST/VPD:复位/备用电源。
① RST(Reset)功能:复位信号输入端。
② VPD功能:在Vcc掉电情况下,接备用电源。
⑷ EA/Vpp:内外ROM选择/片内EPROM编程电源。
① EA功能:内外ROM选择端。
② Vpp功能:片内有EPROM的芯片,在EPROM编程期间,施加编程电源Vpp。

⒋ I/O线
  80C51共有4个8位并行I/O端口:P0、P1、P2、P3口,共32个引脚。P3口还具有第二功能,用于特殊信号输入输出和控制信号(属控制总线)。  

3.3LCD1602简介

工业字符型液晶,能够同时显示16x02即32个字符。(16列2行)
1602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块。它由若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用,正因为如此所以它不能很好地显示图形(用自定义CGRAM,显示效果也不好)。
1602LCD是指显示的内容为16X2,即可以显示两行,每行16个字符液晶模块(显示字符和数字)。
市面上字符液晶大多数是基于HD44780液晶芯片的,控制原理是完全相同的,因此基于HD44780写的控制程序可以很方便地应用于市面上大部分的字符型液晶。

1602LCD 主要技术参数:

显示容量:16×2 个字符

芯片工作电压:4.5—5.5V

工作电流:2.0mA(5.0V)

模块最佳工作电压:5.0V

字符尺寸:2.95×4.35(W×H)mm

管脚功能

1602采用标准的16脚接口,其中:
第1脚:VSS为电源地
第2脚:VCC接5V电源正极
第3脚:V0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高(对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度)。
第4脚:RS为寄存器选择,高电平1时选择数据寄存器、低电平0时选择指令寄存器。
第5脚:RW为读写信号线,高电平(1)时进行读操作,低电平(0)时进行写操作。
第6脚:E(或EN)端为使能(enable)端,高电平(1)时读取信息,负跳变时执行指令。
第7~14脚:D0~D7为8位双向数据端。
第15~16脚:空脚或背灯电源。15脚背光正极,16脚背光负极。

特性

3.3V或5V工作电压,对比度可调
内含复位电路
提供各种控制命令,如:清屏、字符闪烁、光标闪烁、显示移位等多种功能
有80字节显示数据存储器DDRAM
内建有192个5X7点阵的字型的字符发生器CGROM
8个可由用户自定义的5X7的字符发生器CGRAM

特征应用

微功耗、体积小、显示内容丰富、超薄轻巧,常用在袖珍式仪表和低功耗应用系统中。

操作控制

注:关于E=H脉冲——开始时初始化E为0,然后置E为1。
字符集
1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A”。
在单片机编程中还可以用字符型常量或变量赋值,如'A’。因为CGROM储存的字符代码与我们PC中的字符代码是基本一致的,因此我们在向DDRAM写C51字符代码程序时甚至可以直接用P1=‘A’这样的方法。PC在编译时就把'A'先转换为41H代码了。
字符代码0x00~0x0F为用户自定义的字符图形RAM(对于5X8点阵的字符,可以存放8组,5X10点阵的字符,存放4组),就是CGRAM了。
0x20~0x7F为标准的ASCII码,0xA0~0xFF为日文字符和希腊文字符,其余字符码(0x10~0x1F及0x80~0x9F)没有定义。
以下是1602的16进制ASCII码表地址:读的时候,先读左边那列,再读上面那行,如:感叹号!的ASCII为0x21,字母B的ASCII为0x42(前面加0x表示十六进制)。

1602LCD 的指令说明及时序

1602 液晶模块内部的控制器共有11条控制指令。

控制命令表

序号

指令

RS

R/W

D7

D6

D5

D4

D3

D2

D1

D0

1

清显示

0

0

0

0

0

0

0

0

0

1

2

光标返回

0

0

0

0

0

0

0

0

1

*

3

置输入模式

0

0

0

0

0

0

0

1

I/D

S

4

显示开/关控制

0

0

0

0

0

0

1

D

C

B

5

光标或字符移位

0

0

0

0

0

1

S/C

R/L

*

*

6

置功能

0

0

0

0

1

DL

N

F

*

*

7

置字符发生存贮器地址

0

0

0

1

字符发生存贮器地址

8

置数据存贮器地址

0

0

1

显示数据存贮器地址

9

读忙标志或地址

0

1

BF

计数器地址

10

写数到CGRAM或DDRAM)

1

0

要写的数据内容

11

从CGRAM或DDRAM读数

1

1

读出的数据内容

1602 液晶模块的读写操作、屏幕和光标的操作都是通过指令编程来实现的。(说明:1 为高电平、0 为低电平)

指令 1:清显示,指令码 01H,光标复位到地址 00H 位置。

指令 2:光标复位,光标返回到地址 00H。

指令 3:光标和显示模式设置 I/D:光标移动方向,高电平右移,低电平左移 S:屏幕上所有文字是否 左移或者右移。高电平表示有效,低电平则无效。

指令 4:显示开关控制。 D:控制整体显示的开与关,高电平表示开显示,低电平表示关显示 C:控 制光标的开与关,高电平表示有光标,低电平表示无光标 B:控制光标是否闪烁,高电平闪烁,低电

平不闪烁。

指令 5:光标或显示移位 S/C:高电平时移动显示的文字,低电平时移动光标。

指令 6:功能设置命令 DL:高电平时为 4 位总线,低电平时为 8 位总线 N:低电平时为单行显示,高 电平时双行显示 F: 低电平时显示 5x7 的点阵字符,高电平时显示 5x10 的点阵字符。

指令 7:字符发生器 RAM 地址设置。

指令 8:DDRAM 地址设置。

指令 9:读忙信号和光标地址 BF:为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如 果为低电平表示不忙。

指令 10:写数据。

指令 11:读数据。

基本操作时序表

读操作时序:

写操作时序:

LCD1602的RAM地址映射

液晶显示模块是一个慢显示器件,所以在执行每条指令之前一定要确认模块的忙标志为低电平,表示 不忙,否则此指令失效。要显示字符时要先输入显示字符地址,也就是告诉模块在哪里显示字符,图 10-57 是 1602 的内部显示地址。

1602 的内部显示地址:

例如第二行第一个字符的地址是 40H,那么是否直接写入 40H 就可以将光标定位在第二行第一个字符 的位置呢?这样不行,因为写入显示地址时要求最高位 D7 恒定为高电平 1 所以实际写入的数据应该是 01000000B(40H)+10000000B(80H)=11000000B(C0H)。

在对液晶模块的初始化中要先设置其显示模式,在液晶模块显示字符时光标是自动右移的,无需人工 干预。每次输入指令前都要判断液晶模块是否处于忙的状态。

1602 液晶模块内部的字符发生存储器(CGROM)已经存储了 160 个不同的点阵字符图形,如图 10-58 所示,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有 一个固定的代码,比如大写的英文字母“A”的代码是 01000001B(41H),显示时模块把地址 41H 中 的点阵字符图形显示出来,我们就能看到字母“A”。

1602LCD 的一般初始化(复位)过程

延时 15mS

写指令 38H(不检测忙信号)

延时 5mS

写指令 38H(不检测忙信号)

延时 5mS

写指令 38H(不检测忙信号)

以后每次写指令、读/写数据操作均需要检测忙信号

写指令 38H:显示模式设置

写指令 08H:显示关闭

写指令 01H:显示清屏

写指令 06H:显示光标移动设置

写指令 0CH:显示开及光标设置

3.4矩阵键盘简介

矩阵键盘是单片机外部设备中所使用的排布类似于矩阵的键盘组。矩阵式结构的键盘显然比直接法要复杂一些,识别也要复杂一些,列线通过电阻接正电源,并将行线所接的单片机的I/O口作为输出端,而列线所接的I/O口则作为输入。矩阵键盘的优点是节约单片机IO口,例如普通键盘8个IO口只能用作8个按键,而矩阵键盘能作16个按键。

组成结构

在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式。在矩阵式键盘中,每条水平线和垂直线在交叉处不直接连通,而是通过一个按键加以连接。这样,一个端口(如P1口)就可以构成4*4=16个按键,比之直接将端口线用于键盘多出了一倍,而且线数越多,区别越明显,比如再多加一条线就可以构成20键的键盘,而直接用端口线则只能多出一键(9键)。由此可见,在需要的键数比较多时,采用矩阵法来做键盘是合理的。

矩阵键盘不仅在连接上比单独式按键复杂,它的按键识别方法也比单独式按键复杂。在矩阵键盘的软件接口程序中,常使用的按键识别方法有行扫描法和线反转法。这两种方法的基本思路是采用循环查循的方法,反复查询按键的状态,因此会大量占用MCU的时间,所以较好的方式也是采用状态机的方法来设计,尽量减少键盘查询过程对MCU的占用时间。

单片机系统中,若使用按键较多时如电子密码锁、电话机键盘等一般都至少有12到16个按键,通常采用矩阵键盘。

矩阵键盘又称行列键盘,它是用四条I/O线作为行线,四条I/O线作为列线组成的键盘。在行线和列线的每个交叉点上设置一个按键。这样键盘上按键的个数就为4*4个。这种行列式键盘结构能有效地提高单片机系统中I/O口的利用率。

矩阵键盘的工作原理

   最常见的键盘布局如图3所示。一般由16个按键组成,在单片机中正好可以用一个P口实现16个按键功能,这也是在单片机系统中最常用的形式,4*4矩阵键盘的内部电路如图。

矩阵键盘布局图:

矩阵键盘内部布局图:

当无按键闭合时,P3.0~P3.3与P3.4~P3.7之间开路。当有键闭合时,与闭合键相连的两条I/O口线之间短路。判断有无按键按下的方法是:第一步,置列线P3.4~P3.7为输入状态,从行线P3.0~P3.3输出低电平,读入列线数据,若某一列线为低电平,则该列线上有键闭合。第二步,行线轮流输出低电平,从列线P3.4~P3.7读入数据,若有某一列为低电平,则对应行线上有键按下。综合一二两步的结果,可确定按键编号。但是键闭合一次只能进行一次键功能操作,因此须等到按键释放后,再进行键功能操作,否则按一次键,有可能会连续多次进行同样的键操作。  

扫描法:
以4*4矩阵按键为例,将全部行线置低电平,然后检测列线的状态。只要有一列的电平为低,则表示键盘中有键被按下,而且闭合的键位于低电平线与4根行线相交叉的4个按键之中。若所有列线均为高电平,则键盘中无键按下。
判断闭合键所在的位置: 在确认有键按下后,即可进入确定具体闭合键的过程。其方法是:依次将行线置为低电平,即在置某根行线为低电平时,其它线为高电平。在确定某根行线位置为低电平后,再逐行检测各列线的电平状态。若某列为低,则该列线与置为低电平的行线交叉处的按键就是闭合的按键。
线反转法:

Step 1:将列线作为输出线,行线作为输入线。置输出线全部为0,此时行线中呈低电平0的为按键所在行,如果全部都不是0,则没有按键按下。
Step 2:将第一步反过来,即将行线作为输出线,列线作为输入线。置输出线全部为0,此时列线呈低电平的为按键所在的列。这样,就可以确定了按键的位置(X,Y)。

键盘扫描方法:

键盘扫描方法是:行线P10~P13为输出线,列线P14~P17为输入线。一开始单片机将行线(P10~P13)全部输出低电平,此时读入列线数据,若列线全为高电平则没有键按下,当列线有出现低电平时调用延时程序以此来去除按键抖动。延时完成后再判断是否有低电平,如果此时读入列线数据还是有低电平,则说明确实有键按下。最后一步确定键值。以第二行的S5键为例,若按下S5后该怎么得到这个键值呢?当判断确实有键按下之后,行线轮流输出低电平,根据读入列线的数据可以确定键值。首先,单片机将P10输出为低电平,其它P11~P13输出高电平,此时读取列线的数据全为高电平,说明没有在第一行有键按下;其次,单片机将P11输出低电平,其它P10、P12、P13仍为高电平,此时再来读取列线数据,发现列线读到的数据有低电平,数值为1011(0x0B),如果键盘布局已经确定,那么0x0B就代表S5的值了。转到S5键功能处理子程序就可以达到目的。

四、系统软件设计方案

4.1软件设计思路

将整个程序分为三个部分,一个是输入部分,一个是显示部分,最后是密码验证和重置。

输入部分由矩阵键盘完成,将矩阵键盘上的每一个键赋值,主要有数字键0-9,确认键,更正键(重新输入密码),以及重置键(设置新的密码)。

显示部分:在矩阵键盘上输入数字时,将输入的数字显示在LCD液晶屏上,并且在输入密码、验证密码后显示密码是否正确。

密码验证和重置:在输入密码完成后,将输入密码和实际密码比较。而在重置密码时,要先确认输入密码是否正确。


五、系统调试

编程运行显示无错误,经过在老师面前进行实物操作,显示该电子密码锁确实具有输入,显示,验证,修改密码,重置密码等功能。



单片机源程序如下:

  1. <font color="rgb(0, 0, 0)">#include <STC15.h>

  2. #include "intrins.h"
  3. typedef unsigned char u8;
  4. typedef unsigned int u16;
  5. u8 code KeyCodeTable[]=
  6. {0xee,0xde,0xbe,0x7e,0xed,0xdd,0xbd,0x7d,
  7. 0xeb,0xdb,0xbb,0x7b,0xe7,0xd7,0xb7,0x77};

  8. sbit FMQ=P4^2;
  9. sbit RS = P2^6;          //数据/命令选择控制位
  10. sbit RW = P2^5;                //读/写控制位
  11. sbit EN = P2^7;                //使能控制位
  12. #define DataPort P0

  13. u8 Keys_Scan(void);
  14. void Delay_500us(void);
  15. void Delay_nms(u16 nms);
  16. void Beep(void);
  17. void Pin_Mode(void);

  18. void LCD_Initial(void);
  19. bit LCD_Check_Busy(void);
  20. void LCD_Write_Command(u8 command);
  21. void LCD_Write_Data(u8 Data);
  22. void LCD_Clear(void);
  23. void xianshi(void); //LCD显示函数
  24. void xianshiyes(void);  //输入密码正确的显示函数
  25. void xianshiwrong(void);  //输入密码错误后的显示函数
  26. void input(void);  //输入函数
  27. void CZMA(void);   //重置密码函数
  28. void yanzhen(void);  //将输入的密码与正确密码对比的验证函数
  29. void fuzhi1(void);  //对LCD显示函数中的数组赋值函数

  30. u8 RIGHT[]="pass";
  31. u8 WRONG[]="Password Error";
  32. u8 SHURU[]="aaaaaaaaaa";
  33. u8 SHUZU[]="aaaaaaaaaa";
  34. u8 MIMA[]="000aaaaaaa";
  35. u16 Yanzhenshu=0;
  36. void main(void)
  37. {
  38.         Pin_Mode();
  39.         LCD_Initial();
  40.         LCD_Clear();
  41.         while(1)
  42.         { P1=0x0f;
  43.                
  44.                 if((P1&0x0f)!=0x0f)
  45.                 { Delay_nms(15);
  46.                         if((P1&0x0f)!=0x0f)
  47.                         { LCD_Clear();
  48.                                 fuzhi1(); //先对显示的数组进行赋值,以免出现显示错误
  49.                                 
  50.                                 input(); //输入密码
  51.                                 if(Keys_Scan()==12)
  52.                                 LCD_Clear();
  53.                                 fuzhi1();
  54.                                 
  55.                                 input(); //若按下重置键,则重新输入
  56.                                 if(Keys_Scan()==13)
  57.                                 { yanzhen(); //按下确认键,对密码进行验证
  58.                                         if(Yanzhenshu==0)
  59.                                         {LCD_Clear();
  60.                                         xianshiyes(); //密码正确
  61.                                         }
  62.           else
  63.           { LCD_Clear();
  64.                                                 fuzhi1();
  65.                                                 xianshiwrong();        //密码错误
  66.                                         }                                                
  67.                                 }
  68.                                 if(Keys_Scan()==15)
  69.                                 {
  70.                                         LCD_Clear();
  71.                                         fuzhi1();
  72.                                         yanzhen(); //按下重置密码键之后,先确认之前输入的密码是否正确
  73.                                         if(Yanzhenshu==0)
  74.                                         CZMA(); //正确则重置密码
  75.                                   else
  76.                                         {LCD_Clear();
  77.                                         xianshiwrong();        
  78.                                         }
  79.                                 }
  80.                                 P1=0xf0;
  81.                                 while((P1&0xf0)!=0xf0)
  82.                                 { P1=0xf0;
  83.                                         Beep();
  84.                                 }
  85.                         }
  86.                 }

  87.         }
  88. }
  89. void fuzhi1(void)
  90. { u8 i=0;
  91.         for(;i<10;i++)
  92.         { SHUZU[i]='a';
  93.         }
  94. }

  95. void yanzhen(void)
  96. { u8 i;
  97.         Yanzhenshu=0;
  98.         for(i=0;MIMA[i]!='a' && MIMA[i]!='\0';i++)
  99.         { if(SHURU[i]!=MIMA[i] || SHURU[i+1]!=MIMA[i+1])  //验证密码是否正确
  100.           {Yanzhenshu=1;
  101.                         break;
  102.                 }
  103.         }
  104. }
  105. void xianshiyes(void)
  106. { u8 m;
  107.          u8 n=0;
  108.         for (m=0x80;m<0x90;m++)
  109.         {
  110.         LCD_Write_Command(m);
  111.                 if(RIGHT[n]=='\0') break;
  112.                 LCD_Write_Data(RIGHT[n]);
  113.                 n++;
  114.         }
  115. }
  116. void xianshiwrong(void)
  117. { u8 m;
  118.          u8 n=0;
  119.         for (m=0x80;m<0x90;m++)
  120.         {
  121.         LCD_Write_Command(m);
  122.                 if(WRONG[n]=='\0') break;
  123.                 LCD_Write_Data(WRONG[n]);
  124.                 n++;
  125.         }
  126. }
  127. void xianshi(void)
  128. { u8 m;
  129.          u8 n=0;
  130.         for (m=0x80;m<0x90;m++)
  131.         {
  132.           LCD_Write_Command(m);
  133.                 if(SHUZU[n]=='a'|| SHUZU[n]=='\0') break;
  134.                 LCD_Write_Data(SHUZU[n]);
  135.                 n++;
  136.         }
  137. }
  138. void CZMA(void)
  139. { u8 i,key;
  140.         for(i=0;i<10;)
  141.         { P1=0xf0;
  142.                 if((P1&0xf0)!=0xf0)
  143.                 { Delay_nms(15);
  144.                         if((P1&0xf0)!=0xf0 )
  145.                         { if(Keys_Scan()!=15)
  146.                                 {
  147.                                 if (Keys_Scan()==13) break; //再确认要重置密码后,把输入的新密码存入'SHUZU'数组中,若按下确认键则跳出
  148.                           key=Keys_Scan();
  149.                                 SHUZU[i]=key+'0';
  150.                                 xianshi();
  151.                                 i++;
  152.                                 }
  153.                                 P1=0xf0;
  154.                                 while((P1&0xf0)!=0xf0)
  155.                                 { P1=0xf0;
  156.                                         Beep();
  157.                                 }
  158.                         }
  159.                 }
  160.                
  161.         }
  162.         for(i=0;i<9;i++)
  163.         {MIMA[i]=SHUZU[i];//将密码存入“MIMA”数组中
  164.         }
  165.         LCD_Clear();
  166.         fuzhi1();
  167. }
  168. void input(void)
  169. {
  170.         u8 i=0,key;
  171.         for(;i<10;)
  172.         { P1=0xf0;
  173.                 if((P1&0xf0)!=0xf0)
  174.                 { Delay_nms(15);
  175.                         if((P1&0xf0)!=0xf0)
  176.                         { if (Keys_Scan()>=10) break; //确认有键按下后,如果按下的不是数字键0-9,则跳出循环
  177.                                 key=Keys_Scan();
  178.                                 SHURU[i]=key+'0'; //将输入的数字转化为字符变量存入‘SHURU’和‘SHUZU'两个数组中
  179.                                 SHUZU[i]=SHURU[i];
  180.                                 SHURU[i+1]='a';  //对"SHURU"数组的下一位赋值为a,避免在验证密码时出错
  181.                                 xianshi(); //显示函数
  182.                                 i++;
  183.                                 
  184.                                 P1=0xf0;
  185.                                 while((P1&0xf0)!=0xf0)
  186.                                 { P1=0xf0;
  187.                                         Beep();
  188.                                 }
  189.                         }
  190.                 }
  191.                
  192.         }
  193.         
  194. }
  195. void Delay_500us(void)
  196. {
  197.         u16 t;
  198.         for(t=0;t<540;t++);
  199. }

  200. void Delay_nms(u16 nms)
  201. {
  202.         u16 i,t;
  203.         for(i=0;i<nms;i++)        
  204.         {
  205.                 for(t=0;t<1080;t++);
  206.         }
  207. }

  208. void Beep(void)
  209. {
  210.         u8 i;
  211.         for(i=0;i<10;i++)
  212.         {
  213.                 Delay_500us();
  214.                 FMQ=~FMQ;
  215.         }
  216.         FMQ=1;
  217. }

  218. void Pin_Mode(void)
  219. {
  220.         P0M1 = 0x00;        P0M0 = 0x00;
  221.         P2M1 = 0x00;        P2M0 = 0x00;
  222.         P1M1 = 0x00;  P1M0 = 0x00;
  223.         P4M1 = 0x00;  P4M0 = 0x00;
  224. }
  225. u8 Keys_Scan(void)
  226. {
  227.         u8 j,temp,i;
  228.         u8 t=0xfe;
  229.         P1=0xf0;
  230.                 if((P1&0xf0)!=0xf0)
  231.                 { Beep();
  232.                         for(i=0;i<4;i++)
  233.                         { P1=t;
  234.                                 temp=P1;
  235.                    for(j=0;j<16;j++)
  236.                         { if(temp==KeyCodeTable[j]) return(j);
  237.                         }
  238.        t=_crol_(t,1);
  239.                 }
  240.                
  241.         }
  242.         return(16);
  243. }
  244. //当有键按下时,确认所按下的键并赋值
  245. void LCD_Initial(void)
  246. {
  247.         LCD_Write_Command(0x38);         //显示模式设置
  248.         Delay_nms(5);                                 //16*2,5*7点阵
  249.         LCD_Write_Command(0x38);         //8位数据接口
  250.         Delay_nms(5);
  251.         LCD_Write_Command(0x38);
  252.         Delay_nms(5);
  253.         LCD_Write_Command(0x38);  
  254.         LCD_Write_Command(0x08); //显示关闭,见手册4.1.2
  255.         LCD_Write_Command(0x01); //显示清屏
  256.         LCD_Write_Command(0x06); //显示光标移动设置
  257.         Delay_nms(5);
  258.         LCD_Write_Command(0x0C); //显示开及光标设置
  259. }
  260. bit LCD_Check_Busy(void)
  261. {
  262.         DataPort = 0xFF;         //将端口置为全高(输入)
  263.         RS = 0;                 //指令(状态)
  264. ……………………

  265. …………限于本文篇幅 余下代码请从51黑下载附件…………
  266. </font>
复制代码
0.png


所有资料51hei提供下载:

电子密码锁.rar (1.58 MB, 下载次数: 357)

评分

参与人数 2黑币 +17 收起 理由
NPC-1024 + 5 赞一个!
凌净清河 + 12 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:448890 发表于 2018-12-20 00:33 来自手机 | 显示全部楼层
楼主,能分享我一份吗!940121069@qq.com
回复

使用道具 举报

ID:509769 发表于 2019-4-11 16:44 | 显示全部楼层
myqq 发表于 2018-12-20 00:33
楼主,能分享我一份吗!940121069@qq.com

楼主给分享一份好吗?89160985@qq.com
回复

使用道具 举报

ID:502407 发表于 2019-4-17 10:02 | 显示全部楼层
楼主能分享一份吗,黑币不够。614837496@qq.com
回复

使用道具 举报

ID:4303 发表于 2019-11-19 15:40 | 显示全部楼层
有点问题吧,按键最后一列不好用啊
回复

使用道具 举报

ID:671283 发表于 2019-12-28 17:33 来自手机 | 显示全部楼层
文章不错,楼主棒棒的
回复

使用道具 举报

ID:511038 发表于 2020-1-6 10:45 | 显示全部楼层
感谢楼主分享!
回复

使用道具 举报

ID:110278 发表于 2020-1-6 20:56 | 显示全部楼层
很完整。
回复

使用道具 举报

ID:685980 发表于 2020-1-14 11:18 来自手机 | 显示全部楼层
楼主可以分享一份嘛?!!!!!
回复

使用道具 举报

ID:773648 发表于 2020-6-9 10:49 | 显示全部楼层
点赞,做得挺详细的
回复

使用道具 举报

ID:847720 发表于 2020-12-8 10:38 | 显示全部楼层
void Pin_Mode(void)
{
        P0M1 = 0x00;        P0M0 = 0x00;
        P2M1 = 0x00;        P2M0 = 0x00;
        P1M1 = 0x00;  P1M0 = 0x00;
        P4M1 = 0x00;  P4M0 = 0x00;
}
这一段是什么意思啊?
回复

使用道具 举报

ID:842146 发表于 2020-12-10 15:49 | 显示全部楼层
素笺 发表于 2020-12-8 10:38
void Pin_Mode(void)
{
        P0M1 = 0x00;        P0M0 = 0x00;

对I/O口输出模式的设置
回复

使用道具 举报

ID:865623 发表于 2020-12-22 17:08 | 显示全部楼层
楼主有设计总图或者接线图能发一下吗
回复

使用道具 举报

ID:865623 发表于 2020-12-22 17:15 | 显示全部楼层
楼主能发一下电路图吗
回复

使用道具 举报

ID:1103636 发表于 2023-12-12 09:15 | 显示全部楼层
太强了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表