×

支持物联网种植系统的构建

消耗积分:0 | 格式:zip | 大小:0.00 MB | 2023-06-15

刘波

分享资料个

描述

概述

种植植物的宁静和清新是从城市生活的喧嚣中解脱出来的。然而,我们有时会因为生活中的烦恼而无法好好照顾这些美丽的植物。不过不用担心,智能室内花园是自动种植的完美解决方案。即使我们不在家,它也能照料我们的植物。

在这个项目中,我们将一个普通的室内花园改造为一个功能齐全且支持物联网的种植系统。

功能

您可以使室内花园在适度的预算内具有以下功能。

  • 使用应用程序进行远程控制和数据监控。
  • 监测温度和湿度、光照强度、土壤湿度和水位。
  • 自动补光、加湿、加热、换气、浇水、水箱加水。

完成原型后,选择一个亚克力盒子来装饰你的花园。

逻辑

我们将功能划分为更小的构建块,如下图所示。

 
pYYBAGNom2WAdfBDAAOu21cVE7g769.png
 

脚步

第 1 步:原型

程序一:修改主控板

使用涂鸦智能APP实现远程控制,我们使用涂鸦WB3S网络模块作为主控。涂鸦三明治 Wi-Fi SoC 主控板(WB3S)帮助您快速实现各种智能硬件原型。该板只有一个 ADC 端口,因此我们使用 4 通道模拟多路复用器RS2255来扩展更多模拟通道。

 
pYYBAGNom2iAAIMjAAEherTt-VM125.png
 
poYBAGNom2uALhf2AAGS0hxY1Ac107.png
 

RS2255 提供对三个模拟通道的访问,分别表示为 A1、A2 和 A3。

  • 模拟频道

电路图显示,要读取 A1、A2 和 A3 上的值,嵌入式系统必须首先读取 ADC 值。PWM0 和 PWM1 输出控制 RS2255,这与 ADC 如何连接到模拟通道有关。见下表:

pYYBAGNom3CAI2FUAAASk5MVUnA388.png
 

程序 2:检测光强度

使用BH1750光传感器检测光强度。BH1750 是一款使用 I2C 进行通信的数字环境光传感器。BH1750FVI 是用于 I2C 总线接口的数字环境光传感器 IC。它可以精确测量高达 65535 lx 的光的 LUX 值。BH1750如下图:

 
poYBAGNom3KAdrnlAAAxG7-TIGE608.png
 
  • BH1750的电路图:
 
poYBAGNom3SAK6mGAACfEh8Ek0M809.png
 

引脚配置:

  • VCC:3-5V 电源输入
  • GND:电源地
  • SCL:I2C 时钟引脚
  • SDA:I2C 数据引脚
  • ADDR:地址引脚
  • BH1750的电路图:
  • 引脚配置:

程序 3:测量温度和湿度

使用SHT21湿度和温度传感器测量环境温度和湿度。SHT21经过全面校准,具有低功耗和出色的长期稳定性。它使用 I2C 协议进行通信。

注意:如果 SHT21 传感器不可用,您可以使用HTU21D传感器替代。

poYBAGNom3eAHP2XAAC9Z9IUz-E901.png
 
  • SHT21的电路图:
 
poYBAGNom3mASJlGAABxqfnSrpk723.png
 
  • VCC:3.3V电源输入
  • GND:电源地
  • SCL:I2C 时钟引脚
  • SDA:I2C 数据引脚
  • SHT21的电路图:
  • 引脚配置:

程序 4:测量土壤水分

使用土壤湿度传感器测量土壤的含水量。表面镀镍,感应面积大,可提高导电性,防止与土壤接触生锈的问题。该传感器提供模拟和数字输出。数字输出简单,而模拟输出更准确。您可以借助传感器板上的电位器(蓝色)调整传感器的灵敏度。传感器使用 LM393 比较器将土壤湿度水平与预设阈值进行比较。

pYYBAGNom36AJaALAAClS0ydbzo862.png
 
  • 土壤湿度传感器电路图:
 
poYBAGNom4GANM3tAAEZRENc6Kk706.png
 
  • 引脚配置:VCC:3.3-5V 电源输入GND:电源地D0:数字输出A0:模拟输出

程序 5:测量水箱水位

使用水位传感器测量水箱中的水深。水位传感器具有高性能和低功耗的灵敏度。它可以很容易地将水量转换为模拟信号,输出值可以被微处理器识别,从而实现水位报警。

poYBAGNom4OAPFcAAABJX6-K1Zg523.png
 
  • 水位传感器电路图:
 
poYBAGNom4WAMPF9AABc3sMuRII072.png
 
  • 引脚配置:+:3-5V电源输入-:电源地S:模拟输出

程序 6:补光

使用室内花园上的 LED 植物灯补光。生长灯由2835颗LED灯珠组成。共有114颗珠子,分暖白、红、蓝、远红外四个波段,每个波段的比例为25:9:2:2。

为了实现蔬菜以及花卉和水果的两种生长模式,两个 PWM 输出控制光谱。一个控制蓝光,另一个控制暖白光、红光和远红外光。

poYBAGNom4uAYi3cAAO-2PYbGiw084.png
 
  • 蔬菜种植方式:

植物灯板提供暖白光、红光、蓝光和远红外光。频谱报告如下:

pYYBAGNom5CAHQhhAAPxHjGIngw868.png
 
poYBAGNom5SAKzCWAAMp7HdtErM991.png
 
  • 花果种植模式:

植物灯板提供暖白光、红光和远红外光。频谱报告如下:

poYBAGNom52AeMh2AARdwLY4uxw974.png
 
pYYBAGNom6KAWTc4AANqnPbIIF4297.png
 
  • 引脚配置:12V:12V电源输入PON:PWM输入1 RON:PWM输入2 GND:电源地

注意蓝光只能在其他PWM信号输出时进行调节。如果您没有植物灯板,您可以使用两个 PWM 输出交替控制 LED 灯条。

程序 7:喷涂

使用 1 通道继电器模块来控制 5V 雾化器模块。造雾器芯片的工作频率为 108 kHz。第八针可用于监测水位,实现低水位切断,防止雾化盘缺水。

pYYBAGNom6SAVtrHAABXym8jHv4499.png
 
  • 制雾器模块电路图:
 
pYYBAGNom6iAUvqsAAC3DmZjntc143.png
 
  • 引脚配置:红线:5V黑线:GND

程序 8:加热

使用1路继电器模块控制75W远红外线灯泡。红外线灯泡具有热效率高、遇水防爆、传热快、散热快等特点。重要的是,它可以在潮湿的环境中有效地工作。您可以根据需要使用冷却风扇。

poYBAGNom6uAdFpyAABPKj9b8Mw284.png
 

(可选)冷却风扇:使用安装在室内花园中的冷却风扇(12V DC 0.18A)。风扇和红外线灯泡通过220V AC转12V DC电源变压器并联,由继电器模块控制。

pYYBAGNom7GAABJ3AARFPPewQ1U965.png
 

程序 9:通风

使用1路继电器模块控制两个高速冷却风扇(12V 0.5A)。通风可以降低环境温度和湿度,从而为植物授粉。

poYBAGNom7WAFdw0AAGK0JaOqTw650.png
 

程序 10:加注水箱

使用 1 通道继电器模块控制 12V 水泵。您可以根据需要选择供水或将水泵改为12V水电磁阀。

  • 功率:24W
  • 流量:5升/分钟
  • 进水压力:0.48 MPa
poYBAGNom7mAZE0IAAEECNi1FB4228.png
 

程序 11:水

使用 1 通道继电器模块控制两个 12V DC 隔膜泵。水被泵送并施用于土壤。

pYYBAGNom7uAF7_kAAAhtadbN9M848.png
 

程序 12:我们为什么要使用继电器模块?

继电器模块通常用于切换使用比大多数微控制器可以处理的电压更高的电压的设备。

您可以使用两个1路继电器模块和一个4路继电器模块来实现自动喷洒、加热、水箱加水、通风和浇水。

  • 1通道继电器模块
poYBAGNom76AUyIlAABpgN6vWWQ891.png
 
  • 4通道继电器模块
poYBAGNom8KAJb3WAADBH6uwtFw928.png
 
  • 继电器引脚
poYBAGNom8WAfGiiAAA5ON0xWtE766.png
 

程序 13:选择室内花园

选择一个简单的传统室内花园进行改造。

我们准备了一个传统的室内花园,配有种植灯板和大型土壤容器。

pYYBAGNom8iAJkRFAAMEjjNuSVs402.png
 

这个花园有以下功能:

poYBAGNom8uARxpnAAFu7meBOjY296.png
 

程序 14:花园供电

花园需要四种电源,即220V AC、12V DC、5V DC和3.3V DC。为此,我们使用以下解决方案:

  • 220V AC:来自 220V/50 Hz 电网的电源。
poYBAGNom9GANcEnAABP8YQC6ks391.png
 
  • 12V DC:将 S-120-12 开关电源连接到 220V AC 电网。
 
pYYBAGNom9SAOtGiAAAjK2wrJZQ187.png
 

12V散热风扇与红外线灯泡相连。红外灯泡连接到 220V 交流电源。隔离开关电源模块 (12V 400 mA) 为冷却风扇产生 12V DC。

pYYBAGNom9eAYTxlAAAcwL-2JL0410.png
 
  • 5V DC:为继电器模块和超声波雾化器供电。
 
pYYBAGNom9qARKf-AABNAijUdY4912.png
 

模块规格:

  • 输入电压:9V–36V DC
  • 输出电压:5.2V/5A/25W
  • 输入不同的电压会输出不同的功率:
  • 9–24V DC,输出 5.2V/6A/30W。
  • 24–32V DC,输出 5.2V/5A/25W。
  • 32-36V DC,输出 5.2V/3.5A/18W。

3.3V DC:涂鸦三明治DC-DC电源板供电。此电源板配备双电源插孔,可接受 12V DC 或 5V DC 电源。

  • 12V DC输入时,两颗SY8012B芯片工作,为板上其他元件提供12V、5V、3.3V DC供电
poYBAGNom92Ae_bXAABwK19cKto209.png
 

步骤 15:设计亚克力盒子

我们使用 Adob​​e AutoCAD 设计了一个亚克力盒子。注意事项:

  • 锅大小
  • 组件尺寸和布局
  • 固定孔位
  • 接线用螺丝孔

下图显示了组件布局供您参考。您可以修改和重新设计以满足您的需求。下载 2D 图纸

  • 正视图:
pYYBAGNom-CAD-c9AABef6cQREk973.png
 
  • 后视图:
poYBAGNom-KAOUx3AADNcaEdowk027.png
 

第 2 步:组装

程序1:准备材料

准备以下组件和用品。

poYBAGNom-WAZDpZAABzIEGA4_4395.png
 
pYYBAGNom-eASQ8YAAByRaEAByY834.png
 
pYYBAGNom-2AVumfAAB5nQ5Q9uk092.png
 
pYYBAGNom_CAUzlaAAArpDR792o956.png
 

程序2:组装亚克力盒

根据图纸切割亚克力板。用粘合剂组装丙烯酸组件。

pYYBAGNom_eAG9DqAAIVTHlII0s481.png
 

程序 3:接线

下载接线图

 
pYYBAGNonFKAfFVuABftyTi1QVo524.png
 

程序 4:安装组件

注意事项:

  • 组件位置。
  • 上排风口用于进风口,下排风口用于出风口。
  • 电线使用和长度。
  • 光传感器位置。

程序5:制作雾化器

  • 找一个带盖的瓶子。
pYYBAGNonFeAMJ_iAAIiDItPKjc812.png
 
  • 固定脱脂棉。

在盖子上钻一个直径合适的孔来固定脱脂棉。放一些沙子或小石头固定棉花的底部。

poYBAGNonGCALZopAAO00mrBQOM134.png
 
  • 将水位感应线通过盖子孔插入瓶子。
pYYBAGNonGKAWqUIAAA-YNVbehU641.png
 
  • 修复雾化器。

1.如图所示将造雾器放在盖子上。

poYBAGNonGiAVkSAAAC5qliBkjs428.png
 

2. 重新拧上盖子,但不要太紧。否则无法产生雾气。如果没有瓶子,您可以用热胶固定雾化器。

poYBAGNonGuAYkLEAAHLrC5caYg072.png
 

程序 6:完成组装

将组件放入盒子中并整理电线。

 
poYBAGNonHCAGgxQAAoegY3RMCk954.jpg
 
 
pYYBAGNonHSABVmCAAIVXDwrSWU567.jpg
 

第 3 步:创建

进行涂鸦 OS 开发,需要在涂​​鸦IoT 平台上创建一个室内花园产品,然后获取 SDK。该产品代表了智慧花园的所有物联网功能,包括产品授权和配置,构建了花园与涂鸦物联网平台的通信本节介绍如何在涂鸦物联网平台上打造智能室内花园有关详细信息,请参阅创建产品

 
pYYBAGNomXaAGxuSAABiWTVrJ_s934.png
 
  • 找到自定义函数并单击创建函数设置自定义函数的属性。
  • 要设置温度和湿度范围,请添加四个整数数据点 (DP),即Max Temp Min Temp Max HumidityMin Humidity
  • 要将水箱水位的数据传输到云端,请添加水箱水位的整数DP
  • 要控制生长光色,请添加Light Color的枚举 DP
  • 要在预定和自动补光之间切换,请添加Fill Light的布尔 DP
  • 登录涂鸦物联网平台,点击创建
  • 选择小家电>植物种植者
  • 单击自定义解决方案>植物种植者输入产品名称,协议类型选择WiFi+蓝牙,点击页面下方的创建产品。
  • 创建标准函数中,选择开关当前温度当前湿度倒计时剩余时间故障
  • (可选)要实现智能花园的非标准功能,需要自定义一些功能。
  • 完成功能定义后,点击设备面板选择喜欢的应用控制面板。建议选择适合您的调试需要的调试面板。

您已完成在涂鸦 IoT 平台上创建产品它已准备好进行嵌入式系统开发。

第 4 步:代码

嵌入式代码基于 BK7231 芯片组,使用涂鸦通用 Wi-Fi SDK 开发。您可以从涂鸦 GitHub 仓库拉取的 demo 例程中获取环境变量,也可以下载包含 SDK 环境变量的 demo 例程。我们通过方法 1 获取 SDK。

程序 1:进入申请

克隆存储库以在您的计算机上创建本地副本。打开apps存储演示代码的文件夹。在这个文件夹中,新建一个文件夹,命名bk7231t_plant_grow_mach_demo为存放demo相关的源文件、头文件、编译文件。

如果您是第一次接触 BK7231 开发,我们建议您文件夹中分别找到tuya_device.c并将它们复制到这个新创建的文件夹中。tuya_device.hsrcincludebk7231t_bl0937_1_plug_demo

打开tuya_device.c并找到该device_init功能。

OPERATE_RET device_init(VOID)
{
OPERATE_RET op_ret = OPRT_OK;
TY_IOT_CBS_S wf_cbs = {
status_changed_cb,\
gw_ug_inform_cb,\
gw_reset_cb,\
dev_obj_dp_cb,\
dev_raw_dp_cb,\
dev_dp_query_cb,\
NULL,
};
op_ret = tuya_iot_wf_soc_dev_init_param(hw_get_wifi_mode(),WF_START_SMART_FIRST,\
&wf_cbs,NULL,PRODECT_KEY,DEV_SW_VERSION);
if(OPRT_OK != op_ret) {
PR_ERR("tuya_iot_wf_soc_dev_init_param error,err_num:%d",op_ret);
return op_ret;
}
op_ret = tuya_iot_reg_get_wf_nw_stat_cb(wf_nw_status_cb);
if(OPRT_OK != op_ret) {
PR_ERR("tuya_iot_reg_get_wf_nw_stat_cb is error,err_num:%d",op_ret);
return op_ret;
}
op_ret= app_dltj_init(APP_DLTJ_NORMAL);
if(OPRT_OK != op_ret) {
PR_ERR("dltj init err!");
return op_ret;
}
op_ret = app_switch_init(APP_SW_MODE_NORMAL);
if(op_ret != OPRT_OK) {
return op_ret;
}
return op_ret;
}

在 BK7231T 芯片组的开发环境中,device_init函数是应用程序代码的入口。设备上电时,BK7231T适配层运行初始化代码,然后调用该函数初始化应用层。该函数处理以下内容:

  • 调用tuya_iot_wf_soc_dev_init_param()SDK初始化配置工作模式和配对模式,注册回调函数,保存固件密钥和PID。
TY_IOT_CBS_S wf_cbs = {
status_changed_cb,\
gw_ug_inform_cb,\
gw_reset_cb,\
dev_obj_dp_cb,\
dev_raw_dp_cb,\
dev_dp_query_cb,\
NULL,
};
op_ret = tuya_iot_wf_soc_dev_init_param(hw_get_wifi_mode(),WF_START_SMART_FIRST,\
&wf_cbs,NULL,PRODECT_KEY,DEV_SW_VERSION);
if(OPRT_OK != op_ret) {
PR_ERR("tuya_iot_wf_soc_dev_init_param error,err_num:%d",op_ret);
return op_ret;
} op_ret = tuya_iot_reg_get_wf_nw_stat_cb(wf_nw_status_cb);
if(OPRT_OK != op_ret) {
    PR_ERR("tuya_iot_reg_get_wf_nw_stat_cb is error,err_num:%d",op_ret);
    return op_ret;
}
op_ret= app_dltj_init(APP_DLTJ_NORMAL);
if(OPRT_OK != op_ret) {
PR_ERR("dltj init err!");
return op_ret;
}
op_ret = app_switch_init(APP_SW_MODE_NORMAL);
if(op_ret != OPRT_OK) {
return op_ret;
}
  • 调用tuya_iot_reg_get_wf_nw_stat_cb()注册设备网络状态回调。
