摘要:本文基於STM32微控制器設計了一款基於物聯網的智慧魚缸。
本文分享自華為雲社群《基於STM32+華為雲IOT設計的物聯網魚缸【玩轉華為雲】》,作者: DS小龍哥 。
1. 前言
為了緩解學習、生活、工作帶來的壓力,提升生活品質,許多人喜歡在家中、辦公室等場所養魚。為節省魚友時間、勞力、增加養魚樂趣;為此,本文基於STM32微控制器設計了一款基於物聯網的智慧魚缸。該魚缸可以實現水溫檢測、水質檢測、自動或手動換水、氛圍燈燈光變換和自動或手動餵食等功能為一體的控制系統,魚缸通過ESP8266連線華為雲IOT物聯網平臺,並通過應用側介面開發了上位機APP實現遠端對魚缸引數檢測檢視,並能遠端控制。
從功能上分析,需要用到的硬體如下:
(1)STM32系統板
(2)水溫溫度檢測感測器: 測量水溫
(3)水質檢測感測器: 測量水中的溶解性固體含量,反應水質。
(4)步進電機: 作為魚飼料投食器
(5)RGB氛圍燈: 採用RGB 3色燈,給魚缸照明。
(6)抽水電動馬達: 用來給魚缸充氧,換水,加水等。
(7)ESP8266 WIFI:設定串列埠協議的WIFI,內建了TCP/IP協議棧,完善的AT指令,通過簡單的指令就可以聯網通訊,但是當前採用的ESP8266沒有燒寫第三方韌體,採用原本的原滋原味的官方韌體,沒有內建MQTT協議,程式碼裡連線華為雲物聯網平臺需要使用MQTT協議,所以在STM32程式碼裡通過MQTT協議文件的欄位結構自己實現了MQTT協議,在通過ESP8266的TCP相關的AT指令完成資料傳送接收,完成與華為雲IOT平臺互動。
水產養殖水質常規檢測的感測器有哪些?水產養殖水質常規檢測的感測器有水質ph感測器、溶解氧感測器和溫度感測器。
(1)水質ph感測器:
ph感測器是高智慧化線上連續監測儀,由感測器和二次表兩部分組成。可配三複合或兩複合電極,以滿足各種使用場所。配上純水和超純水電極,可適用於電導率小於3μs/cm的水質(如化學補給水、飽和蒸氣、凝結水等)的pH值測量。
(2)溶解氧感測器:
氧氣的消耗量與存在的氧含量成正比,而氧是通過可透膜擴散進來的。感測器與專門設計的監測溶氧的測量電路或電腦資料採集系統相連。 溶解氧感測器能夠空氣校準,一般校準所需時間較長,在使用後要注意保養。如果在養殖水中工作時間過長,就必須定期地清洗膜,對其進行額外保養。
在很多水產養殖中,每天測幾次溶氧就可以瞭解溶氧情況。對池塘和許多水槽養殖系統。溶氧水平不會變化很快,池塘一般每天檢測2~3次。 對於較高密度養殖系統,增氧泵故障發生可能不到1h就會造成魚蝦等大面積死亡。這些密度高的養殖系統要求有足夠多的裝備或每小時多次自動測量溶氧。
(3)溫度感測器:
溫度感測器有多種結構,包括熱電偶、電阻溫度感測器和熱敏電阻。熱電偶技術成熟,應用領域廣,貨源充足。選擇熱電偶必須滿足溫度範圍要求,且其材料與環境相容。 電阻溫度感測器(RTDs)的原理為金屬的電阻隨溫度的改變而改變。大多電阻溫度感測器(RTDs)由鉑、鎳或鎳合金製成,其線性度比熱電偶好,熱切更加穩定,但容易破碎。 熱敏電阻是電阻與溫度具有負相關關係的半導體。熱敏電阻比RTD和熱電偶更靈敏,也更容易破碎,不能承受大的溫差,但這一點在水產養殖中不成問題。
2. 硬體選型
2.1 STM32開發板
主控CPU採用STM32F103RCT6,這顆晶片包括48 KB SRAM、256 KB Flash、2個基本定時器、4個通用定時器、2個高階定時器、51個通用IO口、5個串列埠、2個DMA控制器、3個SPI、2個I2C、1個USB、1個CAN、3個12位ADC、1個12位DAC、1個SDIO介面,晶片屬於大容量型別,配置較高,整體符合硬體選型設計。當前選擇的這款開發板自帶了一個1.4寸的TFT-LCD彩屏,可以顯示當前感測器資料以及一些執行狀態資訊。
2.2 杜邦線
2.3 PCB板
2.4 步進電機
2.5 抽水馬達
2.6 水溫檢測感測器
測溫採用DS18B20,DS18B20是常用的數字溫度感測器,其輸出的是數字訊號,具有體積小,硬體開銷低,抗干擾能力強,精度高的特點。
DS18B20數字溫度感測器接線方便,封裝成後可應用於多種場合,如管道式,螺紋式,磁鐵吸附式,不鏽鋼封裝式,型號多種多樣,有LTM8877,LTM8874等等。
主要根據應用場合的不同而改變其外觀。封裝後的DS18B20可用於電纜溝測溫,高爐水迴圈測溫,鍋爐測溫,機房測溫,農業大棚測溫,潔淨室測溫,彈藥庫測溫等各種非極限溫度場合。耐磨耐碰,體積小,使用方便,封裝形式多樣,適用於各種狹小空間裝置數字測溫和控制領域。
2.7 水質檢測感測器
TDS (Total Dissolved Solids)、中文名總溶解固體、又稱溶解性固體、又稱溶解性固體總量、表明1升水腫容有多少毫克溶解性固體、一般來說、TDS值越高、表示水中含有溶解物越多、水就越不潔淨、雖然在特定情況下TDS並不能有效反映水質的情況、但作為一種可快速檢測的引數、TDS目前還可以作為有效的在水質情況反映引數來作為參考。常用的TDS檢測裝置為TDS筆、雖然價格低廉、簡單易用、但不能把資料傳給控制系統、做長時間的線上監測、並做水質狀況分析、使用專門的儀器、雖然能傳資料、精度也高、但價格很貴、為此這款TDS感測器模組、即插即用、使用簡單方便、測量用的激勵源採用交流訊號、可有效防止探頭極化、延長探頭壽命的同時、也增加了輸出訊號的穩定性、TDS探頭為防水探頭、可長期侵入水中測量、該產品可以應用於生活用水、水培等領域的水質檢測、有了這個感測器、可輕鬆DIY–套TDS檢測儀了、輕鬆檢測水的潔淨程度。
2.8 ESP8266
■模組採用串列埠(LVTTL) 與MCU (或其他串列埠裝置) 通訊,內建TCP/IP協議棧,能夠實現串列埠與WIFI之間的轉換
■模組支援LVTTL串列埠, 相容3…3V和5V微控制器系統
■模組支援串 口轉WIFI STA、串列埠轉AP和WIFI STA+WIFI AP的模式,從而快速構建串列埠-WIFI資料傳輸方案
■模組小巧(19mm*29mm), 通過6個2.54mm間距排針與外部連線
3. 華為雲IOT產品與裝置建立
3.1 建立產品
連結:https://www.huaweicloud.com/product/iothub.html
點選右上角視窗建立產品。
填入產品資訊。
接下來建立模型檔案:
建立服務。
建立屬性。根據魚缸裝置的感測器屬性來新增屬性。
(1)LED氛圍燈
(2)抽水電機
(3)水質感測器
(4)水溫溫度計
3.2 建立裝置
地址: https://console.huaweicloud.com/iotdm/?region=cn-north-4#/dm-portal/device/all-device
點選右上角建立裝置。
按照裝置的情況進行填寫資訊。
裝置建立後儲存資訊:
{ "device_id": "62cd6da66b9813541d510f64_dev1", "secret": "12345678" }
建立成功。
3.3 裝置模擬除錯
為了測試裝置通訊的過程,在裝置頁面點選除錯。
選擇裝置除錯:
3.4 MQTT三元組
為了方便能夠以真實的裝置登陸伺服器進行測試,接下來需要先了解MQTT協議登入需要的引數如何獲取,得到這些引數才可以接著進行下一步。
MQTT(Message Queuing Telemetry Transport)是一個基於客戶端-伺服器的訊息釋出/訂閱傳輸協議,主要應用於計算能力有限,且工作在低頻寬、不可靠的網路的遠端感測器和控制裝置,適合長連線的場景,如智慧路燈等。
MQTTS是MQTT使用TLS加密的協議。採用MQTTS協議接入平臺的裝置,裝置與物聯網平臺之間的通訊過程,資料都是加密的,具有一定的安全性。
採用MQTT協議接入物聯網平臺的裝置,裝置與物聯網平臺之間的通訊過程,資料沒有加密,如果要保證資料的私密性可以使用MQTTS協議。
在這裡可以使用華為雲提供的工具快速得到MQTT三元組進行登入。
https://support.huaweicloud.com/devg-iothub/iot_01_2127.html#ZH-CN_TOPIC_0240834853__zh-cn_topic_0251997880_li365284516112
工具的頁面地址:
https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/
根據提示填入資訊,然後生成三元組資訊即可。 這裡填入的資訊就是在建立裝置的時候生成的資訊。
DeviceId 62cd6da66b9813541d510f64_dev1 DeviceSecret 12345678 ClientId 62cd6da66b9813541d510f64_dev1_0_0_2022071609 Username 62cd6da66b9813541d510f64_dev1 Password a23fb6db6b5bc428971d5ccf64cc8f7767d15ca63bd5e6ac137ef75d175c77bf
3.5 平臺接入地址
華為雲的物聯網伺服器地址在這裡可以獲取:
https://console.huaweicloud.com/iotdm/?region=cn-north-4#/dm-portal/home
MQTT (1883) a161a58a78.iot-mqtts.cn-north-4.myhuaweicloud.com
對應的IP地址是: 121.36.42.100
3.6 MQTT的主題訂閱與釋出格式
得到三元組之後,就可以登入MQTT伺服器進行下一步的主題釋出與訂閱。
主題的格式詳情:
https://support.huaweicloud.com/api-iothub/iot_06_v5_3004.html
裝置訊息上報 $oc/devices/{device_id}/sys/messages/up 平臺下發訊息給裝置 $oc/devices/{device_id}/sys/messages/down 上傳的訊息格式: { "services": [{ "service_id": "Connectivity", "properties": { "dailyActivityTime": 57 }, "event_time": "20151212T121212Z" }, { "service_id": "Battery", "properties": { "batteryLevel": 80 }, "event_time": "20151212T121212Z" } ] }
根據當前裝置的格式總結如下:
ClientId 62cd6da66b9813541d510f64_dev1_0_0_2022071609 Username 62cd6da66b9813541d510f64_dev1 Password a23fb6db6b5bc428971d5ccf64cc8f7767d15ca63bd5e6ac137ef75d175c77bf //訂閱主題: 平臺下發訊息給裝置 $oc/devices/62cd6da66b9813541d510f64_dev1/sys/messages/down //裝置上報資料 $oc/devices/62cd6da66b9813541d510f64_dev1/sys/properties/report //上報的屬性訊息 (一次可以上報多個屬性,在json裡增加就行了) {"services": [{"service_id": "fish","properties":{"LED":1}},{"service_id": "fish","properties":{"motor":1}},{"service_id": "fish","properties":{"水溫":36.2}}]}
3.7 MQTT客戶端模擬裝置除錯
得到資訊之後,將參賽填入軟體進行登入測試。
資料傳送之後,在裝置頁面上可以看到裝置已經線上了,並且收到了上傳的資料。
4. STM32程式設計
4.1 硬體連線
硬體連線方式: 1. TFT 1.44 寸彩屏接線 GND 電源地 VCC 接5V或3.3v電源 SCL 接PC8(SCL) SDA 接PC9(SDA) RST 接PC10 DC 接PB7 CS 接PB8 BL 接PB11 2. 板載LED燈接線 LED1---PA8 LED2---PD2 3. 板載按鍵接線 K0---PA0 K1---PC5 K2---PA15 4. DS18B20溫度感測器接線 DQ->PC6 + : 3.3V - : GND 5. 步進電機 ULN2003控制28BYJ-48步進電機接線: ULN2003接線: IN-D: PB15 d IN-C: PB14 c IN-B: PB13 b IN-A: PB12 a + : 5V - : GND 6. 抽水電機 GND---GND VCC---5V AO----PA4 7. 水質檢測感測器 AO->PA1 + : 3.3V - : GND 8. RGB燈 PC13--R PC14--G PC15--B 9. ATK-ESP8266 WIFI接線 PA2(TX)--RXD 模組接收腳 PA3(RX)--TXD 模組傳送腳 GND---GND 地 VCC---VCC 電源(3.3V~5.0V)
4.2 硬體原理圖
4.3 漢字取模
4.4 程式下載
下載軟體在資料包裡。點選開始程式設計之後,點選開發板的復位鍵即可下載程式進去。
4.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 "oled.h" #include "fontdata.h" #include "bh1750.h" #include "iic.h" #include "sht3x.h" #define ESP8266_WIFI_AP_SSID "aaa" //將要連線的路由器名稱 --不要出現中文、空格等特殊字元 #define ESP8266_AP_PASSWORD "12345678" //將要連線的路由器密碼 //華為雲伺服器的裝置資訊 #define MQTT_ClientID "62cd6da66b9813541d510f64_dev1_0_0_2022071609" #define MQTT_UserName "62cd6da66b9813541d510f64_dev1" #define MQTT_PassWord "a23fb6db6b5bc428971d5ccf64cc8f7767d15ca63bd5e6ac137ef75d175c77bf" //訂閱與釋出的主題 #define SET_TOPIC "$oc/devices/62cd6da66b9813541d510f64_dev1/sys/messages/down" //訂閱 #define POST_TOPIC "$oc/devices/62cd6da66b9813541d510f64_dev1/sys/properties/report" //釋出
4.6 ESP8266主要程式碼
u8 ESP8266_IP_ADDR[16]; //255.255.255.255 u8 ESP8266_MAC_ADDR[18]; //硬體地址 /* 函式功能: ESP8266命令傳送函式 函式返回值:0表示成功 1表示失敗 */ u8 ESP8266_SendCmd(char *cmd) { int RX_CNT=0; u8 i,j; for(i=0;i<10;i++) //檢測的次數--傳送指令的次數 { USARTx_StringSend(USART3,cmd); for(j=0;j<100;j++) //等待的時間 { delay_ms(50); if(USART3_RX_STA&0X8000) { RX_CNT=USART3_RX_STA&0x7FFF; USART3_RX_BUF[RX_CNT]='\0'; USART3_RX_STA=0; if(strstr((char*)USART3_RX_BUF,"OK")) { return 0; } } } } return 1; } /* 函式功能: ESP8266硬體初始化檢測函式 函式返回值:0表示成功 1表示失敗 */ u8 ESP8266_Init(void) { //退出透傳模式 USARTx_StringSend(USART3,"+++"); delay_ms(100); //退出透傳模式 USARTx_StringSend(USART3,"+++"); delay_ms(100); return ESP8266_SendCmd("AT\r\n"); } /* 函式功能: 一鍵配置WIFI為AP+TCP伺服器模式 函式引數: char *ssid 建立的熱點名稱 char *pass 建立的熱點密碼 (最少8位) u16 port 建立的伺服器埠號 函式返回值: 0表示成功 其他值表示對應錯誤值 */ u8 ESP8266_AP_TCP_Server_Mode(char *ssid,char *pass,u16 port) { char *p; u8 i; char ESP8266_SendCMD[100]; //組合傳送過程中的命令 /*1. 測試硬體*/ if(ESP8266_SendCmd("AT\r\n"))return 1; /*2. 關閉回顯*/ if(ESP8266_SendCmd("ATE0\r\n"))return 2; /*3. 設定WIFI模式*/ if(ESP8266_SendCmd("AT+CWMODE=2\r\n"))return 3; /*4. 復位*/ ESP8266_SendCmd("AT+RST\r\n"); delay_ms(1000); delay_ms(1000); delay_ms(1000); /*5. 關閉回顯*/ if(ESP8266_SendCmd("ATE0\r\n"))return 5; /*6. 設定WIFI的AP模式引數*/ sprintf(ESP8266_SendCMD,"AT+CWSAP=\"%s\",\"%s\",1,4\r\n",ssid,pass); if(ESP8266_SendCmd(ESP8266_SendCMD))return 6; /*7. 開啟多連線*/ if(ESP8266_SendCmd("AT+CIPMUX=1\r\n"))return 7; /*8. 設定伺服器埠號*/ sprintf(ESP8266_SendCMD,"AT+CIPSERVER=1,%d\r\n",port); if(ESP8266_SendCmd(ESP8266_SendCMD))return 8; /*9. 查詢本地IP地址*/ if(ESP8266_SendCmd("AT+CIFSR\r\n"))return 9; //提取IP地址 p=strstr((char*)USART3_RX_BUF,"APIP"); if(p) { p+=6; for(i=0;*p!='"';i++) { ESP8266_IP_ADDR[i]=*p++; } ESP8266_IP_ADDR[i]='\0'; } //提取MAC地址 p=strstr((char*)USART3_RX_BUF,"APMAC"); if(p) { p+=7; for(i=0;*p!='"';i++) { ESP8266_MAC_ADDR[i]=*p++; } ESP8266_MAC_ADDR[i]='\0'; } //列印總體資訊 printf("當前WIFI模式:AP+TCP伺服器\r\n"); printf("當前WIFI熱點名稱:%s\r\n",ssid); printf("當前WIFI熱點密碼:%s\r\n",pass); printf("當前TCP伺服器埠號:%d\r\n",port); printf("當前TCP伺服器IP地址:%s\r\n",ESP8266_IP_ADDR); printf("當前TCP伺服器MAC地址:%s\r\n",ESP8266_MAC_ADDR); return 0; } /* 函式功能: TCP伺服器模式下的傳送函式 傳送指令: */ u8 ESP8266_ServerSendData(u8 id,u8 *data,u16 len) { int RX_CNT=0; u8 i,j,n; char ESP8266_SendCMD[100]; //組合傳送過程中的命令 for(i=0;i<10;i++) { sprintf(ESP8266_SendCMD,"AT+CIPSEND=%d,%d\r\n",id,len); USARTx_StringSend(USART3,ESP8266_SendCMD); for(j=0;j<10;j++) { delay_ms(50); if(USART3_RX_STA&0X8000) { RX_CNT=USART3_RX_STA&0x7FFF; USART3_RX_BUF[RX_CNT]='\0'; USART3_RX_STA=0; if(strstr((char*)USART3_RX_BUF,">")) { //繼續傳送資料 USARTx_DataSend(USART3,data,len); //等待資料傳送成功 for(n=0;n<200;n++) { delay_ms(50); if(USART3_RX_STA&0X8000) { RX_CNT=USART3_RX_STA&0x7FFF; USART3_RX_BUF[RX_CNT]='\0'; USART3_RX_STA=0; if(strstr((char*)USART3_RX_BUF,"SEND OK")) { return 0; } } } } } } } return 1; } /* 函式功能: 配置WIFI為STA模式+TCP客戶端模式 函式引數: char *ssid 建立的熱點名稱 char *pass 建立的熱點密碼 (最少8位) char *p 將要連線的伺服器IP地址 u16 port 將要連線的伺服器埠號 u8 flag 1表示開啟透傳模式 0表示關閉透傳模式 函式返回值:0表示成功 其他值表示對應的錯誤 */ u8 ESP8266_STA_TCP_Client_Mode(char *ssid,char *pass,char *ip,u16 port,u8 flag) { char ESP8266_SendCMD[100]; //組合傳送過程中的命令 //退出透傳模式 //USARTx_StringSend(USART3,"+++"); //delay_ms(50); /*1. 測試硬體*/ if(ESP8266_SendCmd("AT\r\n"))return 1; /*2. 關閉回顯*/ if(ESP8266_SendCmd("ATE0\r\n"))return 2; /*3. 設定WIFI模式*/ if(ESP8266_SendCmd("AT+CWMODE=1\r\n"))return 3; /*4. 復位*/ ESP8266_SendCmd("AT+RST\r\n"); delay_ms(1000); delay_ms(1000); delay_ms(1000); /*5. 關閉回顯*/ if(ESP8266_SendCmd("ATE0\r\n"))return 5; /*6. 配置將要連線的WIFI熱點資訊*/ sprintf(ESP8266_SendCMD,"AT+CWJAP=\"%s\",\"%s\"\r\n",ssid,pass); if(ESP8266_SendCmd(ESP8266_SendCMD))return 6; /*7. 設定單連線*/ if(ESP8266_SendCmd("AT+CIPMUX=0\r\n"))return 7; /*8. 配置要連線的TCP伺服器資訊*/ sprintf(ESP8266_SendCMD,"AT+CIPSTART=\"TCP\",\"%s\",%d\r\n",ip,port); if(ESP8266_SendCmd(ESP8266_SendCMD))return 8; /*9. 開啟透傳模式*/ if(flag) { if(ESP8266_SendCmd("AT+CIPMODE=1\r\n"))return 9; //開啟 if(ESP8266_SendCmd("AT+CIPSEND\r\n"))return 10; //開始透傳 if(!(strstr((char*)USART3_RX_BUF,">"))) { return 11; } //如果想要退出傳送: "+++" } printf("WIFI模式:STA+TCP客戶端\r\n"); printf("Connect_WIFI熱點名稱:%s\r\n",ssid); printf("Connect_WIFI熱點密碼:%s\r\n",pass); printf("TCP伺服器埠號:%d\r\n",port); printf("TCP伺服器IP地址:%s\r\n",ip); return 0; } /* 函式功能: TCP客戶端模式下的傳送函式 傳送指令: */ u8 ESP8266_ClientSendData(u8 *data,u16 len) { int RX_CNT=0; u8 i,j,n; char ESP8266_SendCMD[100]; //組合傳送過程中的命令 for(i=0;i<10;i++) { sprintf(ESP8266_SendCMD,"AT+CIPSEND=%d\r\n",len); USARTx_StringSend(USART3,ESP8266_SendCMD); for(j=0;j<10;j++) { delay_ms(50); if(USART3_RX_STA&0X8000) { RX_CNT=USART3_RX_STA&0x7FFF; USART3_RX_BUF[RX_CNT]='\0'; USART3_RX_STA=0; if(strstr((char*)USART3_RX_BUF,">")) { //繼續傳送資料 USARTx_DataSend(USART3,data,len); //等待資料傳送成功 for(n=0;n<200;n++) { delay_ms(50); if(USART3_RX_STA&0X8000) { RX_CNT=USART3_RX_STA&0x7FFF; USART3_RX_BUF[RX_CNT]='\0'; USART3_RX_STA=0; if(strstr((char*)USART3_RX_BUF,"SEND OK")) { return 0; } } } } } } } return 1; }