Nitrox/Trimix & CO analyzer

Please register or login

Welcome to ScubaBoard, the world's largest scuba diving community. Registration is not required to read the forums, but we encourage you to join. Joining has its benefits and enables you to participate in the discussions.

Benefits of registering include

  • Ability to post and comment on topics and discussions.
  • A Free photo gallery to share your dive photos with the world.
  • You can make this box go away

Joining is quick and easy. Log in or Register now!

Battery-operation is indeed a requirement.

I'm looking into using the 18650 battery as well, including a charging option. With the recent live aboard disasters in mind, such a simple analyzer could be a personal CO detector as well. E.g. adding a buzzer that sounds when the CO level goes above a certain value.
At the same time, that battery should never become the cause of a possible fire....
Mine uses an 18650 and a little 5v boost chip like the ones in the charger packs. I added a bit to the program to read the battery voltage so I know when I need to recharge. With the chip, a little logic, and transistor it also shuts down before battery is drained to low. It has a mini usb for simple charging. Works great.
 
It's even easier than that. The ZE07-CO needs a 5V power supply and provides one DAC output. The output is connected to an analogue pin of the arduino.

I just ordered two of these. The stats and ease of use look better than the SPEC sensor I originally used. Shipping will be another month it seems with continued slowness due to covid.. but hopefully not too long.
 
I just ordered two of these. The stats and ease of use look better than the SPEC sensor I originally used. Shipping will be another month it seems with continued slowness due to covid.. but hopefully not too long.
Consider using an ADS1115. The Arduino's built-in AD converter is lacking precision, depends heavily on the voltage reference. The original code I referred to (uses an analog port + Vref) is only reliable when this sensor is the only connected device.
If you combine a O2 sensor and CO sensor, use a single ADS1115 with a differential reading (0,1) for the O2 sensor and a differential reading (2,3) for the CO sensor.
 
Consider using an ADS1115. The Arduino's built-in AD converter is lacking precision, depends heavily on the voltage reference. The original code I referred to (uses an analog port + Vref) is only reliable when this sensor is the only connected device.
If you combine a O2 sensor and CO sensor, use a single ADS1115 with a differential reading (0,1) for the O2 sensor and a differential reading (2,3) for the CO sensor.
Yep already use them. Will just replace my sensor and update the code to match.
 
First prototype ready. Nitrox, Trimix and CO all in one.
trimix1.jpeg
 
This has me really really wanting me to build an analyzer now. I have far too many Raspberry Pi, Arduino, and ESP-32 laying around waiting for a project... Any thoughts on using an ESP-32 and creating a phone app via bluetooth or WiFi?

Funny this comes up because I just took a few tanks out of storage after sitting for awhile (Still in hyrdo though) and wondered if they had rusted at all. Brought them to a local shop, used an analyzer to verify since I didn't want to drain then refill the doubles (impatient), then dove. Had I had my own analyzer, would've saved a ton of time.
 
Sharing the work done so far. The schematic in pdf (otherwise it'll be resized too small by the board).

Few notes:
  • The current schematic will drain a 9V battery block in roughly 2 hours. The MD62 sensor consumes a lot of power for heating, the Arduino requires >5.5V on the Vin pin and turns the rest into heat.
  • There are only 2 interrupts on the Arduino, which is why there are (only) 2 buttons. Shearwater computers use only 2 buttons as well, so this one works the same.
  • Only the minimal code for the display is in here!
  • Code comments are minimal. This is not a tutorial, nor a copy-paste code for creating an analyzer. Program your own menu and screens.
  • Libraries might have changed. Change the code accordingly.
  • Code is separated into multiple posts due to max post length.
Code:
#include <RunningAverage.h>
#include <EEPROM.h>
#include <Adafruit_ADS1015.h> // AD converter
#include <Adafruit_GFX.h>     // Adafruit core graphics library
#include <Adafruit_ST7789.h>  // Adafruit hardware-specific library for ST7789

#define TFT_CS    10  // define chip select pin ST7789 TFT module
#define TFT_DC     9  // define data/command pin ST7789 TFT module
#define TFT_RST    8  // define reset pin, or set to -1 and connect to Arduino RESET pin
#define OLED_RESET 4       // Reset pin # (or -1 if sharing Arduino reset pin)

Adafruit_ADS1115 ads(0x48);    // analog-digital converter for oxygen and helium sensor
Adafruit_ADS1115 ads2(0x49);    // analog-digital converter for CO sensor
Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);

