Software to drive a monitor unit for a closed circuit rebreather using 3 electrogalvanic oxygen sensor cells run through an amplifier (lm324) . Uses a separate ds1307 clock IC to get timestamp values for logged data.
Dependencies: DS1307 TextOLED_custom mbed
The main electornics is housed in another pod mounted on the back of the unit. I'm using an mbed lpc11u24 to drive everything which comes with a flash drive for data logging built in. It has an external ds1307 clock chip added and a very cheapo lm324 quad op-amp to amplify the o2 sensor signals from the 10s of mV range by 30x so that ppo2=0.21 corresponds to about 0.3V. I still have to do some ADC averaging with this amplifier and do have to calibrate out the individual offsets of the chip but this works ok now that I've worked out which amp is on which adc...
Rebmon_main.cpp
- Committer:
- pegcjs
- Date:
- 2013-01-16
- Revision:
- 9:cd3599adfff6
- Parent:
- 8:f45e654b47d0
File content as of revision 9:cd3599adfff6:
//lpc1124lcddemo // driver for mbed based ppo2 monitoring system for closed circuit rebreather // reading 3 electrogalvanic oxygen sensors and one pressure sensor #include "ds1307.h" #include "mbed.h" #include "TextOLED.h" //TODO - MAKE A VERSION THAT DRIVES THE HUD, CHECKS THE 5V SUPPLY AND COMPENSATES THE READINGS IF ITS VARYING (LINEARLY) // AND PREVENT A HANG IF THE DS1307 FAILS TO RESPOND. #define DRATIO 0.6420066 // ratio of voltage at pin20 to voltage actually generated by the sensor //hud LINES DigitalOut AB(p7); //pins AB for data bits DigitalOut CP(p5); // clock to shift reg //DigitalOut MR(p8); // reset to shift reg (low for clear)# DigitalOut btest(p6); // pin to drive lastblue led // offsets for lm324 amp in terms of reading values on adc #define coff1 -0.013375 #define coff2 -0.00936 #define coff3 -0.0212136 Serial pc(USBTX, USBRX); // tx, rx for debug and usb pc comunications //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); // reed switch in display unit DigitalIn SW2(p10); // reed switch in dispaly unit - NONE FUNCIONAL IN CURRENT HEAD - SWITCH FAILED DURING POTTING //DigitalIn MODE(p11);// a switchn on the mbed pcb to select between SCR and CCR modes for the LEDs NOT USED ANYMORE // log data storage LocalFileSystem local("local"); // adc inputs for sensors AnalogIn PRESin(p20); AnalogIn EG1(p19); AnalogIn EG2(p18); AnalogIn EG3(p16); AnalogIn Vbatt(p17); // battery voltage divided down by 3 AnalogIn V5V(p15); // sense the '5V' output from the max1724 unit - divided down by 2. Nominally 2.5V===0.757575757' in 3.3V ADC // 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,scrubold=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 float lowsetpoint=0.7,highsetpoint=1.2,switchdepth=10; // variables to determine HUD led states //switchdepth is centre of switch region 1m deep if switchdepth=10 then will go to high as descebnd //through 10.5 and go back to low when ascending through 9.5 int setpoint=0; // 0=low 1 = high // 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,eg3cal=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,ppo3=0 ,Vb=0,pressure=0; // depth, 1st o2 sensor second o2 sensor battery voltage,,Pressure float fo1=0,fo2=0,fo3=0,mod=55; //%f values,mod FILE *lp; // file pointer for log file bool nostop=1, deco=0; // variables to define state for deco //HUD codes // make a HUD clock pulse int clk() { wait_us(1); CP=0; wait_us(1); CP=1; return(0); } // write 8 bits to the HUD shift register int HUD_write(char d) { int i=0; for(i=7; i>=0; i--) { AB=d & (1 << i); AB=!AB; clk(); } return(0); } // make all HUD leds white - useful for warnings etc int HUD_white() { // set all white; HUD_write(255); btest=0; return(0); } // clear the HUD - make al black int HUD_clr() { HUD_write(0); btest=1; return(0); } // code to detect leap years int LeapYear(int year) { int leap=0; if (year % 400==0) leap=1; else if (year %100 ==0) leap=0; else if (year % 4 ==0) leap=1; else leap=0; return(leap); } //===== sub to get time from ds1307 and create the 'seconds' which is a version of timestamp.... int getseconds() { int leap=0,dayofyear=0,timestamp=0; int y=0,byear=0; int days[12]={0,31,59,90,120,151,181,212,243,273,304,334}; 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 // sort out ds1307 definiteion of year year=year+2000; leap=LeapYear(year); // now decide dayofyear dayofyear=days[month-1]+date-1; if (leap==1 && month >2) dayofyear++; // deal with extra february day in leap year // now find number of days since 1970 for (y=1970; y<year; y++) { if (LeapYear(y) == 1) { byear += 366*24*60*60; } else { byear += 365*24*60*60; } } // finally get the seconds right and construct timestamp in seconds since beginning of 1970 timestamp=(byear)+dayofyear*24*3600+hours*3600+min*60+sec; //DEBUG==================================== // printf("secondst = %d\t timestamp = %d\t%.2d : %.2d : %d - %.2d:%.2d:%.2d\r",secondst,timestamp,date,month,year,hours,min,sec); return(timestamp); } void set_custom_char() { char cgchar[64]={ 6,9,9,9,9,9,9,15, // battery symbol 0 address 64 = 0x40 28,20,20,20,20,20,29,0, // 0. symbol for ppo2 1 address 72 = 0x48 8,24,8,8,8,8,29,0, // 1. symbol for ppo2 2 address 80 =0x50 6,15,15,15,15,15,15,15, // unused 3 address 88 = 0x58 31,19,21,21,21,21,19,31, // unused 4 address 96 = 0x60 6,6,6,6,6,0,0,6, // top char Vmessg 5 address 104 =0x68 - used for Vmessage 31,17,23,17,29,17,31,0, // bottom char Vmessg 6 address 112 =0x70 -used for Vmessg 2,6,2,2,2,2,23 // for dec point in depth 7 address 120 =0x78 }; 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]); } } // stash cal values on local drive void store() { int timestamp=0; timestamp=getseconds(); wait(0.1); FILE *fp=fopen("/local/CAL.dat","w"); fprintf(fp,"%e\n%e\n%e\n%e\n%d\n%d\n",eg1cal,eg2cal,eg3cal,pcal,scrubtime,timestamp); fclose(fp); //NB file system locked on write so must make sure we close files in case want to reprogram etc... wait(0.1); } // subroutine to calibreate o2 sesnors and store ca data in /local/CAL.dat void calibrate() { int count=1; float s1=0,s2=0,s3=0,pres=0; // average 20 readings for noise reduction g_lcd.cls(); for (count=20; count>0; count--) { s1=s1+EG1; s2=s2+EG2; s3=s3+EG3; pres=pres+PRESin; g_lcd.locate(0,0); g_lcd.printf("CAL 21%% %.2d %1.2f",count,pres/(20-count+1)); g_lcd.locate(0,1); g_lcd.printf("%1.2f: %1.2f: %1.2f",s1/(20-count+1),s2/(20-count+1),s3/(20-count+1)); wait(1); } //average s1=s1/20-coff1; s2=s2/20-coff2; s3=s3/20-coff3; // set calibration variables eg1cal=s1; eg2cal=s2; eg3cal=s3; pcal=pres/20/DRATIO; // surface pressure output voltage from sensor scrubtime=0; // reset the scrubber timer to zero. scrubold=0; // set stored scrub time to zero too. // 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...*/ store(); } // 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(7,0,33); // warning icon until 1 min up g_lcd.character(8,0,83); // surface icon - letter S } else { g_lcd.character(7,0,32); } if (state==1) g_lcd.character(8,0,83); // surface icon if (state==2 && iseven(seconds)==1) g_lcd.character(8,0,4); // diving icon - inverse D if (state==2 && iseven(seconds)==0) g_lcd.character(8,0,68); // diving icon - normal D */ // yes - this does nothing as all this is now done by vmessage } // warning and LED conditions void warning() { if (depth>=mod && flash==1) g_lcd.character(11,0,33); else g_lcd.character(11,0,32); // blank sapce } // pick maximum of two values float maximum(float a,float b,float c) { float maximum; if(a>b && a>c) maximum=a; if(b>a && b>c) maximum=b; if(c>a && c>b) maximum=c; return(maximum); } // pick minimum of three values float minimum(float a,float b,float c) { float minim; if (a<b && a < c) minim=a; if(b<a && b<c) minim=b; if(c<a && c <b) minim=c; return(minim); } // handset led control void leds() { // first turn everything off red=0; green=0; blue=0; float ppox,ppom,sp; int mo=0; //mo=MODE; if(setpoint==0) sp=lowsetpoint; else sp=highsetpoint; ppox=maximum(ppo1,ppo2,ppo3); // use max value to compute leds... ppom=minimum(ppo1,ppo2,ppo3); // unless we want minimum if (mo==0) { // CCR mode if (ppom<0.2 && flash==1) {red=1;} // flashing red means very bad things - getting very --low on oxygen!!! if (ppom>0.2 && ppox < (sp-0.15)) red=1; // non-flashing red if (ppox>=(sp-0.15) && ppox <(sp-0.5)) { red=1; // red-green green=1; } if (ppox<(sp+0.05) && ppox >=(sp-0.05)) green=1; // green - optimal range in ccr mode if (ppox<(sp+0.15) && ppox >=(sp+0.05)) { green=1; // green-blue - high ppo2 be careful of spiking blue=1; } if (ppox<1.6 && ppox>=(sp+0.15)) blue=1; // DANGER blue high ppo2 if (ppox>=1.6 && flash==1) blue=1; } /*if (mo==1) { // SCR mode if (ppom<0.2 && flash==1) red=1; if (ppom>=0.2 && ppox <0.26) red=1; // will give green red for low but not lethal ppo2s if (depth < 0.8*mod && ppom>0.2) green=1; if (depth< mod && depth >=0.8*mod) { green=1; blue=1; } if (depth >=mod && flash==1) blue=1; }*/ } //read battery state and insert the battery symbol void battery() { char cgchar[32]={ 6,9,9,9,9,9,9,15, // battery empty symbol 6,9,9,9,9,15,15,15, // battery 50% symbol 6,9,9,15,15,15,15,15, // battery 75% symbol 6,15,15,15,15,15,15,15, // battery 100% symbol }; int batsym=0,i=0; // battery < 3.85V // idea to build in 6 levels of battery indicator by on the fly reprogramming character 2 as required. Vb=0; for (i=0; i<4; i++) { Vb=Vb+Vbatt; // read adc connected to battery via a 1/3 potential divider wait(0.05); } Vb=Vb/4; // average 4 readings to reduce noise if (Vb>0.388) batsym=8; //3.85-3.92V if (Vb>0.395) batsym=16; // battery 3.92-4V if (Vb>0.404) batsym=24; // battery . >4V // write the appropriate battery symbol into the first custom character g_lcd.writeCommand(0x40); // set start address for CGRAM for (i=0; i<8; i++) { g_lcd.writeData(cgchar[i+batsym]); } g_lcd.character(11,1,0); // battery symbol if (batsym ==0 && flash==0) g_lcd.character(11,1,32); // bung in space if flashing } // sub to make the nice stop or no stop message work in locations 9,0 and 9,1 void vmessage() { int i,d,cpos=0; // "INITSURFDIVE" in vertical chas - 1 custom char per two symbols 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}; g_lcd.writeCommand(104); // set start address for CGRAM characrter #6 out of 8 for (i=0; i<16; i++) { // write 2 chars worth into this segment NO DECO g_lcd.writeData(mesg[i+state*16]); } // endfor g_lcd.character(12,0,5); // custom char 5 g_lcd.character(12,1,6); // custom char 6 } // 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() { int mo=0,tmp=0; //mo=MODE; g_lcd.character(3,1,32); //1st line //ppo1 if(ppo1<1) tmp=(int)(ppo1*100); else tmp=(int)(ppo1*100-100); g_lcd.locate(1,0); g_lcd.printf("%02d ",tmp); if(ppo1>=1) g_lcd.character(0,0,2); if(ppo1<1) g_lcd.character(0,0,1); if(ppo2<1) tmp=(int)(ppo2*100); else tmp=(int)(ppo2*100-100); g_lcd.locate(5,0); g_lcd.printf("%02d ",tmp); if(ppo2>=1) g_lcd.character(4,0,2); if(ppo2<1) g_lcd.character(4,0,1); if(ppo3<1) tmp=(int)(ppo3*100); else tmp=(int)(ppo3*100-100); g_lcd.locate(9,0); g_lcd.printf("%02d ",tmp); if(ppo3>=1) g_lcd.character(8,0,2); if(ppo3<1) g_lcd.character(8,0,1); g_lcd.locate(13,0); g_lcd.printf("%.2d",(int)depth); // depth g_lcd.locate(4,1); g_lcd.printf("%2dm",(int)mod); // mod //2nd line g_lcd.locate(0,1); tmp=minimum((float)fo1,(float)fo2,(float)fo3); // get min fraction of oxygen to display lowest for deco use g_lcd.printf("%2d%%",tmp); g_lcd.locate(13,1); g_lcd.printf("%03d",scrubtime % 1000); // modulo to avoid digits conflict - means divetime is always less than 100 g_lcd.locate(8,1); g_lcd.printf("%2d",(int)(divetime/60) % 100 ); // rolls back to zero if go over 99 // bung in battery icon battery(); status(); // this will set the diving / suface mode icon // warning(); // this will set the warning ic on assuming that max ppo2 is exceeded g_lcd.character(7,1,32); // space to cover any write error on top line leds(); // this sets the leds according to the various warning conditions /* if (mo==0) { g_lcd.character(7,1,99); //'c' = ccr } else { g_lcd.character(7,1,115); //'s' = scr }*/ // custom character setting to sort out dp in depths char cgchar[80]={ 7,5,5,5,23,0,0,0, // .0 2,2,2,2,18,0,0,0, // .1 7,1,7,4,23,0,0,0, // .2 7,1,3,1,23,0,0,0, // .3 5,5,7,1,17,0,0,0, //.4 7,4,7,1,23,0,0,0, //.5 7,4,7,5,23,0,0,0, //.6 7,1,2,2,18,0,0,0, //.7 7,5,7,5,23,0,0,0, //.8 7,5,7,1,17,0,0,0 //.9 }; // special dp digit for depth int i=0,d=0; d=(int)((depth-(int)depth)*10); // should be size of the 1st decimal place // do stuff here to set cstom chars g_lcd.writeCommand(120); // set start address for CGRAM for (i=0; i<8; i++) { g_lcd.writeData(cgchar[i+d*8]); } g_lcd.character(15,0,7); // put in appropriate custom character // display the current setpoint information if(setpoint==0) g_lcd.character(7,1,218); // letter down arrow for low setpoint if(setpoint==1) g_lcd.character(7,1,217); // Letter 'H' if(flash==1) g_lcd.character(7,1,115); // Letter ':' } // read sensors and generate calibrated outputs NB battery is read elsewhere void readsensors() { float barometric=0,mod1,mod2,mod3,temp,Vdepth=0,s1,s2,s3,MPXref=0; int tc=0; // ppo1=EG1*0.21/eg1cal; // eg1cal is 0.21bar ppO2 // ppo2=EG2*0.21/eg2cal; // second oxygen cell ppO2 // ppo3=EG3*0.21/eg3cal; s1=0; s2=0; s3=0; for(tc=0;tc<20;tc++) // noise on Vdepth so average readings to compensate { Vdepth=Vdepth+(PRESin/DRATIO); // read the depth sensor and calculate the real value rather using the dividing ratio wait_ms(10); // slows stuff down a bit but not a big problem s1=s1+EG1; // read o2 sensors s2=s2+EG2; s3=s3+EG3; MPXref=MPXref+V5V; // read 5V wait_ms(10); // slows stuff down a bit but not a big problem } Vdepth=Vdepth/20; // now have the average s1=s1/20-coff1; s2=s2/20-coff2; s3=s3/20-coff3; MPXref=MPXref/20*3.3*2; // should be 5V // compute ppO2s ppo1=s1*0.21/eg1cal; ppo2=s2*0.21/eg2cal; ppo3=s3*0.21/eg3cal; pc.printf("EG1=%f\tEG2=%f\tEG3=%f \tMPXref=%f \r",s1,s2,s3,MPXref); pressure=(Vdepth*3.3/MPXref-0.04)/0.0012858; // pressure in kpa NB - assums that the 5V is correct //pressure=(PRESin*3.3/0.65006-0.04)/(0.0012858); // pressure in kPa assuming standard cal for mpx5700 sensor SUSPECT // NB the mpx5700 runs off 5v so would be better to divide its output down by 3/5 to get full range measurement //outputs. with no division the max mbed adc of 3.3V coresponds to 480kpa or about 38m depth..... // standard spec on mpx5700 should be 5V*(P*0.0012858+0.04) // new sensor has 3/5 divider built into sensor wiring. //barometric=(pcal*3.3/0.65006-0.004)/(0.0012858); // sealevel in kPa assuming standard cal for mpx5700 sensor barometric=(pcal*3.3/MPXref-0.04)/0.0012858; // barometric pressure (kpa) evaluated from calibration which we assume is baseline depth=(pressure-barometric)*0.1; //100kPa=10m 1kPa=0.1m - this gives depth in m for freshwater. if (depth<0) depth=0; // deals wtih noise that may lead to small variation in values // THESE SHOULD BE JUST 100*ppox/(pressure/100); fo1=100*ppo1/((pressure-barometric)/100+1); // pressure in bar = pressure /100 and want a % so multiply by 100 as well fo2=100*ppo2/((pressure-barometric)/100+1); fo3=100*ppo3/((pressure-barometric)/100+1); // maybe these should be ppox/(depth/10+1)*100....? /*if (fo1<0) fo2=0; if (fo2<0) fo1=0; */ //with three sensors will calculate mod from the largest ppo2 reading mod1=(1.4/(fo1/100)-1)*10; mod2=(1.4/(fo2/100)-1)*10; mod3=(1.4/(fo3/100)-1)*10; mod=minimum(mod1,mod2,mod3); // pick the least value // output for debugging to pc via usb line. // pc.printf("VDepth %f\tPressure %f\tbarometric %f\tdepth %f\t \n\r",Vdepth,pressure,barometric,depth); //NB - problem - we really need to monitor the 5V power line to ensure that it's driving the depth sensor ok. // it may need thicker cables as it currently only manages 4.8V on the board when everything is running. } // get values back from cal file on local drive void recall() { FILE *fp=fopen("/local/CAL.dat","r"); fscanf(fp,"%e\n%e\n%e\n%e\n%d",&eg1cal,&eg2cal,&eg3cal,&pcal,&scrubold); fclose(fp); //NB file system locked on write so must make sure we close files in case want to reprogram etc... } // write the logfile opened and closed by start and end of dive void store_log() { //FILE *fp=fopen("/local/divelog.dat","a"); float v5=0; v5=V5V; 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); if (divetime % 60==0) fflush(lp); // fclose(fp); } // read switches and report state int switches() { int ss=0; if (SW1==1 && SW2==1) ss=3; if (SW2==1 && SW1==0) ss=2; if (SW1==1 && SW2==0) ss=1; return(ss); } // interpret the ppo2 data into a simple set of hud codes. int HUD_display() { int i,j3,h1,h2,h3; float cset=0; char gcode[6]={0,1,3,2,6,4}; // grey code for HUD reading 'red,amber,green,cyan,blue' HUD_clr(); // clear the HUID ready for write if(setpoint==0) // low setpoint { cset=lowsetpoint; } if(setpoint==1) // hgh setpoint { cset=highsetpoint; } h1=(int)((ppo1-cset)/0.1+3.5); if(h1<1) h1=1; if(h1>5) h1=5; h2=(int)((ppo2-cset)/0.1+3.5); if(h2<1) h2=1; if(h2>5) h2=5; h3=(int)((ppo3-cset)/0.1+3.5); if(h3<1) h3=1; if(h3>5) h3=5; if(h3>3) btest=0; // handle extra blue connected to btest setting btest low lights blue led i=gcode[h1]+8*gcode[h2]+64*gcode[h3]; // this is possible bigger than a char so have to typeconvert HUD_write(i); } // sub to flash HUD n times as a warning of setpoint shift int HUD_flash(int n) { int i; for(i=0;i<n;i++) { HUD_clr(); wait(0.2); HUD_white(); wait(0.05); } } int setswitch() { if(setpoint==0 && depth >(switchdepth+0.5)) { setpoint=1; // handle switch from low to high HUD_flash(4); // flash the hud here } if(setpoint==1 && depth < (switchdepth -0.5)) { setpoint=0; // swtich to low setpoint HUD_flash(2); // flash the HUD here } } 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; // minutes is elapsed minutes since start of prog int j=0,scount=1;; // general loop counting variable int sw=0; // status of the switches in the handset char schars[4]={32,0xd9,0xda,0xfb}; // up arrow, down arrow and both arrows; bool mdir=0; 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; wait(0.2); // get cal values last used from local drive recall(); // display the correct scrubber time scrubtime=scrubold; // hang about waiting for the cal switch to be pressed in ccase it is while (scount<30) { seconds=getseconds(); // NB if this hangs then nothing works :( - usually means 5V is dodgy red=1; green=1; blue=1; // light all leds g_lcd.locate(5,1); g_lcd.printf("%.2d ",30-scount); 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) { if(SW1==0) { calibrate(); scount=31; // make sure it goes to next frame ok } wait(0.05); j=(j+1) % 4; if(flash==0) HUD_white(); else HUD_clr(); scount++; } g_lcd.cls(); // ok there are three states in this system //MAIN LOOP ONCE STARTUP PROTOCOLS ARE COMPLETED j=0; g_lcd.cls(); while (1) { wait(0.1); //stop screen flicker readsensors(); setswitch(); // check the setpoint and adjust if crossing the swtich depth HUD_display(); // write the HUD codes seconds=getseconds(); minutes=(int)(((float)seconds-(float)startuptime)/60); led1=seconds % 2; // flash the onboard led to make it clear stuff is running if (j>1) flash=1; else flash=0; display(); // write the display HUD_display(); // write the HUD // sw=switches(); // read the switches and report their state // 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 // HERE do deco calcs - update tissues and compute desat , nostop or ascent times as required. // 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.8 && state==1) { state=2; // enter dive mode lp=fopen("/local/divelog.dat","a"); 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 store_log(); // make a first log entry to catch this erliest part of the dive if (startdive==0) startdive=seconds; // set start of divetime. don't do this twice endclock=0; // reset end of dive clock } // in dive mode - things to do, 1 update divetime and scrubber time, 2 write log data 3 check for end of dive... if (state==2) { // divetime=(int)(((float)seconds-(float)startdive)/60.0); // time since start of dive in minutes. divetime=(seconds-startdive); // divetime no recorded in seconds since start of dive // do deco calcs here when implemented if (divetime %15 ==0) store_log(); // this saves the dive profile data every 15s and sensor optputs in a file called divelog.dat if (depth<=0.5) { endclock=endclock+1; if (endclock>150) { state=1; // 30s at shallower than 0.5m and we return to surface mode. */ 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... store(); fclose(lp); } // endif endclock } // end if depth scrubtime=scrubold+(divetime/60); // } // end state 2 j=(j+1) %4; // flash control variable = used to make the warnings flash for 0.4s duty cycle vmessage(); // call to generate status message in vertical segment } // end while } //end main