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

1. 前言

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

2. 整体系统设计

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

基于STM32设计的智慧浇花系统(华为云IOT)_第1张图片

基于STM32设计的智慧浇花系统(华为云IOT)_第2张图片

基于STM32设计的智慧浇花系统(华为云IOT)_第3张图片

基于STM32设计的智慧浇花系统(华为云IOT)_第4张图片

3. 硬件选型

3.1 STM32开发板

基于STM32设计的智慧浇花系统(华为云IOT)_第5张图片

基于STM32设计的智慧浇花系统(华为云IOT)_第6张图片

3.2 土壤湿度传感器

基于STM32设计的智慧浇花系统(华为云IOT)_第7张图片

3.3 ESP8266 WIFI

基于STM32设计的智慧浇花系统(华为云IOT)_第8张图片

3.4 环境温湿度

基于STM32设计的智慧浇花系统(华为云IOT)_第9张图片

3.5 水泵电机

基于STM32设计的智慧浇花系统(华为云IOT)_第10张图片

基于STM32设计的智慧浇花系统(华为云IOT)_第11张图片

4. 华为云物联网平台

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

4.1 创建产品

(1)登录官网

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

https://www.huaweicloud.com

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

基于STM32设计的智慧浇花系统(华为云IOT)_第12张图片

基于STM32设计的智慧浇花系统(华为云IOT)_第13张图片

(2)创建产品

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

image-20220314154410232

(3)填写产品的信息

基于STM32设计的智慧浇花系统(华为云IOT)_第14张图片

(4)创建成功

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

基于STM32设计的智慧浇花系统(华为云IOT)_第15张图片

(5)创建服务器ID

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

基于STM32设计的智慧浇花系统(华为云IOT)_第16张图片

基于STM32设计的智慧浇花系统(华为云IOT)_第17张图片

(6)添加属性

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

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

基于STM32设计的智慧浇花系统(华为云IOT)_第18张图片

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

基于STM32设计的智慧浇花系统(华为云IOT)_第19张图片

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

基于STM32设计的智慧浇花系统(华为云IOT)_第20张图片

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

基于STM32设计的智慧浇花系统(华为云IOT)_第21张图片

【5】所有的属性如下

基于STM32设计的智慧浇花系统(华为云IOT)_第22张图片

4.2 创建设备

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

(1)创建设备

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

基于STM32设计的智慧浇花系统(华为云IOT)_第23张图片

(2)单设备注册

根据提示填充设备参数。

基于STM32设计的智慧浇花系统(华为云IOT)_第24张图片

(3)保存设备密匙

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

基于STM32设计的智慧浇花系统(华为云IOT)_第25张图片

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

基于STM32设计的智慧浇花系统(华为云IOT)_第26张图片

(4)查看设备详情

基于STM32设计的智慧浇花系统(华为云IOT)_第27张图片

4.3 生成MQTT登录参数

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

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

基于STM32设计的智慧浇花系统(华为云IOT)_第28张图片

生成密匙:

基于STM32设计的智慧浇花系统(华为云IOT)_第29张图片

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就在创建
数据模型时设置的。

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

基于STM32设计的智慧浇花系统(华为云IOT)_第30张图片

4.5 软件模拟测试

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

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

(1)登录服务器

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

基于STM32设计的智慧浇花系统(华为云IOT)_第31张图片

(2)查看上传的数据

基于STM32设计的智慧浇花系统(华为云IOT)_第32张图片

(3)消息跟踪

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

基于STM32设计的智慧浇花系统(华为云IOT)_第33张图片

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"
 }
}

基于STM32设计的智慧浇花系统(华为云IOT)_第34张图片

(2)查询设备属性

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

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

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

基于STM32设计的智慧浇花系统(华为云IOT)_第35张图片

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

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

基于STM32设计的智慧浇花系统(华为云IOT)_第36张图片

基于STM32设计的智慧浇花系统(华为云IOT)_第37张图片

基于STM32设计的智慧浇花系统(华为云IOT)_第38张图片