// -------sensor settings-----------------
boolean enableHe = true;
boolean enableCO = true;

const byte calibrationCount = 10; // calibration samples
const byte readDelay = 3;          // ADC read delay between samples

float oxVcal = 0;      // oxygen voltage - calibration
float oxVact = 0;      // oxygen voltage - actual / measured
float oxVmax = 0;      // oxygen voltage - max
float oxVmin = 0;      // oxygen voltage - min
float heVact = 0;      // helium voltage - actual
float heVmax = 0;      // helium voltage - max
float heVcal = 0;      // helium voltage - calibration | turn potmeter so it reads 0mV
float carbon = 0;      // ppm
float coVact = 0;      // carbonmonoxide voltage - actual / measured

float gain = 0.03125;         // gain ADS1115
unsigned long time;           // runtime
unsigned long menuCounter=0;  // runtime

float MODcalc = 1.4;      // start with 1.4 for MOD calculation
const byte bLeft = 2;     // pin D2 connected to pushbutton
const byte bRight = 3;    // pin D3 connected to pushbutton

volatile byte buttonStateLeft;
volatile byte buttonStateRight;

byte leftclick = 0;
byte rightclick = 0;
byte action=0;
byte RAsize=20;
byte i=0;
int16_t adcHe;
int16_t adcO2;

boolean calibrateHe = false;
boolean calibrateO2 = false;

char calibrate[] = "Calibrating...";  // create a string
char calibOK[]   = "Calibration OK  ";
char calibReq[]  = "Calibration required";
char mV[]        = "mV  ";
char space1[]    = " ";
char ver1[]      = " Nitrox / Trimix";
char ver2[]      = "Analyzer software";
char warn1[]     = "This analyzer";
char warn2[]     = "has no brain!";
char warn3[]     = "Use your own!";
char HEsensor[]  = "He sensor ";
char O2sensor[]  = "O2 sensor ";
char next[]      = "Next";
char select[]    = "Select";

RunningAverage RAhe(RAsize);       // average He with 20 values
RunningAverage RAox(RAsize);       // average O2 with 20 values
RunningAverage RAco(RAsize);       // average CO with 20 values

float readO2sensor(){
  RAox.clear();
  float millivolts = 0;
  for (i=0; i<=RAsize; i++) {
    millivolts = ads.readADC_Differential_2_3();
    RAox.addValue(millivolts);
  }
  millivolts = abs(RAox.getAverage()*gain);
  return millivolts;
}

float readHEsensor() {
  RAhe.clear();
  float millivolts = 0;
  for (i=0; i<=RAsize; i++) {
    millivolts = ads.readADC_Differential_0_1();
    RAhe.addValue(millivolts);
  }
  millivolts =  abs(RAhe.getAverage()*gain);
  return millivolts;
}

float readCOsensor() {
  RAco.clear();
  for (i=0; i<=RAsize; i++) {
    coVact = ads2.readADC_SingleEnded(3);
    RAco.addValue(coVact);
  }
  coVact = abs(RAco.getAverage()*0.1875)/1000 - 0.015;
    float ppm = (3.125 * coVact - 1.25) * 100;  //linear relationship(0.4V for 0 ppm and 2V for 500ppm)
   if(ppm<0)
     ppm=0;
   else if(ppm>500)
     ppm = 500;
   return ppm;
}
 

Attachments

Back
Top Bottom