基于STM32+华为云IOT设计的智能温室大棚监控系统

描述

一、项目背景

当前文章介绍基于STM32单片机的智能温室大棚监控系统,当前系统由温湿度传感器、二氧化碳传感器、光敏电阻传感器、土壤湿度传感器笨时温宏大棚中内作物生长环境因子主要包括温度、湿度、光度、土壤湿度传感、二氧化碳浓度等参数进行监控。

采集数据,判断是否在系统设定上限、下限范围,如果超出了上限下限蜂鸣器报警、通风系统、LED补光系统、水泵系统就会启也可以通过手机APP和华为云华为云物联网云平台对温室大棚中的数据进行修改和设定新的数据。

本设计整体主要采用STM32单片机为核心、温湿度传感器、二氧化碳传感器、光敏电阻传感器、土壤湿度传感器、通风系统、LED补光系统、水泵系统组成。

(1) 温湿度传感器: 主要对温室大棚中农作物环境进行温湿度监控,把数据传到控制系统,由控制系统传到OLED显示屏上显示出来。

(2) 二氧化碳传感器: 工作过程对温室大棚中的农作物环境二氧化碳浓度进行监控采集数据,把数据传到控制系统后,再把控制系统中的当前环境数据传显示屏上显示出来。

(3) 光敏电阻传感器: 工作过程主要通过对温室大棚中的农作物环境光照强度进行监控采集数据,把数据传到控制系统后,再从控制系统的数据传到显示屏上显示。

(4) 土壤湿度传感器: 工作过程对温室大棚中的农作物生长环境的土壤湿度进行监控采集数据,把数据传到控制系统中,再从控制系统中的数据传到显示屏上显示出来。

(5) OLED显示屏: 主要用来对二氧化碳、温湿度、光照强度以及土壤湿度传感器中的数据显示出来。

(6) 蜂鸣器模块: 主要对二氧化碳浓度、温湿度、土壤湿度、光照强度等传感器的采集数据是否高过或低于上限、下限值时蜂鸣器报警等功能,并提醒用户。

(7) 继电器模块: 主要通过把温湿度、土壤湿度传感器中的温湿度过高时或过低时,把温湿度转换成电信号,使通风、水泵启动等功能。

(8) 通风系统: 当温室大棚中环境温度过高时,通风系统启动对室内进行通风,使温度降下到设定值内通风系统关闭停止工作。

(9) 水泵系统: 当土壤湿度传感器检测土壤湿度低于下限值时,水泵系统开启进行浇水灌溉,当土壤湿度到达土壤湿度传感器上下限内,水泵系统关闭停止工作。

(10) LED补光系统: 通过光敏电阻传感器检测温室大棚中环境光照强度低于下限值时,LED补光系统开启对农作物进行补光,当光敏电阻传感器检测达到上下限内LED补光系统关闭停止补光。

(11) 按键模块: 主要用来调采集数据模块的上、下限值,可以通过按键切换手动和自动和云端三种模式,手动按键控制通风系统、LED补光系统、水泵系统打开和关闭功能。

(12) WIFI模块: 通过控制系统数据处理之后传输给外网,手机APP主要用来接收传来的数据显示出来

(13). 上机模块: 监控各个传感器的采集数据工作情况,执行硬件工作状态,也可以通过手机和华为云物联网云平台切换手动以及自动控制模式,对各传感器的设置上下限值。

华为云华为云

二、硬件设计

【1】硬件设计

本系统硬件设计包括控制模块、传感器模块和执行模块三部分。

控制模块: 该模块使用STM32F103C8T6单片机作为主控制器,负责处理各个传感器的数据和控制执行模块。此外,控制模块还需要与各个执行模块和外部设备进行通信,以实现数据的处理和传输。

传感器模块: 传感器模块包括温湿度传感器、二氧化碳传感器、光敏电阻传感器和土壤湿度传感器,主要负责感应和采集生长环境的温湿度、二氧化碳浓度、光照强度和土壤湿度等参数,并将数据传输给控制模块处理。

执行模块: 执行模块包括通风系统、LED补光系统、水泵系统等,用于根据传感器采集到的数据直接或间接地调节生长环境因子,并保证生长环境达到稳定的状态。

【2】软件设计

软件设计主要分为以下四个模块:传感器数据采集模块、数据处理模块、控制模块和远程控制模块。

传感器数据采集模块: 该模块负责对传感器数据进行采集,包括温湿度传感器、二氧化碳传感器、光敏电阻传感器和土壤湿度传感器。采集到的数据通过串口接口发送给控制模块。