数据总结:

设备端响应的主题格式:
$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
   }
  }
 ]
}

基于STM32设计的智慧浇花系统(华为云IOT)_第39张图片

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

基于STM32设计的智慧浇花系统(华为云IOT)_第40张图片

基于STM32设计的智慧浇花系统(华为云IOT)_第41张图片

响应的主题格式:
$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"}

基于STM32设计的智慧浇花系统(华为云IOT)_第42张图片

5.2 创建IAM账户

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

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

(1)创建用户

基于STM32设计的智慧浇花系统(华为云IOT)_第43张图片

(2)填充参数

基于STM32设计的智慧浇花系统(华为云IOT)_第44张图片

(3)完成创建

基于STM32设计的智慧浇花系统(华为云IOT)_第45张图片

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/

基于STM32设计的智慧浇花系统(华为云IOT)_第46张图片

(2)学习教程

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

(3)实现效果

基于STM32设计的智慧浇花系统(华为云IOT)_第47张图片

基于STM32设计的智慧浇花系统(华为云IOT)_第48张图片

基于STM32设计的智慧浇花系统(华为云IOT)_第49张图片

(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 设备实物图


基于STM32设计的智慧浇花系统(华为云IOT)_第50张图片
基于STM32设计的智慧浇花系统(华为云IOT)_第51张图片
基于STM32设计的智慧浇花系统(华为云IOT)_第52张图片
基于STM32设计的智慧浇花系统(华为云IOT)_第53张图片
基于STM32设计的智慧浇花系统(华为云IOT)_第54张图片
基于STM32设计的智慧浇花系统(华为云IOT)_第55张图片
基于STM32设计的智慧浇花系统(华为云IOT)_第56张图片
基于STM32设计的智慧浇花系统(华为云IOT)_第57张图片

6.3 运行过程

(1)下载程序

基于STM32设计的智慧浇花系统(华为云IOT)_第58张图片

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

基于STM32设计的智慧浇花系统(华为云IOT)_第59张图片

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

基于STM32设计的智慧浇花系统(华为云IOT)_第60张图片

(4)浇水测试

基于STM32设计的智慧浇花系统(华为云IOT)_第61张图片

(5)更新数据

基于STM32设计的智慧浇花系统(华为云IOT)_第62张图片

基于STM32设计的智慧浇花系统(华为云IOT)_第63张图片

6.4 土壤湿度传感器代码

基于STM32设计的智慧浇花系统(华为云IOT)_第64张图片

#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(DHT11_DQ_IN)return 1;
	else return 0;		   
}

//从DHT11读取一个字节
//返回值:读到的数据
u8 DHT11_Read_Byte(void)    
{        
    u8 i,dat;
    dat=0;
	for (i=0;i<8;i++) 
	{
   		dat<<=1; 
	    dat|=DHT11_Read_Bit();
    }						    
    return dat;
}


//从DHT11读取一次数据
//temp:温度值(范围:0~50°)
//humi:湿度值(范围:20%~90%)
//返回值:0,正常;1,读取失败
u8 DHT11_Read_Data(u8 *temp,u8 *humi)    
{        
 	u8 buf[5];
	u8 i;
	DHT11_Rst();
	//printf("------------------------\r\n");
	if(DHT11_Check()==0)
	{
		for(i=0;i<5;i++)//读取40位数据
		{
			buf[i]=DHT11_Read_Byte();
		}
		if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
		{
			*humi=buf[0];
			*temp=buf[2];
		}
	}else return 1;
	return 0;	    
}


//初始化DHT11的IO口 DQ 同时检测DHT11的存在
//返回1:不存在
//返回0:存在    	 
u8 DHT11_Init(void)
{
	RCC->APB2ENR|=1<<2;    //使能PORTA口时钟 
	GPIOA->CRL&=0XFF0FFFFF;//PORTA.5 推挽输出
	GPIOA->CRL|=0X00300000;
	GPIOA->ODR|=1<<5;      //输出1				    
	DHT11_Rst();
	return DHT11_Check();
}

