Hardware | ZE08-CH2O Formaldehyde 센서 사용해보기

|

1. 환경 호르몬


사람은 호르몬으로 살아간다고 해도 과언이 아닙니다.

컨디션, 감정, 치유, 성장, 성향, 행동 등, 인간의 몸안에서 일어나는 거의 모든 화학작용과 관련이 되어 있으며, 몸을 컨트롤 합니다.


다만 아쉽게도, 현대 사회로 진입하면서 생활은 편해졌지만, 화학 물질 등으로 인하여 몸 안의 호르몬들이 교란을 잃으키고 있습니다.

더 무서운 것은 이 "환경 호르몬" 은 거의 모든 곳에 도사리고 있다는 것이지오.

특히 환경 호르몬 중에서는 "포름알데히드" 가 그 주범 물질 중 하나 입니다.


* Formaldehyde

https://en.wikipedia.org/wiki/Formaldehyde



* 포름알데하이드

https://namu.wiki/w/%ED%8F%AC%EB%A6%84%EC%95%8C%EB%8D%B0%ED%95%98%EC%9D%B4%EB%93%9C


메탄올을 잘못 마셨을 때, 실명이나 사망을 일으키는 것도 이 포름알데히드 때문이다. 메탄올이 신체 내부로 유입되면 간에서 포름알데히드 및 포름산이라는 물질로 변환되는데, 특히 포름알데히드는 시신경을 손상시키고 단백질 조직을 변성시켜 굳혀버리는 효과를 갖고 있기 때문에 이런 위험한 상황이 발생하게 되는 것이다.


가구, 특히 MDF를 사용한 가구에서는 본드와 페인트에 의해 포름알데히드가 공기 중으로 방출된다. 소위 새집증후군, 아토피의 원인으로 지목되고 있으며, 새 가구를 샀을 때 매캐한 냄새, 눈이나 목의 따가움을 느꼈다면 이것 때문이다. 포름알데히드는 성인은 물론 특히 어린이에게 매우 유해하기 때문에 실내가구의 방출량은 각국에서 규제하고 있다. 다만 포름알데히드 측정에 대한 국제 표준이 없기 때문에 국가별로 측정방법 및 규정이 다른 상태다.


다이X 같은 곳에 가면, 온갖 화학물질이 공기 중에 떠다니는 것을 대번에 느낄 수 있습니다. 이게 환경호르몬 = 포름알데히드 입니다.


값싸게 제품을 만들다 보니, 출처가 불분명한 재료와, 후처리 되지 않은 채로 공장에서 나와 유통되기 때문이죠.

특히 중국산 물건에서 많이 느낄 수 있습니다. 손이 쥐여지는 것을 입으로 쉽게 가져가는 애기들을 생각하면 소름 돋는 장소라고 생각합니다.




2. 포름알데히드 센서


그럼, 포름알데히드를 측정할 수 있는 센서는 없을까, 하고 찾아 봤습니다. 있네요.

구매를 작년 9월쯤 했을 때에는 위의 가격이었는데, 요즘은 조금 저렴해 졌습니다.


* Formaldehyde sensor ZE08-CH2O serial output formaldehyde concentration measurement with cable

https://ko.aliexpress.com/item/32842350486.html



이 센서에 사용된 "ZE08-CH2O" 는 그리 널리 사용되지 않지만, 아두이노 센서 breakout 보드를 생산하는 DFRobot - Gravity 회사에서도 출시 했을 만큼 완전 무명도 아닙니다. (이 글의 후반부에서 그림과 함께 조금 설명 해놨습니다.)


* ZE08-CH2O formaldehyde gas sensor module

https://www.winsen-sensor.com/sensors/ch2o-gas-sensor/ze08-ch2o.html

ZE08-CH2O_V1.0.pdf




3. 도착


도착샷은 예의 입니다.



센서는 PCB 보드 윗쪽에 얹혀져 있습니다.



Breakout 보드 밑부분은 센서값 처리를 위한 회로 및 IC chip 들로 빼빽하게 차 있습니다.

센서 종류로 14 USD 나 하는, 비싼 값을 하는 이유가 있네요.





4. Specification


메인 chip 에 붙어 있는 IC20 이라는 스티커를 제거하면, chip 명칭을 알 수 있습니다.



사진으로는 흐릿하게 나와서, 제품 설명 그림을 가져와 봤습니다.