op_ret = tuya_iot_reg_get_wf_nw_stat_cb(wf_nw_status_cb);
if(OPRT_OK != op_ret) {
    PR_ERR("tuya_iot_reg_get_wf_nw_stat_cb is error,err_num:%d",op_ret);
    return op_ret;
}
  • 在应用层调用初始化函数。
op_ret= app_dltj_init(APP_DLTJ_NORMAL);
if(OPRT_OK != op_ret) {
    PR_ERR("dltj init err!");
    return op_ret;
}

op_ret = app_switch_init(APP_SW_MODE_NORMAL);
if(op_ret != OPRT_OK) {
    return op_ret;
}

因为tuya_device.c是借用了另一个demo,所以我们需要为这个demo实现一个应用初始化函数。创建app_plant.c及其头文件并实现app_plant_init()device_init.

程序 2:应用程序架构

应用程序代码分三层实现。

  • 底层有传感器驱动代码和封装传感器初始化和数据采集接口。
  • 第二层有部分控制逻辑代码,调用传感器驱动接口来实现各个组件的控制逻辑。该层封装了轮询数据处理的接口。
  • 第一层创建应用任务调用第二层接口,处理DP数据传输,接受解析。

app_plant.c实现第一层。

  • app_plant_init()调用二层封装的设备初始化接口,创建应用任务。
OPERATE_RET app_plant_init(IN APP_PLANT_MODE mode)
{
    OPERATE_RET op_ret = OPRT_OK;

    if(APP_PLANT_NORMAL == mode) {
        
        // Initialize I/O, sensors, PWM, and more
        plant_device_init();
        
        // Create data collection tasks for I2C sensors
        xTaskCreate(sensor_data_get_iic_theard,"thread_data_get_iic",512,NULL,TRD_PRIO_3,NULL);

        // Create data collection tasks for ADC sensors
        xTaskCreate(sensor_data_get_adc_theard,"thread_data_get_adc",512,NULL,TRD_PRIO_4,NULL);

        // Create data processing tasks
        xTaskCreate(sensor_data_deal_theard,"thread_data_deal",512,NULL,TRD_PRIO_4,NULL);

        // Create scheduled tasks for DP data reporting
        xTaskCreate(sensor_data_report_theard,"thread_data_report",512,NULL,TRD_PRIO_4,NULL);
    }else {
        // Non-production test mode
    }

    return op_ret;
}
  • app_report_all_dp_status()报告所有 DP 数据:
VOID app_report_all_dp_status(VOID)
{
    OPERATE_RET op_ret = OPRT_OK;

    INT_T dp_cnt = 0;
    dp_cnt = 12;

    TY_OBJ_DP_S *dp_arr = (TY_OBJ_DP_S *)Malloc(dp_cnt*SIZEOF(TY_OBJ_DP_S));
    if(NULL == dp_arr) {
        PR_ERR("malloc failed");
        return;
    }

    memset(dp_arr, 0, dp_cnt*SIZEOF(TY_OBJ_DP_S));

    dp_arr[0].dpid = DPID_SWITCH_P;
    dp_arr[0].type = PROP_BOOL;
    dp_arr[0].time_stamp = 0;
    dp_arr[0].value.dp_value = plant_ctrl_data.Switch;
    ......
    
    op_ret = dev_report_dp_json_async(NULL,dp_arr,dp_cnt);
    Free(dp_arr);
    if(OPRT_OK != op_ret) {
        PR_ERR("dev_report_dp_json_async relay_config data error,err_num",op_ret);
    }

    PR_DEBUG("dp_query report_all_dp_data");
    return;
}
  • 任务功能。

在任务中,plant_get_iic_sensor_data()plant_get_adc_sensor_data()plant_ctrl_handle()plant_ctrl_all_off()被循环调用。这些接口来自第二层并在plant_control.c.

STATIC VOID sensor_data_get_iic_theard(PVOID_T pArg)
{   
    while(1) {

        PR_DEBUG("plant_get_i2c_sensor_data");
        vTaskDelay(TASKDELAY_SEC);

        if(TRUE == plant_ctrl_data.Switch) {    
            plant_get_iic_sensor_data();
        }
        
    }
}

STATIC VOID sensor_data_get_adc_theard(PVOID_T pArg)
{   
    while(1) {

        PR_DEBUG("plant_get_adc_sensor_data");
        vTaskDelay(TASKDELAY_SEC*2);

        if(TRUE == plant_ctrl_data.Switch) {
            plant_get_adc_sensor_data();
        }
        
    }
}

STATIC VOID sensor_data_deal_theard(PVOID_T pArg)
{   
    while(1) {
        vTaskDelay(TASKDELAY_SEC);

        if(TRUE == plant_ctrl_data.Switch) {
            plant_ctrl_handle();
        }else {
            plant_ctrl_all_off();
        }
        
    }

}

STATIC VOID sensor_data_report_theard(PVOID_T pArg)
{   
    while(1) {
        vTaskDelay(TASKDELAY_SEC*5);
        app_report_all_dp_status();
    }

}
  • deal_dp_proc()根据DP ID处理接收到的DP数据。
VOID deal_dp_proc(IN CONST TY_OBJ_DP_S *root)
{
    UCHAR_T dpid;

    dpid = root->dpid;
    PR_DEBUG("dpid:%d",dpid);
    
    switch (dpid) {
    
    case DPID_SWITCH_P:
        PR_DEBUG("set switch:%d",root->value.dp_bool);
        plant_ctrl_data.Switch = root->value.dp_bool;
        break;
        
    case DPID_PUMP:
        PR_DEBUG("set pump:%d",root->value.dp_bool);
        plant_ctrl_data.Pump = root->value.dp_bool;
        break;
        
        ......
        
    default:
        break;
    }

    return;

}