6.6 主函数逻辑代码

#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 "motor.h"
#include "oled.h"
#include "dht11.h"
#include "adc.h"

/*
硬件连接方式:

1. ESP8266 WIFI接线
ATK-ESP8266串口WIFI模块与STM32的串口2相连接。
PA2(TX)--RXD 模块接收脚
PA3(RX)--TXD 模块发送脚
GND---GND 地
VCC---VCC 电源(3.3V~5.0V)

2. TFT 1.44 寸彩屏接线
GND   电源地
VCC   接5V或3.3v电源
SCL   接PC8(SCL)
SDA   接PC9(SDA)
RST   接PBPC10
DC    接PB7
CS    接PB8
BL	  接PB11

3. DHT11 温湿度
VCC--VCC
GND---GND
DAT---PA5 

4. 浇水电机
GND---GND
VCC---5V
AO----PA4


5. 土壤湿度
GND---GND
VCC---3.3V
AO----PA1


6. 板载LED灯接线
LED1---PA8
LED2---PD2


7. 板载按键接线
K0---PA0 
K1---PC5 
K2---PA15

*/

//华为物联网服务器的设备信息
#define MQTT_ClientID "622ef2e8c4e6a958e356fe84_STM32_0_0_2022031408"
#define MQTT_UserName "622ef2e8c4e6a958e356fe84_STM32"
#define MQTT_PassWord "c9bc1837fc5cba8728a5e7ad625e422799e9a96975e3836a0054ea8e00f9ae5d"

//订阅与发布的主题
#define SET_TOPIC  "$oc/devices/622ef2e8c4e6a958e356fe84_STM32/sys/messages/down"  //订阅
#define POST_TOPIC "$oc/devices/622ef2e8c4e6a958e356fe84_STM32/sys/properties/report"  //发布

//设置连接的路由器信息
#define CONNECT_WIFI  "Xiaomi_meizi6"   //将要连接的路由器名称 --不要出现中文、空格等特殊字符
#define CONNECT_PASS "12170307yu"       //将要连接的路由器密码

#define CONNECT_SERVER_IP "121.36.42.100"   //服务器IP地址
#define CONNECT_SERVER_PORT 1883            //服务器端口号

char mqtt_message[200];//上报数据缓存区


//JTAG模式设置,用于设置JTAG的模式
//mode:jtag,swd模式设置;00,全使能;01,使能SWD;10,全关闭;	   
#define JTAG_SWD_DISABLE   0X02
#define SWD_ENABLE         0X01
#define JTAG_SWD_ENABLE    0X00		  
void JTAG_Set(u8 mode)
{
	u32 temp;
	temp=mode;
	temp<<=25;
	RCC->APB2ENR|=1<<0;     //开启辅助时钟	   
	AFIO->MAPR&=0XF8FFFFFF; //清除MAPR的[26:24]
	AFIO->MAPR|=temp;       //设置jtag模式
} 


u32 motor_time_cnt=0;
u8 motor_flag=0; //灌溉标志

//开启抽水点击、浇花
void open_motor()
{
    motor_flag=1; //开始灌溉标志
    motor_time_cnt=0; //计数器--定时
    MOTOR=1; //开始灌溉
}

//关闭抽水电机
void close_motor()
{
     motor_flag=0;
     MOTOR=0; //停止灌溉
}

u8 temp;
u8 humidity;
u16 soil_moisture;
char request_id[100];
char data_buff[300];

int main()
{
    u8 esp8266_state=0;
    u8 key;
    u8 i;
    u32 time_cnt=0;

    
    JTAG_Set(JTAG_SWD_DISABLE); //释放PA15
    LED_Init();
    KEY_Init();
    USART1_Init(115200);
    Moto_Init();  //电机初始化
    USART2_Init(115200);//串口-WIFI
    TIMER2_Init(72,20000); //超时时间20ms
    DHT11_Init();		//初始化DHT11
    AdcInit();  //土壤湿度传感器--ADC检测
    Lcd_Init(); //LCD初始化
    Lcd_Clear(0); //清屏为黑色
    LCD_LED_SET;//通过IO控制背光亮		
    
    printf("正在初始化WIFI请稍等.\r\n");
    
    for(i=0;i<5;i++)
    {
        if(ESP8266_Init()==0)
        {
            esp8266_state=1;
            break;
        }
        else
        {
            esp8266_state=0;
            printf("ESP8266硬件检测错误.\n");  
        }
    }
  
   if(esp8266_state)
   {
       printf("准备连接服务器....\r\n");
        //非加密端口
        printf("WIFI:%d\n",ESP8266_STA_TCP_Client_Mode(CONNECT_WIFI,CONNECT_PASS,CONNECT_SERVER_IP,CONNECT_SERVER_PORT,1));
         
        //2. MQTT协议初始化	
        MQTT_Init(); 

        //3. 连接服务器  
        for(i=0;i<5;i++)
        {
            if(MQTT_Connect(MQTT_ClientID,MQTT_UserName,MQTT_PassWord)==0)
            {
                esp8266_state=1;
                break;
            }
            esp8266_state=0;
            printf("服务器连接失败,正在重试...\n");
            delay_ms(500);
        }
        printf("服务器连接成功.\n");

        //3. 订阅主题
        if(MQTT_SubscribeTopic(SET_TOPIC,0,1))
        {
           printf("主题订阅失败.\n");
        }
        else
        {
           printf("主题订阅成功.\n");
        } 
   }
	 
	 while(1)
	 {
        //按键可以测试浇花
        key=KEY_Scan(0);
        if(key==2)
        {
            LED1=0;  //亮灯--表示开锁
            time_cnt=0;
            
            //开始浇水
            open_motor();
            
            printf("启动电机灌溉..\r\n");
        }
        else if(key==3)
        {
            LED2=!LED2;
        } 

        DelayMs(10);
        time_cnt++;
        motor_time_cnt++;
        
        //如果需要灌溉
        if(motor_flag)
        {
            //5秒后停止灌溉
            if(motor_time_cnt>500)
            {
                close_motor();
                printf("灌溉电机停止..\r\n");
            }
        }
         
        if(time_cnt>=100)
        {
            time_cnt=0;
            LED1=!LED1;
            
            soil_moisture=GetAdcCHxDATA(1);   //获取一次转换值    //2099
            printf("土壤湿度:%d\r\n",soil_moisture);
            if(DHT11_Read_Data(&temp,&humidity))
            {
                printf("温度读取失败.\r\n");
            }
            printf("环境温度:%d\r\n环境湿度:%d\r\n",temp,humidity);
            
            //Lcd_Clear(0); //清屏为黑色
            
            sprintf(mqtt_message,"H1:%d",soil_moisture);
            Gui_DrawFont_GBK16(0,16*0,RED,GRAY0,(u8*)mqtt_message);	
            
            sprintf(mqtt_message,"H2:%d",humidity);
            Gui_DrawFont_GBK16(0,16*1,RED,GRAY0,(u8*)mqtt_message);
            
            sprintf(mqtt_message,"T2:%d",temp);
            Gui_DrawFont_GBK16(0,16*2,RED,GRAY0,(u8*)mqtt_message);
            
            //土壤湿度越高,ADC得到的值越小
            
            //土壤比较干,启动浇水
            if(soil_moisture>4090)
            {
                 //开始浇水
                 open_motor();
            }
            
            
            //上报数据
            sprintf(mqtt_message,"{\"services\": [{\"service_id\":\"STM32\",\"properties\":{\"temp\":%d,\"humidity\":%d,\"soil_moisture\":%d}}]}",
            temp,humidity,soil_moisture);
            MQTT_PublishData(POST_TOPIC,mqtt_message,0);
            printf("更新数据.\r\n");
            
        }
			 
        // 接收WIFI返回的数据
        if(USART2_RX_FLAG)
        {
            USART2_RX_BUFFER[USART2_RX_CNT]='\0';
            
		    printf("UART3收到数据.....\r\n");
            //向串口打印服务器返回的数据
            for(i=0;i<USART2_RX_CNT;i++)
            {
                printf("%c",USART2_RX_BUFFER[i]);
            }
            
            //如果是下发了属性
            if(USART2_RX_CNT>5)
            {
                //使用字符串查找函数
                //设置属性,浇水
                //"motor":1
                if(strstr((char*)&USART2_RX_BUFFER[5],"properties/set/request_id"))
                {
                    char *p=NULL;
                    p=strstr((char*)&USART2_RX_BUFFER[5],"request_id");
                    if(p)
                    {        
                        //解析数据
                        //$oc/devices/6210e8acde9933029be8facf_dev1/sys/properties/get/request_id=5f359b5c-542f-460e-9f51-85e82150ff4a{"service_id":"gps"} 
                        strncpy(request_id,p,47);      
                    }
                    
                      //上报数据
                    sprintf(mqtt_message,"{\"result_code\": 0,\"result_desc\": \"success\"}");
                    
                    sprintf(data_buff,"$oc/devices/622ef2e8c4e6a958e356fe84_STM32/sys/properties/set/response/%s",
                    request_id);
                    
                    MQTT_PublishData(data_buff,mqtt_message,0);
                    
                    printf("发布主题:%s\r\n",data_buff);
                    printf("发布数据:%s\r\n",mqtt_message);
                    
                    //开始浇水
                    open_motor();
                    
                }
                //获取属性
                else if(strstr((char*)&USART2_RX_BUFFER[5],"properties/get/request_id"))
                {
                    char *p=NULL;
                    p=strstr((char*)&USART2_RX_BUFFER[5],"request_id");
                    if(p)
                    {        
                        //解析数据
                        //$oc/devices/6210e8acde9933029be8facf_dev1/sys/properties/get/request_id=5f359b5c-542f-460e-9f51-85e82150ff4a{"service_id":"gps"} 
                        strncpy(request_id,p,47);      
                    }
                    
                    //上报数据
                    sprintf(mqtt_message,"{\"services\": [{\"service_id\":\"STM32\",\"properties\":{\"temp\":%d,\"humidity\":%d,\"soil_moisture\":%d}}]}",
                    humidity,temp,soil_moisture);
                    
                    sprintf(data_buff,"$oc/devices/622ef2e8c4e6a958e356fe84_STM32/sys/properties/get/response/%s",
                    request_id);
                    
                    MQTT_PublishData(data_buff,mqtt_message,0);
                    
                    printf("发布主题:%s\r\n",data_buff);
                    printf("发布数据:%s\r\n",mqtt_message);
                }
           
                USART2_RX_CNT=0;
                USART2_RX_FLAG=0;
            }
        }
	 }
}

6.7 硬件接线说明

1. ESP8266 WIFI接线
ATK-ESP8266串口WIFI模块与STM32的串口2相连接。
PA2(TX)--RXD 模块接收脚
PA3(RX)--TXD 模块发送脚
GND---GND 地
VCC---VCC 电源(3.3V~5.0V)
 
2. TFT 1.44 寸彩屏接线
GND   电源地
VCC   接5V或3.3v电源
SCL   接PC8(SCL)
SDA   接PC9(SDA)
RST   接PBPC10
DC    接PB7
CS    接PB8
BL	  接PB11

3. DHT11 温湿度
VCC--VCC
GND---GND
DAT---PA5 

4. 浇水电机
GND---GND
VCC---5V
AO----PA4


5. 土壤湿度
GND---GND
VCC---3.3V
AO----PA1


6. 板载LED灯接线
LED1---PA8
LED2---PD2


7. 板载按键接线
K0---PA0 
K1---PC5 
K2---PA15

你可能感兴趣的:(智能家居与物联网项目实战,物联网,华为云,stm32)