种植植物的宁静和清新是从城市生活的喧嚣中解脱出来的。然而,我们有时会因为生活中的烦恼而无法好好照顾这些美丽的植物。不过不用担心,智能室内花园是自动种植的完美解决方案。即使我们不在家,它也能照料我们的植物。
在这个项目中,我们将一个普通的室内花园改造为一个功能齐全且支持物联网的种植系统。
您可以使室内花园在适度的预算内具有以下功能。
完成原型后,选择一个亚克力盒子来装饰你的花园。
我们将功能划分为更小的构建块,如下图所示。
使用涂鸦智能APP实现远程控制,我们使用涂鸦WB3S网络模块作为主控。涂鸦三明治 Wi-Fi SoC 主控板(WB3S)帮助您快速实现各种智能硬件原型。该板只有一个 ADC 端口,因此我们使用 4 通道模拟多路复用器RS2255来扩展更多模拟通道。
RS2255 提供对三个模拟通道的访问,分别表示为 A1、A2 和 A3。
电路图显示,要读取 A1、A2 和 A3 上的值,嵌入式系统必须首先读取 ADC 值。PWM0 和 PWM1 输出控制 RS2255,这与 ADC 如何连接到模拟通道有关。见下表:
使用BH1750光传感器检测光强度。BH1750 是一款使用 I2C 进行通信的数字环境光传感器。BH1750FVI 是用于 I2C 总线接口的数字环境光传感器 IC。它可以精确测量高达 65535 lx 的光的 LUX 值。BH1750如下图:
引脚配置:
使用SHT21湿度和温度传感器测量环境温度和湿度。SHT21经过全面校准,具有低功耗和出色的长期稳定性。它使用 I2C 协议进行通信。
注意:如果 SHT21 传感器不可用,您可以使用HTU21D传感器替代。
使用土壤湿度传感器测量土壤的含水量。表面镀镍,感应面积大,可提高导电性,防止与土壤接触生锈的问题。该传感器提供模拟和数字输出。数字输出简单,而模拟输出更准确。您可以借助传感器板上的电位器(蓝色)调整传感器的灵敏度。传感器使用 LM393 比较器将土壤湿度水平与预设阈值进行比较。
使用水位传感器测量水箱中的水深。水位传感器具有高性能和低功耗的灵敏度。它可以很容易地将水量转换为模拟信号,输出值可以被微处理器识别,从而实现水位报警。
使用室内花园上的 LED 植物灯补光。生长灯由2835颗LED灯珠组成。共有114颗珠子,分暖白、红、蓝、远红外四个波段,每个波段的比例为25:9:2:2。
为了实现蔬菜以及花卉和水果的两种生长模式,两个 PWM 输出控制光谱。一个控制蓝光,另一个控制暖白光、红光和远红外光。
植物灯板提供暖白光、红光、蓝光和远红外光。频谱报告如下:
植物灯板提供暖白光、红光和远红外光。频谱报告如下:
注意蓝光只能在其他PWM信号输出时进行调节。如果您没有植物灯板,您可以使用两个 PWM 输出交替控制 LED 灯条。
使用 1 通道继电器模块来控制 5V 雾化器模块。造雾器芯片的工作频率为 108 kHz。第八针可用于监测水位,实现低水位切断,防止雾化盘缺水。
使用1路继电器模块控制75W远红外线灯泡。红外线灯泡具有热效率高、遇水防爆、传热快、散热快等特点。重要的是,它可以在潮湿的环境中有效地工作。您可以根据需要使用冷却风扇。
(可选)冷却风扇:使用安装在室内花园中的冷却风扇(12V DC 0.18A)。风扇和红外线灯泡通过220V AC转12V DC电源变压器并联,由继电器模块控制。
使用1路继电器模块控制两个高速冷却风扇(12V 0.5A)。通风可以降低环境温度和湿度,从而为植物授粉。
使用 1 通道继电器模块控制 12V 水泵。您可以根据需要选择供水或将水泵改为12V水电磁阀。
使用 1 通道继电器模块控制两个 12V DC 隔膜泵。水被泵送并施用于土壤。
继电器模块通常用于切换使用比大多数微控制器可以处理的电压更高的电压的设备。
您可以使用两个1路继电器模块和一个4路继电器模块来实现自动喷洒、加热、水箱加水、通风和浇水。
选择一个简单的传统室内花园进行改造。
我们准备了一个传统的室内花园,配有种植灯板和大型土壤容器。
这个花园有以下功能:
花园需要四种电源,即220V AC、12V DC、5V DC和3.3V DC。为此,我们使用以下解决方案:
12V散热风扇与红外线灯泡相连。红外灯泡连接到 220V 交流电源。隔离开关电源模块 (12V 400 mA) 为冷却风扇产生 12V DC。
模块规格:
3.3V DC:涂鸦三明治DC-DC电源板供电。此电源板配备双电源插孔,可接受 12V DC 或 5V DC 电源。
我们使用 Adobe AutoCAD 设计了一个亚克力盒子。注意事项:
下图显示了组件布局供您参考。您可以修改和重新设计以满足您的需求。下载 2D 图纸。
准备以下组件和用品。
根据图纸切割亚克力板。用粘合剂组装丙烯酸组件。
注意事项:
在盖子上钻一个直径合适的孔来固定脱脂棉。放一些沙子或小石头固定棉花的底部。
1.如图所示将造雾器放在盖子上。
2. 重新拧上盖子,但不要太紧。否则无法产生雾气。如果没有瓶子,您可以用热胶固定雾化器。
将组件放入盒子中并整理电线。
进行涂鸦 OS 开发,需要在涂鸦IoT 平台上创建一个室内花园产品,然后获取 SDK。该产品代表了智慧花园的所有物联网功能,包括产品授权和配置,构建了花园与涂鸦物联网平台的通信。本节介绍如何在涂鸦物联网平台上打造智能室内花园。有关详细信息,请参阅创建产品。
您已完成在涂鸦 IoT 平台上创建产品。它已准备好进行嵌入式系统开发。
嵌入式代码基于 BK7231 芯片组,使用涂鸦通用 Wi-Fi SDK 开发。您可以从涂鸦 GitHub 仓库拉取的 demo 例程中获取环境变量,也可以下载包含 SDK 环境变量的 demo 例程。我们通过方法 1 获取 SDK。
ty_iot_wf_bt_sdk_bk7231t
。
克隆存储库以在您的计算机上创建本地副本。打开apps
存储演示代码的文件夹。在这个文件夹中,新建一个文件夹,命名bk7231t_plant_grow_mach_demo
为存放demo相关的源文件、头文件、编译文件。
如果您是第一次接触 BK7231 开发,我们建议您在和文件夹中分别找到tuya_device.c
和并将它们复制到这个新创建的文件夹中。tuya_device.h
src
include
bk7231t_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
.
应用程序代码分三层实现。
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
. 以下程序描述了温度和湿度、光照和土壤湿度方面的控制逻辑。
要控制温度和湿度,首先我们必须收集数据。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();
}
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();
}
土壤湿度传感器根据土壤电阻的变化输出不同的模拟信号值。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_COUNT
。ADD_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();
......
}
水泵用于从水箱抽水并向工厂供水。当水位下降时,需要另一个水泵为水箱供水。水位传感器根据电阻产生输出电压,通过测量我们可以确定水位。我们需要使用 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数据传输后,我们就可以进行固件编译了。
在 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
将固件烧录到模块后,我们开始进行功能调试。有关刻录和授权的更多信息,请参阅刻录和授权 WB 系列模块。
一旦模块被授权,我们将手机连接到 Wi-Fi 网络,打开蓝牙,按照说明对花园进行配对。然后,我们可以用应用程序控制花园。在本项目中,我们使用涂鸦智能 App 作为控制终端。有不同的应用程序选项。有关详细信息,请参阅应用程序开发。
调试过程如下:
2.设置灯光颜色,生长灯板相应改变颜色。
3.当倒计时设置为取消时,植物灯板将关闭。
4.开启自动补光后,灯光亮度会不断增加,直到达到预设值。
1.可以在涂鸦智能APP上查看当前环境温度和湿度。
2.如果您设置的最小湿度大于当前湿度,雾化器将启动。当环境湿度超过最小值时,制雾器将停止。
3.如果您设置的最低温度高于当前温度,红外线灯泡将打开。当环境温度超过最小值时,红外灯泡将停止。
4.以同样的方式测试最高温度和湿度,并观察冷却风扇是否相应运行。这个风扇可以对空气进行除湿和冷却。
1.可查看水箱水位剩余水百分比。
2.在涂鸦智能APP开启Pump ,开启水泵。
1:通风继电器模块
2:喷涂继电器模块
3:补水箱继电器模块
3.将水位传感器放入杯中,加水至铜线完全没入。您会发现水泵停止并且应用程序上的Pump恢复。
4.水箱水位变为100。
2.将土壤湿度传感器放入水中,模拟土壤湿度达到阈值的情况。你会发现水泵停止。
恭喜!您已成功构建智能室内花园的原型。依托涂鸦物联网平台,您可以快速轻松地从零开始构建各种智能原型。
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
全部0条评论
快来发表一下你的评论吧 !