![](/media/cache/profiles/7c9a78d4cbeacba4b35f3b445d01f055.50x50_q85.jpg)
Software to drive a monitor unit for a closed circuit rebreather using 3 electrogalvanic oxygen sensor cells run through an amplifier (lm324) . Uses a separate ds1307 clock IC to get timestamp values for logged data.
Dependencies: DS1307 TextOLED_custom mbed
The main electornics is housed in another pod mounted on the back of the unit. I'm using an mbed lpc11u24 to drive everything which comes with a flash drive for data logging built in. It has an external ds1307 clock chip added and a very cheapo lm324 quad op-amp to amplify the o2 sensor signals from the 10s of mV range by 30x so that ppo2=0.21 corresponds to about 0.3V. I still have to do some ADC averaging with this amplifier and do have to calibrate out the individual offsets of the chip but this works ok now that I've worked out which amp is on which adc...
Rebmon_main.cpp@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 |