基于STM32F103设计的智能门锁(支持多种开锁解锁方式)

529 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第25天,点击查看活动详情

这是基于STM32设计的智能锁模型,支持多种开锁方式,支持门禁卡刷卡开锁、蓝牙自动开锁、微信小程序开锁、关锁、使用RC522射频卡读卡器、按键开锁、关锁。

一、环境介绍

编程软件: keil5

主控MCU: STM32F103ZET6

射频卡读写器: RFID-RC522

步进电机: 28BYJ4 4相5线

蓝牙: ATK-HC05

WIFI: ATK-ESP8266

物联网云平台: 采用腾讯云物联网平台,直接支持微信小程序和手机独立APP控制

二、功能介绍

这是基于STM32设计的智能锁模型,支持多种开锁方式,详情如下:

1. 门禁卡刷卡开锁: 使用RC522射频卡读卡器,读取IC卡卡号和内部数据,验证身份,开锁。

2. 蓝牙自动开锁: 业主的手机蓝牙在范围内,自动开锁(通过连接蓝牙地址确认业主身份),范围是通过蓝牙断开与连接上为准。

3. 微信小程序开锁、关锁: 通过ESP8266连接腾讯云物联网平台,业主可以通过微信小程序“腾讯连连” 进行远程开锁和关锁。

4. 按键开锁、关锁: 可以通过开发板上的按键进行开锁和关锁(模拟物理钥匙而已)

开锁和关锁使用步进电机正转一圈、反转一圈模拟。

img

img

三、使用的相关硬件介绍

3.1 STM32F103ZET6系统板

img

3.2 HC05蓝牙模块

img

3.3 WIFI模块

img

3.4 RFID-RC522模块

img

3.5 步进电机

img

四、腾讯物联网平台

img

img

img

img

五、设备核心源码

 #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");
             }   
         }
      }
 }