新闻  |   论坛  |   博客  |   在线研讨会
【真香现场】为老婆 DIY 一款集多功能于一身的环境检测仪,守护家人健康全靠它!【内附原理图+源代码】
智能物联研习社 | 2021-04-24 17:58:57    阅读:3486   发布文章


近日,刚入住新房,老婆说:“家里有没有甲醛超标呀!? 总感觉闻着一股味儿~"

我顿时心里一紧,感觉被无形的、摸不着的危害威胁着生命。

心想:“不行、不行,一定要买个环境检测仪,来检测一下!”

家中老小的健康安全,促使我打开了X宝,准备入手个环境检测仪。

但......(急刹车!)

定睛一看,环境监测仪怎么那么贵,并不是说"剁手”就能“剁手”的(紧紧裹住自己小钱袋)!

而且,市面上大多数的环境监测仪并没有拥有多功能的性能,难道要买好几个不同功能点的仪器吗?

NO!  既烧钱,又麻烦 !

灵机一动,不如自制一个环境检测仪,实时检测空气健康安全,在家,在公司,随时拿出来测一测,节能环保,健康安全!

有了想法,必须付诸实践~毕竟不是光说说的!

先来张定妆照~


new


戳以下链接,回复“环境检测仪2”,即可获取50元模组券以及详细开发者资料,手慢无!!

 https://www.wjx.cn/vj/wFXuAGU.aspx  


开启动我的DIY之路~

先给大家介绍几款简单的传感器,如果大家有别的传感器,也可以采用!

一、甲醛检测


ZE08-CH2O型电化学甲醛模组,是一个通用型、小型化模组,利用电化学原理对空气中存在的CH2O进行探测,具有良好的选择性,稳定性。内置温度传感器,可进行温度补偿;同时具有数字输出与模拟电压输出,方便使用。

具体电气参数如图:

注 释 : 气 体 浓 度 值 (PPB)=( 气 体 浓 度 高 位 *256+ 气 体 浓 度 低 位 ). 当 转 换 为 PPM 时 : PPM= PPB/1000.
1PPM×1.25 = 1.25mg/m3.

其中Byte8校验值=(取反(Byte1+Byte2+……+Byte7))+ 1

二、PM2.5检测


PM2.5检测采用ZPH02 空污粉尘传感器。它整合了红外PM2.5检测原理和较为成熟的VOC检测技术,能够实现对同一环境中PM2.5和VOC的同时检测。

该传感器中PM2.5检测采用粒子计数原理,可灵敏检测直径1μm以上灰尘颗粒物,VOC传感器对有机挥发气体具有极高的灵敏度。

PM2.5+

PM2.5-

具体电气参数如图:


备注:
对PM2.5 的计算:
举例:传感器发出一帧正常数据中,第 3位 0X12,第 4位 0X13。则表示:传感器输出的占空比为18.19%。
串口模式下低脉冲率输出范围 0.5%-50%。


对 VOC气体检测:
每一帧数据中第 7位表示 VOC输出,直接输出 0x01-0x04四个等级,依次对应“优、良、中、差”,无传感器
或故障时显示 0x00;

其中Byte8校验值=(取反(Byte1+Byte2+……+Byte7))+ 1

三、烟雾检测


烟雾检测采用MQ-2烟雾传感器,该传感器可用于家庭和工厂的气体泄漏监测装置,

适宜于液化气、苯、烷、酒精、氢气、烟雾等的探测。

MQ2--

传感器灵敏度曲线如图


MQ2_S

为了减少开发周期,本次采购了MQ-2烟雾传感器模组

MQ2

该模块原理图如下


MQ系列气体传感器模块电路图


如图可知,可以通过检测AO端的电平电压,来判断烟雾大小(电压越高,烟雾浓度越高)。

四、燃气检测

燃气检测采用MQ-4气体传感器,该传感器对甲烷,天燃气有很高的灵敏度,广泛适用于家庭用气体泄漏报警器、工业用可燃气体报警器以及便携式气体检测器。电气特性如下


传感器灵敏度曲线如图

MQ4灵敏度

为了减少开发周期,本次采购了MQ-4气体传感器模组。该模组的原理图和MQ-2烟雾传感器模组相同,可以通过检测AO端的电平电压,来判断燃气浓度(电压越高,燃气浓度越高)。

