网络知识 娱乐 基于STM32设计的智慧浇花系统(华为云IOT)

基于STM32设计的智慧浇花系统(华为云IOT)

1. 前言

随着社会的不断发展和人们生活水平的逐渐提高,人们逐渐追求高质量的生活,很多人都会选择在家里或办公室种植一些花卉以净化家庭空气,陶冶情操,但是很多人忙于工作、学习、出差、旅游或者一些其他的原因,不能及时地对花卉进行照料,短时间内导致很多花卉因缺水分而影响正常生长,长时间不照料有些名贵的花卉直接死亡。基于上述状况,提出了此基于物联网的智慧浇花系统。该系统采用工业级高精度土壤温湿度传感器采集花盆中的土壤温湿度,环境的温度湿度,通过ESP8266 WIFI实时上传当前的土壤温湿度、环境光照度等数据到华为云物联网云平台,可以通过 app实时查看花卉的土壤湿度、环境温度等信息,并且本地通过OLED显示屏实时显示这些信息,可以设定某种花适宜的生长的土壤湿度条件,实现自动控制给花浇水,即能让花卉生长在适宜的湿度下,与目前市场上的自动浇花系统相比,该系统的特点具有远程控制,低成本、极高的资源利用率、操作简单和反应灵敏等。

2. 整体系统设计

主控MCU选择STM32F103芯片,通过土壤湿度传感器、环境温湿度传感器,检测整个周边环境信息,再通过ESP8266 WIFI传递到物联网平台。程序里可以预设湿度阀值,当检测到土壤湿度低于阀值就自动浇花。在手机APP上可以实现远程控制水泵浇花,本地在搭载一个TFT小尺寸显示屏,可以实时显示测量检测的数据,在办公室里也可以通过TFT彩屏显示屏解周围环境的信息。

image-20220314220440225

image-20220314220612175

9)ZPR5ZTLKT1V945T)LI420.jpg

image-20220612231630969

image-20220612231655496

image-20220612231713008

3. 硬件选型

3.1 STM32开发板

image-20220310112203970

image-20220314225132797

3.2 土壤湿度传感器

image-20220310113015073

3.3 ESP8266 WIFI

image-20220310112928724

3.4 环境温湿度

image-20220310113210331

3.5 水泵电机

image-20220315005148887

image-20220310113457534

4. 华为云物联网平台

采用现成的物联网云平台,可以方便设备上云,完成设备与上位机之间双向通信,不需要自己搭建服务器,还可以通过云端的存储桶存储数据,分析数据等。

4.1 创建产品

(1)登录官网

登录官网,找到物联网产品

https://www.huaweicloud.com

选择产品、IOT物联网、设备接入

image-20220314152340383

image-20220314152436051

(2)创建产品

选择产品选项栏,点击右上角创建产品;先创建产品、再创建设备。一个产品下可以创建多个设备。

image-20220314154410232

(3)填写产品的信息

image-20220314154643551

(4)创建成功

点击确定,产品创建成功后,点击查看详情,保存好产品ID等信息

image-20220314154713911

(5)创建服务器ID

点击自定义模型按钮,创建服务器ID

image-20220314154845545

image-20220314154941078

(6)添加属性

添加的这个属性非常重要,就是设置设备与服务器之间数据传输的属性,设备端哪些传感器需要上传数据到服务器,这里就按照传感器的数据类型给它添加属性。

【1】添加环境温度属性:温度属性是设备主动上传,这里就设置为只读属性。

image-20220314155109865

【2】添加环境湿度属性:湿度属性是设备主动上传,这里就设置为只读属性。

image-20220314155619873

【3】添加环境湿度属性:湿度属性是设备主动上传,这里就设置为只读属性。

image-20220314155714699

【4】添加灌溉电机的属性:电机需要下发指令控制,就设置为只读只写属性。

image-20220314160413622

【5】所有的属性如下

image-20220314160519969

4.2 创建设备

产品创建好之后,在下面创建对应的设备。这个设备创建一般可以采用服务器提供的接口,在应用端开发引导界面自动创建,这里采用手动形式创建,方便了解设备创建流程,需要填充什么属性参数等等。

(1)创建设备

选择所有设备选项卡、跳转到设备页面、点击右上角创建设备。

image-20220314160626012

