Skip to content

Instantly share code, notes, and snippets.

@soemarko
Created October 28, 2018 17:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save soemarko/7af13d2d31edb54bd3f6ca529cf79fca to your computer and use it in GitHub Desktop.
Save soemarko/7af13d2d31edb54bd3f6ca529cf79fca to your computer and use it in GitHub Desktop.
Source code for DIY O2 Analyzer, read the introduction here: http://soemarko.com/blog/diy-o2-analyzer-part-1
#include <SPI.h>
#include <Wire.h>
#include <Piccolino_OLED.h>
#include <Piccolino_RAM.h>
#include <EEPROM.h>
#include <Adafruit_ADS1015.h>
#include <RunningAverage.h>
const int buttonPin=3; // push button
#define RA_SIZE 20
RunningAverage RA(RA_SIZE);
Adafruit_ADS1115 ads(0x48);
PROGMEM const unsigned char logo [] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x01, 0x37, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x09, 0xb7, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x9d, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x9f, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x01, 0xdf, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x60, 0x00, 0x00, 0x13, 0xff, 0x17, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x78, 0x10, 0x00, 0x93, 0xf8, 0x97, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x7c, 0x12, 0x00, 0xb7, 0xe3, 0x97, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x7e, 0x36, 0xa1, 0xbf, 0xcf, 0xb7, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x7e, 0x37, 0xed, 0xfe, 0xdf, 0xb7, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x7e, 0x3f, 0xff, 0xf8, 0xdf, 0xb7, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x3e, 0x3f, 0xff, 0xe6, 0x1e, 0x37, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x0e, 0x3f, 0xff, 0x9e, 0xd8, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0x7e, 0xc7, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xfe, 0x7e, 0xdf, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0xff, 0xfe, 0x7c, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0xff, 0xfe, 0x71, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0xff, 0xff, 0x47, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0xff, 0xff, 0x1f, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0xff, 0xff, 0x7f, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x7f, 0xff, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x7f, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x7f, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xff, 0xfe, 0x0e, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, 0xff, 0xf8, 0x71, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x7f, 0xc0, 0x66, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1f, 0x00, 0xd8, 0x0d, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x03, 0xde, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x01, 0xdf, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0xdf, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x03, 0x00, 0x00, 0xdf, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x07, 0x03, 0x00, 0xdf, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x07, 0x02, 0x01, 0x1f, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x87, 0x02, 0x07, 0x1f, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xe7, 0x02, 0x07, 0x27, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x02, 0x0f, 0x39, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x03, 0xff, 0x3e, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff};
Piccolino_OLED display;
Piccolino_RAM ram;
int calibrationv;
float multiplier;
const int EEPROM_addr = 0;
const int cal_holdTime = 1; // 2 sec button hold to calibration
long secs_held; // How long the button was held (seconds)
byte previous = HIGH;
unsigned long firstTime; // how long since the button was first pressed
int active = 0;
double result_max = 0;
/*
Calculate MOD (Maximum Operating Depth)
*/
const float max_po1 = 1.40;
const float max_po2 = 1.60;
float cal_mod(float percentage, float ppo2 = 1.4) {
return 10 * ((ppo2 / (percentage / 100)) - 1);
}
void drawBitmap(int16_t x, int16_t y,
const unsigned char * bitmap, int16_t w, int16_t h) {
int16_t i, j, byteWidth = (w + 7) / 8;
display.clear();
for (j = 0; j < h; j++) {
for (i = 0; i < w; i++) {
if (pgm_read_byte(bitmap + j * byteWidth + i / 8) & (128 >> (i & 7))) {
display.drawPixel(x + i, y + j, WHITE);
}
}
}
display.update();
}
void read_sensor() {
int16_t millivolts = 0;
millivolts = ads.readADC_Differential_0_1();
// Serial.println(millivolts);
RA.addValue(millivolts);
}
void calibrate() {
display.clear();
display.setTextColor(WHITE);
display.setCursor(0, 0);
display.setTextSize(1);
display.print(F("Calibrating..."));
display.update();
active = 0;
result_max = 0.0;
double avg = RA.getAverage();
calibrationv = abs(avg);
EEPROMWriteInt(EEPROM_addr, calibrationv); // write to eeprom
// Serial.print(">>>>>> ");
// Serial.println(calibrationv);
delay(1000);
}
void analyzing() {
double currentmv = 0;
double result;
double mv = 0.0;
read_sensor();
currentmv = RA.getAverage();
currentmv = abs(currentmv);
// Serial.print(">> ");
// Serial.println(currentmv);
result = (currentmv / calibrationv) * 20.9;
if (result > 99.9) result = 99.9;
mv = currentmv * multiplier;
display.clear();
display.setTextColor(WHITE);
display.setCursor(0, 0);
if (mv < 0.02 || result <= 0) {
display.setTextSize(2);
display.println(F("Sensor"));
display.print(F("Error!"));
} else {
display.setTextSize(4);
display.print(result, 1);
display.println(F("%"));
if (result >= result_max) {
result_max = result;
}
display.setTextSize(1);
display.setCursor(0, 31);
display.setTextColor(BLACK, WHITE);
display.print(F("Max "));
display.print(result_max, 1);
display.print(F("% "));
display.print(mv, 2);
display.print(F("mv"));
if (active % 4) {
display.setCursor(115, 29);
display.setTextColor(WHITE);
display.print(F("."));
}
display.setTextColor(WHITE);
display.setCursor(0, 40);
display.print(F("pO2 "));
display.print(max_po1, 1);
display.print(F("/"));
display.print(max_po2, 1);
display.print(F(" MOD"));
display.setTextSize(2);
display.setCursor(0, 50);
display.print(cal_mod(result, max_po1), 1);
display.print(F("/"));
display.print(cal_mod(result, max_po2), 1);
display.print(F("m "));
}
display.update();
}
void EEPROMWriteInt(int p_address, int p_value) {
byte lowByte = ((p_value >> 0) & 0xFF);
byte highByte = ((p_value >> 8) & 0xFF);
EEPROM.write(p_address, lowByte);
EEPROM.write(p_address + 1, highByte);
}
unsigned int EEPROMReadInt(int p_address) {
byte lowByte = EEPROM.read(p_address);
byte highByte = EEPROM.read(p_address + 1);
return ((lowByte << 0) & 0xFF) + ((highByte << 8) & 0xFF00);
}
void setup() {
// put your setup code here, to run once:
display.begin();
ram.begin();
// Serial.begin(9600);
drawBitmap(0, 0, logo, 128, 64);
pinMode(buttonPin, INPUT_PULLUP);
ads.setGain(GAIN_TWO);
multiplier = 0.0625F;
ads.begin(); // ads1115 start
//calibrate
for (int cx = 0; cx < RA_SIZE; cx++) {
read_sensor();
delay(50);
}
calibrationv = EEPROMReadInt(EEPROM_addr);
if (calibrationv < 100) {
calibrate();
}
// delay(1000);
}
void loop() {
// put your main code here, to run repeatedly:
int current = digitalRead(buttonPin);
if (current == LOW && previous == HIGH && (millis() - firstTime) > 200) {
firstTime = millis();
active = 17;
}
secs_held = (millis() - firstTime) / 1000;
if (secs_held > 0 && current == LOW && previous == LOW) {
if (secs_held >= cal_holdTime) {
calibrate();
}
}
previous = current;
analyzing();
delay(200);
active++;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment