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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Rebmon_main.cpp Source File

Rebmon_main.cpp

00001 //lpc1124lcddemo
00002 // driver for mbed based ppo2 monitoring system for closed circuit rebreather
00003 // reading 3 electrogalvanic oxygen sensors and one pressure sensor
00004 #include "ds1307.h"
00005 #include "mbed.h"
00006 #include "TextOLED.h"
00007 
00008 
00009 #define DRATIO 0.6420066 // ratio of voltage at pin20 to voltage actually generated by the sensor
00010 
00011 //hud LINES
00012 DigitalOut AB(p7); //pins AB for data bits
00013 DigitalOut CP(p5); // clock to shift reg
00014 //DigitalOut MR(p8); // reset to shift reg (low for clear)#
00015 DigitalOut btest(p6); // pin to  drive lastblue led
00016 
00017 // offsets for lm324 amp in terms of reading values on adc
00018 // these are calibrated fromthe actual amplifier circuit but effectively include the ADC offsets for the mbed
00019 #define coff1 -0.013375
00020 #define coff2 -0.00936
00021 #define coff3 -0.0212136
00022 
00023 
00024 
00025 Serial pc(USBTX, USBRX); // tx, rx  for debug and usb pc comunications
00026 
00027 
00028 //pin assignments and declarations
00029 // LCD display
00030 TextLCD g_lcd(p26, p25, p24, p23, p22, p21);  // RS, E, DB4, DB5, DB6, DB7
00031 //backlight
00032 DigitalOut backlight(p29);
00033 
00034 //onboard leds
00035 DigitalOut led1(LED1);
00036 DigitalOut led2(LED2);
00037 
00038 // warning leds
00039 DigitalOut red(p34);
00040 DigitalOut green(p33);
00041 DigitalOut blue(p30);
00042 
00043 
00044 // switches and buttons - these are pulled up by resistors so are active low
00045 DigitalIn CAL(p36);
00046 DigitalIn SW1(p35); // reed switch in display unit
00047 DigitalIn SW2(p10); // reed switch in dispaly unit - NONE FUNCIONAL IN CURRENT HEAD - SWITCH FAILED DURING POTTING
00048 //DigitalIn MODE(p11);// a switchn on the mbed pcb to select between SCR and CCR modes for the LEDs NOT USED ANYMORE
00049 
00050 // log data storage
00051 LocalFileSystem local("local");
00052 
00053 // adc inputs for sensors
00054 AnalogIn PRESin(p20);
00055 AnalogIn EG1(p19);
00056 AnalogIn EG2(p18);
00057 AnalogIn EG3(p16); 
00058 AnalogIn Vbatt(p17); // battery voltage divided down by 3
00059 AnalogIn V5V(p15); // sense the '5V' output from the max1724 unit - divided down by 2.  Nominally 2.5V===0.757575757' in 3.3V ADC
00060 
00061 
00062 
00063 // realtime clock
00064 DS1307 my1307(p28,p27); // start DS1307 class and give it pins for connections of the DS1307 device
00065 
00066 // variables for realtime clock
00067 int sec = 0;
00068 int min = 0;
00069 int hours = 0;
00070 int day = 0;
00071 int date = 0;
00072 int month = 0;
00073 int year = 0;
00074 int seconds=0; // general number of seconds since 2000 etc timestamp variable
00075 
00076 int scrubtime=0,scrubold=0; // these are expressed in minutes
00077 int divetime=0;
00078 
00079 int flash=0; // variable used top control flashing icons
00080 int state=0; // IMPORTANT - VARIABLE THAT DRIVES HNTE STATE MACHINE STATE=0 = STARTUP, STATE=1=SURFACE  STATE=2= DIVING
00081 float lowsetpoint=0.7,highsetpoint=1.2,switchdepth=10; // variables to determine HUD led states 
00082 //switchdepth is centre of switch region 1m deep if switchdepth=10 then will go to high as descebnd 
00083 //through 10.5 and go back to low when ascending through 9.5
00084 int setpoint=0; // 0=low 1 = high
00085 
00086 // variables for the eg cells and pressure sensor eg1calamd eg2cal ar reading when the sensor is in 0.21bar O2 and
00087 //dcal is the reading whe the pressure sensor is at the surface
00088 float eg1cal=0.09,eg2cal=0.09,eg3cal=0.09,pcal=0.1136;
00089 // NB these are updated from /local/cal.dat so values not so important.... eventually
00090 
00091 float depth=0,ppo1=0,ppo2=0,ppo3=0  ,Vb=0,pressure=0; // depth, 1st o2 sensor second o2 sensor battery voltage,,Pressure
00092 float fo1=0,fo2=0,fo3=0,mod=55; //%f values,mod
00093 
00094 FILE *lp; // file pointer for log file
00095 
00096 bool nostop=1, deco=0; // variables to define state for deco
00097 
00098 
00099 
00100 //HUD codes
00101 // make a HUD clock pulse
00102 int clk()
00103 {
00104     wait_us(1);
00105     CP=0;
00106     wait_us(1);
00107     CP=1;
00108     return(0);
00109 }
00110 
00111 // write 8 bits to the HUD shift register
00112 int HUD_write(char d)
00113 {
00114     int i=0;
00115     for(i=7; i>=0; i--) {
00116         AB=d & (1 << i);
00117         AB=!AB;
00118         clk();
00119     }
00120     return(0);
00121 }
00122 
00123 // make all HUD leds white - useful for warnings etc
00124 int HUD_white()
00125 {
00126     // set all white;
00127     HUD_write(255);
00128     btest=0;
00129 
00130     return(0);
00131 }
00132 // clear the HUD - make al black
00133 int HUD_clr()
00134 {
00135     HUD_write(0);
00136     btest=1;
00137     return(0);
00138 }
00139 
00140 
00141 
00142 // code to detect leap years
00143 int LeapYear(int year) {
00144     int leap=0;
00145 
00146     if (year % 400==0) leap=1;
00147     else if (year %100 ==0) leap=0;
00148     else if (year % 4 ==0) leap=1;
00149     else leap=0;
00150     return(leap);
00151 }
00152 
00153 
00154 //===== sub to get time from ds1307 and create the 'seconds' which is a version of timestamp....
00155 int getseconds() {
00156     int leap=0,dayofyear=0,timestamp=0;
00157     int y=0,byear=0;
00158     int days[12]={0,31,59,90,120,151,181,212,243,273,304,334};
00159     my1307.gettime( &sec, &min, &hours, &day, &date, &month, &year);
00160     //simple timestamp = # seconds since midnight jan 1st 2000 if all months were 30 days.
00161     //int secondst=year*365*24*60*60+month*30*24*60*60+day*24*60*60+hours*60*60+min*60+sec;
00162     //simple timestamp = # seconds since midnight jan 1st 2000 if all months were 30 days....
00163     // ie wrong but simpler than the real thing
00164 
00165 
00166     // sort out ds1307 definiteion of year
00167     year=year+2000;
00168     leap=LeapYear(year);
00169 
00170     // now decide dayofyear
00171     dayofyear=days[month-1]+date-1;
00172     if (leap==1 && month >2) dayofyear++; // deal with extra february day in leap year
00173 
00174     // now find number of days since 1970
00175     for (y=1970; y<year; y++) {
00176         if (LeapYear(y) == 1) {
00177             byear += 366*24*60*60;
00178         } else {
00179             byear += 365*24*60*60;
00180         }
00181     }
00182 
00183     // finally get the seconds right and construct timestamp in seconds since beginning of 1970
00184     timestamp=(byear)+dayofyear*24*3600+hours*3600+min*60+sec;
00185 
00186     //DEBUG====================================
00187     // printf("secondst =  %d\t timestamp = %d\t%.2d : %.2d : %d - %.2d:%.2d:%.2d\r",secondst,timestamp,date,month,year,hours,min,sec);
00188 
00189     return(timestamp);
00190 
00191 }
00192 
00193 
00194 void set_custom_char() {
00195     char cgchar[64]={
00196         6,9,9,9,9,9,9,15, // battery  symbol                    0 address 64 = 0x40
00197         28,20,20,20,20,20,29,0, //  0. symbol for ppo2          1 address 72 = 0x48
00198         8,24,8,8,8,8,29,0, // 1. symbol for ppo2                2 address 80 =0x50
00199         6,15,15,15,15,15,15,15, // unused                       3 address 88 = 0x58
00200         31,19,21,21,21,21,19,31,  // unused                     4 address 96 = 0x60
00201         6,6,6,6,6,0,0,6,             // top char Vmessg         5 address 104 =0x68 - used for Vmessage
00202         31,17,23,17,29,17,31,0, // bottom char Vmessg           6 address 112 =0x70 -used for Vmessg
00203         2,6,2,2,2,2,23 // for dec point in depth                7 address 120 =0x78
00204     };
00205     int i=0;
00206 // do stuff here to set cstom chars
00207     g_lcd.writeCommand(0x40); // set start address for CGRAM
00208     for (i=0; i<64; i++) {
00209         g_lcd.writeData(cgchar[i]);
00210     }
00211 
00212 }
00213 
00214 // stash cal values on local drive
00215 void store() {
00216     int timestamp=0;
00217     timestamp=getseconds();
00218     wait(0.1);
00219     FILE *fp=fopen("/local/CAL.dat","w");
00220     fprintf(fp,"%e\n%e\n%e\n%e\n%d\n%d\n",eg1cal,eg2cal,eg3cal,pcal,scrubtime,timestamp);
00221 
00222     fclose(fp); //NB file system locked on write so must make sure we close files in case want to reprogram etc...
00223     wait(0.1);
00224 }
00225 
00226 
00227 // subroutine to calibreate o2 sesnors and store ca data in /local/CAL.dat
00228 void calibrate() {
00229     int count=1;
00230     float s1=0,s2=0,s3=0,pres=0;
00231     // average 20 readings for noise reduction
00232     g_lcd.cls();
00233     for (count=20; count>0; count--) {
00234         s1=s1+EG1;
00235         s2=s2+EG2;
00236         s3=s3+EG3;
00237         pres=pres+PRESin;
00238         g_lcd.locate(0,0);
00239         g_lcd.printf("CAL 21%% %.2d %1.2f",count,pres/(20-count+1));
00240        
00241         g_lcd.locate(0,1);
00242         g_lcd.printf("%1.2f: %1.2f: %1.2f",s1/(20-count+1),s2/(20-count+1),s3/(20-count+1));
00243         wait(1);
00244     }
00245     //average
00246     s1=s1/20-coff1;
00247     s2=s2/20-coff2;
00248     s3=s3/20-coff3;
00249     // set calibration variables
00250     eg1cal=s1;
00251     eg2cal=s2;
00252     eg3cal=s3;
00253     pcal=pres/20/DRATIO; // surface pressure output voltage from sensor
00254     scrubtime=0; // reset the scrubber timer to zero.
00255     scrubold=0; // set stored scrub time to zero too.
00256     // write cal data NB overwites previous
00257     /*  FILE *fp=fopen("/local/CAL.dat","w");
00258       fprintf(fp,"%e\n%e\n%e\n%d",eg1cal,eg2cal,pcal,scrubtime);
00259       fclose(fp); //NB file system locked on write so must make sure we close files in case want to reprogram etc...*/
00260     store();
00261 }
00262 
00263 // sub to test if a variable is an even number
00264 int iseven(int g) {
00265     int test=0;
00266     if (g%2 ==0) test=1;
00267     return(test);
00268 }
00269 
00270 
00271 void status() {
00272    /* if (state==0) {
00273         g_lcd.character(7,0,33); // warning icon until 1 min up
00274         g_lcd.character(8,0,83); // surface icon - letter S
00275     } else {
00276         g_lcd.character(7,0,32);
00277     }
00278     if (state==1) g_lcd.character(8,0,83); // surface icon
00279     if (state==2 && iseven(seconds)==1) g_lcd.character(8,0,4); // diving icon - inverse D
00280     if (state==2 && iseven(seconds)==0) g_lcd.character(8,0,68); // diving icon - normal D
00281     */
00282 // yes - this does nothing as all this is now done by vmessage
00283 }
00284 
00285 // warning and LED conditions
00286 
00287 void warning() {
00288     if (depth>=mod && flash==1) g_lcd.character(11,0,33);
00289     else g_lcd.character(11,0,32); // blank sapce
00290 
00291 }
00292 
00293 // pick maximum of two values
00294 float maximum(float a,float b,float c) {
00295     float maximum;
00296     if(a>b && a>c) maximum=a;
00297     if(b>a && b>c) maximum=b;
00298     if(c>a && c>b) maximum=c;
00299     return(maximum);
00300 }
00301 
00302 // pick minimum  of three values
00303 float minimum(float a,float b,float c) {
00304     float minim;
00305     if (a<b && a < c) minim=a;
00306     if(b<a && b<c) minim=b;
00307     if(c<a && c <b) minim=c;
00308 
00309     return(minim);
00310 }
00311 
00312 
00313 // handset led control
00314 void leds() {
00315 // first turn everything off
00316     red=0;
00317     green=0;
00318     blue=0;
00319     float ppox,ppom,sp;
00320     int mo=0;
00321     //mo=MODE;
00322     if(setpoint==0) sp=lowsetpoint;
00323     else sp=highsetpoint;
00324     ppox=maximum(ppo1,ppo2,ppo3); // use max value to compute leds...
00325     ppom=minimum(ppo1,ppo2,ppo3); // unless we want minimum
00326     if (mo==0) { // CCR mode
00327         if (ppom<0.2 && flash==1) {red=1;} // flashing red means very bad things - getting very --low on oxygen!!!
00328         if (ppom>0.2 && ppox < (sp-0.15)) red=1; // non-flashing red
00329         if (ppox>=(sp-0.15) && ppox <(sp-0.5)) {
00330             red=1;    // red-green
00331             green=1;
00332         }
00333         if (ppox<(sp+0.05) && ppox >=(sp-0.05)) green=1; // green - optimal range in ccr mode
00334         if (ppox<(sp+0.15) && ppox >=(sp+0.05)) {
00335             green=1;    // green-blue - high ppo2 be careful of spiking
00336             blue=1;
00337         }
00338         if (ppox<1.6 && ppox>=(sp+0.15)) blue=1; // DANGER blue high ppo2
00339         if (ppox>=1.6 && flash==1) blue=1;
00340     }
00341    /*if (mo==1) { // SCR mode
00342         if (ppom<0.2 && flash==1) red=1;
00343         if (ppom>=0.2 && ppox <0.26) red=1; // will give green red for low but not lethal ppo2s
00344         if (depth < 0.8*mod && ppom>0.2) green=1;
00345         if (depth< mod && depth >=0.8*mod) {
00346             green=1;
00347             blue=1;
00348         }
00349         if (depth >=mod && flash==1) blue=1;
00350     }*/
00351 
00352 }
00353 
00354 
00355 
00356 //read battery state and insert the battery symbol
00357 //RE-WRITE THIS TO USE THE 5 EMPTY PIXELS INSIDE THE BATTERY OUTLINE TO REPRESENT 50Mv INCREMENTS ON 3.5V
00358 void battery() {
00359  char cgchar[32]={
00360         6,9,9,9,9,9,9,15, // battery empty symbol         
00361         6,9,9,9,9,15,15,15, // battery 50% symbol         
00362         6,9,9,15,15,15,15,15, // battery 75% symbol       
00363         6,15,15,15,15,15,15,15, // battery 100% symbol    
00364         };
00365 
00366 
00367     int batsym=0,i=0,bstate=0,row=0; // bstate =(Vbattery-3.5V)/0.05;
00368 
00369 
00370     // idea to build in 6 levels of battery indicator by on the fly reprogramming character 2 as required.
00371     Vb=0;
00372     for (i=0; i<20; i++) {
00373         Vb=Vb+Vbatt; // read adc connected to battery via a 1/3 potential divider
00374         wait(0.05);
00375     }
00376     Vb=Vb*3.3/20/0.337; // average 4 readings to reduce noise and rescale to ADC limit and convert to volts and account for potential divider on pcb.
00377 
00378     bstate=floor((Vb-3.5)/0.05);
00379     if(bstate > 9) bstate=9;
00380     if(bstate <0) bstate=0;
00381     
00382     // fill up batery symbol according to bstate
00383     for(i=0;i<10;i++)
00384     {
00385         // find row to enter 
00386         row=6-floor((float)i/2);
00387        if(bstate >=i) 
00388        {
00389        if(iseven(i)==1) cgchar[row]=cgchar[row]+4;
00390        else cgchar[row]=cgchar[row]+2;
00391        }
00392         
00393     }
00394 
00395 /*
00396     if (Vb>0.388) batsym=8; //3.85-3.92V
00397     if (Vb>0.395) batsym=16; // battery 3.92-4V
00398     if (Vb>0.404) batsym=24; // battery . >4V
00399     */
00400 
00401 
00402 // write the appropriate battery symbol into the first custom character
00403     g_lcd.writeCommand(0x40); // set start address for CGRAM
00404     for (i=0; i<8; i++) {
00405         g_lcd.writeData(cgchar[i]);
00406     }
00407 
00408 g_lcd.character(11,1,0); // battery symbol
00409  if (bstate <2 && flash==0) g_lcd.character(11,1,32); // bung in space if flashing
00410 
00411 
00412 }
00413 
00414 // sub to make the nice status message work in locations 9,0 and 9,1
00415 void vmessage() {
00416 int i,d,cpos=0;
00417 // "INITSURFDIVE" in vertical chas - 1 custom char per two symbols
00418    char mesg[48]={  17,31,17,0,31,6,12,31, 0,17,31,17,0,1,31,1,  19,21,25,0,31,16,31,0,    31,13,23,0,31,5,1,0,   31,17,14,0,17,31,17,0,  15,16,15,0,31,21,17,0};
00419                   
00420    
00421  
00422    g_lcd.writeCommand(104); // set start address for CGRAM characrter #6 out of 8
00423 
00424     for (i=0; i<16; i++) { // write 2 chars worth into this segment NO DECO
00425    
00426 
00427        g_lcd.writeData(mesg[i+state*16]);
00428     } // endfor
00429 
00430 
00431     
00432 g_lcd.character(12,0,5); // custom char 5
00433 
00434 g_lcd.character(12,1,6); // custom char 6
00435 
00436 }
00437 
00438 
00439 // subroutine to write the main display data
00440 //0123456789abcdef
00441 
00442 //x.xx:xx D XX  xx
00443 //x.xx:xx B XX xxx NB the warning, staus and battery icons are driven by separate subroutines.
00444 void display() {
00445     int mo=0,tmp=0;
00446     //mo=MODE;
00447     g_lcd.character(3,1,32);
00448 //1st line
00449 
00450  //ppo1
00451     if(ppo1<1) tmp=(int)(ppo1*100); else tmp=(int)(ppo1*100-100);
00452     g_lcd.locate(1,0);
00453     g_lcd.printf("%02d ",tmp);
00454     if(ppo1>=1) g_lcd.character(0,0,2);
00455     if(ppo1<1) g_lcd.character(0,0,1);
00456     
00457     if(ppo2<1) tmp=(int)(ppo2*100); else tmp=(int)(ppo2*100-100);
00458     g_lcd.locate(5,0);
00459     g_lcd.printf("%02d ",tmp);
00460     if(ppo2>=1) g_lcd.character(4,0,2);
00461     if(ppo2<1) g_lcd.character(4,0,1);
00462     
00463     if(ppo3<1) tmp=(int)(ppo3*100); else tmp=(int)(ppo3*100-100);
00464     g_lcd.locate(9,0);
00465     g_lcd.printf("%02d ",tmp);
00466     if(ppo3>=1) g_lcd.character(8,0,2);
00467     if(ppo3<1) g_lcd.character(8,0,1);
00468     
00469     g_lcd.locate(13,0);
00470     g_lcd.printf("%.2d",(int)depth); // depth
00471     g_lcd.locate(4,1);
00472     g_lcd.printf("%2dm",(int)mod); // mod
00473 //2nd line
00474     g_lcd.locate(0,1);
00475     tmp=minimum((float)fo1,(float)fo2,(float)fo3); // get min fraction of oxygen to display lowest for deco use
00476     g_lcd.printf("%2d%%",tmp);
00477     g_lcd.locate(13,1);
00478     g_lcd.printf("%03d",scrubtime % 1000); // modulo to avoid digits conflict - means divetime is always less than 100
00479     g_lcd.locate(8,1);
00480     g_lcd.printf("%2d",(int)(divetime/60) % 100 ); // rolls back to zero if go over 99
00481     // bung in battery icon
00482     battery();
00483     status(); // this will set the diving / suface mode icon
00484  //   warning(); // this will set the warning ic on assuming that max ppo2 is exceeded
00485     g_lcd.character(7,1,32); // space to cover any write error on top line
00486     leds(); // this sets the leds according to the various warning conditions
00487    /* if (mo==0) {
00488         g_lcd.character(7,1,99);    //'c' = ccr
00489     } else {
00490         g_lcd.character(7,1,115);    //'s' = scr
00491     }*/
00492     // custom character setting to sort out dp in depths
00493 
00494 
00495     char cgchar[80]={
00496         7,5,5,5,23,0,0,0, // .0
00497         2,2,2,2,18,0,0,0, //  .1
00498         7,1,7,4,23,0,0,0, // .2
00499         7,1,3,1,23,0,0,0, // .3
00500         5,5,7,1,17,0,0,0, //.4
00501         7,4,7,1,23,0,0,0, //.5
00502         7,4,7,5,23,0,0,0, //.6
00503         7,1,2,2,18,0,0,0, //.7
00504         7,5,7,5,23,0,0,0, //.8
00505         7,5,7,1,17,0,0,0 //.9
00506 
00507     };
00508 // special dp digit for depth
00509     int i=0,d=0;
00510     d=(int)((depth-(int)depth)*10); // should be size of the 1st decimal place
00511 // do stuff here to set cstom chars
00512     g_lcd.writeCommand(120); // set start address for CGRAM
00513     for (i=0; i<8; i++) {
00514         g_lcd.writeData(cgchar[i+d*8]);
00515     }
00516 
00517     g_lcd.character(15,0,7); // put in appropriate custom character
00518     
00519     // display the current setpoint information
00520     if(setpoint==0)    g_lcd.character(7,1,218); // letter down arrow for low setpoint
00521     if(setpoint==1)    g_lcd.character(7,1,217); // Letter 'H'
00522     if(flash==1)  g_lcd.character(7,1,115); // Letter ':'
00523 
00524 }
00525 
00526 
00527 
00528 
00529 // read sensors and generate calibrated outputs NB battery is read elsewhere
00530 
00531 void readsensors() {
00532     float barometric=0,mod1,mod2,mod3,temp,Vdepth=0,s1,s2,s3,MPXref=0;
00533     int tc=0;
00534   //  ppo1=EG1*0.21/eg1cal; // eg1cal is 0.21bar ppO2
00535   //  ppo2=EG2*0.21/eg2cal; // second oxygen cell ppO2
00536   //  ppo3=EG3*0.21/eg3cal;
00537    
00538     s1=0;
00539     s2=0;
00540     s3=0;
00541     for(tc=0;tc<20;tc++) // noise on Vdepth so average readings to compensate
00542     { 
00543     Vdepth=Vdepth+(PRESin/DRATIO); // read the depth sensor and calculate the real value rather using the dividing ratio
00544     wait_ms(10); // slows stuff down a bit but not a big problem
00545     s1=s1+EG1; // read o2 sensors
00546     s2=s2+EG2;
00547     s3=s3+EG3;
00548     MPXref=MPXref+V5V; // read 5V reference
00549     wait_ms(10); // slows stuff down a bit but not a big problem
00550     }
00551     Vdepth=Vdepth/20; // now have the average
00552     s1=s1/20-coff1;
00553     s2=s2/20-coff2;
00554     s3=s3/20-coff3;
00555     MPXref=MPXref/20*3.3*2; // should be 5V but may not be.....
00556 
00557     
00558     // compute ppO2s
00559     ppo1=s1*0.21/eg1cal;
00560     ppo2=s2*0.21/eg2cal;
00561     ppo3=s3*0.21/eg3cal;
00562     
00563     pc.printf("EG1=%f\tEG2=%f\tEG3=%f   \tMPXref=%f                             \r",s1,s2,s3,MPXref);
00564     pressure=(Vdepth*3.3/MPXref-0.04)/0.0012858; // pressure in kpa NB - assums that the 5V is correct
00565     //pressure=(PRESin*3.3/0.65006-0.04)/(0.0012858); // pressure in kPa assuming standard cal for mpx5700 sensor SUSPECT
00566     // NB the mpx5700 runs off 5v so would be better to divide its output down by 3/5 to get full range measurement
00567     //outputs. with no division the max mbed adc of 3.3V coresponds to 480kpa or about 38m depth.....
00568     // standard spec on mpx5700 should be 5V*(P*0.0012858+0.04)
00569     // new sensor has 3/5 divider built into sensor wiring.
00570     //barometric=(pcal*3.3/0.65006-0.004)/(0.0012858); // sealevel in kPa assuming standard cal for mpx5700 sensor
00571     barometric=(pcal*3.3/MPXref-0.04)/0.0012858; // barometric pressure (kpa) evaluated from calibration which we assume is baseline
00572     depth=(pressure-barometric)*0.1;   //100kPa=10m 1kPa=0.1m - this gives depth in m for freshwater.
00573     
00574     if (depth<0) depth=0; // deals wtih noise that may lead to small variation in values
00575 
00576 
00577 
00578 // THESE SHOULD BE JUST 100*ppox/(pressure/100);
00579     fo1=100*ppo1/((pressure-barometric)/100+1); // pressure in bar = pressure /100 and want a % so multiply by 100 as well
00580     fo2=100*ppo2/((pressure-barometric)/100+1);
00581     fo3=100*ppo3/((pressure-barometric)/100+1); // maybe these should be ppox/(depth/10+1)*100....?
00582 
00583     /*if (fo1<0) fo2=0;
00584     if (fo2<0) fo1=0;
00585 */
00586     //with three sensors will calculate mod from the largest ppo2 reading
00587     mod1=(1.4/(fo1/100)-1)*10;
00588     mod2=(1.4/(fo2/100)-1)*10;
00589     mod3=(1.4/(fo3/100)-1)*10;
00590 
00591     mod=minimum(mod1,mod2,mod3); // pick the least value
00592     
00593    // output for debugging to pc via usb line.
00594   //  pc.printf("VDepth %f\tPressure %f\tbarometric %f\tdepth %f\t  \n\r",Vdepth,pressure,barometric,depth);
00595     //NB - problem - we really need to monitor the 5V power line to ensure that it's driving the depth sensor ok.
00596     // it may need thicker cables as it currently only manages 4.8V on the board when everything is running.
00597 
00598 }
00599 // get values back from cal file on local drive
00600 void recall() {
00601     FILE *fp=fopen("/local/CAL.dat","r");
00602     fscanf(fp,"%e\n%e\n%e\n%e\n%d",&eg1cal,&eg2cal,&eg3cal,&pcal,&scrubold);
00603     fclose(fp); //NB file system locked on write so must make sure we close files in case want to reprogram etc...
00604 }
00605 
00606 // write the logfile opened and closed by start and end of dive
00607 void store_log() {
00608 
00609     //FILE *fp=fopen("/local/divelog.dat","a");
00610     float v5=0;
00611     v5=V5V;
00612     fprintf(lp,"%d\t%e\t%e\t%e\t%e\t%e\t%e\t%d\n",seconds,depth,ppo1,ppo2,ppo3,Vb,v5,scrubtime);
00613 
00614     if (divetime % 60==0) fflush(lp);
00615     // fclose(fp);
00616 }
00617 
00618 // read switches and report state
00619 int switches() {
00620     int ss=0;
00621     if (SW1==1 && SW2==1) ss=3;
00622     if (SW2==1 && SW1==0) ss=2;
00623     if (SW1==1 && SW2==0) ss=1;
00624     return(ss);
00625 }
00626 
00627 // interpret the ppo2 data into a simple set of hud codes.
00628 int HUD_display()
00629 { 
00630     int i,j3,h1,h2,h3;
00631     float cset=0;
00632       char gcode[6]={0,1,3,2,6,4}; // grey code for HUD reading 'red,amber,green,cyan,blue'
00633     
00634     HUD_clr(); // clear the HUID ready for write
00635    
00636     
00637     if(setpoint==0)  // low setpoint
00638     {
00639     cset=lowsetpoint;
00640     }
00641     
00642     if(setpoint==1) // hgh setpoint
00643     {
00644     cset=highsetpoint;
00645     }
00646 
00647     h1=(int)((ppo1-cset)/0.1+3.5);
00648     if(h1<1) h1=1;
00649     if(h1>5) h1=5;
00650     h2=(int)((ppo2-cset)/0.1+3.5);
00651     if(h2<1) h2=1;
00652     if(h2>5) h2=5;
00653     h3=(int)((ppo3-cset)/0.1+3.5);
00654     if(h3<1) h3=1;
00655     if(h3>5) h3=5;
00656     
00657     if(h3>3) btest=0; // handle extra blue connected to btest setting btest low lights blue led
00658     
00659     
00660     i=gcode[h1]+8*gcode[h2]+64*gcode[h3]; // this is possible bigger than a char so have to typeconvert
00661     HUD_write(i);
00662        
00663 }
00664 
00665 // sub to flash HUD n times as a warning of setpoint shift
00666 int HUD_flash(int n)
00667 {
00668     int i;
00669     for(i=0;i<n;i++)
00670     {
00671     HUD_clr();
00672     wait(0.3);
00673     HUD_white();
00674     wait(0.3);
00675    
00676     }
00677     HUD_display();
00678 }
00679 // sub to decide if the setpoint should change - in this variant it always changes at 9.5-10.5m
00680 // this might become annoyiong later so might want to make this function totally manual and use SW1 to control it.
00681 int setswitch()
00682 {
00683     if(setpoint==0 && depth >(switchdepth+0.5)) 
00684     { 
00685         setpoint=1; // handle switch from low to high
00686         HUD_flash(4); // 4 flashes says going to high setpoint
00687         // flash the hud here
00688     }
00689     
00690     if(setpoint==1 && depth < (switchdepth -0.5))
00691     {
00692         setpoint=0;  // swtich to low setpoint
00693         HUD_flash(2); // two flashes says going to low setpoint
00694         // flash the HUD here
00695     }
00696 }
00697 
00698 int main() {
00699 
00700 // start the clock in case it stopped for some reason 
00701 //this happens when the power drops due to battery getting too low. 
00702 // system still runs as a monitor but wont log.
00703 // might be useful later to build a sub that checks the clock is reading and starts it if its stopped
00704 
00705     my1307.start_clock();
00706 
00707 // first some local variables
00708     int startuptime=getseconds();
00709     int startdive=0,endclock=0; // value of seconds when dive starts and counter to decide if dive complete...
00710 
00711     int minutes=0; // minutes is elapsed minutes since start of prog
00712     int j=0,scount=1;; // general loop counting variable
00713     int sw=0; // status of the switches in the handset
00714     char schars[4]={32,0xd9,0xda,0xfb}; // up arrow, down arrow and both arrows;
00715 
00716     bool mdir=0;
00717 
00718 // code to deal with clock problem
00719 if(startuptime==0){ // clock buggered and needs reseting
00720 j=my1307.settime( 0, 0, 1, 1, 1, 1, 13); // set time to 1am on 1st jan 2013
00721 g_lcd.locate(0,0);
00722 g_lcd.printf( "Clockreset %d",j);
00723     wait(3);
00724 }
00725     set_custom_char(); // does what it says on the tin really
00726     g_lcd.cls();
00727     g_lcd.locate(0, 0);
00728     g_lcd.printf( "CCRMon SP%1.1f:%1.1f",lowsetpoint,highsetpoint);
00729     wait(3);
00730         g_lcd.cls(); // clear display to look nice
00731     g_lcd.locate(0,1);
00732     g_lcd.printf("CAL?");
00733     battery();
00734     j=0;
00735 wait(0.2);
00736 
00737     // get cal values last used from local drive
00738     recall();
00739     // display the correct scrubber time
00740     scrubtime=scrubold;
00741 
00742 // hang about waiting for the cal switch to be pressed in ccase it is
00743     while (scount<30) {
00744         seconds=getseconds(); // NB if this hangs then nothing works :( - usually means 5V is dodgy
00745         red=1;
00746         green=1;
00747         blue=1; // light all leds
00748 
00749         g_lcd.locate(5,1);
00750         g_lcd.printf("%.2d ",30-scount);
00751         if (j>1) flash=1;
00752         else flash=0;
00753         battery(); // bung in battery symbol.
00754         g_lcd.locate(7,0);
00755         g_lcd.printf( "%.2d:%.2d:%.2d", hours,min,sec);
00756       //  if (CAL==0) {
00757         if(SW1==0) {
00758             calibrate();
00759             scount=31; // make sure it goes to next frame ok
00760         }
00761         wait(0.05);
00762 
00763 
00764         j=(j+1) % 4;
00765         if(flash==0) HUD_white();
00766         else HUD_clr();
00767         scount++;
00768     } 
00769     g_lcd.cls();
00770 
00771 
00772     // ok there are three states in this system
00773 //MAIN LOOP ONCE STARTUP PROTOCOLS ARE COMPLETED
00774     j=0;
00775     g_lcd.cls();
00776     while (1) {
00777         wait(0.1); //stop screen flicker
00778         readsensors();
00779         setswitch(); // check the setpoint and adjust if crossing the swtich depth
00780         HUD_display(); // write the HUD codes
00781         seconds=getseconds();
00782         minutes=(int)(((float)seconds-(float)startuptime)/60);
00783         led1=seconds % 2; // flash the onboard led to make it clear stuff is running
00784         led2=!(seconds %2);
00785 
00786         if (j>1) flash=1;
00787         else flash=0;
00788 
00789         display(); // write the display
00790         HUD_display(); // write the HUD
00791       // sw=switches(); // read the switches and report their state
00792       // if(SW1==0) g_lcd.character(11,0,0xEF); else g_lcd.character(11,0,32); // NB here is possible alternate display underwater switching point
00793         // HERE do deco calcs - update tissues and compute desat , nostop or ascent times as required.
00794 
00795         // setup state variable
00796       if (minutes<1) state=0; // startup mode - do nothing just wait to allow sensor readings to settle.
00797         if (minutes>=1 && state==0) state=1; // surface mode - ok to go for a dive now
00798         if (minutes>=1 && depth>0.8 && state==1) {
00799             state=2; // enter dive mode
00800             lp=fopen("/local/divelog.dat","a");
00801             fprintf(lp,"#startdive = %d\n#seconds\tdepth\tppo1\tppo2\tppo3\tVb\t\tV5V\tscrubtime\n",seconds); // bung in a header here in case one needs it
00802             store_log(); // make a first log entry to catch this erliest part of the dive
00803             if (startdive==0) startdive=seconds; // set start of divetime. don't do this twice
00804             endclock=0; // reset end of dive clock
00805         }
00806         // in dive mode - things to do, 1 update divetime and scrubber time, 2 write log data 3 check for end of dive...
00807        if (state==2) {
00808             // divetime=(int)(((float)seconds-(float)startdive)/60.0); // time since start of dive in minutes.
00809             divetime=(seconds-startdive); // divetime no recorded in seconds since start of dive
00810 
00811             // do deco calcs here when implemented
00812             if (divetime %15 ==0) store_log(); // this saves the dive profile data every 15s and sensor optputs in a file called divelog.dat
00813             if (depth<=0.5) {
00814                 endclock=endclock+1;
00815 
00816                 if (endclock>150) {
00817                     state=1; // 30s at shallower than 0.5m and we return to surface mode. */
00818                     FILE *fp=fopen("/local/CAL.dat","w");
00819                     fprintf(fp,"%e\n%e\n%e\n%d",eg1cal,eg2cal,pcal,scrubtime);
00820                     fclose(fp); //NB file system locked on write so must make sure we close files in case want to reprogram etc...
00821                     
00822                     store();
00823                     fclose(lp);
00824                 } // endif endclock
00825                    
00826             } // end if depth
00827             scrubtime=scrubold+(divetime/60); //
00828         } // end state 2
00829 
00830 
00831         j=(j+1) %4; // flash control variable = used to make the warnings flash for 0.4s duty cycle
00832 
00833 
00834         vmessage(); // call to generate status message in vertical segment
00835     } // end while
00836 } //end main
00837 
00838 
00839 
00840