我们已经构建了应用程序架构。接下来,我们需要在第二层实现接口,这些接口放在plant_control.c. 以下程序描述了温度和湿度、光照和土壤湿度方面的控制逻辑。

程序 3:温度和湿度

要控制温度和湿度,首先我们必须收集数据。SHT21 传感器收集温度和湿度数据。它使用 I2C 协议进行通信。我们根据SHT21 技术手册编写传感器驱动程序代码驱动代码完成后,我们封装了传感器初始化、数据采集、数据转换的接口。

所有 SHT21 驱动程序和外部接口均以sht21.c. 封装的外部接口从plant_control.c.

1.tuya_sht21_init(sht21_init_t* param)初始化传感器。request 参数是一个指向结构的指针,该结构包含有关 SDA 和 SCL I/O 引脚和分辨率的信息。

typedef struct 
{
    UCHAR_T SDA_PIN;            ///< SDA pin
    UCHAR_T SCL_PIN;            ///< SCL pin
    sht21_resolution_t RESOLUTION;   
}sht21_init_t;

2.定义结构变量plant_control.c并调用plant_device_init()以初始化传感器。

#define IIC_SDA_PIN                         (6)
#define IIC_SCL_PIN                         (7)

STATIC sht21_init_t sht21_int_param = {IIC_SDA_PIN, IIC_SCL_PIN, SHT2x_RES_10_13BIT};

VOID plant_device_init(VOID)
{

    // SHT21 IIC driver init 
    tuya_sht21_init(&sht21_int_param);
    
}

3.初始化后,传感器可以提供环境温度和湿度值。因为花园需要连续的环境参数,所以必须相应地调用获取传感数据的接口。在上述过程中,任务函数app_plant.c之一plant_get_iic_sensor_data()plant_control.c. 因此,我们需要调用传感器数据采集接口tuya_sht21_measure()和计算接口tuya_sht21_cal_RH()这两个接口的参数都是枚举值,用来获取温度或湿度。

VOID plant_get_iic_sensor_data(VOID)
{

    SHORT_T hum;
    SHORT_T temp;

    tuya_sht21_init(&sht21_int_param);

    hum = tuya_sht21_measure(HUMIDITY);
    device_data.humidity = tuya_sht21_cal_RH(hum);
    
    if(device_data.humidity > 0){ // Remove invalid humidity values less than 0
        plant_report_data.Humidity_current = (UCHAR_T)device_data.humidity;
        PR_NOTICE("humidity = %d",plant_report_data.Humidity_current);
    }

    temp = tuya_sht21_measure(TEMP);
    device_data.temperature = tuya_sht21_cal_temperature(temp);
    plant_report_data.Temp_current = (UCHAR_T)device_data.temperature;
    PR_NOTICE("tempre = %d",plant_report_data.Temp_current);
}

4.将环境温度和湿度与阈值进行比较。我们在涂鸦 IoT 平台上创建了最高最低温度和湿度的四个 DP ,因此我们可以通过应用设置阈值并通过云端发送到设备。处理DP数据中deal_dp_proc()函数。app_plant.c

VOID deal_dp_proc(IN CONST TY_OBJ_DP_S *root)
{
    UCHAR_T dpid;

    dpid = root->dpid;
    PR_DEBUG("dpid:%d",dpid);
    
    switch (dpid) {

    ......
    
    case DPID_TEMP_MAX:
        PR_DEBUG("set temp max:%d",root->value.dp_value);
        plant_ctrl_data.Temp_max = root->value.dp_value;
        break;
    
    case DPID_HUMIDITY_MAX:
        PR_DEBUG("set humidity max:%d",root->value.dp_value);
        plant_ctrl_data.Humidity_max = root->value.dp_value;
        break;
    
    case DPID_TEMP_MIN:
        PR_DEBUG("set temp min:%d",root->value.dp_value);
        plant_ctrl_data.Temp_min = root->value.dp_value;
        break;

    case DPID_HUMIDITY_MIN:
        PR_DEBUG("set humidity min:%d",root->value.dp_value);
        plant_ctrl_data.Humidity_min = root->value.dp_value;
        break;
    ......
    
    default:
        break;
    }

    return;

}

5.创建数据比较和I/O设备控制任务app_plant.c它在循环中调用plant_ctrl_handle()函数。plant.control.c所有控制逻辑都在 中指定plant_ctrl_handle()为了调节温度和湿度,我们使用了雾化器、红外线灯泡和冷却风扇,它们通过继电器模块打开/关闭。tuya_gpio_inout_set()此 SDK 中封装的接口和tuya_gpio_write()接口控制 I/O 输出。代码如下:

#define HUMIDIFIER_PORT                     (24)
#define HUMIDIFIER_LEVEL                    LOW

#define HEATING_ROD_PORT                    (20)
#define HEATING_ROD_LEVEL                   LOW

#define COOL_DOWN_FAN_PORT                  (21)
#define COOL_DOWN_FAN_LEVEL                 LOW

STATIC VOID __ctrl_gpio_init(CONST TY_GPIO_PORT_E port, CONST BOOL_T high)
{
    // Set I/O pin to output mode
    tuya_gpio_inout_set(port, FALSE);
    // Set I/O level
    tuya_gpio_write(port, high);
}

VOID plant_device_init(VOID)
{
    // SHT21 IIC driver init 
    tuya_sht21_init(&sht21_int_param);

    // gpio init
    __ctrl_gpio_init(HUMIDIFIER_PORT, HUMIDIFIER_LEVEL);

    __ctrl_gpio_init(COOL_DOWN_FAN_PORT, COOL_DOWN_FAN_LEVEL);  

    __ctrl_gpio_init(HEATING_ROD_PORT, HEATING_ROD_LEVEL);

}