五、火焰检测


火焰检测采用红外接收管,该管可以用来探测火源或其它一些波长在700纳米~1000纳米范围内的热源。当无红外光照时,有很小的饱和和反向漏电流(暗电流),此时光敏管不导通。当有红外光照时,饱和反向漏电流马上增加,形成光电流,在一定的范围,它随入射光强度的增大而增大。

为了减少开发周期,本次采购了市面上常见的火焰传感器模组
火焰传感器

原理图如下

火焰原理图

可以通过检测AO端的电平电压,来判断火势的强弱(电压越低,火势越强)。


1、环境安全卫士电路设计

到此步,大家肯定都已经选择好心仪的环境传感器,接着就带大家基于这些传感器,设计一款环境安全卫士电路~

主控单元选择WB3S 模组,这是一款由涂鸦智能开发的低功耗嵌入式Wi-Fi+BLE 双协议模组。它由一个高集成度的无线射频芯片BK7231T和少量外围器件构成,内置了Wi-Fi网络协议栈和丰富的库函数。由于ADC口资源不足,我们还需对其进行适当修改,拓展ADC接口,具体措施是在电路中增加一款四通道模拟多路复用/解复用器芯片——RS2255。这是一款是数字控制的模拟开关,它的导通电阻只有24欧姆,漏电流只有1nA。

另外,本方案使用了较多传感器,为了减少走线,使整体更加简洁美观,主控板需要引出各种传感器接口,而且各个模块与主控板的通信接口电平存在不匹配的现象,模块供电电压也存在差异。

为了解决上述问题,具体原理图设计如下


SCHV3

PCB如下

PCBV2

原理图与PCB查看:

下载地址

  • 原理图

  • PCB


戳以下链接,回复“环境检测仪2”,即可获取50元模组券以及详细开发者资料,手慢无!!

 https://www.wjx.cn/vj/wFXuAGU.aspx  



  • 2、环境安全卫士实物搭建

这一步结束,大家肯定也都完成了环境安全卫士电路设计,接下来就要把PCB文件发给PCB厂家进行打样。

这个过程,很培养大家的动手能力,看着枯燥却又会带着欢乐,当然也要注意安全,别被烙铁烫着。
电容电阻三极管焊好之后,接下来就比简单啦。只需要根据结构空间要求,将各个传感器模块安插在对应的位置上,并完成焊接固定。
为了使走线更加精简,可直接将甲醛传感器的VCC,GND,TXD焊到P5的VCC,GND,RXD,其他传感器同理。

全部焊好之后,效果如图:

front1

back1

怎么样,是不是有点小开心~
但是可能也有同学觉得太丑,光秃秃的,都是电路。


别急!为了增加产品的可使用性,我选择了一款带台灯的插座,对其进行改造,将环境安全卫士固定在台灯支架上,这样在检测房间空气质量的同时,还可以检测插座上的设备是否出现火灾等危险情况,尤其是可以对手机等这类锂电池设备充电引发的安全问题恶化之前进行提前通知,防止灾难的进一步发生。


台灯

当然,用户也可以根据自身需求,将本环境安全卫士和其他设备进行关联。

台灯内可增加一路继电器控制,当异常发生时,自动断开220V市电,降低损失。


image.png

以上相关准备工作完成后,接下来就可以开始正式的产品搭建工作。


1.将台灯的灯罩拆开,可以看到里面的LED灯板和两根正负电源线,用电烙铁等工具将LED灯板拆除

step1

2.将台灯底座的四个海绵垫拆除,卸下螺丝,可以拆除底座

step1.5

3.将主控板固定在灯罩区域适当位置,将两根正负电源线分别焊到主控板上的P6端,这样当按下插座上的“台灯”按钮时,插座就可以给主控板提供5V电压,注意区分正负极。

4.修改台灯电路,在火线电路中串入一个继电器,并引出继电器控制线

step4

5.将上一步引出的控制线焊于主控板P2的Sig处,并安装灯罩,底座。

all

当然,我们也可以激发自己创意,给它穿上不同外衣

all2

这样,整机搭建基本完成。

另外,也可以根据自己的创意,设计出其他外观,比如:

new

外形结构文件下载链接


在这里插入图片描述

上罩壳

在这里插入图片描述

下罩壳


下面,讲一讲关于固件开发 part~


