尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

51单片机蓝牙密码锁全解析:HC-05与继电器开锁实践

发布时间:2026/9/16 18:20:54

资讯中心
01
ARTICLE

51单片机蓝牙密码锁全解析:HC-05与继电器开锁实践

51单片机蓝牙密码锁全解析:HC-05与继电器开锁实践
简介基于51单片机的蓝牙密码锁项目资源面向电子爱好者、嵌入式初学者及课程设计人群。项目以STC89C52为控制核心集成蓝牙模块、DS1302时钟芯片、DS18B20温度传感器、AT24C02存储器和4×4矩阵键盘实现手机无线开锁、时间显示、测温、掉电保存密码、一键关门、重新设密、取消确认及密码输入等功能。资源共72个文件约98.91MB含C语言源码、原理图与PCB、视频讲解、PDF芯片手册、元器件清单、系统框图、软件流程图及程序烧录工具等便于从零搭建和调试。已有1914人学习下载适合完整复现蓝牙密码锁、学习多模块协同工作或进行二次开发。整套资料从设计到实物均有覆盖实用性强。1. 51单片机蓝牙密码锁串口链路、密码校验和继电器开锁在实验室机柜和公司文件柜的改造场景里刷卡和指纹方案硬件成本高、施工周期长51单片机蓝牙密码锁反而是性价比最直接的选择一块STC89C52、一个HC-05蓝牙模块和一只继电器整套常用元件成本可以控制在几十元以内。这套方案的本质是把开锁拆成三层蓝牙链路负责传密码单片机负责密码校验继电器负责驱动电磁锁。对正在做51单片机课程设计的人来说它把串口中断、定时器、I2C和外部中断串在了一个完整项目里对想往产品方向走的人它又可以逐步扩展出密码修改、错误锁定和帧加密。2. 硬件搭建与器件选型HC-05、STC89C52和继电器驱动电路2.1 为什么是STC89C52 HC-05这组组合的选型逻辑STC89C52是51单片机课程设计里最常出现的型号内置8KB Flash、512字节RAM5V供电工作频率最高40MHz。它只有一个全双工UART恰好够接HC-05蓝牙模块P3.2和P3.3两路外部中断还可以扩展指纹模块或人体感应模块不会占用串口。相比STM32F103C8T6这类32位方案51单片机的外设简单寄存器少用Keil C51写代码时几乎不需要查复杂的库函数手册从头到尾能自己控制每一个字节的流向。HC-05是经典蓝牙SPP透传模块主从一体支持AT指令配置。模块内部把蓝牙协议栈完全封装好对单片机呈现出来的就是一根串口线手机通过蓝牙发数据HC-05从TXD引脚原样吐出来单片机往RXD引脚写数据HC-05就把数据广播到蓝牙链路上。51单片机侧完全不需要维护蓝牙协议这在Keil C51环境下是最大的优势。另一个被低估的点是HC-05对供电范围容忍度高3.6V到6V都能工作直接接单片机的5V电源轨就可以不需要为了它额外加一路3.3V LDO。相比用NRF24L01射频模块自己组协议HC-05的经典蓝牙SPP在手机端的兼容性稳定得多配对后就是一个虚拟串口手机软件生态成熟。这正是蓝牙密码锁项目大量采用经典蓝牙协议而不是BLE的理由——BLE的GATT服务设计在51单片机上要自己维护连接状态和特征值读写对课程设计周期来说太重了。2.2 串口与电源电路P3.0/P3.1接法、限流电阻和指示灯电路连接的常见做法是HC-05的TXD接单片机的P3.0即RXD引脚HC-05的RXD接单片机的P3.1即TXD引脚中间串联一个1kΩ电阻。串电阻的目的不是电平转换而是保护部分HC-05模块的RXD引脚电平钳位在3.3V单片机TXD输出5V高电平长期直接连接会导致模块内部LDO过热表现就是传数据一段时间后蓝牙掉线摸一下模块外壳烫手。加1kΩ电阻后5V灌入电流被限制在2mA左右电阻上的分压足以把引脚电压压到安全范围。HC-05模块上电后指示灯有两种闪烁状态快速闪烁约2Hz表示模块正在广播等待配对慢速闪烁约0.5Hz表示已和手机建立SPP连接。调试时先看这个灯灯的状态比任何串口助手都能更快判断问题。注意HC-05的STATE引脚是连接状态输出未连接时输出低电平连接成功后输出高电平。这个引脚后面要接外部中断做断开复位预留一根杜邦线到P3.2。2.3 继电器驱动与电磁锁ULN2003、续流二极管和共地处理继电器驱动电路我一般用ULN2003A而不是直接用三极管。51单片机的P2口灌电流能力有限驱动5V继电器线圈的70mA工作电流长时间运行IO口电压会被拉低严重时单片机直接复位。ULN2003是达林顿管阵列输入端接P2.0输出端接继电器线圈负极线圈正极接VCC输出端与电源之间并联1N4007续流二极管。继电器线圈是感性负载断电瞬间会产生反向电动势没有续流二极管就会击穿ULN2003内部三极管这是继电器驱动电路里最常见的损坏原因。12V电磁锁需要独立12V电源12V电源的GND必须和5V电源的GND共地否则串口数据发得通但继电器回路无法形成锁不会动作。判断这个问题的技巧是用万用表测继电器线圈两端在动作瞬间有没有电压差如果有压差但锁不动大概率是电磁锁供电回路的电流不足如果没有压差问题出在共地或驱动引脚上。2.4 引脚分配表与烧录前的检查清单外设51单片机引脚方向说明HC-05 TXDP3.0RXD输入蓝牙数据进单片机HC-05 RXDP3.1TXD串1kΩ输出单片机数据发蓝牙继电器驱动P2.0输出高电平吸合密码正确LEDP2.1输出低电平点亮密码错误LEDP2.2输出低电平点亮AT24C02 SCLP2.3输出I2C时钟线AT24C02 SDAP2.4双向I2C数据线接4.7kΩ上拉HC-05 STATEP3.2INT0输入连接状态监测把引脚定义写成一个头文件烧录前逐个核对// pin.h - 51单片机蓝牙密码锁引脚定义 #include reg52.h sbit RELAY_PIN P2^0; // 继电器控制P2.0输出高电平开锁 sbit PASS_OK_LED P2^1; // 密码正确指示低电平点亮 sbit ERR_LED P2^2; // 密码错误指示低电平点亮 sbit SCL_PIN P2^3; // AT24C02 的 SCL 引脚 sbit SDA_PIN P2^4; // AT24C02 的 SDA 引脚需接上拉在Keil C51里sbit是位寻址声明声明后就能在程序里直接赋值不需要额外再定义sfr地址。P2.3和P2.4做软件模拟I2C是因为51单片机没有硬件I2C外设SCL和SDA任意IO口都行。若把AT24C02换成别的EEPROM型号需要注意确认器件地址位和设备地址的对应关系。3. 单片机程序实现串口中断、密码帧解析和AT24C02掉电存储3.1 串口中断初始化SCON、波特率和帧接收缓冲51的串口工作在模式1时是8位UART一个起始位、一个停止位、没有校验位刚好匹配HC-05默认的数据格式。波特率由定时器1的工作模式2提供晶振必须选11.0592MHz这个频率能整除出9600这个标准波特率误差为0。如果手头只有12MHz晶振串口通信在高波特率下会出现移位误差表现就是HC-05偶尔能通、偶尔乱码。寄存器/位设定值作用SCON0x50串口模式18位UARTREN1允许接收TMOD0x20与0x0F先按位与定时器1工作模式28位自动重装TH1/TL10xFD11.0592MHz晶振下对应9600波特率IE0x90打开总中断EA和串口中断ES// 串口初始化11.0592MHz晶振9600-8-N-1 void UART_Init(void) { SCON 0x50; // 串口模式1REN1允许接收 TMOD 0x0F; // 清除定时器1相关位 TMOD | 0x20; // 定时器1工作模式28位自动重装 TH1 0xFD; // 波特率9600的重装值 TL1 0xFD; // 模式2下TH1和TL1相同 TR1 1; // 启动定时器1 ES 1; // 使能串口中断 EA 1; // 使能总中断 }SCON0x50的含义是SM00、SM11确定串口模式1REN1允许接收。TMOD先与0x0F清零高四位再或0x20设置定时器1为模式2这样不会误动定时器0的配置。TH10xFD对应波特率计算式11059200 / (32 * 12 * (256 - 253)) 9600结果正好是目标波特率。接收用中断而不是查询否则主循环一旦进入继电器延时蓝牙数据就会丢失。中断服务函数把收到的每个字节先放进缓冲区只做接收不做解析解析放在主循环里。unsigned char rx_buf[16]; // 接收缓冲最大容纳16字节帧 unsigned char rx_len 0; // 当前已接收长度 bit frame_ready 0; // 帧完成标志 // 串口接收中断只收字节置位帧完成标志 void UART_ISR(void) interrupt 4 { unsigned char ch; if (RI 0) return; // 仅处理接收中断 RI 0; // 清除接收标志必须软件清0 ch SBUF; // 读取接收寄存器 if (rx_len 16) { rx_buf[rx_len] ch; } if (ch \n) { frame_ready 1; // 收到换行符代表一帧结束 } }RI标志在接收完一个字节后由硬件置1进入中断后如果不软件清零下一次接收就永远无法完成。SBUF是一个字节的接收缓冲区读SBUF本身就会清除硬件接收状态但RI仍需手动置0这是C51中断编写最容易忽略的地方。中断里只做缓冲和帧完成标志不调用延时函数这也是嵌入式中断服务函数的基本纪律。3.2 密码帧格式与校验逻辑开锁和改密两条指令给手机端的帧格式做简单约定开锁帧是#加6位密码加回车换行例如#123456\r\n改密帧是加旧密码加-加新密码例如123456-888888\r\n。帧头字母区分指令类型\r\n作为结束标记这样即使蓝牙中途拆包粘包单片机也能在换行符处重新对齐。// 主循环中的帧解析密码校验与继电器控制 void process_frame(void) { unsigned char i; if (frame_ready 0) return; frame_ready 0; // 开锁帧# 6位密码 \r\n共9字节 if (rx_buf[0] # rx_len 9) { for (i 0; i 6; i) { if (rx_buf[i 1] ! password[i]) break; } if (i 6) { // 密码正确驱动继电器动作 RELAY_PIN 1; // 继电器吸合 PASS_OK_LED 0; // 点亮正确指示灯 delay_ms(800); // 保持开锁800ms RELAY_PIN 0; // 释放继电器自动落锁 PASS_OK_LED 1; error_cnt 0; // 正确开锁后清零错误计数 } else { error_cnt; // 密码错误累计 ERR_LED 0; delay_ms(200); ERR_LED 1; } } // 改密帧 旧密码 - 新密码 \r\n共16字节 else if (rx_buf[0] rx_len 16) { for (i 0; i 6; i) { if (rx_buf[i 1] ! password[i]) break; } if (i 6 rx_buf[7] -) { for (i 0; i 6; i) { password[i] rx_buf[8 i]; // 新密码写入内存 } // 写回EEPROM掉电后依然生效 for (i 0; i 6; i) { AT24C02_WriteByte(PWD_ADDR i, password[i]); } } } rx_len 0; }开锁帧长度必须是9字节多一个空格或少一个回车都会被判为非法帧。密码比对通过break退出时i正好等于6利用这个特性判断全部匹配不需要另外引入布尔标志位。错误计数error_cnt为后续的错误锁定逻辑留了接口。改密帧的旧密码校验通过后才允许覆盖新密码防止无关人员随意改动密码。3.3 AT24C02掉电存储I2C时序和默认密码初始化单片机上电后密码数组直接定义在代码里虽然能用但用户一旦要求改密码重启就恢复默认值。常见做法是外挂AT24C02从机EEPROM掉电保存密码和错误计数。AT24C02是I2C接口SCL时钟频率不要超过100kHz51单片机用软件模拟完全足够。// 向AT24C02写一个字节调用前SCL和SDA均为高电平 void AT24C02_WriteByte(unsigned char addr, unsigned char dat) { I2C_Start(); // SCL高电平时SDA从高到低产生起始信号 I2C_SendByte(0xA0); // 器件地址0xA0最低位0表示写操作 I2C_SendByte(addr); // 目标字地址 I2C_SendByte(dat); // 写入的数据 I2C_Stop(); // SCL高电平时SDA从低到高产生停止信号 delay_ms(10); // 等待芯片内部写周期完成 } // 上电时从AT24C02读取密码 void password_load(void) { unsigned char i, j; for (i 0; i 6; i) { password[i] AT24C02_ReadByte(PWD_ADDR i); if (password[i] 0xFF) { // 空片首次上电 for (j 0; j 6; j) { password[j] 123456[j]; // 默认密码 AT24C02_WriteByte(PWD_ADDR j, password[j]); } break; } } }器件地址0xA0由AT24C02的A0、A1、A2三个引脚接地决定最低位为0时表示写操作为1时表示读操作。每次写操作后芯片需要5ms左右完成内部擦写因此延时10ms才执行下一次I2C操作。AT24C02出厂数据是全0xFF如果读到0xFF说明芯片从未写过密码这时才写入出厂默认值123456。若改成AT24C04器件地址中的最低地址位会被字地址最高位占用地址计算方式完全不一样不建议在入门项目里做这种替换。4. 蓝牙联调与排错AT指令配置、波特率匹配和连接失败定位4.1 HC-05进入AT模式按住按键上电和一组常用参数买来的HC-05默认设备名通常是HC-05默认配对码1234默认数据波特率9600。要改名字或配对码必须先进入AT模式。操作顺序是按住模块上的小按键不松手再给模块上电等指示灯2秒慢闪一次再松开。此时模块以AT模式工作通信波特率一般用38400也有部分固件保持9600先用38400尝试无响应再切换9600。AT指令功能典型返回AT测试通信OKATNAME51Lock修改蓝牙广播名OKATPSWD8888修改配对PIN码OKATUART9600,0,0设置波特率9600无校验1停止位OKATROLE0设置从机模式OKATUART9600,0,0这条最容易踩坑HC-05的AT指令波特率和数据波特率是分开的。改完数据波特率后模块会自动断开此时要用单片机通信必须重新上电。部分旧固件不支持三参数格式可以试ATUART9600返回ERROR就要考虑固件版本问题而不是反复重发指令。4.2 手机端联调蓝牙配对、串口助手和最小开锁测试手机端用通用的蓝牙串口调试类App即可流程基本一致。先打开手机蓝牙和数据扫描到51Lock后点击配对输入配对码。完成配对后在App里连接设备连接成功的瞬间HC-05指示灯会从快闪变成慢闪。随后设置串口参数手机串口工具的波特率设置对SPP透传没有实际意义关键是“发送新行”选项有的App叫“添加CRLF”。最小开锁测试流程如下。手机连接51Lock确认HC-05指示灯为慢闪状态。在串口助手输入#123456勾选发送新行。观察单片机P2.1指示灯闪一下继电器传来吸合声。约1秒后继电器释放完成一次完整的开锁动作。如果App提示发送成功但锁没有任何反应先不要改协议把HC-05的TXD和RXD对调一下再测同时确认两侧GND确实共地这两条解决了大部分沉默故障。4.3 连不上或传不通三种高频故障的定位方法第一种是手机搜不到HC-05。模块一直快闪说明在广播如果手机蓝牙界面反复扫描都不出现最常见原因是模块之前已经和另一台设备配对已配对状态下模块不会进入广播状态。处理方法是删除手机上所有HC-05相关的已配对记录再重新扫描。第二种是配对后数据不通。拿一根杜邦线把HC-05的TXD和RXD短接让模块自发自收然后用手机发送任意字符如果收不到回显问题在模块自身或者波特率配置能收到回显问题就在单片机侧的串口配置或线路连接。这个自环测试能把故障范围缩小一半。还可以用一段最简程序直接驱动继电器验证单片机到继电器的通路是否正常// 硬件自检继电器每500ms吸合释放一次 void relay_self_test(void) { RELAY_PIN 1; // 高电平驱动继电器吸合 delay_ms(500); // 吸合保持500ms RELAY_PIN 0; // 释放继电器 delay_ms(500); }第三种是数据偶尔乱码。除了前面说的晶振频率必须用11.0592MHz外还要检查HC-05的供电。蓝牙发射瞬间电流约50mA如果模块从开发板的LDO取电而LDO输出能力不足无线发射时电压跌落会造成数据帧错位。给HC-05单独加一只100μF电解电容再并联0.1μF瓷片电容乱码问题基本消失。5. 进阶与验证密码帧防重放、错误锁定和连接状态监测5.1 给密码帧加流水号防同一帧被重复解析蓝牙SPP是透传链路只要手机还在连接状态之前缓存在模块里的数据可能被重复发送。更实际的风险是密码帧在手机端被截听后在另一台设备上重放单纯6位固定密码没有抵抗能力。可行的改良在51单片机上就够用开锁帧变成#加4位流水号加6位密码单片机保存上一次合法帧的流水号新帧流水号必须比上一个记录值大才进入密码比对否则直接丢弃。// 帧格式#XXXXYYYYYY\r\nXXXX为流水号YYYYYY为6位密码 if (frame_ready rx_len 13) { // 146213字节 if (memcmp(rx_buf 5, password, 6) 0) { unsigned int seq (rx_buf[1]-0) * 1000 (rx_buf[2]-0) * 100 (rx_buf[3]-0) * 10 (rx_buf[4]-0); if (seq last_seq) { // 新序号才允许开锁 last_seq seq; RELAY_PIN 1; delay_ms(800); RELAY_PIN 0; } } }这里用十进制ASCII转整数的方式解析流水号简单直观。手机端每次生成新流水号后再次开锁必须递增否则会被单片机拒绝这就防止了同一帧被原样重放。5.2 连续错误锁定用定时器2计时不阻塞蓝牙接收前面解析串口时留下了error_cnt现在补上锁定逻辑。连续三次密码错误后要求90秒内不再响应任何开锁帧。这个过程必须用定时器2计时不能把delay_ms(90000)写进主循环否则蓝牙中断接收被阻塞锁定期结束后模块处于假死状态必须重新上电才恢复。// 定时器2中断每1ms进入一次 void Timer2_ISR(void) interrupt 5 { lock_countdown; // 累计计时 if (lock_countdown 90000) { // 达到90秒 lock_countdown 0; locked_out 0; // 解除锁定状态 } }锁定期内即使收到正确密码也不执行比对而是直接丢弃。锁定提示用LED闪烁而不是串口回发因为此时串口仍被监视回发提示字符会把锁定状态暴露给对方对安全没有帮助。5.3 利用STATE引脚断开复位从根上解决失联残留HC-05的STATE引脚在断开连接时输出低电平连接成功后输出高电平。把STATE接到单片机的P3.2配置INT0为下降沿触发蓝牙断开瞬间就进入中断把继电器、密码缓冲和锁定状态全部复位。这个设计处理的实际场景是手机和模块连接时曾成功开锁继电器已释放但接收缓冲里残留了半截数据如果有人在新设备重放旧帧残留数据可能造成误判断。下降沿中断把缓冲清空并强制关闭继电器是这套系统固件层最后一道保险。IT0 1; // INT0下降沿触发 EX0 1; // 使能外部中断0 EA 1; // 总中断已在串口初始化时开启可重复置位 // 外部中断0服务函数 void INT0_ISR(void) interrupt 0 { RELAY_PIN 0; // 强制释放继电器 PASS_OK_LED 1; ERR_LED 1; rx_len 0; // 清空接收缓冲 frame_ready 0; locked_out 1; // 断开后回到锁定待机 }这段逻辑在两个常见平台上要特别注意移植到AT89C51时芯片内部没有EEPROMAT24C02必须保留移植到STC15W4K系列时虽然P3.0和P3.1仍可复用为串口但波特率初值不再由TH1决定要按BRT寄存器和波特率公式重新计算。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。