基于NodeMCU的物聯網窗簾控制系統設計

最終效果

基于NodeMCU的物聯網窗簾控制系統設計

項目介紹

該項目是“物聯網實驗室監測控制系統設計(仿智能家居)”項目中的“家電控制設計”中的“窗簾控制”子項目,最前者還包括“物聯網設計”、“環境監測設計”、“門禁系統設計計”和“小程序設計”等內容。本文只介紹“窗簾控制”部分。

項目功能實現的大致思路為:當單片機接收到MQTT服務器傳來的窗簾新位置時,驅動步進電機轉動,使窗簾移動到指定位置。

硬件設計

接線

NodeMCU

ULN2003

28BYJ-48

電源

OUT1

1

OUT2

2

OUT3

3

OUT4

4

D4

INT1

D3

INT2

D2

INT3

D1

INT4

+

5

5V

GND

-

GND

成本

NodeMCU

28BYJ-48模組

27.9

8.53

其中共需36.5元左右來購買該項目所需的模塊。此外還需1根數據線、若干杜邦線、能提供5~12V中間任意電壓的電源。

機械模型搭建

為使演示更貼合實際,本系統制作了一個窗簾模型,模型圖見下文。

模型左上方的黑色絕緣膠帶表示窗簾的移動端,位于左側時表示窗簾閉合(遮住窗戶);位于右側時表示窗簾打開(露出窗戶)。在模型中,步進電機帶動齒輪旋轉,從而帶動傳送帶轉動,進而實現窗簾的移動。通過控制步進電機的旋轉,便可將窗簾移動至指定位置。該模型中的兩齒輪中心距為800mm,主動輪的周長約為74.61mm(比兩齒輪中心距的10%略小),步進電機旋轉10圈可將窗簾移動到另一側(窗簾行程留有冗余)。

器件圖

正面俯視圖
正面右視圖
正面左視圖
正面右部分局部后視圖
反面俯視圖

器件尺寸

未完待續

皮帶:未完待續

28BYJ-48型步進電機的軸:未完待續

木板:未完待續

軟件設計

本次的開發環境為Arduino IDE,開發板型號為NodeMCU 0.9 (ESP-12 Module)。

本系統軟件部分的流程如下圖所示。在初始化之后,等待小程序下發窗簾位置,據此驅動步進電機旋轉。

連接WiFi以及接收MQTT服務器傳來的消息,可參考:利用ESP-01S中繼實現STM32F103C8T6與MQTT服務器的串口雙向通信_mqtt和stm32開發板通信-CSDN博客

解析JSON數據,可參考:Arduino中解析JSON數據-CSDN博客

驅動28BYJ-48型步進電機轉動,可參考:NodeMCU驅動28BYJ-48型步進電機(Arduino)-CSDN博客

