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:
Thu Aug 02 16:05:46 2012 +0000
Revision:
2:a1c26faa9103
Parent:
1:9cff4feccbce
Child:
3:0d94a277aa8c
basic functions implemented - no backup readout for cal values or any logging. no leds or warnings setup.; need to restrict fo2 to avoid >100% issue and prevent negative depths...

Who changed what in which revision?

UserRevisionLine numberNew contents of line
pegcjs 1:9cff4feccbce 1 //lpc1124lcddemo
pegcjs 1:9cff4feccbce 2 #include "ds1307.h"
pegcjs 1:9cff4feccbce 3 #include "mbed.h"
pegcjs 1:9cff4feccbce 4 #include "TextLCD.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 1:9cff4feccbce 24 // switches and buttons - these are pulled up by resistors so are active low
pegcjs 1:9cff4feccbce 25 DigitalIn CAL(p36);
pegcjs 1:9cff4feccbce 26 DigitalIn SW1(p35);
pegcjs 1:9cff4feccbce 27
pegcjs 1:9cff4feccbce 28 // log data storage
pegcjs 1:9cff4feccbce 29 LocalFileSystem local("local");
pegcjs 1:9cff4feccbce 30
pegcjs 1:9cff4feccbce 31 // adc inputs for sensors
pegcjs 1:9cff4feccbce 32 AnalogIn PRESin(p20);
pegcjs 1:9cff4feccbce 33 AnalogIn EG1(p19);
pegcjs 1:9cff4feccbce 34 AnalogIn EG2(p18);
pegcjs 1:9cff4feccbce 35 AnalogIn Vbatt(p17);
pegcjs 1:9cff4feccbce 36
pegcjs 1:9cff4feccbce 37 // realtime clock
pegcjs 1:9cff4feccbce 38 DS1307 my1307(p28,p27); // start DS1307 class and give it pins for connections of the DS1307 device
pegcjs 1:9cff4feccbce 39
pegcjs 1:9cff4feccbce 40 // variables for realtime clock
pegcjs 1:9cff4feccbce 41 int sec = 0;
pegcjs 1:9cff4feccbce 42 int min = 0;
pegcjs 1:9cff4feccbce 43 int hours = 0;
pegcjs 1:9cff4feccbce 44 int day = 0;
pegcjs 1:9cff4feccbce 45 int date = 0;
pegcjs 1:9cff4feccbce 46 int month = 0;
pegcjs 1:9cff4feccbce 47 int year = 0;
pegcjs 1:9cff4feccbce 48
pegcjs 1:9cff4feccbce 49 int scrubtime=0; // these are expressed in minutes
pegcjs 1:9cff4feccbce 50 int divetime=0;
pegcjs 1:9cff4feccbce 51
pegcjs 2:a1c26faa9103 52
pegcjs 2:a1c26faa9103 53 int state=0; // IMPORTANT - VARIABLE THAT DRIVES HNTE STATE MACHINE STATE=0 = STARTUP, STATE=1=SURFACE STATE=2= DIVING
pegcjs 2:a1c26faa9103 54
pegcjs 1:9cff4feccbce 55 // variables for the eg cells and pressure sensor eg1calamd eg2cal ar reading when the sensor is in 0.21bar O2 and
pegcjs 1:9cff4feccbce 56 //dcal is the reading whe the pressure sensor is at the surface
pegcjs 1:9cff4feccbce 57 float eg1cal=0.09,eg2cal=0.09,pcal=0.1136;
pegcjs 1:9cff4feccbce 58 // NB these are updated from /local/cal.dat so values not so important.... eventually
pegcjs 1:9cff4feccbce 59
pegcjs 1:9cff4feccbce 60 float depth=0,ppo1=0,ppo2=0, Vb=0,pressure=0; // depth, 1st o2 sensor second o2 sensor battery voltage,,Pressure
pegcjs 1:9cff4feccbce 61 float fo1=0,fo2=0,mod=55; //%f values,mod
pegcjs 1:9cff4feccbce 62 //===== sub to get time from ds1307 and create the 'seconds' which is a version of timestamp....
pegcjs 1:9cff4feccbce 63 int getseconds() {
pegcjs 1:9cff4feccbce 64 my1307.gettime( &sec, &min, &hours, &day, &date, &month, &year);
pegcjs 1:9cff4feccbce 65 //simple timestamp = # seconds since midnight jan 1st 2000 if all months were 30 days.
pegcjs 1:9cff4feccbce 66 int seconds=year*365*24*60*60+month*30*24*60*60+day*24*60*60+hours*60*60+min*60+sec;
pegcjs 1:9cff4feccbce 67 //simple timestamp = # seconds since midnight jan 1st 2000 if all months were 30 days....
pegcjs 1:9cff4feccbce 68 // ie wrong but simpler than the real thing
pegcjs 1:9cff4feccbce 69 return(seconds);
pegcjs 1:9cff4feccbce 70 }
pegcjs 1:9cff4feccbce 71
pegcjs 1:9cff4feccbce 72
pegcjs 1:9cff4feccbce 73 void set_custom_char() {
pegcjs 1:9cff4feccbce 74 char cgchar[64]={
pegcjs 1:9cff4feccbce 75 6,9,9,9,9,9,9,15, // battery empty symbol 0
pegcjs 1:9cff4feccbce 76 6,9,9,9,9,15,15,15, // battery 50% symbol 1
pegcjs 1:9cff4feccbce 77 6,9,9,15,15,15,15,15, // battery 75% symbol 2
pegcjs 1:9cff4feccbce 78 6,15,15,15,15,15,15,15, // battery 100% symbol 3
pegcjs 1:9cff4feccbce 79 31,19,21,21,21,21,19,31, // diving symbol 4 inverse D
pegcjs 1:9cff4feccbce 80 6,6,6,6,6,0,0,6, // warning symbol 5
pegcjs 1:9cff4feccbce 81 31,17,23,17,29,17,31,0, // surface symbol 6 inverse S
pegcjs 2:a1c26faa9103 82 0,0,17,17,0,17,14,0 // happy symbol 7
pegcjs 1:9cff4feccbce 83 };
pegcjs 1:9cff4feccbce 84 int i=0;
pegcjs 1:9cff4feccbce 85 // do stuff here to set cstom chars
pegcjs 1:9cff4feccbce 86 g_lcd.writeCommand(0x40); // set start address for CGRAM
pegcjs 1:9cff4feccbce 87 for (i=0; i<64; i++) {
pegcjs 1:9cff4feccbce 88 g_lcd.writeData(cgchar[i]);
pegcjs 1:9cff4feccbce 89 }
pegcjs 1:9cff4feccbce 90
pegcjs 1:9cff4feccbce 91 }
pegcjs 1:9cff4feccbce 92
pegcjs 1:9cff4feccbce 93
pegcjs 1:9cff4feccbce 94 // subroutine to calibreate o2 sesnors and store ca data in /local/CAL.dat
pegcjs 1:9cff4feccbce 95 void calibrate() {
pegcjs 1:9cff4feccbce 96 int count=1;
pegcjs 1:9cff4feccbce 97 float ppo1=0,ppo2=0,pres=0;
pegcjs 1:9cff4feccbce 98 // average 20 readings for noise reduction
pegcjs 1:9cff4feccbce 99 g_lcd.cls();
pegcjs 1:9cff4feccbce 100 for (count=20; count>0; count--) {
pegcjs 1:9cff4feccbce 101 g_lcd.locate(0,0);
pegcjs 1:9cff4feccbce 102 g_lcd.printf("Calibrating %.2d",count);
pegcjs 1:9cff4feccbce 103 ppo1=ppo1+EG1;
pegcjs 1:9cff4feccbce 104 ppo2=ppo2+EG2;
pegcjs 1:9cff4feccbce 105 pres=pres+PRESin;
pegcjs 1:9cff4feccbce 106 g_lcd.locate(0,1);
pegcjs 1:9cff4feccbce 107 g_lcd.printf("%1.2f: %1.2f: %1.2f",ppo1/(20-count+1),ppo2/(20-count+1),pres/(20-count+1));
pegcjs 1:9cff4feccbce 108 wait(1);
pegcjs 1:9cff4feccbce 109 }
pegcjs 1:9cff4feccbce 110 //average
pegcjs 1:9cff4feccbce 111 ppo1=ppo1/20;
pegcjs 1:9cff4feccbce 112 ppo2=ppo2/20;
pegcjs 1:9cff4feccbce 113 // set calibration variables
pegcjs 1:9cff4feccbce 114 eg1cal=ppo1;
pegcjs 1:9cff4feccbce 115 eg2cal=ppo2;
pegcjs 1:9cff4feccbce 116 pcal=pres/20; // surface pressure....
pegcjs 1:9cff4feccbce 117 scrubtime=0; // reset the scrubber timer to zero.
pegcjs 2:a1c26faa9103 118 // write cal data NB overwites previous
pegcjs 2:a1c26faa9103 119 FILE *fp=fopen("/local/CAL.dat","w");
pegcjs 2:a1c26faa9103 120 fprintf(fp,"%e\n%e\n%e\n%d",eg1cal,eg2cal,pcal,scrubtime);
pegcjs 2:a1c26faa9103 121 fclose(fp); //NB file system locked on write so must make sure we close files in case want to reprogram etc...
pegcjs 1:9cff4feccbce 122 }
pegcjs 1:9cff4feccbce 123
pegcjs 1:9cff4feccbce 124
pegcjs 2:a1c26faa9103 125 void status() {
pegcjs 2:a1c26faa9103 126 if (state==0) g_lcd.character(8,0,5); // warning icon until 1 min up
pegcjs 2:a1c26faa9103 127 if (state==1) g_lcd.character(8,0,6); // surface icon
pegcjs 2:a1c26faa9103 128 if (state==2) g_lcd.character(8,0,4); // diving icon
pegcjs 2:a1c26faa9103 129 }
pegcjs 2:a1c26faa9103 130
pegcjs 2:a1c26faa9103 131 void warning() {
pegcjs 2:a1c26faa9103 132
pegcjs 2:a1c26faa9103 133 }
pegcjs 2:a1c26faa9103 134
pegcjs 2:a1c26faa9103 135 void leds() {
pegcjs 1:9cff4feccbce 136 }
pegcjs 1:9cff4feccbce 137
pegcjs 1:9cff4feccbce 138 //read battery state and insert the battery symbol
pegcjs 1:9cff4feccbce 139 void battery() {
pegcjs 1:9cff4feccbce 140 int batsym=0;
pegcjs 1:9cff4feccbce 141 Vb=Vbatt; // read adc connected to battery via a 1/3 potential divider
pegcjs 1:9cff4feccbce 142 if (Vb>0.606) batsym=1;
pegcjs 1:9cff4feccbce 143 if (Vb>0.707) batsym=2;
pegcjs 1:9cff4feccbce 144 if (Vb>0.808) batsym=3;
pegcjs 1:9cff4feccbce 145 g_lcd.character(8,1,batsym);
pegcjs 1:9cff4feccbce 146 }
pegcjs 1:9cff4feccbce 147
pegcjs 2:a1c26faa9103 148 // subroutine to write the main display data
pegcjs 2:a1c26faa9103 149 //0123456789abcdef
pegcjs 2:a1c26faa9103 150
pegcjs 2:a1c26faa9103 151 //x.xx:xx D XX xx
pegcjs 2:a1c26faa9103 152 //x.xx:xx B XX xxx NB the warning, staus and battery icons are driven by separate subroutines.
pegcjs 2:a1c26faa9103 153 void display() {
pegcjs 2:a1c26faa9103 154 //1st line
pegcjs 2:a1c26faa9103 155 g_lcd.locate(0,0);
pegcjs 2:a1c26faa9103 156 g_lcd.printf("%1.2f:%.2d %.2d %.2d",ppo1,(int)fo1,(int)depth,(int)mod);
pegcjs 2:a1c26faa9103 157 //2nd line
pegcjs 2:a1c26faa9103 158 g_lcd.locate(0,1);
pegcjs 2:a1c26faa9103 159 g_lcd.printf("%1.2f:%.2d %.2d %.2d",ppo2,(int)fo2,divetime,scrubtime);
pegcjs 2:a1c26faa9103 160 // bung in battery icon
pegcjs 2:a1c26faa9103 161 battery();
pegcjs 2:a1c26faa9103 162 status(); // this will set the diviong / suface mode icon
pegcjs 2:a1c26faa9103 163 warning(); // this will set the warning icon assuming that max ppo2 is exceeded
pegcjs 2:a1c26faa9103 164
pegcjs 2:a1c26faa9103 165 leds(); // this sets the leds according to the various warning conditions
pegcjs 2:a1c26faa9103 166
pegcjs 2:a1c26faa9103 167 }
pegcjs 2:a1c26faa9103 168
pegcjs 2:a1c26faa9103 169
pegcjs 1:9cff4feccbce 170 // pick maximum of two values
pegcjs 1:9cff4feccbce 171 float maximum(float a,float b) {
pegcjs 1:9cff4feccbce 172 float maximum;
pegcjs 1:9cff4feccbce 173 if (a>b) maximum=a;
pegcjs 1:9cff4feccbce 174 else maximum=b;
pegcjs 1:9cff4feccbce 175 return(maximum);
pegcjs 2:a1c26faa9103 176 }
pegcjs 2:a1c26faa9103 177
pegcjs 1:9cff4feccbce 178 // pick minimum of two values
pegcjs 1:9cff4feccbce 179 float minimum(float a,float b) {
pegcjs 1:9cff4feccbce 180 float minim;
pegcjs 1:9cff4feccbce 181 if (a<b) minim=a;
pegcjs 1:9cff4feccbce 182 else minim=b;
pegcjs 1:9cff4feccbce 183 return(minim);
pegcjs 2:a1c26faa9103 184 }
pegcjs 2:a1c26faa9103 185
pegcjs 1:9cff4feccbce 186
pegcjs 2:a1c26faa9103 187
pegcjs 2:a1c26faa9103 188 // read sensors and generate calibrated outputs NB battery is read elsewhere
pegcjs 1:9cff4feccbce 189 void readsensors() {
pegcjs 1:9cff4feccbce 190 float barometric=0,mod1,mod2;
pegcjs 1:9cff4feccbce 191 ppo1=EG1*0.21/eg1cal; // eg1cal is 0.21bar ppO2
pegcjs 1:9cff4feccbce 192 ppo2=EG2*0.21/eg2cal; // second oxygen cell ppO2
pegcjs 2:a1c26faa9103 193 pressure=(PRESin*3.3-0.024)/(0.0038574); // pressure in kPa assuming standard cal for mpx5700 sensor SUSPECT
pegcjs 2:a1c26faa9103 194 // barometric=(pcal*3.3-0.024)/(0.0038574); // sealevel in kPa assuming standard cal for mpx5700 sensor
pegcjs 2:a1c26faa9103 195 depth=(pressure-101.325)*0.1; //100kPa=10m 1kPa=0.1m - this gives depth in m for freshwater.
pegcjs 1:9cff4feccbce 196 //with two sensors will calculate mod from the largest ppo2 reading
pegcjs 2:a1c26faa9103 197
pegcjs 2:a1c26faa9103 198 fo1=100*ppo1/(pressure/100); // pressure in bar = pressure /100 and want a % so multiply by 100 as well
pegcjs 2:a1c26faa9103 199 fo2=100*ppo2/(pressure/100);
pegcjs 2:a1c26faa9103 200
pegcjs 2:a1c26faa9103 201
pegcjs 2:a1c26faa9103 202 mod1=(1.4/(fo1/100)-1)*10;
pegcjs 2:a1c26faa9103 203 mod2=(1.4/(fo2/100)-1)*10;
pegcjs 2:a1c26faa9103 204 mod=minimum(mod1,mod2); // pick the least value
pegcjs 2:a1c26faa9103 205 //DEBUG
pegcjs 2:a1c26faa9103 206 printf("ppo1=%1.3f\tppo2=%1.3f\tfo1=%2.2f\tfo2=%2.2f\tmod1=%2.1f\tmod2=%2.1f\tpressure=%.3f\t scrubtime=%d\n\r",ppo1,ppo2,fo1,fo2,mod1,mod2,pressure,scrubtime);
pegcjs 1:9cff4feccbce 207 }
pegcjs 1:9cff4feccbce 208
pegcjs 1:9cff4feccbce 209 int main() {
pegcjs 2:a1c26faa9103 210 // first some local variables
pegcjs 2:a1c26faa9103 211 int startuptime=getseconds();
pegcjs 2:a1c26faa9103 212 int startdive=0; // value of seconds when dive starts
pegcjs 1:9cff4feccbce 213
pegcjs 2:a1c26faa9103 214 int seconds=0,minutes=0; // minutes is elapsed minutes since start of prog
pegcjs 1:9cff4feccbce 215 int i=0,j=0; // general loop counting variables
pegcjs 1:9cff4feccbce 216
pegcjs 1:9cff4feccbce 217
pegcjs 1:9cff4feccbce 218 set_custom_char(); // does what it says on the tin really
pegcjs 1:9cff4feccbce 219 g_lcd.cls();
pegcjs 1:9cff4feccbce 220 g_lcd.locate(0, 0);
pegcjs 1:9cff4feccbce 221 g_lcd.printf( "RebMon");
pegcjs 1:9cff4feccbce 222 g_lcd.locate(0,1);
pegcjs 1:9cff4feccbce 223 g_lcd.printf("CAL?");
pegcjs 1:9cff4feccbce 224 battery();
pegcjs 1:9cff4feccbce 225
pegcjs 1:9cff4feccbce 226 // hang about waiting for the cal switch to be pressed in ccase it is
pegcjs 1:9cff4feccbce 227 while (seconds-startuptime<20) {
pegcjs 1:9cff4feccbce 228 seconds=getseconds();
pegcjs 1:9cff4feccbce 229 g_lcd.locate(5,1);
pegcjs 1:9cff4feccbce 230 g_lcd.printf("%.2d",21-(seconds-startuptime));
pegcjs 1:9cff4feccbce 231 battery(); // bung in battery symbol.
pegcjs 1:9cff4feccbce 232 g_lcd.locate(7,0);
pegcjs 1:9cff4feccbce 233 g_lcd.printf( "%.2d:%.2d:%.2d", hours,min,sec);
pegcjs 1:9cff4feccbce 234 if (CAL==0) {
pegcjs 1:9cff4feccbce 235 calibrate();
pegcjs 1:9cff4feccbce 236
pegcjs 1:9cff4feccbce 237 }
pegcjs 1:9cff4feccbce 238 wait(1);
pegcjs 1:9cff4feccbce 239 }
pegcjs 1:9cff4feccbce 240 g_lcd.cls();
pegcjs 1:9cff4feccbce 241 backlight=1; // backlight on - this driven by bc182l and 50ohm resistor off the 5V supply to send ~ 20mA
pegcjs 1:9cff4feccbce 242
pegcjs 1:9cff4feccbce 243 // ok there are three states in this system
pegcjs 1:9cff4feccbce 244 //MAIN LOOP ONCE STARTUP PROTOCOLS ARE COMPLETED
pegcjs 1:9cff4feccbce 245 while (1) {
pegcjs 2:a1c26faa9103 246 wait(0.2); //stop screen flicker
pegcjs 1:9cff4feccbce 247 readsensors();
pegcjs 2:a1c26faa9103 248 seconds=getseconds();
pegcjs 2:a1c26faa9103 249 minutes=(int)((float)seconds-(float)startuptime)/60;
pegcjs 2:a1c26faa9103 250 scrubtime=minutes; // temporary to test
pegcjs 2:a1c26faa9103 251 display();
pegcjs 2:a1c26faa9103 252 if(minutes<1) state=0;
pegcjs 2:a1c26faa9103 253 if(minutes>=1) state=1; // surface mode - ok to go for a dive now
pegcjs 2:a1c26faa9103 254 if(minutes>1 && depth>0.5) state=2; // enter dive mode
pegcjs 1:9cff4feccbce 255
pegcjs 1:9cff4feccbce 256
pegcjs 2:a1c26faa9103 257
pegcjs 1:9cff4feccbce 258 } // end while
pegcjs 1:9cff4feccbce 259 } //end main
pegcjs 1:9cff4feccbce 260
pegcjs 1:9cff4feccbce 261
pegcjs 1:9cff4feccbce 262
pegcjs 1:9cff4feccbce 263