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:
Mon Jan 14 12:55:05 2013 +0000
Revision:
8:f45e654b47d0
Parent:
7:f93b7eaab5f6
Child:
9:cd3599adfff6
added store_log();in start of dive routine to make a first data point close to surface

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 1:9cff4feccbce 235 g_lcd.locate(0,0);
pegcjs 4:74df6d31ee0a 236 g_lcd.printf("Calibrate 21%% %.2d",count);
pegcjs 7:f93b7eaab5f6 237 s1=s1+EG1;
pegcjs 7:f93b7eaab5f6 238 s2=s2+EG2;
pegcjs 7:f93b7eaab5f6 239 s3=s3+EG3;
pegcjs 1:9cff4feccbce 240 pres=pres+PRESin;
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 1:9cff4feccbce 357 void battery() {
pegcjs 7:f93b7eaab5f6 358 char cgchar[32]={
pegcjs 7:f93b7eaab5f6 359 6,9,9,9,9,9,9,15, // battery empty symbol
pegcjs 7:f93b7eaab5f6 360 6,9,9,9,9,15,15,15, // battery 50% symbol
pegcjs 7:f93b7eaab5f6 361 6,9,9,15,15,15,15,15, // battery 75% symbol
pegcjs 7:f93b7eaab5f6 362 6,15,15,15,15,15,15,15, // battery 100% symbol
pegcjs 7:f93b7eaab5f6 363 };
pegcjs 7:f93b7eaab5f6 364
pegcjs 7:f93b7eaab5f6 365
pegcjs 7:f93b7eaab5f6 366 int batsym=0,i=0; // battery < 3.85V
pegcjs 7:f93b7eaab5f6 367
pegcjs 7:f93b7eaab5f6 368
pegcjs 7:f93b7eaab5f6 369 // idea to build in 6 levels of battery indicator by on the fly reprogramming character 2 as required.
pegcjs 7:f93b7eaab5f6 370 Vb=0;
pegcjs 7:f93b7eaab5f6 371 for (i=0; i<4; i++) {
pegcjs 7:f93b7eaab5f6 372 Vb=Vb+Vbatt; // read adc connected to battery via a 1/3 potential divider
pegcjs 7:f93b7eaab5f6 373 wait(0.05);
pegcjs 7:f93b7eaab5f6 374 }
pegcjs 7:f93b7eaab5f6 375 Vb=Vb/4; // average 4 readings to reduce noise
pegcjs 7:f93b7eaab5f6 376
pegcjs 7:f93b7eaab5f6 377 if (Vb>0.388) batsym=8; //3.85-3.92V
pegcjs 7:f93b7eaab5f6 378 if (Vb>0.395) batsym=16; // battery 3.92-4V
pegcjs 7:f93b7eaab5f6 379 if (Vb>0.404) batsym=24; // battery . >4V
pegcjs 7:f93b7eaab5f6 380
pegcjs 7:f93b7eaab5f6 381
pegcjs 7:f93b7eaab5f6 382 // write the appropriate battery symbol into the first custom character
pegcjs 7:f93b7eaab5f6 383 g_lcd.writeCommand(0x40); // set start address for CGRAM
pegcjs 7:f93b7eaab5f6 384 for (i=0; i<8; i++) {
pegcjs 7:f93b7eaab5f6 385 g_lcd.writeData(cgchar[i+batsym]);
pegcjs 7:f93b7eaab5f6 386 }
pegcjs 7:f93b7eaab5f6 387
pegcjs 7:f93b7eaab5f6 388 g_lcd.character(11,1,0); // battery symbol
pegcjs 7:f93b7eaab5f6 389 if (batsym ==0 && flash==0) g_lcd.character(11,1,32); // bung in space if flashing
pegcjs 7:f93b7eaab5f6 390
pegcjs 7:f93b7eaab5f6 391
pegcjs 1:9cff4feccbce 392 }
pegcjs 1:9cff4feccbce 393
pegcjs 7:f93b7eaab5f6 394 // sub to make the nice stop or no stop message work in locations 9,0 and 9,1
pegcjs 7:f93b7eaab5f6 395 void vmessage() {
pegcjs 7:f93b7eaab5f6 396 int i,d,cpos=0;
pegcjs 7:f93b7eaab5f6 397 // "INITSURFDIVE" in vertical chas - 1 custom char per two symbols
pegcjs 7:f93b7eaab5f6 398 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 399
pegcjs 7:f93b7eaab5f6 400
pegcjs 7:f93b7eaab5f6 401
pegcjs 7:f93b7eaab5f6 402 g_lcd.writeCommand(104); // set start address for CGRAM characrter #6 out of 8
pegcjs 7:f93b7eaab5f6 403
pegcjs 7:f93b7eaab5f6 404 for (i=0; i<16; i++) { // write 2 chars worth into this segment NO DECO
pegcjs 7:f93b7eaab5f6 405
pegcjs 7:f93b7eaab5f6 406
pegcjs 7:f93b7eaab5f6 407 g_lcd.writeData(mesg[i+state*16]);
pegcjs 7:f93b7eaab5f6 408 } // endfor
pegcjs 7:f93b7eaab5f6 409
pegcjs 7:f93b7eaab5f6 410
pegcjs 7:f93b7eaab5f6 411
pegcjs 7:f93b7eaab5f6 412 g_lcd.character(12,0,5); // custom char 5
pegcjs 7:f93b7eaab5f6 413
pegcjs 7:f93b7eaab5f6 414 g_lcd.character(12,1,6); // custom char 6
pegcjs 7:f93b7eaab5f6 415
pegcjs 7:f93b7eaab5f6 416 }
pegcjs 7:f93b7eaab5f6 417
pegcjs 7:f93b7eaab5f6 418
pegcjs 2:a1c26faa9103 419 // subroutine to write the main display data
pegcjs 2:a1c26faa9103 420 //0123456789abcdef
pegcjs 2:a1c26faa9103 421
pegcjs 2:a1c26faa9103 422 //x.xx:xx D XX xx
pegcjs 2:a1c26faa9103 423 //x.xx:xx B XX xxx NB the warning, staus and battery icons are driven by separate subroutines.
pegcjs 2:a1c26faa9103 424 void display() {
pegcjs 7:f93b7eaab5f6 425 int mo=0,tmp=0;
pegcjs 7:f93b7eaab5f6 426 //mo=MODE;
pegcjs 7:f93b7eaab5f6 427 g_lcd.character(3,1,32);
pegcjs 2:a1c26faa9103 428 //1st line
pegcjs 7:f93b7eaab5f6 429
pegcjs 7:f93b7eaab5f6 430 //ppo1
pegcjs 7:f93b7eaab5f6 431 if(ppo1<1) tmp=(int)(ppo1*100); else tmp=(int)(ppo1*100-100);
pegcjs 7:f93b7eaab5f6 432 g_lcd.locate(1,0);
pegcjs 7:f93b7eaab5f6 433 g_lcd.printf("%02d ",tmp);
pegcjs 7:f93b7eaab5f6 434 if(ppo1>=1) g_lcd.character(0,0,2);
pegcjs 7:f93b7eaab5f6 435 if(ppo1<1) g_lcd.character(0,0,1);
pegcjs 7:f93b7eaab5f6 436
pegcjs 7:f93b7eaab5f6 437 if(ppo2<1) tmp=(int)(ppo2*100); else tmp=(int)(ppo2*100-100);
pegcjs 7:f93b7eaab5f6 438 g_lcd.locate(5,0);
pegcjs 7:f93b7eaab5f6 439 g_lcd.printf("%02d ",tmp);
pegcjs 7:f93b7eaab5f6 440 if(ppo2>=1) g_lcd.character(4,0,2);
pegcjs 7:f93b7eaab5f6 441 if(ppo2<1) g_lcd.character(4,0,1);
pegcjs 7:f93b7eaab5f6 442
pegcjs 7:f93b7eaab5f6 443 if(ppo3<1) tmp=(int)(ppo3*100); else tmp=(int)(ppo3*100-100);
pegcjs 7:f93b7eaab5f6 444 g_lcd.locate(9,0);
pegcjs 7:f93b7eaab5f6 445 g_lcd.printf("%02d ",tmp);
pegcjs 7:f93b7eaab5f6 446 if(ppo3>=1) g_lcd.character(8,0,2);
pegcjs 7:f93b7eaab5f6 447 if(ppo3<1) g_lcd.character(8,0,1);
pegcjs 7:f93b7eaab5f6 448
pegcjs 7:f93b7eaab5f6 449 g_lcd.locate(13,0);
pegcjs 7:f93b7eaab5f6 450 g_lcd.printf("%.2d",(int)depth); // depth
pegcjs 7:f93b7eaab5f6 451 g_lcd.locate(4,1);
pegcjs 7:f93b7eaab5f6 452 g_lcd.printf("%2dm",(int)mod); // mod
pegcjs 2:a1c26faa9103 453 //2nd line
pegcjs 2:a1c26faa9103 454 g_lcd.locate(0,1);
pegcjs 7:f93b7eaab5f6 455 tmp=minimum((float)fo1,(float)fo2,(float)fo3); // get min fraction of oxygen to display lowest for deco use
pegcjs 7:f93b7eaab5f6 456 g_lcd.printf("%2d%%",tmp);
pegcjs 7:f93b7eaab5f6 457 g_lcd.locate(13,1);
pegcjs 7:f93b7eaab5f6 458 g_lcd.printf("%03d",scrubtime % 1000); // modulo to avoid digits conflict - means divetime is always less than 100
pegcjs 7:f93b7eaab5f6 459 g_lcd.locate(8,1);
pegcjs 7:f93b7eaab5f6 460 g_lcd.printf("%2d",(int)(divetime/60) % 100 ); // rolls back to zero if go over 99
pegcjs 2:a1c26faa9103 461 // bung in battery icon
pegcjs 2:a1c26faa9103 462 battery();
pegcjs 5:35417986539a 463 status(); // this will set the diving / suface mode icon
pegcjs 7:f93b7eaab5f6 464 // warning(); // this will set the warning ic on assuming that max ppo2 is exceeded
pegcjs 7:f93b7eaab5f6 465 g_lcd.character(7,1,32); // space to cover any write error on top line
pegcjs 2:a1c26faa9103 466 leds(); // this sets the leds according to the various warning conditions
pegcjs 7:f93b7eaab5f6 467 /* if (mo==0) {
pegcjs 5:35417986539a 468 g_lcd.character(7,1,99); //'c' = ccr
pegcjs 5:35417986539a 469 } else {
pegcjs 5:35417986539a 470 g_lcd.character(7,1,115); //'s' = scr
pegcjs 7:f93b7eaab5f6 471 }*/
pegcjs 5:35417986539a 472 // custom character setting to sort out dp in depths
pegcjs 6:ab2d7d0a9b07 473
pegcjs 6:ab2d7d0a9b07 474
pegcjs 5:35417986539a 475 char cgchar[80]={
pegcjs 5:35417986539a 476 7,5,5,5,23,0,0,0, // .0
pegcjs 5:35417986539a 477 2,2,2,2,18,0,0,0, // .1
pegcjs 7:f93b7eaab5f6 478 7,1,7,4,23,0,0,0, // .2
pegcjs 7:f93b7eaab5f6 479 7,1,3,1,23,0,0,0, // .3
pegcjs 7:f93b7eaab5f6 480 5,5,7,1,17,0,0,0, //.4
pegcjs 7:f93b7eaab5f6 481 7,4,7,1,23,0,0,0, //.5
pegcjs 7:f93b7eaab5f6 482 7,4,7,5,23,0,0,0, //.6
pegcjs 5:35417986539a 483 7,1,2,2,18,0,0,0, //.7
pegcjs 5:35417986539a 484 7,5,7,5,23,0,0,0, //.8
pegcjs 5:35417986539a 485 7,5,7,1,17,0,0,0 //.9
pegcjs 5:35417986539a 486
pegcjs 5:35417986539a 487 };
pegcjs 7:f93b7eaab5f6 488 // special dp digit for depth
pegcjs 5:35417986539a 489 int i=0,d=0;
pegcjs 5:35417986539a 490 d=(int)((depth-(int)depth)*10); // should be size of the 1st decimal place
pegcjs 5:35417986539a 491 // do stuff here to set cstom chars
pegcjs 5:35417986539a 492 g_lcd.writeCommand(120); // set start address for CGRAM
pegcjs 5:35417986539a 493 for (i=0; i<8; i++) {
pegcjs 5:35417986539a 494 g_lcd.writeData(cgchar[i+d*8]);
pegcjs 5:35417986539a 495 }
pegcjs 5:35417986539a 496
pegcjs 7:f93b7eaab5f6 497 g_lcd.character(15,0,7); // put in appropriate custom character
pegcjs 7:f93b7eaab5f6 498
pegcjs 7:f93b7eaab5f6 499 // display the current setpoint information
pegcjs 7:f93b7eaab5f6 500 if(setpoint==0) g_lcd.character(7,1,218); // letter down arrow for low setpoint
pegcjs 7:f93b7eaab5f6 501 if(setpoint==1) g_lcd.character(7,1,217); // Letter 'H'
pegcjs 7:f93b7eaab5f6 502 if(flash==1) g_lcd.character(7,1,115); // Letter ':'
pegcjs 2:a1c26faa9103 503
pegcjs 2:a1c26faa9103 504 }
pegcjs 2:a1c26faa9103 505
pegcjs 2:a1c26faa9103 506
pegcjs 2:a1c26faa9103 507
pegcjs 1:9cff4feccbce 508
pegcjs 7:f93b7eaab5f6 509 // read sensors and generate calibrated outputs NB battery is read elsewhere
pegcjs 2:a1c26faa9103 510
pegcjs 1:9cff4feccbce 511 void readsensors() {
pegcjs 7:f93b7eaab5f6 512 float barometric=0,mod1,mod2,mod3,temp,Vdepth=0,s1,s2,s3,MPXref=0;
pegcjs 7:f93b7eaab5f6 513 int tc=0;
pegcjs 7:f93b7eaab5f6 514 // ppo1=EG1*0.21/eg1cal; // eg1cal is 0.21bar ppO2
pegcjs 7:f93b7eaab5f6 515 // ppo2=EG2*0.21/eg2cal; // second oxygen cell ppO2
pegcjs 7:f93b7eaab5f6 516 // ppo3=EG3*0.21/eg3cal;
pegcjs 7:f93b7eaab5f6 517
pegcjs 7:f93b7eaab5f6 518 s1=0;
pegcjs 7:f93b7eaab5f6 519 s2=0;
pegcjs 7:f93b7eaab5f6 520 s3=0;
pegcjs 7:f93b7eaab5f6 521 for(tc=0;tc<20;tc++) // noise on Vdepth so average readings to compensate
pegcjs 7:f93b7eaab5f6 522 {
pegcjs 7:f93b7eaab5f6 523 Vdepth=Vdepth+(PRESin/DRATIO); // read the depth sensor and calculate the real value rather using the dividing ratio
pegcjs 7:f93b7eaab5f6 524 wait_ms(10); // slows stuff down a bit but not a big problem
pegcjs 7:f93b7eaab5f6 525 s1=s1+EG1; // read o2 sensors
pegcjs 7:f93b7eaab5f6 526 s2=s2+EG2;
pegcjs 7:f93b7eaab5f6 527 s3=s3+EG3;
pegcjs 7:f93b7eaab5f6 528 MPXref=MPXref+V5V; // read 5V
pegcjs 7:f93b7eaab5f6 529 wait_ms(10); // slows stuff down a bit but not a big problem
pegcjs 7:f93b7eaab5f6 530 }
pegcjs 7:f93b7eaab5f6 531 Vdepth=Vdepth/20; // now have the average
pegcjs 7:f93b7eaab5f6 532 s1=s1/20-coff1;
pegcjs 7:f93b7eaab5f6 533 s2=s2/20-coff2;
pegcjs 7:f93b7eaab5f6 534 s3=s3/20-coff3;
pegcjs 7:f93b7eaab5f6 535 MPXref=MPXref/20*3.3*2; // should be 5V
pegcjs 6:ab2d7d0a9b07 536
pegcjs 7:f93b7eaab5f6 537
pegcjs 7:f93b7eaab5f6 538 // compute ppO2s
pegcjs 7:f93b7eaab5f6 539 ppo1=s1*0.21/eg1cal;
pegcjs 7:f93b7eaab5f6 540 ppo2=s2*0.21/eg2cal;
pegcjs 7:f93b7eaab5f6 541 ppo3=s3*0.21/eg3cal;
pegcjs 7:f93b7eaab5f6 542
pegcjs 7:f93b7eaab5f6 543 pc.printf("EG1=%f\tEG2=%f\tEG3=%f \tMPXref=%f \r",s1,s2,s3,MPXref);
pegcjs 7:f93b7eaab5f6 544 pressure=(Vdepth*3.3/MPXref-0.04)/0.0012858; // pressure in kpa NB - assums that the 5V is correct
pegcjs 7:f93b7eaab5f6 545 //pressure=(PRESin*3.3/0.65006-0.04)/(0.0012858); // pressure in kPa assuming standard cal for mpx5700 sensor SUSPECT
pegcjs 7:f93b7eaab5f6 546 // 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 547 //outputs. with no division the max mbed adc of 3.3V coresponds to 480kpa or about 38m depth.....
pegcjs 7:f93b7eaab5f6 548 // standard spec on mpx5700 should be 5V*(P*0.0012858+0.04)
pegcjs 7:f93b7eaab5f6 549 // new sensor has 3/5 divider built into sensor wiring.
pegcjs 7:f93b7eaab5f6 550 //barometric=(pcal*3.3/0.65006-0.004)/(0.0012858); // sealevel in kPa assuming standard cal for mpx5700 sensor
pegcjs 7:f93b7eaab5f6 551 barometric=(pcal*3.3/MPXref-0.04)/0.0012858; // barometric pressure (kpa) evaluated from calibration which we assume is baseline
pegcjs 5:35417986539a 552 depth=(pressure-barometric)*0.1; //100kPa=10m 1kPa=0.1m - this gives depth in m for freshwater.
pegcjs 7:f93b7eaab5f6 553
pegcjs 7:f93b7eaab5f6 554 if (depth<0) depth=0; // deals wtih noise that may lead to small variation in values
pegcjs 2:a1c26faa9103 555
pegcjs 7:f93b7eaab5f6 556 // THESE SHOULD BE JUST 100*ppox/(pressure/100);
pegcjs 5:35417986539a 557 fo1=100*ppo1/((pressure-barometric)/100+1); // pressure in bar = pressure /100 and want a % so multiply by 100 as well
pegcjs 5:35417986539a 558 fo2=100*ppo2/((pressure-barometric)/100+1);
pegcjs 7:f93b7eaab5f6 559 fo3=100*ppo3/((pressure-barometric)/100+1); // maybe these should be ppox/(depth/10+1)*100....?
pegcjs 6:ab2d7d0a9b07 560
pegcjs 7:f93b7eaab5f6 561 /*if (fo1<0) fo2=0;
pegcjs 6:ab2d7d0a9b07 562 if (fo2<0) fo1=0;
pegcjs 7:f93b7eaab5f6 563 */
pegcjs 7:f93b7eaab5f6 564 //with three sensors will calculate mod from the largest ppo2 reading
pegcjs 2:a1c26faa9103 565 mod1=(1.4/(fo1/100)-1)*10;
pegcjs 2:a1c26faa9103 566 mod2=(1.4/(fo2/100)-1)*10;
pegcjs 7:f93b7eaab5f6 567 mod3=(1.4/(fo3/100)-1)*10;
pegcjs 3:0d94a277aa8c 568
pegcjs 7:f93b7eaab5f6 569 mod=minimum(mod1,mod2,mod3); // pick the least value
pegcjs 7:f93b7eaab5f6 570
pegcjs 7:f93b7eaab5f6 571 // output for debugging to pc via usb line.
pegcjs 7:f93b7eaab5f6 572 // pc.printf("VDepth %f\tPressure %f\tbarometric %f\tdepth %f\t \n\r",Vdepth,pressure,barometric,depth);
pegcjs 7:f93b7eaab5f6 573 //NB - problem - we really need to monitor the 5V power line to ensure that it's driving the depth sensor ok.
pegcjs 7:f93b7eaab5f6 574 // it may need thicker cables as it currently only manages 4.8V on the board when everything is running.
pegcjs 3:0d94a277aa8c 575
pegcjs 1:9cff4feccbce 576 }
pegcjs 6:ab2d7d0a9b07 577 // get values back from cal file on local drive
pegcjs 6:ab2d7d0a9b07 578 void recall() {
pegcjs 6:ab2d7d0a9b07 579 FILE *fp=fopen("/local/CAL.dat","r");
pegcjs 7:f93b7eaab5f6 580 fscanf(fp,"%e\n%e\n%e\n%e\n%d",&eg1cal,&eg2cal,&eg3cal,&pcal,&scrubold);
pegcjs 6:ab2d7d0a9b07 581 fclose(fp); //NB file system locked on write so must make sure we close files in case want to reprogram etc...
pegcjs 6:ab2d7d0a9b07 582 }
pegcjs 6:ab2d7d0a9b07 583
pegcjs 6:ab2d7d0a9b07 584 // write the logfile opened and closed by start and end of dive
pegcjs 6:ab2d7d0a9b07 585 void store_log() {
pegcjs 7:f93b7eaab5f6 586
pegcjs 6:ab2d7d0a9b07 587 //FILE *fp=fopen("/local/divelog.dat","a");
pegcjs 7:f93b7eaab5f6 588 float v5=0;
pegcjs 7:f93b7eaab5f6 589 v5=V5V;
pegcjs 7:f93b7eaab5f6 590 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 591
pegcjs 7:f93b7eaab5f6 592 if (divetime % 60==0) fflush(lp);
pegcjs 7:f93b7eaab5f6 593 // fclose(fp);
pegcjs 7:f93b7eaab5f6 594 }
pegcjs 7:f93b7eaab5f6 595
pegcjs 7:f93b7eaab5f6 596 // read switches and report state
pegcjs 7:f93b7eaab5f6 597 int switches() {
pegcjs 7:f93b7eaab5f6 598 int ss=0;
pegcjs 7:f93b7eaab5f6 599 if (SW1==1 && SW2==1) ss=3;
pegcjs 7:f93b7eaab5f6 600 if (SW2==1 && SW1==0) ss=2;
pegcjs 7:f93b7eaab5f6 601 if (SW1==1 && SW2==0) ss=1;
pegcjs 7:f93b7eaab5f6 602 return(ss);
pegcjs 6:ab2d7d0a9b07 603 }
pegcjs 4:74df6d31ee0a 604
pegcjs 7:f93b7eaab5f6 605 // interpret the ppo2 data into a simple set of hud codes.
pegcjs 7:f93b7eaab5f6 606 int HUD_display()
pegcjs 7:f93b7eaab5f6 607 {
pegcjs 7:f93b7eaab5f6 608 int i,j3,h1,h2,h3;
pegcjs 7:f93b7eaab5f6 609 float cset=0;
pegcjs 7:f93b7eaab5f6 610 char gcode[6]={0,1,3,2,6,4}; // grey code for HUD reading 'red,amber,green,cyan,blue'
pegcjs 7:f93b7eaab5f6 611
pegcjs 7:f93b7eaab5f6 612 HUD_clr(); // clear the HUID ready for write
pegcjs 7:f93b7eaab5f6 613
pegcjs 7:f93b7eaab5f6 614
pegcjs 7:f93b7eaab5f6 615 if(setpoint==0) // low setpoint
pegcjs 7:f93b7eaab5f6 616 {
pegcjs 7:f93b7eaab5f6 617 cset=lowsetpoint;
pegcjs 7:f93b7eaab5f6 618 }
pegcjs 7:f93b7eaab5f6 619
pegcjs 7:f93b7eaab5f6 620 if(setpoint==1) // hgh setpoint
pegcjs 7:f93b7eaab5f6 621 {
pegcjs 7:f93b7eaab5f6 622 cset=highsetpoint;
pegcjs 7:f93b7eaab5f6 623 }
pegcjs 7:f93b7eaab5f6 624
pegcjs 7:f93b7eaab5f6 625 h1=(int)((ppo1-cset)/0.1+3.5);
pegcjs 7:f93b7eaab5f6 626 if(h1<1) h1=1;
pegcjs 7:f93b7eaab5f6 627 if(h1>5) h1=5;
pegcjs 7:f93b7eaab5f6 628 h2=(int)((ppo2-cset)/0.1+3.5);
pegcjs 7:f93b7eaab5f6 629 if(h2<1) h2=1;
pegcjs 7:f93b7eaab5f6 630 if(h2>5) h2=5;
pegcjs 7:f93b7eaab5f6 631 h3=(int)((ppo3-cset)/0.1+3.5);
pegcjs 7:f93b7eaab5f6 632 if(h3<1) h3=1;
pegcjs 7:f93b7eaab5f6 633 if(h3>5) h3=5;
pegcjs 7:f93b7eaab5f6 634
pegcjs 7:f93b7eaab5f6 635 if(h3>3) btest=0; // handle extra blue connected to btest setting btest low lights blue led
pegcjs 7:f93b7eaab5f6 636
pegcjs 7:f93b7eaab5f6 637
pegcjs 7:f93b7eaab5f6 638 i=gcode[h1]+8*gcode[h2]+64*gcode[h3]; // this is possible bigger than a char so have to typeconvert
pegcjs 7:f93b7eaab5f6 639 HUD_write(i);
pegcjs 7:f93b7eaab5f6 640
pegcjs 7:f93b7eaab5f6 641 }
pegcjs 7:f93b7eaab5f6 642
pegcjs 7:f93b7eaab5f6 643 // sub to flash HUD n times as a warning of setpoint shift
pegcjs 7:f93b7eaab5f6 644 int HUD_flash(int n)
pegcjs 7:f93b7eaab5f6 645 {
pegcjs 7:f93b7eaab5f6 646 int i;
pegcjs 7:f93b7eaab5f6 647 for(i=0;i<n;i++)
pegcjs 7:f93b7eaab5f6 648 {
pegcjs 7:f93b7eaab5f6 649 HUD_clr();
pegcjs 7:f93b7eaab5f6 650 wait(0.2);
pegcjs 7:f93b7eaab5f6 651 HUD_white();
pegcjs 7:f93b7eaab5f6 652 wait(0.05);
pegcjs 7:f93b7eaab5f6 653 }
pegcjs 7:f93b7eaab5f6 654 }
pegcjs 7:f93b7eaab5f6 655
pegcjs 7:f93b7eaab5f6 656 int setswitch()
pegcjs 7:f93b7eaab5f6 657 {
pegcjs 7:f93b7eaab5f6 658 if(setpoint==0 && depth >(switchdepth+0.5))
pegcjs 7:f93b7eaab5f6 659 {
pegcjs 7:f93b7eaab5f6 660 setpoint=1; // handle switch from low to high
pegcjs 7:f93b7eaab5f6 661 HUD_flash(4);
pegcjs 7:f93b7eaab5f6 662 // flash the hud here
pegcjs 7:f93b7eaab5f6 663 }
pegcjs 7:f93b7eaab5f6 664
pegcjs 7:f93b7eaab5f6 665 if(setpoint==1 && depth < (switchdepth -0.5))
pegcjs 7:f93b7eaab5f6 666 {
pegcjs 7:f93b7eaab5f6 667 setpoint=0; // swtich to low setpoint
pegcjs 7:f93b7eaab5f6 668 HUD_flash(2);
pegcjs 7:f93b7eaab5f6 669 // flash the HUD here
pegcjs 7:f93b7eaab5f6 670 }
pegcjs 7:f93b7eaab5f6 671 }
pegcjs 1:9cff4feccbce 672
pegcjs 1:9cff4feccbce 673 int main() {
pegcjs 2:a1c26faa9103 674 // first some local variables
pegcjs 2:a1c26faa9103 675 int startuptime=getseconds();
pegcjs 4:74df6d31ee0a 676 int startdive=0,endclock=0; // value of seconds when dive starts and counter to decide if dive complete...
pegcjs 1:9cff4feccbce 677
pegcjs 6:ab2d7d0a9b07 678 int minutes=0; // minutes is elapsed minutes since start of prog
pegcjs 7:f93b7eaab5f6 679 int j=0,scount=1;; // general loop counting variable
pegcjs 7:f93b7eaab5f6 680 int sw=0; // status of the switches in the handset
pegcjs 7:f93b7eaab5f6 681 char schars[4]={32,0xd9,0xda,0xfb}; // up arrow, down arrow and both arrows;
pegcjs 6:ab2d7d0a9b07 682
pegcjs 7:f93b7eaab5f6 683 bool mdir=0;
pegcjs 1:9cff4feccbce 684
pegcjs 1:9cff4feccbce 685 set_custom_char(); // does what it says on the tin really
pegcjs 1:9cff4feccbce 686 g_lcd.cls();
pegcjs 1:9cff4feccbce 687 g_lcd.locate(0, 0);
pegcjs 1:9cff4feccbce 688 g_lcd.printf( "RebMon");
pegcjs 1:9cff4feccbce 689 g_lcd.locate(0,1);
pegcjs 1:9cff4feccbce 690 g_lcd.printf("CAL?");
pegcjs 1:9cff4feccbce 691 battery();
pegcjs 4:74df6d31ee0a 692 j=0;
pegcjs 7:f93b7eaab5f6 693 wait(0.2);
pegcjs 7:f93b7eaab5f6 694
pegcjs 6:ab2d7d0a9b07 695 // get cal values last used from local drive
pegcjs 6:ab2d7d0a9b07 696 recall();
pegcjs 6:ab2d7d0a9b07 697 // display the correct scrubber time
pegcjs 7:f93b7eaab5f6 698 scrubtime=scrubold;
pegcjs 1:9cff4feccbce 699 // hang about waiting for the cal switch to be pressed in ccase it is
pegcjs 7:f93b7eaab5f6 700 while (scount<30) {
pegcjs 7:f93b7eaab5f6 701 seconds=getseconds(); // NB if this hangs then nothing works :( - usually means 5V is dodgy
pegcjs 7:f93b7eaab5f6 702 red=1;
pegcjs 7:f93b7eaab5f6 703 green=1;
pegcjs 7:f93b7eaab5f6 704 blue=1; // light all leds
pegcjs 7:f93b7eaab5f6 705
pegcjs 1:9cff4feccbce 706 g_lcd.locate(5,1);
pegcjs 7:f93b7eaab5f6 707 g_lcd.printf("%.2d ",30-scount);
pegcjs 4:74df6d31ee0a 708 if (j>1) flash=1;
pegcjs 3:0d94a277aa8c 709 else flash=0;
pegcjs 1:9cff4feccbce 710 battery(); // bung in battery symbol.
pegcjs 1:9cff4feccbce 711 g_lcd.locate(7,0);
pegcjs 1:9cff4feccbce 712 g_lcd.printf( "%.2d:%.2d:%.2d", hours,min,sec);
pegcjs 7:f93b7eaab5f6 713 // if (CAL==0) {
pegcjs 7:f93b7eaab5f6 714 if(SW1==0) {
pegcjs 1:9cff4feccbce 715 calibrate();
pegcjs 7:f93b7eaab5f6 716 scount=31; // make sure it goes to next frame ok
pegcjs 1:9cff4feccbce 717 }
pegcjs 7:f93b7eaab5f6 718 wait(0.05);
pegcjs 7:f93b7eaab5f6 719
pegcjs 7:f93b7eaab5f6 720
pegcjs 3:0d94a277aa8c 721 j=(j+1) % 4;
pegcjs 7:f93b7eaab5f6 722 if(flash==0) HUD_white();
pegcjs 7:f93b7eaab5f6 723 else HUD_clr();
pegcjs 7:f93b7eaab5f6 724 scount++;
pegcjs 7:f93b7eaab5f6 725 }
pegcjs 1:9cff4feccbce 726 g_lcd.cls();
pegcjs 5:35417986539a 727
pegcjs 1:9cff4feccbce 728
pegcjs 1:9cff4feccbce 729 // ok there are three states in this system
pegcjs 1:9cff4feccbce 730 //MAIN LOOP ONCE STARTUP PROTOCOLS ARE COMPLETED
pegcjs 3:0d94a277aa8c 731 j=0;
pegcjs 7:f93b7eaab5f6 732 g_lcd.cls();
pegcjs 1:9cff4feccbce 733 while (1) {
pegcjs 7:f93b7eaab5f6 734 wait(0.1); //stop screen flicker
pegcjs 1:9cff4feccbce 735 readsensors();
pegcjs 7:f93b7eaab5f6 736 setswitch(); // check the setpoint and adjust if crossing the swtich depth
pegcjs 7:f93b7eaab5f6 737 HUD_display(); // write the HUD codes
pegcjs 2:a1c26faa9103 738 seconds=getseconds();
pegcjs 4:74df6d31ee0a 739 minutes=(int)(((float)seconds-(float)startuptime)/60);
pegcjs 7:f93b7eaab5f6 740 led1=seconds % 2; // flash the onboard led to make it clear stuff is running
pegcjs 3:0d94a277aa8c 741
pegcjs 3:0d94a277aa8c 742 if (j>1) flash=1;
pegcjs 3:0d94a277aa8c 743 else flash=0;
pegcjs 3:0d94a277aa8c 744
pegcjs 3:0d94a277aa8c 745 display(); // write the display
pegcjs 7:f93b7eaab5f6 746 HUD_display(); // write the HUD
pegcjs 7:f93b7eaab5f6 747 // sw=switches(); // read the switches and report their state
pegcjs 7:f93b7eaab5f6 748 // 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 749 // HERE do deco calcs - update tissues and compute desat , nostop or ascent times as required.
pegcjs 3:0d94a277aa8c 750
pegcjs 3:0d94a277aa8c 751 // setup state variable
pegcjs 7:f93b7eaab5f6 752 if (minutes<1) state=0; // startup mode - do nothing just wait to allow sensor readings to settle.
pegcjs 4:74df6d31ee0a 753 if (minutes>=1 && state==0) state=1; // surface mode - ok to go for a dive now
pegcjs 6:ab2d7d0a9b07 754 if (minutes>=1 && depth>0.8 && state==1) {
pegcjs 3:0d94a277aa8c 755 state=2; // enter dive mode
pegcjs 6:ab2d7d0a9b07 756 lp=fopen("/local/divelog.dat","a");
pegcjs 7:f93b7eaab5f6 757 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 758 store_log(); // make a first log entry to catch this erliest part of the dive
pegcjs 4:74df6d31ee0a 759 if (startdive==0) startdive=seconds; // set start of divetime. don't do this twice
pegcjs 3:0d94a277aa8c 760 endclock=0; // reset end of dive clock
pegcjs 3:0d94a277aa8c 761 }
pegcjs 7:f93b7eaab5f6 762 // 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 763 if (state==2) {
pegcjs 7:f93b7eaab5f6 764 // divetime=(int)(((float)seconds-(float)startdive)/60.0); // time since start of dive in minutes.
pegcjs 7:f93b7eaab5f6 765 divetime=(seconds-startdive); // divetime no recorded in seconds since start of dive
pegcjs 7:f93b7eaab5f6 766
pegcjs 3:0d94a277aa8c 767 // do deco calcs here when implemented
pegcjs 7:f93b7eaab5f6 768 if (divetime %15 ==0) store_log(); // this saves the dive profile and sensor optputs in a file called divelog.dat every 15s
pegcjs 7:f93b7eaab5f6 769 if (depth<=0.5) {
pegcjs 4:74df6d31ee0a 770 endclock=endclock+1;
pegcjs 4:74df6d31ee0a 771
pegcjs 6:ab2d7d0a9b07 772 if (endclock>150) {
pegcjs 7:f93b7eaab5f6 773 state=1; // 30s at shallower than 0.3m and we return to surface mode. */
pegcjs 6:ab2d7d0a9b07 774 FILE *fp=fopen("/local/CAL.dat","w");
pegcjs 6:ab2d7d0a9b07 775 fprintf(fp,"%e\n%e\n%e\n%d",eg1cal,eg2cal,pcal,scrubtime);
pegcjs 6:ab2d7d0a9b07 776 fclose(fp); //NB file system locked on write so must make sure we close files in case want to reprogram etc...
pegcjs 7:f93b7eaab5f6 777
pegcjs 7:f93b7eaab5f6 778 store();
pegcjs 6:ab2d7d0a9b07 779 fclose(lp);
pegcjs 7:f93b7eaab5f6 780 } // endif endclock
pegcjs 7:f93b7eaab5f6 781
pegcjs 7:f93b7eaab5f6 782 } // end if depth
pegcjs 7:f93b7eaab5f6 783 scrubtime=scrubold+(divetime/60); //
pegcjs 7:f93b7eaab5f6 784 } // end state 2
pegcjs 1:9cff4feccbce 785
pegcjs 1:9cff4feccbce 786
pegcjs 3:0d94a277aa8c 787 j=(j+1) %4; // flash control variable = used to make the warnings flash for 0.4s duty cycle
pegcjs 7:f93b7eaab5f6 788
pegcjs 7:f93b7eaab5f6 789
pegcjs 7:f93b7eaab5f6 790 vmessage(); // call to generate status message in vertical segment
pegcjs 1:9cff4feccbce 791 } // end while
pegcjs 1:9cff4feccbce 792 } //end main
pegcjs 1:9cff4feccbce 793
pegcjs 1:9cff4feccbce 794
pegcjs 1:9cff4feccbce 795
pegcjs 1:9cff4feccbce 796