A code to drive a 3sensor reading unit for monitoring the operation opf a closed circuit rebreather (CCR) with 3 electrogalvanic sensors. Also uses a DS1307 for realtime clock and an MPX5700 to read the depth (mounted inside the breathing loop to keep it 'dry'). circuit diagrams available on rebreather world.
Dependencies: DS1307 TextOLED mbed
Rebmon_main.cpp@6:ab2d7d0a9b07, 2012-08-07 (annotated)
- Committer:
- pegcjs
- Date:
- Tue Aug 07 16:25:18 2012 +0000
- Revision:
- 6:ab2d7d0a9b07
- Parent:
- 5:35417986539a
- Child:
- 7:f93b7eaab5f6
finalised version - ready to build permanent hardware
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
pegcjs | 1:9cff4feccbce | 1 | //lpc1124lcddemo |
pegcjs | 1:9cff4feccbce | 2 | #include "ds1307.h" |
pegcjs | 1:9cff4feccbce | 3 | #include "mbed.h" |
pegcjs | 5:35417986539a | 4 | #include "TextOLED.h" |
pegcjs | 1:9cff4feccbce | 5 | |
pegcjs | 1:9cff4feccbce | 6 | |
pegcjs | 1:9cff4feccbce | 7 | #define METRE 0.02 // change in DEPin for 1m depth |
pegcjs | 1:9cff4feccbce | 8 | |
pegcjs | 1:9cff4feccbce | 9 | //pin assignments and declarations |
pegcjs | 1:9cff4feccbce | 10 | // LCD display |
pegcjs | 1:9cff4feccbce | 11 | TextLCD g_lcd(p26, p25, p24, p23, p22, p21); // RS, E, DB4, DB5, DB6, DB7 |
pegcjs | 1:9cff4feccbce | 12 | //backlight |
pegcjs | 1:9cff4feccbce | 13 | DigitalOut backlight(p29); |
pegcjs | 1:9cff4feccbce | 14 | |
pegcjs | 1:9cff4feccbce | 15 | //onboard leds |
pegcjs | 1:9cff4feccbce | 16 | DigitalOut led1(LED1); |
pegcjs | 1:9cff4feccbce | 17 | DigitalOut led2(LED2); |
pegcjs | 1:9cff4feccbce | 18 | |
pegcjs | 1:9cff4feccbce | 19 | // warning leds |
pegcjs | 1:9cff4feccbce | 20 | DigitalOut red(p34); |
pegcjs | 1:9cff4feccbce | 21 | DigitalOut green(p33); |
pegcjs | 1:9cff4feccbce | 22 | DigitalOut blue(p30); |
pegcjs | 1:9cff4feccbce | 23 | |
pegcjs | 6:ab2d7d0a9b07 | 24 | |
pegcjs | 1:9cff4feccbce | 25 | // switches and buttons - these are pulled up by resistors so are active low |
pegcjs | 1:9cff4feccbce | 26 | DigitalIn CAL(p36); |
pegcjs | 5:35417986539a | 27 | DigitalIn SW1(p35); // reed switch in display unit |
pegcjs | 5:35417986539a | 28 | DigitalIn SW2(p10); // reed switch in dispaly unit |
pegcjs | 5:35417986539a | 29 | DigitalIn MODE(p11);// a switchn on the mbed pcb to select between SCR and CCR modes for the LEDs |
pegcjs | 1:9cff4feccbce | 30 | |
pegcjs | 1:9cff4feccbce | 31 | // log data storage |
pegcjs | 1:9cff4feccbce | 32 | LocalFileSystem local("local"); |
pegcjs | 1:9cff4feccbce | 33 | |
pegcjs | 1:9cff4feccbce | 34 | // adc inputs for sensors |
pegcjs | 1:9cff4feccbce | 35 | AnalogIn PRESin(p20); |
pegcjs | 1:9cff4feccbce | 36 | AnalogIn EG1(p19); |
pegcjs | 1:9cff4feccbce | 37 | AnalogIn EG2(p18); |
pegcjs | 1:9cff4feccbce | 38 | AnalogIn Vbatt(p17); |
pegcjs | 1:9cff4feccbce | 39 | |
pegcjs | 1:9cff4feccbce | 40 | // realtime clock |
pegcjs | 1:9cff4feccbce | 41 | DS1307 my1307(p28,p27); // start DS1307 class and give it pins for connections of the DS1307 device |
pegcjs | 1:9cff4feccbce | 42 | |
pegcjs | 1:9cff4feccbce | 43 | // variables for realtime clock |
pegcjs | 1:9cff4feccbce | 44 | int sec = 0; |
pegcjs | 1:9cff4feccbce | 45 | int min = 0; |
pegcjs | 1:9cff4feccbce | 46 | int hours = 0; |
pegcjs | 1:9cff4feccbce | 47 | int day = 0; |
pegcjs | 1:9cff4feccbce | 48 | int date = 0; |
pegcjs | 1:9cff4feccbce | 49 | int month = 0; |
pegcjs | 1:9cff4feccbce | 50 | int year = 0; |
pegcjs | 4:74df6d31ee0a | 51 | int seconds=0; // general number of seconds since 2000 etc timestamp variable |
pegcjs | 1:9cff4feccbce | 52 | |
pegcjs | 6:ab2d7d0a9b07 | 53 | int scrubtime=0,scrubold=0;; // these are expressed in minutes |
pegcjs | 1:9cff4feccbce | 54 | int divetime=0; |
pegcjs | 1:9cff4feccbce | 55 | |
pegcjs | 3:0d94a277aa8c | 56 | int flash=0; // variable used top control flashing icons |
pegcjs | 2:a1c26faa9103 | 57 | int state=0; // IMPORTANT - VARIABLE THAT DRIVES HNTE STATE MACHINE STATE=0 = STARTUP, STATE=1=SURFACE STATE=2= DIVING |
pegcjs | 2:a1c26faa9103 | 58 | |
pegcjs | 1:9cff4feccbce | 59 | // variables for the eg cells and pressure sensor eg1calamd eg2cal ar reading when the sensor is in 0.21bar O2 and |
pegcjs | 1:9cff4feccbce | 60 | //dcal is the reading whe the pressure sensor is at the surface |
pegcjs | 1:9cff4feccbce | 61 | float eg1cal=0.09,eg2cal=0.09,pcal=0.1136; |
pegcjs | 1:9cff4feccbce | 62 | // NB these are updated from /local/cal.dat so values not so important.... eventually |
pegcjs | 1:9cff4feccbce | 63 | |
pegcjs | 1:9cff4feccbce | 64 | float depth=0,ppo1=0,ppo2=0, Vb=0,pressure=0; // depth, 1st o2 sensor second o2 sensor battery voltage,,Pressure |
pegcjs | 1:9cff4feccbce | 65 | float fo1=0,fo2=0,mod=55; //%f values,mod |
pegcjs | 3:0d94a277aa8c | 66 | |
pegcjs | 6:ab2d7d0a9b07 | 67 | FILE *lp; // file pointer for log file |
pegcjs | 6:ab2d7d0a9b07 | 68 | |
pegcjs | 1:9cff4feccbce | 69 | //===== sub to get time from ds1307 and create the 'seconds' which is a version of timestamp.... |
pegcjs | 1:9cff4feccbce | 70 | int getseconds() { |
pegcjs | 1:9cff4feccbce | 71 | my1307.gettime( &sec, &min, &hours, &day, &date, &month, &year); |
pegcjs | 1:9cff4feccbce | 72 | //simple timestamp = # seconds since midnight jan 1st 2000 if all months were 30 days. |
pegcjs | 4:74df6d31ee0a | 73 | 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 | 74 | //simple timestamp = # seconds since midnight jan 1st 2000 if all months were 30 days.... |
pegcjs | 1:9cff4feccbce | 75 | // ie wrong but simpler than the real thing |
pegcjs | 4:74df6d31ee0a | 76 | return(secondst); |
pegcjs | 1:9cff4feccbce | 77 | } |
pegcjs | 1:9cff4feccbce | 78 | |
pegcjs | 1:9cff4feccbce | 79 | |
pegcjs | 1:9cff4feccbce | 80 | void set_custom_char() { |
pegcjs | 1:9cff4feccbce | 81 | char cgchar[64]={ |
pegcjs | 1:9cff4feccbce | 82 | 6,9,9,9,9,9,9,15, // battery empty symbol 0 |
pegcjs | 1:9cff4feccbce | 83 | 6,9,9,9,9,15,15,15, // battery 50% symbol 1 |
pegcjs | 1:9cff4feccbce | 84 | 6,9,9,15,15,15,15,15, // battery 75% symbol 2 |
pegcjs | 1:9cff4feccbce | 85 | 6,15,15,15,15,15,15,15, // battery 100% symbol 3 |
pegcjs | 1:9cff4feccbce | 86 | 31,19,21,21,21,21,19,31, // diving symbol 4 inverse D |
pegcjs | 1:9cff4feccbce | 87 | 6,6,6,6,6,0,0,6, // warning symbol 5 |
pegcjs | 1:9cff4feccbce | 88 | 31,17,23,17,29,17,31,0, // surface symbol 6 inverse S |
pegcjs | 5:35417986539a | 89 | 2,6,2,2,2,2,23 // defined to handle dec point in depth 7 |
pegcjs | 1:9cff4feccbce | 90 | }; |
pegcjs | 1:9cff4feccbce | 91 | int i=0; |
pegcjs | 1:9cff4feccbce | 92 | // do stuff here to set cstom chars |
pegcjs | 1:9cff4feccbce | 93 | g_lcd.writeCommand(0x40); // set start address for CGRAM |
pegcjs | 1:9cff4feccbce | 94 | for (i=0; i<64; i++) { |
pegcjs | 1:9cff4feccbce | 95 | g_lcd.writeData(cgchar[i]); |
pegcjs | 1:9cff4feccbce | 96 | } |
pegcjs | 1:9cff4feccbce | 97 | |
pegcjs | 1:9cff4feccbce | 98 | } |
pegcjs | 1:9cff4feccbce | 99 | |
pegcjs | 6:ab2d7d0a9b07 | 100 | // stash cal values on local drive |
pegcjs | 6:ab2d7d0a9b07 | 101 | void store() { |
pegcjs | 6:ab2d7d0a9b07 | 102 | FILE *fp=fopen("/local/CAL.dat","w"); |
pegcjs | 6:ab2d7d0a9b07 | 103 | fprintf(fp,"%e\n%e\n%e\n%d",eg1cal,eg2cal,pcal,scrubtime); |
pegcjs | 6:ab2d7d0a9b07 | 104 | fclose(fp); //NB file system locked on write so must make sure we close files in case want to reprogram etc... |
pegcjs | 6:ab2d7d0a9b07 | 105 | } |
pegcjs | 6:ab2d7d0a9b07 | 106 | |
pegcjs | 1:9cff4feccbce | 107 | |
pegcjs | 1:9cff4feccbce | 108 | // subroutine to calibreate o2 sesnors and store ca data in /local/CAL.dat |
pegcjs | 1:9cff4feccbce | 109 | void calibrate() { |
pegcjs | 1:9cff4feccbce | 110 | int count=1; |
pegcjs | 1:9cff4feccbce | 111 | float ppo1=0,ppo2=0,pres=0; |
pegcjs | 1:9cff4feccbce | 112 | // average 20 readings for noise reduction |
pegcjs | 1:9cff4feccbce | 113 | g_lcd.cls(); |
pegcjs | 1:9cff4feccbce | 114 | for (count=20; count>0; count--) { |
pegcjs | 1:9cff4feccbce | 115 | g_lcd.locate(0,0); |
pegcjs | 4:74df6d31ee0a | 116 | g_lcd.printf("Calibrate 21%% %.2d",count); |
pegcjs | 1:9cff4feccbce | 117 | ppo1=ppo1+EG1; |
pegcjs | 1:9cff4feccbce | 118 | ppo2=ppo2+EG2; |
pegcjs | 1:9cff4feccbce | 119 | pres=pres+PRESin; |
pegcjs | 1:9cff4feccbce | 120 | g_lcd.locate(0,1); |
pegcjs | 1:9cff4feccbce | 121 | g_lcd.printf("%1.2f: %1.2f: %1.2f",ppo1/(20-count+1),ppo2/(20-count+1),pres/(20-count+1)); |
pegcjs | 1:9cff4feccbce | 122 | wait(1); |
pegcjs | 1:9cff4feccbce | 123 | } |
pegcjs | 1:9cff4feccbce | 124 | //average |
pegcjs | 1:9cff4feccbce | 125 | ppo1=ppo1/20; |
pegcjs | 1:9cff4feccbce | 126 | ppo2=ppo2/20; |
pegcjs | 1:9cff4feccbce | 127 | // set calibration variables |
pegcjs | 1:9cff4feccbce | 128 | eg1cal=ppo1; |
pegcjs | 1:9cff4feccbce | 129 | eg2cal=ppo2; |
pegcjs | 1:9cff4feccbce | 130 | pcal=pres/20; // surface pressure.... |
pegcjs | 1:9cff4feccbce | 131 | scrubtime=0; // reset the scrubber timer to zero. |
pegcjs | 2:a1c26faa9103 | 132 | // write cal data NB overwites previous |
pegcjs | 6:ab2d7d0a9b07 | 133 | /* FILE *fp=fopen("/local/CAL.dat","w"); |
pegcjs | 6:ab2d7d0a9b07 | 134 | fprintf(fp,"%e\n%e\n%e\n%d",eg1cal,eg2cal,pcal,scrubtime); |
pegcjs | 6:ab2d7d0a9b07 | 135 | fclose(fp); //NB file system locked on write so must make sure we close files in case want to reprogram etc...*/ |
pegcjs | 6:ab2d7d0a9b07 | 136 | store(); |
pegcjs | 1:9cff4feccbce | 137 | } |
pegcjs | 1:9cff4feccbce | 138 | |
pegcjs | 4:74df6d31ee0a | 139 | // sub to test if a variable is an even number |
pegcjs | 4:74df6d31ee0a | 140 | int iseven(int g) { |
pegcjs | 4:74df6d31ee0a | 141 | int test=0; |
pegcjs | 5:35417986539a | 142 | if (g%2 ==0) test=1; |
pegcjs | 4:74df6d31ee0a | 143 | return(test); |
pegcjs | 4:74df6d31ee0a | 144 | } |
pegcjs | 4:74df6d31ee0a | 145 | |
pegcjs | 1:9cff4feccbce | 146 | |
pegcjs | 2:a1c26faa9103 | 147 | void status() { |
pegcjs | 3:0d94a277aa8c | 148 | if (state==0) { |
pegcjs | 3:0d94a277aa8c | 149 | g_lcd.character(9,0,5); // warning icon until 1 min up |
pegcjs | 3:0d94a277aa8c | 150 | g_lcd.character(8,0,6); // surface icon |
pegcjs | 5:35417986539a | 151 | } else { |
pegcjs | 5:35417986539a | 152 | g_lcd.character(9,0,32); |
pegcjs | 3:0d94a277aa8c | 153 | } |
pegcjs | 2:a1c26faa9103 | 154 | if (state==1) g_lcd.character(8,0,6); // surface icon |
pegcjs | 4:74df6d31ee0a | 155 | if (state==2 && iseven(seconds)==1) g_lcd.character(8,0,4); // diving icon |
pegcjs | 4:74df6d31ee0a | 156 | if (state==2 && iseven(seconds)==0) g_lcd.character(8,0,68); // diving icon |
pegcjs | 4:74df6d31ee0a | 157 | |
pegcjs | 4:74df6d31ee0a | 158 | } |
pegcjs | 3:0d94a277aa8c | 159 | |
pegcjs | 3:0d94a277aa8c | 160 | // warning and LED conditions |
pegcjs | 2:a1c26faa9103 | 161 | |
pegcjs | 2:a1c26faa9103 | 162 | void warning() { |
pegcjs | 3:0d94a277aa8c | 163 | if (depth>=mod && flash==1) g_lcd.character(13,0,5); |
pegcjs | 6:ab2d7d0a9b07 | 164 | else g_lcd.character(13,0,32); // blank sapce |
pegcjs | 2:a1c26faa9103 | 165 | |
pegcjs | 2:a1c26faa9103 | 166 | } |
pegcjs | 2:a1c26faa9103 | 167 | |
pegcjs | 4:74df6d31ee0a | 168 | // pick maximum of two values |
pegcjs | 4:74df6d31ee0a | 169 | float maximum(float a,float b) { |
pegcjs | 4:74df6d31ee0a | 170 | float maximum; |
pegcjs | 4:74df6d31ee0a | 171 | if (a>b) maximum=a; |
pegcjs | 4:74df6d31ee0a | 172 | else maximum=b; |
pegcjs | 4:74df6d31ee0a | 173 | return(maximum); |
pegcjs | 4:74df6d31ee0a | 174 | } |
pegcjs | 4:74df6d31ee0a | 175 | |
pegcjs | 4:74df6d31ee0a | 176 | // pick minimum of two values |
pegcjs | 4:74df6d31ee0a | 177 | float minimum(float a,float b) { |
pegcjs | 4:74df6d31ee0a | 178 | float minim; |
pegcjs | 4:74df6d31ee0a | 179 | if (a<b) minim=a; |
pegcjs | 4:74df6d31ee0a | 180 | else minim=b; |
pegcjs | 4:74df6d31ee0a | 181 | return(minim); |
pegcjs | 4:74df6d31ee0a | 182 | } |
pegcjs | 4:74df6d31ee0a | 183 | |
pegcjs | 4:74df6d31ee0a | 184 | |
pegcjs | 4:74df6d31ee0a | 185 | |
pegcjs | 2:a1c26faa9103 | 186 | void leds() { |
pegcjs | 4:74df6d31ee0a | 187 | // first turn everything off |
pegcjs | 5:35417986539a | 188 | red=0; |
pegcjs | 5:35417986539a | 189 | green=0; |
pegcjs | 5:35417986539a | 190 | blue=0; |
pegcjs | 5:35417986539a | 191 | float ppo; |
pegcjs | 5:35417986539a | 192 | int mo=0; |
pegcjs | 5:35417986539a | 193 | mo=MODE; |
pegcjs | 5:35417986539a | 194 | ppo=maximum(ppo1,ppo2); // use max value to compute leds... |
pegcjs | 5:35417986539a | 195 | if (mo==0) { // CCR mode |
pegcjs | 5:35417986539a | 196 | if (ppo<0.2 && flash==1) red=1; // flashing red means very bad things - getting low on oxygen!!! |
pegcjs | 5:35417986539a | 197 | if (ppo>0.2 && ppo < 1) red=1; // non-flashing red |
pegcjs | 5:35417986539a | 198 | if (ppo>=1.0 && ppo <1.2) { |
pegcjs | 5:35417986539a | 199 | red=1; // red-green |
pegcjs | 5:35417986539a | 200 | green=1; |
pegcjs | 5:35417986539a | 201 | } |
pegcjs | 5:35417986539a | 202 | if (ppo<1.3 && ppo >=1.2) green=1; // green - optimal range in ccr mode |
pegcjs | 5:35417986539a | 203 | if (ppo<1.4 && ppo >=1.3) { |
pegcjs | 5:35417986539a | 204 | green=1; // green-blue - high ppo2 be careful of spiking |
pegcjs | 5:35417986539a | 205 | blue=1; |
pegcjs | 5:35417986539a | 206 | } |
pegcjs | 5:35417986539a | 207 | if (ppo2<1.6 && ppo2>=1.4) blue=1; // DANGE ble high ppo2 |
pegcjs | 5:35417986539a | 208 | if (ppo2>=1.6 && flash==1) blue=1; |
pegcjs | 5:35417986539a | 209 | } |
pegcjs | 5:35417986539a | 210 | if (mo==1) { // SCR mode |
pegcjs | 5:35417986539a | 211 | if (ppo<0.2 && flash==1) red=1; |
pegcjs | 6:ab2d7d0a9b07 | 212 | if(ppo2>=0.2 && ppo2 <0.26) red=1; // will give green red for low but not lethal ppo2s |
pegcjs | 5:35417986539a | 213 | if (depth < 0.8*mod && ppo>0.2) green=1; |
pegcjs | 5:35417986539a | 214 | if (depth< mod && depth >=0.8*mod) { |
pegcjs | 5:35417986539a | 215 | green=1; |
pegcjs | 5:35417986539a | 216 | blue=1; |
pegcjs | 5:35417986539a | 217 | } |
pegcjs | 5:35417986539a | 218 | if (depth >=mod && flash==1) blue=1; |
pegcjs | 5:35417986539a | 219 | } |
pegcjs | 6:ab2d7d0a9b07 | 220 | |
pegcjs | 1:9cff4feccbce | 221 | } |
pegcjs | 1:9cff4feccbce | 222 | |
pegcjs | 4:74df6d31ee0a | 223 | |
pegcjs | 4:74df6d31ee0a | 224 | |
pegcjs | 1:9cff4feccbce | 225 | //read battery state and insert the battery symbol |
pegcjs | 1:9cff4feccbce | 226 | void battery() { |
pegcjs | 1:9cff4feccbce | 227 | int batsym=0; |
pegcjs | 1:9cff4feccbce | 228 | Vb=Vbatt; // read adc connected to battery via a 1/3 potential divider |
pegcjs | 1:9cff4feccbce | 229 | if (Vb>0.606) batsym=1; |
pegcjs | 1:9cff4feccbce | 230 | if (Vb>0.707) batsym=2; |
pegcjs | 1:9cff4feccbce | 231 | if (Vb>0.808) batsym=3; |
pegcjs | 3:0d94a277aa8c | 232 | if (batsym >0) g_lcd.character(8,1,batsym); |
pegcjs | 3:0d94a277aa8c | 233 | if (batsym ==0 && flash==1) g_lcd.character(8,1,batsym); |
pegcjs | 3:0d94a277aa8c | 234 | if (batsym ==0 && flash==0) g_lcd.character(8,1,32); |
pegcjs | 1:9cff4feccbce | 235 | } |
pegcjs | 1:9cff4feccbce | 236 | |
pegcjs | 2:a1c26faa9103 | 237 | // subroutine to write the main display data |
pegcjs | 2:a1c26faa9103 | 238 | //0123456789abcdef |
pegcjs | 2:a1c26faa9103 | 239 | |
pegcjs | 2:a1c26faa9103 | 240 | //x.xx:xx D XX xx |
pegcjs | 2:a1c26faa9103 | 241 | //x.xx:xx B XX xxx NB the warning, staus and battery icons are driven by separate subroutines. |
pegcjs | 2:a1c26faa9103 | 242 | void display() { |
pegcjs | 5:35417986539a | 243 | int mo=0; |
pegcjs | 5:35417986539a | 244 | mo=MODE; |
pegcjs | 2:a1c26faa9103 | 245 | //1st line |
pegcjs | 2:a1c26faa9103 | 246 | g_lcd.locate(0,0); |
pegcjs | 5:35417986539a | 247 | g_lcd.printf("%1.2f:%.2d",ppo1,(int)fo1); |
pegcjs | 5:35417986539a | 248 | g_lcd.locate(10,0); |
pegcjs | 6:ab2d7d0a9b07 | 249 | g_lcd.printf("%.2d",(int)depth); |
pegcjs | 6:ab2d7d0a9b07 | 250 | g_lcd.locate(14,0); |
pegcjs | 6:ab2d7d0a9b07 | 251 | g_lcd.printf("%.2d",(int)mod); |
pegcjs | 2:a1c26faa9103 | 252 | //2nd line |
pegcjs | 2:a1c26faa9103 | 253 | g_lcd.locate(0,1); |
pegcjs | 5:35417986539a | 254 | g_lcd.printf("%1.2f:%.2d",ppo2,(int)fo2); |
pegcjs | 5:35417986539a | 255 | g_lcd.locate(10,1); |
pegcjs | 5:35417986539a | 256 | g_lcd.printf("%.2d %.3d",divetime % 100 ,scrubtime % 1000); // modulo to avoid digits conflict - means divetime is always less than 100 |
pegcjs | 2:a1c26faa9103 | 257 | // bung in battery icon |
pegcjs | 2:a1c26faa9103 | 258 | battery(); |
pegcjs | 5:35417986539a | 259 | status(); // this will set the diving / suface mode icon |
pegcjs | 2:a1c26faa9103 | 260 | warning(); // this will set the warning icon assuming that max ppo2 is exceeded |
pegcjs | 2:a1c26faa9103 | 261 | |
pegcjs | 2:a1c26faa9103 | 262 | leds(); // this sets the leds according to the various warning conditions |
pegcjs | 5:35417986539a | 263 | if (mo==0) { |
pegcjs | 5:35417986539a | 264 | g_lcd.character(7,1,99); //'c' = ccr |
pegcjs | 5:35417986539a | 265 | } else { |
pegcjs | 5:35417986539a | 266 | g_lcd.character(7,1,115); //'s' = scr |
pegcjs | 5:35417986539a | 267 | } |
pegcjs | 5:35417986539a | 268 | // custom character setting to sort out dp in depths |
pegcjs | 6:ab2d7d0a9b07 | 269 | |
pegcjs | 6:ab2d7d0a9b07 | 270 | |
pegcjs | 5:35417986539a | 271 | char cgchar[80]={ |
pegcjs | 5:35417986539a | 272 | 7,5,5,5,23,0,0,0, // .0 |
pegcjs | 5:35417986539a | 273 | 2,2,2,2,18,0,0,0, // .1 |
pegcjs | 5:35417986539a | 274 | 7,1,7,4,23,0,0,0, // 0.2 |
pegcjs | 5:35417986539a | 275 | 7,1,3,1,23,0,0,0, // 0.3 |
pegcjs | 5:35417986539a | 276 | 5,5,7,1,17,0,0,0, //0.4 |
pegcjs | 5:35417986539a | 277 | 7,4,7,1,23,0,0,0, //0.5 |
pegcjs | 5:35417986539a | 278 | 7,4,7,5,23,0,0,0, //0.6 |
pegcjs | 5:35417986539a | 279 | 7,1,2,2,18,0,0,0, //.7 |
pegcjs | 5:35417986539a | 280 | 7,5,7,5,23,0,0,0, //.8 |
pegcjs | 5:35417986539a | 281 | 7,5,7,1,17,0,0,0 //.9 |
pegcjs | 5:35417986539a | 282 | |
pegcjs | 5:35417986539a | 283 | }; |
pegcjs | 5:35417986539a | 284 | |
pegcjs | 5:35417986539a | 285 | int i=0,d=0; |
pegcjs | 5:35417986539a | 286 | d=(int)((depth-(int)depth)*10); // should be size of the 1st decimal place |
pegcjs | 5:35417986539a | 287 | // do stuff here to set cstom chars |
pegcjs | 5:35417986539a | 288 | g_lcd.writeCommand(120); // set start address for CGRAM |
pegcjs | 5:35417986539a | 289 | for (i=0; i<8; i++) { |
pegcjs | 5:35417986539a | 290 | g_lcd.writeData(cgchar[i+d*8]); |
pegcjs | 5:35417986539a | 291 | } |
pegcjs | 5:35417986539a | 292 | |
pegcjs | 5:35417986539a | 293 | g_lcd.character(12,0,7); // put in appropriate custom character |
pegcjs | 2:a1c26faa9103 | 294 | |
pegcjs | 2:a1c26faa9103 | 295 | } |
pegcjs | 2:a1c26faa9103 | 296 | |
pegcjs | 2:a1c26faa9103 | 297 | |
pegcjs | 2:a1c26faa9103 | 298 | |
pegcjs | 1:9cff4feccbce | 299 | |
pegcjs | 2:a1c26faa9103 | 300 | |
pegcjs | 2:a1c26faa9103 | 301 | // read sensors and generate calibrated outputs NB battery is read elsewhere |
pegcjs | 1:9cff4feccbce | 302 | void readsensors() { |
pegcjs | 1:9cff4feccbce | 303 | float barometric=0,mod1,mod2; |
pegcjs | 1:9cff4feccbce | 304 | ppo1=EG1*0.21/eg1cal; // eg1cal is 0.21bar ppO2 |
pegcjs | 1:9cff4feccbce | 305 | ppo2=EG2*0.21/eg2cal; // second oxygen cell ppO2 |
pegcjs | 5:35417986539a | 306 | // NB this assumes that the calibration is done at exactly 1 bar.... - not always the case but ok for sea level diving |
pegcjs | 2:a1c26faa9103 | 307 | pressure=(PRESin*3.3-0.024)/(0.0038574); // pressure in kPa assuming standard cal for mpx5700 sensor SUSPECT |
pegcjs | 5:35417986539a | 308 | barometric=(pcal*3.3-0.024)/(0.0038574); // sealevel in kPa assuming standard cal for mpx5700 sensor |
pegcjs | 6:ab2d7d0a9b07 | 309 | |
pegcjs | 5:35417986539a | 310 | depth=(pressure-barometric)*0.1; //100kPa=10m 1kPa=0.1m - this gives depth in m for freshwater. |
pegcjs | 6:ab2d7d0a9b07 | 311 | if (depth<0) depth=0; |
pegcjs | 2:a1c26faa9103 | 312 | |
pegcjs | 5:35417986539a | 313 | fo1=100*ppo1/((pressure-barometric)/100+1); // pressure in bar = pressure /100 and want a % so multiply by 100 as well |
pegcjs | 5:35417986539a | 314 | fo2=100*ppo2/((pressure-barometric)/100+1); |
pegcjs | 6:ab2d7d0a9b07 | 315 | |
pegcjs | 6:ab2d7d0a9b07 | 316 | if (fo1<0) fo2=0; |
pegcjs | 6:ab2d7d0a9b07 | 317 | if (fo2<0) fo1=0; |
pegcjs | 3:0d94a277aa8c | 318 | |
pegcjs | 5:35417986539a | 319 | //with two sensors will calculate mod from the largest ppo2 reading |
pegcjs | 2:a1c26faa9103 | 320 | mod1=(1.4/(fo1/100)-1)*10; |
pegcjs | 2:a1c26faa9103 | 321 | mod2=(1.4/(fo2/100)-1)*10; |
pegcjs | 3:0d94a277aa8c | 322 | |
pegcjs | 2:a1c26faa9103 | 323 | mod=minimum(mod1,mod2); // pick the least value |
pegcjs | 3:0d94a277aa8c | 324 | |
pegcjs | 1:9cff4feccbce | 325 | } |
pegcjs | 6:ab2d7d0a9b07 | 326 | // get values back from cal file on local drive |
pegcjs | 6:ab2d7d0a9b07 | 327 | void recall() { |
pegcjs | 6:ab2d7d0a9b07 | 328 | FILE *fp=fopen("/local/CAL.dat","r"); |
pegcjs | 6:ab2d7d0a9b07 | 329 | fscanf(fp,"%e\n%e\n%e\n%d",&eg1cal,&eg2cal,&pcal,&scrubold); |
pegcjs | 6:ab2d7d0a9b07 | 330 | fclose(fp); //NB file system locked on write so must make sure we close files in case want to reprogram etc... |
pegcjs | 6:ab2d7d0a9b07 | 331 | } |
pegcjs | 6:ab2d7d0a9b07 | 332 | |
pegcjs | 6:ab2d7d0a9b07 | 333 | // write the logfile opened and closed by start and end of dive |
pegcjs | 6:ab2d7d0a9b07 | 334 | void store_log() { |
pegcjs | 6:ab2d7d0a9b07 | 335 | Vb=Vbatt; |
pegcjs | 6:ab2d7d0a9b07 | 336 | //FILE *fp=fopen("/local/divelog.dat","a"); |
pegcjs | 6:ab2d7d0a9b07 | 337 | fprintf(lp,"%d\t%e\t%e\t%e\t%e\t%d\n",seconds,depth,ppo1,ppo2,Vb,scrubtime); |
pegcjs | 6:ab2d7d0a9b07 | 338 | // fclose(fp); |
pegcjs | 6:ab2d7d0a9b07 | 339 | } |
pegcjs | 4:74df6d31ee0a | 340 | |
pegcjs | 1:9cff4feccbce | 341 | |
pegcjs | 1:9cff4feccbce | 342 | int main() { |
pegcjs | 2:a1c26faa9103 | 343 | // first some local variables |
pegcjs | 2:a1c26faa9103 | 344 | int startuptime=getseconds(); |
pegcjs | 4:74df6d31ee0a | 345 | int startdive=0,endclock=0; // value of seconds when dive starts and counter to decide if dive complete... |
pegcjs | 1:9cff4feccbce | 346 | |
pegcjs | 6:ab2d7d0a9b07 | 347 | int minutes=0; // minutes is elapsed minutes since start of prog |
pegcjs | 6:ab2d7d0a9b07 | 348 | int j=0; // general loop counting variable |
pegcjs | 6:ab2d7d0a9b07 | 349 | |
pegcjs | 1:9cff4feccbce | 350 | |
pegcjs | 1:9cff4feccbce | 351 | |
pegcjs | 1:9cff4feccbce | 352 | set_custom_char(); // does what it says on the tin really |
pegcjs | 1:9cff4feccbce | 353 | g_lcd.cls(); |
pegcjs | 1:9cff4feccbce | 354 | g_lcd.locate(0, 0); |
pegcjs | 1:9cff4feccbce | 355 | g_lcd.printf( "RebMon"); |
pegcjs | 1:9cff4feccbce | 356 | g_lcd.locate(0,1); |
pegcjs | 1:9cff4feccbce | 357 | g_lcd.printf("CAL?"); |
pegcjs | 1:9cff4feccbce | 358 | battery(); |
pegcjs | 4:74df6d31ee0a | 359 | j=0; |
pegcjs | 6:ab2d7d0a9b07 | 360 | // get cal values last used from local drive |
pegcjs | 6:ab2d7d0a9b07 | 361 | recall(); |
pegcjs | 6:ab2d7d0a9b07 | 362 | // display the correct scrubber time |
pegcjs | 6:ab2d7d0a9b07 | 363 | scrubtime=scrubtime+scrubold; |
pegcjs | 1:9cff4feccbce | 364 | // hang about waiting for the cal switch to be pressed in ccase it is |
pegcjs | 1:9cff4feccbce | 365 | while (seconds-startuptime<20) { |
pegcjs | 1:9cff4feccbce | 366 | seconds=getseconds(); |
pegcjs | 1:9cff4feccbce | 367 | g_lcd.locate(5,1); |
pegcjs | 1:9cff4feccbce | 368 | g_lcd.printf("%.2d",21-(seconds-startuptime)); |
pegcjs | 4:74df6d31ee0a | 369 | if (j>1) flash=1; |
pegcjs | 3:0d94a277aa8c | 370 | else flash=0; |
pegcjs | 1:9cff4feccbce | 371 | battery(); // bung in battery symbol. |
pegcjs | 1:9cff4feccbce | 372 | g_lcd.locate(7,0); |
pegcjs | 1:9cff4feccbce | 373 | g_lcd.printf( "%.2d:%.2d:%.2d", hours,min,sec); |
pegcjs | 1:9cff4feccbce | 374 | if (CAL==0) { |
pegcjs | 1:9cff4feccbce | 375 | calibrate(); |
pegcjs | 1:9cff4feccbce | 376 | |
pegcjs | 1:9cff4feccbce | 377 | } |
pegcjs | 3:0d94a277aa8c | 378 | wait(0.2); |
pegcjs | 3:0d94a277aa8c | 379 | j=(j+1) % 4; |
pegcjs | 1:9cff4feccbce | 380 | } |
pegcjs | 1:9cff4feccbce | 381 | g_lcd.cls(); |
pegcjs | 5:35417986539a | 382 | |
pegcjs | 1:9cff4feccbce | 383 | |
pegcjs | 1:9cff4feccbce | 384 | // ok there are three states in this system |
pegcjs | 1:9cff4feccbce | 385 | //MAIN LOOP ONCE STARTUP PROTOCOLS ARE COMPLETED |
pegcjs | 3:0d94a277aa8c | 386 | j=0; |
pegcjs | 1:9cff4feccbce | 387 | while (1) { |
pegcjs | 2:a1c26faa9103 | 388 | wait(0.2); //stop screen flicker |
pegcjs | 1:9cff4feccbce | 389 | readsensors(); |
pegcjs | 2:a1c26faa9103 | 390 | seconds=getseconds(); |
pegcjs | 4:74df6d31ee0a | 391 | minutes=(int)(((float)seconds-(float)startuptime)/60); |
pegcjs | 6:ab2d7d0a9b07 | 392 | |
pegcjs | 3:0d94a277aa8c | 393 | |
pegcjs | 3:0d94a277aa8c | 394 | if (j>1) flash=1; |
pegcjs | 3:0d94a277aa8c | 395 | else flash=0; |
pegcjs | 3:0d94a277aa8c | 396 | |
pegcjs | 3:0d94a277aa8c | 397 | display(); // write the display |
pegcjs | 3:0d94a277aa8c | 398 | |
pegcjs | 3:0d94a277aa8c | 399 | // setup state variable |
pegcjs | 3:0d94a277aa8c | 400 | if (minutes<1) state=0; // startup mode - do nothing just wait to allow sensor readings to settle. |
pegcjs | 4:74df6d31ee0a | 401 | if (minutes>=1 && state==0) state=1; // surface mode - ok to go for a dive now |
pegcjs | 6:ab2d7d0a9b07 | 402 | if (minutes>=1 && depth>0.8 && state==1) { |
pegcjs | 3:0d94a277aa8c | 403 | state=2; // enter dive mode |
pegcjs | 6:ab2d7d0a9b07 | 404 | lp=fopen("/local/divelog.dat","a"); |
pegcjs | 4:74df6d31ee0a | 405 | if (startdive==0) startdive=seconds; // set start of divetime. don't do this twice |
pegcjs | 3:0d94a277aa8c | 406 | endclock=0; // reset end of dive clock |
pegcjs | 3:0d94a277aa8c | 407 | } |
pegcjs | 3:0d94a277aa8c | 408 | if (state==2) { |
pegcjs | 4:74df6d31ee0a | 409 | divetime=(int)(((float)seconds-(float)startdive)/60); // time since start of dive in minutes. |
pegcjs | 3:0d94a277aa8c | 410 | // do deco calcs here when implemented |
pegcjs | 6:ab2d7d0a9b07 | 411 | if ((seconds-startdive) %15 ==0) store_log(); // this saves the dive profile and sensor optputs in a file called divelog.dat every 15s |
pegcjs | 6:ab2d7d0a9b07 | 412 | if (depth<=0.3) { |
pegcjs | 4:74df6d31ee0a | 413 | endclock=endclock+1; |
pegcjs | 4:74df6d31ee0a | 414 | |
pegcjs | 6:ab2d7d0a9b07 | 415 | if (endclock>150) { |
pegcjs | 6:ab2d7d0a9b07 | 416 | state=1; // 30s at shallower than 0.3m and we return to surface mode. |
pegcjs | 6:ab2d7d0a9b07 | 417 | FILE *fp=fopen("/local/CAL.dat","w"); |
pegcjs | 6:ab2d7d0a9b07 | 418 | fprintf(fp,"%e\n%e\n%e\n%d",eg1cal,eg2cal,pcal,scrubtime); |
pegcjs | 6:ab2d7d0a9b07 | 419 | fclose(fp); //NB file system locked on write so must make sure we close files in case want to reprogram etc... |
pegcjs | 6:ab2d7d0a9b07 | 420 | fclose(lp); |
pegcjs | 6:ab2d7d0a9b07 | 421 | } |
pegcjs | 3:0d94a277aa8c | 422 | } |
pegcjs | 6:ab2d7d0a9b07 | 423 | scrubtime=scrubold+divetime; // |
pegcjs | 3:0d94a277aa8c | 424 | } |
pegcjs | 1:9cff4feccbce | 425 | |
pegcjs | 1:9cff4feccbce | 426 | |
pegcjs | 3:0d94a277aa8c | 427 | j=(j+1) %4; // flash control variable = used to make the warnings flash for 0.4s duty cycle |
pegcjs | 1:9cff4feccbce | 428 | } // end while |
pegcjs | 1:9cff4feccbce | 429 | } //end main |
pegcjs | 1:9cff4feccbce | 430 | |
pegcjs | 1:9cff4feccbce | 431 | |
pegcjs | 1:9cff4feccbce | 432 | |
pegcjs | 1:9cff4feccbce | 433 |