Serial Communication CH2O sensor

Hi guys,

I'm trying to get a ZE08-CH2O sensor to work but I'm stuck. Here's the datasheet:

http://www.komputer.de/wordpress/wp-content/uploads/2017/07/ZE08-CH2O-V1.0.pdf

I've been using a modified version of a code for a similar version. I modified it according to the specs in the datasheet (or so I thought).

I've attached the modified library and the ino code I'm using. I print out the buffer read from the sensor just for debugging. I get 00000000

I connected the sensor like this:

  • pin 3 (GND) to arduino GND
  • pin 4 (VIN) to 5V
  • pin 5 (RX) to arduino pin 12 (also tried the RX pin)
  • pin 6 (TX) to arduino pin 13 (also tried the TX pin)

I also tried all combinations reversing RX and TX but I still only get 0.

What do you suggest?

my_aqm_ch2o.h

/*!
 * @file    mf_aqm_ch2o.h
 * @brief
 *
 * \n
 * @details
 *
 * \n
 * @version 1.0
 * @author  Jack
 * @date    2015-11-26
 *
 * @history
 *
 */
#ifndef __MF_AQM_CH2O_H__
#define __MF_AQM_CH2O_H__

#define SOFTWARE_SERIAL     1
#if SOFTWARE_SERIAL
#define HARDWARE_SERIAL     0
#else
#define HARDWARE_SERIAL     1
#endif

#if SOFTWARE_SERIAL
#define __RX_PIN__          12
#define __TX_PIN__          13
#endif

class my_aqm_ch2o
{
	public :
		my_aqm_ch2o( byte[8] );	
		void loop( void );
        float read( void );
        byte buffer(byte);
};



#endif  /*__MF_AQM_CH2O_H__*/

my_aqm_ch2o.cpp

/**
  ******************************************************************************
  * @file   	my_aqm_ch2o.cpp
  * @author   	Jack
  * @version	1.0
  * @date		2015-11-26
  * @brief		my_aqm_ch2o甲醛传感器模块驱动
  * 
  * Discription:
  ******************************************************************************
  */
#include "arduino.h"
#include "stdio.h"
#include "my_aqm_ch2o.h"
#if SOFTWARE_SERIAL
#include "SoftwareSerial.h"
#endif

#if SOFTWARE_SERIAL
SoftwareSerial uart1(__RX_PIN__, __TX_PIN__);
#else
Serial uart1();
#endif


typedef struct

{
    byte rx_buffer[20];     //接收数据缓存
	u8   rx_posi;        //当前接收数据字节数
    float concentration;    //气体浓度
}param_t;


static param_t param = {{0}, 0, 0.0};



my_aqm_ch2o::my_aqm_ch2o( byte mode[9] )
{ 

	uart1.begin(9600);	
  for (int i=0;i<=sizeof(mode);i++){
    uart1.write(mode[i]);
  }
}

void my_aqm_ch2o::loop( void )
{
    if (uart1.available() > 0)
    {
        char dat = uart1.read();
        static unsigned long time = millis();

        if (millis() - time > 1000)
        {
            u8 i;
            param.rx_posi = 0;
            for (i = 0; i < sizeof(param.rx_buffer); i++)
            {
                param.rx_buffer[0] = 0;
            }
        }
        
        time = millis();

        param.rx_buffer[param.rx_posi++] = dat;

        if (param.rx_posi > 8)
        {
            u8 i;
            if ((param.rx_buffer[0] == 0xFF)
                && (param.rx_buffer[1] == 0x17)
                && (param.rx_buffer[8] == 0x25))
            {
                param.concentration = 
                    (param.rx_buffer[4]*256+param.rx_buffer[5])*0.001;
            }
            param.rx_posi = 0;
            for (i = 0; i < sizeof(param.rx_buffer); i++)
            {
                param.rx_buffer[0] = 0;
            }
        }
    }
}

//read CH2O gas concentration
float my_aqm_ch2o::read( void )
{
    return 	param.concentration;
}

byte my_aqm_ch2o::buffer(byte idx){
  return param.rx_buffer[idx];
}

ch2o.ino

#include <my_aqm_ch2o.h>

float concentration = 0.0;
byte ACTIVE_UPLOAD_CMD[9] = {0xFF,0x01,0x78,0x40,0x00, 0x00, 0x00, 0x00, 0x47};
byte QA_CMD[9] = {0xFF,0x01, 0x78, 0x41, 0x00, 0x00, 0x00, 0x00, 0x46};

my_aqm_ch2o ch2o(QA_CMD);//串口输入格式:FF FF 01 22 5A 05 03 05 00 00 03 05 DD,其中22 5A为有效数据,22是高位,5A是地位,代表气体浓度(0x22*256+0x5A)/1000 = 23.045mg/m3


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

void loop() {
  // put your main code here, to run repeatedly:
  ch2o.loop();
  for (int i=0;i<9;i++){
    Serial.print(ch2o.buffer(i));
  }
  Serial.println();
  if (concentration != ch2o.read())
  {
      u16 result;
      concentration = ch2o.read();
      Serial.println(concentration);
  }
  
}

my_aqm_ch2o.cpp (2.07 KB)

my_aqm_ch2o.h (584 Bytes)

ch2o.ino (788 Bytes)

  • pin 5 (RX) to arduino pin 12 (also tried the RX pin)
  • pin 6 (TX) to arduino pin 13 (also tried the TX pin)

Note this from the header file

#if SOFTWARE_SERIAL
#define __RX_PIN__          12
#define __TX_PIN__          13
#endif

But you are not using SoftwareSerial in your program

Thank you for replying.

Does this mean that I have to include the SoftwareSerial library?

#include <SoftwareSerial.h>

or do I have to do something extra?

Looking further into this I see that SoftwareSerial.h is #included in the .cpp file and that an object named uart1 is declared

SoftwareSerial uart1(__RX_PIN__, __TX_PIN__);

However, you never read from that object in your program.

Yes I do:

..
char dat = uart1.read();
...

in the ::loop method of the class

codingdude:
Yes I do:

..
char dat = uart1.read();
...

in the ::loop method of the class

My apologies

I got it working. The sensor has 2 modes:
Q&A
Active

In active mode it should send a result every second but I only get FFFF...

I only got it to work in Q&A. I have to send it the 9 bytes command and it responds with the readings

I didn't use the library, just the plain SoftwareSerial directly in the info

Also I had to connect sensor TX to Arduino RX and RX to tx, but maybe that's the normal way

thank you for your answers

Glad you got it working

I had to connect sensor TX to Arduino RX and RX to tx, but maybe that's the normal way

Perfectly normal. The Arduino transmits the data and the device receives it and vice versa. Logical if you think about it.

codingdude:
I got it working. The sensor has 2 modes:
Q&A
Active

In active mode it should send a result every second but I only get FFFF...

I only got it to work in Q&A. I have to send it the 9 bytes command and it responds with the readings

I didn't use the library, just the plain SoftwareSerial directly in the info

Also I had to connect sensor TX to Arduino RX and RX to tx, but maybe that's the normal way

thank you for your answers

Ciao a tutti. Potresti postare il codice definitivo? Grazie

Hi everyone. Is it possible to see all working code for these sensor?

Hello friends

We are working with ZE08-CH2O.
Sensor module was sourced from
https://www.winsen-sensor.com/products/formaldehyde-detection-module/ze08-ch2o.html

Our connections with the Arduino board as follows
Connected the power pin to 5V
TX pin of ZE08-CH2O to the RX pin of Arduino

please find our code below

we are working on default mode (active upload) using which we are getting data from the sensor after every 1 sec

When we take using URAT mode for a 5ppm solution we are reading as 0.05-0.1

We even tried getting readings from DAC pin on the sensor
for a 5ppm solution, we getting 0.47~v and it increased only up to 0.6~v at 100ppm

We have cross-checked our solution using chemical methods and solution are of proper concentration. However, we are not able to figure why the sensor is giving low values the said concentration

Thanks in advance

#include <arduino.h>
#include <SoftwareSerial.h>
#define MAXLENGTH  9
#define VREF  5.0   //
#//include "Timer.h"
long tenMinutes = 10 * 60 * 1000L; // on time of heater
//Timer t; // Object of the timer class
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(9600);

}

void loop() 
{  
 
  ze08_PPM();
  //analogReadPPM();
}

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;
}

ZE08_CH2O.ino (2.08 KB)