(2)单设备注册

根据提示填充设备参数。

image-20220314160955567

(3)保存设备密匙

创建成功后,保存设备密匙,后续生成MQTT登录密码、账号需要使用。

image-20220314161241229

{
    "device_id": "622ef2e8c4e6a958e356fe84_STM32",
    "secret": "12345678"
}

image-20220314161535617

(4)查看设备详情

image-20220314161630794

4.3 生成MQTT登录参数

华为云提供的MQTT账户信息生成在线小工具:

https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com

image-20220314161923312

生成密匙:

image-20220314161949887

ClientId  622ef2e8c4e6a958e356fe84_STM32_0_0_2022031408
Username  622ef2e8c4e6a958e356fe84_STM32
Password  c9bc1837fc5cba8728a5e7ad625e422799e9a96975e3836a0054ea8e00f9ae5d

4.4 主题订阅格式

在上面的步骤中,产品、设备、MQTT登录信息都已经创建好,接下来要考虑的的就是,如何登录华为云物联网平台,登录之后数据如何交互等问题。

(1)云平台地址

端口: 1883
域名: a161a58a78.iot-mqtts.cn-north-4.myhuaweicloud.com
IP地址: 121.36.42.100

(2)订阅主题

格式: $oc/devices/{device_id}/sys/messages/down
//订阅主题: 平台下发消息给设备
$oc/devices/622ef2e8c4e6a958e356fe84_STM32/sys/messages/down

(3)上报主题

格式: $oc/devices/{device_id}/sys/properties/report
//设备上报主题请求
$oc/devices/622ef2e8c4e6a958e356fe84_STM32/sys/properties/report
//上报的数据格式如下
{"services": [{"service_id": "STM32","properties":
{"temp":12,"humidity":21,"soil_moisture":15,"motor":1}}]}

参数说明:
device_id 设备ID这个字段,在创建设备时生成的。

service_id 这个字段填服务ID,这个ID在产品页面下面自定义模型的位置可以看到,这个服务ID就在创建
数据模型时设置的。

后面的{}里表示上传到服务器的数据属性字段。这个属性的名称是自己在自定义模型页面自己填的。

image-20220314163822196

4.5 软件模拟测试

为了验证云端设备的情况,这里先采用MQTT客户端软件模拟设备,登录云端服务器,测试数据交互。

MQTT客户端软件下载地址: https://download.csdn.net/download/xiaolong1126626497/18784012

(1)登录服务器

登录服务器,测试主题上报,订阅等功能。

image-20220314164327705

(2)查看上传的数据

image-20220314164503380

(3)消息跟踪

在设备详情页面开启消息跟踪,可以查看设备与服务器交互的过程,调试比较方便,如果数据不对,或者其他问题,在服务器消息跟踪页面可以快速定位问题。

image-20220314164600727

5. 上位机软件开发

为了方便查看设备的环境温湿度、土壤湿度信息,远程控制电机浇花,还需要开发一款可视化界面软件。

华为云物联网平台提供了应用端开发的API接口,可以通过对应的API完成数据交互。

5.1 应用端开发接口

(1)查询设备列表

查询设备列表这个接口是查询在这个产品目录下有几个设备,返回设置设备的列表信息。

前面也说过,一个产品下可以创建很多个设备。

帮助文档地址: https://support.huaweicloud.com/api-iothub/iot_06_v5_0048.html

官方提供了API接口,可以直接获取产品下面的所有设备详细信息返回。

关于请求参数,返回结果的字段含义,在帮助文档里有详细介绍。

接口的在线调试地址:https://apiexplorer.developer.huaweicloud.com/apiexplorer/doc?product=IoTDA&api=ListDevices

第一次使用接口时,可以使用在线调试接口测试参数,交互过程。

URL格式: /v5/iot/{project_id}/devices
示例:
https://iotda.cn-north-4.myhuaweicloud.com/v5/iot/611f253373344433821fb63448091eec/devices

响应的数据:

{
 "devices": [
  {
   "app_id": "e91f518007424be0bbe2763d0e2e1c0d",
   "app_name": "DefaultApp_622ezesm",
   "device_id": "622ef2e8c4e6a958e356fe84_STM32",
   "node_id": "STM32",
   "gateway_id": "622ef2e8c4e6a958e356fe84_STM32",
   "device_name": "浇花设备",
   "node_type": "GATEWAY",
   "description": null,
   "fw_version": null,
   "sw_version": null,
   "device_sdk_version": null,
   "product_id": "622ef2e8c4e6a958e356fe84",
   "product_name": "浇花神器",
   "status": "OFFLINE",
   "tags": []
  }
 ],
 "page": {
  "count": 1,
  "marker": "622ef8e6b617d2412bae4c7e"
 }
}

image-20220314170401019

(2)查询设备属性

通过查询属性的接口,可以主动请求获取设备详细属性。

流程是:应用层调用这个API接口---->请求服务器----->请求客户端设备------>返回给服务器----->返回给应用层调用处。

文档地址:https://support.huaweicloud.com/api-iothub/iot_06_v5_0034.html

image-20220314171229746

在线调试接口:https://apiexplorer.developer.huaweicloud.com/apiexplorer/debug?product=IoTDA&api=ListProperties

采用MQTT客户端软件模拟,设备登录,再使用上面的调试接口调试。

image-20220314171455527

image-20220314171834632

image-20220314171852537

数据总结:

设备端响应的主题格式:
$oc/devices/{device_id}/sys/properties/get/response/request_id={request_id}

示 例:
$oc/devices/622ef2e8c4e6a958e356fe84_STM32/sys/properties/get/response/request_id=43408b9d-41d1-48a6-a2e7-ece314dbd0a3

设备端响应的数据格式:
{"services": [{"service_id": "STM32","properties":{"temp":14,"humidity":22,"soil_moisture":16,"motor":0}}]}

应用端上位机收到设备端的响应数据:
{
 "response": {
  "services": [
   {
    "service_id": "STM32",
    "properties": {
     "temp": 14,
     "humidity": 22,
     "soil_moisture": 16,
     "motor": 0
    }
   }
  ]
 }
}

(3)修改设备属性

设备的产品模型中定义了物联网平台可向设备下发的属性,应用服务器可调用此接口向指定设备下属性。平台负责将属性以同步方式发送给设备,并将设备执行属性结果同步返回。

文档地址: https://support.huaweicloud.com/api-iothub/iot_06_v5_0035.html

在线调试地址: https://apiexplorer.developer.huaweicloud.com/apiexplorer/doc?product=IoTDA&api=UpdateProperties

请求URL: 
https://iotda.cn-north-4.myhuaweicloud.com/v5/iot/611f253373344433821fb63448091eec/devices/622ef2e8c4e6a958e356fe84_STM32/properties

请求体:
{
 "services": [
  {
   "service_id": "STM32",
   "properties": {
    "motor": 1
   }
  }
 ]
}

image-20220314173005178

设备响应格式:https://support.huaweicloud.com/api-iothub/iot_06_v5_3008.html

image-20220314212257609

image-20220314212155389

响应的主题格式:
$oc/devices/{device_id}/sys/properties/set/response/request_id={request_id}

示例: 
$oc/devices/622ef2e8c4e6a958e356fe84_STM32/sys/properties/set/response/request_id=ad492c4f-7498-4243-b6ae-93089eda1945
 
响应的数据:
{"result_code": 0,"result_desc": "success"}

image-20220314212647992

5.2 创建IAM账户

创建一个IAM账户,方便接下来使用API接口访问华为云服务时,生成token登录密匙。

地址:https://console.huaweicloud.com/iam/?region=cn-north-4#/iam/users

(1)创建用户

image-20220314174027401

(2)填充参数

image-20220314174139690

(3)完成创建

image-20220314174215442

User     Name	Access Key Id	Secret Access Key
ds_abc	IQJXEPFKUALTIBKYKJ0Q	xweOS1ohe9c5KQ2fqyYPhwmdv37WicxGOaybi1FC

5.3 开发上位机软件

(1)开发环境介绍

上位机软件采用Qt框架设计,Qt是一个跨平台的C++图形用户界面应用程序框架。Qt是一个1991年由Qt Company开发的跨平台C++图形用户界面应用程序开发框架。它既可以开发GUI程序,也可用于开发非GUI程序,比如控制台工具和服务器。简单来说,QT可以很轻松的帮你做带界面的软件,甚至不需要你投入很大精力。

QT官网: https://www.qt.io/

image-20220314143105032

(2)学习教程

QT入门实战专栏: https://blog.csdn.net/xiaolong1126626497/category_11400392.html

(3)实现效果

image-20220314220429689

image-20220314220612175

image-20220314221035015

(4)核心代码

//手动浇花
void Widget::on_pushButton_ditu_clicked()
{
    //修改属性
    function_select=2;

    QString requestUrl;
    QNetworkRequest request;

    //设置请求地址
    QUrl url;

    //修改属性的地址
    requestUrl="https://iotda.cn-north-4.myhuaweicloud.com/v5/iot/611f253373344433821fb63448091eec/devices/622ef2e8c4e6a958e356fe84_STM32/properties";

    //设置数据提交格式
    request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));

    //设置token
    request.setRawHeader("X-Auth-Token",Token);

    //构造请求
    url.setUrl(requestUrl);

    request.setUrl(url);

    //打包请求参数赋值
    QString post_param=QString("{"service_id":"STM32","properties":{"motor":1}}");
    //发送请求
    manager->put(request, post_param.toUtf8());
}

//查询所有设备
void Widget::Get_AllDevice()
{
    //查询设备列表
    function_select=1;

    QString requestUrl;
    QNetworkRequest request;

    //设置请求地址
    QUrl url;

    //设备列表请求地址
    requestUrl = QString("https://iotda.%1.myhuaweicloud.com/v5/iot/%2/devices?product_id=%3&is_cascade_query=false&limit=10&marker=ffffffffffffffffffffffff&offset=0")
                 .arg(SERVER_ID)
            .arg(PROJECT_ID)
            .arg(Product_id);

    //设置数据提交格式
    request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));

    //设置token
    request.setRawHeader("X-Auth-Token",Token);

    //构造请求
    url.setUrl(requestUrl);

    request.setUrl(url);

    //发送请求
    manager->get(request);
}

//查询设备属性
void Widget::Get_device_properties()
{
    //表示查询设备属性
    function_select=0;

    QString requestUrl;
    QNetworkRequest request;

    //设置请求地址
    QUrl url;

    if(device_id_lis.size()<=0)
    {
        //显示错误代码
        QMessageBox::information(this,"提示","未选择设备,请先获取设备列表n选择设备后重试.",QMessageBox::Ok,QMessageBox::Ok);
        return;
    }

    //获取token请求地址
    requestUrl = QString("https://iotda.%1.myhuaweicloud.com/v5/iot/%2/devices/%3/properties?service_id=%4")
                 .arg(SERVER_ID)
            .arg(PROJECT_ID)
            .arg(device_id_lis.at(ui->comboBox->currentIndex()))
            .arg(service_id);

    //自己创建的TCP服务器,测试用
    //requestUrl="http://10.0.0.6:8080";

    //设置数据提交格式
    request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));

    //设置token
    request.setRawHeader("X-Auth-Token",Token);

    //构造请求
    url.setUrl(requestUrl);

    request.setUrl(url);

    //发送请求
    manager->get(request);
}

6. STM32设备端开发

基于STM32+物联网设计的浇花神器-(华为云IOT)(STM32设备端源代码).zip

https://download.csdn.net/download/xiaolong1126626497/85623120

基于STM32+物联网设计的浇花神器-(华为云IOT)(上位机源码与可执行文件).zip

https://download.csdn.net/download/xiaolong1126626497/85623171

6.1 设备实物图

image-20220314225450773.png
image-20220315004128180.png
image-20220315012115581.png
9)ZPR5ZTLKT1V945T)LI420.jpg
image.png
1.jpg
image-20220315015914129.png
image-20220315015941794.png
image-20220315020302958.png

6.3 运行过程

(1)下载程序

image-20220315015018948

(2)正常上电串口调试助手输出。

image-20220315012115581

(3)登录成功后,设备上线:

image-20220315013202574

(4)浇水测试

image-20220315015914129

(5)更新数据

image-20220315020302958

image-20220315020317962

6.4 土壤湿度传感器代码

image-20220315004128180

#include "adc.h"

