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

Committer:
pegcjs
Date:
Fri Apr 12 10:16:53 2013 +0000
Revision:
9:71b8ac65b73a
Parent:
8:f45e654b47d0
Version driving HUD 9LED based) with full logging and using 0.7 and 1.2bar setpoints witha  10m switch depth. Tested in full on 5 dives in February 2013

Who changed what in which revision?

UserRevisionLine numberNew contents of line
pegcjs 1:9cff4feccbce 1 //lpc1124lcddemo
pegcjs 7:f93b7eaab5f6 2 // driver for mbed based ppo2 monitoring system for closed circuit rebreather
pegcjs 7:f93b7eaab5f6 3 // reading 3 electrogalvanic oxygen sensors and one pressure sensor
pegcjs 1:9cff4feccbce 4 #include "ds1307.h"
pegcjs 1:9cff4feccbce 5 #include "mbed.h"
pegcjs 5:35417986539a 6 #include "TextOLED.h"
pegcjs 1:9cff4feccbce 7
pegcjs 1:9cff4feccbce 8
pegcjs 7:f93b7eaab5f6 9 #define DRATIO 0.6420066 // ratio of voltage at pin20 to voltage actually generated by the sensor
pegcjs 7:f93b7eaab5f6 10
pegcjs 7:f93b7eaab5f6 11 //hud LINES
pegcjs 7:f93b7eaab5f6 12 DigitalOut AB(p7); //pins AB for data bits
pegcjs 7:f93b7eaab5f6 13 DigitalOut CP(p5); // clock to shift reg
pegcjs 7:f93b7eaab5f6 14 //DigitalOut MR(p8); // reset to shift reg (low for clear)#
pegcjs 7:f93b7eaab5f6 15 DigitalOut btest(p6); // pin to drive lastblue led
pegcjs 7:f93b7eaab5f6 16
pegcjs 7:f93b7eaab5f6 17 // offsets for lm324 amp in terms of reading values on adc
pegcjs 9:71b8ac65b73a 18 // these are calibrated fromthe actual amplifier circuit but effectively include the ADC offsets for the mbed
pegcjs 7:f93b7eaab5f6 19 #define coff1 -0.013375
pegcjs 7:f93b7eaab5f6 20 #define coff2 -0.00936
pegcjs 7:f93b7eaab5f6 21 #define coff3 -0.0212136
pegcjs 7:f93b7eaab5f6 22
pegcjs 7:f93b7eaab5f6 23
pegcjs 7:f93b7eaab5f6 24
pegcjs 7:f93b7eaab5f6 25 Serial pc(USBTX, USBRX); // tx, rx for debug and usb pc comunications
pegcjs 7:f93b7eaab5f6 26
pegcjs 1:9cff4feccbce 27
pegcjs 1:9cff4feccbce 28 //pin assignments and declarations
pegcjs 1:9cff4feccbce 29 // LCD display
pegcjs 1:9cff4feccbce 30 TextLCD g_lcd(p26, p25, p24, p23, p22, p21); // RS, E, DB4, DB5, DB6, DB7
pegcjs 1:9cff4feccbce 31 //backlight
pegcjs 1:9cff4feccbce 32 DigitalOut backlight(p29);
pegcjs 1:9cff4feccbce 33
pegcjs 1:9cff4feccbce 34 //onboard leds
pegcjs 1:9cff4feccbce 35 DigitalOut led1(LED1);
pegcjs 1:9cff4feccbce 36 DigitalOut led2(LED2);
pegcjs 1:9cff4feccbce 37
pegcjs 1:9cff4feccbce 38 // warning leds
pegcjs 1:9cff4feccbce 39 DigitalOut red(p34);
pegcjs 1:9cff4feccbce 40 DigitalOut green(p33);
pegcjs 1:9cff4feccbce 41 DigitalOut blue(p30);
pegcjs 1:9cff4feccbce 42
pegcjs 6:ab2d7d0a9b07 43
pegcjs 1:9cff4feccbce 44 // switches and buttons - these are pulled up by resistors so are active low
pegcjs 1:9cff4feccbce 45 DigitalIn CAL(p36);
pegcjs 5:35417986539a 46 DigitalIn SW1(p35); // reed switch in display unit
pegcjs 7:f93b7eaab5f6 47 DigitalIn SW2(p10); // reed switch in dispaly unit - NONE FUNCIONAL IN CURRENT HEAD - SWITCH FAILED DURING POTTING
pegcjs 7:f93b7eaab5f6 48 //DigitalIn MODE(p11);// a switchn on the mbed pcb to select between SCR and CCR modes for the LEDs NOT USED ANYMORE
pegcjs 1:9cff4feccbce 49
pegcjs 1:9cff4feccbce 50 // log data storage
pegcjs 1:9cff4feccbce 51 LocalFileSystem local("local");
pegcjs 1:9cff4feccbce 52
pegcjs 1:9cff4feccbce 53 // adc inputs for sensors
pegcjs 1:9cff4feccbce 54 AnalogIn PRESin(p20);
pegcjs 1:9cff4feccbce 55 AnalogIn EG1(p19);
pegcjs 1:9cff4feccbce 56 AnalogIn EG2(p18);
pegcjs 7:f93b7eaab5f6 57 AnalogIn EG3(p16);
pegcjs 7:f93b7eaab5f6 58 AnalogIn Vbatt(p17); // battery voltage divided down by 3
pegcjs 7:f93b7eaab5f6 59 AnalogIn V5V(p15); // sense the '5V' output from the max1724 unit - divided down by 2. Nominally 2.5V===0.757575757' in 3.3V ADC
pegcjs 7:f93b7eaab5f6 60
pegcjs 7:f93b7eaab5f6 61
pegcjs 1:9cff4feccbce 62
pegcjs 1:9cff4feccbce 63 // realtime clock
pegcjs 1:9cff4feccbce 64 DS1307 my1307(p28,p27); // start DS1307 class and give it pins for connections of the DS1307 device
pegcjs 1:9cff4feccbce 65
pegcjs 1:9cff4feccbce 66 // variables for realtime clock
pegcjs 1:9cff4feccbce 67 int sec = 0;
pegcjs 1:9cff4feccbce 68 int min = 0;
pegcjs 1:9cff4feccbce 69 int hours = 0;
pegcjs 1:9cff4feccbce 70 int day = 0;
pegcjs 1:9cff4feccbce 71 int date = 0;
pegcjs 1:9cff4feccbce 72 int month = 0;
pegcjs 1:9cff4feccbce 73 int year = 0;
pegcjs 4:74df6d31ee0a 74 int seconds=0; // general number of seconds since 2000 etc timestamp variable
pegcjs 1:9cff4feccbce 75
pegcjs 7:f93b7eaab5f6 76 int scrubtime=0,scrubold=0; // these are expressed in minutes
pegcjs 1:9cff4feccbce 77 int divetime=0;
pegcjs 1:9cff4feccbce 78
pegcjs 3:0d94a277aa8c 79 int flash=0; // variable used top control flashing icons
pegcjs 2:a1c26faa9103 80 int state=0; // IMPORTANT - VARIABLE THAT DRIVES HNTE STATE MACHINE STATE=0 = STARTUP, STATE=1=SURFACE STATE=2= DIVING
pegcjs 7:f93b7eaab5f6 81 float lowsetpoint=0.7,highsetpoint=1.2,switchdepth=10; // variables to determine HUD led states
pegcjs 7:f93b7eaab5f6 82 //switchdepth is centre of switch region 1m deep if switchdepth=10 then will go to high as descebnd
pegcjs 7:f93b7eaab5f6 83 //through 10.5 and go back to low when ascending through 9.5
pegcjs 7:f93b7eaab5f6 84 int setpoint=0; // 0=low 1 = high
pegcjs 2:a1c26faa9103 85
pegcjs 1:9cff4feccbce 86 // variables for the eg cells and pressure sensor eg1calamd eg2cal ar reading when the sensor is in 0.21bar O2 and
pegcjs 1:9cff4feccbce 87 //dcal is the reading whe the pressure sensor is at the surface
pegcjs 7:f93b7eaab5f6 88 float eg1cal=0.09,eg2cal=0.09,eg3cal=0.09,pcal=0.1136;
pegcjs 1:9cff4feccbce 89 // NB these are updated from /local/cal.dat so values not so important.... eventually
pegcjs 1:9cff4feccbce 90
pegcjs 7:f93b7eaab5f6 91 float depth=0,ppo1=0,ppo2=0,ppo3=0 ,Vb=0,pressure=0; // depth, 1st o2 sensor second o2 sensor battery voltage,,Pressure
pegcjs 7:f93b7eaab5f6 92 float fo1=0,fo2=0,fo3=0,mod=55; //%f values,mod
pegcjs 3:0d94a277aa8c 93
pegcjs 6:ab2d7d0a9b07 94 FILE *lp; // file pointer for log file
pegcjs 6:ab2d7d0a9b07 95
pegcjs 7:f93b7eaab5f6 96 bool nostop=1, deco=0; // variables to define state for deco
pegcjs 7:f93b7eaab5f6 97
pegcjs 7:f93b7eaab5f6 98
pegcjs 7:f93b7eaab5f6 99
pegcjs 7:f93b7eaab5f6 100 //HUD codes
pegcjs 7:f93b7eaab5f6 101 // make a HUD clock pulse
pegcjs 7:f93b7eaab5f6 102 int clk()
pegcjs 7:f93b7eaab5f6 103 {
pegcjs 7:f93b7eaab5f6 104 wait_us(1);
pegcjs 7:f93b7eaab5f6 105 CP=0;
pegcjs 7:f93b7eaab5f6 106 wait_us(1);
pegcjs 7:f93b7eaab5f6 107 CP=1;
pegcjs 7:f93b7eaab5f6 108 return(0);
pegcjs 7:f93b7eaab5f6 109 }
pegcjs 7:f93b7eaab5f6 110
pegcjs 7:f93b7eaab5f6 111 // write 8 bits to the HUD shift register
pegcjs 7:f93b7eaab5f6 112 int HUD_write(char d)
pegcjs 7:f93b7eaab5f6 113 {
pegcjs 7:f93b7eaab5f6 114 int i=0;
pegcjs 7:f93b7eaab5f6 115 for(i=7; i>=0; i--) {
pegcjs 7:f93b7eaab5f6 116 AB=d & (1 << i);
pegcjs 7:f93b7eaab5f6 117 AB=!AB;
pegcjs 7:f93b7eaab5f6 118 clk();
pegcjs 7:f93b7eaab5f6 119 }
pegcjs 7:f93b7eaab5f6 120 return(0);
pegcjs 7:f93b7eaab5f6 121 }
pegcjs 7:f93b7eaab5f6 122
pegcjs 7:f93b7eaab5f6 123 // make all HUD leds white - useful for warnings etc
pegcjs 7:f93b7eaab5f6 124 int HUD_white()
pegcjs 7:f93b7eaab5f6 125 {
pegcjs 7:f93b7eaab5f6 126 // set all white;
pegcjs 7:f93b7eaab5f6 127 HUD_write(255);
pegcjs 7:f93b7eaab5f6 128 btest=0;
pegcjs 7:f93b7eaab5f6 129
pegcjs 7:f93b7eaab5f6 130 return(0);
pegcjs 7:f93b7eaab5f6 131 }
pegcjs 7:f93b7eaab5f6 132 // clear the HUD - make al black
pegcjs 7:f93b7eaab5f6 133 int HUD_clr()
pegcjs 7:f93b7eaab5f6 134 {
pegcjs 7:f93b7eaab5f6 135 HUD_write(0);
pegcjs 7:f93b7eaab5f6 136 btest=1;
pegcjs 7:f93b7eaab5f6 137 return(0);
pegcjs 7:f93b7eaab5f6 138 }
pegcjs 7:f93b7eaab5f6 139
pegcjs 7:f93b7eaab5f6 140
pegcjs 7:f93b7eaab5f6 141
pegcjs 7:f93b7eaab5f6 142 // code to detect leap years
pegcjs 7:f93b7eaab5f6 143 int LeapYear(int year) {
pegcjs 7:f93b7eaab5f6 144 int leap=0;
pegcjs 7:f93b7eaab5f6 145
pegcjs 7:f93b7eaab5f6 146 if (year % 400==0) leap=1;
pegcjs 7:f93b7eaab5f6 147 else if (year %100 ==0) leap=0;
pegcjs 7:f93b7eaab5f6 148 else if (year % 4 ==0) leap=1;
pegcjs 7:f93b7eaab5f6 149 else leap=0;
pegcjs 7:f93b7eaab5f6 150 return(leap);
pegcjs 7:f93b7eaab5f6 151 }
pegcjs 7:f93b7eaab5f6 152
pegcjs 7:f93b7eaab5f6 153
pegcjs 1:9cff4feccbce 154 //===== sub to get time from ds1307 and create the 'seconds' which is a version of timestamp....
pegcjs 1:9cff4feccbce 155 int getseconds() {
pegcjs 7:f93b7eaab5f6 156 int leap=0,dayofyear=0,timestamp=0;
pegcjs 7:f93b7eaab5f6 157 int y=0,byear=0;
pegcjs 7:f93b7eaab5f6 158 int days[12]={0,31,59,90,120,151,181,212,243,273,304,334};
pegcjs 1:9cff4feccbce 159 my1307.gettime( &sec, &min, &hours, &day, &date, &month, &year);
pegcjs 1:9cff4feccbce 160 //simple timestamp = # seconds since midnight jan 1st 2000 if all months were 30 days.
pegcjs 7:f93b7eaab5f6 161 //int secondst=year*365*24*60*60+month*30*24*60*60+day*24*60*60+hours*60*60+min*60+sec;
pegcjs 1:9cff4feccbce 162 //simple timestamp = # seconds since midnight jan 1st 2000 if all months were 30 days....
pegcjs 1:9cff4feccbce 163 // ie wrong but simpler than the real thing
pegcjs 7:f93b7eaab5f6 164
pegcjs 7:f93b7eaab5f6 165
pegcjs 7:f93b7eaab5f6 166 // sort out ds1307 definiteion of year
pegcjs 7:f93b7eaab5f6 167 year=year+2000;
pegcjs 7:f93b7eaab5f6 168 leap=LeapYear(year);
pegcjs 7:f93b7eaab5f6 169
pegcjs 7:f93b7eaab5f6 170 // now decide dayofyear
pegcjs 7:f93b7eaab5f6 171 dayofyear=days[month-1]+date-1;
pegcjs 7:f93b7eaab5f6 172 if (leap==1 && month >2) dayofyear++; // deal with extra february day in leap year
pegcjs 7:f93b7eaab5f6 173
pegcjs 7:f93b7eaab5f6 174 // now find number of days since 1970
pegcjs 7:f93b7eaab5f6 175 for (y=1970; y<year; y++) {
pegcjs 7:f93b7eaab5f6 176 if (LeapYear(y) == 1) {
pegcjs 7:f93b7eaab5f6 177 byear += 366*24*60*60;
pegcjs 7:f93b7eaab5f6 178 } else {
pegcjs 7:f93b7eaab5f6 179 byear += 365*24*60*60;
pegcjs 7:f93b7eaab5f6 180 }
pegcjs 7:f93b7eaab5f6 181 }
pegcjs 7:f93b7eaab5f6 182
pegcjs 7:f93b7eaab5f6 183 // finally get the seconds right and construct timestamp in seconds since beginning of 1970
pegcjs 7:f93b7eaab5f6 184 timestamp=(byear)+dayofyear*24*3600+hours*3600+min*60+sec;
pegcjs 7:f93b7eaab5f6 185
pegcjs 7:f93b7eaab5f6 186 //DEBUG====================================
pegcjs 7:f93b7eaab5f6 187 // printf("secondst = %d\t timestamp = %d\t%.2d : %.2d : %d - %.2d:%.2d:%.2d\r",secondst,timestamp,date,month,year,hours,min,sec);
pegcjs 7:f93b7eaab5f6 188
pegcjs 7:f93b7eaab5f6 189 return(timestamp);
pegcjs 7:f93b7eaab5f6 190
pegcjs 1:9cff4feccbce 191 }
pegcjs 1:9cff4feccbce 192
pegcjs 1:9cff4feccbce 193
pegcjs 1:9cff4feccbce 194 void set_custom_char() {
pegcjs 1:9cff4feccbce 195 char cgchar[64]={
pegcjs 7:f93b7eaab5f6 196 6,9,9,9,9,9,9,15, // battery symbol 0 address 64 = 0x40
pegcjs 7:f93b7eaab5f6 197 28,20,20,20,20,20,29,0, // 0. symbol for ppo2 1 address 72 = 0x48
pegcjs 7:f93b7eaab5f6 198 8,24,8,8,8,8,29,0, // 1. symbol for ppo2 2 address 80 =0x50
pegcjs 7:f93b7eaab5f6 199 6,15,15,15,15,15,15,15, // unused 3 address 88 = 0x58
pegcjs 7:f93b7eaab5f6 200 31,19,21,21,21,21,19,31, // unused 4 address 96 = 0x60
pegcjs 7:f93b7eaab5f6 201 6,6,6,6,6,0,0,6, // top char Vmessg 5 address 104 =0x68 - used for Vmessage
pegcjs 7:f93b7eaab5f6 202 31,17,23,17,29,17,31,0, // bottom char Vmessg 6 address 112 =0x70 -used for Vmessg
pegcjs 7:f93b7eaab5f6 203 2,6,2,2,2,2,23 // for dec point in depth 7 address 120 =0x78
pegcjs 1:9cff4feccbce 204 };
pegcjs 1:9cff4feccbce 205 int i=0;
pegcjs 1:9cff4feccbce 206 // do stuff here to set cstom chars
pegcjs 1:9cff4feccbce 207 g_lcd.writeCommand(0x40); // set start address for CGRAM
pegcjs 1:9cff4feccbce 208 for (i=0; i<64; i++) {
pegcjs 1:9cff4feccbce 209 g_lcd.writeData(cgchar[i]);
pegcjs 1:9cff4feccbce 210 }
pegcjs 1:9cff4feccbce 211
pegcjs 1:9cff4feccbce 212 }
pegcjs 1:9cff4feccbce 213
pegcjs 6:ab2d7d0a9b07 214 // stash cal values on local drive
pegcjs 6:ab2d7d0a9b07 215 void store() {
pegcjs 7:f93b7eaab5f6 216 int timestamp=0;
pegcjs 7:f93b7eaab5f6 217 timestamp=getseconds();
pegcjs 7:f93b7eaab5f6 218 wait(0.1);
pegcjs 6:ab2d7d0a9b07 219 FILE *fp=fopen("/local/CAL.dat","w");
pegcjs 7:f93b7eaab5f6 220 fprintf(fp,"%e\n%e\n%e\n%e\n%d\n%d\n",eg1cal,eg2cal,eg3cal,pcal,scrubtime,timestamp);
pegcjs 7:f93b7eaab5f6 221
pegcjs 6:ab2d7d0a9b07 222 fclose(fp); //NB file system locked on write so must make sure we close files in case want to reprogram etc...
pegcjs 7:f93b7eaab5f6 223 wait(0.1);
pegcjs 6:ab2d7d0a9b07 224 }
pegcjs 6:ab2d7d0a9b07 225
pegcjs 1:9cff4feccbce 226
pegcjs 1:9cff4feccbce 227 // subroutine to calibreate o2 sesnors and store ca data in /local/CAL.dat
pegcjs 1:9cff4feccbce 228 void calibrate() {
pegcjs 1:9cff4feccbce 229 int count=1;
pegcjs 7:f93b7eaab5f6 230 float s1=0,s2=0,s3=0,pres=0;
pegcjs 1:9cff4feccbce 231 // average 20 readings for noise reduction
pegcjs 1:9cff4feccbce 232 g_lcd.cls();
pegcjs 1:9cff4feccbce 233 for (count=20; count>0; count--) {
pegcjs 7:f93b7eaab5f6 234 s1=s1+EG1;
pegcjs 7:f93b7eaab5f6 235 s2=s2+EG2;
pegcjs 7:f93b7eaab5f6 236 s3=s3+EG3;
pegcjs 1:9cff4feccbce 237 pres=pres+PRESin;
pegcjs 9:71b8ac65b73a 238 g_lcd.locate(0,0);
pegcjs 9:71b8ac65b73a 239 g_lcd.printf("CAL 21%% %.2d %1.2f",count,pres/(20-count+1));
pegcjs 9:71b8ac65b73a 240
pegcjs 1:9cff4feccbce 241 g_lcd.locate(0,1);
pegcjs 7:f93b7eaab5f6 242 g_lcd.printf("%1.2f: %1.2f: %1.2f",s1/(20-count+1),s2/(20-count+1),s3/(20-count+1));
pegcjs 1:9cff4feccbce 243 wait(1);
pegcjs 1:9cff4feccbce 244 }
pegcjs 1:9cff4feccbce 245 //average
pegcjs 7:f93b7eaab5f6 246 s1=s1/20-coff1;
pegcjs 7:f93b7eaab5f6 247 s2=s2/20-coff2;
pegcjs 7:f93b7eaab5f6 248 s3=s3/20-coff3;
pegcjs 1:9cff4feccbce 249 // set calibration variables
pegcjs 7:f93b7eaab5f6 250 eg1cal=s1;
pegcjs 7:f93b7eaab5f6 251 eg2cal=s2;
pegcjs 7:f93b7eaab5f6 252 eg3cal=s3;
pegcjs 7:f93b7eaab5f6 253 pcal=pres/20/DRATIO; // surface pressure output voltage from sensor
pegcjs 1:9cff4feccbce 254 scrubtime=0; // reset the scrubber timer to zero.
pegcjs 7:f93b7eaab5f6 255 scrubold=0; // set stored scrub time to zero too.
pegcjs 2:a1c26faa9103 256 // write cal data NB overwites previous
pegcjs 6:ab2d7d0a9b07 257 /* FILE *fp=fopen("/local/CAL.dat","w");
pegcjs 6:ab2d7d0a9b07 258 fprintf(fp,"%e\n%e\n%e\n%d",eg1cal,eg2cal,pcal,scrubtime);
pegcjs 6:ab2d7d0a9b07 259 fclose(fp); //NB file system locked on write so must make sure we close files in case want to reprogram etc...*/
pegcjs 6:ab2d7d0a9b07 260 store();
pegcjs 1:9cff4feccbce 261 }
pegcjs 1:9cff4feccbce 262
pegcjs 4:74df6d31ee0a 263 // sub to test if a variable is an even number
pegcjs 4:74df6d31ee0a 264 int iseven(int g) {
pegcjs 4:74df6d31ee0a 265 int test=0;
pegcjs 5:35417986539a 266 if (g%2 ==0) test=1;
pegcjs 4:74df6d31ee0a 267 return(test);
pegcjs 4:74df6d31ee0a 268 }
pegcjs 4:74df6d31ee0a 269
pegcjs 1:9cff4feccbce 270
pegcjs 2:a1c26faa9103 271 void status() {
pegcjs 7:f93b7eaab5f6 272 /* if (state==0) {
pegcjs 7:f93b7eaab5f6 273 g_lcd.character(7,0,33); // warning icon until 1 min up
pegcjs 7:f93b7eaab5f6 274 g_lcd.character(8,0,83); // surface icon - letter S
pegcjs 5:35417986539a 275 } else {
pegcjs 7:f93b7eaab5f6 276 g_lcd.character(7,0,32);
pegcjs 3:0d94a277aa8c 277 }
pegcjs 7:f93b7eaab5f6 278 if (state==1) g_lcd.character(8,0,83); // surface icon
pegcjs 7:f93b7eaab5f6 279 if (state==2 && iseven(seconds)==1) g_lcd.character(8,0,4); // diving icon - inverse D
pegcjs 7:f93b7eaab5f6 280 if (state==2 && iseven(seconds)==0) g_lcd.character(8,0,68); // diving icon - normal D
pegcjs 7:f93b7eaab5f6 281 */
pegcjs 7:f93b7eaab5f6 282 // yes - this does nothing as all this is now done by vmessage
pegcjs 4:74df6d31ee0a 283 }
pegcjs 3:0d94a277aa8c 284
pegcjs 3:0d94a277aa8c 285 // warning and LED conditions
pegcjs 2:a1c26faa9103 286
pegcjs 2:a1c26faa9103 287 void warning() {
pegcjs 7:f93b7eaab5f6 288 if (depth>=mod && flash==1) g_lcd.character(11,0,33);
pegcjs 7:f93b7eaab5f6 289 else g_lcd.character(11,0,32); // blank sapce
pegcjs 2:a1c26faa9103 290
pegcjs 2:a1c26faa9103 291 }
pegcjs 2:a1c26faa9103 292
pegcjs 4:74df6d31ee0a 293 // pick maximum of two values
pegcjs 7:f93b7eaab5f6 294 float maximum(float a,float b,float c) {
pegcjs 4:74df6d31ee0a 295 float maximum;
pegcjs 7:f93b7eaab5f6 296 if(a>b && a>c) maximum=a;
pegcjs 7:f93b7eaab5f6 297 if(b>a && b>c) maximum=b;
pegcjs 7:f93b7eaab5f6 298 if(c>a && c>b) maximum=c;
pegcjs 4:74df6d31ee0a 299 return(maximum);
pegcjs 4:74df6d31ee0a 300 }
pegcjs 4:74df6d31ee0a 301
pegcjs 7:f93b7eaab5f6 302 // pick minimum of three values
pegcjs 7:f93b7eaab5f6 303 float minimum(float a,float b,float c) {
pegcjs 4:74df6d31ee0a 304 float minim;
pegcjs 7:f93b7eaab5f6 305 if (a<b && a < c) minim=a;
pegcjs 7:f93b7eaab5f6 306 if(b<a && b<c) minim=b;
pegcjs 7:f93b7eaab5f6 307 if(c<a && c <b) minim=c;
pegcjs 7:f93b7eaab5f6 308
pegcjs 4:74df6d31ee0a 309 return(minim);
pegcjs 4:74df6d31ee0a 310 }
pegcjs 4:74df6d31ee0a 311
pegcjs 4:74df6d31ee0a 312
pegcjs 7:f93b7eaab5f6 313 // handset led control
pegcjs 2:a1c26faa9103 314 void leds() {
pegcjs 4:74df6d31ee0a 315 // first turn everything off
pegcjs 5:35417986539a 316 red=0;
pegcjs 5:35417986539a 317 green=0;
pegcjs 5:35417986539a 318 blue=0;
pegcjs 7:f93b7eaab5f6 319 float ppox,ppom,sp;
pegcjs 5:35417986539a 320 int mo=0;
pegcjs 7:f93b7eaab5f6 321 //mo=MODE;
pegcjs 7:f93b7eaab5f6 322 if(setpoint==0) sp=lowsetpoint;
pegcjs 7:f93b7eaab5f6 323 else sp=highsetpoint;
pegcjs 7:f93b7eaab5f6 324 ppox=maximum(ppo1,ppo2,ppo3); // use max value to compute leds...
pegcjs 7:f93b7eaab5f6 325 ppom=minimum(ppo1,ppo2,ppo3); // unless we want minimum
pegcjs 5:35417986539a 326 if (mo==0) { // CCR mode
pegcjs 7:f93b7eaab5f6 327 if (ppom<0.2 && flash==1) {red=1;} // flashing red means very bad things - getting very --low on oxygen!!!
pegcjs 7:f93b7eaab5f6 328 if (ppom>0.2 && ppox < (sp-0.15)) red=1; // non-flashing red
pegcjs 7:f93b7eaab5f6 329 if (ppox>=(sp-0.15) && ppox <(sp-0.5)) {
pegcjs 5:35417986539a 330 red=1; // red-green
pegcjs 5:35417986539a 331 green=1;
pegcjs 5:35417986539a 332 }
pegcjs 7:f93b7eaab5f6 333 if (ppox<(sp+0.05) && ppox >=(sp-0.05)) green=1; // green - optimal range in ccr mode
pegcjs 7:f93b7eaab5f6 334 if (ppox<(sp+0.15) && ppox >=(sp+0.05)) {
pegcjs 5:35417986539a 335 green=1; // green-blue - high ppo2 be careful of spiking
pegcjs 5:35417986539a 336 blue=1;
pegcjs 5:35417986539a 337 }
pegcjs 7:f93b7eaab5f6 338 if (ppox<1.6 && ppox>=(sp+0.15)) blue=1; // DANGER blue high ppo2
pegcjs 7:f93b7eaab5f6 339 if (ppox>=1.6 && flash==1) blue=1;
pegcjs 5:35417986539a 340 }
pegcjs 7:f93b7eaab5f6 341 /*if (mo==1) { // SCR mode
pegcjs 7:f93b7eaab5f6 342 if (ppom<0.2 && flash==1) red=1;
pegcjs 7:f93b7eaab5f6 343 if (ppom>=0.2 && ppox <0.26) red=1; // will give green red for low but not lethal ppo2s
pegcjs 7:f93b7eaab5f6 344 if (depth < 0.8*mod && ppom>0.2) green=1;
pegcjs 5:35417986539a 345 if (depth< mod && depth >=0.8*mod) {
pegcjs 5:35417986539a 346 green=1;
pegcjs 5:35417986539a 347 blue=1;
pegcjs 5:35417986539a 348 }
pegcjs 5:35417986539a 349 if (depth >=mod && flash==1) blue=1;
pegcjs 7:f93b7eaab5f6 350 }*/
pegcjs 6:ab2d7d0a9b07 351
pegcjs 1:9cff4feccbce 352 }
pegcjs 1:9cff4feccbce 353
pegcjs 4:74df6d31ee0a 354
pegcjs 4:74df6d31ee0a 355
pegcjs 1:9cff4feccbce 356 //read battery state and insert the battery symbol
pegcjs 9:71b8ac65b73a 357 //RE-WRITE THIS TO USE THE 5 EMPTY PIXELS INSIDE THE BATTERY OUTLINE TO REPRESENT 50Mv INCREMENTS ON 3.5V
pegcjs 1:9cff4feccbce 358 void battery() {
pegcjs 7:f93b7eaab5f6 359 char cgchar[32]={
pegcjs 7:f93b7eaab5f6 360 6,9,9,9,9,9,9,15, // battery empty symbol
pegcjs 7:f93b7eaab5f6 361 6,9,9,9,9,15,15,15, // battery 50% symbol
pegcjs 7:f93b7eaab5f6 362 6,9,9,15,15,15,15,15, // battery 75% symbol
pegcjs 7:f93b7eaab5f6 363 6,15,15,15,15,15,15,15, // battery 100% symbol
pegcjs 7:f93b7eaab5f6 364 };
pegcjs 7:f93b7eaab5f6 365
pegcjs 7:f93b7eaab5f6 366
pegcjs 9:71b8ac65b73a 367 int batsym=0,i=0,bstate=0,row=0; // bstate =(Vbattery-3.5V)/0.05;
pegcjs 7:f93b7eaab5f6 368
pegcjs 7:f93b7eaab5f6 369
pegcjs 7:f93b7eaab5f6 370 // idea to build in 6 levels of battery indicator by on the fly reprogramming character 2 as required.
pegcjs 7:f93b7eaab5f6 371 Vb=0;
pegcjs 9:71b8ac65b73a 372 for (i=0; i<20; i++) {
pegcjs 7:f93b7eaab5f6 373 Vb=Vb+Vbatt; // read adc connected to battery via a 1/3 potential divider
pegcjs 7:f93b7eaab5f6 374 wait(0.05);
pegcjs 7:f93b7eaab5f6 375 }
pegcjs 9:71b8ac65b73a 376 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.
pegcjs 7:f93b7eaab5f6 377
pegcjs 9:71b8ac65b73a 378 bstate=floor((Vb-3.5)/0.05);
pegcjs 9:71b8ac65b73a 379 if(bstate > 9) bstate=9;
pegcjs 9:71b8ac65b73a 380 if(bstate <0) bstate=0;
pegcjs 9:71b8ac65b73a 381
pegcjs 9:71b8ac65b73a 382 // fill up batery symbol according to bstate
pegcjs 9:71b8ac65b73a 383 for(i=0;i<10;i++)
pegcjs 9:71b8ac65b73a 384 {
pegcjs 9:71b8ac65b73a 385 // find row to enter
pegcjs 9:71b8ac65b73a 386 row=6-floor((float)i/2);
pegcjs 9:71b8ac65b73a 387 if(bstate >=i)
pegcjs 9:71b8ac65b73a 388 {
pegcjs 9:71b8ac65b73a 389 if(iseven(i)==1) cgchar[row]=cgchar[row]+4;
pegcjs 9:71b8ac65b73a 390 else cgchar[row]=cgchar[row]+2;
pegcjs 9:71b8ac65b73a 391 }
pegcjs 9:71b8ac65b73a 392
pegcjs 9:71b8ac65b73a 393 }
pegcjs 9:71b8ac65b73a 394
pegcjs 9:71b8ac65b73a 395 /*
pegcjs 7:f93b7eaab5f6 396 if (Vb>0.388) batsym=8; //3.85-3.92V
pegcjs 7:f93b7eaab5f6 397 if (Vb>0.395) batsym=16; // battery 3.92-4V
pegcjs 7:f93b7eaab5f6 398 if (Vb>0.404) batsym=24; // battery . >4V
pegcjs 9:71b8ac65b73a 399 */
pegcjs 7:f93b7eaab5f6 400
pegcjs 7:f93b7eaab5f6 401
pegcjs 7:f93b7eaab5f6 402 // write the appropriate battery symbol into the first custom character
pegcjs 7:f93b7eaab5f6 403 g_lcd.writeCommand(0x40); // set start address for CGRAM
pegcjs 7:f93b7eaab5f6 404 for (i=0; i<8; i++) {
pegcjs 9:71b8ac65b73a 405 g_lcd.writeData(cgchar[i]);
pegcjs 7:f93b7eaab5f6 406 }
pegcjs 7:f93b7eaab5f6 407
pegcjs 7:f93b7eaab5f6 408 g_lcd.character(11,1,0); // battery symbol
pegcjs 9:71b8ac65b73a 409 if (bstate <2 && flash==0) g_lcd.character(11,1,32); // bung in space if flashing
pegcjs 7:f93b7eaab5f6 410
pegcjs 7:f93b7eaab5f6 411
pegcjs 1:9cff4feccbce 412 }
pegcjs 1:9cff4feccbce 413
pegcjs 9:71b8ac65b73a 414 // sub to make the nice status message work in locations 9,0 and 9,1
pegcjs 7:f93b7eaab5f6 415 void vmessage() {
pegcjs 7:f93b7eaab5f6 416 int i,d,cpos=0;
pegcjs 7:f93b7eaab5f6 417 // "INITSURFDIVE" in vertical chas - 1 custom char per two symbols
pegcjs 7:f93b7eaab5f6 418 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};
pegcjs 7:f93b7eaab5f6 419
pegcjs 7:f93b7eaab5f6 420
pegcjs 7:f93b7eaab5f6 421
pegcjs 7:f93b7eaab5f6 422 g_lcd.writeCommand(104); // set start address for CGRAM characrter #6 out of 8
pegcjs 7:f93b7eaab5f6 423
pegcjs 7:f93b7eaab5f6 424 for (i=0; i<16; i++) { // write 2 chars worth into this segment NO DECO
pegcjs 7:f93b7eaab5f6 425
pegcjs 7:f93b7eaab5f6 426
pegcjs 7:f93b7eaab5f6 427 g_lcd.writeData(mesg[i+state*16]);
pegcjs 7:f93b7eaab5f6 428 } // endfor
pegcjs 7:f93b7eaab5f6 429
pegcjs 7:f93b7eaab5f6 430
pegcjs 7:f93b7eaab5f6 431
pegcjs 7:f93b7eaab5f6 432 g_lcd.character(12,0,5); // custom char 5
pegcjs 7:f93b7eaab5f6 433
pegcjs 7:f93b7eaab5f6 434 g_lcd.character(12,1,6); // custom char 6
pegcjs 7:f93b7eaab5f6 435
pegcjs 7:f93b7eaab5f6 436 }
pegcjs 7:f93b7eaab5f6 437
pegcjs 7:f93b7eaab5f6 438
pegcjs 2:a1c26faa9103 439 // subroutine to write the main display data
pegcjs 2:a1c26faa9103 440 //0123456789abcdef
pegcjs 2:a1c26faa9103 441
pegcjs 2:a1c26faa9103 442 //x.xx:xx D XX xx
pegcjs 2:a1c26faa9103 443 //x.xx:xx B XX xxx NB the warning, staus and battery icons are driven by separate subroutines.
pegcjs 2:a1c26faa9103 444 void display() {
pegcjs 7:f93b7eaab5f6 445 int mo=0,tmp=0;
pegcjs 7:f93b7eaab5f6 446 //mo=MODE;
pegcjs 7:f93b7eaab5f6 447 g_lcd.character(3,1,32);
pegcjs 2:a1c26faa9103 448 //1st line
pegcjs 7:f93b7eaab5f6 449
pegcjs 7:f93b7eaab5f6 450 //ppo1
pegcjs 7:f93b7eaab5f6 451 if(ppo1<1) tmp=(int)(ppo1*100); else tmp=(int)(ppo1*100-100);
pegcjs 7:f93b7eaab5f6 452 g_lcd.locate(1,0);
pegcjs 7:f93b7eaab5f6 453 g_lcd.printf("%02d ",tmp);
pegcjs 7:f93b7eaab5f6 454 if(ppo1>=1) g_lcd.character(0,0,2);
pegcjs 7:f93b7eaab5f6 455 if(ppo1<1) g_lcd.character(0,0,1);
pegcjs 7:f93b7eaab5f6 456
pegcjs 7:f93b7eaab5f6 457 if(ppo2<1) tmp=(int)(ppo2*100); else tmp=(int)(ppo2*100-100);
pegcjs 7:f93b7eaab5f6 458 g_lcd.locate(5,0);
pegcjs 7:f93b7eaab5f6 459 g_lcd.printf("%02d ",tmp);
pegcjs 7:f93b7eaab5f6 460 if(ppo2>=1) g_lcd.character(4,0,2);
pegcjs 7:f93b7eaab5f6 461 if(ppo2<1) g_lcd.character(4,0,1);
pegcjs 7:f93b7eaab5f6 462
pegcjs 7:f93b7eaab5f6 463 if(ppo3<1) tmp=(int)(ppo3*100); else tmp=(int)(ppo3*100-100);
pegcjs 7:f93b7eaab5f6 464 g_lcd.locate(9,0);
pegcjs 7:f93b7eaab5f6 465 g_lcd.printf("%02d ",tmp);
pegcjs 7:f93b7eaab5f6 466 if(ppo3>=1) g_lcd.character(8,0,2);
pegcjs 7:f93b7eaab5f6 467 if(ppo3<1) g_lcd.character(8,0,1);
pegcjs 7:f93b7eaab5f6 468
pegcjs 7:f93b7eaab5f6 469 g_lcd.locate(13,0);
pegcjs 7:f93b7eaab5f6 470 g_lcd.printf("%.2d",(int)depth); // depth
pegcjs 7:f93b7eaab5f6 471 g_lcd.locate(4,1);
pegcjs 7:f93b7eaab5f6 472 g_lcd.printf("%2dm",(int)mod); // mod
pegcjs 2:a1c26faa9103 473 //2nd line
pegcjs 2:a1c26faa9103 474 g_lcd.locate(0,1);
pegcjs 7:f93b7eaab5f6 475 tmp=minimum((float)fo1,(float)fo2,(float)fo3); // get min fraction of oxygen to display lowest for deco use
pegcjs 7:f93b7eaab5f6 476 g_lcd.printf("%2d%%",tmp);
pegcjs 7:f93b7eaab5f6 477 g_lcd.locate(13,1);
pegcjs 7:f93b7eaab5f6 478 g_lcd.printf("%03d",scrubtime % 1000); // modulo to avoid digits conflict - means divetime is always less than 100
pegcjs 7:f93b7eaab5f6 479 g_lcd.locate(8,1);
pegcjs 7:f93b7eaab5f6 480 g_lcd.printf("%2d",(int)(divetime/60) % 100 ); // rolls back to zero if go over 99
pegcjs 2:a1c26faa9103 481 // bung in battery icon
pegcjs 2:a1c26faa9103 482 battery();
pegcjs 5:35417986539a 483 status(); // this will set the diving / suface mode icon
pegcjs 7:f93b7eaab5f6 484 // warning(); // this will set the warning ic on assuming that max ppo2 is exceeded
pegcjs 7:f93b7eaab5f6 485 g_lcd.character(7,1,32); // space to cover any write error on top line
pegcjs 2:a1c26faa9103 486 leds(); // this sets the leds according to the various warning conditions
pegcjs 7:f93b7eaab5f6 487 /* if (mo==0) {
pegcjs 5:35417986539a 488 g_lcd.character(7,1,99); //'c' = ccr
pegcjs 5:35417986539a 489 } else {
pegcjs 5:35417986539a 490 g_lcd.character(7,1,115); //'s' = scr
pegcjs 7:f93b7eaab5f6 491 }*/
pegcjs 5:35417986539a 492 // custom character setting to sort out dp in depths
pegcjs 6:ab2d7d0a9b07 493
pegcjs 6:ab2d7d0a9b07 494
pegcjs 5:35417986539a 495 char cgchar[80]={
pegcjs 5:35417986539a 496 7,5,5,5,23,0,0,0, // .0
pegcjs 5:35417986539a 497 2,2,2,2,18,0,0,0, // .1
pegcjs 7:f93b7eaab5f6 498 7,1,7,4,23,0,0,0, // .2
pegcjs 7:f93b7eaab5f6 499 7,1,3,1,23,0,0,0, // .3
pegcjs 7:f93b7eaab5f6 500 5,5,7,1,17,0,0,0, //.4
pegcjs 7:f93b7eaab5f6 501 7,4,7,1,23,0,0,0, //.5
pegcjs 7:f93b7eaab5f6 502 7,4,7,5,23,0,0,0, //.6
pegcjs 5:35417986539a 503 7,1,2,2,18,0,0,0, //.7
pegcjs 5:35417986539a 504 7,5,7,5,23,0,0,0, //.8
pegcjs 5:35417986539a 505 7,5,7,1,17,0,0,0 //.9
pegcjs 5:35417986539a 506
pegcjs 5:35417986539a 507 };
pegcjs 7:f93b7eaab5f6 508 // special dp digit for depth
pegcjs 5:35417986539a 509 int i=0,d=0;
pegcjs 5:35417986539a 510 d=(int)((depth-(int)depth)*10); // should be size of the 1st decimal place
pegcjs 5:35417986539a 511 // do stuff here to set cstom chars
pegcjs 5:35417986539a 512 g_lcd.writeCommand(120); // set start address for CGRAM
pegcjs 5:35417986539a 513 for (i=0; i<8; i++) {
pegcjs 5:35417986539a 514 g_lcd.writeData(cgchar[i+d*8]);
pegcjs 5:35417986539a 515 }
pegcjs 5:35417986539a 516
pegcjs 7:f93b7eaab5f6 517 g_lcd.character(15,0,7); // put in appropriate custom character
pegcjs 7:f93b7eaab5f6 518
pegcjs 7:f93b7eaab5f6 519 // display the current setpoint information
pegcjs 7:f93b7eaab5f6 520 if(setpoint==0) g_lcd.character(7,1,218); // letter down arrow for low setpoint
pegcjs 7:f93b7eaab5f6 521 if(setpoint==1) g_lcd.character(7,1,217); // Letter 'H'
pegcjs 7:f93b7eaab5f6 522 if(flash==1) g_lcd.character(7,1,115); // Letter ':'
pegcjs 2:a1c26faa9103 523
pegcjs 2:a1c26faa9103 524 }
pegcjs 2:a1c26faa9103 525
pegcjs 2:a1c26faa9103 526
pegcjs 2:a1c26faa9103 527
pegcjs 1:9cff4feccbce 528
pegcjs 7:f93b7eaab5f6 529 // read sensors and generate calibrated outputs NB battery is read elsewhere
pegcjs 2:a1c26faa9103 530
pegcjs 1:9cff4feccbce 531 void readsensors() {
pegcjs 7:f93b7eaab5f6 532 float barometric=0,mod1,mod2,mod3,temp,Vdepth=0,s1,s2,s3,MPXref=0;
pegcjs 7:f93b7eaab5f6 533 int tc=0;
pegcjs 7:f93b7eaab5f6 534 // ppo1=EG1*0.21/eg1cal; // eg1cal is 0.21bar ppO2
pegcjs 7:f93b7eaab5f6 535 // ppo2=EG2*0.21/eg2cal; // second oxygen cell ppO2
pegcjs 7:f93b7eaab5f6 536 // ppo3=EG3*0.21/eg3cal;
pegcjs 7:f93b7eaab5f6 537
pegcjs 7:f93b7eaab5f6 538 s1=0;
pegcjs 7:f93b7eaab5f6 539 s2=0;
pegcjs 7:f93b7eaab5f6 540 s3=0;
pegcjs 7:f93b7eaab5f6 541 for(tc=0;tc<20;tc++) // noise on Vdepth so average readings to compensate
pegcjs 7:f93b7eaab5f6 542 {
pegcjs 7:f93b7eaab5f6 543 Vdepth=Vdepth+(PRESin/DRATIO); // read the depth sensor and calculate the real value rather using the dividing ratio
pegcjs 7:f93b7eaab5f6 544 wait_ms(10); // slows stuff down a bit but not a big problem
pegcjs 7:f93b7eaab5f6 545 s1=s1+EG1; // read o2 sensors
pegcjs 7:f93b7eaab5f6 546 s2=s2+EG2;
pegcjs 7:f93b7eaab5f6 547 s3=s3+EG3;
pegcjs 9:71b8ac65b73a 548 MPXref=MPXref+V5V; // read 5V reference
pegcjs 7:f93b7eaab5f6 549 wait_ms(10); // slows stuff down a bit but not a big problem
pegcjs 7:f93b7eaab5f6 550 }
pegcjs 7:f93b7eaab5f6 551 Vdepth=Vdepth/20; // now have the average
pegcjs 7:f93b7eaab5f6 552 s1=s1/20-coff1;
pegcjs 7:f93b7eaab5f6 553 s2=s2/20-coff2;
pegcjs 7:f93b7eaab5f6 554 s3=s3/20-coff3;
pegcjs 9:71b8ac65b73a 555 MPXref=MPXref/20*3.3*2; // should be 5V but may not be.....
pegcjs 6:ab2d7d0a9b07 556
pegcjs 7:f93b7eaab5f6 557
pegcjs 7:f93b7eaab5f6 558 // compute ppO2s
pegcjs 7:f93b7eaab5f6 559 ppo1=s1*0.21/eg1cal;
pegcjs 7:f93b7eaab5f6 560 ppo2=s2*0.21/eg2cal;
pegcjs 7:f93b7eaab5f6 561 ppo3=s3*0.21/eg3cal;
pegcjs 7:f93b7eaab5f6 562
pegcjs 7:f93b7eaab5f6 563 pc.printf("EG1=%f\tEG2=%f\tEG3=%f \tMPXref=%f \r",s1,s2,s3,MPXref);
pegcjs 7:f93b7eaab5f6 564 pressure=(Vdepth*3.3/MPXref-0.04)/0.0012858; // pressure in kpa NB - assums that the 5V is correct
pegcjs 7:f93b7eaab5f6 565 //pressure=(PRESin*3.3/0.65006-0.04)/(0.0012858); // pressure in kPa assuming standard cal for mpx5700 sensor SUSPECT
pegcjs 7:f93b7eaab5f6 566 // NB the mpx5700 runs off 5v so would be better to divide its output down by 3/5 to get full range measurement
pegcjs 7:f93b7eaab5f6 567 //outputs. with no division the max mbed adc of 3.3V coresponds to 480kpa or about 38m depth.....
pegcjs 7:f93b7eaab5f6 568 // standard spec on mpx5700 should be 5V*(P*0.0012858+0.04)
pegcjs 7:f93b7eaab5f6 569 // new sensor has 3/5 divider built into sensor wiring.
pegcjs 7:f93b7eaab5f6 570 //barometric=(pcal*3.3/0.65006-0.004)/(0.0012858); // sealevel in kPa assuming standard cal for mpx5700 sensor
pegcjs 7:f93b7eaab5f6 571 barometric=(pcal*3.3/MPXref-0.04)/0.0012858; // barometric pressure (kpa) evaluated from calibration which we assume is baseline
pegcjs 5:35417986539a 572 depth=(pressure-barometric)*0.1; //100kPa=10m 1kPa=0.1m - this gives depth in m for freshwater.
pegcjs 7:f93b7eaab5f6 573
pegcjs 7:f93b7eaab5f6 574 if (depth<0) depth=0; // deals wtih noise that may lead to small variation in values
pegcjs 2:a1c26faa9103 575
pegcjs 9:71b8ac65b73a 576
pegcjs 9:71b8ac65b73a 577
pegcjs 7:f93b7eaab5f6 578 // THESE SHOULD BE JUST 100*ppox/(pressure/100);
pegcjs 5:35417986539a 579 fo1=100*ppo1/((pressure-barometric)/100+1); // pressure in bar = pressure /100 and want a % so multiply by 100 as well
pegcjs 5:35417986539a 580 fo2=100*ppo2/((pressure-barometric)/100+1);
pegcjs 7:f93b7eaab5f6 581 fo3=100*ppo3/((pressure-barometric)/100+1); // maybe these should be ppox/(depth/10+1)*100....?
pegcjs 6:ab2d7d0a9b07 582
pegcjs 7:f93b7eaab5f6 583 /*if (fo1<0) fo2=0;
pegcjs 6:ab2d7d0a9b07 584 if (fo2<0) fo1=0;
pegcjs 7:f93b7eaab5f6 585 */
pegcjs 7:f93b7eaab5f6 586 //with three sensors will calculate mod from the largest ppo2 reading
pegcjs 2:a1c26faa9103 587 mod1=(1.4/(fo1/100)-1)*10;
pegcjs 2:a1c26faa9103 588 mod2=(1.4/(fo2/100)-1)*10;
pegcjs 7:f93b7eaab5f6 589 mod3=(1.4/(fo3/100)-1)*10;
pegcjs 3:0d94a277aa8c 590
pegcjs 7:f93b7eaab5f6 591 mod=minimum(mod1,mod2,mod3); // pick the least value
pegcjs 7:f93b7eaab5f6 592
pegcjs 7:f93b7eaab5f6 593 // output for debugging to pc via usb line.
pegcjs 7:f93b7eaab5f6 594 // pc.printf("VDepth %f\tPressure %f\tbarometric %f\tdepth %f\t \n\r",Vdepth,pressure,barometric,depth);
pegcjs 7:f93b7eaab5f6 595 //NB - problem - we really need to monitor the 5V power line to ensure that it's driving the depth sensor ok.
pegcjs 7:f93b7eaab5f6 596 // it may need thicker cables as it currently only manages 4.8V on the board when everything is running.
pegcjs 3:0d94a277aa8c 597
pegcjs 1:9cff4feccbce 598 }
pegcjs 6:ab2d7d0a9b07 599 // get values back from cal file on local drive
pegcjs 6:ab2d7d0a9b07 600 void recall() {
pegcjs 6:ab2d7d0a9b07 601 FILE *fp=fopen("/local/CAL.dat","r");
pegcjs 7:f93b7eaab5f6 602 fscanf(fp,"%e\n%e\n%e\n%e\n%d",&eg1cal,&eg2cal,&eg3cal,&pcal,&scrubold);
pegcjs 6:ab2d7d0a9b07 603 fclose(fp); //NB file system locked on write so must make sure we close files in case want to reprogram etc...
pegcjs 6:ab2d7d0a9b07 604 }
pegcjs 6:ab2d7d0a9b07 605
pegcjs 6:ab2d7d0a9b07 606 // write the logfile opened and closed by start and end of dive
pegcjs 6:ab2d7d0a9b07 607 void store_log() {
pegcjs 7:f93b7eaab5f6 608
pegcjs 6:ab2d7d0a9b07 609 //FILE *fp=fopen("/local/divelog.dat","a");
pegcjs 7:f93b7eaab5f6 610 float v5=0;
pegcjs 7:f93b7eaab5f6 611 v5=V5V;
pegcjs 7:f93b7eaab5f6 612 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);
pegcjs 7:f93b7eaab5f6 613
pegcjs 7:f93b7eaab5f6 614 if (divetime % 60==0) fflush(lp);
pegcjs 7:f93b7eaab5f6 615 // fclose(fp);
pegcjs 7:f93b7eaab5f6 616 }
pegcjs 7:f93b7eaab5f6 617
pegcjs 7:f93b7eaab5f6 618 // read switches and report state
pegcjs 7:f93b7eaab5f6 619 int switches() {
pegcjs 7:f93b7eaab5f6 620 int ss=0;
pegcjs 7:f93b7eaab5f6 621 if (SW1==1 && SW2==1) ss=3;
pegcjs 7:f93b7eaab5f6 622 if (SW2==1 && SW1==0) ss=2;
pegcjs 7:f93b7eaab5f6 623 if (SW1==1 && SW2==0) ss=1;
pegcjs 7:f93b7eaab5f6 624 return(ss);
pegcjs 6:ab2d7d0a9b07 625 }
pegcjs 4:74df6d31ee0a 626
pegcjs 7:f93b7eaab5f6 627 // interpret the ppo2 data into a simple set of hud codes.
pegcjs 7:f93b7eaab5f6 628 int HUD_display()
pegcjs 7:f93b7eaab5f6 629 {
pegcjs 7:f93b7eaab5f6 630 int i,j3,h1,h2,h3;
pegcjs 7:f93b7eaab5f6 631 float cset=0;
pegcjs 7:f93b7eaab5f6 632 char gcode[6]={0,1,3,2,6,4}; // grey code for HUD reading 'red,amber,green,cyan,blue'
pegcjs 7:f93b7eaab5f6 633
pegcjs 7:f93b7eaab5f6 634 HUD_clr(); // clear the HUID ready for write
pegcjs 7:f93b7eaab5f6 635
pegcjs 7:f93b7eaab5f6 636
pegcjs 7:f93b7eaab5f6 637 if(setpoint==0) // low setpoint
pegcjs 7:f93b7eaab5f6 638 {
pegcjs 7:f93b7eaab5f6 639 cset=lowsetpoint;
pegcjs 7:f93b7eaab5f6 640 }
pegcjs 7:f93b7eaab5f6 641
pegcjs 7:f93b7eaab5f6 642 if(setpoint==1) // hgh setpoint
pegcjs 7:f93b7eaab5f6 643 {
pegcjs 7:f93b7eaab5f6 644 cset=highsetpoint;
pegcjs 7:f93b7eaab5f6 645 }
pegcjs 7:f93b7eaab5f6 646
pegcjs 7:f93b7eaab5f6 647 h1=(int)((ppo1-cset)/0.1+3.5);
pegcjs 7:f93b7eaab5f6 648 if(h1<1) h1=1;
pegcjs 7:f93b7eaab5f6 649 if(h1>5) h1=5;
pegcjs 7:f93b7eaab5f6 650 h2=(int)((ppo2-cset)/0.1+3.5);
pegcjs 7:f93b7eaab5f6 651 if(h2<1) h2=1;
pegcjs 7:f93b7eaab5f6 652 if(h2>5) h2=5;
pegcjs 7:f93b7eaab5f6 653 h3=(int)((ppo3-cset)/0.1+3.5);
pegcjs 7:f93b7eaab5f6 654 if(h3<1) h3=1;
pegcjs 7:f93b7eaab5f6 655 if(h3>5) h3=5;
pegcjs 7:f93b7eaab5f6 656
pegcjs 7:f93b7eaab5f6 657 if(h3>3) btest=0; // handle extra blue connected to btest setting btest low lights blue led
pegcjs 7:f93b7eaab5f6 658
pegcjs 7:f93b7eaab5f6 659
pegcjs 7:f93b7eaab5f6 660 i=gcode[h1]+8*gcode[h2]+64*gcode[h3]; // this is possible bigger than a char so have to typeconvert
pegcjs 7:f93b7eaab5f6 661 HUD_write(i);
pegcjs 7:f93b7eaab5f6 662
pegcjs 7:f93b7eaab5f6 663 }
pegcjs 7:f93b7eaab5f6 664
pegcjs 7:f93b7eaab5f6 665 // sub to flash HUD n times as a warning of setpoint shift
pegcjs 7:f93b7eaab5f6 666 int HUD_flash(int n)
pegcjs 7:f93b7eaab5f6 667 {
pegcjs 7:f93b7eaab5f6 668 int i;
pegcjs 7:f93b7eaab5f6 669 for(i=0;i<n;i++)
pegcjs 7:f93b7eaab5f6 670 {
pegcjs 7:f93b7eaab5f6 671 HUD_clr();
pegcjs 9:71b8ac65b73a 672 wait(0.3);
pegcjs 7:f93b7eaab5f6 673 HUD_white();
pegcjs 9:71b8ac65b73a 674 wait(0.3);
pegcjs 9:71b8ac65b73a 675
pegcjs 7:f93b7eaab5f6 676 }
pegcjs 9:71b8ac65b73a 677 HUD_display();
pegcjs 7:f93b7eaab5f6 678 }
pegcjs 9:71b8ac65b73a 679 // sub to decide if the setpoint should change - in this variant it always changes at 9.5-10.5m
pegcjs 9:71b8ac65b73a 680 // this might become annoyiong later so might want to make this function totally manual and use SW1 to control it.
pegcjs 7:f93b7eaab5f6 681 int setswitch()
pegcjs 7:f93b7eaab5f6 682 {
pegcjs 7:f93b7eaab5f6 683 if(setpoint==0 && depth >(switchdepth+0.5))
pegcjs 7:f93b7eaab5f6 684 {
pegcjs 7:f93b7eaab5f6 685 setpoint=1; // handle switch from low to high
pegcjs 9:71b8ac65b73a 686 HUD_flash(4); // 4 flashes says going to high setpoint
pegcjs 7:f93b7eaab5f6 687 // flash the hud here
pegcjs 7:f93b7eaab5f6 688 }
pegcjs 7:f93b7eaab5f6 689
pegcjs 7:f93b7eaab5f6 690 if(setpoint==1 && depth < (switchdepth -0.5))
pegcjs 7:f93b7eaab5f6 691 {
pegcjs 7:f93b7eaab5f6 692 setpoint=0; // swtich to low setpoint
pegcjs 9:71b8ac65b73a 693 HUD_flash(2); // two flashes says going to low setpoint
pegcjs 7:f93b7eaab5f6 694 // flash the HUD here
pegcjs 7:f93b7eaab5f6 695 }
pegcjs 7:f93b7eaab5f6 696 }
pegcjs 1:9cff4feccbce 697
pegcjs 1:9cff4feccbce 698 int main() {
pegcjs 9:71b8ac65b73a 699
pegcjs 9:71b8ac65b73a 700 // start the clock in case it stopped for some reason
pegcjs 9:71b8ac65b73a 701 //this happens when the power drops due to battery getting too low.
pegcjs 9:71b8ac65b73a 702 // system still runs as a monitor but wont log.
pegcjs 9:71b8ac65b73a 703 // might be useful later to build a sub that checks the clock is reading and starts it if its stopped
pegcjs 9:71b8ac65b73a 704
pegcjs 9:71b8ac65b73a 705 my1307.start_clock();
pegcjs 9:71b8ac65b73a 706
pegcjs 2:a1c26faa9103 707 // first some local variables
pegcjs 2:a1c26faa9103 708 int startuptime=getseconds();
pegcjs 4:74df6d31ee0a 709 int startdive=0,endclock=0; // value of seconds when dive starts and counter to decide if dive complete...
pegcjs 1:9cff4feccbce 710
pegcjs 6:ab2d7d0a9b07 711 int minutes=0; // minutes is elapsed minutes since start of prog
pegcjs 7:f93b7eaab5f6 712 int j=0,scount=1;; // general loop counting variable
pegcjs 7:f93b7eaab5f6 713 int sw=0; // status of the switches in the handset
pegcjs 7:f93b7eaab5f6 714 char schars[4]={32,0xd9,0xda,0xfb}; // up arrow, down arrow and both arrows;
pegcjs 6:ab2d7d0a9b07 715
pegcjs 7:f93b7eaab5f6 716 bool mdir=0;
pegcjs 1:9cff4feccbce 717
pegcjs 9:71b8ac65b73a 718 // code to deal with clock problem
pegcjs 9:71b8ac65b73a 719 if(startuptime==0){ // clock buggered and needs reseting
pegcjs 9:71b8ac65b73a 720 j=my1307.settime( 0, 0, 1, 1, 1, 1, 13); // set time to 1am on 1st jan 2013
pegcjs 9:71b8ac65b73a 721 g_lcd.locate(0,0);
pegcjs 9:71b8ac65b73a 722 g_lcd.printf( "Clockreset %d",j);
pegcjs 9:71b8ac65b73a 723 wait(3);
pegcjs 9:71b8ac65b73a 724 }
pegcjs 1:9cff4feccbce 725 set_custom_char(); // does what it says on the tin really
pegcjs 1:9cff4feccbce 726 g_lcd.cls();
pegcjs 1:9cff4feccbce 727 g_lcd.locate(0, 0);
pegcjs 9:71b8ac65b73a 728 g_lcd.printf( "CCRMon SP%1.1f:%1.1f",lowsetpoint,highsetpoint);
pegcjs 9:71b8ac65b73a 729 wait(3);
pegcjs 9:71b8ac65b73a 730 g_lcd.cls(); // clear display to look nice
pegcjs 1:9cff4feccbce 731 g_lcd.locate(0,1);
pegcjs 1:9cff4feccbce 732 g_lcd.printf("CAL?");
pegcjs 1:9cff4feccbce 733 battery();
pegcjs 4:74df6d31ee0a 734 j=0;
pegcjs 7:f93b7eaab5f6 735 wait(0.2);
pegcjs 7:f93b7eaab5f6 736
pegcjs 6:ab2d7d0a9b07 737 // get cal values last used from local drive
pegcjs 6:ab2d7d0a9b07 738 recall();
pegcjs 6:ab2d7d0a9b07 739 // display the correct scrubber time
pegcjs 7:f93b7eaab5f6 740 scrubtime=scrubold;
pegcjs 9:71b8ac65b73a 741
pegcjs 1:9cff4feccbce 742 // hang about waiting for the cal switch to be pressed in ccase it is
pegcjs 7:f93b7eaab5f6 743 while (scount<30) {
pegcjs 7:f93b7eaab5f6 744 seconds=getseconds(); // NB if this hangs then nothing works :( - usually means 5V is dodgy
pegcjs 7:f93b7eaab5f6 745 red=1;
pegcjs 7:f93b7eaab5f6 746 green=1;
pegcjs 7:f93b7eaab5f6 747 blue=1; // light all leds
pegcjs 7:f93b7eaab5f6 748
pegcjs 1:9cff4feccbce 749 g_lcd.locate(5,1);
pegcjs 7:f93b7eaab5f6 750 g_lcd.printf("%.2d ",30-scount);
pegcjs 4:74df6d31ee0a 751 if (j>1) flash=1;
pegcjs 3:0d94a277aa8c 752 else flash=0;
pegcjs 1:9cff4feccbce 753 battery(); // bung in battery symbol.
pegcjs 1:9cff4feccbce 754 g_lcd.locate(7,0);
pegcjs 1:9cff4feccbce 755 g_lcd.printf( "%.2d:%.2d:%.2d", hours,min,sec);
pegcjs 7:f93b7eaab5f6 756 // if (CAL==0) {
pegcjs 7:f93b7eaab5f6 757 if(SW1==0) {
pegcjs 1:9cff4feccbce 758 calibrate();
pegcjs 7:f93b7eaab5f6 759 scount=31; // make sure it goes to next frame ok
pegcjs 1:9cff4feccbce 760 }
pegcjs 7:f93b7eaab5f6 761 wait(0.05);
pegcjs 7:f93b7eaab5f6 762
pegcjs 7:f93b7eaab5f6 763
pegcjs 3:0d94a277aa8c 764 j=(j+1) % 4;
pegcjs 7:f93b7eaab5f6 765 if(flash==0) HUD_white();
pegcjs 7:f93b7eaab5f6 766 else HUD_clr();
pegcjs 7:f93b7eaab5f6 767 scount++;
pegcjs 7:f93b7eaab5f6 768 }
pegcjs 1:9cff4feccbce 769 g_lcd.cls();
pegcjs 5:35417986539a 770
pegcjs 1:9cff4feccbce 771
pegcjs 1:9cff4feccbce 772 // ok there are three states in this system
pegcjs 1:9cff4feccbce 773 //MAIN LOOP ONCE STARTUP PROTOCOLS ARE COMPLETED
pegcjs 3:0d94a277aa8c 774 j=0;
pegcjs 7:f93b7eaab5f6 775 g_lcd.cls();
pegcjs 1:9cff4feccbce 776 while (1) {
pegcjs 7:f93b7eaab5f6 777 wait(0.1); //stop screen flicker
pegcjs 1:9cff4feccbce 778 readsensors();
pegcjs 7:f93b7eaab5f6 779 setswitch(); // check the setpoint and adjust if crossing the swtich depth
pegcjs 7:f93b7eaab5f6 780 HUD_display(); // write the HUD codes
pegcjs 2:a1c26faa9103 781 seconds=getseconds();
pegcjs 4:74df6d31ee0a 782 minutes=(int)(((float)seconds-(float)startuptime)/60);
pegcjs 7:f93b7eaab5f6 783 led1=seconds % 2; // flash the onboard led to make it clear stuff is running
pegcjs 9:71b8ac65b73a 784 led2=!(seconds %2);
pegcjs 3:0d94a277aa8c 785
pegcjs 3:0d94a277aa8c 786 if (j>1) flash=1;
pegcjs 3:0d94a277aa8c 787 else flash=0;
pegcjs 3:0d94a277aa8c 788
pegcjs 3:0d94a277aa8c 789 display(); // write the display
pegcjs 7:f93b7eaab5f6 790 HUD_display(); // write the HUD
pegcjs 7:f93b7eaab5f6 791 // sw=switches(); // read the switches and report their state
pegcjs 7:f93b7eaab5f6 792 // 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
pegcjs 7:f93b7eaab5f6 793 // HERE do deco calcs - update tissues and compute desat , nostop or ascent times as required.
pegcjs 3:0d94a277aa8c 794
pegcjs 3:0d94a277aa8c 795 // setup state variable
pegcjs 7:f93b7eaab5f6 796 if (minutes<1) state=0; // startup mode - do nothing just wait to allow sensor readings to settle.
pegcjs 4:74df6d31ee0a 797 if (minutes>=1 && state==0) state=1; // surface mode - ok to go for a dive now
pegcjs 6:ab2d7d0a9b07 798 if (minutes>=1 && depth>0.8 && state==1) {
pegcjs 3:0d94a277aa8c 799 state=2; // enter dive mode
pegcjs 6:ab2d7d0a9b07 800 lp=fopen("/local/divelog.dat","a");
pegcjs 7:f93b7eaab5f6 801 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
pegcjs 8:f45e654b47d0 802 store_log(); // make a first log entry to catch this erliest part of the dive
pegcjs 4:74df6d31ee0a 803 if (startdive==0) startdive=seconds; // set start of divetime. don't do this twice
pegcjs 3:0d94a277aa8c 804 endclock=0; // reset end of dive clock
pegcjs 3:0d94a277aa8c 805 }
pegcjs 7:f93b7eaab5f6 806 // in dive mode - things to do, 1 update divetime and scrubber time, 2 write log data 3 check for end of dive...
pegcjs 7:f93b7eaab5f6 807 if (state==2) {
pegcjs 7:f93b7eaab5f6 808 // divetime=(int)(((float)seconds-(float)startdive)/60.0); // time since start of dive in minutes.
pegcjs 7:f93b7eaab5f6 809 divetime=(seconds-startdive); // divetime no recorded in seconds since start of dive
pegcjs 7:f93b7eaab5f6 810
pegcjs 3:0d94a277aa8c 811 // do deco calcs here when implemented
pegcjs 9:71b8ac65b73a 812 if (divetime %15 ==0) store_log(); // this saves the dive profile data every 15s and sensor optputs in a file called divelog.dat
pegcjs 7:f93b7eaab5f6 813 if (depth<=0.5) {
pegcjs 4:74df6d31ee0a 814 endclock=endclock+1;
pegcjs 4:74df6d31ee0a 815
pegcjs 6:ab2d7d0a9b07 816 if (endclock>150) {
pegcjs 9:71b8ac65b73a 817 state=1; // 30s at shallower than 0.5m and we return to surface mode. */
pegcjs 6:ab2d7d0a9b07 818 FILE *fp=fopen("/local/CAL.dat","w");
pegcjs 6:ab2d7d0a9b07 819 fprintf(fp,"%e\n%e\n%e\n%d",eg1cal,eg2cal,pcal,scrubtime);
pegcjs 6:ab2d7d0a9b07 820 fclose(fp); //NB file system locked on write so must make sure we close files in case want to reprogram etc...
pegcjs 7:f93b7eaab5f6 821
pegcjs 7:f93b7eaab5f6 822 store();
pegcjs 6:ab2d7d0a9b07 823 fclose(lp);
pegcjs 7:f93b7eaab5f6 824 } // endif endclock
pegcjs 7:f93b7eaab5f6 825
pegcjs 7:f93b7eaab5f6 826 } // end if depth
pegcjs 7:f93b7eaab5f6 827 scrubtime=scrubold+(divetime/60); //
pegcjs 7:f93b7eaab5f6 828 } // end state 2
pegcjs 1:9cff4feccbce 829
pegcjs 1:9cff4feccbce 830
pegcjs 3:0d94a277aa8c 831 j=(j+1) %4; // flash control variable = used to make the warnings flash for 0.4s duty cycle
pegcjs 7:f93b7eaab5f6 832
pegcjs 7:f93b7eaab5f6 833
pegcjs 7:f93b7eaab5f6 834 vmessage(); // call to generate status message in vertical segment
pegcjs 1:9cff4feccbce 835 } // end while
pegcjs 1:9cff4feccbce 836 } //end main
pegcjs 1:9cff4feccbce 837
pegcjs 1:9cff4feccbce 838
pegcjs 1:9cff4feccbce 839
pegcjs 1:9cff4feccbce 840