A code to drive a 3sensor reading unit for monitoring the operation opf a closed circuit rebreather (CCR) with 3 electrogalvanic sensors. Also uses a DS1307 for realtime clock and an MPX5700 to read the depth (mounted inside the breathing loop to keep it 'dry'). circuit diagrams available on rebreather world.

Dependencies:   DS1307 TextOLED mbed

Rebmon_main.cpp

Committer:
pegcjs
Date:
2012-08-03
Revision:
3:0d94a277aa8c
Parent:
2:a1c26faa9103
Child:
4:74df6d31ee0a

File content as of revision 3:0d94a277aa8c:

//lpc1124lcddemo
#include "ds1307.h"
#include "mbed.h"
#include "TextLCD.h"


#define METRE 0.02 // change in DEPin for 1m depth

//pin assignments and declarations
// LCD display
TextLCD g_lcd(p26, p25, p24, p23, p22, p21);  // RS, E, DB4, DB5, DB6, DB7
//backlight
DigitalOut backlight(p29);

//onboard leds
DigitalOut led1(LED1);
DigitalOut led2(LED2);

// warning leds
DigitalOut red(p34);
DigitalOut green(p33);
DigitalOut blue(p30);

// switches and buttons - these are pulled up by resistors so are active low
DigitalIn CAL(p36);
DigitalIn SW1(p35);

// log data storage
LocalFileSystem local("local");

// adc inputs for sensors
AnalogIn PRESin(p20);
AnalogIn EG1(p19);
AnalogIn EG2(p18);
AnalogIn Vbatt(p17);

// realtime clock
DS1307 my1307(p28,p27); // start DS1307 class and give it pins for connections of the DS1307 device

// variables for realtime clock
int sec = 0;
int min = 0;
int hours = 0;
int day = 0;
int date = 0;
int month = 0;
int year = 0;

int scrubtime=0; // these are expressed in minutes
int divetime=0;

int flash=0; // variable used top control flashing icons
int state=0; // IMPORTANT - VARIABLE THAT DRIVES HNTE STATE MACHINE STATE=0 = STARTUP, STATE=1=SURFACE  STATE=2= DIVING

// variables for the eg cells and pressure sensor eg1calamd eg2cal ar reading when the sensor is in 0.21bar O2 and
//dcal is the reading whe the pressure sensor is at the surface
float eg1cal=0.09,eg2cal=0.09,pcal=0.1136;
// NB these are updated from /local/cal.dat so values not so important.... eventually

float depth=0,ppo1=0,ppo2=0,  Vb=0,pressure=0; // depth, 1st o2 sensor second o2 sensor battery voltage,,Pressure
float fo1=0,fo2=0,mod=55; //%f values,mod

//===== sub to get time from ds1307 and create the 'seconds' which is a version of timestamp....
int getseconds() {
    my1307.gettime( &sec, &min, &hours, &day, &date, &month, &year);
    //simple timestamp = # seconds since midnight jan 1st 2000 if all months were 30 days.
    int seconds=year*365*24*60*60+month*30*24*60*60+day*24*60*60+hours*60*60+min*60+sec;
    //simple timestamp = # seconds since midnight jan 1st 2000 if all months were 30 days....
    // ie wrong but simpler than the real thing
    return(seconds);
}


void set_custom_char() {
    char cgchar[64]={
        6,9,9,9,9,9,9,15, // battery empty symbol         0
        6,9,9,9,9,15,15,15, // battery 50% symbol         1
        6,9,9,15,15,15,15,15, // battery 75% symbol       2
        6,15,15,15,15,15,15,15, // battery 100% symbol    3
        31,19,21,21,21,21,19,31,  // diving symbol        4 inverse D
        6,6,6,6,6,0,0,6,             // warning symbol    5
        31,17,23,17,29,17,31,0, // surface symbol         6 inverse S
        0,0,17,17,0,17,14,0 // happy symbol                 7
    };
    int i=0;
// do stuff here to set cstom chars
    g_lcd.writeCommand(0x40); // set start address for CGRAM
    for (i=0; i<64; i++) {
        g_lcd.writeData(cgchar[i]);
    }

}


// subroutine to calibreate o2 sesnors and store ca data in /local/CAL.dat
void calibrate() {
    int count=1;
    float ppo1=0,ppo2=0,pres=0;
    // average 20 readings for noise reduction
    g_lcd.cls();
    for (count=20; count>0; count--) {
        g_lcd.locate(0,0);
        g_lcd.printf("Calibrating %.2d",count);
        ppo1=ppo1+EG1;
        ppo2=ppo2+EG2;
        pres=pres+PRESin;
        g_lcd.locate(0,1);
        g_lcd.printf("%1.2f: %1.2f: %1.2f",ppo1/(20-count+1),ppo2/(20-count+1),pres/(20-count+1));
        wait(1);
    }
    //average
    ppo1=ppo1/20;
    ppo2=ppo2/20;
    // set calibration variables
    eg1cal=ppo1;
    eg2cal=ppo2;
    pcal=pres/20; // surface pressure....
    scrubtime=0; // reset the scrubber timer to zero.
    // write cal data NB overwites previous
    FILE *fp=fopen("/local/CAL.dat","w");
    fprintf(fp,"%e\n%e\n%e\n%d",eg1cal,eg2cal,pcal,scrubtime);
    fclose(fp); //NB file system locked on write so must make sure we close files in case want to reprogram etc...
}


void status() {
    if (state==0) {
        g_lcd.character(9,0,5); // warning icon until 1 min up
        g_lcd.character(8,0,6); // surface icon
    }
    if (state==1) g_lcd.character(8,0,6); // surface icon
    if (state==2 && flash==1) g_lcd.character(8,0,4); // diving icon
    if (state==2 && flash==0) g_lcd.character(8,0,68); // diving icon
    }