STATIC VOID __passive_ctrl_module_temp_humidity(VOID)
{   
    if(device_data.humidity < plant_ctrl_data.Humidity_min) {
        tuya_gpio_write(HUMIDIFIER_PORT, !HUMIDIFIER_LEVEL);
    }else {
        tuya_gpio_write(HUMIDIFIER_PORT, HUMIDIFIER_LEVEL);
    }

    if(device_data.temperature < plant_ctrl_data.Temp_min) {
        tuya_gpio_write(HEATING_ROD_PORT, !HEATING_ROD_LEVEL);
    }else {
        tuya_gpio_write(HEATING_ROD_PORT, HEATING_ROD_LEVEL);
    }

    if((device_data.temperature > plant_ctrl_data.Temp_max)||(device_data.humidity > plant_ctrl_data.Humidity_max)) {
        tuya_gpio_write(COOL_DOWN_FAN_PORT,!COOL_DOWN_FAN_LEVEL);
    }else {
        tuya_gpio_write(COOL_DOWN_FAN_PORT,COOL_DOWN_FAN_LEVEL);
    }
    
}

VOID plant_ctrl_handle(VOID)
{   
    PR_DEBUG("enter ctrl handle");

    __passive_ctrl_module_temp_humidity();
    
}

程序 4:灯光控制

BH1750 光传感器使用 I2C 协议进行通信。我们根据BH1750 数据表编写传感器驱动程序代码驱动代码完成后,我们封装了传感器初始化和数据采集的接口。所有 BH1750 驱动程序和外部接口均以bh1750.c. 封装的外部接口从plant_control.c.

1.tuya_bh1750_init(sht21_init_t* param)初始化传感器。request 参数是一个指向包含有关 SDA 和 SCL I/O 管脚信息的结构的指针。

typedef struct 
{
    UCHAR_T SDA_PIN;            ///< SDA pin
    UCHAR_T SCL_PIN;            ///< SCL pin 
}bh1750_init_t;

2.定义结构变量plant_control.c并调用plant_device_init()以初始化传感器。

#define IIC_SDA_PIN                         (6)
#define IIC_SCL_PIN                         (7)

STATIC bh1750_init_t bh1750_int_param = {IIC_SDA_PIN, IIC_SCL_PIN};

VOID plant_device_init(VOID)
{
......
    // SHT21 IIC driver init 
    tuya_bh1750_init(&bh1750_int_param);
......
}

tuya_bh1750_get_bright_value()3.初始化完成后,调用BH1750数据采集接口plant_get_iic_sensor_data()获取光照强度值。为保证光传感器和温湿度传感器采集数据时通信稳定,plant_get_iic_sensor_data()输入时只启用其中一个传感器。

VOID plant_get_iic_sensor_data(VOID)
{

    SHORT_T hum;
    SHORT_T temp;

    switch (IIC_SELECT_FLAG)
    {
    case 0:    
        tuya_sht21_init(&sht21_int_param);

        hum = tuya_sht21_measure(HUMIDITY);
        device_data.humidity = tuya_sht21_cal_RH(hum);
        if(device_data.humidity > 0){ // Remove invalid humidity values less than 0
            plant_report_data.Humidity_current = (UCHAR_T)device_data.humidity;
            PR_NOTICE("humidity = %d",plant_report_data.Humidity_current);
        }

        temp = tuya_sht21_measure(TEMP);
        device_data.temperature = tuya_sht21_cal_temperature(temp);
        plant_report_data.Temp_current = (UCHAR_T)device_data.temperature;
        PR_NOTICE("tempre = %d",plant_report_data.Temp_current);
        
        IIC_SELECT_FLAG = 1;

        break;
    case 1:    
        tuya_bh1750_init(&bh1750_int_param);

        device_data.light_intensity_value = tuya_bh1750_get_bright_value();
        PR_NOTICE("light_intensity_value = %d",device_data.light_intensity_value);
        
        IIC_SELECT_FLAG = 0;

        break;

    default:
        break;
    }

}

4.因为我们没有创建一个DP来设置一个应用程序的光强度值,我们在代码中设置了一个值。调整光亮度,使光传感器采集的数据接近该值。我们还设置了一个误差范围,以避免在临界点出现光闪烁。

#define ACCURACY                         (2000)  // Error range
#define light_value_set                  (12000) // Light intensity in lx unit

5.PWM输出控制灯光亮度。PWM 初始化和输出功能在plant_pwm.c. 初始化PWM in plant_device_init(),调用实现光控的接口plant_ctrl_handle()

USER_PWM_DUTY_T user_pwm_duty = {0,0};

VOID plant_device_init(VOID)
{
    ......
    plant_pwm_init();
    ......
}

STATIC VOID __passive_ctrl_module_light(VOID)
{   
    if(IIC_SELECT_FLAG){ // If the I2C temperature and humidity sensor operates previously
        return;
    }

    if((TRUE == plant_ctrl_data.Auto_switch)) { // Automatic light filling is switched on
        USHORT_T current = device_data.light_intensity_value;
        USHORT_T set = light_value_set;

        if((current - set) > ACCURACY) { // Current light intensity is greater than the set value but not within the error range
            if((current - set) >= 200) {
                if(plant_ctrl_data.Bright_value >= 50)plant_ctrl_data.Bright_value -= 50;
            }else if((current - set) > 150) {
                if(plant_ctrl_data.Bright_value >= 20)plant_ctrl_data.Bright_value -= 20;
            }else {
                if(plant_ctrl_data.Bright_value >= 1)plant_ctrl_data.Bright_value--;
            }
        }else if((set - current) > ACCURACY) { // Current light intensity is less than the set value but not within the error range
            if((set - current) >= 200) {
                if(plant_ctrl_data.Bright_value <= 950)plant_ctrl_data.Bright_value += 50;
            }else if((set - current) > 150) {
                if(plant_ctrl_data.Bright_value <= 980)plant_ctrl_data.Bright_value += 20;
            }else {
                if(plant_ctrl_data.Bright_value <= 999)plant_ctrl_data.Bright_value++;
            }
        }
    } 
}

