写点什么

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

作者:DS小龙哥
  • 2023-06-05
    重庆
  • 本文字数:7795 字

    阅读完需:约 26 分钟

一、项目背景

当前文章介绍基于 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:\Users\11266>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:\Users\11266>
复制代码



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 协议使用限制

(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%%RH\r\n", temperature, humidity);    }    else    {        printf("读取失败,请检查连接和传感器是否正常!\r\n");    }}
int main(){ HAL_Init();
// 初始化串口输出 uart_init();
printf("DHT11温湿度传感器读取测试开始\r\n");
// 初始化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 Lux\r\n", lux);
while (1) { /* 主程序循环,可以进行其他操作或等待 */ }}
复制代码

五、总结

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

发布于: 2023-06-05阅读数: 49
用户头像

DS小龙哥

关注

之所以觉得累,是因为说的比做的多。 2022-01-06 加入

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

评论

发布
暂无评论
基于STM32+华为云IOT设计的智能温室大棚监控系统_6 月 优质更文活动_DS小龙哥_InfoQ写作社区