?
一、環境介紹
上網方式:采用ESP8266,也可以使用其他設備代替,只要支持TCP協議即可。比如:GSM模塊、有線網卡等。
與物聯網云平臺的通信協議:標準MQTT協議3.1.1(TCP)
開發軟件:keil5
物聯網平臺: 騰訊IOT物聯網物聯網平臺。騰訊的物聯網平臺比起其他廠家的物聯網平臺更加有優勢,騰訊物聯網平臺可以將數據推到微信小程序上,用戶可以直接使用小程序綁定設備,完成與設備之間交互,現在用戶基本都會使用微信,所以使用起來非常方便。
?
?
?
?
?
二、智慧農業介紹
智慧農業就是將物聯網技術運用到傳統農業中去,運用傳感器和軟件通過移動平臺或者電腦平臺對農業生產進行控制,使傳統農業更具有“智慧”。除 了精準感知、控制與決策管理外,從廣泛意義上講,智慧農業還包括農業電子商務、食品溯源防偽、農業休閑旅游、農業信息服務等方面的內容。
所謂“智慧農業”就是充分應用現代信息技術成果,集成應用計算機與網絡技術、物聯網技術、音視頻技術、3S技術、無線通信技術及專家智慧與知識,實現農業可視化遠程診斷、遠程控制、災變預警等智能管理。
智慧農業是農業生產的高級階段,是集新興的互聯網、移動互聯網、云計算和物聯網技術為一體,依托部署在農業生產現場的各種傳感節點(環境溫濕度、土壤水分、二氧化碳、圖像等)和無線通信網絡實現農業生產環境的智能感知、智能預警、智能決策、智能分析、專家在線指導,為農業生產提供精準化種植、可視化管理、智能化決策。
“智慧農業”是云計算、傳感網、3S等多種信息技術在農業中綜合、全面的應用,實現更完備的信息化基礎支撐、更透徹的農業信息感知、更集中的數據資源、更廣泛的互聯互通、更深入的智能控制、更貼心的公眾服務。“智慧農業”與現代生物技術、種植技術等科學技術融合于一體,對建設世界水平農業具有重要意義。
本項目采用STM32F103ZET6 + ESP8266 設計一個智慧農業管理系統,能夠獲取空氣中的溫濕度數據,光照度數據等,根據種植區的空氣溫濕度數據,判斷是否進行灌溉;可以通過ESP8266 + MQTT 協議將采集的溫濕度、光照度上傳至騰訊云物聯網平臺,并推送到微信小程序上實時查看;可以在小程序上直接控制電機抽水灌溉。
硬件詳情介紹:
主控MCU: STM32F103ZET6
環境光傳感器: BH1750
溫濕度傳感器:SHT30
本地OLED顯示屏: 中景園電子0.96寸 SPI接口 OLED顯示屏
電機: 微型直流電機
三、創建騰訊云物聯網平臺設備并配置微信小程序
如果之前從來沒有使用過騰訊云物聯網平臺,創建的詳細步驟請看這里: STM32+ESP8266+MQTT協議連接騰訊物聯網開發平臺_DS小龍哥的專欄-CSDN博客_騰訊物聯網平臺
下面就是登錄騰訊云物聯網平臺,創建一個智慧農業的設備的關鍵步驟,有些細節步驟沒寫,細節請看上面鏈接這篇文章。
官網地址:登錄 - 騰訊云
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
四、生成騰訊物聯網平臺的設備登錄信息
使用MQTT協議登錄需要一些參數信息,需要使用官網提供的方式生成。
?
Python示例代碼:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import base64
import hashlib
import hmac
import random
import string
import time
import sys
# 生成指定長度的隨機字符串
def RandomConnid(length):
return ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(length))
# 生成接入物聯網通信平臺需要的各參數
def IotHmac(productID, devicename, devicePsk):
# 1. 生成 connid 為一個隨機字符串,方便后臺定位問題
connid = RandomConnid(5)
# 2. 生成過期時間,表示簽名的過期時間,從紀元1970年1月1日 00:00:00 UTC 時間至今秒數的 UTF8 字符串
expiry = int(time.time()) + 30*24*60 * 60
# 3. 生成 MQTT 的 clientid 部分, 格式為 ${productid}${devicename}
clientid = "{}{}".format(productID, devicename)
# 4. 生成 MQTT 的 username 部分, 格式為 ${clientid};${sdkappid};${connid};${expiry}
username = "{};12010126;{};{}".format(clientid, connid, expiry)
# 5. 對 username 進行簽名,生成token
secret_key = devicePsk.encode('utf-8') # convert to bytes
data_to_sign = username.encode('utf-8') # convert to bytes
secret_key = base64.b64decode(secret_key) # this is still bytes
token = hmac.new(secret_key, data_to_sign, digestmod=hashlib.sha256).hexdigest()
# 6. 根據物聯網通信平臺規則生成 password 字段
password = "{};{}".format(token, "hmacsha256")
return {
"clientid" : clientid,
"username" : username,
"password" : password
}
if __name__ == '__main__':
# 參數分別填入: 產品ID,設備名稱,設備密匙
print(IotHmac("6142CX41XE", "SmartAgriculture","20Y/aAcmj+y6SDDh+ANR9g=="))
輸出的登錄參數,用于MQTT協議填參數:
{'clientid': '6142CX41XESmartAgriculture', 'username': '6142CX41XESmartAgriculture;12010126;HUA2G;1624271589',
'password': 'a8aadebe9721f70e6f9e14fe56ff1d2b5cac9625fa1f96af2f0e0098597fe78b;hmacsha256'}
五、使用MQTT軟件測試
?
設備主題發布與定義的格式:
?
設備消息數據上傳格式:
{"method":"report","clientToken":"123","params":{"light":78.4,"temperature":21.4,"humidity":60.8,"motor":1}}
登錄成功之后,就可以看到設備在線:
?
打開微信小程序可以查看到設備上傳的數據:
?
六、編寫STM32設備端代碼
?
?
6.1 main.c代碼
#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
#include "key.h"
#include "usart.h"
#include
#include "timer.h"
#include "esp8266.h"
#include "mqtt.h"
#include "oled.h"
#include "fontdata.h"
#include "bh1750.h"
#include "iic.h"
#include "sht3x.h"
/*
硬件連接方式:
ESP8266串口WIFI模塊與STM32的串口3相連接。
PB10--RXD 模塊接收腳
PB11--TXD 模塊發送腳
GND---GND 地
VCC---VCC 電源(3.3V~5.0V)
OLED接線:
D0----SCK-----PB14
D1----MOSI----PB13
RES—復位(低電平有效)—PB12
DC---數據和命令控制管腳—PB1
CS---片選引腳-----PA7
微型直流電機: PB8
紫光燈: PB9
LED硬件連接: PB5 PE5
KEY硬件連接:PE3 PE4
*/
#define ESP8266_WIFI_AP_SSID "CMCC-Cqvn" //將要連接的路由器名稱 --不要出現中文、空格等特殊字符
#define ESP8266_AP_PASSWORD "99pu58cb" //將要連接的路由器密碼
//騰訊物聯網服務器的設備信息
#define MQTT_ClientID "6142CX41XESmartAgriculture"
#define MQTT_UserName "6142CX41XESmartAgriculture;12010126;HUA2G;1624271589"
#define MQTT_PassWord "a8aadebe9721f70e6f9e14fe56ff1d2b5cac9625fa1f96af2f0e0098597fe78b;hmacsha256"
//訂閱與發布的主題
#define SET_TOPIC "$thing/down/property/6142CX41XE/SmartAgriculture" //訂閱
#define POST_TOPIC "$thing/up/property/6142CX41XE/SmartAgriculture" //發布
char mqtt_message[200];//上報數據緩存區
char OLED_ShowBuff[100];
u8 ESP8266_Stat=0;
/*
函數功能: 溫濕度\光強度顯示
*/
void ShowTemperatureAndHumidity(float temp,float humi,float light)
{
sprintf(OLED_ShowBuff,"T: %.2f",temp);
OLED_ShowString(40,16*0,16,OLED_ShowBuff);
sprintf(OLED_ShowBuff,"H: %.2f%%",humi);
OLED_ShowString(40,16*1,16,OLED_ShowBuff);
sprintf(OLED_ShowBuff,"L: %.2f%%",light);
OLED_ShowString(40,16*2,16,OLED_ShowBuff);
}
/*
函數功能: ESP8266顯示頁面
*/
void ESP8266_ShowPageTable(void)
{
if(ESP8266_Stat)OLED_ShowString(0,16*0,16,"WIFI STAT:ERROR");
else OLED_ShowString(0,16*0,16,"WIFI STAT:OK");
//顯示字符串
sprintf((char*)OLED_ShowBuff,"%s",ESP8266_WIFI_AP_SSID);
OLED_ShowString(0,16*1,16,OLED_ShowBuff);
sprintf((char*)OLED_ShowBuff,"%s",ESP8266_AP_PASSWORD);
OLED_ShowString(0,16*2,16,OLED_ShowBuff);
}
int main()
{
u32 time_cnt=0;
u32 i;
u8 key;
u8 page=0;
float temp=0;
float humi=0;
float light=0;
u8 motor_state=0;
float Humidity;
float Temperature;
delay_ms(1000);
delay_ms(1000);
LED_Init();
KEY_Init();
IIC_Init();
//OLED初始化
OLED_Init(0xc8,0xa1); //OLED顯示屏初始化--正常顯示;
//清屏
OLED_Clear(0);
USART1_Init(115200);
TIMER1_Init(72,20000); //超時時間20ms
USART3_Init(115200);//串口-WIFI
TIMER3_Init(72,20000); //超時時間20ms
Init_SHT30();
USART1_Printf("正在初始化WIFI請稍等.\n");
if(ESP8266_Init())
{
ESP8266_Stat=1;
USART1_Printf("ESP8266硬件檢測錯誤.\n");
}
else
{
//非加密端口
USART1_Printf("WIFI:%d\n",ESP8266_STA_TCP_Client_Mode(ESP8266_WIFI_AP_SSID,ESP8266_AP_PASSWORD,"106.55.124.154",1883,1));
}
//2. MQTT協議初始化
MQTT_Init();
//3. 連接騰訊云IOT服務器
while(MQTT_Connect(MQTT_ClientID,MQTT_UserName,MQTT_PassWord))
{
USART1_Printf("服務器連接失敗,正在重試...\n");
delay_ms(500);
}
USART1_Printf("服務器連接成功.\n");
//3. 訂閱主題
if(MQTT_SubscribeTopic(SET_TOPIC,0,1))
{
USART1_Printf("主題訂閱失敗.\n");
}
else
{
USART1_Printf("主題訂閱成功.\n");
}
while(1)
{
//按鍵可以測試開鎖和關鎖
key=KEY_Scan(0);
if(key==1)
{
//清屏
OLED_Clear(0);
//翻頁
if(page>=1)
{
page=0;
}
else
{
page++;
}
LED1=!LED1; //LEd狀態燈
}
else if(key==2)
{
LED1=!LED1; //LEd狀態燈
time_cnt=0;
//電機狀態改變
MOTOR_DEV=!MOTOR_DEV;
//電機狀態
motor_state=MOTOR_DEV;
//補光燈
LIGHT_DEV=!LIGHT_DEV;
}
//微信小程序開鎖方式: 接收WIFI返回的數據
if(USART3_RX_FLAG)
{
USART3_RX_BUFFER[USART3_RX_CNT]='\0';
//向串口打印微信小程序返回的數據
for(i=0;i5)
{
//使用字符串查找函數
if(strstr((char*)&USART3_RX_BUFFER[5],""motor":1"))
{
LED1=0; //亮燈
MOTOR_DEV=1; //開電機
motor_state=1;
}
else if(strstr((char*)&USART3_RX_BUFFER[5],""motor":0"))
{
LED1=1; //滅燈
MOTOR_DEV=0; //關電機
motor_state=0;
}
}
USART3_RX_CNT=0;
USART3_RX_FLAG=0;
}
//定時與保持與微信小程序的同步--1秒一次
delay_ms(10);
time_cnt++;
if(time_cnt==50)
{
time_cnt=0;
//狀態燈 --表示程序還活著
LED2=!LED2;
//讀取光強度
light=Read_BH1750_Data();
//讀取溫濕度
SHT3x_ReadData(&Humidity,&Temperature);
humi=Humidity;
temp=Temperature;
//上傳數據
sprintf(mqtt_message,"{"method":"report","clientToken":"123","params":{"temperature":%f,"humidity":%f,"motor":%d,"light":%f}}",
temp,humi,motor_state,light);
MQTT_PublishData(POST_TOPIC,mqtt_message,0);
//根據濕度自動灌溉
if(humi<50.0) //小于50自動灌溉
{
motor_state=1; //電機狀態更新
MOTOR_DEV=1; //開電機
}
}
//OLED顯示屏
if(page==0)
{
ShowTemperatureAndHumidity(temp,humi,light);
}
else if(page==1)
{
ESP8266_ShowPageTable();
}
}
}
;i++)>
6.2 mqtt.c 代碼
#include "mqtt.h"
u8 *mqtt_rxbuf;
u8 *mqtt_txbuf;
u16 mqtt_rxlen;
u16 mqtt_txlen;
u8 _mqtt_txbuf[256];//發送數據緩存區
u8 _mqtt_rxbuf[256];//接收數據緩存區
typedef enum
{
//名字 值 報文流動方向 描述
M_RESERVED1 =0 , // 禁止 保留
M_CONNECT , // 客戶端到服務端 客戶端請求連接服務端
M_CONNACK , // 服務端到客戶端 連接報文確認
M_PUBLISH , // 兩個方向都允許 發布消息
M_PUBACK , // 兩個方向都允許 QoS 1消息發布收到確認
M_PUBREC , // 兩個方向都允許 發布收到(保證交付第一步)
M_PUBREL , // 兩個方向都允許 發布釋放(保證交付第二步)
M_PUBCOMP , // 兩個方向都允許 QoS 2消息發布完成(保證交互第三步)
M_SUBSCRIBE , // 客戶端到服務端 客戶端訂閱請求
M_SUBACK , // 服務端到客戶端 訂閱請求報文確認
M_UNSUBSCRIBE , // 客戶端到服務端 客戶端取消訂閱請求
M_UNSUBACK , // 服務端到客戶端 取消訂閱報文確認
M_PINGREQ , // 客戶端到服務端 心跳請求
M_PINGRESP , // 服務端到客戶端 心跳響應
M_DISCONNECT , // 客戶端到服務端 客戶端斷開連接
M_RESERVED2 , // 禁止 保留
}_typdef_mqtt_message;
//連接成功服務器回應 20 02 00 00
//客戶端主動斷開連接 e0 00
const u8 parket_connetAck[] = {0x20,0x02,0x00,0x00};
const u8 parket_disconnet[] = {0xe0,0x00};
const u8 parket_heart[] = {0xc0,0x00};
const u8 parket_heart_reply[] = {0xc0,0x00};
const u8 parket_subAck[] = {0x90,0x03};
void MQTT_Init(void)
{
//緩沖區賦值
mqtt_rxbuf = _mqtt_rxbuf;
mqtt_rxlen = sizeof(_mqtt_rxbuf);
mqtt_txbuf = _mqtt_txbuf;
mqtt_txlen = sizeof(_mqtt_txbuf);
memset(mqtt_rxbuf,0,mqtt_rxlen);
memset(mqtt_txbuf,0,mqtt_txlen);
//無條件先主動斷開
MQTT_Disconnect();
delay_ms(100);
MQTT_Disconnect();
delay_ms(100);
}
/*
函數功能: 登錄服務器
函數返回值: 0表示成功 1表示失敗
*/
u8 MQTT_Connect(char *ClientID,char *Username,char *Password)
{
u8 i,j;
int ClientIDLen = strlen(ClientID);
int UsernameLen = strlen(Username);
int PasswordLen = strlen(Password);
int DataLen;
mqtt_txlen=0;
//可變報頭+Payload 每個字段包含兩個字節的長度標識
DataLen = 10 + (ClientIDLen+2) + (UsernameLen+2) + (PasswordLen+2);
//固定報頭
//控制報文類型
mqtt_txbuf[mqtt_txlen++] = 0x10; //MQTT Message Type CONNECT
//剩余長度(不包括固定頭部)
do
{
u8 encodedByte = DataLen % 128;
DataLen = DataLen / 128;
// if there are more data to encode, set the top bit of this byte
if ( DataLen > 0 )
encodedByte = encodedByte | 128;
mqtt_txbuf[mqtt_txlen++] = encodedByte;
}while ( DataLen > 0 );
//可變報頭
//協議名
mqtt_txbuf[mqtt_txlen++] = 0; // Protocol Name Length MSB
mqtt_txbuf[mqtt_txlen++] = 4; // Protocol Name Length LSB
mqtt_txbuf[mqtt_txlen++] = 'M'; // ASCII Code for M
mqtt_txbuf[mqtt_txlen++] = 'Q'; // ASCII Code for Q
mqtt_txbuf[mqtt_txlen++] = 'T'; // ASCII Code for T
mqtt_txbuf[mqtt_txlen++] = 'T'; // ASCII Code for T
//協議級別
mqtt_txbuf[mqtt_txlen++] = 4; // MQTT Protocol version = 4 對于 3.1.1 版協議,協議級別字段的值是 4(0x04)
//連接標志
mqtt_txbuf[mqtt_txlen++] = 0xc2; // conn flags
mqtt_txbuf[mqtt_txlen++] = 0; // Keep-alive Time Length MSB
mqtt_txbuf[mqtt_txlen++] = 100; // Keep-alive Time Length LSB 100S心跳包 保活時間
mqtt_txbuf[mqtt_txlen++] = BYTE1(ClientIDLen);// Client ID length MSB
mqtt_txbuf[mqtt_txlen++] = BYTE0(ClientIDLen);// Client ID length LSB
memcpy(&mqtt_txbuf[mqtt_txlen],ClientID,ClientIDLen);
mqtt_txlen += ClientIDLen;
if(UsernameLen > 0)
{
mqtt_txbuf[mqtt_txlen++] = BYTE1(UsernameLen); //username length MSB
mqtt_txbuf[mqtt_txlen++] = BYTE0(UsernameLen); //username length LSB
memcpy(&mqtt_txbuf[mqtt_txlen],Username,UsernameLen);
mqtt_txlen += UsernameLen;
}
if(PasswordLen > 0)
{
mqtt_txbuf[mqtt_txlen++] = BYTE1(PasswordLen); //password length MSB
mqtt_txbuf[mqtt_txlen++] = BYTE0(PasswordLen); //password length LSB
memcpy(&mqtt_txbuf[mqtt_txlen],Password,PasswordLen);
mqtt_txlen += PasswordLen;
}
memset(mqtt_rxbuf,0,mqtt_rxlen);
MQTT_SendBuf(mqtt_txbuf,mqtt_txlen);
for(j=0;j<10;j++)
{
delay_ms(50);
if(USART3_RX_FLAG)
{
memcpy((char *)mqtt_rxbuf,USART3_RX_BUFFER,USART3_RX_CNT);
//memcpy
for(i=0;i;i++)usart1_printf("%#x>
本項目完整代碼下載地址:https://download.csdn.net/download/xiaolong1126626497/18973282
審核編輯:符乾江?
-
STM32
+關注
關注
2270文章
10918瀏覽量
356821 -
智慧農業
+關注
關注
4文章
789瀏覽量
19877
發布評論請先 登錄
相關推薦
評論