STATIC VOID __initiative_ctrl_module_light(VOID)
{   
    
    if(TRUE == plant_ctrl_data.Auto_switch) { // Automatic light filling is switched on
        PR_NOTICE("Ligth open !!!!");
        if(plant_ctrl_data.Light_color == red) { // Set light color to red
            user_pwm_duty.duty_red = plant_ctrl_data.Bright_value;
            user_pwm_duty.duty_blue = 0;
        }else if(plant_ctrl_data.Light_color == blue) { // Set light color to blue
            user_pwm_duty.duty_blue = plant_ctrl_data.Bright_value;
            user_pwm_duty.duty_red = 0;
        }else {
            user_pwm_duty.duty_blue = plant_ctrl_data.Bright_value;
            user_pwm_duty.duty_red = user_pwm_duty.duty_blue;
        }
        plant_pwm_set(&user_pwm_duty);
    }else { // Automatic light filling is switched off. Users manually schedule light filling.
        if(plant_ctrl_data.Light_color == red) {
            user_pwm_duty.duty_red = 1000;
            user_pwm_duty.duty_blue = 0;
        }else if(plant_ctrl_data.Light_color == blue) {
            user_pwm_duty.duty_blue = 1000;
            user_pwm_duty.duty_red = 0;
        }else {
            user_pwm_duty.duty_red = 1000;
            user_pwm_duty.duty_blue = 1000;
        }
        if((IsThisSysTimerRun(light_timer) == FALSE)&&(plant_ctrl_data.Countdown_set != cancel)) {
            light_flag_min = (USHORT_T)plant_ctrl_data.Countdown_set * 60;
            plant_pwm_set(&user_pwm_duty);
            sys_start_timer(light_timer,1000*60,TIMER_CYCLE);
        }else if(plant_ctrl_data.Countdown_set == cancel) {
            user_pwm_duty.duty_blue = 0;
            user_pwm_duty.duty_red = 0;
            plant_pwm_set(&user_pwm_duty);
            light_flag_min = 0;
            sys_stop_timer(light_timer);
        }else if(IsThisSysTimerRun(light_timer) == TRUE) {
            plant_pwm_set(&user_pwm_duty);
        }
        // Save timer's remaining time in minute
        plant_report_data.Countdown_left = light_flag_min;
    }
                                                                        
}

VOID plant_ctrl_handle(VOID)
{   
    ......
    __passive_ctrl_module_light();
    __initiative_ctrl_module_light();
}

程序 5:土壤水分

土壤湿度传感器根据土壤电阻的变化输出不同的模拟信号值。ADC 将来自传感器的模拟信号转换为数字信号,以监测水分的变化。

1.app_plant.c中,ADC采集任务循环调用plant_get_adc_sensor_data()plant_control.c所有ADC采集相关的代码都放在这个界面中:

VOID plant_get_adc_sensor_data(VOID)
{   // Control switch analog chip to select soil moisture channel
    rs2255_channel_checkout(SOIL_MOISTURE_SENSOR_PORT);
        
    tuya_hal_adc_init(&tuya_adc);
    tuya_hal_adc_value_get(TEMP_ADC_DATA_LEN, &device_data.soil_humidity);
    PR_NOTICE("soil_humidity = %d",device_data.soil_humidity);

    tuya_hal_adc_finalize(&tuya_adc);

}

2.当土壤水分值低于阈值时,水泵开始运行并为植物供水。调用自动浇水接口plant_ctrl_handle()

  • 变量使水泵有一个休息间隔,以避免植物浇水过多ADD_WATER_COUNTADD_WATER_READY
STATIC VOID __passive_ctrl_module_soil_humidity(VOID)
{   
    if(device_data.soil_humidity > plant_ctrl_data.Soil_humidity_threshold) { 

        if(ADD_WATER_READY) { 

            tuya_gpio_write(WATER_VALVE_PORT, !WATER_VALVE_LEVEL);

            ADD_WATER_COUNT++;
            if(ADD_WATER_COUNT > 5) {
                ADD_WATER_READY = 0;
            }

        } else{

            tuya_gpio_write(WATER_VALVE_PORT, WATER_VALVE_LEVEL);
            ADD_WATER_COUNT++;
            if(ADD_WATER_COUNT >15) {
                ADD_WATER_READY = 1;
                ADD_WATER_COUNT = 0;
            }

        }
    }else {

        ADD_WATER_READY = 1;
        ADD_WATER_COUNT = 0;
        tuya_gpio_write(WATER_VALVE_PORT, WATER_VALVE_LEVEL);

    }
}

VOID plant_ctrl_handle(VOID)
{   
    ......
    __passive_ctrl_module_soil_humidity();
    ......
}

程序 6:水箱

水泵用于从水箱抽水并向工厂供水。当水位下降时,需要另一个水泵为水箱供水。水位传感器根据电阻产生输出电压,通过测量我们可以确定水位。我们需要使用 ADC 读取这个模拟电压并将其转换为数字值。

1.rs2255_init()用于初始化模拟开关芯片。RS2255 与 SDA 和 SCL 引脚共享相同的 I/O,因此初始化在 ADC 数据采集开始时运行,这与其他 I2C 传感器初始化相同。

VOID plant_get_adc_sensor_data(VOID)
{
    rs2255_init();

    switch (ADC_SELECT_FLAG)
    {
    case 0:    

        rs2255_channel_checkout(WATER_SENSOR_PORT);
        tuya_hal_adc_init(&tuya_adc);
        tuya_hal_adc_value_get(TEMP_ADC_DATA_LEN, &device_data.water_tank_value);
        PR_NOTICE("water_tank_value = %d",device_data.water_tank_value);

        ADC_SELECT_FLAG = 1;

        break;
    case 1:    
        
        rs2255_channel_checkout(SOIL_MOISTURE_SENSOR_PORT);
        tuya_hal_adc_init(&tuya_adc);
        tuya_hal_adc_value_get(TEMP_ADC_DATA_LEN, &device_data.soil_humidity);
        PR_NOTICE("soil_humidity = %d",device_data.soil_humidity);

        ADC_SELECT_FLAG = 0;

        break;

    default:
        break;
    }
    
    tuya_hal_adc_finalize(&tuya_adc);

}

