1. 功能介紹
現在物聯網已經遍布生活每個角落,幾乎哪里都能看到物聯網的應用。物聯網就是物物相連的互聯網,可以將之前單機設備全部接入互聯網,完成數據交互,遠程控制。 比如: 智能電表(遠程抄表),智能水表,智能天然氣表,智能井蓋(遠程向市政機關上包污水污染程度、水深程度),智慧路燈,智慧停車場(APP上遠程查看是否有空余車位)等等,都是物聯網成功應用的例子。
現在各大平臺都提供了物聯網服務器,比如:OneNet(中國移動)、阿里云物聯網、百度天工物接入、華為云物聯網、機智云物聯網、騰訊云物聯網(支持自定義小程序,效果非常nice)等。
前面幾篇文章已經分別介紹了,OneNet(中國移動)、阿里云物聯網、騰訊云物聯網 平臺的接入案例。
OneNet(中國移動): https://xiaolong.blog.csdn.net/article/details/107385118
騰訊云物聯網: https://xiaolong.blog.csdn.net/article/details/117167261
阿里云物聯網: https://xiaolong.blog.csdn.net/article/details/107311897
這篇文章就介紹如何使用STM32接入華為云物聯網平臺,完成數據交互,設計案例是基于華為云物聯網平臺設計智能家居控制系統(模型),硬件采用STM32+ESP8266完成上云組合;通過云平臺可以遠程控制家里的各種電器開關,并且可以遠程收集家里煤氣、天然氣、煙霧、光照度、溫度濕度等信息。
硬件介紹:
主控MCU: STM32F103ZET6
天然氣檢測傳感:MQ5
溫度濕度檢測傳感器: DHT11
光照強度檢測傳感器: BH1750
物聯網云平臺: 華為云物聯網平臺
電器開關模擬采用板載的LED燈、繼電器。
WIFI: ESP8266
這是支持串口AT指令控制的WIFI模塊,聯網比較方便。
與華為云物聯網平臺通信的協議: MQTT
說明: 當前程序里的MQTT協議代碼是參考MQTT官方文檔編寫的,不是使用ESP8266內置的,所以程序并不依賴ESP8266專用或者指定的SDK,使用任意可以上網的網卡都可以套用,并不是一定非要使用ESP8266。
2. 登錄華為云創建云端設備
2.1 創建產品
華為運官網: https://www.huaweicloud.com/
在這里可以查看接入的協議的端口號和地址。
我們設備接入的協議選擇MQTT,端口對應是1883
接下來繼續創建產品,點擊產品頁面,點擊右上角創建產品:
2.2 創建設備
設備ID
61a580fad28ce3028832c2d8_esp8266_iot
設備密鑰
1126626497
{
"device_id": "61a580fad28ce3028832c2d8_esp8266_iot",
"secret": "1126626497"
}
2.3 產品模型定義
這一步就是設置上報設備的屬性,也就是設備的數據類型定義。
2.4 生成MQTT登錄密匙
創建完產品、設備之后,接下來就需要知道如何通過MQTT協議登陸華為云服務器。
官方的詳細介紹在這里: https://support.huaweicloud.com/devg-iothub/iot_01_2127.html#ZH-CN_TOPIC_0240834853__zh-cn_topic_0251997880_li365284516112
MQTT設備登陸密匙生成地址: https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/
下面就得到了MQTT協議設備登錄的參數。
2.5 使用MQTT客戶端軟件登錄
所有的參數已經得到,接下來采用MQTT客戶端登錄華為云進行測試。
下面這個軟件是自己開發的,為了方便測試MQTT協議登錄。
華為云物聯網平臺的域名是: a161a58a78.iot-mqtts.cn-north-4.myhuaweicloud.com
華為云物聯網平臺的IP地址是: 121.36.42.100
在軟件里參數填充正確之后,就看到設備已經連接成功了。
接下來打開設備頁面,可以看到設備已經在線了。
2.6 上報數據
官方文檔: https://support.huaweicloud.com/devg-iothub/iot_01_2127.html#ZH-CN_TOPIC_0240834853__zh-cn_topic_0251997880_li365284516112
在這個文檔里介紹了MQTT上報數據的格式。
總結的格式:
//訂閱主題: 平臺下發消息給設備
$oc/devices/61a580fad28ce3028832c2d8_esp8266_iot/sys/messages/down
//設備上報數據
$oc/devices/61a580fad28ce3028832c2d8_esp8266_iot/sys/properties/report
//上報的屬性消息 (一次可以上報多個屬性,在json里增加就行了)
{"services": [{"service_id": "dht11","properties":{"DHT11-C":50}}]}
下面采用MQTT軟件上報數據:
到此,設備數據已經上報成功,如果需要增加更多的屬性,按照流程繼續增加即可。
3. STM32+ESP8266上報數據到華為云
3.1 硬件設備效果圖
3.2 BH1750.c 光照度傳感器
#include "bh1750.h"
float Read_BH1750_Data()
{
unsigned char t0;
unsigned char t1;
float t;
u8 r_s=0;
IIC_Start(); //發送起始信號
IIC_WriteOneByteData(0x46);
r_s=IIC_GetACK();//獲取應答
if(r_s)printf("error:1\r\n");
IIC_WriteOneByteData(0x01);
r_s=IIC_GetACK();//獲取應答
if(r_s)printf("error:2\r\n");
IIC_Stop(); //停止信號
IIC_Start(); //發送起始信號
IIC_WriteOneByteData(0x46);
r_s=IIC_GetACK();//獲取應答
if(r_s)printf("error:3\r\n");
IIC_WriteOneByteData(0x01);
r_s=IIC_GetACK();//獲取應答
if(r_s)printf("error:4\r\n");
IIC_Stop(); //停止信號
IIC_Start(); //發送起始信號
IIC_WriteOneByteData(0x46);
r_s=IIC_GetACK();//獲取應答
if(r_s)printf("error:5\r\n");
IIC_WriteOneByteData(0x10);
r_s=IIC_GetACK();//獲取應答
if(r_s)printf("error:6\r\n");
IIC_Stop(); //停止信號
DelayMs(300); //等待
IIC_Start(); //發送起始信號
IIC_WriteOneByteData(0x47);
r_s=IIC_GetACK();//獲取應答
if(r_s)printf("error:7\r\n");
t0=IIC_ReadOneByteData(); //接收數據
IIC_SendACK(0); //發送應答信號
t1=IIC_ReadOneByteData(); //接收數據
IIC_SendACK(1); //發送非應答信號
IIC_Stop(); //停止信號
t=(((t0<<8)|t1)/1.2);
return t;
}
3.3 ESP8266.c WIFI代碼
#include "esp8266.h"
u8 ESP8266_IP_ADDR[16]; //255.255.255.255
u8 ESP8266_MAC_ADDR[18]; //硬件地址
/*
函數功能: ESP8266命令發送函數
函數返回值:0表示成功 1表示失敗
*/
u8 ESP8266_SendCmd(char *cmd)
{
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_FLAG)
{
USART3_RX_BUFFER[USART3_RX_CNT]='\0';
USART3_RX_FLAG=0;
USART3_RX_CNT=0;
if(strstr((char*)USART3_RX_BUFFER,"OK"))
{
return 0;
}
}
}
}
return 1;
}
/*
函數功能: ESP8266硬件初始化檢測函數
函數返回值:0表示成功 1表示失敗
*/
u8 ESP8266_Init(void)
{
//退出透傳模式
USARTx_StringSend(USART3,"+++");
delay_ms(50);
return ESP8266_SendCmd("AT\r\n");
}
/*
函數功能: TCP服務器模式下的發送函數
發送指令:
*/
u8 ESP8266_ServerSendData(u8 id,u8 *data,u16 len)
{
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_FLAG)
{
USART3_RX_BUFFER[USART3_RX_CNT]='\0';
USART3_RX_FLAG=0;
USART3_RX_CNT=0;
if(strstr((char*)USART3_RX_BUFFER,">"))
{
//繼續發送數據
USARTx_DataSend(USART3,data,len);
//等待數據發送成功
for(n=0;n<200;n++)
{
delay_ms(50);
if(USART3_RX_FLAG)
{
USART3_RX_BUFFER[USART3_RX_CNT]='\0';
USART3_RX_FLAG=0;
USART3_RX_CNT=0;
if(strstr((char*)USART3_RX_BUFFER,"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_BUFFER,">")))
{
return 11;
}
//如果想要退出發送: "+++"
}
//打印總體信息
USART1_Printf("WIFI模式:STA+TCP客戶端\n");
USART1_Printf("Connect_WIFI熱點名稱:%s\n",ssid);
USART1_Printf("Connect_WIFI熱點密碼:%s\n",pass);
USART1_Printf("TCP服務器端口號:%d\n",port);
USART1_Printf("TCP服務器IP地址:%s\n",ip);
return 0;
}
/*
函數功能: TCP客戶端模式下的發送函數
發送指令:
*/
u8 ESP8266_ClientSendData(u8 *data,u16 len)
{
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_FLAG)
{
USART3_RX_BUFFER[USART3_RX_CNT]='\0';
USART3_RX_FLAG=0;
USART3_RX_CNT=0;
if(strstr((char*)USART3_RX_BUFFER,">"))
{
//繼續發送數據
USARTx_DataSend(USART3,data,len);
//等待數據發送成功
for(n=0;n<200;n++)
{
delay_ms(50);
if(USART3_RX_FLAG)
{
USART3_RX_BUFFER[USART3_RX_CNT]='\0';
USART3_RX_FLAG=0;
USART3_RX_CNT=0;
if(strstr((char*)USART3_RX_BUFFER,"SEND OK"))
{
return 0;
}
}
}
}
}
}
}
return 1;
}
3.4 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"
#define ESP8266_WIFI_AP_SSID "CMCC-Cqvn" //將要連接的路由器名稱 --不要出現中文、空格等特殊字符
#define ESP8266_AP_PASSWORD "99pu58cb" //將要連接的路由器密碼
//華為云服務器的設備信息
#define MQTT_ClientID "61a580fad28ce3028832c2d8_esp8266_iot_0_0_2021113002"
#define MQTT_UserName "61a580fad28ce3028832c2d8_esp8266_iot"
#define MQTT_PassWord "74af3bf3024cf9c41b13d6c63fc86e25012b54141ecfcdff3516f08665140e6f"
//訂閱與發布的主題
#define SET_TOPIC "$oc/devices/61a580fad28ce3028832c2d8_esp8266_iot/sys/messages/down" //訂閱
#define POST_TOPIC "$oc/devices/61a580fad28ce3028832c2d8_esp8266_iot/sys/properties/report" //發布
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,"121.36.42.100",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;i;i++)>
審核編輯:湯梓紅
-
控制系統
+關注
關注
41文章
6550瀏覽量
110498 -
物聯網
+關注
關注
2904文章
44306瀏覽量
371459 -
STM32
+關注
關注
2266文章
10876瀏覽量
354925 -
智能家居
+關注
關注
1926文章
9523瀏覽量
184374 -
華為云
+關注
關注
3文章
2435瀏覽量
17322
發布評論請先 登錄
相關推薦
評論