3、环境安全卫士固件开发


开发环境是在Linux下进行开发的,环境搭建和SDK的拉取可以在涂鸦 github 上的仓库 上进行学习。

该代码是基于1.0.2版本的 SDK 进行开发的,第一次接触soc开发的同学,可以在 涂鸦github上的仓库 上拉取代码进行学习和开发。该代码中的 apps/template-demo 比较简单,可在该代码的基础上进行学习或开发。

本 demo可在github上下载源代码 ,下载完成源代码后,将代码放入SDK里面的APPS文件夹下。进行编译下载就可以了。编译后的产物中会出现QIO,UA,UG文件其中QIO是生产固件,UA是用户去固件,UG是升级固件。
在这里插入图片描述

本 demo主要是通过3种方式进行获取传感器信息的,分别是串口,adc,检测引脚高低电平。下面将以这三种方式进行简单的介绍。

1.串口类传感器:甲醛,pm2.5

  • 甲醛传感器相关资料

  • PM2.5传感器资料

通过阅读甲醛传感器的资料我们可以发现,传感器数据上传格式和计算方法如下:

 /***********************************************************
 *   Function:  get_ch2o_sensor_value
 *   Input:     none
 *   Output:    none
 *   Return:    none
 *   Notice:    得到并上传甲醛的数据
 ***********************************************************/
static VOID get_ch2o_sensor_value(VOID)
{
    UINT_T  buff_ret, find_head_index = 0;
    //甲醛数据高位,低位
    UCHAR_T ch2o_data_high, ch2o_data_low;
    //校验和
    UCHAR_T check_sums = 0x00;    
    //串口数据缓存区
    UCHAR_T ch2o_receive_buffer[CH2O_BUFFER_SIZE];
    //指向甲醛数据头部
    UCHAR_T *p_ch2o_value = NULL;

    memset(ch2o_receive_buffer, 0, sizeof(ch2o_receive_buffer));

    //读取串口数据
    bk_uart_recv(CH2O_SENSOR_UART, ch2o_receive_buffer, CH2O_BUFFER_SIZE, 0xFFFF);

    // for (find_head_index = 0; find_head_index<CH2O_BUFFER_SIZE; find_head_index++) {
    //     PR_NOTICE("ch2o_receive_buffer[%d] = %02x", find_head_index, ch2o_receive_buffer[find_head_index]);
    // }

    //寻找 ch2o 传感器发送过来的头部
    for (find_head_index = 0; find_head_index<CH2O_BUFFER_SIZE; find_head_index++) {
        if (ch2o_receive_buffer[find_head_index] == 0xff && \
            ch2o_receive_buffer[find_head_index+1] == 0x17 && \
            ch2o_receive_buffer[find_head_index+2] == 0x04){
            //PR_NOTICE("find head is %d", find_head_index);
            break;
        }
    }

    //本次采集数据不完整
    if (find_head_index > 11) { 
        PR_ERR("ch2o get uart data no complete!");
        return;
    }

    //将指针指向 ch2o 数据中的头部
    p_ch2o_value = ch2o_receive_buffer + find_head_index;

    //检验和,确认读取的数据的准确性
    check_sums = ch2o_check_sum(p_ch2o_value, 9);
    if (check_sums != *(p_ch2o_value + 8)) {
        PR_ERR("ch2o check_sums error");
        return;
    }
    
    ch2o_data_high = *(p_ch2o_value+4);
    ch2o_data_low = *(p_ch2o_value+5);

    gs_air_box.ch2o_value = ch2o_data_high * 256 + ch2o_data_low;

    //PR_NOTICE("ch2o value is : %d .", gs_air_box.ch2o_value);

    //上传 ch2o 数据到涂鸦云
    updata_dp_single(gs_air_box.dp_ch2o_value, PROP_VALUE, gs_air_box.ch2o_value);

    return;
}

校验和的计算方式为:

 /***********************************************************
 *   Function:  ch2o_check_sum
 *   Input:     none
 *   Output:    none
 *   Return:    none
 *   Notice:    甲醛数据校验和
 ***********************************************************/
static UCHAR_T ch2o_check_sum(UCHAR_T *data, UCHAR_T len)
{
    UCHAR_T i, tempq = 0;
    data += 1; //指向data[1]

    for(i=0; i<(len-2); i++)
    {
        tempq += *data;
        data++;
    }

    tempq = (~tempq) + 1;

    return (tempq);
}


