Bit banging a CO2 sensor with an arduino

by Daemach on Sat Nov 27, 2010 2:05 pm

I recently discovered a self-calibrating CO2 sensor that uses an interface similar to I2C: http://www.epluse.com/en/products/co2-measurement/co2-measurement-module-for-oem-applications/ee892/ They sent me a couple of samples and said the price would be ~$58 in quantities of 5-10K. The sensor returns temperature, relative humidity and a CO2 measurement (apparently), and possibly air velocity too, though the documentation seems to be conflicting on that one.

The datasheet for the E2 interface, (their protocol), has code for interfacing with the processor that must be modified to work with specific processors: http://www.epluse.com/uploads/tx_EplusEprDownloads/application_note_e2-ee03_v1_englisch_33.pdf (see the section that says "// adapt this code for your target processor !!!")

I've attempted to do this using pinMode and digitalWrite in the .h file I'm trying to create but the compiler is throwing errors saying the Arduino functions (pinMode, etc) aren't declared. I'm not a C coder so I've probably screwed up the file structure somehow. I would really appreciate some help with this. I'll post the library on the Arduino site if I can get it working.

The problem functions are at the very end. See below:

Code: Select all
/***************************************************************************/
// definitions

#define DELAY_FAKTOR 10
#define ACK 1
#define NAK 0

int SDA = 4;
int SCL = 5;

/***************************************************************************/
// variables

unsigned char rh_low;
unsigned char rh_high;
unsigned char temp_low;
unsigned char temp_high;
unsigned char checksum_03;
unsigned int rh_ee03= 0;
unsigned int temp_ee03= 0;
float rh = 0;
float temperature = 0;

/***************************************************************************/
// functions

char check_ack(void);
void send_ack(void);
void send_nak(void);
void E2Bus_start(void);
void E2Bus_stop(void);
void E2Bus_send(unsigned char);
void set_SDA(void);
void clear_SDA(void);
int read_SDA(void);
void set_SCL(void);
void clear_SCL(void);
unsigned char E2Bus_read(void);
void e2Delay(unsigned int value);

/***************************************************************************/


float RH_read(void);
float Temp_read(void);
unsigned char EE03_status(void);

int sdaPin = 9;
int sclPin = 10;
int ledPin = 13;

float Temp_read(void)
{

  E2Bus_start();
  E2Bus_send(0xA1);

  if (check_ack()==ACK)
  {
    temp_low = E2Bus_read();
    send_ack();
    checksum_03 = E2Bus_read();
    send_nak();
    // terminate communication
    E2Bus_stop();

    if (((0xA1 + temp_low) % 256) == checksum_03) // checksum OK?
    {
      E2Bus_start();
      E2Bus_send(0xB1);        // MW2-high request
      check_ack();
      temp_high = E2Bus_read();
      send_ack();        // terminate communication
      checksum_03 = E2Bus_read();
      send_nak();
      E2Bus_stop();

      // default value (error code)

      // MW2-low request

      if (((0xB1 + temp_high) % 256) == checksum_03) // checksum OK?
      {
        temp_ee03=temp_low+256*temp_high; //yes->calculate temperature
        temperature=((float)temp_ee03/100) - 273.15;
        // overwrite default (error) value
      }

    }
    E2Bus_stop();

  }
  return temperature;

}

float RH_read(void)

{
  rh = -1;

  E2Bus_start();
  E2Bus_send(0x81);    // MW1-low request

  if (check_ack()==ACK)
  {
    rh_low = E2Bus_read();
    send_ack();
    checksum_03 = E2Bus_read();
    send_nak();    // terminate communication
    E2Bus_stop();

    if (((0x81 + rh_low) % 256) == checksum_03)     // checksum OK?
    {
      E2Bus_start();
      E2Bus_send(0x91);      // MW1-high request
      check_ack();
      rh_high = E2Bus_read();
      send_ack();
      checksum_03 = E2Bus_read();
      send_nak();      // terminate communication
      E2Bus_stop();

      if (((0x91 + rh_high) % 256) == checksum_03)      // checksum OK?
      {
        rh_ee03=rh_low+256*(unsigned int)rh_high;       // yes-> calculate humidity value
        rh=(float)rh_ee03/100;        // overwrite default (error) value
      }

    }
    E2Bus_stop();

  }
  return rh;

}