//選擇NodeMCU 0.9 (ESP-12 module)
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <Arduino.h>// 設置wifi接入信息和MQTT服務器
const char* wifiname = "DOILMSBOIOT";
const char* password = "doilmsboiot";
const char* mqttServer = "broker.emqx.io";bool receive_message_flag = 0;  //1表示收到信息但還未處理,0表示未收到信息或已處理WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);// 待解析的json文件,所需空間:13~15個字節,正好初始值為最多的字節;若初始化時空間不足,收到信息后無法賦值
String json = "{\"curtain\":000}";// 創建DynamicJsonDocument對象
const size_t capacity = JSON_OBJECT_SIZE(1) + 32 ;   //1表示待解析的JSON對象中有1對數據,32為解析過程中需要的額外空間,可在此網站計算 https://arduinojson.org/v6/assistant/#/step1
DynamicJsonDocument doc(capacity);int curtain_position ;   // 解析后的窗簾位置
int curtain_now_position =0 ;   // 窗簾現在的位置void setup() 
{Serial.begin(9600);    // 啟動串口通訊WiFi.mode(WIFI_STA);    //設置ESP8266工作模式為無線終端模式connectWifi();    // 連接WiFimqttClient.setServer(mqttServer, 1883);   // 設置MQTT服務器和端口號mqttClient.setCallback(receiveCallback);    // 設置MQTT訂閱回調函數connectMQTTserver();    // 連接MQTT服務器stepmotor_initial();  //步進電機初始化
}void loop() 
{if (mqttClient.connected())   // 如果開發板成功連接服務器{ mqttClient.loop();          // 處理信息(收到信息后的回調函數)以及心跳} else                          // 如果開發板未能成功連接服務器{                      connectMQTTserver();        // 則嘗試連接服務器并訂閱主題}if (receive_message_flag == 1) //收到信息但還未處理{     deserializeJson(doc, json);  // 反序列化數據// 解析收到的數據信息curtain_position = doc["curtain"].as<int>();if(curtain_position - curtain_now_position > 0){Serial.print("電機要轉到的位置:");Serial.println(curtain_position);Serial.print("電機現在的位置:");Serial.println(curtain_now_position);int cycle = (int)(curtain_position - curtain_now_position)/10;Serial.println("開始轉動");Serial.println(cycle);for(int i=0; i < cycle; i++){clockwise_turn_one_circle();curtain_now_position += 10;Serial.print("轉過的圈數:");Serial.println(i);} Serial.println("結束轉動");Serial.print("電機現在的位置:");Serial.println(curtain_now_position);Serial.println("");}if(curtain_position - curtain_now_position < 0){Serial.print("電機要轉到的位置:");Serial.println(curtain_position);Serial.print("電機現在的位置:");Serial.println(curtain_now_position);int cycle = (int)(curtain_now_position - curtain_position)/10;Serial.println("開始轉動");Serial.println(-cycle);for(int i=0; i < cycle; i++){anti_clockwise_turn_one_circle();curtain_now_position -= 10;Serial.print("轉過的圈數:");Serial.println(i);} Serial.println("結束轉動");Serial.print("電機現在的位置:");Serial.println(curtain_now_position);Serial.println("");}receive_message_flag = 0;    //已處理接收到的信息}}// 連接MQTT服務器并訂閱主題
void connectMQTTserver()
{// 根據ESP8266的MAC地址生成客戶端ID(避免與其它ESP8266的客戶端ID重名)String clientId = "esp8266-" + WiFi.macAddress();if (mqttClient.connect(clientId.c_str()))     //如果成功連接MQTT服務器{ Serial.print("MQTT Server Has Connected. ");Serial.print("Server Address: ");Serial.println(mqttServer);Serial.print("ClientId: ");Serial.println(clientId);subscribeTopic(); // 訂閱指定主題} else {Serial.print("MQTT Server Connect Failed. Client State:");Serial.println(mqttClient.state());delay(3000);}   
}// 收到信息后的回調函數
void receiveCallback(char* topic, byte* payload, unsigned int length) 
{Serial.print("Message with the topic of [ ");Serial.print(topic);Serial.println(" ] has been received.");Serial.print("Content: ");for (int i = 0; i < length; i++) {Serial.print((char)payload[i]);json[i] = (char)payload[i];   //將收到的信息賦給json,以便后續解析和發射信號}Serial.println("");for (int i = length; i < 15; i++)  //清除掉多余字符{json[i] = '\0';}receive_message_flag = 1;   //表示收到信息但還未處理Serial.print("Message Length (Bytes) :  ");Serial.println(length);Serial.println(" ");
}// 訂閱指定主題
void subscribeTopic()
{String topicString = "deviceControl3/curtain";   // 訂閱主題的名稱char subTopic[topicString.length() + 1];  strcpy(subTopic, topicString.c_str());if(mqttClient.subscribe(subTopic))    //如果成功訂閱主題{Serial.print("Subscrib Topic: ");Serial.println(subTopic);Serial.println("");} else {Serial.print("Subscribe Fail...");}  
}// ESP8266連接wifi
void connectWifi()  
{WiFi.begin(wifiname, password);Serial.println("Connecting to WiFi");while (WiFi.status() != WL_CONNECTED) //等待WiFi連接,當wifi未連接時,持續輸出".";成功連接后輸出連接成功信息{delay(1000);Serial.print(".");}Serial.println("");Serial.println("WiFi Connected!");  Serial.println(""); 
}void stepmotor_initial()
{pinMode(D1, OUTPUT);pinMode(D2, OUTPUT); pinMode(D3, OUTPUT);pinMode(D4, OUTPUT);
}void clockwise_turn_one_circle()
{for(int i=0;i<512;i++){digitalWrite(D1, HIGH);digitalWrite(D2, LOW);digitalWrite(D3, LOW);digitalWrite(D4, LOW);delay(1);digitalWrite(D1, HIGH);digitalWrite(D2, HIGH);digitalWrite(D3, LOW);digitalWrite(D4, LOW);delay(1);digitalWrite(D1, LOW);digitalWrite(D2, HIGH);digitalWrite(D3, LOW);digitalWrite(D4, LOW);delay(1);digitalWrite(D1, LOW);digitalWrite(D2, HIGH);digitalWrite(D3, HIGH);digitalWrite(D4, LOW);delay(1);digitalWrite(D1, LOW);digitalWrite(D2, LOW);digitalWrite(D3, HIGH);digitalWrite(D4, LOW);delay(1);digitalWrite(D1, LOW);digitalWrite(D2, LOW);digitalWrite(D3, HIGH);digitalWrite(D4, HIGH);delay(1);digitalWrite(D1, LOW);digitalWrite(D2, LOW);digitalWrite(D3, LOW);digitalWrite(D4, HIGH);delay(1);digitalWrite(D1, HIGH);digitalWrite(D2, LOW);digitalWrite(D3, LOW);digitalWrite(D4, HIGH);delay(1);}
}void anti_clockwise_turn_one_circle()
{for(int i=0;i<512;i++){digitalWrite(D1, LOW);digitalWrite(D2, LOW);digitalWrite(D3, LOW);digitalWrite(D4, HIGH);delay(1);digitalWrite(D1, LOW);digitalWrite(D2, LOW);digitalWrite(D3, HIGH);digitalWrite(D4, HIGH);delay(1);digitalWrite(D1, LOW);digitalWrite(D2, LOW);digitalWrite(D3, HIGH);digitalWrite(D4, LOW);delay(1);digitalWrite(D1, LOW);digitalWrite(D2, HIGH);digitalWrite(D3, HIGH);digitalWrite(D4, LOW);delay(1);digitalWrite(D1, LOW);digitalWrite(D2, HIGH);digitalWrite(D3, LOW);digitalWrite(D4, LOW);delay(1);digitalWrite(D1, HIGH);digitalWrite(D2, HIGH);digitalWrite(D3, LOW);digitalWrite(D4, LOW);delay(1);digitalWrite(D1, HIGH);digitalWrite(D2, LOW);digitalWrite(D3, LOW);digitalWrite(D4, LOW);delay(1);digitalWrite(D1, HIGH);digitalWrite(D2, LOW);digitalWrite(D3, LOW);digitalWrite(D4, HIGH);delay(1);}
}

不足之處

  1. 電機轉速太慢
  2. 缺少獲取窗簾當前位置的功能,無法處理手動和打滑。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/64180.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/64180.shtml
英文地址,請注明出處:http://en.pswp.cn/web/64180.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

有沒有免費提取音頻的軟件?音頻編輯軟件介紹!

出于工作和生活娛樂等原因&#xff0c;有時候我們需要把音頻單獨提取出來&#xff08;比如歌曲伴奏、人聲清唱等、樂器獨奏等&#xff09;。要提取音頻必須借助音頻處理軟件&#xff0c;那么有沒有免費提取音頻的軟件呢&#xff1f;下面我們將為大家介紹幾款免費軟件&#xff0…

WPF自定義窗口 輸入驗證不生效

WPF自定義窗口 輸入驗證不生效 WPF ValidationRule 不生效 WPF ValidationRule 不生效 解決方案&#xff1a;在WindowStyle的Template中添加AdornerDecorator標簽。 <Style x:Key"WindowStyle1" TargetType"{x:Type Window}"><Setter Property&…

【保姆式】python調用api通過機器人發送文件到飛書指定群聊

當前飛書webhook機器人還不支持發送文件類型的群消息&#xff0c;它目前僅支持文本&#xff0c;富文本&#xff0c;卡片等文字類型的數據。 我們可以申請創建一個機器人應用來實現群發送文件消息。 創建飛書應用 創建飛書應用、配置權限、添加機器人 來到飛書開發者后臺 創建…

MySQL-存儲過程(頭歌數據庫實驗題)

&#xff08;學校數據庫課程的頭歌平臺實驗題&#xff0c;根據自己理解編寫&#xff0c;希望對正在學的人有啟發作用和借鑒幫助&#xff0c;不喜勿噴&#xff0c;有錯請聯系改正&#xff09; 實驗 存儲過程&#xff1a;輸入1 任務描述&#xff1a; 本關任務&#xff1a;編寫…

GitLab 服務變更提醒:中國大陸、澳門和香港用戶停止提供服務(GitLab 服務停止)

目錄 前言 一. 變更詳情 1. 停止服務區域 2. 郵件通知 3. 新的服務提供商 4. 關鍵日期 5. 行動建議 二. 遷移指南 三. 注意事項 四. 相關推薦 前言 近期&#xff0c;許多位于中國大陸、澳門和香港的 GitLab 用戶收到了一封來自 GitLab 官方的重要通知。根據這封郵件…

mysql基礎快速入門

通用語法及分類 DDL: 數據定義語言&#xff0c;用來定義數據庫對象&#xff08;數據庫、表、字段&#xff09;DML: 數據操作語言&#xff0c;用來對數據庫表中的數據進行增刪改DQL: 數據查詢語言&#xff0c;用來查詢數據庫中表的記錄DCL: 數據控制語言&#xff0c;用來創建數…

Python文件讀寫在“簡易記事本”項目中的應用

Python文件讀寫在“簡易記事本”項目中的應用 文件讀寫是“簡易記事本”項目實現數據持久化的關鍵部分。在本節中&#xff0c;我們將逐步拆解記事本的功能&#xff0c;詳細講解與文件讀寫相關的代碼&#xff0c;并結合實際操作幫助讀者更好地理解文件操作的核心知識點。 功能…

【Agent】AutoGen Studio2.0開源框架-UI層環境安裝+詳細操作教程(從0到1帶跑通智能體AutoGen Studio)

&#x1f4a5; 歡迎來到我的博客&#xff01;很高興能在這里與您相遇&#xff01; 首頁&#xff1a;GPT-千鑫 – 熱愛AI、熱愛Python的天選打工人&#xff0c;活到老學到老&#xff01;&#xff01;&#xff01;導航 - 人工智能系列&#xff1a;包含 OpenAI API Key教程, 50個…

三層交換機配置

一&#xff0c;三層交換 概念&#xff1a;三層交換技術就是&#xff1a;二層交換技術三層轉發技術(路由器功能)。它解決了局域網中網段劃分之后&#xff0c;網段中子網必須依賴路由器進行管理的局面&#xff0c;解決了傳統路由器低速&#xff0c;復雜所造成的網絡瓶頸問題。 …

js單例模式

單例模式是一種常見的設計模式&#xff0c;在JavaScript中也有廣泛應用&#xff0c;以下是關于它的詳細介紹&#xff1a; 定義 單例模式是一種創建型設計模式&#xff0c;它確保一個類只有一個實例&#xff0c;并提供一個全局訪問點來訪問該實例。在JavaScript中&#xff0c;…

【Golang 面試題】每日 3 題(六)

?個人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;專欄地址&#xff1a;http://t.csdnimg.cn/UWz06 &#x1f4da;專欄簡介&#xff1a;在這個專欄中&#xff0c;我將會分享 Golang 面試中常見的面試題給大家~ ??如果有收獲的話&#xff0c;歡迎點贊&#x1f44d;收藏…

SQL Server數據庫多主模式解決方案

SQL Server 本身并不直接支持多主模式(Multi-Master Replication),即多個數據庫實例可以同時進行寫操作,并且這些更改會自動同步到其他實例。不過,SQL Server 提供了多種高可用性和復制解決方案,可以實現類似多主模式的功能。以下是幾種常見的方法: 1. Always On 可用性…

連鎖餐飲行業數據可視化分析方案

引言 隨著連鎖餐飲行業的迅速發展&#xff0c;市場競爭日益激烈。企業需要更加精準地把握運營狀況、消費者需求和市場趨勢&#xff0c;以制定科學合理的決策&#xff0c;提升競爭力和盈利能力。可視化數據分析可以幫助連鎖餐飲企業整合多源數據&#xff0c;通過直觀、動態的可…

Zookeeper JavaAPI操作(Curator API常用操作)

構建項目 zk版本&#xff1a;3.5.7&#xff0c;引入4.0.0的curator版本&#xff0c;Curator依賴的版本只能比zookeeper依賴的版本高。 Curator簡單介紹 Curator是Netflix公司開源的一套zookeeper客戶端框架&#xff0c;解決了很多Zookeeper客戶端非常底層的細節開發工作&…

可搜索的下拉選擇框:filterable屬性詳解

在前端開發中&#xff0c;下拉選擇框&#xff08;Dropdown Select&#xff09;是一個常見的UI組件&#xff0c;它允許用戶從一組預定義的選項中選擇一個或多個值。然而&#xff0c;當選項數量較多時&#xff0c;手動查找特定的選項可能會變得繁瑣。為了解決這個問題&#xff0c…

精選9個自動化任務的Python腳本精選

大家好&#xff0c;我是老鄧&#xff0c;今天我們來一起學習如何用Python進行一些常見的自動化操作&#xff0c;涉及文件處理、網絡交互等實用技巧。即使你沒有任何Python基礎也沒關系&#xff0c;我會用最通俗易懂的語言來講解。 1. 對目錄中的文件進行排序 import osdef so…

滑動窗口 + 算法復習

維護一個滿足條件的窗口大小&#xff0c;然后進行雙指針移動 1.最長子串 題目鏈接&#xff1a;1.最長子串 - 藍橋云課 #include<bits/stdc.h> #define int long long using namespace std; string s; int k; signed main() {int max_len0,left0;cin>>s>>k;…

PDF書籍《手寫調用鏈監控APM系統-Java版》第9章 插件與鏈路的結合:Mysql插件實現

本人閱讀了 Skywalking 的大部分核心代碼&#xff0c;也了解了相關的文獻&#xff0c;對此深有感悟&#xff0c;特此借助巨人的思想自己手動用JAVA語言實現了一個 “調用鏈監控APM” 系統。本書采用邊講解實現原理邊編寫代碼的方式&#xff0c;看本書時一定要跟著敲代碼。 作者…

關于Vue的子組件改變父組件傳來的值

一、組件直接傳值 大家都知道父子組件傳值的方案&#xff0c;有以下幾個&#xff0c;不再詳細敖述 Props&#xff1a;父組件向子組件傳遞數據 $emit&#xff1a;子組件通過自定義事件向父組件傳遞數據 .sync修飾符&#xff1a;一個方便且強大的工具&#xff0c;可以簡化父子組…

Flink的Watermark水位線詳解

一、Flink的時間語義 Flink有如下三種時間語義&#xff1a; Flink的三種時間語義-CSDN博客 在實際應用中&#xff0c;一般會采用事件時間語義。而正如前面所說的&#xff0c;事件時間語義需要等窗口的數據全部到齊了&#xff0c;才能進行窗口計算。那么&#xff0c;什么時候數…