STM32+華為云IOT設(shè)計(jì)的動(dòng)態(tài)密碼鎖【玩轉(zhuǎn)華為云】

      網(wǎng)友投稿 633 2025-04-02

      1. 前言


      隨著人們生活水平的提高及科學(xué)技術(shù)的發(fā)展,個(gè)人信息保護(hù)顯得至關(guān)重要,設(shè)計(jì)了一款物聯(lián)網(wǎng)智能電子密碼鎖,以STM32單片機(jī)為主控制器,由觸摸矩陣鍵盤、ESP8266、步進(jìn)電機(jī)等模塊組成,具有遠(yuǎn)程控制、隨機(jī)密碼生成等功能。經(jīng)軟硬件測(cè)試,系統(tǒng)響應(yīng)迅速,靈敏度高,實(shí)時(shí)性好,系統(tǒng)識(shí)別準(zhǔn)確率高達(dá)99%,該系統(tǒng)運(yùn)行穩(wěn)定,安全可靠,功耗低及具有較好的擴(kuò)展性。

      當(dāng)前支持的開鎖方式:

      (1)支持手機(jī)APP遠(yuǎn)程開鎖。通過華為云物聯(lián)網(wǎng)平臺(tái)實(shí)現(xiàn)遠(yuǎn)程發(fā)送指令開鎖,設(shè)備上的ESP8266通過連接家里路由器,在連接華為云物聯(lián)網(wǎng)平臺(tái),可以在手機(jī)APP上對(duì)設(shè)備端的RTC時(shí)間進(jìn)行校準(zhǔn),設(shè)備唯一ID獲取,生成隨機(jī)開鎖密碼,可以點(diǎn)擊APP上的開鎖按鈕,通過物聯(lián)網(wǎng)平臺(tái)提供的API發(fā)送指令給STM32設(shè)備完成開鎖。

      (2)隨機(jī)密碼開鎖。手機(jī)APP與本地設(shè)備都采用時(shí)間、作為算法種子,采用算法生成開鎖密碼,每一串的密碼有效時(shí)間為一分鐘。查看手機(jī)APP上顯示的密碼之后,在本地設(shè)備上輸入完成密碼對(duì)比開鎖。

      2. 相關(guān)硬件

      2.1 WIFI模塊

      2.2 步進(jìn)電機(jī)模塊

      2.3 OLED顯示屏

      2.4 STM32開發(fā)板

      2.5 矩陣鍵盤模塊

      3. 手機(jī)APP設(shè)計(jì)

      3.1 開發(fā)環(huán)境介紹

      上位機(jī)軟件采用Qt框架設(shè)計(jì),Qt是一個(gè)跨平臺(tái)的C++圖形用戶界面應(yīng)用程序框架。Qt是一個(gè)1991年由Qt Company開發(fā)的跨平臺(tái)C++圖形用戶界面應(yīng)用程序開發(fā)框架。它既可以開發(fā)GUI程序,也可用于開發(fā)非GUI程序,比如控制臺(tái)工具和服務(wù)器。簡(jiǎn)單來說,QT可以很輕松的幫你做帶界面的軟件,甚至不需要你投入很大精力。

      QT官網(wǎng): https://www.qt.io/

      3.2 學(xué)習(xí)教程

      QT入門實(shí)戰(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

      軟件安裝時(shí)斷網(wǎng)安裝,否則會(huì)提示輸入賬戶。

      ** 安裝的時(shí)候,勾選一個(gè)mingw 32編譯器即可。**

      3.3 實(shí)現(xiàn)效果

      4. 創(chuàng)建云端設(shè)備

      4.1 創(chuàng)建設(shè)備

      登錄官網(wǎng): https://www.huaweicloud.com/

      直接搜索物聯(lián)網(wǎng),打開頁(yè)面。

      https://www.huaweicloud.com/product/iothub.html

      選擇設(shè)備接入:

      選擇免費(fèi)試用:

      在產(chǎn)品頁(yè)面,點(diǎn)擊右上角創(chuàng)建產(chǎn)品:

      填上產(chǎn)品信息:

      得到產(chǎn)品ID,保存好ID,點(diǎn)擊查看詳情:

      產(chǎn)品ID為:61b9ba3a2b2aa20288c1e7f1.

      點(diǎn)擊設(shè)備頁(yè)面,注冊(cè)設(shè)備:

      填充信息進(jìn)行注冊(cè):

      保存設(shè)備密匙和設(shè)備ID,點(diǎn)擊保存關(guān)閉會(huì)自動(dòng)下載文件保存,后面生成密碼和登錄賬號(hào)需要使用

      關(guān)閉后就看到創(chuàng)建好的設(shè)備了:

      點(diǎn)擊產(chǎn)品頁(yè)面,選擇剛才創(chuàng)建的產(chǎn)品:

      選擇自定義模型—?jiǎng)?chuàng)建數(shù)據(jù)模型服務(wù):

      選擇新增屬性,創(chuàng)建設(shè)備的屬性

      4.2 創(chuàng)建MQTT登錄賬號(hào)和密匙

      設(shè)備創(chuàng)建完成接來下生成MQTT登錄賬號(hào)、密匙,方便設(shè)備登錄云端平臺(tái)。

      官網(wǎng)工具地址: https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/

      打開剛才創(chuàng)建設(shè)備時(shí),下載的密匙文件,把內(nèi)容復(fù)制出來對(duì)應(yīng)的填進(jìn)去,生成即可。

      4.3 拼接主題訂閱與發(fā)布的格式

      官方文檔介紹: https://support.huaweicloud.com/devg-iothub/iot_01_2127.html

      在產(chǎn)品頁(yè)面可以,看到主題的全部格式:

      幫助文檔:https://support.huaweicloud.com/iothub/index.html

      總結(jié)的格式如下:

      格式: $oc/devices/{device_id}/sys/messages/down //訂閱主題: 平臺(tái)下發(fā)消息給設(shè)備 $oc/devices/61b9ba3a2b2aa20288c1e7f1_QQ1126626497_0_0_2021121510/sys/messages/down 格式: $oc/devices/{device_id}/sys/properties/report //設(shè)備上報(bào)數(shù)據(jù) $oc/devices/61b9ba3a2b2aa20288c1e7f1_QQ1126626497_0_0_2021121510/sys/properties/report 上屬性的數(shù)據(jù)格式: //上報(bào)的屬性消息 (一次可以上報(bào)多個(gè)屬性,在json里增加就行了) {"services": [{"service_id": "lock","properties":{"門鎖":1}}]}

      上面屬性里的服務(wù)ID和屬性里的名稱,在設(shè)備頁(yè)面,影子設(shè)備頁(yè)面查看。

      4.4 MQTT客戶端模擬設(shè)備登錄云端

      下面使用MQTT客戶端模擬設(shè)備登錄服務(wù)器測(cè)試,看設(shè)備創(chuàng)建的是否OK。

      STM32+華為云IOT設(shè)計(jì)的動(dòng)態(tài)密碼鎖【玩轉(zhuǎn)華為云】

      服務(wù)器的IP地址是: 121.36.42.100

      端口號(hào)是: 1883

      打開MQTT客戶端軟件,按照提示,輸入相關(guān)參數(shù)后,點(diǎn)擊連接,然后再點(diǎn)擊訂閱主題,發(fā)布主題即可:

      查看云端服務(wù)器的情況: 可以看到設(shè)備已經(jīng)在線了,并且收到上傳的數(shù)據(jù)。

      修改一下鎖的狀態(tài),上報(bào)屬性再查看:

      發(fā)現(xiàn)云端的狀態(tài)也已經(jīng)改變,現(xiàn)在設(shè)備上報(bào)已經(jīng)OK。

      接下來測(cè)試命令下發(fā),實(shí)現(xiàn)遠(yuǎn)程開鎖關(guān)鎖的功能:

      打開產(chǎn)品頁(yè)面,新增加命令:

      命令添加成功:

      在設(shè)備頁(yè)面,選擇同步命令下發(fā):

      點(diǎn)擊確定后,查看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ù),就可以完成多步進(jìn)電機(jī)的控制,完成開鎖關(guān)鎖。

      5. STM32設(shè)備端代碼設(shè)計(jì)

      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型號(hào)的驅(qū)動(dòng)芯片 SCL接PC11 SDA-OUT接PC10 電源接VCC-3.3 GND接GND 3. ULN2003控制28BYJ-48步進(jìn)電機(jī)接線: 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];//上報(bào)數(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); //超時(shí)時(shí)間20ms USART2_Init(9600);//串口-藍(lán)牙 TIMER2_Init(72,20000); //超時(shí)時(shí)間20ms USART3_Init(115200);//串口-WIFI TIMER3_Init(72,20000); //超時(shí)時(shí)間20ms USART1_Printf("正在初始化WIFI請(qǐng)稍等.\n"); if(ESP8266_Init()) { USART1_Printf("ESP8266硬件檢測(cè)錯(cuò)誤.\n"); } else { //非加密端口 USART1_Printf("WIFI:%d\n",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 隨機(jī)密碼生成

      #include #include #include #include #include char pwdcont[] = "0123456789abcdefghijklmn"; char* get_Password(int pwd_size) { int i; int random; char *Password = (char *)malloc(pwd_size + 1); //獲取時(shí)間種子 srand((unsigned)time(NULL)); for (i = 0; i < pwd_size; i++) { random = rand() % (strlen(pwdcont)); *(Password + i) = pwdcont[random]; } *(Password + i) = '\0'; return Password; } int main() { int random; char *Password; srand((unsigned)time(NULL)); for (int i = 0; i < 10; i++) { Sleep(100); random = rand() % 10;//密碼的長(zhǎng)度范圍 (6-63) printf("random = %d\n", random); Password = get_Password(random); printf("Password = %s\n", Password); } free(Password); return 0; }

      5.6 RTC實(shí)時(shí)時(shí)鐘代碼

      #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. 備份寄存器時(shí)鐘 RCC->APB1ENR|=1<<27; //備份時(shí)鐘接口 RCC->APB1ENR|=1<<28; //電源時(shí)鐘接口 PWR->CR|=1<<8; //允許寫入RTC和后備寄存器 //2. 配置RTC時(shí)鐘源 RCC->BDCR|=1<<0; //開啟外部32.768K時(shí)鐘 while(!(RCC->BDCR&1<<1)){} //等待時(shí)鐘就緒 RCC->BDCR&=~(0x3<<8); //清空時(shí)鐘配置 RCC->BDCR|=0x1<<8; //選擇外部32.768K時(shí)鐘 //3. 配置RTC核心寄存器 RCC->BDCR|=1<<15; //開啟RTC時(shí)鐘 while(!(RTC->CRL&1<<5)){} //判斷上一次寄存器是否寫完成 RTC->CRL|=1<<4; //進(jìn)入配置模式 RTC->PRLH=0; //預(yù)分頻高位 RTC->PRLL=0x7FFF; //32767 預(yù)分頻低位 RTC->CNTH=0; //計(jì)數(shù)器高位 RTC->CNTL=0; //計(jì)數(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)先級(jí) 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)時(shí)間 RTC_GetWeek(SecCnt); // printf("%d-%d-%d %d:%d:%d week:%d\n",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("鬧鐘時(shí)間到達(dá)!....\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í)間 函數(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;iAPB1ENR|=1<<27; //備份時(shí)鐘接口 RCC->APB1ENR|=1<<28; //電源時(shí)鐘接口 PWR->CR|=1<<8; //允許寫入RTC和后備寄存器 while(!(RTC->CRL&1<<5)){} //判斷上一次寄存器是否寫完成 RTC->CRL|=1<<4; //進(jìn)入配置模式 RTC->CNTH=SecCnt>>16; //計(jì)數(shù)器高位 RTC->CNTL=SecCnt&0xFFFF; //計(jì)數(shù)器低位 RTC->CRL&=~(1<<4);//退出配置模式 while(!(RTC->CRL&1<<5)){} //判斷上一次寄存器是否寫完成 } /* 函數(shù)功能: 獲取RTC時(shí)間 函數(shù)參數(shù): u32 sec 秒單位時(shí)間 */ void RTC_GetTime(u32 sec) { u32 i; rtc_clock.year=2017; //基準(zhǔn)年份 /*1. 計(jì)算當(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. 計(jì)算當(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. 計(jì)算當(dāng)前的天數(shù)*/ rtc_clock.day=1; while(1) { if(sec>=24*60*60) { sec-=24*60*60; rtc_clock.day++; } else break; } /*4. 計(jì)算當(dāng)前的小時(shí)*/ rtc_clock.hour=0; while(1) { if(sec>=60*60) { sec-=60*60; rtc_clock.hour++; } else break; } /*5. 計(jì)算當(dāng)前的分鐘*/ rtc_clock.min=0; while(1) { if(sec>=60) { sec-=60; rtc_clock.min++; } else break; } /*6. 計(jì)算當(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); //將秒單位時(shí)間轉(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)時(shí)間轉(zhuǎn)為秒單位時(shí)間 思路: 全程加法 時(shí)間基準(zhǔn)點(diǎn): 1970年1月1日0時(shí)0分0秒 返回值: 得到的秒單位時(shí)間 */ unsigned int TimeToSec(int year, int mon, int mdeay, int hour, int min) { int i; int sec_cnt = 0; //記錄秒單位的時(shí)間 /*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)換小時(shí)*/ sec_cnt += hour * 60 * 60; /*5. 轉(zhuǎn)換分鐘*/ sec_cnt += min * 60; return sec_cnt; }

      云端實(shí)踐 IoT Qt

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:倉(cāng)儲(chǔ)管理系統(tǒng)有什么作用?
      下一篇:如何在wps表格中快速查找重復(fù)項(xiàng)
      相關(guān)文章
      亚洲午夜视频在线观看| 香蕉蕉亚亚洲aav综合| 亚洲国语在线视频手机在线| 色婷婷亚洲十月十月色天| 亚洲va久久久噜噜噜久久 | 亚洲精品国产福利在线观看| 亚洲av无码成人黄网站在线观看 | 亚洲免费闲人蜜桃| 亚洲人成在久久综合网站| 久久久婷婷五月亚洲97号色| 久久精品a亚洲国产v高清不卡| 亚洲第一成年男人的天堂| 亚洲成AV人片在线播放无码| 亚洲阿v天堂在线| 亚洲AV色香蕉一区二区| 亚洲AV人无码激艳猛片| 亚洲电影中文字幕| 亚洲黄色免费网址| 亚洲视频国产精品| 亚洲成A∨人片在线观看无码| 亚洲最大的视频网站| 亚洲三级中文字幕| 亚洲 日韩 色 图网站| 亚洲中文字幕一区精品自拍| 亚洲欧美aⅴ在线资源| 亚洲AV无码一区二区大桥未久| 人人狠狠综合久久亚洲高清| 亚洲国产精品一区二区九九 | 亚洲人AV永久一区二区三区久久| 亚洲精品无码专区久久同性男| 精品亚洲一区二区三区在线观看 | 亚洲伊人久久大香线蕉AV| 亚洲av无码偷拍在线观看| 亚洲av午夜成人片精品电影 | 亚洲AV成人噜噜无码网站| 亚洲色在线无码国产精品不卡| 亚洲AV无码一区二区三区网址 | 亚洲国产小视频精品久久久三级 | 亚洲综合日韩久久成人AV| 亚洲av无码乱码国产精品fc2| 久久亚洲日韩看片无码|