写点什么

基于 STM32+ESP8266+ 华为云设计的智能家居控制系统

作者:DS小龙哥
  • 2022 年 3 月 01 日
  • 本文字数:7440 字

    阅读完需:约 24 分钟

1. 功能介绍

这是基于华为云物联网平台设计智能家居控制系统(模型),硬件采用 STM32+ESP8266 完成上云组合;通过云平台可以远程控制家里的各种电器开关,并且可以远程收集家里煤气、天然气、烟雾、光照度、温度湿度等信息。


硬件介绍:


主控 MCU: STM32F103ZET6


烟雾检测传感器: MQ2


天然气检测传感: MQ5


温度湿度检测传感器: DHT11


光照强度检测传感器: BH1750


物联网云平台: 华为云物联网平台


电器开关模拟采用板载的 LED 灯、继电器。


WIFI: ESP8266 这是支持串口 AT 指令控制的 WIFI 模块,联网比较方便。


与华为云物联网平台通信的协议: MQTT


说明: 当前程序里的 MQTT 协议代码是参考 MQTT 官方文档编写的,不是使用 ESP8266 内置的,所以程序并不依赖 ESP8266 专用或者指定的 SDK,使用任意可以上网的网卡都可以套用,并不是一定非要使用 ESP8266。

2. 登录华为云创建云端设备

2.1 创建产品

华为运官网: https://www.huaweicloud.com/





在这里可以查看接入的协议的端口号和地址。




MQTT (1883)  a161a58a78.iot-mqtts.cn-north-4.myhuaweicloud.com  
复制代码


我们设备接入的协议选择 MQTT,端口对应是 1883


接下来继续创建产品,点击产品页面,点击右上角创建产品:




2.2 创建设备



这是我的设备信息:


设备ID61a580fad28ce3028832c2d8_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.255u8 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 <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 "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<USART3_RX_CNT;i++) { USART1_Printf("%c",USART3_RX_BUFFER[i]); } 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,"{\"services\": [{\"service_id\": \"dht11\",\"properties\":{\"DHT11-C\":%d}}]}",temp); 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(); } }}
复制代码


**项目源码:**https://download.csdn.net/download/xiaolong1126626497/81993720

发布于: 2022 年 03 月 01 日阅读数: 2
用户头像

DS小龙哥

关注

之所以觉得累,是因为说的比做的多。 2022.01.06 加入

熟悉C/C++、51单片机、STM32、Linux应用开发、Linux驱动开发、音视频开发、QT开发. 目前已经完成的项目涉及音视频、物联网、智能家居、工业控制领域

评论

发布
暂无评论
基于STM32+ESP8266+华为云设计的智能家居控制系统_物联网_DS小龙哥_InfoQ写作平台