PM2.5的获取方法和甲醛的很相似,这里不再过多介绍。

2.ADC类传感器:燃气传感器,烟雾传感器

相关资料
由于在WB3S上只要一个ADC,所以我们这里用RS2255 芯片进行复用,引脚选择如下:


ADC初始化:

/* ADC */
#define ADC_DATA_LEN    4
static  tuya_adc_dev_t  tuya_adc;

static VOID adc_init(VOID)
{
    tuya_adc.priv.pData = Malloc(ADC_DATA_LEN * sizeof(USHORT_T)); //这里一直使用tuya_adc,所有后面就没有释放该空间
    memset(tuya_adc.priv.pData, 0, ADC_DATA_LEN*sizeof(USHORT_T));
    tuya_adc.priv.data_buff_size = ADC_DATA_LEN; //设置数据缓存个数
}


ADC采集:

 /***********************************************************
 *   Function:  get_adc_value
 *   Input:     none
 *   Output:    adc_value : 采集到的 adc 值
 *   Return:    none
 *   Notice:    得到 adc 采集的电压值
 ***********************************************************/
VOID get_adc_value(OUT USHORT_T* adc_value) 
{
    INT_T ret;

    if (adc_value == NULL) {
        PR_ERR("pm25_adc_value is NULL");
        return;
    }
    memset(tuya_adc.priv.pData, 0, ADC_DATA_LEN*sizeof(USHORT_T));
    ret = tuya_hal_adc_init(&tuya_adc);
    if (ret != OPRT_OK) {
        PR_ERR("ADC init error : %d ", ret);
        return;
    }

    ret = ret = tuya_hal_adc_value_get(ADC_DATA_LEN, adc_value); 
    if (ret != OPRT_OK) {
        PR_ERR("ADC get value error : %d ", ret);
    }

    tuya_hal_adc_finalize(&tuya_adc);
    return;
}

烟雾传感器,数据获取:

/* 烟雾传感器 */
#define SMOKE_ALARM_LIM 1.0

/***********************************************************
 *   Function:  get_smoke_sensor_value
 *   Input:     none
 *   Output:    none
 *   Return:    none
 *   Notice:    得到并上传烟雾的数据,A1
 ***********************************************************/
static VOID get_smoke_sensor_value(VOID)
{
    USHORT_T    smoke_adc_value;
    FLOAT_T     smoke_volt; 

    //复用 adc 到 A1 
    tuya_gpio_write(RS2255_A, FALSE);
    tuya_gpio_write(RS2255_B, TRUE);

    tuya_hal_system_sleep(500);

    //得到烟雾传感器 ad 值
    get_adc_value(&smoke_adc_value);
    //PR_NOTICE("smoke_adc_value : %d ", smoke_adc_value);

    //计算实际电压值
    smoke_volt = (smoke_adc_value / 4095.0) * 2.4 * 2;
    //PR_NOTICE("smoke_volt : %lf ", smoke_volt);

    //判断是否到报警门限值
    if (smoke_volt >= SMOKE_ALARM_LIM) {
        gs_air_box.smoke_state = ALARM;
    } else {
        gs_air_box.smoke_state = NORMAL;
    }

    //上传数据
    updata_dp_single(gs_air_box.dp_smoke_state, PROP_ENUM, gs_air_box.smoke_state);

    //PR_NOTICE("get smoke value, updata...");
    return;
}

燃气传感器和烟雾相似,这里就不再过多介绍。

3.检测引脚高低电平获取状态:火焰传感器

火焰传感器,检测到火焰后断开220v电源,重启后220v通电,防止发生意外情况。

 /***********************************************************
 *   Function:  get_smoke_sensor_value
 *   Input:     none
 *   Output:    none
 *   Return:    none
 *   Notice:    得到并上传火焰的数据
 ***********************************************************/
static VOID get_flame_sensor_value(VOID)
{
    if (FALSE == tuya_gpio_read(FLAME_SENSOR_PIN)) {
        gs_air_box.flame_state = ALARM;
        /* 检测到火焰,拉低220V控制引脚,断电 */
        tuya_gpio_write(POWER_OFF_220V_PIN, FALSE);
    } else {
        gs_air_box.flame_state = NORMAL;
    }

    updata_dp_single(gs_air_box.dp_flame_state, PROP_ENUM, gs_air_box.flame_state);

    return;
}