2.调用plant_ctrl_handle()实现水箱水位控制。

#define WATER_PUMP_PORT                     (22)
#define WATER_PUMP_LEVEL                    LOW

STATIC VOID __initiative_ctrl_module_pump(VOID)
{   
    // Convert water level sensor value into remaining water level percentage for data transmission
    if(device_data.water_tank_value < 1700) {
        plant_report_data.Water_remain = 10;
    }else if(device_data.water_tank_value < 2500) {
        plant_report_data.Water_remain = 25;
    }else if(device_data.water_tank_value < 2700) {
        plant_report_data.Water_remain = 50;
    }else if(device_data.water_tank_value < 2900) {
        plant_report_data.Water_remain = 75;
    }else if(device_data.water_tank_value >= 3000) {
        plant_report_data.Water_remain = 100;
    }

    if(TRUE == plant_ctrl_data.Pump){ // If water pump is switched on
        PR_NOTICE("water pump open !!!!");
        tuya_gpio_write(WATER_PUMP_PORT,!WATER_PUMP_LEVEL);
    }else {
        tuya_gpio_write(WATER_PUMP_PORT,WATER_PUMP_LEVEL);
    }
    if(device_data.water_tank_value >= 3000) { // When the water level approaches the threshold, the water pump is switched off
        PR_NOTICE("water tank is full !!!!");
        tuya_gpio_write(WATER_PUMP_PORT,WATER_PUMP_LEVEL);
        plant_ctrl_data.Pump = FALSE;
    }
                                                                    
}

VOID plant_ctrl_handle(VOID)
{   
    ......
    __initiative_ctrl_module_pump();
    ......
}

现在,我们已经完成了编码部分。用APP上的调试面板测试DP数据传输后,我们就可以进行固件编译了。

程序 7:编译和烧录

在 Linux 终端中,运行build_app.sh脚本来编译固件。生成的固件位于apps> APP_PATH>output中。

  • 命令格式:
build_app.sh /home/share/samba/ci/ty_iot_wf_bt_sdk_bk7231t$ sudo sh build_app.sh apps/bk7231t_plant_grow_mach_demo bk7231t_plant_grow_mach_demo 1.0.0
  • 命令示例:
/home/share/samba/ci/ty_iot_wf_bt_sdk_bk7231t$ sudo sh build_app.sh apps/bk7231t_plant_grow_mach_demo bk7231t_plant_grow_mach_demo 1.0.0
  • 下图显示成功返回。
poYBAGNomYaAKb8ZAAHQ8-a4huI824.png
 

 

将固件烧录到模块后,我们开始进行功能调试。有关刻录和授权的更多信息,请参阅刻录和授权 WB 系列模块。

第 5 步:调试

一旦模块被授权,我们将手机连接到 Wi-Fi 网络,打开蓝牙,按照说明对花园进行配对。然后,我们可以用应用程序控制花园。在本项目中,我们使用涂鸦智能 App 作为控制终端。有不同的应用程序选项。有关详细信息,请参阅应用程序开发

调试过程如下:

程序 1:预定和自动补光

  • 打开花园并设置倒计时

 

pYYBAGNonIGAct_qAABLKGV8mZY390.png
 

 

pYYBAGNonIqAapkRAAK1JGk9sLM415.png
 

 

2.设置灯光颜色,生长灯板相应改变颜色。

 

pYYBAGNonI6AObkQAALMN6vhZSc153.png
 

 

3.当倒计时设置为取消时,植物灯板将关闭。

4.开启自动补光后,灯光亮度会不断增加,直到达到预设值。

程序二:温湿度控制

1.可以在涂鸦智能APP上查看当前环境温度和湿度。

 

pYYBAGNonJCAB82lAABAFpJRPes330.png
 

 

2.如果您设置的最小湿度大于当前湿度,雾化器将启动。当环境湿度超过最小值时,制雾器将停止。

 

pYYBAGNonJWAHjhjAAMhxAz1cCk103.png
 

 

3.如果您设置的最低温度高于当前温度,红外线灯泡将打开。当环境温度超过最小值时,红外灯泡将停止。

4.以同样的方式测试最高温度和湿度,并观察冷却风扇是否相应运行。这个风扇可以对空气进行除湿和冷却。

程序 3:加注水箱

1.可查看水箱水位剩余水百分比。

2.在涂鸦智能APP开启Pump ,开启水泵。

 

 

pYYBAGNonJeAUBsQAABGBxUYzOY139.png
 

 

poYBAGNonJyAcsotAAD3ZNcvzTo292.png
 

 

1:通风继电器模块

2:喷涂继电器模块

3:补水箱继电器模块

 

3.将水位传感器放入杯中,加水至铜线完全没入。您会发现水泵停止并且应用程序上的Pump恢复。

 

pYYBAGNonJ-AdHAMAAIST79UUi4961.png
 

 

4.水箱水位变为100。

 

poYBAGNonKSAMaanAAAmELbputM549.png
 

 

程序 4:自动浇水

  • 当您打开花园时,用于浇水的水泵将持续运行。

 

poYBAGNonKaAYuFIAAC440iATqY131.png
 

 

  • 4:浇水继电器模块
  • 5:加热继电器模块

2.将土壤湿度传感器放入水中,模拟土壤湿度达到阈值的情况。你会发现水泵停止。

 
poYBAGNonLGARtssABGAhS5Fs4U105.png
 

概括

恭喜!您已成功构建智能室内花园的原型。依托涂鸦物联网平台,您可以快速轻松地从零开始构建各种智能原型。


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

评论(0)
发评论

下载排行榜

全部0条评论

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