unsigned char EE03_status(void)

{
  unsigned char stat_ee03;

  E2Bus_start();
  E2Bus_send(0x71); //main command for STATUS request
  if (check_ack()==ACK)
  {
    stat_ee03 = E2Bus_read();
    send_ack();
    checksum_03 = E2Bus_read();
    send_nak();

    E2Bus_stop();

    if (((stat_ee03 + 0x71) % 256) == checksum_03)
      return stat_ee03;
  }
  return 0xFF;

}












void E2Bus_start(void)
// send Start condition to E2 Interface
{
  set_SDA();
  set_SCL();
  e2Delay(30*DELAY_FAKTOR);
  clear_SDA();
  e2Delay(30*DELAY_FAKTOR);
}
/*-------------------------------------------------------------------------*/

void E2Bus_stop(void)
// send Stop condition to E2 Interface
{
  clear_SCL();
  e2Delay(20*DELAY_FAKTOR);
  clear_SDA();
  e2Delay(20*DELAY_FAKTOR);
  set_SCL();
  e2Delay(20*DELAY_FAKTOR);
  set_SDA();
  e2Delay(20*DELAY_FAKTOR);
}
/*-------------------------------------------------------------------------*/

void E2Bus_send(unsigned char value)
{
  unsigned char i;
  unsigned char maske = 0x80;

  for (i=8;i>0;i--)
  {
    clear_SCL();
    e2Delay(10*DELAY_FAKTOR);
    if ((value & maske) != 0)
    {
      set_SDA();
    }
    else
    {
      clear_SDA();
    }
    e2Delay(20*DELAY_FAKTOR);
    set_SCL();
    maske >>= 1;
    e2Delay(30*DELAY_FAKTOR);
    clear_SCL();
  }
  set_SDA();

}
/*-------------------------------------------------------------------------*/

unsigned char E2Bus_read(void)
{
  unsigned char data_in = 0x00;
  unsigned char maske = 0x80;

  for (maske=0x80;maske>0;maske >>=1)
  {
    clear_SCL();
    e2Delay(30*DELAY_FAKTOR);
    set_SCL();
    e2Delay(15*DELAY_FAKTOR);
    if (read_SDA())
    {
      data_in |= maske;
    }
    e2Delay(15*DELAY_FAKTOR);
    clear_SCL();
  }
  return data_in;

}
/*-------------------------------------------------------------------------*/

char check_ack(void)// check for acknowledge
{
  int input;

  e2Delay(30*DELAY_FAKTOR);
  set_SCL();
  e2Delay(15*DELAY_FAKTOR);
  input = read_SDA();
  e2Delay(15*DELAY_FAKTOR);
  if(input == 1)
    return NAK;
  else
    return ACK;

}
/*-------------------------------------------------------------------------*/

void send_ack(void)
// send acknowledge
{
  clear_SCL();
  e2Delay(15*DELAY_FAKTOR);
  clear_SDA();
  e2Delay(15*DELAY_FAKTOR);
  set_SCL();
  e2Delay(30*DELAY_FAKTOR);
  clear_SCL();
  set_SDA();
}
/*-------------------------------------------------------------------------*/

void send_nak(void)
// send NOT-acknowledge
{
  clear_SCL();
  e2Delay(15*DELAY_FAKTOR);
  set_SDA();
  e2Delay(15*DELAY_FAKTOR);
  set_SCL();
  e2Delay(30*DELAY_FAKTOR);
  clear_SCL();
  set_SDA();
}
/*-------------------------------------------------------------------------*/

void e2Delay(unsigned int value)
// delay- routine
{
  while (--value != 0);
}
/*-------------------------------------------------------------------------*/


// adapt this code for your target processor !!!

void set_SDA(void)    // set port-pin (SDA)
{
  pinMode(sdaPin,OUTPUT);
  digitalWrite(sdaPin,HIGH);
  //  SDA = 1;
}

void clear_SDA(void)  // clear port-pin (SDA)
{
  pinMode(sdaPin,OUTPUT);
  digitalWrite(sdaPin,LOW);
  //  SDA = 0;
}