STMicroelectronics 사의 32-bit ARM Cortex-M 프로세서라는 것을 알 수 있습니다.


stm32f030f4.pdf



STM32F030F4 네요. 아래 장표를 보면 32-bit ARM Cortex-M 에서 Mainstream 에 해당하는 chip 입니다.



동일 계열의 칩 중에서는 USB 인터페이스가 생략되어 있고, 메모리가 가장 적은 버전이군요.



ZE08-CH2O 의 인터페이스는 다음과 같습니다.



인터페이스 선들을 살펴 보면, 신호를 받는 방식이 PWM, UART, 그리고 DAC 세 가지 임을 알 수 있습니다.

아래는 default 연결인 Active Upload type 방식이라고 하는데, 기본적으로 TX/RX 를 사용하는 UART 방식을 표시합니다.





5. Arduino 용 Active Upload 소스


Default 방식인 Active Upload (UART) 소스 입니다.


* Serial Communication CH2O sensor
    - https://forum.arduino.cc/index.php?topic=547952.0


Sketch 는 다음과 같습니다.


#include "arduino.h"
#include "SoftwareSerial.h"

#define MAXLENGTH 9
#define VREF 5.0 // voltage on AREF pin

long tenMinutes = 10 * 60 * 1000L; // on time of heater
SoftwareSerial mySerial(10, 11);

byte receivedCommandStack[MAXLENGTH];
byte checkSum(byte array[], byte length);
boolean receivedFlag;

void setup() {
	// put your setup code here, to run once
	mySerial.begin(9600);
	Serial.begin(115200);
}

void loop() {
	ze08_PPM();
}

byte checkSum(byte array[], byte length) {
	byte sum = 0;
	for (int i = 1; i < length - 1; i ++) {
		sum += array[i];
	}
	sum = (~sum) + 1;
	return sum;
}

boolean available1() { //new data was recevied
	while (mySerial.available()) {
		for (byte index = 0; index < MAXLENGTH - 1; index++) {
			receivedCommandStack[index] = receivedCommandStack[index + 1];
		}
		receivedCommandStack[MAXLENGTH - 1] = mySerial.read();
		
		byte sumNum = checkSum(receivedCommandStack, MAXLENGTH);
		if ( (receivedCommandStack[0] == 0xFF) && (receivedCommandStack[1] == 0x17) && (receivedCommandStack[2] == 0x04) && (receivedCommandStack[MAXLENGTH - 1] == sumNum) ) { //head bit and sum are all right
			receivedFlag = 1; //new data received
			return receivedFlag;
		} else {
			receivedFlag = 0; //data loss or error
			return receivedFlag;
		}
	}
	return receivedFlag;
}

float ze08_PPM() {
	if (available1() == 1) {
		receivedFlag = 0;
		
		float ppb = (unsigned int) (receivedCommandStack[4] * 256) + receivedCommandStack[5]; // bit 4: ppm high 8-bit; bit 5: ppm low 8-bit
		float ppm = ppb / 1000; // 1ppb = 1000ppm
		delay (1000);
		Serial.print("Formalin ppm == ");
		Serial.println(ppm);
		return ppm;
	}
}

float analogReadPPM() {
	float analogVoltage = analogRead(A0) / 1024.0 * VREF;
	float ppm = 3.125 * analogVoltage - 1.25; //linear relationship (0.4V for 0 ppm and 2V for 5ppm)
	
	if( ppm < 0 ) {
		ppm = 0;
	} else if( ppm > 5 ) {
		ppm = 5;
	}
	delay (1000);
	return ppm;
}


Arduino 와의 Pin 연결은 다음과 같습니다.


 ZE08-CH2O | Arduino Nano
--------------------------
   6 (TX)  |      D10
   5 (RX)  |      D11
--------------------------
           |     POWER
--------------------------
    VCC    |      3.3V
    GND    |      GND
--------------------------


회로 diagram 도 그려 봤습니다.


실재로 연결할 선들은 CO2 센서인 MH-Z14A 와 갯수와 크기가 동일하여, 만들어 놨던 선을 사용 했습니다.


* Hardware | CO2 센서인 MH-Z14A 를 활용해 보자

https://chocoball.tistory.com/entry/Hardware-CO2-sensor-MH-Z14A


사용하지 않는 선들은 빵판 고정용으로 사용. :-)



