基于 STM32F103 设计的智能门锁 (支持多种开锁解锁方式)
作者:DS小龙哥
- 2022 年 8 月 20 日 湖北
本文字数:5867 字
阅读完需:约 19 分钟
这是基于 STM32 设计的智能锁模型,支持多种开锁方式,支持门禁卡刷卡开锁、蓝牙自动开锁、微信小程序开锁、关锁、使用 RC522 射频卡读卡器、按键开锁、关锁。
一、环境介绍
编程软件: keil5
主控 MCU: STM32F103ZET6
射频卡读写器: RFID-RC522
步进电机: 28BYJ4 4 相 5 线
蓝牙: ATK-HC05
WIFI: ATK-ESP8266
物联网云平台: 采用腾讯云物联网平台,直接支持微信小程序和手机独立 APP 控制
二、功能介绍
这是基于 STM32 设计的智能锁模型,支持多种开锁方式,详情如下:
1. 门禁卡刷卡开锁: 使用 RC522 射频卡读卡器,读取 IC 卡卡号和内部数据,验证身份,开锁。
2. 蓝牙自动开锁: 业主的手机蓝牙在范围内,自动开锁(通过连接蓝牙地址确认业主身份),范围是通过蓝牙断开与连接上为准。
3. 微信小程序开锁、关锁: 通过 ESP8266 连接腾讯云物联网平台,业主可以通过微信小程序“腾讯连连” 进行远程开锁和关锁。
4. 按键开锁、关锁: 可以通过开发板上的按键进行开锁和关锁(模拟物理钥匙而已)
开锁和关锁使用步进电机正转一圈、反转一圈模拟。
三、使用的相关硬件介绍
3.1 STM32F103ZET6 系统板
3.2 HC05 蓝牙模块
3.3 WIFI 模块
3.4 RFID-RC522 模块
3.5 步进电机
四、腾讯物联网平台
五、设备核心源码
#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
#include "key.h"
#include "usart.h"
#include <string.h>
#include "timer.h"
#include "esp8266.h"
#include "mqtt.h"
#include "hc05_Bluetooth.h"
#include "RFID_RC522.h"
#include "motor.h"
/*
硬件连接方式:
ATK-HC-05串口蓝牙模块与STM32的串口2相连接。
PA1--LED 配对状态输出; 配对成功输出高电平,未配对则输出低电平。
PA4---KEY 用于进入 AT 状态;高电平有效(悬空默认为低电平)。
PA2--RXD 模块接收脚
PA3--TXD 模块发送脚
GND---GND 地
VCC---VCC 电源(3.3V~5.0V)
ATK-ESP8266串口WIFI模块与STM32的串口3相连接。
PB10--RXD 模块接收脚
PB11--TXD 模块发送脚
GND---GND 地
VCC---VCC 电源(3.3V~5.0V)
RC522射频模块外部的接口:
*1--SDA <----->PB5--片选脚
*2--SCK <----->PB4--时钟线
*3--MOSI<----->PA12--输出
*4--MISO<----->PA11--输入
*5--悬空
*6--GND <----->GND
*7--RST <----->PA8--复位脚
*8--VCC <----->VCC
ULN2003控制28BYJ-48步进电机接线:
ULN2003接线:
IN4: PC9 d
IN3: PC8 c
IN2: PC7 b
IN1: PC6 a
+ : 5V
- : GND
*/
//腾讯物联网服务器的设备信息
#define MQTT_ClientID "3XM7FNOG4Llock"
#define MQTT_UserName "3XM7FNOG4Llock;12010126;W5WOU;1624006004"
#define MQTT_PassWord "209f8dfc3079a54540aeb4263e99be24c5b0212141d8067e6348036383535941;hmacsha256"
//订阅与发布的主题
#define SET_TOPIC "$thing/down/property/3XM7FNOG4L/lock" //订阅
#define POST_TOPIC "$thing/up/property/3XM7FNOG4L/lock" //发布
#define CONNECT_WIFI "CMCC-Cqvn" //将要连接的路由器名称 --不要出现中文、空格等特殊字符
#define CONNECT_PASS "99pu58cb" //将要连接的路由器密码
#define CONNECT_SERVER_IP "106.55.124.154" //服务器IP地址
#define CONNECT_SERVER_PORT 1883 //服务器端口号
char mqtt_message[200];//上报数据缓存区
unsigned char SN[4]; //存放读出的卡号
unsigned char CheckSN[4]={71,151,114,179}; //用于验证的卡号--业主的卡号用于开锁
char SendBuff[10];
/*
函数功能: 打印卡号
*/
void print_info(unsigned char *p,int cnt)
{
int i;
for(i=0;i<cnt;i++)
{
printf("%d ",p[i]);
}
printf("\r\n");
}
/*
函数功能: 读卡号--电子标签的卡号
返回值: 1成功 0失败
*/
int ReadCardNumber(void)
{
unsigned char CT[2];//卡类型
u8 status=1;
status=RC522_PcdRequest(PICC_REQIDL ,CT);//(寻卡模式,卡类型),成功返回0
if(status==MI_OK)//寻卡成功
{
status=MI_ERR;
status=RC522_PcdAnticoll(SN); //防冲撞,成功返回0,SN是读到卡号的地址
printf("卡类型:");
print_info(CT,2);//打印类型
printf("卡号:");
print_info(SN,4);//打印卡号
return 1;
}
return 0;
}
int main()
{
u8 esp8266_state=0;
u8 key;
u8 i;
u32 time_cnt=0;
u8 ble_connect_flag=0;
u8 Motor=0; //电机状态
LED_Init();
KEY_Init();
USART1_Init(115200);
RC522_Init(); //RC522
Moto_Init(); //步进电机初始化
USART3_Init(115200);//串口-WIFI
TIMER3_Init(72,20000); //超时时间20ms
USART1_Printf("正在初始化WIFI请稍等.\r\n");
for(i=0;i<5;i++)
{
if(ESP8266_Init()==0)
{
esp8266_state=1;
break;
}
else
{
esp8266_state=0;
USART1_Printf("ESP8266硬件检测错误.\n");
}
}
if(esp8266_state)
{
printf("准备连接服务器....\r\n");
//非加密端口
USART1_Printf("WIFI:%d\n",ESP8266_STA_TCP_Client_Mode(CONNECT_WIFI,CONNECT_PASS,CONNECT_SERVER_IP,CONNECT_SERVER_PORT,1));
//2. MQTT协议初始化
MQTT_Init();
//3. 连接服务器
for(i=0;i<5;i++)
{
if(MQTT_Connect(MQTT_ClientID,MQTT_UserName,MQTT_PassWord)==0)
{
esp8266_state=1;
break;
}
esp8266_state=0;
USART1_Printf("服务器连接失败,正在重试...\n");
delay_ms(500);
}
USART1_Printf("服务器连接成功.\n");
//3. 订阅主题
if(MQTT_SubscribeTopic(SET_TOPIC,0,1))
{
USART1_Printf("主题订阅失败.\n");
}
else
{
USART1_Printf("主题订阅成功.\n");
}
}
/*4. 初始化HC05串口蓝牙*/
printf("蓝牙正在初始化.........\r\n");
USART2_RX_FLAG=0;
while(HC05_Bluetooth_Init()){}
/*设置当前蓝牙为从机模式---这里设置从机的代码只需要设置一次,后面就可以屏蔽掉了*/
// HC05_Bluetooth_SetCmd((u8*)"AT+ROLE=0\r\n"); //设置为从机模式
// if(HC05_Bluetooth_GetRoleStatus()==0)printf("当前蓝牙处于从机状态!\r\n");
// else if(HC05_Bluetooth_GetRoleStatus()==1)printf("当前蓝牙处于主机状态!\r\n");
// HC05_Bluetooth_SetCmd((u8*)"AT+RESET\r\n"); //复位ATK-HC05模块
DelayMs(1000); //等待蓝牙模块稳定
/*2. 查询蓝牙主从状态*/
if(HC05_Bluetooth_GetRoleStatus()==0)printf("2 当前蓝牙处于从机状态!\r\n");
else if(HC05_Bluetooth_GetRoleStatus()==1)printf("2 当前蓝牙处于主机状态!\r\n");
else printf("2 当前蓝牙主从状态查询失败!\r\n");
/*3. 查看蓝牙连接状态*/
if(HC05_LED)printf("3 当前蓝牙连接成功!\r\n");
else printf("3 当前蓝牙未连接!\r\n");
// /*4. 设置蓝牙的名称*/
// if(HC05_Bluetooth_SetCmd((u8*)"AT+NAME=WBYQ_HC-05\r\n"))printf("4 蓝牙名称设置失败!\r\n");
// else printf("4 蓝牙名称设置为 WBYQ_HC-05! \r\n");
// /*5. 设置蓝牙配对密码*/
// if(HC05_Bluetooth_SetCmd((u8*)"AT+PSWD=1234\r\n"))printf("5 蓝牙配对密码设置失败!\r\n"); //密码必须是4位
// else printf("5 蓝牙配对密码设置为 1234 \r\n");
while(1)
{
//按键可以测试开锁和关锁
key=KEY_Scan(0);
if(key==1)
{
LED1=0; //亮灯--表示开锁
time_cnt=0;
Motorcw_ring(1,300); //电机正转1圈
Motor=1;
//更新微信小程序
sprintf(mqtt_message,"{"method":"report","clientToken":"123","params":{"Motor":%d}}",Motor);
MQTT_PublishData(POST_TOPIC,mqtt_message,0);
USART1_Printf("更新门锁状态:开锁\r\n");
}
else if(key==2)
{
LED1=1; //灭灯--表示关锁
time_cnt=0;
Motorccw_ring(1,300); //电机反转1圈
Motor=0;
//更新微信小程序
sprintf(mqtt_message,"{"method":"report","clientToken":"123","params":{"Motor":%d}}",Motor);
MQTT_PublishData(POST_TOPIC,mqtt_message,0);
USART1_Printf("更新门锁状态:关锁\r\n");
}
DelayMs(10);
time_cnt++;
if(time_cnt>=50)
{
time_cnt=0;
LED2=!LED2;
}
//微信小程序开锁方式: 接收WIFI返回的数据
if(USART3_RX_FLAG)
{
USART3_RX_BUFFER[USART3_RX_CNT]='\0';
printf("UART3收到数据.....\r\n");
//向串口打印微信小程序返回的数据
for(i=0;i<USART3_RX_CNT;i++)
{
USART1_Printf("%c",USART3_RX_BUFFER[i]);
}
//如果是下发了属性,判断是开锁还是关锁
if(USART3_RX_CNT>5)
{
//使用字符串查找函数
//开锁
if(strstr((char*)&USART3_RX_BUFFER[5],""Motor":1"))
{
LED1=0; //亮灯--表示开锁
//开锁
//执行开锁代码--电机正转
Motorcw_ring(1,300); //电机正转1圈
Motor=1;
}
//关锁
else if(strstr((char*)&USART3_RX_BUFFER[5],""Motor":0"))
{
LED1=1; //灭灯--表示关锁
//关锁
//执行开锁代码--电机反转
Motorccw_ring(1,300); //电机反转1圈
Motor=0;
}
}
USART3_RX_CNT=0;
USART3_RX_FLAG=0;
}
//RC522开锁方式: 读取IC卡号
if(ReadCardNumber())
{
sprintf(SendBuff,"%x%x%x%x\r\n",SN[0],SN[1],SN[2],SN[3]);
//比较卡号是否是业主的卡号,决定是否需要开锁
int i=0;
for(i=0;i<4;i++)
{
if(CheckSN[i]!=SN[i])break;
}
//如果是业主,就开锁
if(i==4)
{
LED1=0; //亮灯--表示开锁
//更新微信小程序
sprintf(mqtt_message,"{"method":"report","clientToken":"123","params":{"Motor":%d}}",Motor);
MQTT_PublishData(POST_TOPIC,mqtt_message,0);
USART1_Printf("更新门锁状态:开锁\r\n");
Motor=1;
//执行开锁代码--电机正转
Motorcw_ring(1,300); //电机正转1圈
}
}
if(USART2_RX_FLAG)
{
USART2_RX_BUFFER[USART2_RX_CNT]='\0';
USART1_Printf("蓝牙:%s\r\n",USART2_RX_BUFFER);
USART2_RX_CNT=0;
USART2_RX_FLAG=0;
}
//蓝牙解锁方式: 离开范围就自动关锁 连接上就自动解锁
// 区分业主身份方式: 使用蓝牙的配对密码区分.
if(HC05_LED==1 && Motor==0) //关锁状态才需要开始
{
LED1=0; //亮灯--表示开锁
ble_connect_flag=1; //表示蓝牙已经连接过
printf("蓝牙已经连接.\r\n");
Motor=1;
//更新微信小程序
sprintf(mqtt_message,"{"method":"report","clientToken":"123","params":{"Motor":%d}}",Motor);
MQTT_PublishData(POST_TOPIC,mqtt_message,0);
USART1_Printf("更新门锁状态:开锁\r\n");
//开锁
//执行开锁代码--电机正转
Motorcw_ring(1,300); //电机正转1圈
}
else
{
//之前蓝牙连接过
if(ble_connect_flag)
{
ble_connect_flag=0; //清除标记
LED1=1; //关灯--表示上锁
printf("蓝牙已经断开.\r\n");
Motor=0;
//关锁
//执行开锁代码--电机反转
Motorccw_ring(1,300); //电机反转1圈
//更新微信小程序
sprintf(mqtt_message,"{"method":"report","clientToken":"123","params":{"Motor":%d}}",Motor);
MQTT_PublishData(POST_TOPIC,mqtt_message,0);
USART1_Printf("更新门锁状态:关锁\r\n");
}
}
}
}
复制代码
划线
评论
复制
发布于: 刚刚阅读数: 4
版权声明: 本文为 InfoQ 作者【DS小龙哥】的原创文章。
原文链接:【http://xie.infoq.cn/article/a1ca18335cc70e84b041b1499】。文章转载请联系作者。
DS小龙哥
关注
之所以觉得累,是因为说的比做的多。 2022.01.06 加入
熟悉C/C++、51单片机、STM32、Linux应用开发、Linux驱动开发、音视频开发、QT开发. 目前已经完成的项目涉及音视频、物联网、智能家居、工业控制领域
评论