int read_SDA(void)    // read SDA-pin status
{
  pinMode(sdaPin,INPUT);
  return digitalRead(sdaPin);
}

void set_SCL(void)    // set port-pin (SCL)
{
  pinMode(sclPin,OUTPUT);
  digitalWrite(sclPin,HIGH);
  //  SCL = 1;
}

void clear_SCL(void)  // clear port-pin (SCL)
{
  pinMode(sclPin,OUTPUT);
  digitalWrite(sclPin,LOW);
  //  SCL = 0;
}

Daemach
 
Posts: 67
Joined: Fri Feb 13, 2009 1:07 pm

Re: Bit banging a CO2 sensor with an arduino

by Zener on Sat Nov 27, 2010 3:28 pm

I am guessing this is a simple problem having to do with file paths or something. Those built in functions are supposed to be included auromatically when you compile. I would try searching in that error message. It is probably a common problem. But I have not programmed in Arduino lately. I know that you don't have to manually include or declare for those functions to work. That is one of the helpful features of Arduino.
Zener
 
Posts: 2382
Joined: Sat Feb 21, 2009 1:38 am

Re: Bit banging a CO2 sensor with an arduino

by Daemach on Sat Nov 27, 2010 3:50 pm

I tried including wiring.h and it stopped complaining about the missing arduino functions but it's giving me new errors:

_NewTemp.cpp.o:(.data.SDA+0x0): multiple definition of `SDA'
E2_Interface.cpp.o:(.data.SDA+0x0): first defined here
_NewTemp.cpp.o:(.data.SCL+0x0): multiple definition of `SCL'
E2_Interface.cpp.o:(.data.SCL+0x0): first defined here
_NewTemp.cpp.o: In function `loop':

etc...

I also tried splitting the functions into a .cpp file and left the definitions in the .h file. I'm not a c coder so I'm sure my structure is part of the problem.

e2_interface.h:
Code: Select all

/***************************************************************************/
// definitions

#define DELAY_FAKTOR 10
#define ACK 1
#define NAK 0

int SDA = 4;
int SCL = 5;

/***************************************************************************/
// variables

unsigned char rh_low;
unsigned char rh_high;
unsigned char temp_low;
unsigned char temp_high;
unsigned char checksum_03;
unsigned int rh_ee03= 0;
unsigned int temp_ee03= 0;
float rh = 0;
float temperature = 0;

/***************************************************************************/
// private functions

char check_ack(void);
void send_ack(void);
void send_nak(void);
void E2Bus_start(void);
void E2Bus_stop(void);
void E2Bus_send(unsigned char);
void set_SDA(void);
void clear_SDA(void);
int read_SDA(void);
void set_SCL(void);
void clear_SCL(void);
unsigned char E2Bus_read(void);
void e2Delay(unsigned int value);

//public functions

float RH_read(void);
float Temp_read(void);
unsigned char EE03_status(void);

/***************************************************************************/



e2_interface.cpp:
Code: Select all
#include "Wiring.h"
#include "E2_Interface.h"


int sdaPin = 9;
int sclPin = 10;
int ledPin = 13;

float Temp_read(void)
{

  E2Bus_start();
  E2Bus_send(0xA1);

  if (check_ack()==ACK)
  {
    temp_low = E2Bus_read();
    send_ack();
    checksum_03 = E2Bus_read();
    send_nak();
    // terminate communication
    E2Bus_stop();

    if (((0xA1 + temp_low) % 256) == checksum_03) // checksum OK?
    {
      E2Bus_start();
      E2Bus_send(0xB1);        // MW2-high request
      check_ack();
      temp_high = E2Bus_read();
      send_ack();        // terminate communication
      checksum_03 = E2Bus_read();
      send_nak();
      E2Bus_stop();

      // default value (error code)

      // MW2-low request

      if (((0xB1 + temp_high) % 256) == checksum_03) // checksum OK?
      {
        temp_ee03=temp_low+256*temp_high; //yes->calculate temperature
        temperature=((float)temp_ee03/100) - 273.15;
        // overwrite default (error) value
      }

    }
    E2Bus_stop();

  }
  return temperature;

}

float RH_read(void)

{
  rh = -1;

  E2Bus_start();
  E2Bus_send(0x81);    // MW1-low request

  if (check_ack()==ACK)
  {
    rh_low = E2Bus_read();
    send_ack();
    checksum_03 = E2Bus_read();
    send_nak();    // terminate communication
    E2Bus_stop();

    if (((0x81 + rh_low) % 256) == checksum_03)     // checksum OK?
    {
      E2Bus_start();
      E2Bus_send(0x91);      // MW1-high request
      check_ack();
      rh_high = E2Bus_read();
      send_ack();
      checksum_03 = E2Bus_read();
      send_nak();      // terminate communication
      E2Bus_stop();

      if (((0x91 + rh_high) % 256) == checksum_03)      // checksum OK?
      {
        rh_ee03=rh_low+256*(unsigned int)rh_high;       // yes-> calculate humidity value
        rh=(float)rh_ee03/100;        // overwrite default (error) value
      }

    }
    E2Bus_stop();

  }
  return rh;

}

unsigned char EE03_status(void)

{
  unsigned char stat_ee03;

  E2Bus_start();
  E2Bus_send(0x71); //main command for STATUS request
  if (check_ack()==ACK)
  {
    stat_ee03 = E2Bus_read();
    send_ack();
    checksum_03 = E2Bus_read();
    send_nak();

    E2Bus_stop();

    if (((stat_ee03 + 0x71) % 256) == checksum_03)
      return stat_ee03;
  }
  return 0xFF;

}












void E2Bus_start(void)
// send Start condition to E2 Interface
{
  set_SDA();
  set_SCL();
  e2Delay(30*DELAY_FAKTOR);
  clear_SDA();
  e2Delay(30*DELAY_FAKTOR);
}
/*-------------------------------------------------------------------------*/

void E2Bus_stop(void)
// send Stop condition to E2 Interface
{
  clear_SCL();
  e2Delay(20*DELAY_FAKTOR);
  clear_SDA();
  e2Delay(20*DELAY_FAKTOR);
  set_SCL();
  e2Delay(20*DELAY_FAKTOR);
  set_SDA();
  e2Delay(20*DELAY_FAKTOR);
}
/*-------------------------------------------------------------------------*/

void E2Bus_send(unsigned char value)
{
  unsigned char i;
  unsigned char maske = 0x80;

  for (i=8;i>0;i--)
  {
    clear_SCL();
    e2Delay(10*DELAY_FAKTOR);
    if ((value & maske) != 0)
    {
      set_SDA();
    }
    else
    {
      clear_SDA();
    }
    e2Delay(20*DELAY_FAKTOR);
    set_SCL();
    maske >>= 1;
    e2Delay(30*DELAY_FAKTOR);
    clear_SCL();
  }
  set_SDA();

}
/*-------------------------------------------------------------------------*/

unsigned char E2Bus_read(void)
{
  unsigned char data_in = 0x00;
  unsigned char maske = 0x80;

  for (maske=0x80;maske>0;maske >>=1)
  {
    clear_SCL();
    e2Delay(30*DELAY_FAKTOR);
    set_SCL();
    e2Delay(15*DELAY_FAKTOR);
    if (read_SDA())
    {
      data_in |= maske;
    }
    e2Delay(15*DELAY_FAKTOR);
    clear_SCL();
  }
  return data_in;

}
/*-------------------------------------------------------------------------*/

char check_ack(void)// check for acknowledge
{
  int input;

  e2Delay(30*DELAY_FAKTOR);
  set_SCL();
  e2Delay(15*DELAY_FAKTOR);
  input = read_SDA();
  e2Delay(15*DELAY_FAKTOR);
  if(input == 1)
    return NAK;
  else
    return ACK;

}
/*-------------------------------------------------------------------------*/

void send_ack(void)
// send acknowledge
{
  clear_SCL();
  e2Delay(15*DELAY_FAKTOR);
  clear_SDA();
  e2Delay(15*DELAY_FAKTOR);
  set_SCL();
  e2Delay(30*DELAY_FAKTOR);
  clear_SCL();
  set_SDA();
}
/*-------------------------------------------------------------------------*/

void send_nak(void)
// send NOT-acknowledge
{
  clear_SCL();
  e2Delay(15*DELAY_FAKTOR);
  set_SDA();
  e2Delay(15*DELAY_FAKTOR);
  set_SCL();
  e2Delay(30*DELAY_FAKTOR);
  clear_SCL();
  set_SDA();
}
/*-------------------------------------------------------------------------*/

void e2Delay(unsigned int value)
// delay- routine
{
  while (--value != 0);
}
/*-------------------------------------------------------------------------*/


// adapt this code for your target processor !!!

void set_SDA(void)    // set port-pin (SDA)
{
  pinMode(sdaPin,OUTPUT);
  digitalWrite(sdaPin,HIGH);
  //  SDA = 1;
}

void clear_SDA(void)  // clear port-pin (SDA)
{
  pinMode(sdaPin,OUTPUT);
  digitalWrite(sdaPin,LOW);
  //  SDA = 0;
}

int read_SDA(void)    // read SDA-pin status
{
  pinMode(sdaPin,INPUT);
  return digitalRead(sdaPin);
}

void set_SCL(void)    // set port-pin (SCL)
{
  pinMode(sclPin,OUTPUT);
  digitalWrite(sclPin,HIGH);
  //  SCL = 1;
}

void clear_SCL(void)  // clear port-pin (SCL)
{
  pinMode(sclPin,OUTPUT);
  digitalWrite(sclPin,LOW);
  //  SCL = 0;
}



The test sketch:
Code: Select all
#include "E2_Interface.h"

void setup() {       
  dummy = EE03_status();
}

void loop() {
  humidity = RH_read();
  //  status = EE03_status();
}

Daemach
 
Posts: 67
Joined: Fri Feb 13, 2009 1:07 pm

Re: Bit banging a CO2 sensor with an arduino

by Zener on Sun Nov 28, 2010 1:42 pm

I am sorry I'm the only one here answering you since I am least qualified! Hopefully the smart people show up soon! I think you have a very simple error probably.

Looking at your code I can only come up with a couple of ideas: First of all maybe you split it up too much. I am not sure the fine points of that. I do notice you have "#include "E2_Interface.h"" in two seperate parts, so maybe that is causing the multiple defines error. Just a guess. It is interesting that wiring.h fixed your first problem since I don't think I ever had to include that specifically. Anyway, you know how computers are about error messages, sometimes they are not 'exactly' right.
Zener
 
Posts: 2382
Joined: Sat Feb 21, 2009 1:38 am

Re: Bit banging a CO2 sensor with an arduino

by oPossum on Sun Nov 28, 2010 1:51 pm

The header file should only have the public functions. Put everything else in the cpp file.
I am the Possum, and I approve of this message. Sent from MacBook Wheel Sorry for my bad German.
User avatar
oPossum
 
Posts: 635
Joined: Thu Oct 25, 2007 11:42 pm
Location: Michigan, USA

Re: Bit banging a CO2 sensor with an arduino

by Daemach on Mon Dec 06, 2010 3:24 pm

I am making more progress with this. At this point it looks like it's spitting out data but the clock is not consistent at all when using the arduino functions. I tried using some bit shifting functions instead but the pulse trains look even worse.

See the attachment to see the Arduino function pulse train. Clock is on the bottom.

I have the arduino and bit-shifting functions below. I have a hunch the bit-shifting functions would work better but I'm having problems writing LOWs.

Thanks in advance!

Code: Select all
// adapt this code for your target processor !!!

void set_SDA(void)    // set port-pin (SDA)
{
  pinMode(sdaPin,OUTPUT);
   if(DEBUG==1){
    PORTD |= 1<<4;
  } else {
    digitalWrite(sdaPin,HIGH);
  }
}

void clear_SDA(void)  // clear port-pin (SDA)
{
  pinMode(sdaPin,OUTPUT);
   if(DEBUG==1){
    PORTD &= !1<<4;
  } else {
    digitalWrite(sdaPin,LOW);
  }
}

int read_SDA(void)    // read SDA-pin status
{
  pinMode(sdaPin,INPUT);
  return digitalRead(sdaPin);
}

void set_SCL(void)    // set port-pin (SCL)
{
  if(DEBUG==1){
    PORTD |= 1<<5;
  } else {
    digitalWrite(sclPin,HIGH);
  }
}

void clear_SCL(void)  // clear port-pin (SCL)
{
  if(DEBUG==1){
    PORTD &= !1<<5;
  } else {
    digitalWrite(sclPin,LOW);
  }
}
Attachments
EE892_Logic.JPG
EE892_Logic.JPG (49.87 KiB) Viewed 3230 times
Daemach
 
Posts: 67
Joined: Fri Feb 13, 2009 1:07 pm

Re: Bit banging a CO2 sensor with an arduino

by oPossum on Mon Dec 06, 2010 3:53 pm

This will not work...

Code: Select all
    PORTD &= !1<<4;


Use the bitwise compliment to invert individual bits...

Code: Select all
    PORTD &= ~(1<<4);


The jitter you are seeing may be due to the ISR that handles timing, PWM and such. Is it causing communication problems?
I am the Possum, and I approve of this message. Sent from MacBook Wheel Sorry for my bad German.
User avatar
oPossum
 
Posts: 635
Joined: Thu Oct 25, 2007 11:42 pm
Location: Michigan, USA

Re: Bit banging a CO2 sensor with an arduino

by Daemach on Mon Dec 06, 2010 5:06 pm

Thanks very much - I figured I had that expression wrong. At this point it's not communicating at all still, unfortunately.

I included two screenshots - the one named _Native uses the bitwise functions. _Arduino is the arduino functions. The Arduino pulsetrain looks more correct although, like you said, something is causing jitter. I assumed that was the Arduino function overhead which is why I'm trying to figure out the bitwise stuff. The native train looks very broken which means I probably still don't have those functions right. Thats the only thing that changes.

The entire sketch, with the new bitwise functions, is below. Moving everything into one file got me past the compiling errors. I figure I'll try to break everything out into a library once I get it working. The block I posted before is at the bottom.


Code: Select all
/***************************************************************************/
// definitions

#define DELAY_FAKTOR 5
#define ACK 1
#define NAK 0
#define DEBUG 0

int SDA = 4;
int SCL = 5;
int sdaPin = 4;
int sclPin = 5;
int ledPin = 13;
int dummy = 0xFF;

/***************************************************************************/
// variables

unsigned char rh_low;
unsigned char rh_high;
unsigned char temp_low;
unsigned char temp_high;
unsigned char checksum_03;
unsigned int rh_ee03= 0;
unsigned int temp_ee03= 0;
float rh = 0;
float temperature = 0;
float humidity = 0;

/***************************************************************************/
// private functions

char check_ack(void);
void send_ack(void);
void send_nak(void);
void E2Bus_start(void);
void E2Bus_stop(void);
void E2Bus_send(unsigned char);
void set_SDA(void);
void clear_SDA(void);
int read_SDA(void);
void set_SCL(void);
void clear_SCL(void);
unsigned char E2Bus_read(void);
void e2Delay(unsigned int value);

//public functions

float RH_read(void);
float Temp_read(void);
unsigned char EE03_status(void);

/***************************************************************************/



void setup() {
  Serial.begin(9600); 
  dummy = EE03_status();
  // pinMode(13, OUTPUT);
  pinMode(sclPin,OUTPUT);
}

void loop() {
  //humidity = RH_read();
  temperature = Temp_read();
  dummy = EE03_status();
  /*
  digitalWrite(13, HIGH);   // set the LED on
   delay(100);              // wait for a second
   digitalWrite(13, LOW);    // set the LED off
   delay(50);              // wait for a second
   */

  Serial.print("Temperature: ");
  serialPrintFloat(temperature);
  //Serial.print("  F, Humidity: ");
  //serialPrintFloat(humidity);
  Serial.println();
  delay(1000);
  //  status = EE03_status();
}

void serialPrintFloat(float f){
  Serial.print((int)f);
  Serial.print(".");
  int decplace = (f - (int)f) * 100;
  Serial.print(abs(decplace));
}

float Temp_read(void)
{

  E2Bus_start();
  E2Bus_send(0xA1);

  if (check_ack()==ACK)
  {
    temp_low = E2Bus_read();
    send_ack();
    checksum_03 = E2Bus_read();
    send_nak();
    // terminate communication
    E2Bus_stop();

    if (((0xA1 + temp_low) % 256) == checksum_03) // checksum OK?
    {
      E2Bus_start();
      E2Bus_send(0xB1);        // MW2-high request
      check_ack();
      temp_high = E2Bus_read();
      send_ack();        // terminate communication
      checksum_03 = E2Bus_read();
      send_nak();
      E2Bus_stop();

      // default value (error code)

      // MW2-low request

      if (((0xB1 + temp_high) % 256) == checksum_03) // checksum OK?
      {
        temp_ee03=temp_low+256*temp_high; //yes->calculate temperature
        temperature=((float)temp_ee03/100) - 273.15;
        // overwrite default (error) value
      }

    }
    E2Bus_stop();

  }
  return temperature;

}

float RH_read(void)

{
  rh = -1;

  E2Bus_start();
  E2Bus_send(0x81);    // MW1-low request

  if (check_ack()==ACK)
  {
    rh_low = E2Bus_read();
    send_ack();
    checksum_03 = E2Bus_read();
    send_nak();    // terminate communication
    E2Bus_stop();

    if (((0x81 + rh_low) % 256) == checksum_03)     // checksum OK?
    {
      E2Bus_start();
      E2Bus_send(0x91);      // MW1-high request
      check_ack();
      rh_high = E2Bus_read();
      send_ack();
      checksum_03 = E2Bus_read();
      send_nak();      // terminate communication
      E2Bus_stop();

      if (((0x91 + rh_high) % 256) == checksum_03)      // checksum OK?
      {
        rh_ee03=rh_low+256*(unsigned int)rh_high;       // yes-> calculate humidity value
        rh=(float)rh_ee03/100;        // overwrite default (error) value
      }

    }
    E2Bus_stop();

  }
  return rh;

}

unsigned char EE03_status(void)

{
  unsigned char stat_ee03;

  E2Bus_start();
  E2Bus_send(0x71); //main command for STATUS request
  if (check_ack()==ACK)
  {
    stat_ee03 = E2Bus_read();
    send_ack();
    checksum_03 = E2Bus_read();
    send_nak();

    E2Bus_stop();

    if (((stat_ee03 + 0x71) % 256) == checksum_03)
      return stat_ee03;
  }
  return 0xFF;

}












void E2Bus_start(void)
// send Start condition to E2 Interface
{
  set_SDA();
  set_SCL();
  e2Delay(30*DELAY_FAKTOR);
  clear_SDA();
  e2Delay(30*DELAY_FAKTOR);

}
/*-------------------------------------------------------------------------*/

void E2Bus_stop(void)
// send Stop condition to E2 Interface
{
  clear_SCL();
  e2Delay(20*DELAY_FAKTOR);
  clear_SDA();
  e2Delay(20*DELAY_FAKTOR);
  set_SCL();
  e2Delay(20*DELAY_FAKTOR);
  set_SDA();
  e2Delay(20*DELAY_FAKTOR);
}
/*-------------------------------------------------------------------------*/

void E2Bus_send(unsigned char value)
{
  unsigned char i;
  unsigned char maske = 0x80;

  for (i=8;i>0;i--)
  {
    clear_SCL();
    e2Delay(10*DELAY_FAKTOR);
    if ((value & maske) != 0)
    {
      set_SDA();
    }
    else
    {
      clear_SDA();
    }
    e2Delay(20*DELAY_FAKTOR);
    set_SCL();
    maske >>= 1;
    e2Delay(30*DELAY_FAKTOR);
    clear_SCL();
  }
  set_SDA();

}
/*-------------------------------------------------------------------------*/

unsigned char E2Bus_read(void)
{
  unsigned char data_in = 0x00;
  unsigned char maske = 0x80;

  for (maske=0x80;maske>0;maske >>=1)
  {
    clear_SCL();
    e2Delay(30*DELAY_FAKTOR);
    set_SCL();
    e2Delay(15*DELAY_FAKTOR);
    if (read_SDA())
    {
      data_in |= maske;
    }
    e2Delay(15*DELAY_FAKTOR);
    clear_SCL();
  }
  return data_in;

}
/*-------------------------------------------------------------------------*/

char check_ack(void)// check for acknowledge
{
  int input;

  e2Delay(30*DELAY_FAKTOR);
  set_SCL();
  e2Delay(15*DELAY_FAKTOR);
  input = read_SDA();
  e2Delay(15*DELAY_FAKTOR);
  if(input == 1)
    return NAK;
  else
    return ACK;

}
/*-------------------------------------------------------------------------*/

void send_ack(void)
// send acknowledge
{
  clear_SCL();
  e2Delay(15*DELAY_FAKTOR);
  clear_SDA();
  e2Delay(15*DELAY_FAKTOR);
  set_SCL();
  e2Delay(30*DELAY_FAKTOR);
  clear_SCL();
  set_SDA();
}
/*-------------------------------------------------------------------------*/

void send_nak(void)
// send NOT-acknowledge
{
  clear_SCL();
  e2Delay(15*DELAY_FAKTOR);
  set_SDA();
  e2Delay(15*DELAY_FAKTOR);
  set_SCL();
  e2Delay(30*DELAY_FAKTOR);
  clear_SCL();
  set_SDA();
}
/*-------------------------------------------------------------------------*/

void e2Delay(unsigned int value)
// delay- routine
{
  while (--value != 0);
}
/*-------------------------------------------------------------------------*/


// adapt this code for your target processor !!!

void set_SDA(void)    // set port-pin (SDA)
{
  pinMode(sdaPin,OUTPUT);
   if(DEBUG==1){
    PORTD |= 1<<4;
  } else {
    digitalWrite(sdaPin,HIGH);
  }
}

void clear_SDA(void)  // clear port-pin (SDA)
{
  pinMode(sdaPin,OUTPUT);
   if(DEBUG==1){
    PORTD &= ~(1<<4);
  } else {
    digitalWrite(sdaPin,LOW);
  }
}

int read_SDA(void)    // read SDA-pin status
{
  pinMode(sdaPin,INPUT);
  return digitalRead(sdaPin);
}

void set_SCL(void)    // set port-pin (SCL)
{
  if(DEBUG==1){
    PORTD |= 1<<5;
  } else {
    digitalWrite(sclPin,HIGH);
  }
}

void clear_SCL(void)  // clear port-pin (SCL)
{
  if(DEBUG==1){
    PORTD &= ~(1<<5);
  } else {
    digitalWrite(sclPin,LOW);
  }
}
Attachments
EE892_Arduino.JPG
EE892_Arduino.JPG (45.85 KiB) Viewed 3224 times
EE892_Native.JPG
EE892_Native.JPG (41.82 KiB) Viewed 3224 times
Daemach
 
Posts: 67
Joined: Fri Feb 13, 2009 1:07 pm

Re: Bit banging a CO2 sensor with an arduino

by gromain on Wed Feb 06, 2013 5:53 am

Hi there!

I know this is a bit old, and I hope that you solved your problem already!
But anyway, I was faced with the same one, and decided to tackle it hard, so I wrote my own arduino library to go on with the E2 protocol.
In case anyone is interested (because this thread is the only one I found when "googling arduino E2 protocol", so it's kinda reference), the code (and lib) is available on github: http://www.github.com/gromain/E2
As of today, it's completely functional.
I just need to add the function to read from a custom adress (currently it reads from the custom memory address 0x00, and the pointer is incremented by one after each read, so not really easy to access a particular memory address!) and the function to write in custom memory.
But otherwise, it's functionnal with the humidity,temperature and CO2 measurement from the E+E Elektronics sensors (http://www.epluse.com).
(I didn't code the air velocity function yet, mainly because I don't have access to an air velocity sensor. But it shouldn't be hard to do once you have the library with the rest of the code).


Well, that's it.

Cheers,

gromain
gromain
 
Posts: 1
Joined: Mon Jul 04, 2011 9:32 am

Re: Bit banging a CO2 sensor with an arduino

by Daemach on Thu Feb 07, 2013 4:01 pm

I did get it worked out finally. I wish I had posted the library here now to save you the trouble!

I do need to figure out an easy way to check for the sensors existence before trying to use it though. It would be great if they would have stuck to the i2c protocol instead of rolling their own...
Daemach
 
Posts: 67
Joined: Fri Feb 13, 2009 1:07 pm