아래와 같이 값이 표시됩니다. Calibration 이 적용되지 않아서, 이 값이 정확한 것인지는 모르겠습니다.

센서 주변 공기가 바뀌면, 그에 따라서 센서값도 달라집니다.





6. DFRobot 용 소스 - DAC


UARTDAC 를 스위치 하나로 변경하면서 사용할 수 있는 breakout 보드를 DFRobot 에서 출시한 제품도 있습니다.


* Gravity: Formaldehyde (HCHO) Sensor
    - https://www.dfrobot.com/product-1574.html



깔끔하게 잘 만들었네요. 저는 비싸서 구입하지 않았습니다.



Breakout 보드도 Pin 별로 이미 구분되어 있어서, 조금 아는 사람이면 굳이 DFRobot 제품을 구매할 필요는 없을 듯 하다.


DFRobot / DFRobotHCHOSensor - A library for DFRobot Gravity HCHO Sensor, Arduino Compatible.

https://github.com/DFRobot/DFRobotHCHOSensor

DFRobotHCHOSensor.zip


* Gravity HCHO WiKi
    - https://wiki.dfrobot.com/Gravity__HCHO_Sensor_SKU__SEN0231


DFRobot 도 동일한 센서를 사용했으므로, DAC 소스를 가져다 사용해 봅시다.


/***************************************************
 DFRobot Gravity: HCHO Sensor
 "https://www.dfrobot.com/wiki/index.php/Gravity:_HCHO_Sensor_SKU:_SEN0231"

 ***************************************************
 This example reads the concentration of HCHO in air by DAC mode.

 Created 2016-12-15
 By Jason "jason.ling@dfrobot.com@dfrobot.com"

 GNU Lesser General Public License.
 See "http://www.gnu.org/licenses/" for details.
 All above must be included in any redistribution
 ****************************************************/

 /***********Notice and Trouble shooting***************
 1. This code is tested on Arduino Uno with Arduino IDE 1.0.5 r2.
 2. In order to protect the sensor, do not touch the white sensor film on the sensor module,
 and high concentration of Hydrogen sulfide, hydrogen, methanol, ethanol, carbon monoxide should be avoided.
 3. Please do not use the modules in systems which related to human being’s safety.
 ****************************************************/

#define SensorAnalogPin A2 // this pin read the analog voltage from the HCHO sensor
#define VREF 5.0 // voltage on AREF pin

void setup() {
	Serial.begin(115200);
}

void loop() {
	Serial.print(analogReadPPM());
	Serial.println("ppm");
	delay(1000);
}

float analogReadPPM() {
	float analogVoltage = analogRead(SensorAnalogPin) / 1024.0 * VREF;
	float ppm = 3.125 * analogVoltage - 1.25;    //linear relationship(0.4V for 0 ppm and 2V for 5ppm)
	
	if( ppm < 0) {
		ppm = 0;
	} else if( ppm > 5) {
		ppm = 5;
	}
	return ppm;
}


Arduino 와 연결되는 Pin 정보는 다음과 같습니다.


 ZE08-CH2O | Arduino Nano
--------------------------
  2 (DAC)  |      A2
--------------------------
           |     POWER
--------------------------
    VCC    |      3.3V
    GND    |      GND
--------------------------


Layout 구성도 입니다.



실재로 구현한 사진 :-)



Default 연결 방식인 Active Upload 방식과는 값의 차이가 많이 날 뿐더러, 일관적인 값을 보여주지 않습니다.





7. DFRobot 용 소스 - UART


이번에는 DFRobot 에서 나온 UART 방식의 소스를 이용해 봅니다.


/***************************************************
 DFRobot Gravity: HCHO Sensor
 "https://www.dfrobot.com/wiki/index.php/Gravity:_HCHO_Sensor_SKU:_SEN0231"

 ***************************************************
 This example reads the concentration of HCHO in air by UART mode.

 Created 2016-12-15
 By Jason "jason.ling@dfrobot.com@dfrobot.com"

 GNU Lesser General Public License.
 See "http://www.gnu.org/licenses/" for details.
 All above must be included in any redistribution
 ****************************************************/

 /***********Notice and Trouble shooting***************
 1. This code is tested on Arduino Uno with Arduino IDE 1.0.5 r2.
 2. In order to protect the sensor, do not touch the white sensor film on the sensor module,
 and high concentration of Hydrogen sulfide, hydrogen, methanol, ethanol, carbon monoxide should be avoided.
 3. Please do not use the modules in systems which related to human being’s safety.
 ****************************************************/