// warning and LED conditions

void warning() {
    if (depth>=mod && flash==1) g_lcd.character(13,0,5);

}

void leds() {
}

//read battery state and insert the battery symbol
void battery() {
    int batsym=0;
    Vb=Vbatt; // read adc connected to battery via a 1/3 potential divider
    if (Vb>0.606) batsym=1;
    if (Vb>0.707) batsym=2;
    if (Vb>0.808) batsym=3;
    if (batsym >0) g_lcd.character(8,1,batsym);
    if (batsym ==0 && flash==1) g_lcd.character(8,1,batsym);
    if (batsym ==0 && flash==0) g_lcd.character(8,1,32);
}

// subroutine to write the main display data
//0123456789abcdef

//x.xx:xx D XX  xx
//x.xx:xx B XX xxx NB the warning, staus and battery icons are driven by separate subroutines.
void display() {
//1st line
    g_lcd.locate(0,0);
    g_lcd.printf("%1.2f:%.2d   %.2d  %.2d",ppo1,(int)fo1,(int)depth,(int)mod);
//2nd line
    g_lcd.locate(0,1);
    g_lcd.printf("%1.2f:%.2d   %.2d %.3d",ppo2,(int)fo2,divetime,scrubtime);
    // bung in battery icon
    battery();
    status(); // this will set the diviong / suface mode icon
    warning(); // this will set the warning icon assuming that max ppo2 is exceeded

    leds(); // this sets the leds according to the various warning conditions

}


// pick maximum of two values
float maximum(float a,float b) {
    float maximum;
    if (a>b) maximum=a;
    else maximum=b;
    return(maximum);
}

// pick minimum  of two values
float minimum(float a,float b) {
    float minim;
    if (a<b) minim=a;
    else minim=b;
    return(minim);
}



// read sensors and generate calibrated outputs NB battery is read elsewhere
void readsensors() {
    float barometric=0,mod1,mod2;
    ppo1=EG1*0.21/eg1cal; // eg1cal is 0.21bar ppO2
    ppo2=EG2*0.21/eg2cal; // second oxygen cell ppO2
    pressure=(PRESin*3.3-0.024)/(0.0038574); // pressure in kPa assuming standard cal for mpx5700 sensor SUSPECT
    // barometric=(pcal*3.3-0.024)/(0.0038574); // sealevel in kPa assuming standard cal for mpx5700 sensor
    depth=(pressure-101.325)*0.1;   //100kPa=10m 1kPa=0.1m - this gives depth in m for freshwater.
    //with two sensors will calculate mod from the largest ppo2 reading

    fo1=100*ppo1/(pressure/100); // pressure in bar = pressure /100 and want a % so multiply by 100 as well
    fo2=100*ppo2/(pressure/100);


    mod1=(1.4/(fo1/100)-1)*10;
    mod2=(1.4/(fo2/100)-1)*10;

    mod=minimum(mod1,mod2); // pick the least value
    //DEBUG

}
// sub to test if a variable is an even number
/*int iseven(int g) {
    int test=0;
    if ((float)g/2==(int)((float)g/2)) test=1;
    return(test);
}*/

int main() {
// first some local variables
    int startuptime=getseconds();
    int startdive=0,endclock=0;; // value of seconds when dive starts and counter to decide if dive complete...

    int seconds=0,minutes=0,dt=0;; // minutes is elapsed minutes since start of prog
    int i=0,j=0; // general loop counting variables


    set_custom_char(); // does what it says on the tin really
    g_lcd.cls();
    g_lcd.locate(0, 0);
    g_lcd.printf( "RebMon");
    g_lcd.locate(0,1);
    g_lcd.printf("CAL?");
    battery();
j=0;
// hang about waiting for the cal switch to be pressed in ccase it is
    while (seconds-startuptime<20) {
        seconds=getseconds();
        g_lcd.locate(5,1);
        g_lcd.printf("%.2d",21-(seconds-startuptime));
        if(j>1) flash=1;
        else flash=0;
        battery(); // bung in battery symbol.
        g_lcd.locate(7,0);
        g_lcd.printf( "%.2d:%.2d:%.2d", hours,min,sec);
        if (CAL==0) {
            calibrate();

        }
        wait(0.2);
        j=(j+1) % 4;
    }
    g_lcd.cls();
    backlight=1; // backlight on - this driven by bc182l and 50ohm resistor off the 5V supply to send ~ 20mA

    // ok there are three states in this system
//MAIN LOOP ONCE STARTUP PROTOCOLS ARE COMPLETED
    j=0;
    while (1) {
        wait(0.2); //stop screen flicker
        readsensors();
        seconds=getseconds();
        minutes=(int)((float)seconds-(float)startuptime)/60;
        dt=seconds-startuptime; // elapsed seconds

        if (j>1) flash=1;
        else flash=0;

        display(); // write the display

        // setup state variable
        if (minutes<1) state=0; // startup mode - do nothing just wait to allow sensor readings to settle.
        if (minutes>=1) state=1; // surface mode - ok to go for a dive now
        if (minutes>1 && depth>0.5 && state==1) {
            state=2; // enter dive mode
            startdive=seconds; // set start of divetime.
            endclock=0; // reset end of dive clock
        }
        if (state==2) {
            divetime=(int)((float)seconds-(float)startdive)/60; // time since start of dive in minutes.
            // do deco calcs here when implemented
            if (depth<0.3) {
                endclock++;
                if (endclock==150) state=1; // 30s at shallower than 0.3m and we return to surface mode.
            }
        }


        j=(j+1) %4; // flash control variable = used to make the warnings flash for 0.4s duty cycle
    } // end while
} //end main