数据处理模块: 该模块负责对采集到的传感器数据进行处理,判断当前环境因子是否超出设定范围,如果超出,则触发报警和控制执行模块的操作。同时,该模块还要将处理后的数据发送给控制模块进行控制操作。

控制模块: 该模块负责控制执行模块,根据数据处理模块的指令,启动通风系统、LED补光系统、水泵系统等设备,以保证生长环境稳定和水平。

远程控制模块: 该模块实现通过手机APP和华为云IOT平台远程管理系统,对温室大棚中的数据进行修改和设定新的数据。用户可以通过手机APP或者华为云IOT平台,实时查看和修改温室大棚的环境因子,实现远程控制和管理。

三、华为云IOT平台开发

在华为云IOT平台上,需要进行设备接入、数据模型定义、规则引擎配置和应用开发等四个核心模块的开发。其中,设备接入模块包括设备注册、获取设备证书、建立连接等步骤,以保障设备与云平台之间的安全通信;数据模型定义模块需要根据实际需求定义相应的数据模型,包括上传数据格式、设备属性和服务等。规则引擎配置模块需要完成实时消息推送、远程控制和告警等功能。应用开发模块则是将完整的智能井盖系统进行打包,为用户提供统一的操作接口。

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

打开官网,搜索物联网,就能快速找到 设备接入IoTDA

华为云

3.1 物联网平台介绍

华为云物联网平台(IoT 设备接入云服务)提供海量设备的接入和管理能力,将物理设备联接到云,支撑设备数据采集上云和云端下发命令给设备进行远程控制,配合华为云其他产品,帮助我们快速构筑物联网解决方案。

使用物联网平台构建一个完整的物联网解决方案主要包括3部分:物联网平台、业务应用和设备。

物联网平台作为连接业务应用和设备的中间层,屏蔽了各种复杂的设备接口,实现设备的快速接入;同时提供强大的开放能力,支撑行业用户构建各种物联网解决方案。

设备可以通过固网、2G/3G/4G/5G、NB-IoT、Wifi等多种网络接入物联网平台,并使用LWM2M/CoAP、MQTT、HTTPS协议将业务数据上报到平台,平台也可以将控制命令下发给设备。

业务应用通过调用物联网平台提供的API,实现设备数据采集、命令下发、设备管理等业务场景。

华为云

3.2 开通物联网服务

地址: https://www.huaweicloud.com/product/iothub.html

华为云

开通标准版免费单元。

华为云华为云

开通之后,点击总览,查看接入信息。 我们当前设备准备采用MQTT协议接入华为云平台,这里可以看到MQTT协议的地址和端口号等信息。

华为云

总结:

 端口号:   MQTT (1883)| MQTTS (8883)    
 接入地址: a3433ab133.iot-mqtts.cn-north-4.myhuaweicloud.com

根据域名地址得到IP地址信息:

 Microsoft Windows [版本 10.0.19044.2846]
 (c) Microsoft Corporation。保留所有权利。
 ​
 C:Users11266>ping a3433ab133.iot-mqtts.cn-north-4.myhuaweicloud.com
 ​
 正在 Ping a3433ab133.iot-mqtts.cn-north-4.myhuaweicloud.com [121.36.42.100] 具有 32 字节的数据:
 来自 121.36.42.100 的回复: 字节=32 时间=37ms TTL=31
 来自 121.36.42.100 的回复: 字节=32 时间=37ms TTL=31
 来自 121.36.42.100 的回复: 字节=32 时间=36ms TTL=31
 来自 121.36.42.100 的回复: 字节=32 时间=37ms TTL=31
 ​
 121.36.42.100 的 Ping 统计信息:
     数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
 往返行程的估计时间(以毫秒为单位):
     最短 = 36ms,最长 = 37ms,平均 = 36ms
 ​
 C:Users11266>
华为云

MQTT协议接入端口号有两个,1883是非加密端口,8883是证书加密端口,单片机无法加载证书,所以使用1883端口比较合适。 接下来的ESP8266就采用1883端口连接华为云物联网平台。

3.3 创建产品

(1)创建产品

点击右上角创建产品。

华为云

(2)填写产品信息

根据自己产品名字填写,设备类型选择自定义类型。

(3)添加自定义模型

产品创建完成之后,点击进入产品详情页面,翻到最下面可以看到模型定义。

华为云

模型简单来说: 就是存放设备上传到云平台的数据。比如:环境温度、环境湿度、环境烟雾浓度、火焰检测状态图等等,这些我们都可以单独创建一个模型保存。

3.4 添加设备

产品是属于上层的抽象模型,接下来在产品模型下添加实际的设备。添加的设备最终需要与真实的设备关联在一起,完成数据交互。

(1)注册设备

点击右上角注册设备。

华为云

(2)根据自己的设备填写

在弹出的对话框里填写自己设备的信息。根据自己设备详细情况填写。

(3)保存设备信息

创建完毕之后,点击保存并关闭,得到创建的设备密匙信息。该信息在后续生成MQTT三元组的时候需要使用。

3.5 MQTT协议主题订阅与发布

(1)MQTT协议介绍

当前的设备是采用MQTT协议与华为云平台进行通信。

MQTT是一个物联网传输协议,它被设计用于轻量级的发布/订阅式消息传输,旨在为低带宽和不稳定的网络环境中的物联网设备提供可靠的网络服务。MQTT是专门针对物联网开发的轻量级传输协议。MQTT协议针对低带宽网络,低计算能力的设备,做了特殊的优化,使得其能适应各种物联网应用场景。目前MQTT拥有各种平台和设备上的客户端,已经形成了初步的生态系统。

MQTT是一种消息队列协议,使用发布/订阅消息模式,提供一对多的消息发布,解除应用程序耦合,相对于其他协议,开发更简单;MQTT协议是工作在TCP/IP协议上;由TCP/IP协议提供稳定的网络连接;所以,只要具备TCP协议栈的网络设备都可以使用MQTT协议。 本次设备采用的ESP8266就具备TCP协议栈,能够建立TCP连接,所以,配合STM32代码里封装的MQTT协议,就可以与华为云平台完成通信。

华为云的MQTT协议接入帮助文档在这里: https://support.huaweicloud.com/devg-iothub/iot_02_2200.html

华为云

业务流程:

华为云

(2)华为云平台MQTT协议使用限制

描述 限制
支持的MQTT协议版本 3.1.1
与标准MQTT协议的区别 支持Qos 0和Qos 1支持Topic自定义不支持QoS2不支持will、retain msg
MQTTS支持的安全等级 采用TCP通道基础 + TLS协议(最高TLSv1.3版本)
单帐号每秒最大MQTT连接请求数 无限制
单个设备每分钟支持的最大MQTT连接数 1
单个MQTT连接每秒的吞吐量,即带宽,包含直连设备和网关 3KB/s
MQTT单个发布消息最大长度,超过此大小的发布请求将被直接拒绝 1MB
MQTT连接心跳时间建议值 心跳时间限定为30至1200秒,推荐设置为120秒
产品是否支持自定义Topic 支持
消息发布与订阅 设备只能对自己的Topic进行消息发布与订阅
每个订阅请求的最大订阅数 无限制

(3)主题订阅格式

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

华为云

对于设备而言,一般会订阅平台下发消息给设备 这个主题。

设备想接收平台下发的消息,就需要订阅平台下发消息给设备 的主题,订阅后,平台下发消息给设备,设备就会收到消息。

(4)主题发布格式

对于设备来说,主题发布表示向云平台上传数据,将最新的传感器数据,设备状态上传到云平台。

这个操作称为:属性上报。

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

华为云

3.6 MQTT三元组

MQTT协议登录需要填用户ID,设备ID,设备密码等信息,就像我们平时登录QQ,微信一样要输入账号密码才能登录。MQTT协议登录的这3个参数,一般称为MQTT三元组。

接下来介绍,华为云平台的MQTT三元组参数如何得到。

(1)MQTT服务器地址

要登录MQTT服务器,首先记得先知道服务器的地址是多少,端口是多少。

帮助文档地址:https://console.huaweicloud.com/iotdm/?region=cn-north-4#/dm-portal/home

华为云

MQTT协议的端口支持1883和8883,它们的区别是:8883 是加密端口更加安全。但是单片机上使用比较困难,所以当前的设备是采用1883端口进连接的。

根据上面的域名和端口号,得到下面的IP地址和端口号信息: 如果设备支持填写域名可以直接填域名,不支持就直接填写IP地址。 (IP地址就是域名解析得到的)

 华为云的MQTT服务器地址:121.36.42.100
 华为云的MQTT端口号:1883

(2)生成MQTT三元组

华为云提供了一个在线工具,用来生成MQTT鉴权三元组: https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/

打开这个工具,填入设备的信息(也就是刚才创建完设备之后保存的信息),点击生成,就可以得到MQTT的登录信息了。

下面是打开的页面:

华为云

3.7 参考案例

