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:
- 4:74df6d31ee0a
- Parent:
- 3:0d94a277aa8c
- Child:
- 5:35417986539a
File content as of revision 4:74df6d31ee0a:
//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 seconds=0; // general number of seconds since 2000 etc timestamp variable 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 secondst=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(secondst); } 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("Calibrate 21%% %.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... } // sub to test if a variable is an even number int iseven(int g) { int test=0; if(g%2 ==0) test=1; return(test); } 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 && iseven(seconds)==1) g_lcd.character(8,0,4); // diving icon if (state==2 && iseven(seconds)==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); } // 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); } void leds() { // first turn everything off red=0; green=0; blue=0; float ppo; ppo=maximum(ppo1,ppo2); // use max value to compute leds... if(ppo<0.2 && flash==1) red=1; // flashing red means very bad things - getting low on oxygen!!! if(ppo>0.2 && ppo < 1) red=1; // non-flashing red if(ppo>=1.0 && ppo <1.2) {red=1;green=1;} // red-green if(ppo<1.3 && ppo >=1.2) green=1; // green - optimal range in ccr mode if(ppo<1.4 && ppo >=1.3){green=1;blue=1;} // green-blue - high ppo2 be careful of spiking if(ppo2<1.6 && ppo2>=1.4) blue=1; // DANGE ble high ppo2 if(ppo2>=1.6 && flash==1) blue=1; } //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 } // 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 } 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 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==0) state=1; // surface mode - ok to go for a dive now if (minutes>=1 && depth>0.5 && state==1) { state=2; // enter dive mode if (startdive==0) startdive=seconds; // set start of divetime. don't do this twice 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=endclock+1; if (endclock>150) state=1; // 30s at shallower than 0.3m and we return to surface mode. } scrubtime=minutes; // need to add memory of prior scrub time to this once variable input fom log file is implements } j=(j+1) %4; // flash control variable = used to make the warnings flash for 0.4s duty cycle } // end while } //end main