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:
Fri Aug 03 11:29:30 2012 +0000
Revision:
3:0d94a277aa8c
Parent:
2:a1c26faa9103
Child:
4:74df6d31ee0a
just leds to go

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 3:0d94a277aa8c 52 int flash=0; // variable used top control flashing icons
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 3:0d94a277aa8c 62
pegcjs 1:9cff4feccbce 63 //===== sub to get time from ds1307 and create the 'seconds' which is a version of timestamp....
pegcjs 1:9cff4feccbce 64 int getseconds() {
pegcjs 1:9cff4feccbce 65 my1307.gettime( &sec, &min, &hours, &day, &date, &month, &year);
pegcjs 1:9cff4feccbce 66 //simple timestamp = # seconds since midnight jan 1st 2000 if all months were 30 days.
pegcjs 1:9cff4feccbce 67 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 68 //simple timestamp = # seconds since midnight jan 1st 2000 if all months were 30 days....
pegcjs 1:9cff4feccbce 69 // ie wrong but simpler than the real thing
pegcjs 1:9cff4feccbce 70 return(seconds);
pegcjs 1:9cff4feccbce 71 }
pegcjs 1:9cff4feccbce 72
pegcjs 1:9cff4feccbce 73
pegcjs 1:9cff4feccbce 74 void set_custom_char() {
pegcjs 1:9cff4feccbce 75 char cgchar[64]={
pegcjs 1:9cff4feccbce 76 6,9,9,9,9,9,9,15, // battery empty symbol 0
pegcjs 1:9cff4feccbce 77 6,9,9,9,9,15,15,15, // battery 50% symbol 1
pegcjs 1:9cff4feccbce 78 6,9,9,15,15,15,15,15, // battery 75% symbol 2
pegcjs 1:9cff4feccbce 79 6,15,15,15,15,15,15,15, // battery 100% symbol 3
pegcjs 1:9cff4feccbce 80 31,19,21,21,21,21,19,31, // diving symbol 4 inverse D
pegcjs 1:9cff4feccbce 81 6,6,6,6,6,0,0,6, // warning symbol 5
pegcjs 1:9cff4feccbce 82 31,17,23,17,29,17,31,0, // surface symbol 6 inverse S
pegcjs 2:a1c26faa9103 83 0,0,17,17,0,17,14,0 // happy symbol 7
pegcjs 1:9cff4feccbce 84 };
pegcjs 1:9cff4feccbce 85 int i=0;
pegcjs 1:9cff4feccbce 86 // do stuff here to set cstom chars
pegcjs 1:9cff4feccbce 87 g_lcd.writeCommand(0x40); // set start address for CGRAM
pegcjs 1:9cff4feccbce 88 for (i=0; i<64; i++) {
pegcjs 1:9cff4feccbce 89 g_lcd.writeData(cgchar[i]);
pegcjs 1:9cff4feccbce 90 }
pegcjs 1:9cff4feccbce 91
pegcjs 1:9cff4feccbce 92 }
pegcjs 1:9cff4feccbce 93
pegcjs 1:9cff4feccbce 94
pegcjs 1:9cff4feccbce 95 // subroutine to calibreate o2 sesnors and store ca data in /local/CAL.dat
pegcjs 1:9cff4feccbce 96 void calibrate() {
pegcjs 1:9cff4feccbce 97 int count=1;
pegcjs 1:9cff4feccbce 98 float ppo1=0,ppo2=0,pres=0;
pegcjs 1:9cff4feccbce 99 // average 20 readings for noise reduction
pegcjs 1:9cff4feccbce 100 g_lcd.cls();
pegcjs 1:9cff4feccbce 101 for (count=20; count>0; count--) {
pegcjs 1:9cff4feccbce 102 g_lcd.locate(0,0);
pegcjs 1:9cff4feccbce 103 g_lcd.printf("Calibrating %.2d",count);
pegcjs 1:9cff4feccbce 104 ppo1=ppo1+EG1;
pegcjs 1:9cff4feccbce 105 ppo2=ppo2+EG2;
pegcjs 1:9cff4feccbce 106 pres=pres+PRESin;
pegcjs 1:9cff4feccbce 107 g_lcd.locate(0,1);
pegcjs 1:9cff4feccbce 108 g_lcd.printf("%1.2f: %1.2f: %1.2f",ppo1/(20-count+1),ppo2/(20-count+1),pres/(20-count+1));
pegcjs 1:9cff4feccbce 109 wait(1);
pegcjs 1:9cff4feccbce 110 }
pegcjs 1:9cff4feccbce 111 //average
pegcjs 1:9cff4feccbce 112 ppo1=ppo1/20;
pegcjs 1:9cff4feccbce 113 ppo2=ppo2/20;
pegcjs 1:9cff4feccbce 114 // set calibration variables
pegcjs 1:9cff4feccbce 115 eg1cal=ppo1;
pegcjs 1:9cff4feccbce 116 eg2cal=ppo2;
pegcjs 1:9cff4feccbce 117 pcal=pres/20; // surface pressure....
pegcjs 1:9cff4feccbce 118 scrubtime=0; // reset the scrubber timer to zero.
pegcjs 2:a1c26faa9103 119 // write cal data NB overwites previous
pegcjs 2:a1c26faa9103 120 FILE *fp=fopen("/local/CAL.dat","w");
pegcjs 2:a1c26faa9103 121 fprintf(fp,"%e\n%e\n%e\n%d",eg1cal,eg2cal,pcal,scrubtime);
pegcjs 2:a1c26faa9103 122 fclose(fp); //NB file system locked on write so must make sure we close files in case want to reprogram etc...
pegcjs 1:9cff4feccbce 123 }
pegcjs 1:9cff4feccbce 124
pegcjs 1:9cff4feccbce 125
pegcjs 2:a1c26faa9103 126 void status() {
pegcjs 3:0d94a277aa8c 127 if (state==0) {
pegcjs 3:0d94a277aa8c 128 g_lcd.character(9,0,5); // warning icon until 1 min up
pegcjs 3:0d94a277aa8c 129 g_lcd.character(8,0,6); // surface icon
pegcjs 3:0d94a277aa8c 130 }
pegcjs 2:a1c26faa9103 131 if (state==1) g_lcd.character(8,0,6); // surface icon
pegcjs 3:0d94a277aa8c 132 if (state==2 && flash==1) g_lcd.character(8,0,4); // diving icon
pegcjs 3:0d94a277aa8c 133 if (state==2 && flash==0) g_lcd.character(8,0,68); // diving icon
pegcjs 3:0d94a277aa8c 134 }
pegcjs 3:0d94a277aa8c 135
pegcjs 3:0d94a277aa8c 136 // warning and LED conditions
pegcjs 2:a1c26faa9103 137
pegcjs 2:a1c26faa9103 138 void warning() {
pegcjs 3:0d94a277aa8c 139 if (depth>=mod && flash==1) g_lcd.character(13,0,5);
pegcjs 2:a1c26faa9103 140
pegcjs 2:a1c26faa9103 141 }
pegcjs 2:a1c26faa9103 142
pegcjs 2:a1c26faa9103 143 void leds() {
pegcjs 1:9cff4feccbce 144 }
pegcjs 1:9cff4feccbce 145
pegcjs 1:9cff4feccbce 146 //read battery state and insert the battery symbol
pegcjs 1:9cff4feccbce 147 void battery() {
pegcjs 1:9cff4feccbce 148 int batsym=0;
pegcjs 1:9cff4feccbce 149 Vb=Vbatt; // read adc connected to battery via a 1/3 potential divider
pegcjs 1:9cff4feccbce 150 if (Vb>0.606) batsym=1;
pegcjs 1:9cff4feccbce 151 if (Vb>0.707) batsym=2;
pegcjs 1:9cff4feccbce 152 if (Vb>0.808) batsym=3;
pegcjs 3:0d94a277aa8c 153 if (batsym >0) g_lcd.character(8,1,batsym);
pegcjs 3:0d94a277aa8c 154 if (batsym ==0 && flash==1) g_lcd.character(8,1,batsym);
pegcjs 3:0d94a277aa8c 155 if (batsym ==0 && flash==0) g_lcd.character(8,1,32);
pegcjs 1:9cff4feccbce 156 }
pegcjs 1:9cff4feccbce 157
pegcjs 2:a1c26faa9103 158 // subroutine to write the main display data
pegcjs 2:a1c26faa9103 159 //0123456789abcdef
pegcjs 2:a1c26faa9103 160
pegcjs 2:a1c26faa9103 161 //x.xx:xx D XX xx
pegcjs 2:a1c26faa9103 162 //x.xx:xx B XX xxx NB the warning, staus and battery icons are driven by separate subroutines.
pegcjs 2:a1c26faa9103 163 void display() {
pegcjs 2:a1c26faa9103 164 //1st line
pegcjs 2:a1c26faa9103 165 g_lcd.locate(0,0);
pegcjs 2:a1c26faa9103 166 g_lcd.printf("%1.2f:%.2d %.2d %.2d",ppo1,(int)fo1,(int)depth,(int)mod);
pegcjs 2:a1c26faa9103 167 //2nd line
pegcjs 2:a1c26faa9103 168 g_lcd.locate(0,1);
pegcjs 3:0d94a277aa8c 169 g_lcd.printf("%1.2f:%.2d %.2d %.3d",ppo2,(int)fo2,divetime,scrubtime);
pegcjs 2:a1c26faa9103 170 // bung in battery icon
pegcjs 2:a1c26faa9103 171 battery();
pegcjs 2:a1c26faa9103 172 status(); // this will set the diviong / suface mode icon
pegcjs 2:a1c26faa9103 173 warning(); // this will set the warning icon assuming that max ppo2 is exceeded
pegcjs 2:a1c26faa9103 174
pegcjs 2:a1c26faa9103 175 leds(); // this sets the leds according to the various warning conditions
pegcjs 2:a1c26faa9103 176
pegcjs 2:a1c26faa9103 177 }
pegcjs 2:a1c26faa9103 178
pegcjs 2:a1c26faa9103 179
pegcjs 1:9cff4feccbce 180 // pick maximum of two values
pegcjs 1:9cff4feccbce 181 float maximum(float a,float b) {
pegcjs 1:9cff4feccbce 182 float maximum;
pegcjs 1:9cff4feccbce 183 if (a>b) maximum=a;
pegcjs 1:9cff4feccbce 184 else maximum=b;
pegcjs 1:9cff4feccbce 185 return(maximum);
pegcjs 2:a1c26faa9103 186 }
pegcjs 2:a1c26faa9103 187
pegcjs 1:9cff4feccbce 188 // pick minimum of two values
pegcjs 1:9cff4feccbce 189 float minimum(float a,float b) {
pegcjs 1:9cff4feccbce 190 float minim;
pegcjs 1:9cff4feccbce 191 if (a<b) minim=a;
pegcjs 1:9cff4feccbce 192 else minim=b;
pegcjs 1:9cff4feccbce 193 return(minim);
pegcjs 2:a1c26faa9103 194 }
pegcjs 2:a1c26faa9103 195
pegcjs 1:9cff4feccbce 196
pegcjs 2:a1c26faa9103 197
pegcjs 2:a1c26faa9103 198 // read sensors and generate calibrated outputs NB battery is read elsewhere
pegcjs 1:9cff4feccbce 199 void readsensors() {
pegcjs 1:9cff4feccbce 200 float barometric=0,mod1,mod2;
pegcjs 1:9cff4feccbce 201 ppo1=EG1*0.21/eg1cal; // eg1cal is 0.21bar ppO2
pegcjs 1:9cff4feccbce 202 ppo2=EG2*0.21/eg2cal; // second oxygen cell ppO2
pegcjs 2:a1c26faa9103 203 pressure=(PRESin*3.3-0.024)/(0.0038574); // pressure in kPa assuming standard cal for mpx5700 sensor SUSPECT
pegcjs 3:0d94a277aa8c 204 // barometric=(pcal*3.3-0.024)/(0.0038574); // sealevel in kPa assuming standard cal for mpx5700 sensor
pegcjs 2:a1c26faa9103 205 depth=(pressure-101.325)*0.1; //100kPa=10m 1kPa=0.1m - this gives depth in m for freshwater.
pegcjs 1:9cff4feccbce 206 //with two sensors will calculate mod from the largest ppo2 reading
pegcjs 2:a1c26faa9103 207
pegcjs 2:a1c26faa9103 208 fo1=100*ppo1/(pressure/100); // pressure in bar = pressure /100 and want a % so multiply by 100 as well
pegcjs 2:a1c26faa9103 209 fo2=100*ppo2/(pressure/100);
pegcjs 3:0d94a277aa8c 210
pegcjs 2:a1c26faa9103 211
pegcjs 2:a1c26faa9103 212 mod1=(1.4/(fo1/100)-1)*10;
pegcjs 2:a1c26faa9103 213 mod2=(1.4/(fo2/100)-1)*10;
pegcjs 3:0d94a277aa8c 214
pegcjs 2:a1c26faa9103 215 mod=minimum(mod1,mod2); // pick the least value
pegcjs 2:a1c26faa9103 216 //DEBUG
pegcjs 3:0d94a277aa8c 217
pegcjs 1:9cff4feccbce 218 }
pegcjs 3:0d94a277aa8c 219 // sub to test if a variable is an even number
pegcjs 3:0d94a277aa8c 220 /*int iseven(int g) {
pegcjs 3:0d94a277aa8c 221 int test=0;
pegcjs 3:0d94a277aa8c 222 if ((float)g/2==(int)((float)g/2)) test=1;
pegcjs 3:0d94a277aa8c 223 return(test);
pegcjs 3:0d94a277aa8c 224 }*/
pegcjs 1:9cff4feccbce 225
pegcjs 1:9cff4feccbce 226 int main() {
pegcjs 2:a1c26faa9103 227 // first some local variables
pegcjs 2:a1c26faa9103 228 int startuptime=getseconds();
pegcjs 3:0d94a277aa8c 229 int startdive=0,endclock=0;; // value of seconds when dive starts and counter to decide if dive complete...
pegcjs 1:9cff4feccbce 230
pegcjs 3:0d94a277aa8c 231 int seconds=0,minutes=0,dt=0;; // minutes is elapsed minutes since start of prog
pegcjs 1:9cff4feccbce 232 int i=0,j=0; // general loop counting variables
pegcjs 1:9cff4feccbce 233
pegcjs 1:9cff4feccbce 234
pegcjs 1:9cff4feccbce 235 set_custom_char(); // does what it says on the tin really
pegcjs 1:9cff4feccbce 236 g_lcd.cls();
pegcjs 1:9cff4feccbce 237 g_lcd.locate(0, 0);
pegcjs 1:9cff4feccbce 238 g_lcd.printf( "RebMon");
pegcjs 1:9cff4feccbce 239 g_lcd.locate(0,1);
pegcjs 1:9cff4feccbce 240 g_lcd.printf("CAL?");
pegcjs 1:9cff4feccbce 241 battery();
pegcjs 3:0d94a277aa8c 242 j=0;
pegcjs 1:9cff4feccbce 243 // hang about waiting for the cal switch to be pressed in ccase it is
pegcjs 1:9cff4feccbce 244 while (seconds-startuptime<20) {
pegcjs 1:9cff4feccbce 245 seconds=getseconds();
pegcjs 1:9cff4feccbce 246 g_lcd.locate(5,1);
pegcjs 1:9cff4feccbce 247 g_lcd.printf("%.2d",21-(seconds-startuptime));
pegcjs 3:0d94a277aa8c 248 if(j>1) flash=1;
pegcjs 3:0d94a277aa8c 249 else flash=0;
pegcjs 1:9cff4feccbce 250 battery(); // bung in battery symbol.
pegcjs 1:9cff4feccbce 251 g_lcd.locate(7,0);
pegcjs 1:9cff4feccbce 252 g_lcd.printf( "%.2d:%.2d:%.2d", hours,min,sec);
pegcjs 1:9cff4feccbce 253 if (CAL==0) {
pegcjs 1:9cff4feccbce 254 calibrate();
pegcjs 1:9cff4feccbce 255
pegcjs 1:9cff4feccbce 256 }
pegcjs 3:0d94a277aa8c 257 wait(0.2);
pegcjs 3:0d94a277aa8c 258 j=(j+1) % 4;
pegcjs 1:9cff4feccbce 259 }
pegcjs 1:9cff4feccbce 260 g_lcd.cls();
pegcjs 1:9cff4feccbce 261 backlight=1; // backlight on - this driven by bc182l and 50ohm resistor off the 5V supply to send ~ 20mA
pegcjs 1:9cff4feccbce 262
pegcjs 1:9cff4feccbce 263 // ok there are three states in this system
pegcjs 1:9cff4feccbce 264 //MAIN LOOP ONCE STARTUP PROTOCOLS ARE COMPLETED
pegcjs 3:0d94a277aa8c 265 j=0;
pegcjs 1:9cff4feccbce 266 while (1) {
pegcjs 2:a1c26faa9103 267 wait(0.2); //stop screen flicker
pegcjs 1:9cff4feccbce 268 readsensors();
pegcjs 2:a1c26faa9103 269 seconds=getseconds();
pegcjs 2:a1c26faa9103 270 minutes=(int)((float)seconds-(float)startuptime)/60;
pegcjs 3:0d94a277aa8c 271 dt=seconds-startuptime; // elapsed seconds
pegcjs 3:0d94a277aa8c 272
pegcjs 3:0d94a277aa8c 273 if (j>1) flash=1;
pegcjs 3:0d94a277aa8c 274 else flash=0;
pegcjs 3:0d94a277aa8c 275
pegcjs 3:0d94a277aa8c 276 display(); // write the display
pegcjs 3:0d94a277aa8c 277
pegcjs 3:0d94a277aa8c 278 // setup state variable
pegcjs 3:0d94a277aa8c 279 if (minutes<1) state=0; // startup mode - do nothing just wait to allow sensor readings to settle.
pegcjs 3:0d94a277aa8c 280 if (minutes>=1) state=1; // surface mode - ok to go for a dive now
pegcjs 3:0d94a277aa8c 281 if (minutes>1 && depth>0.5 && state==1) {
pegcjs 3:0d94a277aa8c 282 state=2; // enter dive mode
pegcjs 3:0d94a277aa8c 283 startdive=seconds; // set start of divetime.
pegcjs 3:0d94a277aa8c 284 endclock=0; // reset end of dive clock
pegcjs 3:0d94a277aa8c 285 }
pegcjs 3:0d94a277aa8c 286 if (state==2) {
pegcjs 3:0d94a277aa8c 287 divetime=(int)((float)seconds-(float)startdive)/60; // time since start of dive in minutes.
pegcjs 3:0d94a277aa8c 288 // do deco calcs here when implemented
pegcjs 3:0d94a277aa8c 289 if (depth<0.3) {
pegcjs 3:0d94a277aa8c 290 endclock++;
pegcjs 3:0d94a277aa8c 291 if (endclock==150) state=1; // 30s at shallower than 0.3m and we return to surface mode.
pegcjs 3:0d94a277aa8c 292 }
pegcjs 3:0d94a277aa8c 293 }
pegcjs 1:9cff4feccbce 294
pegcjs 1:9cff4feccbce 295
pegcjs 3:0d94a277aa8c 296 j=(j+1) %4; // flash control variable = used to make the warnings flash for 0.4s duty cycle
pegcjs 1:9cff4feccbce 297 } // end while
pegcjs 1:9cff4feccbce 298 } //end main
pegcjs 1:9cff4feccbce 299
pegcjs 1:9cff4feccbce 300
pegcjs 1:9cff4feccbce 301
pegcjs 1:9cff4feccbce 302