#include "DFRobotHCHOSensor.h"
#include "SoftwareSerial.h"

#define SensorSerialPin 10 // this pin read the uart signal from the HCHO sensor

SoftwareSerial sensorSerial(SensorSerialPin, SensorSerialPin);
DFRobotHCHOSensor hchoSensor(&sensorSerial);

void setup() {
	sensorSerial.begin(9600); // the baudrate of HCHO is 9600
	sensorSerial.listen();
	Serial.begin(115200);
}

void loop() {
	if(hchoSensor.available() > 0) {
		Serial.print(hchoSensor.uartReadPPM());
		Serial.println("ppm");
	}
}


Arduino 와의 Pin 연결은 다음과 같습니다.


 ZE08-CH2O | Arduino Nano
--------------------------
   6 (TX)  |      D10
--------------------------
           |     POWER
--------------------------
    VCC    |      3.3V
    GND    |      GND
--------------------------


Layout 그림도 그려 봤습니다.



실재 구성 모습 입니다.



처음 시도한 UART 소스의 결과값과 거의 동일하게 나옵니다.
DFRobot 라이브러리에서 거의 모든 처리가 이루어 지지만, 처음 시도한 UART 방식과 동일한 듯 합니다.




8. ESP8266 용 소스


인터넷 바다를 떠돌다가, ESP8266 을 이용한 소스를 발견하게 됩니다.


* rsalinas/ze08-ch2o-arduino

https://github.com/rsalinas/ze08-ch2o-arduino


Remember that this sensor requires 5V in Vcc but does NOT tolerate 5V in its RX input. If you just want to use the default, active mode, you don't even need to connect this pin, so you can connect directly 5V, GND and Arduino's RX.


ZE08-CH2O.zip


궁극적으로는 WiFi > internet 을 통하여 sensor data 를 올리고, 모니터링 방식이 좋으므로, 잘 되었습니다.

ESP8266 에서 돌아가는 소스라면, WiFi 연결 코드만 추가하면 추가로 arduino 필요 없이 바로 구현이 가능 하겠습니다.


지금까지는, arduino 와 sensor 를 연결하고, ESP8266 은 오로지 WiFi 용으로만 사용하는 구성이었습니다.

ESP8266 에서 sensor 값 감지와 WiFi 가 동시에 되면, arduino 를 사용할 필요가 없어 효율이 좋겠네요.


ZIP 파일을 그대로 Library 에 추가 합니다.


Sketch > Include Library



Libraries 폴더에 보면, 새롭게 올라가 있는 것을 확인할 수 있습니다.



소스를 보면 Basic 하나만 등록되어 있습니다.


File > Examples > ze08-ch2o > Basic



Sketch 는 다음과 같습니다. SoftwareSerial 에서 조금 손을 봤습니다.


#include "ze08_ch2o.h"
#include "SoftwareSerial.h"

// Instantiate a serial port, whatever Stream you have
// SoftwareSerial ch2oSerial(4, SW_SERIAL_UNUSED_PIN); // RX, TX
SoftwareSerial ch2oSerial(14, 14); // RX, TX

// Instantiate a sensor connected to the previous port
Ze08CH2O ch2o{&ch2oSerial};

void setup() {
	ch2oSerial.begin(9600);
	ch2oSerial.listen();
	Serial.begin(115200); // Serial Monitor
}

void loop() {
	Ze08CH2O::concentration_t reading;
	
	if (ch2o.read(reading)) {
		Serial.print("New value: ");
		Serial.println(reading);
	}
}


여기서 한가지 문제가 있습니다.

ESP8266 에는 RX pin 이 하나만 있어, Serial Monitor 를 이용하면서 "수신" 을 받을 수 있는 pin 이 없다는 것이죠.

즉, sensor 를 연결할 수 있는 Pin 이 없습니다.



남아있는 GPIO2 는 TX 용도이고, 부팅 후에는 HIGH 로, 3V 전압이 걸려 있습니다.

그럼 도대체 이 소스 제작자는 어떻게 확인한 것일 까요?


사실은 ESP2866 이라는 것은 ESP-01 만 뜻하는 것이 아니라, ESP8266EX 을 사용한 WiFi module 의 총칭이었던 것입니다.

저는 지금까지 ESP8266 = ESP-01 인줄 알고, SoftwareSerial 부분에서 더 이상 진행을 못하고 있었습니다.



위의 도식처럼 ESP8266EX 에는, 더 많은 GPIO 를 지원하고 있었습니다.

단순히, ESP-01 의 pin out 갯수가 적었던 것이였죠. 더 많은 연결을 위해 ESP-01 도 pin out 을 처음부터 늘려 줬으면 어떠했을까 합니다.

어떤 사람이 "it's a shame to have such a small number of GPIOs at ESP-01" 라고 쓴 글을 본것 같습니다.


저도 chip diagram 을 보고, 납땜을 시도 했습니다.... 만 실패 했습니다. 너무 조밀합니다.



굴하지 않고, ESP8266EX chip 을 사용하면서 Pinout 이 확장된 breakout 모델인 ESP-03 을 구입해서 연결 했습니다!

연결할 수 있는 Pinout - GPIO 가 많아서 행복합니다.



Pin 연결도는 다음과 같습니다.


 ZE08-CH2O |  ESP-03
----------------------
   6 (TX)  | GPIO 14
----------------------
           |  POWER
----------------------
    VCC    |   3.3V
    GND    |   GND
----------------------


실재 구성도는 다음과 같습니다.



Serial Monitor 까지 연결한 모습이 다음과 같습니다. ESP-03 의 GPIO 14 에 ZE08-CH2O 의 TX 와 연결되어 있습니다.




기본 소스에 IoT 솔루션인 Blynk 소스를 입혀 봤습니다. 자세한 내용은 아래 포스트에 올려 놨습니다.


* Software | Blynk 사용해 보기

https://chocoball.tistory.com/entry/Software-Blynk-howto


이렇게 하므로써, WiFi 연결까지 소스에 한방에 녹여 놓을 수 있습니다.


#include "ze08_ch2o.h"
#include "SoftwareSerial.h"
 
SoftwareSerial ch2oSerial(14, 14); // RX, TX
Ze08CH2O ch2o{&ch2oSerial};
 
int sensorData;
 
/* Comment this out to disable prints and save space */
#define BLYNK_PRINT Serial
 
#include "ESP8266WiFi.h"
#include "BlynkSimpleEsp8266.h"
 
// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 
// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "XXXXXXXXXXXX";
char pass[] = "YYYYYYYYYYYYYYYYYYY";
 
BlynkTimer timer;
 
// This function sends Arduino's up time every second to Virtual Pin (5).
// In the app, Widget's reading frequency should be set to PUSH. This means
// that you define how often to send data to Blynk App.
void myTimerEvent() {
    // You can send any value at any time.
    // Please don't send more that 10 values per second.
     
    Ze08CH2O::concentration_t reading;
    if (ch2o.read(reading)) {
        Serial.print("ZE08-CH2O : ");
        Serial.println(reading);
         
        sensorData = reading;
    }
    Blynk.virtualWrite(V5, sensorData);
}
 
void setup() {
    // Debug console
    Serial.begin(115200);
     
    ch2oSerial.begin(9600);
    ch2oSerial.listen();
     
    Blynk.begin(auth, ssid, pass);
    // You can also specify server:
    //Blynk.begin(auth, ssid, pass, "blynk-cloud.com", 80);
    //Blynk.begin(auth, ssid, pass, IPAddress(192,168,1,100), 8080);
     
    // Setup a function to be called every second
    timer.setInterval(5000L, myTimerEvent);
}
 
void loop() {
    Blynk.run();
    timer.run(); // Initiates BlynkTimer
}


아래와 같이 값들이 표시됩니다.

값의 범위가 50 ~ 150 정도여서, 기준을 모르겠어나, 값의 변동이 기민하게 발생하는 것을 보니, 문제 없을 듯 합니다.

나누기 100 을 하면, UART 방식의 값과 거의 비슷해 집니다.



문제 없이 Blynk 어플에서 값들을 확인할 수 있습니다.





FIN


ZE08-CH2O 의 연결 방식인 DAC / UART 는 시험해 봤으나, PWM 은 정보가 없어서 시도해 보지 못했네요.

나중에 알게 되면 추가하도록 하겠습니다.


Formaldehyde 센서 확인도 끝났으니, 자 다음 센서요~.


And