1. 前言
隨機密碼鎖是一種常見的電子鎖系統(tǒng),它使用數(shù)字密碼代替?zhèn)鹘y(tǒng)的物理鑰匙來進行身份驗證和門鎖控制。該項目基于STM32微控制器實現(xiàn)一個安全可靠的隨機密碼鎖系統(tǒng)。
傳統(tǒng)的機械鎖存在一些安全和便捷性的問題。鑰匙可能會丟失、被盜或者被復(fù)制,這會給用戶帶來安全風(fēng)險。而且,當(dāng)需要為多個用戶提供訪問權(quán)限時,分發(fā)和管理多個物理鑰匙變得復(fù)雜。為了解決這些問題,隨機密碼鎖系統(tǒng)應(yīng)運而生。
隨機密碼鎖系統(tǒng)基于STM32微控制器實現(xiàn),具備以下特點:
- 高安全性:系統(tǒng)使用數(shù)字密碼進行身份驗證,密碼是隨機生成的,并且每次開鎖時會自動更換密碼。這樣可以提高安全性,防止密碼被破解或預(yù)測。
- 多用戶支持:系統(tǒng)可以為多個用戶分配不同的訪問權(quán)限和密碼。管理員可以輕松添加、刪除或修改用戶信息,并設(shè)置其對應(yīng)權(quán)限。
- 多種開鎖方式:除了密碼輸入外,系統(tǒng)還可以支持其他開鎖方式,如指紋識別、刷卡等,增加了便捷性和靈活性。
- 電池供電:系統(tǒng)采用低功耗設(shè)計,可以通過電池供電,避免線路布線的限制,適用于不同的門鎖應(yīng)用場景。
- 報警功能:系統(tǒng)能夠檢測異常操作或入侵,并觸發(fā)報警,提高安全性。
當(dāng)前支持的開鎖方式:
(1)支持手機APP遠程開鎖。通過華為云物聯(lián)網(wǎng)平臺實現(xiàn)遠程發(fā)送指令開鎖,設(shè)備上的ESP8266通過連接家里路由器,在連接華為云物聯(lián)網(wǎng)平臺,可以在手機APP上對設(shè)備端的RTC時間進行校準(zhǔn),設(shè)備唯一ID獲取,生成隨機開鎖密碼,可以點擊APP上的開鎖按鈕,通過物聯(lián)網(wǎng)平臺提供的API發(fā)送指令給STM32設(shè)備完成開鎖。
(2)隨機密碼開鎖。手機APP與本地設(shè)備都采用時間、作為算法種子,采用算法生成開鎖密碼,每一串的密碼有效時間為一分鐘。查看手機APP上顯示的密碼之后,在本地設(shè)備上輸入完成密碼對比開鎖。
2. 相關(guān)硬件
2.1 WIFI模塊
2.2 步進電機模塊
2.3 OLED顯示屏
2.4 STM32開發(fā)板
2.5 矩陣鍵盤模塊
3. 手機APP設(shè)計
3.1 開發(fā)環(huán)境介紹
上位機軟件采用Qt框架設(shè)計,Qt是一個跨平臺的C++圖形用戶界面應(yīng)用程序框架。Qt是一個1991年由Qt Company開發(fā)的跨平臺C++圖形用戶界面應(yīng)用程序開發(fā)框架。它既可以開發(fā)GUI程序,也可用于開發(fā)非GUI程序,比如控制臺工具和服務(wù)器。簡單來說,QT可以很輕松的幫你做帶界面的軟件,甚至不需要你投入很大精力。
QT官網(wǎng):https://www.qt.io/
3.2 學(xué)習(xí)教程
QT入門實戰(zhàn)專欄: https://blog.csdn.net/xiaolong1126626497/category_11400392.html
QT5環(huán)境安裝教程:https://xiaolong.blog.csdn.net/article/details/120654599
下載QT5.12.6下載地址: https://download.qt.io/archive/qt/5.12/5.12.6/
打開鏈接后選擇:
qt-opensource-windows-x86-5.12.6.exe 13-Nov-2019 07:28 3.7G Details
軟件安裝時斷網(wǎng)安裝,否則會提示輸入賬戶。
安裝的時候,勾選一個mingw 32編譯器即可。
3.3 實現(xiàn)效果
4. 創(chuàng)建云端設(shè)備
4.1 創(chuàng)建設(shè)備
登錄官網(wǎng): https://www.huaweicloud.com/
直接搜索物聯(lián)網(wǎng),打開頁面。
https://www.huaweicloud.com/product/iothub.html
選擇設(shè)備接入:
選擇免費試用:
在產(chǎn)品頁面,點擊右上角創(chuàng)建產(chǎn)品:
填上產(chǎn)品信息:
得到產(chǎn)品ID,保存好ID,點擊查看詳情:
產(chǎn)品ID為:61b9ba3a2b2aa20288c1e7f1.
點擊設(shè)備頁面,注冊設(shè)備:
填充信息進行注冊:
保存設(shè)備密匙和設(shè)備ID,點擊保存關(guān)閉會自動下載文件保存,后面生成密碼和登錄賬號需要使用
關(guān)閉后就看到創(chuàng)建好的設(shè)備了:
點擊產(chǎn)品頁面,選擇剛才創(chuàng)建的產(chǎn)品:
選擇自定義模型---創(chuàng)建數(shù)據(jù)模型服務(wù):
選擇新增屬性,創(chuàng)建設(shè)備的屬性
4.2 創(chuàng)建MQTT登錄賬號和密匙
設(shè)備創(chuàng)建完成接來下生成MQTT登錄賬號、密匙,方便設(shè)備登錄云端平臺。
官網(wǎng)工具地址: https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/
打開剛才創(chuàng)建設(shè)備時,下載的密匙文件,把內(nèi)容復(fù)制出來對應(yīng)的填進去,生成即可。
4.3 拼接主題訂閱與發(fā)布的格式
官方文檔介紹: https://support.huaweicloud.com/devg-iothub/iot_01_2127.html
在產(chǎn)品頁面可以,看到主題的全部格式:
幫助文檔:https://support.huaweicloud.com/iothub/index.html
總結(jié)的格式如下:
格式: $oc/devices/{device_id}/sys/messages/down
//訂閱主題: 平臺下發(fā)消息給設(shè)備
$oc/devices/61b9ba3a2b2aa20288c1e7f1_QQ1126626497_0_0_2021121510/sys/messages/down
?
?
格式: $oc/devices/{device_id}/sys/properties/report
//設(shè)備上報數(shù)據(jù)
$oc/devices/61b9ba3a2b2aa20288c1e7f1_QQ1126626497_0_0_2021121510/sys/properties/report
?
上屬性的數(shù)據(jù)格式:
//上報的屬性消息 (一次可以上報多個屬性,在json里增加就行了)
{"services": [{"service_id": "lock","properties":{"門鎖":1}}]}
上面屬性里的服務(wù)ID和屬性里的名稱,在設(shè)備頁面,影子設(shè)備頁面查看。
4.4 MQTT客戶端模擬設(shè)備登錄云端
下面使用MQTT客戶端模擬設(shè)備登錄服務(wù)器測試,看設(shè)備創(chuàng)建的是否OK。
服務(wù)器的IP地址是: 121.36.42.100
端口號是: 1883
打開MQTT客戶端軟件,按照提示,輸入相關(guān)參數(shù)后,點擊連接,然后再點擊訂閱主題,發(fā)布主題即可:
查看云端服務(wù)器的情況: 可以看到設(shè)備已經(jīng)在線了,并且收到上傳的數(shù)據(jù)。
修改一下鎖的狀態(tài),上報屬性再查看:
發(fā)現(xiàn)云端的狀態(tài)也已經(jīng)改變,現(xiàn)在設(shè)備上報已經(jīng)OK。
接下來測試命令下發(fā),實現(xiàn)遠程開鎖關(guān)鎖的功能:
打開產(chǎn)品頁面,新增加命令:
命令添加成功:
在設(shè)備頁面,選擇同步命令下發(fā):
點擊確定后,查看MQTT客戶端,發(fā)現(xiàn)已經(jīng)收到數(shù)據(jù)了:
$oc/devices/61b9ba3a2b2aa20288c1e7f1_QQ1126626497/sys/commands/request_id=88e2626f-290d-405e-962d-51554445a8fd{"paras":{"lock":1},"service_id":"lock","command_name":"lock"}
設(shè)備端解析收到的數(shù)據(jù),就可以完成多步進電機的控制,完成開鎖關(guān)鎖。
5. STM32設(shè)備端代碼設(shè)計
STM32連接華為云IOT的工程代碼Get: https://download.csdn.net/download/xiaolong1126626497/81993720
5.1 硬件相關(guān)原理圖
5.2 程序下載配置
5.3 硬件接線
1. 板載ESP8266串口WIFI模塊與STM32的串口3相連接。
PB10--RXD 模塊接收腳
PB11--TXD 模塊發(fā)送腳
PB8---CH-PD---懸空
PB9---RST---懸空
GND---GND 地
VCC---VCC 電源(3.3V~5.0V)
?
?
2. 觸摸按鍵使用TTP229型號的驅(qū)動芯片
SCL接PC11
SDA-OUT接PC10
電源接VCC-3.3
GND接GND
?
3. ULN2003控制28BYJ-48步進電機接線:
?
ULN2003接線:
IN4: PC9 d
IN3: PC8 c
IN2: PC7 b
IN1: PC6 a
+ : 5V
- : GND
?
4. OLED顯示屏
D0----SCK-----PB14
D1----MOSI----PB13
RES—復(fù)位(低電平有效)—PB12
DC---數(shù)據(jù)和命令控制管腳—PB1
CS---片選引腳-----PA7
?
?
5. 板載按鍵
KEY1---PA0
KEY2---PC13
?
?
6.板載LED燈
LED1---PB5
LED2---PB0
LED3---PB1
?
7. 板載蜂鳴器
BEEP---PA8
5.4 服務(wù)器連接核心代碼
//華為物聯(lián)網(wǎng)服務(wù)器的設(shè)備信息
#define MQTT_ClientID "61b9ba3a2b2aa20288c1e7f1_QQ1126626497_0_0_2021121510"
#define MQTT_UserName "61b9ba3a2b2aa20288c1e7f1_QQ1126626497"
#define MQTT_PassWord "385ce91dfe7da5b7431868d5d87e7998163c493344040935d5a00024d6324242"
?
//訂閱與發(fā)布的主題
#define SET_TOPIC "$oc/devices/61b9ba3a2b2aa20288c1e7f1_QQ1126626497_0_0_2021121510/sys/messages/down" //訂閱
#define POST_TOPIC "$oc/devices/61b9ba3a2b2aa20288c1e7f1_QQ1126626497_0_0_2021121510/sys/properties/report" //發(fā)布
?
char mqtt_message[200];//上報數(shù)據(jù)緩存區(qū)
?
int main()
{
u32 time_cnt=0;
u32 i;
u8 key;
LED_Init();
BEEP_Init();
KEY_Init();
USART1_Init(115200);
TIMER1_Init(72,20000); //超時時間20ms
USART2_Init(9600);//串口-藍牙
TIMER2_Init(72,20000); //超時時間20ms
USART3_Init(115200);//串口-WIFI
TIMER3_Init(72,20000); //超時時間20ms
USART1_Printf("正在初始化WIFI請稍等.n");
if(ESP8266_Init())
{
USART1_Printf("ESP8266硬件檢測錯誤.n");
}
else
{
//非加密端口
USART1_Printf("WIFI:%dn",ESP8266_STA_TCP_Client_Mode("CMCC-Cqvn","99pu58cb","121.36.42.100",1883,1));
}
//2. MQTT協(xié)議初始化
MQTT_Init();
//3. 連接華為服務(wù)器
while(MQTT_Connect(MQTT_ClientID,MQTT_UserName,MQTT_PassWord))
{
USART1_Printf("服務(wù)器連接失敗,正在重試...n");
delay_ms(500);
}
USART1_Printf("服務(wù)器連接成功.n");
//3. 訂閱主題
if(MQTT_SubscribeTopic(SET_TOPIC,0,1))
{
USART1_Printf("主題訂閱失敗.n");
}
else
{
USART1_Printf("主題訂閱成功.n");
}
..................
..................
...................
}
5.5 隨機密碼生成
#include < stdio.h >
#include < time.h >
#include < stdlib.h >
#include < string.h >
#include < windows.h >
?
char pwdcont[] = "0123456789abcdefghijklmn";
?
char* get_Password(int pwd_size)
{
int i;
int random;
char *Password = (char *)malloc(pwd_size + 1);
?
//獲取時間種子
srand((unsigned)time(NULL));
?
for (i = 0; i < pwd_size; i++)
{
random = rand() % (strlen(pwdcont));
*(Password + i) = pwdcont[random];
}
?
*(Password + i) = '?';
return Password;
}
?
int main()
{
int random;
char *Password;
srand((unsigned)time(NULL));
?
for (int i = 0; i < 10; i++)
{
Sleep(100);
random = rand() % 10;//密碼的長度范圍 (6-63)
printf("random = %dn", random);
Password = get_Password(random);
printf("Password = %sn", Password);
}
free(Password);
return 0;
}
5.6 RTC實時時鐘代碼
#include "rtc.h"
?
//定義RTC標(biāo)準(zhǔn)結(jié)構(gòu)體
struct RTC_CLOCK rtc_clock;
?
/*
函數(shù)功能: RTC初始化函數(shù)
*/
void RTC_Init(void)
{
if(BKP- >DR1!=0xAB) //表示RTC第一次初始化
{
//1. 備份寄存器時鐘
RCC- >APB1ENR|=1< < 27; //備份時鐘接口
RCC- >APB1ENR|=1< < 28; //電源時鐘接口
PWR- >CR|=1< < 8; //允許寫入RTC和后備寄存器
//2. 配置RTC時鐘源
RCC- >BDCR|=1< < 0; //開啟外部32.768K時鐘
while(!(RCC- >BDCR&1< < 1)){} //等待時鐘就緒
RCC- >BDCR&=~(0x3< < 8); //清空時鐘配置
RCC- >BDCR|=0x1< < 8; //選擇外部32.768K時鐘
//3. 配置RTC核心寄存器
RCC- >BDCR|=1< < 15; //開啟RTC時鐘
while(!(RTC- >CRL&1< < 5)){} //判斷上一次寄存器是否寫完成
RTC- >CRL|=1< < 4; //進入配置模式
RTC- >PRLH=0; //預(yù)分頻高位
RTC- >PRLL=0x7FFF; //32767 預(yù)分頻低位
RTC- >CNTH=0; //計數(shù)器高位
RTC- >CNTL=0; //計數(shù)器低位
RTC- >ALRH=0; //鬧鐘寄存器高位
RTC- >ALRL=60; //鬧鐘寄存器低位
RTC- >CRL&=~(1< < 4);//退出配置模式
while(!(RTC- >CRL&1< < 5)){} //判斷上一次寄存器是否寫完成
BKP- >DR1=0xAB; //表示配置成功了
}
?
RTC- >CRH|=1< < 0; //秒中斷
RTC- >CRH|=1< < 1; //鬧鐘中斷
STM32_SetPriority(RTC_IRQn,2,2); //優(yōu)先級
RTC_SetTime(2022,4,9,0,36,1);
}
?
extern void Update_FrameShow(void);
/*
函數(shù)功能: RTC鬧鐘中斷服務(wù)函數(shù)
*/
void RTC_IRQHandler(void)
{
u32 SecCnt;
if(RTC- >CRL&1< < 0)
{
SecCnt=RTC- >CNTH< < 16;//獲取高位
SecCnt|=RTC- >CNTL; //獲取低位
RTC_GetTime(SecCnt); //轉(zhuǎn)換標(biāo)準(zhǔn)時間
RTC_GetWeek(SecCnt);
// printf("%d-%d-%d %d:%d:%d week:%dn",rtc_clock.year,rtc_clock.mon,rtc_clock.day,rtc_clock.hour,rtc_clock.min,rtc_clock.sec,rtc_clock.week);
Update_FrameShow(); //更新顯示
RTC- >CRL&=~(1< < 0); //清除秒中斷標(biāo)志位
}
if(RTC- >CRL&1< < 1)
{
// printf("鬧鐘時間到達!....n");
// BEEP=1;
// DelayMs(500);
// BEEP=0;
RTC- >CRL&=~(1< < 1); //清除鬧鐘中斷標(biāo)志位
}
}
?
?
?
//閏年的月份
static int mon_r[12]={31,29,31,30,31,30,31,31,30,31,30,31};
//平年的月份
static int mon_p[12]={31,28,31,30,31,30,31,31,30,31,30,31};
?
?
/*
函數(shù)功能: 設(shè)置RTC時間
函數(shù)形參:
u32 year; 2018
u32 mon; 8
u32 day;
u32 hour;
u32 min;
u32 sec;
*/
void RTC_SetTime(u32 year,u32 mon,u32 day,u32 hour,u32 min,u32 sec)
{
u32 i;
u32 SecCnt=0; //總秒數(shù)
/*1. 累加已經(jīng)過去的年份*/
for(i=2017;i< year;i++) //基準(zhǔn)年份:20170101000000
{
if(RTC_GetYearState(i))
{
SecCnt+=366*24*60*60; //閏年一年的秒數(shù)
}
else
{
SecCnt+=365*24*60*60; //平年一年的秒數(shù)
}
}
/*2. 累加過去的月份*/
for(i=0;i< mon-1;i++)
{
if(RTC_GetYearState(year))
{
SecCnt+=mon_r[i]*24*60*60; //閏年一月的秒數(shù)
}
else
{
SecCnt+=mon_p[i]*24*60*60; //平年一月的秒數(shù)
}
}
/*3. 累加過去的天數(shù)*/
SecCnt+=(day-1)*24*60*60;
/*4. 累加過去小時*/
SecCnt+=hour*60*60;
/*5. 累加過去的分鐘*/
SecCnt+=min*60;
/*6. 累加過去的秒*/
SecCnt+=sec;
/*7. 設(shè)置RTC時間*/
RCC- >APB1ENR|=1< < 27; //備份時鐘接口
RCC- >APB1ENR|=1< < 28; //電源時鐘接口
PWR- >CR|=1< < 8; //允許寫入RTC和后備寄存器
while(!(RTC- >CRL&1< < 5)){} //判斷上一次寄存器是否寫完成
RTC- >CRL|=1< < 4; //進入配置模式
RTC- >CNTH=SecCnt > >16; //計數(shù)器高位
RTC- >CNTL=SecCnt&0xFFFF; //計數(shù)器低位
RTC- >CRL&=~(1< < 4);//退出配置模式
while(!(RTC- >CRL&1< < 5)){} //判斷上一次寄存器是否寫完成
}
?
?
/*
函數(shù)功能: 獲取RTC時間
函數(shù)參數(shù): u32 sec 秒單位時間
*/
void RTC_GetTime(u32 sec)
{
u32 i;
rtc_clock.year=2017; //基準(zhǔn)年份
/*1. 計算當(dāng)前的年份*/
while(1)
{
if(RTC_GetYearState(rtc_clock.year))
{
if(sec >=366*24*60*60) //夠一年
{
sec-=366*24*60*60;
rtc_clock.year++;
}
else break;
}
else
{
if(sec >=365*24*60*60) //夠一年
{
sec-=365*24*60*60;
rtc_clock.year++;
}
else break;
}
}
/*2. 計算當(dāng)前的月份*/
rtc_clock.mon=1;
for(i=0;i< 12;i++)
{
if(RTC_GetYearState(rtc_clock.year))
{
if(sec >=mon_r[i]*24*60*60)
{
sec-=mon_r[i]*24*60*60;
rtc_clock.mon++;
}
else break;
}
else
{
if(sec >=mon_p[i]*24*60*60)
{
sec-=mon_p[i]*24*60*60;
rtc_clock.mon++;
}
else break;
}
}
/*3. 計算當(dāng)前的天數(shù)*/
rtc_clock.day=1;
while(1)
{
if(sec >=24*60*60)
{
sec-=24*60*60;
rtc_clock.day++;
}
else break;
}
/*4. 計算當(dāng)前的小時*/
rtc_clock.hour=0;
while(1)
{
if(sec >=60*60)
{
sec-=60*60;
rtc_clock.hour++;
}
else break;
}
/*5. 計算當(dāng)前的分鐘*/
rtc_clock.min=0;
while(1)
{
if(sec >=60)
{
sec-=60;
rtc_clock.min++;
}
else break;
}
/*6. 計算當(dāng)前的秒*/
rtc_clock.sec=sec;
}
?
?
/*
函數(shù)功能: 判斷年份是否是平年、閏年
返回值 : 0表示平年 1表示閏年
*/
u8 RTC_GetYearState(u32 year)
{
if((year%4==0&&year%100!=0)||year%400==0)
{
return 1;
}
return 0;
}
?
?
/*
函數(shù)功能: 獲取星期
*/
void RTC_GetWeek(u32 sec)
{
u32 day1=sec/(60*60*24); //將秒單位時間轉(zhuǎn)為天數(shù)
switch(day1%7)
{
case 0:
rtc_clock.week=0;
break;
case 1:
rtc_clock.week=1;
break;
case 2:
rtc_clock.week=2;
break;
case 3:
rtc_clock.week=3;
break;
case 4:
rtc_clock.week=4;
break;
case 5:
rtc_clock.week=5;
break;
case 6:
rtc_clock.week=6;
break;
}
}
?
/*
將標(biāo)準(zhǔn)時間轉(zhuǎn)為秒單位時間
思路: 全程加法
時間基準(zhǔn)點: 1970年1月1日0時0分0秒
返回值: 得到的秒單位時間
*/
unsigned int TimeToSec(int year, int mon, int mdeay, int hour, int min)
{
int i;
int sec_cnt = 0; //記錄秒單位的時間
/*1. 轉(zhuǎn)換年*/
for (i = 1970; i < year; i++)
{
if (RTC_GetYearState(i)) //閏年
{
sec_cnt += 366 * 24 * 60 * 60;
}
else
{
sec_cnt += 365 * 24 * 60 * 60;
}
}
?
/*2. 轉(zhuǎn)換月*/
for (i = 0; i < mon - 1; i++)
{
if (RTC_GetYearState(year)) //閏年
{
sec_cnt += mon_r[i] * 24 * 60 * 60;
}
else
{
sec_cnt += mon_p[i] * 24 * 60 * 60;
}
}
?
/*3. 轉(zhuǎn)換天數(shù)*/
sec_cnt += (mdeay - 1) * 24 * 60 * 60;
?
/*4. 轉(zhuǎn)換小時*/
sec_cnt += hour * 60 * 60;
?
/*5. 轉(zhuǎn)換分鐘*/
sec_cnt += min * 60;
return sec_cnt;
}
?
審核編輯 黃宇
-
微控制器
+關(guān)注
關(guān)注
48文章
7651瀏覽量
152120 -
物聯(lián)網(wǎng)
+關(guān)注
關(guān)注
2914文章
44938瀏覽量
377074 -
STM32
+關(guān)注
關(guān)注
2272文章
10924瀏覽量
357592 -
密碼鎖
+關(guān)注
關(guān)注
6文章
249瀏覽量
35117 -
步進電機
+關(guān)注
關(guān)注
151文章
3120瀏覽量
147848 -
開發(fā)板
+關(guān)注
關(guān)注
25文章
5121瀏覽量
98209 -
Qt
+關(guān)注
關(guān)注
1文章
308瀏覽量
38068 -
IOT
+關(guān)注
關(guān)注
187文章
4230瀏覽量
197621 -
華為云
+關(guān)注
關(guān)注
3文章
2691瀏覽量
17588
發(fā)布評論請先 登錄
相關(guān)推薦
基于單片機的紅外遙控密碼鎖的設(shè)計與實現(xiàn)
![基于單片機的紅外遙控<b class='flag-5'>密碼鎖</b>的設(shè)計與<b class='flag-5'>實現(xiàn)</b>](https://file.elecfans.com/web2/M00/48/89/pYYBAGKhtAyATOuiAAAfVQIV6s4994.jpg)
電子密碼鎖的設(shè)計
![電子<b class='flag-5'>密碼鎖</b>的設(shè)計](https://file1.elecfans.com//web2/M00/A5/93/wKgZomUMORKAPEizAACNHdfNGT0452.jpg)
微電腦密碼鎖設(shè)計
![微電腦<b class='flag-5'>密碼鎖</b>設(shè)計](https://file.elecfans.com/web2/M00/49/CD/pYYBAGKhvGKAAH1_AAAdU5X0pSI972.png)
指紋密碼鎖的優(yōu)點和缺點
基于STM32的指紋密碼鎖的電路方案設(shè)計
基于ATMEGA128的密碼鎖
![基于ATMEGA128的<b class='flag-5'>密碼鎖</b>](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
評論