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...

Committer:
pegcjs
Date:
Wed Jan 16 13:47:34 2013 +0000
Revision:
9:cd3599adfff6
Parent:
8:f45e654b47d0
published version of the rebreather monitor software

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