华为云平台部署开发也可以参考这里:

https://bbs.huaweicloud.com/blogs/381072

【基于华为云IOT平台实现多节点温度采集(STM32+NBIOT)】

四、设计代码

【1】DHT11温湿度数据读取

以下是基于HAL库的STM32F103ZET6读取DHT11温湿度传感器的代码:

 #include "dht11.h"
 ​
 #define DHT11_GPIO_PORT    GPIOA
 #define DHT11_GPIO_PIN     GPIO_PIN_0
 ​
 /* DHT11引脚初始化 */
 void DHT11_Init()
 {
     GPIO_InitTypeDef GPIO_InitStruct = {0};
 ​
     /* 打开GPIO时钟 */
     __HAL_RCC_GPIOA_CLK_ENABLE();
 ​
     /* 配置GPIO为推挽输出模式 */
     GPIO_InitStruct.Pin = DHT11_GPIO_PIN;
     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
     HAL_GPIO_Init(DHT11_GPIO_PORT, &GPIO_InitStruct);
 }
 ​
 /* 从DHT11读取一次温湿度数据 */
 DHT11_Result_t DHT11_Read_Data()
 {
     uint8_t data[5] = {0};
     uint8_t check = 0;
     uint8_t i = 0;
 ​
     /* 向DHT11发送起始信号 */
     HAL_GPIO_WritePin(DHT11_GPIO_PORT, DHT11_GPIO_PIN, GPIO_PIN_RESET);
     HAL_Delay(20);
     HAL_GPIO_WritePin(DHT11_GPIO_PORT, DHT11_GPIO_PIN, GPIO_PIN_SET);
     HAL_Delay(30);
 ​
     /* 切换到输入模式等待DHT11的响应 */
     GPIO_InitTypeDef GPIO_InitStruct = {0};
     GPIO_InitStruct.Pin = DHT11_GPIO_PIN;
     GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
     GPIO_InitStruct.Pull = GPIO_PULLUP;
     HAL_GPIO_Init(DHT11_GPIO_PORT, &GPIO_InitStruct);
 ​
     /* 等待DHT11响应 */
     while (HAL_GPIO_ReadPin(DHT11_GPIO_PORT, DHT11_GPIO_PIN) == GPIO_PIN_SET);
 ​
     /* 等待DHT11发送完毕 */
     while (HAL_GPIO_ReadPin(DHT11_GPIO_PORT, DHT11_GPIO_PIN) == GPIO_PIN_RESET);
 ​
     /* 读取DHT11发送的数据 */
     for (i = 0; i < 5; i++) {
         uint8_t j = 0;
         for (j = 0; j < 8; j++) {
             /* 等待低电平结束 */
             while (HAL_GPIO_ReadPin(DHT11_GPIO_PORT, DHT11_GPIO_PIN) == GPIO_PIN_RESET);
 ​
             /* 等待高电平结束,并记录时间 */
             uint32_t t = 0;
             while (HAL_GPIO_ReadPin(DHT11_GPIO_PORT, DHT11_GPIO_PIN) == GPIO_PIN_SET) {
                 t++;
                 if (t > 100) break;
             }
 ​
             /* 根据时间计算数据位的值 */
             data[i] <<= 1;
             if (t >= 50) {
                 data[i] |= 0x01;
             }
         }
     }
 ​
     /* 切换回输出模式 */
     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
     HAL_GPIO_Init(DHT11_GPIO_PORT, &GPIO_InitStruct);
 ​
     /* 验证数据的正确性 */
     check = data[0] + data[1] + data[2] + data[3];
     if (check != data[4]) {
         return DHT11_ERROR_CHECKSUM;
     }
 ​
     /* 读取温湿度数据结果 */
     DHT11_Result_t result;
     result.humidity = data[0];
     result.temperature = data[2];
     return result;
 }

该代码基于HAL库的STM32F103ZET6读取DHT11温湿度传感器的代码示例:

 /* 获取温湿度数据 */
 void get_temperature_humidity()
 {
     DHT11_Result_t res = DHT11_Read_Data();
     if (res != DHT11_ERROR_CHECKSUM)
     {
         float humidity = res.humidity;
         float temperature = res.temperature;
         printf("温度:%.1f°C 湿度:%.1f%%RHrn", temperature, humidity);
     }
     else
     {
         printf("读取失败,请检查连接和传感器是否正常!rn");
     }
 }
 ​
 int main()
 {
     HAL_Init();
 ​
     // 初始化串口输出
     uart_init();
 ​
     printf("DHT11温湿度传感器读取测试开始rn");
 ​
     // 初始化DHT11引脚
     DHT11_Init();
 ​
     while (1)
     {
         // 读取温湿度传感器数据
         get_temperature_humidity();
         HAL_Delay(2000);
     }
 }

