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
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
Generated on Sat Jul 23 2022 13:44:02 by 1.7.2