4.设备初始化:

启动时,先对环境安全卫士相关的外设和引脚进行初始化设置,创建信号量,传感器预热,预热完成后释放信号量,开始采集。


 /***********************************************************
 *   Function:  air_box_device_init
 *   Input:     none
 *   Output:    none
 *   Return:    none
 *   Notice:    环境安全卫士设备初始化
 ***********************************************************/
VOID air_box_device_init(VOID)
{
    INT_T opRet = OPRT_OK;

    /* 火焰传感器相关外设初始化 */
    tuya_gpio_inout_set(FLAME_SENSOR_PIN, TRUE);
    tuya_gpio_inout_set(POWER_OFF_220V_PIN, FALSE);
    /* 启动时,拉高220V控制引脚,通电 */
    tuya_gpio_write(POWER_OFF_220V_PIN, TRUE);

    /* ADC 复用,相关引脚初始化 */ 
    tuya_gpio_inout_set(RS2255_A, FALSE);
    tuya_gpio_inout_set(RS2255_B, FALSE);
    adc_init();

    /* 甲醛传感器使用 uart2 接收数据,在函数 app_init() 里面已经修改完成波特率 */
    
    /* pm2.5 传感器 串口 初始化 */
    ty_uart_init(PM25_SENSOR_UART, TYU_RATE_9600, TYWL_8B, TYP_NONE, TYS_STOPBIT1, (PM25_BUFFER_SIZE * SIZEOF(UCHAR_T)), TRUE);

    /* 创建信号量 */
    opRet = tuya_hal_semaphore_create_init(&preheat_semaphore, 0, 1);
    if (opRet != OPRT_OK) {
        PR_ERR("creat preheat semaphore error : %d", opRet);
    }

    /* 预热 60s 后释放信号量,开始采集传感器数据 */
    opSocSWTimerStart(preheat_timer, SENSOR_PREHEAT_TIME, preheat_semaphore_post_task); 

    tuya_hal_thread_create(NULL, "acquire sensor data", 512*4, TRD_PRIO_2, acquire_data_task, NULL);
}

预热完成释放信号量:

VOID preheat_semaphore_post_task(VOID)
{
    //预热完成,释放信号量
    tuya_hal_semaphore_post(preheat_semaphore);
    //关闭预热软件定时器
    opSocSWTimerStop(preheat_timer);

    //预热完成,上传预热完成数据到涂鸦云
    gs_air_box.preheat_state = false;
    updata_dp_single(gs_air_box.dp_preheat, PROP_BOOL, gs_air_box.preheat_state);
}

传感器采集数据任务轮询函数:

 /***********************************************************
 *   Function:  acquire_data_task
 *   Input:     none
 *   Output:    none
 *   Return:    none
 *   Notice:    获取传感器数据任务
 ***********************************************************/
VOID acquire_data_task(VOID)
{
    //等待预热完成
    tuya_hal_semaphore_wait(preheat_semaphore);

    while (1) {
        get_ch2o_sensor_value();
        get_flame_sensor_value();
        get_gas_sensor_value();
        get_pm25_sensor_value();
        get_smoke_sensor_value();
        tuya_hal_system_sleep(500);
    }
}

整机演示1.实时显示当前空气状况

烧录授权 完成后,设备就可以正常配网了。连接WiFi,打开蓝牙,按照配网流程成功配网后,即可使用app控制设备。已经配网成功的设备,可长按按键再次进入配网模式。

环境安全卫士APP显示界面:


app

2.报警

当烟雾,燃气或者火焰三者中有一种的浓度大于设定值,则app会显示报警状态,并且断开220V电压。


img

至此,我们已经成功完成多功能环境安全卫士的开发~搓搓手,原来DIY一款如此高级的环境检测仪也是如此简单~



戳以下链接,回复“环境检测仪2”,即可获取50元模组券以及详细开发者资料,

手慢无!!

 https://www.wjx.cn/vj/wFXuAGU.aspx  

心动不如行动~ 老铁们!在家、在公司也能让室内环境变得更健康、安全!有趣又省钱的难道不香吗?



*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
推荐文章
最近访客