需要注意的是,在主函数中,我们先初始化了串口输出和DHT11引脚,然后通过循环一直读取温湿度数据并打印输出。其中,get_temperature_humidity()函数负责调用DHT11_Read_Data()函数读取温湿度数据,并将结果打印出来。如果读取失败,get_temperature_humidity()函数也会将错误信息打印出来。

【2】读取BH1750光敏传感器的值

以下是基于HAL库的STM32F103ZET6读取BH1750光照强度传感器的代码:

 #include "bh1750.h"
 ​
 /* BH1750地址 */
 #define BH1750_ADDR         0x23
 ​
 /* BH1750命令 */
 #define BH1750_CMD_POWER_ON      0x01
 #define BH1750_CMD_POWER_DOWN    0x00
 #define BH1750_CMD_RESET         0x07
 #define BH1750_CMD_ONE_TIME_H    0x20
 #define BH1750_CMD_ONE_TIME_L    0x23
 ​
 /* BH1750初始化配置 */
 void BH1750_Init()
 {
     I2C_HandleTypeDef hi2c1 = {0};
     hi2c1.Instance = I2C1;
     hi2c1.Init.ClockSpeed = 200000;
     hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
     hi2c1.Init.OwnAddress1 = 0;
     hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
     hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
     hi2c1.Init.OwnAddress2 = 0;
     hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
     hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
     HAL_I2C_Init(&hi2c1);
 ​
     uint8_t init_data = BH1750_CMD_POWER_ON;
     HAL_I2C_Master_Transmit(&hi2c1, BH1750_ADDR, &init_data, 1, HAL_MAX_DELAY);
 }
 ​
 /* 从BH1750读取光照强度数据 */
 float BH1750_Read_Lux()
 {
     I2C_HandleTypeDef hi2c1 = {0};
     hi2c1.Instance = I2C1;
     hi2c1.Init.ClockSpeed = 200000;
     hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
     hi2c1.Init.OwnAddress1 = 0;
     hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
     hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
     hi2c1.Init.OwnAddress2 = 0;
     hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
     hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
     HAL_I2C_Init(&hi2c1);
 ​
     /* 发送手动读取命令 */
     uint8_t cmd_data = BH1750_CMD_ONE_TIME_H;
     HAL_I2C_Master_Transmit(&hi2c1, BH1750_ADDR, &cmd_data, 1, HAL_MAX_DELAY);
 ​
     /* 等待读取完成 */
     HAL_Delay(180);
 ​
     /* 读取数据 */
     uint8_t buf[2];
     HAL_I2C_Master_Receive(&hi2c1, BH1750_ADDR, buf, 2, HAL_MAX_DELAY);
 ​
     /* 计算光照强度 */
     uint16_t val = (buf[0] << 8) | buf[1];
     float lux = val / 1.2;
     return lux;
 }

该代码首先在BH1750_Init()函数中初始化了I2C相关的参数,并使用HAL_I2C_Master_Transmit()函数向BH1750发送了开启电源的命令。在BH1750_Read_Lux()函数中,我们首先发送手动读取命令,等待数据准备完成后,使用 HAL_I2C_Master_Receive() 函数读取BH1750返回的2字节数据。随后通过计算获得光照强度值。

使用时,只需要在主函数中调用BH1750_Init()函数初始化I2C参数和发送开启电源命令,然后在需要读取光照强度数据时调用BH1750_Read_Lux()函数即可,如下所示:

 int main(void) 
 {
     HAL_Init();
 ​
     /* 初始化BH1750 */
     BH1750_Init();
 ​
     /* 读取BH1750光照强度 */
     float lux = BH1750_Read_Lux();
     printf("光照强度:%.1f Luxrn", lux);
 ​
     while (1) 
     {
         /* 主程序循环,可以进行其他操作或等待 */
     }
 }

五、总结

当前设计实现了一款基于STM32单片机的智能温室大棚监控系统,该系统通过多种传感器实现环境因子的实时监测和数据上传,在应用上具有重要的作用和应用价值。整体介绍了系统硬件和软件设计的各个环节,提供了一定的参考价值和设计思路。同时,该系统还可以在未来加入更多的传感器和控制设备,提升温室大棚监控系统的智能化和自动化程度。

审核编辑:汤梓红

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分