ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于51单片机的电子密码锁设计:矩阵键盘、状态机与AT24C02掉电存储

基于51单片机的电子密码锁设计:矩阵键盘、状态机与AT24C02掉电存储 简介一份基于51单片机的电子密码锁设计完整报告适用于单片机课程设计、毕业设计及实训报告撰写适合初、中级学习者参考。压缩包仅含1个docx文档整体约1.52MB轻量便于下载阅读目前已有177人浏览学习。文档以LCD1602显示、矩阵键盘输入、复位和电源电路为核心完整呈现从绪论、实验原理到设计实现与结论的论述脉络。其中既分析了电子密码锁相对机械锁的安全优势也介绍了单片机开发系统与Keil C51开发环境并通过C语言程序实现开锁、修改密码等基本功能。读者可借此掌握51单片机最小系统及外围接口设计思路理解密码输入、显示与校验的软件流程还可参考其章节组织与论证方式用于撰写课程设计报告或毕业设计说明书。1. 电子密码锁用51单片机第一件事不是写代码电子密码锁在 51 单片机课程设计里几乎是一道必考题也是硬件工程师练手最常见的组合矩阵键盘、LCD 显示、EEPROM 掉电存储、继电器控制电磁锁四个外设同时出现在一块板子上。很多人拿到“基于51单片机的电子密码锁设计”第一反应是直接写按键扫描结果往往卡在两个地方:密码按什么格式存在哪、矩阵键盘怎么扫才能不串键不抖动。这篇不按文档顺序讲而是按你自己从零搭一个能跑起来的系统顺序讲先定硬件电路和引脚再写状态机和键盘扫描最后落到位密码校验和掉电保护怎么做得像真的产品而不是课程作业。2. 51单片机电子密码锁硬件设计矩阵键盘、显示与引脚规划2.1 硬件的核心矛盾按键位数多、GPIO 不够用电子密码锁至少要 10 个数字键加上确认、删除、修改密码等功能键通常是 4×4 或 4×5 矩阵。如果每个按键都占一个独立 GPIOP0、P1、P2 加起来还不够所以第一步必须用矩阵键盘。显示方面数码管方案适合只显示 4 位密码的场景但要做到“输入时回显星号、提示 OPEN / ERROR、显示剩余错误次数”LCD1602 明显更合适。存储芯片选 AT24C02 是因为它便宜、I2C 协议简单、掉电不丢数据。执行机构一般用继电器控制 12V 电磁锁或者直接驱动小功率电控锁。整套系统的 GPIO 占用如下矩阵键盘 8 个脚、LCD1602 的 RS/EN/D0~D7 共 10 个脚、AT24C02 的 SCL/SDA 共 2 个脚、蜂鸣器和继电器各 1 个脚。51 单片机全部引脚正好用完但基本没有余量所以引脚规划必须在画原理图前定死否则后面改一处牵连一大片。2.2 矩阵键盘和 AT24C02 为什么都选 P1/P2在 51 单片机里P1 口是准双向 I/O 口内部自带弱上拉读引脚之前写 1 就能直接当输入用非常适合矩阵键盘的行输入。P0 口是开漏输出做键盘输入必须要外加上拉电阻既浪费元件又容易出电平问题。P3 口则承担串口、外部中断和定时器功能密码锁不用串口时虽然能释放出来但最好为调试预留。所以矩阵键盘固定用 P1.0~P1.7这是大多数 51 单片机电子密码锁原理图的标准接法。AT24C02 用 P2.2/P2.3 软件模拟 I2C比硬件 I2C 好移植换 STC、AT89 系列都不用改。SDA 和 SCL 上必须各接一个 4.7k 左右的上拉电阻I2C 总线是开漏结构漏掉这个电阻的常见现象是写入时好时坏、掉电后密码丢失。LCD1602 的数据口放 P0 口因为 P0 恰好还要接上拉排阻数据线和高电平都一起解决。2.3 引脚分配表与最小系统注意事项下面是这套设计里常用的引脚分配实际画板时按这个表对能省很多回头查线的功夫。模块信号51 单片机引脚说明矩阵键盘R1~R4 行输入P1.0~P1.3内部上拉按键按下读到低电平矩阵键盘C1~C4 列输出P1.4~P1.7扫描时逐列拉低电平LCD1602RS / ENP2.0 / P2.1RS 高电平时为数据操作LCD1602D0~D7P0.0~P0.78 位数据总线必须接上拉排阻AT24C02SCL / SDAP2.2 / P2.3模拟 I2C两条线各接 4.7k 上拉蜂鸣器BUZZERP2.4通过 8050 三极管驱动继电器RELAYP2.5控制电磁锁线圈反并续流二极管最小系统三件事不能省12MHz 晶振加两个 30pF 负载电容、10uF 电解电容与 10k 电阻组成的复位电路、VCC 和 GND 之间 0.1uF 高频去耦电容。很多 Proteus 仿真能跑、实物上电就重启的板子问题基本出在去耦电容太远或复位电容漏焊。另外继电器公共端如果是 12V 供电不要在单片机 5V 上直接取电吸合瞬间电流尖峰足以让 51 单片机复位。3. 电子密码锁软件核心51单片机状态机与按键扫描3.1 状态机设计从按一下键到开锁密码锁软件最忌讳写成一大串 if 嵌套按哪个键做什么分散在各处改一个功能就要通读全代码。我习惯把系统拆成五个状态待机状态STATE_IDLE、输入状态STATE_INPUT、验证状态STATE_VERIFY、改密状态STATE_CHANGE、锁定状态STATE_LOCK。主循环里只做一件事根据当前状态调用对应的处理函数。按键扫描放在主循环的固定位置扫描结果先不处理只在状态机里同步更新。比如待机状态收到数字键会进入输入状态并显示第一位星号输入状态收到确认键就跳转验证状态收到删除键就回退一位验证成功置位继电器并延时断开验证失败则错误计数器加一。这样每个状态对应一个函数参数传递清晰后面加“管理员密码”“指纹模块预留接口”都只需要在状态机里加分支。3.2 行列反转法扫描矩阵键盘矩阵键盘扫描有逐行扫描、逐列扫描、行列反转法三种常用写法。逐行扫描代码直观但循环次数多行列反转法一次读出唯一的组合值代码短适合 4×4 小键盘。下面是比较通用的一段unsigned char keyscan(void) { unsigned char row, col, keycode; P1 0x0F; // 高四位输出低电平低四位读行 if ((P1 0x0F) ! 0x0F) // 有键按下 { delay_ms(10); // 消抖 if ((P1 0x0F) ! 0x0F) { row P1 0x0F; // 保存按下的行号 P1 (row 4) | 0x0F; // 反转原行线变输出列线变输入 col P1 0xF0; // 读取列号 keycode row | col; // 行列组合唯一对应一个按键 return get_key_value(keycode); } } return NO_KEY; }第一句把 P1 高四位全部拉低这时候低四位读到的值中0 的位置就是被按下的行。第一次读到按下不直接取键值而是等 10ms 再读一次消掉机械按键的通断抖动消抖时间太短等于没有太长会导致按键手感发粘。确认按下后反转方向把原来拉低的列线变成输入把原来读到的行线拉低再次读取的列值与之前保存的行值拼在一起就是该按键的唯一编码。get_key_value一般用 switch-case 把散列的组合值映射成字符比如 0xEE 对应按键 1、0xDE 对应按键 2、0xBE 对应按键 30x7E 对应功能键 A。这里的组合值取决于 P1.0~P1.7 接的行列顺序画原理图和写映射表必须一一对应否则会出现“按 1 显示 4”这类串键问题。3.3 密码输入缓冲区与比较逻辑密码输入缓冲区建议固定长度 6 位用数组存字符而不是用整数累加因为密码以 0 开头时整数会丢位。每次按键解析出数字后先把对应位置写进数组同时用光标位置指示输入进度if (key 0 key 9) { if (input_len 6) { pwd_buf[input_len] key; lcd_write_char(*); // 只显示星号不回显明文 } }密码比较在验证状态里进行逐位比较输入缓冲区和存储在 EEPROM 里的密码。这里注意不要用字符串比较函数因为 EEPROM 读出的数据末尾不一定有\0自己写 6 次循环更可靠。验证成功之后继电器吸合时间一般控制在 2~5 秒用定时器计数控制不要用delay死等否则等待继电器断开的这段时间里按键完全不响应用户按删除键会没反应体验很差。验证失败逻辑放到第四章和第五章一起展开。4. 基于51单片机的密码存储与Proteus仿真联调4.1 AT24C02 写入与读出I2C 时序必须按手册来EEPROM 的读写是电子密码锁和普通密码板最本质的差别。AT24C02 的器件地址是 0xA0A2A1A0 引脚接地时最后一位表示读写方向写为 0、读为 1。写入一个字节需要四个步骤起始信号、发送器件地址、发送存储地址、发送数据每步都要等 ACK。完整代码如下void write_eeprom(unsigned char addr, unsigned char dat) { i2c_start(); // SCL 高电平时 SDA 由高变低表示起始 i2c_send_byte(0xA0); // 器件地址 写方向 i2c_wait_ack(); i2c_send_byte(addr); // 数据存储地址0x00~0x07 i2c_wait_ack(); i2c_send_byte(dat); // 要写入的密码字节 i2c_wait_ack(); i2c_stop(); // SCL 高电平时 SDA 由低变高表示停止 delay_ms(5); // 等待芯片内部写周期完成 }最后这 5ms 延时常被忽略。AT24C02 写入后需要几毫秒的写周期期间不响应任何 I2C 请求如果写完立刻连续写下一个字节会丢掉数据。我调试时踩过这个坑表现是第一次写进去正常连续改第二次密码就变成 FF。读操作的时序稍有不同需要先发写方向指定地址再重新产生起始信号最后发读方向读数据不能像 RAM 一样直接寻址读。4.2 上电默认密码与数据校验第一次上电时 EEPROM 里全是 0xFF如果直接当密码用用户会永远无法开锁。所以上电初始化时要做一次校验在 EEPROM 的 0x06 地址存一个预设校验字节读出来不等于预设值就认为芯片是全新的把默认密码 123456 写入 0x00~0x05 地址并写入校验字节。if (read_eeprom(0x06) ! 0x5A) { for (i 0; i 6; i) write_eeprom(i, default_pwd[i]); write_eeprom(0x06, 0x5A); }这里校验位比直接判断密码是否为 0xFF 更可靠因为用户有可能把密码设置成 FF 对应的十进制值。读取密码做验证时6 个字节要连续读完再比较不要读一个比一个防止校验过程中 EEPROM 被其他中断打扰产生半新半旧的密码组合。4.3 Proteus 仿真 51 单片机密码锁的常见坑仿真能跑通并不能保证实物一次点亮Proteus 里最常见的坑有三个。第一AT24C02 的 SCL/SDA 悬空时仿真器不会报错但写入会失败必须在仿真图里加 4.7k 上拉电阻这和实物要求一致。第二LCD1602 数据口接 P0 时仿真里即使不加上拉排阻也能显示正常但实物会花屏所以仿真阶段就把上拉加上别给自己留一个“仿真行实物不行”的隐患。第三继电器模块在 Proteus 里用普通开关模拟即可但要注意开关属性里的驱动电压默认 5V 继电器和实物 12V 锁的模型参数不同仿真通过后到实物焊接时驱动三极管和续流二极管不能省。仿真联调时建议把验证失败后的蜂鸣器报警时间写短一点比如 200ms方便在仿真里观察逻辑是否正确确认无误后再把报警时间调回实际需要的 2 秒左右。键盘扫描里的消抖延时在仿真环境下几乎不需要但代码里必须保留否则实物上会因为按键抖动出现一次按下变成两次输入。5. 电子密码锁防暴力破解错误次数锁定与掉电保持优化5.1 定时器实现的错误次数锁定防暴力破解最简单的策略是连续输错 3 次锁定 30 秒。锁定期间不扫描键盘、不刷新输入状态只显示“LOCKED”和倒计时。锁定时间用定时器 T0 产生 1ms 基准累积不要在锁定状态下用delay(30000)那样期间无法刷新 LCD也无法提前解锁。void timer0_isr() interrupt 1 { TH0 0xFC; // 12MHz 晶振12T 模式下 1ms 定时初值 TL0 0x18; if (state STATE_LOCK) { lock_tick; if (lock_tick 30000) // 锁定 30 秒 { lock_tick 0; retry_cnt 0; state STATE_IDLE; } } }retry_cnt和lock_tick都要定义成全局变量锁定期间蜂鸣器和 LCD 仍然由主循环刷新只是按键扫描直接返回空值。这样实现比延时解锁稳定得多而且锁定时间可以做成宏定义调试时改成 5 秒发布时再调回 30 秒。5.2 掉电瞬间保存状态与 EEPROM 校验如果密码锁使用在经常断电的环境要考虑掉电瞬间正在修改密码的情况。常见做法是用电源检测电路接外部中断正常工作时二极管隔离的主电源给单片机供电掉电瞬间 INT0 引脚电平变化触发中断在中断里把当前密码重新写入 EEPROM 并清空输入缓冲区。写入代码和正常写 EEPROM 一样只是中断服务程序里要关掉其他中断避免 I2C 时序被打断。EEPROM 写入过程中断电会留下错数据所以上电校验字节可以更严格在 0x07 存校验字节的反码读出来两字节不互为反码则判断数据损坏恢复默认密码。这套做法用在门禁、储物柜这类不能因为一次断电就报废的场合非常实用代码量增加不到十行。把错误次数和锁定时间做成宏校验逻辑单独抽一个函数整个状态机就具备了从密码锁迁移到指纹锁、刷卡锁的基础后续加模块时不用重写主流程。本文还有配套的精品资源点击获取
返回列表