/*
函数功能:初始化ADC1为规则通道
转换通道1-->PA1
*/
void AdcInit(void)
{
	/*开启端口时钟*/
	RCC->APB2ENR|=1<<2;  //PA
	GPIOA->CRL&=0xFFFFFF0F;
	GPIOA->CRL|=0x00000000; //配置PA1为模拟输入

	/*开启ADC1的外设时钟*/
	RCC->APB2ENR|=1<<9; 

	/*开启ADC1的外设复位时钟*/
	RCC->APB2RSTR|=1<<9;     //开始复位
	RCC->APB2RSTR&=~(1<<9);  //停止复位
		
	/*配置ADC预分频器*/
	RCC->CFGR&=~(0X3<<14);  //清除预分频寄存器
	RCC->CFGR|=0x2<<14;     //配置ADC时钟为12MHZ.注意:ADC的时钟不能超过14MHZ
	

	/*ADC相关的基本配置*/
	ADC1->CR1&=~(0xF<<16);   //ADC工作在独立模式
	ADC1->CR2|=1<<20;        //使用外部事件启动转换。
	ADC1->CR2|=0X7<<17;      //选择启动规则通道组转换的外部事件
	ADC1->CR2&=~(1<<11);     //0:数据右对齐;
	ADC1->CR2&=~(1<<1);      //0:单次转换模式;
	
	/*ADC输入通道配置*/
	ADC1->SQR1&=~(0XF<<20);  //规则通道序列长度  : 1个转换
	
	/*ADC通道1采样时间配置*/
	ADC1->SMPR2&=~(0x7<<(3*1));   
	ADC1->SMPR2|=0x7<<(3*1); //通道1的采样时间239.5周期
	ADC1->CR2|=1<<0;         //1:开启ADC并启动转换。
	
	ADC1->CR2|=1<<3;         //1:初始化校准寄存器。
	while(ADC1->CR2&1<<3){}   //等待校准结束 
	ADC1->CR2|=1<<2;         //1:开始校准。
	while(ADC1->CR2&1<<2){}  //等待校准结束
}



/*
获取ch通道的ADC转换值
ch的范围:0-17
16 :内部温度
17 :内部参考电压值
0-15 :外部输入引脚
*/
u16 GetAdcCHxDATA(u8 ch)
{
	ADC1->SQR3&=0XFFFFFFE0;  //E=:1110  清除通道号
	ADC1->SQR3|=ch;          //设置要转换的通道
	ADC1->CR2|=1<<22;        //开始转换规则通道
	while(!ADC1->SR&1<<1){}  //等待规则通道转换完毕
	return ADC1->DR;         //返回采集的值
}

/*
dat=temp*3.3/4095;        //转换的电压值
dat=(1.43-dat)/0.0043+25; //实际温度=(1.43-测出的电压)/0.0043+25;
*/

6.5 DHT11温湿度传感器代码

#include "dht11.h"
#include "delay.h"

//复位DHT11
void DHT11_Rst(void)	   
{                 
	  DHT11_IO_OUT(); 	//SET OUTPUT
    DHT11_DQ_OUT=0; 	//拉低DQ
    DelayMs(20);    	//拉低至少18ms
    DHT11_DQ_OUT=1; 	//DQ=1 
	  DelayUs(30);     	//主机拉高20~40us
}
//等待DHT11的回应
//返回1:未检测到DHT11的存在
//返回0:存在
u8 DHT11_Check(void) 	   
{   
	u8 retry=0;
	DHT11_IO_IN();//SET INPUT	 
    while (DHT11_DQ_IN&&retry<100)//DHT11会拉低40~80us
	{
		retry++;
		DelayUs(1);
	};	 
	if(retry>=100)return 1;
	else retry=0;
    while (!DHT11_DQ_IN&&retry<100)//DHT11拉低后会再次拉高40~80us
	{
		retry++;
		DelayUs(1);
	};
	if(retry>=100)return 1;	    
	return 0;
}
//从DHT11读取一个位
//返回值:1/0
u8 DHT11_Read_Bit(void) 			 
{
 	u8 retry=0;
	while(DHT11_DQ_IN&&retry<100)//等待变为低电平
	{
		retry++;
		DelayUs(1);
	}
	retry=0;
	while(!DHT11_DQ_IN&&retry<100)//等待变高电平
	{
		retry++;
		DelayUs(1);
	}
	DelayUs(40);//等待40us
	if