├── _20131118_FirstBuild_withSleep&Alarm ├── ReadMe.txt └── 2013_11_18_FirstBuild_withSleep&Alarm.ino ├── _20140225_SRAMloops_wNewLogfileNames ├── ReadMe.txt └── _20140225_SRAMloops_wNewLogfileNames.ino ├── _20131215_Codefrom1stLongTermDeployment ├── Readme.txt └── _20131215_1stLongTermDeployment.ino ├── _20140222_CleanerCode_ArrayLoopsWorking ├── Readme.txt └── _20140222_CleanerCode_ArrayLoopsWorking.ino ├── _20141002_DripSensors_WithPowerControl └── ReadMe.txt ├── README.md ├── _20140303_AT24C32_EEpromBuffering_wNewLogFiles ├── ReadMe.txt └── _20140303_AT24C32_EEpromBuffering_wNewLogFiles.ino └── _20140630_CavePearl_ModularAdjustableCode ├── readme.txt └── _20140630_CavePearl_ModularAdjustableCode.ino /_20131118_FirstBuild_withSleep&Alarm/ReadMe.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EKMallon/The_Cave_Pearl_Project_OLD_codebuilds/HEAD/_20131118_FirstBuild_withSleep&Alarm/ReadMe.txt -------------------------------------------------------------------------------- /_20140225_SRAMloops_wNewLogfileNames/ReadMe.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EKMallon/The_Cave_Pearl_Project_OLD_codebuilds/HEAD/_20140225_SRAMloops_wNewLogfileNames/ReadMe.txt -------------------------------------------------------------------------------- /_20131215_Codefrom1stLongTermDeployment/Readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EKMallon/The_Cave_Pearl_Project_OLD_codebuilds/HEAD/_20131215_Codefrom1stLongTermDeployment/Readme.txt -------------------------------------------------------------------------------- /_20140222_CleanerCode_ArrayLoopsWorking/Readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EKMallon/The_Cave_Pearl_Project_OLD_codebuilds/HEAD/_20140222_CleanerCode_ArrayLoopsWorking/Readme.txt -------------------------------------------------------------------------------- /_20141002_DripSensors_WithPowerControl/ReadMe.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EKMallon/The_Cave_Pearl_Project_OLD_codebuilds/HEAD/_20141002_DripSensors_WithPowerControl/ReadMe.txt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The_Cave_Pearl_Project_OLD_codebuilds 2 | Functional datalogger code builds, but hardware will change between builds, so read the comments. 3 | 4 | These are OLD builds that show the development leading up to the code currently used 5 | for the Cave Pearl Project data loggers. The base code evolved from a fairly crude 6 | starting point, and these various versions were successfully deployed in the field. 7 | 8 | They are posted here primarily as a teaching reference for Dr. Beddows instrumentation course students, 9 | and have various library dependencies which may make them inoperable at the current time 10 | without significant de-bugging. 11 | -------------------------------------------------------------------------------- /_20140303_AT24C32_EEpromBuffering_wNewLogFiles/ReadMe.txt: -------------------------------------------------------------------------------- 1 | This script uses PSTRING to to dramatically simplify the concatenation of the sensor data into a 28 byte long char buffer (the block write buffer on the AT24C32 eeprom is only 32 characters long and you need room for termination characters, etc). Pstring uses simple print statements, but more importantly, it never causes buffer overflows if you try to stuff in too much data, like a mishandled sprintf statement could. . 2 | 3 | This code buffers each sensor read cycle to the I2C eeprom on, using two page writes per cycle. This simplifies the code a bit, as I have only one set of variables on the go. Then when the countlog = SamplesPerCycle, it does a reverse for loop to pull the data back out of the eeprom, and write it to the SD card. -------------------------------------------------------------------------------- /_20140630_CavePearl_ModularAdjustableCode/readme.txt: -------------------------------------------------------------------------------- 1 | A major overhaul of the Cave Pearl software in this release: 2 | 3 | ---------------------------------------------------------------------------------------------------- 4 | 5 | 6 | Common I2C functions have been now been extracted to their own subroutines and, drawing on the elegant code over at the multiwii project, I have wrapped large sections with #ifdef/#endif statements, to get the sketch to adapt automatically to whatever combination of different sensors is attached for a given deployment. Simply uncomment the defines at the beginning of the script for each sensor you have connected - the rest of the code should adjust automatically...mostly...still some tweaks needed for the SD card writing. 7 | 8 | "#define SamplesPerCycle XX "is limited to 42 if you have the compass or the pressure sensor attached, as that pushes the page writes to 3 per sample cycle, and the AT25C32 eeprom only has 4k of storage. I know I have very inefficient use of the eeprom here, but I wont bother optimizing the data handling till I have done my final sensor selections, as then I will know what the data actually looks like... 9 | 10 | ---------------------------------------------------------------------------------------------------- 11 | 12 | 13 | Added: scheme to replace power wasting delays (while waiting for high bit depth sensor conversions) with variable watchdog timer sleeps. 14 | 15 | Added: a facility to have sampling intervals less than one minute. I only use this when debugging, so under normal operation make sure that the "#define SampleIntSeconds 20" is commented out, and you have a number greater than 0 for "#define SampleIntervalMinutes 0". Still not happy about the RTC library, and its requirement to load SPI.h just to run without errors, but will find a better lib to use later. I have linked some alternates there in the code. 16 | 17 | Added: A smoothing routine for the spiky accelerometer data based on Paul Badger's Digital Smooth http://playground.arduino.cc/Main/DigitalSmooth - but keep a close eye on the freemem if you push "#define filterSamples 7" much beyond 7 you could have problems, especially if you are trying to run several other sensors at the same time. 18 | 19 | Added: a voltage check AFTER the SD card saves. Since the SD is the largest current drawing event, I figured that checking for unsafe voltage events then made sense. Low volt errors now go to permanent sleep state, rather than a while(1) loop. 20 | 21 | 22 | ---------------------------------------------------------------------------------------------------- 23 | 24 | 25 | Electronic components for the current datalogger platform: 26 | ********************************************************** 27 | TinyDuino Processor board (unregulated), TinyShield Proto, TinySheild microSD, 28 | TinyShield Ambient Light sensor (hacked) to use vregulated I2C lines, DS3232 Rtc, AT24C32 I2C eeprom 29 | 30 | 31 | Sensors support included in this build: 32 | *************************************** 33 | HMC5883 Compass, DS18B20 Temp, TMP102 Temp, BMA180 Acc, BMA250 Acc, Ms5803-02 & 05 Pressure sensors* 34 | 35 | *Note: I was using a derivative of the OPENROV code by Walt Holm to drive the MS5803's, but Luke Miller spotted that the float math was generating errors. I have mangled his libs here, because with the rest of the parts bolted together here I don't have enough ram to load even one of his libs directly, and just barely have enough ram for the first order calculations for debugging. So I am only recording the D1 & D2 values in the logged data. 36 | 37 | ----------------------------------------------------------------------------------------------------- 38 | 39 | 40 | P.S. Looking back at the earlier Cave Pearl scripts, I can see many places where I borked the fomatting so badly that it probably any real coders out there wish they were blind. But hey, I have only ever taken one programming course in my life...fortran...in high school...no screens & keyboards...just bubble cards and printouts several days later... This might be something for you to consider before using any of this code on a project that is actually important... 41 | 42 | -------------------------------------------------------------------------------- /_20131118_FirstBuild_withSleep&Alarm/2013_11_18_FirstBuild_withSleep&Alarm.ino: -------------------------------------------------------------------------------- 1 | /* Codebuild for Cave Pearl Project 2013-11-18 -first stable datalogger build! */ 2 | /* for a Tinyduino stack consisting of: a processor board, a BMA250 accelerometer sheild, 3 | the microSD adapter, and a protoboard, jumpered to a chronodot RTC. */ 4 | 5 | // Date, Time and Alarm functions using a DS3231 chronodot RTC connected via I2C // and Wire library from https://github.com/MrAlvin/RTClib 6 | // based largely on Jean-Claude Wippler from JeeLab’s https://github.com/jcw 7 | // Clear alarm interupt code from http://forum.arduino.cc/index.php?topic=109062.0 8 | // Get temp from http://forum.arduino.cc/index.php/topic,22301.0.html [which does not use the RTCLIB!] 9 | // BMA250_I2C_Sketch.pde – from 10 | // https://tiny-circuits.com/learn/using-the-accelerometer-tinyshield/ 11 | // which links to 12 | // http://www.dsscircuits.com/accelerometer-bma250.html 13 | // floats to string conversion: http://dereenigne.org/arduino/arduino-float-to-string 14 | // note: angle brackets which should be around library names are missing here due to formatting weirdness in WordPress 15 | 16 | #include 17 | #include 18 | #include // not used here, but needed to prevent a RTClib compile error 19 | #include 20 | #include 21 | 22 | #ifndef cbi //defs for stopping the ADC during sleep mode 23 | #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) 24 | #endif 25 | #ifndef sbi 26 | #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) 27 | #endif 28 | 29 | #define DS3231_I2C_ADDRESS 104 //for the RTC temp reading function 30 | 31 | #define BMA250 0×18 32 | #define BW 0×08 //7.81Hz bandwith 33 | #define GSEL 0×03 // set range 0×03 – 2g, 0×05 – 4, 0×08 – 8g, 0x0C – 16g 34 | //#define DELAY 10000 is this line an orphan? 35 | 36 | RTC_DS3231 RTC; 37 | byte Alarmhour = 1; 38 | byte Alarmminute = 1; 39 | byte dummyRegister; 40 | int INTERRUPT_PIN = 2; 41 | volatile int state = LOW; 42 | volatile boolean clockInterrupt = false; 43 | int SampleInterval = 1; 44 | // power-down time in minutes before interupt triggers next sample 45 | 46 | byte tMSB, tLSB; //for the RTC temp reading function 47 | float temp3231; 48 | 49 | const int chipSelect = 10; //sd card chip select 50 | 51 | uint8_t dataArray[16]; 52 | //variables for accellerometer reading 53 | int8_t BMAtemp; 54 | float BMAtempfloat; 55 | int x,y,z; 56 | String BMAdata; //for passing back data from bma read function 57 | char TimeStampbuffer[ ]= "0000/00/00,00:00:00, "; 58 | 59 | int ledpin = 13; //led indicator pin 60 | 61 | void setup () { 62 | 63 | pinMode(INTERRUPT_PIN, INPUT); 64 | digitalWrite(INTERRUPT_PIN, HIGH);//pull up the interrupt pin 65 | pinMode(13, OUTPUT); // initialize the LED pin as an output. 66 | digitalWrite(13, HIGH); // turn the LED on to warn against SD card removal 67 | 68 | Serial.begin(9600); 69 | Wire.begin(); 70 | RTC.begin(); 71 | //RTC.adjust(DateTime(__DATE__, __TIME__)); 72 | //the above line set the time with code compile time – you only run this line ONCE! 73 | clearClockTrigger(); //stops RTC from holding the interrupt low if system reset 74 | // time for next alarm 75 | DateTime now = RTC.now(); 76 | Alarmhour = now.hour(); 77 | Alarmminute = now.minute()+ SampleInterval ; 78 | if (Alarmminute > 59) { //error catch – if Alarmminute=60 the interrupt never triggers due to rollover 79 | Alarmminute = 0; Alarmhour = Alarmhour+1; if (Alarmhour > 23) {Alarmhour =0;} 80 | } 81 | 82 | initializeBMA(); //initialize the accelerometer 83 | 84 | //get the SD card ready 85 | pinMode(chipSelect, OUTPUT); //make sure that the default chip select pin is set to output, even if you don’t use it 86 | Serial.print("Initializing SD card…"); 87 | if (!SD.begin(chipSelect)) { // see if the card is present and can be initialized: 88 | Serial.println("Card failed, or not present"); // don’t do anything more: 89 | return; 90 | } 91 | Serial.println("card initialized."); 92 | File dataFile = SD.open("datalog.txt", FILE_WRITE); //PRINT THE DATA FILE HEADER 93 | if (dataFile) { // if the file is available, write to it: 94 | dataFile.println("YYYY/MM/DD, HH:MM:SS, Vcc(mV), X = , Y = , Z = , BMATemp (C) , RTC temp (C)"); 95 | dataFile.close(); 96 | } 97 | else { //if the file isn’t open, pop up an error: 98 | Serial.println("Error opening datalog.txt file!"); 99 | } 100 | } 101 | 102 | void loop () { 103 | 104 | if (clockInterrupt) { 105 | clearClockTrigger(); 106 | } 107 | 108 | //read in our data 109 | BMAdata = String(""); //clear out the datastring 110 | read3AxisAcceleration(); //loads up the dataString 111 | DateTime now = RTC.now(); // Read the time and date from the RTC 112 | sprintf(TimeStampbuffer, "%04d/%02d/%02d,%02d:%02d:%02d,", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second()); 113 | Serial.println("Timestamp Y/M/D, HH:MM:SS, Vcc = , X = , Y = , Z = , BMATemp (C) , RTC temp (C)"); 114 | Serial.print(TimeStampbuffer); Serial.print(readVcc()); Serial.print(","); 115 | Serial.print(BMAdata); Serial.print(","); Serial.println(get3231Temp()); 116 | 117 | //write data to the SD card 118 | // note that only one file can be open at a time,so you have to close this one before opening another. 119 | File dataFile = SD.open("datalog.txt", FILE_WRITE); 120 | 121 | if (dataFile) { // if the file is available, write to it: 122 | dataFile.print(TimeStampbuffer);dataFile.print(readVcc()); dataFile.print(","); 123 | dataFile.print(BMAdata); dataFile.print(","); dataFile.println(get3231Temp()); 124 | dataFile.close(); 125 | } 126 | else { //if the file isn’t open, pop up an error: 127 | Serial.println("Error opening datalog.txt file"); 128 | } 129 | 130 | // setNextAlarmTime(); 131 | Alarmhour = now.hour(); Alarmminute = now.minute()+SampleInterval; 132 | if (Alarmminute > 59) { //error catch – if alarmminute=60 the interrupt never triggers due to rollover! 133 | Alarmminute =0; Alarmhour = Alarmhour+1; if (Alarmhour > 23) {Alarmhour =0;} 134 | } 135 | RTC.setAlarm1Simple(Alarmhour, Alarmminute); 136 | RTC.turnOnAlarm(1); 137 | 138 | Serial.print("Alarm Enabled at: "); 139 | Serial.print(now.hour(), DEC); Serial.print(":’); Serial.println(now.minute(), DEC); 140 | Serial.print("Going to Sleep for "); Serial.print(SampleInterval);Serial.println(" minutes."); 141 | delay(100); 142 | //a delay long enough to boot out the serial coms before sleeping. 143 | 144 | sleepNow(); 145 | 146 | //Serial.println("Alarm 1 has been Triggered!"); 147 | } 148 | 149 | void sleepNow() { 150 | digitalWrite(13, LOW); 151 | cbi(ADCSRA,ADEN); // Switch ADC OFF 152 | set_sleep_mode(SLEEP_MODE_PWR_DOWN); 153 | sleep_enable(); 154 | attachInterrupt(0,clockTrigger, LOW); 155 | sleep_mode(); 156 | //HERE AFTER WAKING UP 157 | sleep_disable(); 158 | detachInterrupt(0); 159 | sbi(ADCSRA,ADEN); // Switch ADC converter ON 160 | pinMode(13, OUTPUT); digitalWrite(13, HIGH); 161 | // turn the LED on to warn against SD card removal 162 | // But I have some conflict between the SD chip select line, and the led – so the darned thing never lit! 163 | } 164 | 165 | void clockTrigger() { 166 | clockInterrupt = true; //do something quick, flip a flag, and handle in loop(); 167 | } 168 | 169 | void clearClockTrigger() 170 | { 171 | Wire.beginTransmission(0×68); //Tell devices on the bus we are talking to the DS3231 172 | Wire.write(0x0F); //Tell the device which address we want to read or write 173 | Wire.endTransmission(); //Before you can write to and clear the alarm flag you have to read the flag first! 174 | Wire.requestFrom(0×68,1); // Read one byte 175 | dummyRegister=Wire.read(); // In this example we are not interest in actually using the bye 176 | Wire.beginTransmission(0×68); //Tell devices on the bus we are talking to the DS3231 177 | Wire.write(0x0F); //Tell the device which address we want to read or write 178 | Wire.write(0b00000000); //Write the byte. The last 0 bit resets Alarm 1 179 | Wire.endTransmission(); 180 | clockInterrupt=false; //Finally clear the flag we used to indicate the trigger occurred 181 | } 182 | 183 | // could also use RTC.getTemperature() from the library here as in: 184 | // RTC.convertTemperature(); //convert current temperature into registers 185 | // Serial.print(RTC.getTemperature()); //read registers and display the temperature 186 | 187 | float get3231Temp() 188 | { 189 | //temp registers (11h-12h) get updated automatically every 64s 190 | Wire.beginTransmission(DS3231_I2C_ADDRESS); 191 | Wire.write(0×11); 192 | Wire.endTransmission(); 193 | Wire.requestFrom(DS3231_I2C_ADDRESS, 2); 194 | 195 | if(Wire.available()) { 196 | tMSB = Wire.read(); //2′s complement int portion 197 | tLSB = Wire.read(); //fraction portion 198 | 199 | temp3231 = ((((short)tMSB << 8 | (short)tLSB) >> 6) / 4.0); // Allows for readings below freezing – Thanks to Coding Badly 200 | //temp3231 = (temp3231 * 1.8 + 32.0); // Convert Celcius to Fahrenheit 201 | return temp3231; 202 | 203 | } 204 | else { 205 | temp3231 = 255.0; //Use a value of 255 to error flag that we did not get temp data from the ds3231 206 | } 207 | 208 | return temp3231; 209 | } 210 | 211 | byte read3AxisAcceleration() 212 | { 213 | Wire.beginTransmission(BMA250); 214 | Wire.write(0×02); 215 | Wire.endTransmission(); 216 | Wire.requestFrom(BMA250,7); 217 | for(int i = 0; i < 7;i++) 218 | { 219 | dataArray[i] = Wire.read(); 220 | } 221 | if(!bitRead(dataArray[0],0)){return(0);} 222 | 223 | BMAtemp = dataArray[6]; 224 | x = dataArray[1] << 8; x |= dataArray[0]; x >>= 6; 225 | y = dataArray[3] << 8; y |= dataArray[2]; y >>= 6; 226 | z = dataArray[5] << 8; z |= dataArray[4]; z >>= 6; 227 | 228 | BMAdata += String(x); 229 | BMAdata += ","; 230 | BMAdata += String(y); 231 | BMAdata += ","; 232 | BMAdata += String(z); 233 | BMAdata += ","; 234 | BMAtempfloat = (BMAtemp*0.5)+24.0; 235 | // add digits of BMAtempfloat value to datastring 236 | BMAdata += ((int)BMAtempfloat); 237 | BMAdata += "."; 238 | int temp = (BMAtempfloat – (int)BMAtempfloat) * 100; 239 | BMAdata += (abs(temp)); 240 | 241 | //the following 2 lines could also be used to to convert floats to string 242 | //dtostrf(floatVariable2convert, minStringWidthIncDecimalPoint, numVarsAfterDecimal, charBuffer); 243 | //for example: dtostrf(BMAtempfloat, 5, 2, dtostrfbuffer); dataString += dtostrfbuffer; 244 | } 245 | 246 | byte initializeBMA() 247 | { 248 | Wire.beginTransmission(BMA250); 249 | Wire.write(0x0F); //set g 250 | Wire.write(GSEL); 251 | Wire.endTransmission(); 252 | Wire.beginTransmission(BMA250); 253 | Wire.write(0×10); //set bandwith 254 | Wire.write(BW); 255 | Wire.endTransmission(); 256 | return(0); 257 | } 258 | 259 | // internal voltage reading trick from: http://forum.arduino.cc/index.php/topic,15629.0.html 260 | long readVcc() { //trick to read the Vin using internal 1.1 v as a refrence 261 | long result; 262 | // Read 1.1V reference against AVcc 263 | ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 264 | delay(2); // Wait for Vref to settle 265 | ADCSRA |= _BV(ADSC); // Convert 266 | while (bit_is_set(ADCSRA,ADSC)); 267 | result = ADCL; 268 | result |= ADCH<<8; 269 | result = 1126400L / result; // Back-calculate AVcc in mV 270 | return result; 271 | } 272 | -------------------------------------------------------------------------------- /_20131215_Codefrom1stLongTermDeployment/_20131215_1stLongTermDeployment.ino: -------------------------------------------------------------------------------- 1 | // Date, Time and Alarm functions using a DS3231 RTC connected via I2C and Wire lib by https://github.com/MrAlvin/RTClib 2 | // based largely on Jean-Claude Wippler from JeeLab's excellent RTC library https://github.com/jcw 3 | // clear alarm interupt from http://forum.arduino.cc/index.php?topic=109062.0 4 | // get temp from http://forum.arduino.cc/index.php/topic,22301.0.html which does not use the RTCLIB! 5 | // BMA250_I2C_Sketch.pde -BMA250 Accelerometer using I2C from www.dsscircuits.com/accelerometer-bma250.html 6 | // combined with internal voltage reading trick //forum.arduino.cc/index.php/topic,15629.0.html 7 | // floats to string conversion: http://dereenigne.org/arduino/arduino-float-to-string 8 | 9 | // free mem stabilizes around 616 with this three cycle buffer code.. 10 | // so each extra set of buffered variables adds about 57 bytes to the ram usage 11 | 12 | #include 13 | #include 14 | #include // not used here, but needed to prevent a RTClib compile error 15 | #include 16 | #include 17 | 18 | #ifndef cbi //defs for stopping the ADC during sleep mode 19 | #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) 20 | #endif 21 | #ifndef sbi 22 | #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) 23 | #endif 24 | 25 | #define DS3231_I2C_ADDRESS 104 //for the RTC temp reading function 26 | 27 | #define BMA250 0x18 28 | #define BW 0x08 //7.81Hz bandwith 29 | #define GSEL 0x03 // set range 0x03 - 2g, 0x05 - 4, 0x08 - 8g, 0x0C - 16g 30 | 31 | RTC_DS3231 RTC; 32 | byte Alarmhour = 1; 33 | byte Alarmminute = 1; 34 | byte dummyRegister; 35 | byte INTERRUPT_PIN = 2; 36 | //volatile int state = LOW; 37 | volatile boolean clockInterrupt = false; 38 | byte SampleInterval = 30; // power-down time in minutes before interupt triggers next sample 39 | 40 | byte tMSB, tLSB; //for the RTC temp reading function 41 | float temp3231; 42 | 43 | const byte chipSelect = 10; //sd card chip select 44 | 45 | uint8_t dataArray[16]; //variables for accellerometer reading - why is the temp a float value? 46 | int8_t BMAtemp; //Ok so this thing is an interger 47 | float BMAtempfloat; 48 | int x,y,z; 49 | 50 | String BMAdata; //for passing back data from bma read function 51 | String BMAdata1; 52 | String BMAdata2 = "0000,0000,0000,0000"; 53 | String BMAdata3 = "0000,0000,0000,0000"; 54 | char TimeStampbuffer1[ ]= "0000/00/00,00:00:00, "; 55 | char TimeStampbuffer2[ ]= "0000/00/00,00:00:00, "; 56 | char TimeStampbuffer3[ ]= "0000/00/00,00:00:00, "; 57 | float Temp3231a =0.0; 58 | float Temp3231b =0.0; 59 | float Temp3231c =0.0; 60 | int Vcc1=0; //the supply voltage via 1.1 internal and gap 61 | int Vcc2=0; 62 | int Vcc3=0; 63 | byte cycle=1; 64 | 65 | int ledpin = 13; //led indicator pin not used in this code 66 | 67 | void setup () { 68 | 69 | pinMode(INTERRUPT_PIN, INPUT); 70 | digitalWrite(INTERRUPT_PIN, HIGH);//pull up the interrupt pin 71 | pinMode(13, OUTPUT); // initialize the LED pin as an output. 72 | digitalWrite(13, HIGH); // turn the LED on to warn against SD card removal 73 | 74 | Serial.begin(9600); 75 | Wire.begin(); 76 | RTC.begin(); 77 | //RTC.adjust(DateTime(__DATE__, __TIME__)); //set the time with code compile time only run this once! 78 | clearClockTrigger(); //stops RTC from holding the interrupt low if system reset 79 | // time for next alarm 80 | DateTime now = RTC.now(); 81 | Alarmhour = now.hour(); 82 | Alarmminute = now.minute()+ SampleInterval ; 83 | if (Alarmminute > 59) { //error catch - if Alarmminute=60 the interrupt never triggers due to rollover 84 | Alarmminute = 0; Alarmhour = Alarmhour+1; if (Alarmhour > 23) {Alarmhour =0;} 85 | } 86 | 87 | initializeBMA(); //initialize the accelerometer - do I have to do this on every wake cycle? 88 | 89 | //get the SD card ready 90 | pinMode(chipSelect, OUTPUT); //make sure that the default chip select pin is set to output, even if you don't use it 91 | //Serial.print(F("Initializing SD card...")); 92 | if (!SD.begin(chipSelect)) { // see if the card is present and can be initialized: 93 | Serial.println(F("Card failed, or not present")); // don't do anything more: 94 | return; 95 | } 96 | //Serial.println(F("card initialized.")); 97 | File dataFile = SD.open("datalog.txt", FILE_WRITE); //PRINT THE DATA FILE HEADER 98 | if (dataFile) { // if the file is available, write to it: 99 | dataFile.println(F("YYYY/MM/DD HH:MM:SS, Vcc(mV), X = , Y = , Z = , BMATemp (C) , RTC temp (C)")); 100 | dataFile.close(); 101 | } 102 | else { //if the file isn't open, pop up an error: 103 | Serial.println(F("Error opening datalog.txt file!")); 104 | } 105 | digitalWrite(13, LOW); 106 | } 107 | 108 | void loop () { 109 | 110 | if (clockInterrupt) { 111 | clearClockTrigger(); 112 | } 113 | 114 | //read in our data 115 | read3AxisAcceleration(); //loads up the dataString 116 | DateTime now = RTC.now(); // Read the time and date from the RTC 117 | 118 | if (cycle==1){ 119 | BMAdata1 = BMAdata; 120 | Vcc1 = (readVcc()); 121 | Temp3231a = get3231Temp(); 122 | sprintf(TimeStampbuffer1, "%04d/%02d/%02d %02d:%02d:%02d,", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second()); 123 | 124 | //Serial.print(TimeStampbuffer1); Serial.print(Vcc1); Serial.print(","); 125 | //Serial.print(BMAdata1); Serial.print(","); Serial.println(Temp3231a); 126 | //Serial.println(freeRam()); 127 | //delay(100); 128 | } 129 | 130 | if (cycle==2){ 131 | BMAdata2 = BMAdata; 132 | Vcc2 = int(readVcc()); 133 | Temp3231b = get3231Temp(); 134 | sprintf(TimeStampbuffer2, "%04d/%02d/%02d %02d:%02d:%02d,", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second()); 135 | //Serial.println("Timestamp Y/M/D, HH:MM:SS, Vcc = , X = , Y = , Z = , BMATemp (C) , RTC temp (C)"); 136 | //Serial.print(TimeStampbuffer2); Serial.print(Vcc2); Serial.print(","); 137 | //Serial.print(BMAdata2); Serial.print(","); Serial.println(Temp3231b); 138 | //Serial.println(freeRam()); 139 | //delay(100); 140 | } 141 | 142 | if (cycle==3){ //only write to mem card on this cycle 143 | BMAdata3 = BMAdata; 144 | Vcc3 = int(readVcc()); 145 | Temp3231c = get3231Temp(); 146 | sprintf(TimeStampbuffer3, "%04d/%02d/%02d %02d:%02d:%02d,", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second()); 147 | //Serial.println("Timestamp Y/M/D, HH:MM:SS, Vcc = , X = , Y = , Z = , BMATemp (C) , RTC temp (C)"); 148 | //Serial.print(TimeStampbuffer3); Serial.print(Vcc3); Serial.print(","); 149 | ///Serial.print(BMAdata3); Serial.print(","); Serial.println(Temp3231c); 150 | //Serial.println(freeRam()); 151 | //delay(100); 152 | 153 | // the whole dataset looks like 0000/00/00 00:00:00,0000,0000,0000,0000,00000,00000 154 | // if Vcc too low, dont write to the sd card 155 | if (Vcc1 > 2850){ 156 | //Serial.println(F("-write cycle performed-")); delay (50);//for debugging only 157 | 158 | File dataFile = SD.open("datalog.txt", FILE_WRITE); 159 | if (dataFile) { // if the file is available, write to it: 160 | //here we do the two writes at one time - hopefully saving power only writing every second cycle 161 | dataFile.print(TimeStampbuffer1);dataFile.print(Vcc1); dataFile.print(","); 162 | dataFile.print(BMAdata1); dataFile.print(","); dataFile.println(Temp3231a); 163 | 164 | dataFile.print(TimeStampbuffer2);dataFile.print(Vcc2); dataFile.print(","); 165 | dataFile.print(BMAdata2); dataFile.print(","); dataFile.println(Temp3231b); 166 | 167 | dataFile.print(TimeStampbuffer3);dataFile.print(Vcc3); dataFile.print(","); 168 | dataFile.print(BMAdata3); dataFile.print(","); dataFile.println(Temp3231c); 169 | 170 | dataFile.close(); 171 | } 172 | else { //if the file isn't open, pop up an error: 173 | Serial.println(F("Error opening datalog.txt file")); 174 | } 175 | } 176 | } 177 | // setNextAlarmTime(); 178 | Alarmhour = now.hour(); Alarmminute = now.minute()+SampleInterval; 179 | if (Alarmminute > 59) { //error catch - if alarmminute=60 the interrupt never triggers due to rollover! 180 | Alarmminute =0; Alarmhour = Alarmhour+1; if (Alarmhour > 23) {Alarmhour =0;} 181 | } 182 | RTC.setAlarm1Simple(Alarmhour, Alarmminute); 183 | RTC.turnOnAlarm(1); 184 | 185 | //Serial.print(F("Alarm Enabled at: ")); 186 | //Serial.print(now.hour(), DEC); Serial.print(':'); Serial.println(now.minute(), DEC); 187 | //Serial.print(F("Going to Sleep for ")); Serial.print(SampleInterval);Serial.println(F(" minutes.")); 188 | //delay(100); //a delay long enought to boot out the serial coms 189 | 190 | cycle ++; 191 | if (cycle>3){ 192 | cycle=1;} 193 | 194 | sleepNow(); 195 | 196 | //Serial.println(F("Alarm 1 has been Triggered!")); 197 | } 198 | 199 | 200 | void sleepNow() { 201 | //digitalWrite(13, LOW); 202 | cbi(ADCSRA,ADEN); // Switch ADC OFF 203 | set_sleep_mode(SLEEP_MODE_PWR_DOWN); 204 | sleep_enable(); 205 | attachInterrupt(0,clockTrigger, LOW); 206 | sleep_mode(); 207 | //HERE AFTER WAKING UP 208 | sleep_disable(); 209 | detachInterrupt(0); 210 | sbi(ADCSRA,ADEN); // Switch ADC converter ON 211 | //digitalWrite(13, HIGH); 212 | } 213 | 214 | void clockTrigger() { 215 | clockInterrupt = true; //do something quick, flip a flag, and handle in loop(); 216 | } 217 | 218 | void clearClockTrigger() 219 | { 220 | Wire.beginTransmission(0x68); //Tell devices on the bus we are talking to the DS3231 221 | Wire.write(0x0F); //Tell the device which address we want to read or write 222 | Wire.endTransmission(); //Before you can write to and clear the alarm flag you have to read the flag first! 223 | Wire.requestFrom(0x68,1); // Read one byte 224 | dummyRegister=Wire.read(); // In this example we are not interest in actually using the bye 225 | Wire.beginTransmission(0x68); //Tell devices on the bus we are talking to the DS3231 226 | Wire.write(0x0F); //Tell the device which address we want to read or write 227 | Wire.write(0b00000000); //Write the byte. The last 0 bit resets Alarm 1 228 | Wire.endTransmission(); 229 | clockInterrupt=false; //Finally clear the flag we use to indicate the trigger occurred 230 | } 231 | 232 | // could also use RTC.getTemperature() from the library here as in: 233 | //RTC.convertTemperature(); //convert current temperature into registers 234 | //Serial.print(RTC.getTemperature()); //read registers and display the temperature 235 | 236 | float get3231Temp() 237 | { 238 | //temp registers (11h-12h) get updated automatically every 64s 239 | Wire.beginTransmission(DS3231_I2C_ADDRESS); 240 | Wire.write(0x11); 241 | Wire.endTransmission(); 242 | Wire.requestFrom(DS3231_I2C_ADDRESS, 2); 243 | 244 | if(Wire.available()) { 245 | tMSB = Wire.read(); //2's complement int portion 246 | tLSB = Wire.read(); //fraction portion 247 | 248 | temp3231 = ((((short)tMSB << 8 | (short)tLSB) >> 6) / 4.0); // Allows for readings below freezing - Thanks to Coding Badly 249 | //temp3231 = (temp3231 * 1.8 + 32.0); // Convert Celcius to Fahrenheit 250 | return temp3231; 251 | 252 | } 253 | else { 254 | temp3231 = 255.0; //Use a value of 255 to error flag that we did not get temp data from the ds3231 255 | } 256 | 257 | return temp3231; 258 | } 259 | 260 | 261 | byte read3AxisAcceleration() 262 | { 263 | Wire.beginTransmission(BMA250); 264 | Wire.write(0x02); 265 | Wire.endTransmission(); 266 | Wire.requestFrom(BMA250,7); 267 | for(int i = 0; i < 7;i++) 268 | { 269 | dataArray[i] = Wire.read(); 270 | } 271 | if(!bitRead(dataArray[0],0)){return(0);} 272 | 273 | BMAtemp = dataArray[6]; 274 | x = dataArray[1] << 8; 275 | x |= dataArray[0]; 276 | x >>= 6; 277 | y = dataArray[3] << 8; 278 | y |= dataArray[2]; 279 | y >>= 6; 280 | z = dataArray[5] << 8; 281 | z |= dataArray[4]; 282 | z >>= 6; 283 | //sprintf(BMAdatabuffer, "%04d,%4d,%4d,%4d,", readVcc(), x, y, z); //this does not read x,y.z properly 284 | //dataString = BMAdatabuffer; 285 | //dataString += String(readVcc()); //added with internal voltage meter trick 286 | //dataString += " , "; 287 | BMAdata = String(""); //clear out the datastring 288 | BMAdata += String(x); 289 | BMAdata += ","; 290 | BMAdata += String(y); 291 | BMAdata += ","; 292 | BMAdata += String(z); 293 | BMAdata += ","; 294 | BMAtempfloat = (BMAtemp*0.5)+24.0; 295 | // add digits of BMAtempfloat value to datastring 296 | BMAdata += ((int)BMAtempfloat); 297 | BMAdata += "."; 298 | int temp = (BMAtempfloat - (int)BMAtempfloat) * 100; 299 | BMAdata += (abs(temp)); 300 | //this also works to convert float to string 301 | //dtostrf(floatVariable2convert, minStringWidthIncDecimalPoint, numVarsAfterDecimal, charBuffer); 302 | //for example: dtostrf(BMAtempfloat, 5, 2, dtostrfbuffer); dataString += dtostrfbuffer; 303 | } 304 | 305 | 306 | byte initializeBMA() 307 | { 308 | Wire.beginTransmission(BMA250); 309 | Wire.write(0x0F); //set g 310 | Wire.write(GSEL); 311 | Wire.endTransmission(); 312 | Wire.beginTransmission(BMA250); 313 | Wire.write(0x10); //set bandwith 314 | Wire.write(BW); 315 | Wire.endTransmission(); 316 | return(0); 317 | } 318 | 319 | long readVcc() { //trick to read the Vin using internal 1.1 v as a refrence 320 | long result; 321 | // Read 1.1V reference against AVcc 322 | ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 323 | delay(3); // Wait for Vref to settle 324 | ADCSRA |= _BV(ADSC); // Convert 325 | while (bit_is_set(ADCSRA,ADSC)); 326 | result = ADCL; 327 | result |= ADCH<<8; 328 | result = 1126400L / result; // Back-calculate AVcc in mV 329 | return result; 330 | } 331 | 332 | int freeRam () { 333 | extern int __heap_start, *__brkval; 334 | int v; 335 | return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 336 | } 337 | 338 | 339 | -------------------------------------------------------------------------------- /_20140222_CleanerCode_ArrayLoopsWorking/_20140222_CleanerCode_ArrayLoopsWorking.ino: -------------------------------------------------------------------------------- 1 | // Date, Time and Alarm functions using a DS3231 RTC connected via I2C and Wire lib by https://github.com/MrAlvin/RTClib 2 | // based largely on Jean-Claude Wippler from JeeLab's excellent RTC library https://github.com/jcw 3 | // clear alarm interupt from http://forum.arduino.cc/index.php?topic=109062.0 4 | // get temp from http://forum.arduino.cc/index.php/topic,22301.0.html which does not use the RTCLIB! 5 | // BMA250_I2C_Sketch.pde -BMA250 Accelerometer using I2C from www.dsscircuits.com/accelerometer-bma250.html 6 | // combined with internal voltage reading trick //forum.arduino.cc/index.php/topic,15629.0.html 7 | // floats to string conversion: http://dereenigne.org/arduino/arduino-float-to-string 8 | 9 | // free ram code trick: http://learn.adafruit.com/memories-of-an-arduino/measuring-free-memory 10 | // power saving during sleep from http://www.gammon.com.au/forum/?id=11497 11 | 12 | // free ram stable at around 715 with 5 cycles 13 | // about 12 bytes per data cycle! 681 freeram with 10 cycles! 14 | 15 | #include //a memory hog - takes 512 bytes of ram just to run! 16 | #include 17 | #include // not used here, but needed to prevent a RTClib compile error 18 | #include 19 | #include 20 | #include 21 | 22 | #ifndef cbi //defs for stopping the ADC during sleep mode 23 | #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) 24 | #endif 25 | #ifndef sbi 26 | #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) 27 | #endif 28 | 29 | #define DS3231_I2C_ADDRESS 104 //for the RTC temp reading function 30 | #define EEPROM_ADDR 0x57 // I2C Buss address of AT24C32 32K EEPROM 31 | 32 | #define BMA250 0x18 33 | #define BW 0x08 //7.81Hz bandwidth 34 | #define GSEL 0x03 // set range 0x03 - 2g, 0x05 - 4, 0x08 - 8g, 0x0C - 16g 35 | 36 | #define SampleInterval 1 // power-down time in minutes before interrupt triggers the next sample 37 | #define SamplesPerSRAMCycle 10 //# of sample cycles before writing to the sd card 38 | 39 | RTC_DS3231 RTC; 40 | byte Alarmhour = 1; 41 | byte Alarmminute = 1; 42 | byte dummyRegister; 43 | byte INTERRUPT_PIN = 2; 44 | volatile boolean clockInterrupt = false; 45 | byte tMSB, tLSB; //for the RTC temp reading function 46 | float RTCTempfloat; 47 | char SRAMCycleTimeStamp[ ]= "0000/00/00,00:00:00"; 48 | byte Cycle=0; 49 | 50 | const byte chipSelect = 10; //sd card chip select 51 | 52 | uint8_t dataArray[16]; //variables for accellerometer reading 53 | int8_t BMAtemp; //why does the bma temp read out as an integer? Temp is in units of 0.5 degrees C 54 | //8 bits given in two's complement representation 55 | float BMAtempfloat;//float BMATempHolder; 56 | //char BMATempHolder[ ]= "00.00"; 57 | //components for holding bma temp as two integers - we have no negative temps in our application 58 | uint8_t wholeBMAtemp[SamplesPerSRAMCycle],fracBMAtemp[SamplesPerSRAMCycle]; 59 | 60 | int x,y,z; //these guys range to negative values 61 | int xAcc[SamplesPerSRAMCycle],yAcc[SamplesPerSRAMCycle],zAcc[SamplesPerSRAMCycle]; 62 | 63 | uint8_t wRTCtemp[SamplesPerSRAMCycle],fRTCtemp[SamplesPerSRAMCycle]; //components for holding RTC temp as two intergers 64 | int temp3231; 65 | int Vcc[SamplesPerSRAMCycle];//the supply voltage via 1.1 internal band gap 66 | 67 | byte ledpin = 13; //led indicator pin not used in this code 68 | 69 | void setup () { 70 | 71 | pinMode(INTERRUPT_PIN, INPUT); 72 | digitalWrite(INTERRUPT_PIN, HIGH);//pull up the interrupt pin 73 | pinMode(13, OUTPUT); // initialize the LED pin as an output. 74 | digitalWrite(13, HIGH); // turn the LED on to warn against SD card removal 75 | 76 | Serial.begin(9600); 77 | Wire.begin(); 78 | RTC.begin(); 79 | DateTime now = RTC.now(); 80 | DateTime compiled = DateTime(__DATE__, __TIME__); 81 | if (now.unixtime() < compiled.unixtime()) { 82 | Serial.println(F("RTC is older than compile time! Updating")); 83 | // following line sets the RTC to the date & time this sketch was compiled 84 | RTC.adjust(DateTime(__DATE__, __TIME__)); 85 | } 86 | clearClockTrigger(); //stops RTC from holding the interrupt low if system reset 87 | // time for next alarm 88 | Alarmhour = now.hour(); 89 | Alarmminute = now.minute()+ SampleInterval ; 90 | if (Alarmminute > 59) { //error catch - if Alarmminute=60 the interrupt never triggers due to rollover 91 | Alarmminute = 0; 92 | Alarmhour = Alarmhour+1; 93 | if (Alarmhour > 23) { 94 | Alarmhour =0; 95 | } 96 | } 97 | 98 | initializeBMA(); //initialize the accelerometer - do I have to do this on every wake cycle? 99 | 100 | //get the SD card ready 101 | pinMode(chipSelect, OUTPUT); //make sure that the default chip select pin is set to output, even if you don't use it 102 | Serial.print(F("Initializing SD card...")); 103 | if (!SD.begin(chipSelect)) { // see if the card is present and can be initialized: 104 | Serial.println(F("Card failed, or not present")); // don't do anything more: 105 | return; 106 | } 107 | Serial.println(F("card initialized.")); 108 | Serial.print(F("The sample interval for this series is: ")); 109 | Serial.print(SampleInterval); 110 | Serial.println(F(" minutes")); 111 | Serial.println(F("Timestamp Y/M/D, HH:MM:SS,Time offset, Vcc = , X = , Y = , Z = , BMATemp (C) , RTC temp (C)")); 112 | 113 | File dataFile = SD.open("datalog.txt", FILE_WRITE); //PRINT THE DATA FILE HEADER 114 | if (dataFile) { // if the file is available, write to it: 115 | dataFile.print(F("The sample interval for this series is: ")); 116 | dataFile.print(SampleInterval); 117 | dataFile.println(F(" minutes.")); 118 | dataFile.print(F("A full timestamp will be generated every")); 119 | dataFile.print(SamplesPerSRAMCycle); 120 | dataFile.println(F(" samples.")); 121 | dataFile.println(F("YYYY/MM/DD HH:MM:SS, Cycle# = Time offset, Vcc(mV), X = , Y = , Z = , BMATemp (C) , RTC temp (C)")); 122 | dataFile.close(); 123 | } 124 | else { //if the file isn't open, pop up an error: 125 | Serial.println(F("Error opening datalog.txt file!")); 126 | } 127 | digitalWrite(13, LOW); 128 | } 129 | 130 | void loop () { 131 | 132 | for (int Cycle = 0; Cycle < SamplesPerSRAMCycle; Cycle++) { //this counts from 0 to (SamplesPerSRAMCycle-1) 133 | 134 | if (clockInterrupt) { 135 | clearClockTrigger(); 136 | } 137 | 138 | read3AxisAcceleration(); //loads up the dataString 139 | DateTime now = RTC.now(); // Read the time and date from the RTC 140 | 141 | if(Cycle==0){ //timestamp for each cycle only gets set once 142 | sprintf(SRAMCycleTimeStamp, "%04d/%02d/%02d %02d:%02d:%02d", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second()); 143 | } 144 | 145 | xAcc[Cycle]=x; 146 | yAcc[Cycle]=y; 147 | zAcc[Cycle]=z; //BMAtemp_[Cycle] = BMAtempfloat; 148 | wholeBMAtemp[Cycle] = (int)BMAtempfloat; 149 | fracBMAtemp[Cycle]= (BMAtempfloat - wholeBMAtemp[Cycle]) * 100; // Float split into 2 intergers 150 | //can use sprintf(BMATempHolder, "%2d.%2d", wholeBMAtemp[Cycle], fracBMAtemp[Cycle]) if we need to recompose that float 151 | Vcc[Cycle] = (readVcc()); 152 | RTCTempfloat= get3231Temp(); 153 | wRTCtemp[Cycle] = (int)RTCTempfloat; 154 | fRTCtemp[Cycle]= (RTCTempfloat - wRTCtemp[Cycle]) * 100; // Float split into 2 intergers 155 | 156 | //main serial line output loop - which can be commented out for deployment 157 | Serial.print(SRAMCycleTimeStamp); 158 | Serial.print(F(" Cycle ")); 159 | Serial.print(Cycle); 160 | Serial.print(","); 161 | Serial.print(Vcc[Cycle]); 162 | Serial.print(","); 163 | Serial.print(xAcc[Cycle]); 164 | Serial.print(","); 165 | Serial.print(yAcc[Cycle]); 166 | Serial.print(","); 167 | ; 168 | Serial.print(zAcc[Cycle]); 169 | Serial.print(","); 170 | Serial.print(wholeBMAtemp[Cycle]); 171 | Serial.print("."); 172 | Serial.print(fracBMAtemp[Cycle]); 173 | Serial.print(","); 174 | Serial.print(wRTCtemp[Cycle]); 175 | Serial.print("."); 176 | Serial.print(fRTCtemp[Cycle]); 177 | Serial.print(F(", Ram:")); 178 | Serial.print(freeRam()); 179 | delay(50); //short delay to clear com lines 180 | 181 | // Once each full set of cycles is complete, dump data to the sd card 182 | // but if Vcc below 2.85 volts, dont write to the sd card 183 | if (Cycle==(SamplesPerSRAMCycle-1) && Vcc[Cycle] >= 2850){ 184 | Serial.print(F(" --write data --")); 185 | delay (50);// this line for debugging only 186 | 187 | File dataFile = SD.open("datalog.txt", FILE_WRITE); 188 | 189 | if (dataFile) { // if the file is available, write to it: 190 | 191 | for (int i = 0; i < SamplesPerSRAMCycle; i++) { //loop to dump out one line of data per cycle 192 | if (i=0){ 193 | dataFile.print(SRAMCycleTimeStamp); 194 | } 195 | dataFile.print(F(",offset:")); 196 | dataFile.print(i); 197 | dataFile.print(","); 198 | dataFile.print(Vcc[i]); 199 | dataFile.print(","); 200 | dataFile.print(xAcc[i]); 201 | dataFile.print(","); 202 | dataFile.print(yAcc[i]); 203 | dataFile.print(","); 204 | dataFile.print(zAcc[i]); 205 | dataFile.print(","); 206 | dataFile.print(wholeBMAtemp[i]); 207 | dataFile.print("."); 208 | dataFile.print(fracBMAtemp[i]); 209 | dataFile.print(","); 210 | dataFile.print(wRTCtemp[i]); 211 | dataFile.print("."); 212 | dataFile.println(fRTCtemp[i]); 213 | // do I need to add a delay line here for sd card communications? could I buffer this better to save power? 214 | } 215 | dataFile.close(); 216 | } 217 | else { //if the file isn't open, pop up an error: 218 | Serial.println(F("Error opening datalog.txt file")); 219 | } 220 | } 221 | 222 | // setNextAlarmTime(); 223 | Alarmhour = now.hour(); 224 | Alarmminute = now.minute()+SampleInterval; 225 | if (Alarmminute > 59) { //error catch - if alarmminute=60 the interrupt never triggers due to rollover! 226 | Alarmminute =0; 227 | Alarmhour = Alarmhour+1; 228 | if (Alarmhour > 23) { 229 | Alarmhour =0; 230 | } 231 | } 232 | RTC.setAlarm1Simple(Alarmhour, Alarmminute); 233 | RTC.turnOnAlarm(1); 234 | 235 | //print lines commented out for deployment 236 | Serial.print(F(" Alarm Set:")); 237 | Serial.print(now.hour(), DEC); 238 | Serial.print(':'); 239 | Serial.print(now.minute(), DEC); 240 | Serial.print(F(" Sleep:")); 241 | Serial.print(SampleInterval); 242 | Serial.println(F(" min.")); 243 | delay(100); //a delay long enought to boot out the serial coms 244 | 245 | sleepNow(); //the sleep call is inside the main cycle counter loop 246 | } 247 | 248 | } 249 | 250 | 251 | void sleepNow() { 252 | // set the unused digital pins to output low - only worth 1-2 µA during sleep 253 | // if you have an LED or something like that on an output pin, you will draw more current. 254 | // for (byte i = 0; i <= A5; i++) 255 | // { 256 | // pinMode (i, OUTPUT); 257 | // digitalWrite (i, LOW); 258 | // } 259 | 260 | cbi(ADCSRA,ADEN); // Switch ADC OFF: worth 334 µA during sleep 261 | set_sleep_mode(SLEEP_MODE_PWR_DOWN); 262 | sleep_enable(); 263 | attachInterrupt(0,clockTrigger, LOW); 264 | // turn off brown-out enable in software: worth 25 µA during sleep 265 | // BODS must be set to one and BODSE must be set to zero within four clock cycles 266 | MCUCR = bit (BODS) | bit (BODSE); // turn on brown-out enable select 267 | MCUCR = bit (BODS); // The BODS bit is automatically cleared after three clock cycles 268 | sleep_mode(); 269 | //HERE AFTER WAKING UP 270 | sleep_disable(); 271 | detachInterrupt(0); 272 | sbi(ADCSRA,ADEN); // Switch ADC converter back ON 273 | //digitalWrite(13, HIGH); this doesnt work because of conflict with sd card chip select 274 | } 275 | 276 | void clockTrigger() { 277 | clockInterrupt = true; //do something quick, flip a flag, and handle in loop(); 278 | } 279 | 280 | void clearClockTrigger() 281 | { 282 | Wire.beginTransmission(0x68); //Tell devices on the bus we are talking to the DS3231 283 | Wire.write(0x0F); //Tell the device which address we want to read or write 284 | Wire.endTransmission(); //Before you can write to and clear the alarm flag you have to read the flag first! 285 | Wire.requestFrom(0x68,1); // Read one byte 286 | dummyRegister=Wire.read(); // In this example we are not interest in actually using the bye 287 | Wire.beginTransmission(0x68); //Tell devices on the bus we are talking to the DS3231 288 | Wire.write(0x0F); //Tell the device which address we want to read or write 289 | Wire.write(0b00000000); //Write the byte. The last 0 bit resets Alarm 1 290 | Wire.endTransmission(); 291 | clockInterrupt=false; //Finally clear the flag we use to indicate the trigger occurred 292 | } 293 | 294 | // could also use RTC.getTemperature() from the library here as in: 295 | // RTC.convertTemperature(); //convert current temperature into registers 296 | // Serial.print(RTC.getTemperature()); //read registers and display the temperature 297 | 298 | float get3231Temp() 299 | { 300 | //temp registers (11h-12h) get updated automatically every 64s 301 | Wire.beginTransmission(DS3231_I2C_ADDRESS); 302 | Wire.write(0x11); 303 | Wire.endTransmission(); 304 | Wire.requestFrom(DS3231_I2C_ADDRESS, 2); 305 | 306 | if(Wire.available()) { 307 | tMSB = Wire.read(); //2's complement int portion 308 | tLSB = Wire.read(); //fraction portion 309 | 310 | temp3231 = ((((short)tMSB << 8 | (short)tLSB) >> 6) / 4.0); // Allows for readings below freezing - Thanks to Coding Badly 311 | //temp3231 = (temp3231 * 1.8 + 32.0); // Convert Celcius to Fahrenheit 312 | return temp3231; 313 | 314 | } 315 | else { 316 | temp3231 = 255.0; //Use a value of 255 to error flag that we did not get temp data from the ds3231 317 | } 318 | 319 | return temp3231; 320 | } 321 | 322 | 323 | byte read3AxisAcceleration() 324 | { 325 | Wire.beginTransmission(BMA250); 326 | Wire.write(0x02); 327 | Wire.endTransmission(); 328 | Wire.requestFrom(BMA250,7); 329 | for(int j = 0; j < 7;j++) 330 | { 331 | dataArray[j] = Wire.read(); 332 | } 333 | if(!bitRead(dataArray[0],0)){ 334 | return(0); 335 | } 336 | 337 | BMAtemp = dataArray[6]; 338 | x = dataArray[1] << 8; 339 | x |= dataArray[0]; 340 | x >>= 6; 341 | y = dataArray[3] << 8; 342 | y |= dataArray[2]; 343 | y >>= 6; 344 | z = dataArray[5] << 8; 345 | z |= dataArray[4]; 346 | z >>= 6; 347 | 348 | BMAtempfloat = (BMAtemp*0.5)+24.0; 349 | } 350 | 351 | 352 | byte initializeBMA() 353 | { 354 | Wire.beginTransmission(BMA250); 355 | Wire.write(0x0F); //set g 356 | Wire.write(GSEL); 357 | Wire.endTransmission(); 358 | Wire.beginTransmission(BMA250); 359 | Wire.write(0x10); //set bandwith 360 | Wire.write(BW); 361 | Wire.endTransmission(); 362 | return(0); 363 | } 364 | 365 | long readVcc() { //trick to read the Vin using internal 1.1 v as a reference 366 | long result; 367 | // Read 1.1V reference against AVcc 368 | ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 369 | delay(3); // Wait for Vref to settle 370 | ADCSRA |= _BV(ADSC); // Convert 371 | while (bit_is_set(ADCSRA,ADSC)); 372 | result = ADCL; 373 | result |= ADCH<<8; 374 | result = 1126400L / result; // Back-calculate AVcc in mV 375 | return result; 376 | } 377 | 378 | int freeRam () { 379 | extern int __heap_start, *__brkval; 380 | int v; 381 | return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 382 | } 383 | 384 | 385 | 386 | -------------------------------------------------------------------------------- /_20140225_SRAMloops_wNewLogfileNames/_20140225_SRAMloops_wNewLogfileNames.ino: -------------------------------------------------------------------------------- 1 | // Date, Time and Alarm functions using a DS3231 RTC connected via I2C and Wire lib by https://github.com/MrAlvin/RTClib 2 | // based largely on Jean-Claude Wippler from JeeLab's excellent RTC library https://github.com/jcw 3 | // clear alarm interupt from http://forum.arduino.cc/index.php?topic=109062.0 4 | // get temp from http://forum.arduino.cc/index.php/topic,22301.0.html which does not use the RTCLIB! 5 | // BMA250_I2C_Sketch.pde -BMA250 Accelerometer using I2C from www.dsscircuits.com/accelerometer-bma250.html 6 | // combined with internal voltage reading trick //forum.arduino.cc/index.php/topic,15629.0.html 7 | // floats to string conversion: http://dereenigne.org/arduino/arduino-float-to-string 8 | 9 | // free ram code trick: http://learn.adafruit.com/memories-of-an-arduino/measuring-free-memory 10 | // power saving during sleep from http://www.gammon.com.au/forum/?id=11497 11 | 12 | // new name routine from https://github.com/adafruit/Light-and-Temp-logger 13 | // about 12 bytes per data cycle! 681 freeram with 10 cycles! 14 | 15 | #include //a memory hog - takes 512 bytes of ram just to run! 16 | #include 17 | #include // not used here, but needed to prevent a RTClib compile error 18 | #include 19 | #include 20 | 21 | #ifndef cbi //defs for stopping the ADC during sleep mode 22 | #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) 23 | #endif 24 | #ifndef sbi 25 | #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) 26 | #endif 27 | 28 | #define DS3231_I2C_ADDRESS 104 //for the RTC temp reading function 29 | 30 | #define BMA250 0x18 31 | #define BW 0x08 //7.81Hz bandwith 32 | #define GSEL 0x03 // set range 0x03 - 2g, 0x05 - 4, 0x08 - 8g, 0x0C - 16g 33 | 34 | #define SampleInterval 1 // power-down time in minutes before interupt triggers the next sample 35 | #define SamplesPerCycle 12 //# of sample cycles before writing to the sd card 36 | unsigned int countLogs = 0; // how many records written to each file 37 | unsigned int fileInterval = 96; // #of log records before new logfile is made 38 | /* count each time a log is written into each file. Must be less than 65,535 39 | counts per file. If the sampleinterval is 15min, and fileInterval is 2880 40 | seconds, then 96samples/day * 30days/month = 30 day intervals */ 41 | 42 | //#define ECHO_TO_SERIAL // echo data that we are logging to the serial monitor 43 | // if you don't want to echo the data to serial, comment out the above define 44 | #ifdef ECHO_TO_SERIAL 45 | //#define WAIT_TO_START 46 | /* Wait for serial input in setup(), only if serial is enabled. You don't want 47 | to define WAIT_TO_START unless ECHO_TO_SERIAL is defined, because it would 48 | wait forever to start if you aren't using the serial monitor. 49 | If you want echo to serial, but not wait to start, 50 | just comment out the above define */ 51 | #endif 52 | 53 | File logfile; 54 | char filename[] = "LOGGER00.CSV"; //the first file name 55 | 56 | RTC_DS3231 RTC; 57 | byte Alarmhour = 1; 58 | byte Alarmminute = 1; 59 | byte dummyRegister; 60 | byte INTERRUPT_PIN = 2; 61 | volatile boolean clockInterrupt = false; 62 | byte tMSB, tLSB; //for the RTC temp reading function 63 | float RTCTempfloat; 64 | char CycleTimeStamp[ ]= "0000/00/00,00:00:00"; 65 | byte Cycle=0; 66 | 67 | const byte chipSelect = 10; //sd card chip select 68 | 69 | uint8_t dataArray[16]; //variables for accellerometer reading 70 | int8_t BMAtemp; //why does the bma temp read out as an interger? Temp is in units of 0.5 degrees C 71 | //8 bits given in two's complement representation 72 | float BMAtempfloat;//float BMATempHolder; 73 | //char BMATempHolder[ ]= "00.00"; 74 | //components for holding bma temp as two intergers - we have no negative temps in our application 75 | uint8_t wholeBMAtemp[SamplesPerCycle],fracBMAtemp[SamplesPerCycle]; 76 | 77 | int x,y,z; //these guys range to negative values 78 | int xAcc[SamplesPerCycle],yAcc[SamplesPerCycle],zAcc[SamplesPerCycle]; 79 | 80 | uint8_t wRTCtemp[SamplesPerCycle],fRTCtemp[SamplesPerCycle]; //components for holding RTC temp as two intergers 81 | int temp3231; 82 | int Vcc[SamplesPerCycle];//the supply voltage via 1.1 internal band gap 83 | 84 | byte ledpin = 13; //led indicator pin not used in this code 85 | 86 | void setup () { 87 | 88 | pinMode(INTERRUPT_PIN, INPUT); 89 | digitalWrite(INTERRUPT_PIN, HIGH);//pull up the interrupt pin 90 | pinMode(13, OUTPUT); // initialize the LED pin as an output. 91 | digitalWrite(13, HIGH); // turn the LED on to warn against SD card removal does this work? 92 | 93 | Serial.begin(9600); 94 | Wire.begin(); 95 | RTC.begin(); 96 | clearClockTrigger(); //stops RTC from holding the interrupt low if system reset 97 | // time for next alarm 98 | RTC.turnOffAlarm(1); 99 | 100 | #ifdef WAIT_TO_START // only triggered if WAIT_TO_START is defined at beging of code 101 | Serial.println(F("Type any character to start")); 102 | while (!Serial.available()); 103 | #endif 104 | 105 | 106 | DateTime now = RTC.now(); 107 | DateTime compiled = DateTime(__DATE__, __TIME__); 108 | if (now.unixtime() < compiled.unixtime()) { 109 | Serial.println(F("RTC is older than compile time! Updating")); 110 | // following line sets the RTC to the date & time this sketch was compiled 111 | RTC.adjust(DateTime(__DATE__, __TIME__)); 112 | } 113 | 114 | Alarmhour = now.hour(); 115 | Alarmminute = now.minute()+ SampleInterval ; 116 | if (Alarmminute > 59) { //error catch - if Alarmminute=60 the interrupt never triggers due to rollover 117 | Alarmminute = 0; 118 | Alarmhour = Alarmhour+1; 119 | if (Alarmhour > 23) { 120 | Alarmhour =0; 121 | } 122 | } 123 | 124 | initializeBMA(); //initialize the accelerometer - do I have to do this on every wake cycle? 125 | 126 | delay(1000); //delay to prevent power stutters from writing header to the sd card 127 | 128 | //get the SD card ready 129 | pinMode(chipSelect, OUTPUT); //make sure that the default chip select pin is set to output, even if you don't use it 130 | 131 | // initialize the SD card 132 | Serial.print("Initializing SD card..."); 133 | // make sure that the default chip select pin is set to 134 | // output, even if you don't use it: 135 | pinMode(10, OUTPUT); 136 | 137 | // see if the card is present and can be initialized: 138 | if (!SD.begin(chipSelect)) { 139 | Serial.println("Card failed, or not present"); 140 | // don't do anything more: 141 | return; 142 | } 143 | Serial.println("card initialized."); 144 | 145 | // create a new file 146 | for (uint8_t i = 0; i < 100; i++) { 147 | filename[6] = i/10 + '0'; 148 | filename[7] = i%10 + '0'; 149 | if (! SD.exists(filename)) { 150 | // only open a new file if it doesn't exist 151 | logfile = SD.open(filename, FILE_WRITE); 152 | break; // leave the loop! 153 | } 154 | } 155 | 156 | if (! logfile) { 157 | Serial.println(F("Error creating logger file!")); 158 | error("1"); 159 | } 160 | 161 | logfile.print(F("The sample interval for this series is: ")); 162 | logfile.print(SampleInterval); 163 | logfile.println(F(" minutes")); 164 | logfile.println(F("YYYY/MM/DD HH:MM:SS, Cycle# = Time offset, Vcc(mV), X = , Y = , Z = , BMATemp (C) , RTC temp (C)")); 165 | logfile.close(); 166 | 167 | // if (logfile.writeError || !logfile.sync()) { 168 | // Serial.println(F("Error writing header to logger file!"));error("2"); 169 | // } 170 | 171 | #ifdef ECHO_TO_SERIAL 172 | Serial.print("Logging to: "); 173 | Serial.println(filename); 174 | Serial.print(F("The sample interval for this series is: ")); 175 | Serial.print(SampleInterval); 176 | Serial.println(F(" minutes")); 177 | Serial.println(F("Timestamp Y/M/D, HH:MM:SS,Time offset, Vcc = , X = , Y = , Z = , BMATemp (C) , RTC temp (C)")); 178 | #endif 179 | 180 | digitalWrite(13, LOW); 181 | } 182 | 183 | void loop () { 184 | 185 | // keep track of how many lines have been written to a file 186 | // after so many lines, start a new file 187 | if(countLogs >= fileInterval){ 188 | 189 | // create a new file 190 | for (uint8_t i = 0; i < 100; i++) { 191 | filename[6] = i/10 + '0'; 192 | filename[7] = i%10 + '0'; 193 | if (! SD.exists(filename)) { 194 | // only open a new file if it doesn't exist 195 | logfile = SD.open(filename, FILE_WRITE); 196 | break; // leave the loop! 197 | } 198 | } 199 | 200 | if (! logfile) { 201 | Serial.println(F("Error creating logger file!")); 202 | error("1"); 203 | } 204 | 205 | logfile.print(F("The sample interval for this series is: ")); 206 | logfile.print(SampleInterval); 207 | logfile.println(F(" minutes")); 208 | logfile.println(F("YYYY/MM/DD HH:MM:SS, Cycle#, = Time offset, Vcc(mV), X = , Y = , Z = , BMATemp (C) , RTC temp (C)")); 209 | logfile.close(); 210 | 211 | // if (logfile.writeError || !logfile.sync()) { 212 | // Serial.println(F("Error writing header to logger file!"));error("2"); 213 | // } 214 | 215 | #ifdef ECHO_TO_SERIAL 216 | Serial.print("Logging to: "); 217 | Serial.println(filename); 218 | Serial.print(F("The sample interval for this series is: ")); 219 | Serial.print(SampleInterval); 220 | Serial.println(F(" minutes")); 221 | Serial.println(F("Timestamp Y/M/D, HH:MM:SS,Time offset, Vcc = , X = , Y = , Z = , BMATemp (C) , RTC temp (C)")); 222 | #endif 223 | 224 | countLogs = 0; // reset our counter to zero 225 | 226 | } 227 | 228 | for (int Cycle = 0; Cycle < SamplesPerCycle; Cycle++) { //this counts from 0 to (SamplesPerCycle-1) 229 | 230 | if (clockInterrupt) { 231 | clearClockTrigger(); 232 | } 233 | 234 | read3AxisAcceleration(); //loads up the dataString 235 | DateTime now = RTC.now(); // Read the time and date from the RTC 236 | 237 | if(Cycle==0){ //timestamp for each cycle only gets set once 238 | sprintf(CycleTimeStamp, "%04d/%02d/%02d %02d:%02d:%02d", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second()); 239 | } 240 | 241 | xAcc[Cycle]=x; 242 | yAcc[Cycle]=y; 243 | zAcc[Cycle]=z; //BMAtemp_[Cycle] = BMAtempfloat; 244 | wholeBMAtemp[Cycle] = (int)BMAtempfloat; 245 | fracBMAtemp[Cycle]= (BMAtempfloat - wholeBMAtemp[Cycle]) * 100; // Float split into 2 intergers 246 | //can use sprintf(BMATempHolder, "%2d.%2d", wholeBMAtemp[Cycle], fracBMAtemp[Cycle]) if we need to recompose that float 247 | Vcc[Cycle] = (readVcc()); 248 | if (Vcc[Cycle] < 2800){ 249 | Serial.println(F("Voltage too LOW")); 250 | error ("L"); 251 | } //the hangs the system when the voltage is too low. 252 | 253 | RTCTempfloat= get3231Temp(); 254 | wRTCtemp[Cycle] = (int)RTCTempfloat; 255 | fRTCtemp[Cycle]= (RTCTempfloat - wRTCtemp[Cycle]) * 100; // Float split into 2 intergers 256 | 257 | //main serial line output loop - which can be commented out for deployment 258 | #ifdef ECHO_TO_SERIAL 259 | Serial.print(CycleTimeStamp); 260 | Serial.print(F(" Cycle ")); 261 | Serial.print(Cycle); 262 | Serial.print(F(",")); 263 | Serial.print(Vcc[Cycle]); 264 | Serial.print(F(",")); 265 | Serial.print(xAcc[Cycle]); 266 | Serial.print(F(",")); 267 | Serial.print(yAcc[Cycle]); 268 | Serial.print(F(",")); 269 | ; 270 | Serial.print(zAcc[Cycle]); 271 | Serial.print(F(",")); 272 | Serial.print(wholeBMAtemp[Cycle]); 273 | Serial.print(F(".")); 274 | Serial.print(fracBMAtemp[Cycle]); 275 | Serial.print(F(",")); 276 | Serial.print(wRTCtemp[Cycle]); 277 | Serial.print(F(".")); 278 | Serial.print(fRTCtemp[Cycle]); 279 | Serial.print(F(", Ram:")); 280 | Serial.print(freeRam()); 281 | delay(50); //short delay to clear com lines 282 | #endif 283 | 284 | // Once each full set of cycles is complete, dump data to the sd card 285 | // but if Vcc below 2.85 volts, dont write to the sd card 286 | if (Cycle==(SamplesPerCycle-1) && Vcc[Cycle] >= 2850){ 287 | Serial.print(F(" --write data --")); 288 | delay (50);// this line for debugging only 289 | 290 | File logfile = SD.open(filename, FILE_WRITE); 291 | 292 | if (logfile) { // if the file is available, write to it: 293 | 294 | for (int i = 0; i < SamplesPerCycle; i++) { //loop to dump out one line of data per cycle 295 | logfile.print(CycleTimeStamp); 296 | logfile.print(F(",time offset:,")); 297 | logfile.print(i); 298 | logfile.print(F(",")); 299 | logfile.print(Vcc[i]); 300 | logfile.print(F(",")); 301 | logfile.print(xAcc[i]); 302 | logfile.print(F(",")); 303 | logfile.print(yAcc[i]); 304 | logfile.print(","); 305 | logfile.print(zAcc[i]); 306 | logfile.print(F(",")); 307 | logfile.print(wholeBMAtemp[i]); 308 | logfile.print(F(".")); 309 | logfile.print(fracBMAtemp[i]); 310 | logfile.print(F(",")); 311 | logfile.print(wRTCtemp[i]); 312 | logfile.print(F(".")); 313 | logfile.print(fRTCtemp[i]); 314 | logfile.println(F(",")); 315 | // do I need to add a delay line here for sd card communications? could I buffer this better to save power? 316 | countLogs++; 317 | } 318 | logfile.close(); 319 | } 320 | else { //if the file isn't open, pop up an error: 321 | Serial.println(F("Error opening datalog.txt file")); 322 | } 323 | } 324 | 325 | // setNextAlarmTime(); 326 | Alarmhour = now.hour(); 327 | Alarmminute = now.minute()+SampleInterval; 328 | if (Alarmminute > 59) { //error catch - if alarmminute=60 the interrupt never triggers due to rollover! 329 | Alarmminute =0; 330 | Alarmhour = Alarmhour+1; 331 | if (Alarmhour > 23) { 332 | Alarmhour =0; 333 | } 334 | } 335 | RTC.setAlarm1Simple(Alarmhour, Alarmminute); 336 | RTC.turnOnAlarm(1); 337 | 338 | //print lines commented out for deployment 339 | Serial.print(F(" Alarm Set:")); 340 | Serial.print(now.hour(), DEC); 341 | Serial.print(':'); 342 | Serial.print(now.minute(), DEC); 343 | Serial.print(F(" Sleep:")); 344 | Serial.print(SampleInterval); 345 | Serial.println(F(" min.")); 346 | delay(100); //a delay long enought to boot out the serial coms 347 | 348 | sleepNow(); //the sleep call is inside the main cycle counter loop 349 | } 350 | 351 | } 352 | 353 | 354 | 355 | void sleepNow() { 356 | // set the unused digital pins to output low - only worth 1-2 µA during sleep 357 | // if you have an LED or something like that on an output pin, you will draw more current. 358 | // for (byte i = 0; i <= A5; i++) 359 | // { 360 | // pinMode (i, OUTPUT); 361 | // digitalWrite (i, LOW); 362 | // } 363 | 364 | cbi(ADCSRA,ADEN); // Switch ADC OFF: worth 334 µA during sleep 365 | set_sleep_mode(SLEEP_MODE_PWR_DOWN); 366 | sleep_enable(); 367 | attachInterrupt(0,clockTrigger, LOW); 368 | // turn off brown-out enable in software: worth 25 µA during sleep 369 | // BODS must be set to one and BODSE must be set to zero within four clock cycles 370 | MCUCR = bit (BODS) | bit (BODSE); // turn on brown-out enable select 371 | MCUCR = bit (BODS); // The BODS bit is automatically cleared after three clock cycles 372 | sleep_mode(); 373 | //HERE AFTER WAKING UP 374 | sleep_disable(); 375 | detachInterrupt(0); 376 | sbi(ADCSRA,ADEN); // Switch ADC converter back ON 377 | //digitalWrite(13, HIGH); this doesnt work because of conflict with sd card chip select 378 | } 379 | 380 | void clockTrigger() { 381 | clockInterrupt = true; //do something quick, flip a flag, and handle in loop(); 382 | } 383 | 384 | void clearClockTrigger() 385 | { 386 | Wire.beginTransmission(0x68); //Tell devices on the bus we are talking to the DS3231 387 | Wire.write(0x0F); //Tell the device which address we want to read or write 388 | Wire.endTransmission(); //Before you can write to and clear the alarm flag you have to read the flag first! 389 | Wire.requestFrom(0x68,1); // Read one byte 390 | dummyRegister=Wire.read(); // In this example we are not interest in actually using the bye 391 | Wire.beginTransmission(0x68); //Tell devices on the bus we are talking to the DS3231 392 | Wire.write(0x0F); //Tell the device which address we want to read or write 393 | Wire.write(0b00000000); //Write the byte. The last 0 bit resets Alarm 1 394 | Wire.endTransmission(); 395 | clockInterrupt=false; //Finally clear the flag we use to indicate the trigger occurred 396 | } 397 | 398 | // could also use RTC.getTemperature() from the library here as in: 399 | // RTC.convertTemperature(); //convert current temperature into registers 400 | // Serial.print(RTC.getTemperature()); //read registers and display the temperature 401 | 402 | float get3231Temp() 403 | { 404 | //temp registers (11h-12h) get updated automatically every 64s 405 | Wire.beginTransmission(DS3231_I2C_ADDRESS); 406 | Wire.write(0x11); 407 | Wire.endTransmission(); 408 | Wire.requestFrom(DS3231_I2C_ADDRESS, 2); 409 | 410 | if(Wire.available()) { 411 | tMSB = Wire.read(); //2's complement int portion 412 | tLSB = Wire.read(); //fraction portion 413 | 414 | temp3231 = ((((short)tMSB << 8 | (short)tLSB) >> 6) / 4.0); // Allows for readings below freezing - Thanks to Coding Badly 415 | //temp3231 = (temp3231 * 1.8 + 32.0); // Convert Celcius to Fahrenheit 416 | return temp3231; 417 | 418 | } 419 | else { 420 | temp3231 = 255.0; //Use a value of 255 to error flag that we did not get temp data from the ds3231 421 | } 422 | 423 | return temp3231; 424 | } 425 | 426 | 427 | byte read3AxisAcceleration() 428 | { 429 | Wire.beginTransmission(BMA250); 430 | Wire.write(0x02); 431 | Wire.endTransmission(); 432 | Wire.requestFrom(BMA250,7); 433 | for(int j = 0; j < 7;j++) 434 | { 435 | dataArray[j] = Wire.read(); 436 | } 437 | if(!bitRead(dataArray[0],0)){ 438 | return(0); 439 | } 440 | 441 | BMAtemp = dataArray[6]; 442 | x = dataArray[1] << 8; 443 | x |= dataArray[0]; 444 | x >>= 6; 445 | y = dataArray[3] << 8; 446 | y |= dataArray[2]; 447 | y >>= 6; 448 | z = dataArray[5] << 8; 449 | z |= dataArray[4]; 450 | z >>= 6; 451 | 452 | BMAtempfloat = (BMAtemp*0.5)+24.0; 453 | } 454 | 455 | 456 | byte initializeBMA() 457 | { 458 | Wire.beginTransmission(BMA250); 459 | Wire.write(0x0F); //set g 460 | Wire.write(GSEL); 461 | Wire.endTransmission(); 462 | Wire.beginTransmission(BMA250); 463 | Wire.write(0x10); //set bandwith 464 | Wire.write(BW); 465 | Wire.endTransmission(); 466 | return(0); 467 | } 468 | 469 | long readVcc() { //trick to read the Vin using internal 1.1 v as a refrence 470 | long result; 471 | // Read 1.1V reference against AVcc 472 | ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 473 | delay(3); // Wait for Vref to settle 474 | ADCSRA |= _BV(ADSC); // Convert 475 | while (bit_is_set(ADCSRA,ADSC)); 476 | result = ADCL; 477 | result |= ADCH<<8; 478 | result = 1126400L / result; // Back-calculate AVcc in mV 479 | return result; 480 | } 481 | 482 | int freeRam () { 483 | extern int __heap_start, *__brkval; 484 | int v; 485 | return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 486 | } 487 | 488 | void error(char *str) { 489 | // always write error messages to the serial monitor but this routine wastes 490 | // everything passed to the string from the original call is in sram! 491 | Serial.print(F("error in: ")); 492 | Serial.println(str); 493 | /* this next statement will start an endless loop, basically stopping all 494 | operation upon any error. Change this behavior if you want. */ 495 | // red LED indicates error 496 | //digitalWrite(redLEDpin, HIGH); 497 | while (1); 498 | } 499 | 500 | 501 | 502 | -------------------------------------------------------------------------------- /_20140303_AT24C32_EEpromBuffering_wNewLogFiles/_20140303_AT24C32_EEpromBuffering_wNewLogFiles.ino: -------------------------------------------------------------------------------- 1 | // Date, Time and Alarm functions using a DS3231 RTC connected via I2C and Wire lib by https://github.com/MrAlvin/RTClib 2 | // based largely on Jean-Claude Wippler from JeeLab's excellent RTC library https://github.com/jcw 3 | // clear alarm interupt from http://forum.arduino.cc/index.php?topic=109062.0 4 | // get temp from http://forum.arduino.cc/index.php/topic,22301.0.html 5 | // BMA250_I2C_Sketch.pde -BMA250 Accelerometer using I2C from www.dsscircuits.com/accelerometer-bma250.html 6 | // internal Vcc reading trick //forum.arduino.cc/index.php/topic,15629.0.html 7 | // and http://forum.arduino.cc/index.php?topic=88935.0 8 | // free ram code trick: http://learn.adafruit.com/memories-of-an-arduino/measuring-free-memory 9 | // power saving during sleep from http://www.gammon.com.au/forum/?id=11497 10 | // I2C routine based on http://playground.arduino.cc/Code/I2CEEPROM#.UwrbpPldUyI 11 | // New file name routine from http://forums.adafruit.com/viewtopic.php?f=31&t=17964 12 | 13 | #include // 128 byte Serial buffer 14 | #include // not used here, but needed to prevent a RTClib compile error 15 | #include 16 | #include 17 | #include 18 | #include 19 | SdFat sd; // Create the objects to talk to the SD card 20 | SdFile file; 21 | const byte chipSelect = 10; //sd card chip select 22 | 23 | #define SampleInterval 1 // power-down time in minutes before interupt triggers the next sample 24 | #define SamplesPerCycle 16 // # of sample cycles to buffer in eeprom before writing to the sd card: MAX of 96! 25 | unsigned int countLogs = 0; // how many records written to each file 26 | unsigned int fileInterval = 31; // #of log records before new logfile is made 27 | /* count each time a log is written into each file. Must be less than 65,535 28 | counts per file. If the sampleinterval is 15min, and fileInterval is 2880 29 | seconds, then 96samples/day * 30days/month = 30 day intervals */ 30 | 31 | #define ECHO_TO_SERIAL // echo data that we are logging to the serial monitor 32 | // if you don't want to echo the data to serial, comment out the above define 33 | #ifdef ECHO_TO_SERIAL 34 | //#define WAIT_TO_START 35 | /* Wait for serial input in setup(), only if serial is enabled. You don't want 36 | to define WAIT_TO_START unless ECHO_TO_SERIAL is defined, because it would 37 | wait forever to start if you aren't using the serial monitor. 38 | If you want echo to serial, but not wait to start, 39 | just comment out the above define */ 40 | #endif 41 | 42 | char FileName[] = "LOG00000.CSV"; //the first file name 43 | 44 | #ifndef cbi //defs for stopping the ADC during sleep mode 45 | #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) 46 | #endif 47 | #ifndef sbi 48 | #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) 49 | #endif 50 | 51 | #define DS3231_I2C_ADDRESS 104 //for the RTC temp reading function 52 | #define EEPROM_ADDR 0x57 // I2C Buss address of AT24C32 32K EEPROM 53 | #define EEPromPageSize 32 //32 bytes for the AT24c32 I am using 54 | 55 | #define BMA250 0x18 56 | #define BW 0x08 //7.81Hz bandwith 57 | #define GSEL 0x03 // set range 0x03=2g, 0x05=4, 0x08=8g, 0x0C=16g 58 | 59 | //I2C eeprom variables 60 | unsigned int CurrentPageStartAddress = 0; //set to zero at the start of each cycle 61 | char EEPROMBuffer[28]; //this buffer contains a string of ascii 62 | //char EEPROMinBuffer[28]; // this buffer recieves numbers from the eeprom was an unsigned char 63 | //note the data read from the eeprom is binary - not ascii characters! 64 | 65 | RTC_DS3231 RTC; 66 | byte Alarmhour = 1; 67 | byte Alarmminute = 1; 68 | byte dummyRegister; 69 | byte INTERRUPT_PIN = 2; 70 | volatile boolean clockInterrupt = false; 71 | byte tMSB, tLSB; //for the RTC temp reading function 72 | float RTCTempfloat; 73 | char CycleTimeStamp[ ]= "0000/00/00,00:00:00"; 74 | byte Cycle=0; 75 | 76 | //variables for accellerometer reading 77 | uint8_t dataArray[16]; 78 | int8_t BMAtemp; 79 | float BMAtempfloat; 80 | uint8_t wholeBMAtemp,fracBMAtemp; 81 | int x,y,z; //acc readings range to negative values 82 | 83 | int temp3231; 84 | uint8_t wRTCtemp,fRTCtemp; //components for holding RTC temp as whole and fraction component integers 85 | int Vcc;//the supply voltage via 1.1 internal band gap 86 | byte ledpin = 13; //led indicator pin not used in this code 87 | 88 | void setup () { 89 | 90 | pinMode(INTERRUPT_PIN, INPUT); 91 | digitalWrite(INTERRUPT_PIN, HIGH);//pull up the interrupt pin 92 | pinMode(13, OUTPUT); // initialize the LED pin as an output. 93 | 94 | Serial.begin(9600); 95 | Wire.begin(); 96 | RTC.begin(); 97 | clearClockTrigger(); //stops RTC from holding the interrupt low if system reset 98 | // time for next alarm 99 | RTC.turnOffAlarm(1); 100 | 101 | #ifdef WAIT_TO_START // only triggered if WAIT_TO_START is defined at beging of code 102 | Serial.println(F("Type any character to start")); 103 | while (!Serial.available()); 104 | #endif 105 | 106 | DateTime now = RTC.now(); 107 | 108 | DateTime compiled = DateTime(__DATE__, __TIME__); 109 | if (now.unixtime() < compiled.unixtime()) { //checks if the RTC is not set yet 110 | Serial.println(F("RTC is older than compile time! Updating")); 111 | // following line sets the RTC to the date & time this sketch was compiled 112 | RTC.adjust(DateTime(__DATE__, __TIME__)); 113 | } 114 | 115 | initializeBMA(); //initialize the accelerometer - do I have to do this on every wake cycle? 116 | 117 | //get the SD card ready 118 | pinMode(chipSelect, OUTPUT); //make sure that the default chip select pin is set to output, even if you don't use it 119 | 120 | #ifdef ECHO_TO_SERIAL 121 | Serial.print(F("Initializing SD card...")); 122 | #endif 123 | 124 | // Initialize SdFat or print a detailed error message and halt 125 | // Use half speed like the native library. // change to SPI_FULL_SPEED for more performance. 126 | if (!sd.begin(chipSelect, SPI_HALF_SPEED)) { 127 | Serial.println(F("Cound not Initialize Sd Card")); 128 | error("0"); 129 | } 130 | 131 | #ifdef ECHO_TO_SERIAL 132 | Serial.println(F("card initialized.")); 133 | Serial.print(F("The sample interval for this series is: ")); 134 | Serial.print(SampleInterval); 135 | Serial.println(F(" minutes")); 136 | Serial.println(F("Timestamp Y/M/D, HH:MM:SS,Time offset, Vcc = , X = , Y = , Z = , BMATemp (C) , RTC temp (C)")); 137 | #endif 138 | 139 | // open the file for write at end like the Native SD library 140 | // O_CREAT - create the file if it does not exist 141 | if (!file.open(FileName, O_RDWR | O_CREAT | O_AT_END)) { 142 | Serial.println(F("1st open LOG.CSV fail")); 143 | error("1"); 144 | } 145 | 146 | file.print(F("The sample interval for this series is: ")); 147 | file.print(SampleInterval); 148 | file.println(F(" minutes")); 149 | file.println(F("YYYY/MM/DD HH:MM:SS, Vcc(mV), X = , Y = , Z = , BMATemp (C) , RTC temp (C)")); 150 | file.close(); 151 | 152 | 153 | digitalWrite(13, LOW); 154 | } 155 | 156 | void loop () { 157 | 158 | // keep track of how many lines have been written to a file 159 | // after so many lines, start a new file 160 | if(countLogs >= fileInterval){ 161 | countLogs = 0; // reset our counter to zero 162 | createLogFile(); // create a new file 163 | } 164 | 165 | CurrentPageStartAddress = 0; 166 | 167 | for (int Cycle = 0; Cycle < SamplesPerCycle; Cycle++) { //this counts from 0 to (SamplesPerCycle-1) 168 | 169 | if (clockInterrupt) { 170 | clearClockTrigger(); 171 | } 172 | 173 | read3AxisAcceleration(); //loads up the Acc data 174 | DateTime now = RTC.now(); // Read the time and date from the RTC 175 | 176 | sprintf(CycleTimeStamp, "%04d/%02d/%02d %02d:%02d:%02d", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second()); 177 | 178 | wholeBMAtemp = (int)BMAtempfloat; 179 | fracBMAtemp= (BMAtempfloat - wholeBMAtemp) * 100; // Float split into 2 intergers 180 | //can use sprintf(BMATempHolder, "%2d.%2d", wholeBMAtemp[Cycle], fracBMAtemp[Cycle]) if we need to recompose that float 181 | RTCTempfloat= get3231Temp(); 182 | wRTCtemp = (int)RTCTempfloat; 183 | fRTCtemp= (RTCTempfloat - wRTCtemp) * 100; // Float split into 2 intergers 184 | Vcc = (readVcc()); 185 | if (Vcc < 2800){ 186 | Serial.println(F("Voltage too LOW")); 187 | error ("L"); 188 | } 189 | 190 | //serial output for debugging - comment out ECHO_TO_SERIAL to eliminate 191 | #ifdef ECHO_TO_SERIAL 192 | Serial.print(CycleTimeStamp); 193 | Serial.print(F(" Cycle ")); 194 | Serial.print(Cycle); 195 | Serial.print(F(",")); 196 | Serial.print(Vcc); 197 | Serial.print(F(",")); 198 | Serial.print(x); 199 | Serial.print(F(",")); 200 | Serial.print(y); 201 | Serial.print(F(",")); 202 | ; 203 | Serial.print(z); 204 | Serial.print(F(",")); 205 | Serial.print(wholeBMAtemp); 206 | Serial.print(F(".")); 207 | Serial.print(fracBMAtemp); 208 | Serial.print(F(",")); 209 | Serial.print(wRTCtemp); 210 | Serial.print(F(".")); 211 | Serial.print(fRTCtemp); 212 | Serial.print(F(", Ram:")); 213 | Serial.print(freeRam()); 214 | delay(40); //short delay to clear com lines 215 | #endif 216 | 217 | //Construct first char string of 28 bytes - end of buffer is filled with blank spaces flexibly with pstring 218 | //but could contruct the buffer with sprintf if I wasn't changing my sensors so often! 219 | 220 | PString str(EEPROMBuffer, sizeof(EEPROMBuffer)); 221 | str = CycleTimeStamp; 222 | str.print(F(",")); 223 | str.print(Vcc); 224 | str.print(F(" ")); 225 | 226 | Write_i2c_eeprom_page(EEPROM_ADDR, CurrentPageStartAddress, EEPROMBuffer); // whole page is written at once here 227 | CurrentPageStartAddress += EEPromPageSize; 228 | 229 | //Construct second char string of 28 bytes to complete the record 230 | str = ","; 231 | str.print(x); 232 | str.print(F(",")); 233 | str.print(y); 234 | str.print(F(",")); 235 | str.print(z); 236 | str.print(F(",")); 237 | str.print(wholeBMAtemp); 238 | str.print(F(".")); 239 | str.print(fracBMAtemp); 240 | str.print(F(",")); 241 | str.print(wRTCtemp); 242 | str.print(F(".")); 243 | str.print(fRTCtemp); 244 | str.print(F(",")); 245 | str.print(F(" ")); 246 | 247 | Write_i2c_eeprom_page(EEPROM_ADDR, CurrentPageStartAddress, EEPROMBuffer); // 28 bytes/page is max whole page is written at once here 248 | CurrentPageStartAddress += EEPromPageSize; 249 | 250 | // IF full set of sample cycles is complete, run a loop to dump data to the sd card 251 | // BUT only if Vcc is above 2.85 volts so we have enough juice! 252 | if (Cycle==(SamplesPerCycle-1) && Vcc >= 2850){ 253 | 254 | #ifdef ECHO_TO_SERIAL 255 | Serial.print(F(" --Writing to SDcard --")); 256 | delay (10);// this line for debugging only 257 | #endif 258 | 259 | CurrentPageStartAddress=0; //reset the page counter back to the beginning 260 | 261 | file.open(FileName, O_RDWR | O_AT_END); 262 | // open the file for write at end like the Native SD library 263 | //if (!file.open(FileName, O_RDWR | O_AT_END)) { 264 | // error("L open file fail"); 265 | //} 266 | 267 | for (int i = 0; i < SamplesPerCycle; i++) { //loop to read back and write to SD card 268 | 269 | Read_i2c_eeprom_page(EEPROM_ADDR, CurrentPageStartAddress, EEPROMBuffer, sizeof(EEPROMBuffer) ); //there will be a few blank spaces 270 | CurrentPageStartAddress += EEPromPageSize; 271 | file.write(EEPROMBuffer,sizeof(EEPROMBuffer)); 272 | 273 | Read_i2c_eeprom_page(EEPROM_ADDR, CurrentPageStartAddress, EEPROMBuffer, sizeof(EEPROMBuffer) ); 274 | CurrentPageStartAddress += EEPromPageSize; 275 | file.write(EEPROMBuffer,sizeof(EEPROMBuffer)); 276 | file.println(F(" ")); 277 | 278 | countLogs++; 279 | // An application which writes to a file using print(), println() or write() must call sync() 280 | // at the appropriate time to force data and directory information to be written to the SD Card. 281 | // every 8 cycles we have dumped approximately 512 bytes to the card 282 | // note only going to buffer 96 cycles to eeprom (one day at 15 min samples) 283 | if(i==8){ 284 | syncTheFile; 285 | } 286 | if(i==16){ 287 | syncTheFile; 288 | } 289 | if(i==24){ 290 | syncTheFile; 291 | } 292 | if(i==32){ 293 | syncTheFile; 294 | } 295 | if(i==40){ 296 | syncTheFile; 297 | } 298 | if(i==48){ 299 | syncTheFile; 300 | } 301 | if(i==56){ 302 | syncTheFile; 303 | } 304 | if(i==64){ 305 | syncTheFile; 306 | } 307 | if(i==72){ 308 | syncTheFile; 309 | } 310 | if(i==80){ 311 | syncTheFile; 312 | } 313 | if(i==88){ 314 | syncTheFile; 315 | } 316 | } 317 | 318 | file.close(); 319 | 320 | } 321 | 322 | // setNextAlarmTime(); 323 | Alarmhour = now.hour(); 324 | Alarmminute = now.minute()+SampleInterval; 325 | if (Alarmminute > 59) { //error catch - if alarmminute=60 the interrupt never triggers due to rollover! 326 | Alarmminute =0; 327 | Alarmhour = Alarmhour+1; 328 | if (Alarmhour > 23) { 329 | Alarmhour =0; 330 | } 331 | } 332 | RTC.setAlarm1Simple(Alarmhour, Alarmminute); 333 | RTC.turnOnAlarm(1); 334 | 335 | #ifdef ECHO_TO_SERIAL 336 | Serial.print(F(" Alarm Set:")); 337 | Serial.print(now.hour(), DEC); 338 | Serial.print(':'); 339 | Serial.print(now.minute(), DEC); 340 | Serial.print(F(" Sleep:")); 341 | Serial.print(SampleInterval); 342 | Serial.println(F(" min.")); 343 | delay(100); //a delay long enought to boot out the serial coms 344 | #endif 345 | 346 | sleepNow(); //the sleep call is inside the main cycle counter loop 347 | 348 | } //samples per cycle loop terminator 349 | 350 | } //the main void loop terminator 351 | 352 | 353 | void error(char *str) { 354 | // always write error messages to the serial monitor but this routine wastes 355 | // everything passed to the string from the original call is in sram! 356 | Serial.print(F("error in: ")); 357 | Serial.println(str); 358 | /* this next statement will start an endless loop, basically stopping all 359 | operation upon any error. Change this behavior if you want. */ 360 | while (1); 361 | } 362 | 363 | void createLogFile(void) { 364 | // create a new file, up to 100,000 files allowed 365 | // we will create a new file every time this routine is called 366 | 367 | // If we are creating another file after fileInterval, then we must 368 | // close the open file first. 369 | if (file.isOpen()) { 370 | file.close(); 371 | } 372 | for (uint16_t i = 0; i < 100000; i++) { 373 | FileName[3] = i/10000 + '0'; 374 | FileName[4] = i/1000 + '0'; 375 | FileName[5] = i/100 + '0'; 376 | FileName[6] = i/10 + '0'; 377 | FileName[7] = i%10 + '0'; 378 | // O_CREAT - create the file if it does not exist 379 | // O_EXCL - fail if the file exists 380 | // O_WRITE - open for write 381 | if (file.open(FileName, O_CREAT | O_EXCL | O_WRITE)) break; //if you can open a file with the new name, break out of the loop 382 | } 383 | 384 | // clear the writeError flags generated when we broke the new name loop 385 | file.writeError = 0; 386 | 387 | if (!file.isOpen()) error ("diskful?"); 388 | Serial.print(F("Logging to: ")); 389 | Serial.println(FileName); 390 | 391 | // fetch the time 392 | DateTime now = RTC.now(); 393 | // set creation date time 394 | if (!file.timestamp(T_CREATE,now.year(),now.month(),now.day(),now.hour(), 395 | now.minute(),now.second() )) { 396 | error("cr t"); 397 | } 398 | // set write/modification date time 399 | if (!file.timestamp(T_WRITE,now.year(),now.month(),now.day(),now.hour(), 400 | now.minute(),now.second() )) { 401 | error("wr t"); 402 | } 403 | // set access date 404 | if (!file.timestamp(T_ACCESS,now.year(),now.month(),now.day(),now.hour(), 405 | now.minute(),now.second() )) { 406 | error("ac t"); 407 | } 408 | file.sync(); 409 | //file.close(); 410 | //file.open(FileName, O_RDWR | O_AT_END); 411 | 412 | // write the file as a header: 413 | file.print(F("The sample interval for this series is:")); 414 | ; 415 | Serial.print(SampleInterval); 416 | Serial.println(F(" minutes")); 417 | file.println(F("YYYY/MM/DD HH:MM:SS, Vcc(mV), X = , Y = , Z = , BMATemp (C) , RTC temp (C)")); 418 | file.close(); 419 | 420 | //#ifdef ECHO_TO_SERIAL 421 | // Serial.println(F("YYYY/MM/DD HH:MM:SS, Vcc(mV), X = , Y = , Z = , BMATemp (C) , RTC temp (C)")); 422 | //#endif // ECHO_TO_SERIAL 423 | 424 | // write out the header to the file, only upon creating a new file 425 | if (file.writeError) { 426 | // check if error writing 427 | error("write header"); 428 | } 429 | 430 | // if (!file.sync()) { 431 | // check if error writing 432 | // error("fsync er"); 433 | // } 434 | 435 | } 436 | 437 | 438 | void syncTheFile(void) { 439 | /* don't sync too often - requires 2048 bytes of I/O to SD card. 440 | 512 bytes of I/O if using Fat16 library */ 441 | 442 | /* blink LED to show we are syncing data to the card & updating FAT! 443 | you could use the LED on pin 13, or whatever pin had an LED */ 444 | // digitalWrite(greenLEDpin, HIGH); 445 | 446 | if (!file.sync()) error("sync error"); 447 | 448 | // digitalWrite(greenLEDpin, LOW); 449 | } 450 | 451 | 452 | // Address is a page address 453 | // But data can be maximum of 28 bytes, because the Wire library has a buffer of 32 bytes 454 | 455 | void Write_i2c_eeprom_page( int deviceaddress, unsigned int eeaddress, char* data) { 456 | unsigned char i=0; 457 | unsigned int address; 458 | address=eeaddress; 459 | Wire.beginTransmission(deviceaddress); 460 | Wire.write((int)((address) >> 8)); // MSB 461 | Wire.write((int)((address) & 0xFF)); // LSB 462 | do{ 463 | Wire.write((byte) data[i]); 464 | i++; 465 | } 466 | while(data[i]); 467 | Wire.endTransmission(); 468 | delay(10); // data sheet says 5ms for page write 469 | } 470 | 471 | // should not read more than 28 bytes at a time! 472 | 473 | void Read_i2c_eeprom_page( int deviceaddress, unsigned int eeaddress,char* data, unsigned int num_chars) { 474 | unsigned char i=0; 475 | Wire.beginTransmission(deviceaddress); 476 | Wire.write((int)(eeaddress >> 8)); // MSB 477 | Wire.write((int)(eeaddress & 0xFF)); // LSB 478 | Wire.endTransmission(); 479 | Wire.requestFrom(deviceaddress,(num_chars-1)); 480 | while(Wire.available()) data[i++] = Wire.read(); 481 | } 482 | 483 | void sleepNow() { 484 | // can set the unused digital pins to output low - BUT only worth 1-2 µA during sleep 485 | // if you have an LED or something like that on an output pin, you will draw more current. 486 | // for (byte i = 0; i <= number of digital pins; i++) 487 | // { 488 | // pinMode (i, OUTPUT); 489 | // digitalWrite (i, LOW); 490 | // } 491 | 492 | cbi(ADCSRA,ADEN); // Switch ADC OFF: worth 334 µA during sleep 493 | set_sleep_mode(SLEEP_MODE_PWR_DOWN); 494 | sleep_enable(); 495 | attachInterrupt(0,clockTrigger, LOW); 496 | // turn off brown-out enable in software: worth 25 µA during sleep 497 | // BODS must be set to one and BODSE must be set to zero within four clock cycles 498 | // BUT http://learn.adafruit.com/low-power-coin-cell-voltage-logger/other-lessons 499 | // MCUCR = bit (BODS) | bit (BODSE); // turn on brown-out enable select 500 | // MCUCR = bit (BODS); // The BODS bit is automatically cleared after three clock cycles 501 | sleep_mode(); 502 | //HERE AFTER WAKING UP 503 | sleep_disable(); 504 | detachInterrupt(0); 505 | sbi(ADCSRA,ADEN); // Switch ADC converter back ON 506 | //digitalWrite(13, HIGH); this doesnt work because of conflict with sd card chip select 507 | } 508 | 509 | void clockTrigger() { 510 | clockInterrupt = true; //do something quick, flip a flag, and handle in loop(); 511 | } 512 | 513 | void clearClockTrigger() 514 | { 515 | Wire.beginTransmission(0x68); //Tell devices on the bus we are talking to the DS3231 516 | Wire.write(0x0F); //Tell the device which address we want to read or write 517 | Wire.endTransmission(); //Before you can write to and clear the alarm flag you have to read the flag first! 518 | Wire.requestFrom(0x68,1); // Read one byte 519 | dummyRegister=Wire.read(); // In this example we are not interest in actually using the bye 520 | Wire.beginTransmission(0x68); //Tell devices on the bus we are talking to the DS3231 521 | Wire.write(0x0F); //Tell the device which address we want to read or write 522 | Wire.write(0b00000000); //Write the byte. The last 0 bit resets Alarm 1 523 | Wire.endTransmission(); 524 | clockInterrupt=false; //Finally clear the flag we use to indicate the trigger occurred 525 | } 526 | 527 | // could also use RTC.getTemperature() from the library here as in: 528 | // RTC.convertTemperature(); //convert current temperature into registers 529 | // Serial.print(RTC.getTemperature()); //read registers and display the temperature 530 | 531 | float get3231Temp() 532 | { 533 | //temp registers (11h-12h) get updated automatically every 64s 534 | Wire.beginTransmission(DS3231_I2C_ADDRESS); 535 | Wire.write(0x11); 536 | Wire.endTransmission(); 537 | Wire.requestFrom(DS3231_I2C_ADDRESS, 2); 538 | 539 | if(Wire.available()) { 540 | tMSB = Wire.read(); //2's complement int portion 541 | tLSB = Wire.read(); //fraction portion 542 | 543 | temp3231 = ((((short)tMSB << 8 | (short)tLSB) >> 6) / 4.0); 544 | // Allows for readings below freezing - Thanks to Coding Badly 545 | //temp3231 = (temp3231 * 1.8 + 32.0); // Convert Celcius to Fahrenheit 546 | return temp3231; 547 | 548 | } 549 | else { 550 | temp3231 = 255.0; //Use a value of 255 as error flag 551 | } 552 | 553 | return temp3231; 554 | } 555 | 556 | 557 | byte read3AxisAcceleration() 558 | { 559 | Wire.beginTransmission(BMA250); 560 | Wire.write(0x02); 561 | Wire.endTransmission(); 562 | Wire.requestFrom(BMA250,7); 563 | for(int j = 0; j < 7;j++) 564 | { 565 | dataArray[j] = Wire.read(); 566 | } 567 | if(!bitRead(dataArray[0],0)){ 568 | return(0); 569 | } 570 | 571 | BMAtemp = dataArray[6]; 572 | x = dataArray[1] << 8; 573 | x |= dataArray[0]; 574 | x >>= 6; 575 | y = dataArray[3] << 8; 576 | y |= dataArray[2]; 577 | y >>= 6; 578 | z = dataArray[5] << 8; 579 | z |= dataArray[4]; 580 | z >>= 6; 581 | 582 | BMAtempfloat = (BMAtemp*0.5)+24.0; 583 | } 584 | 585 | 586 | byte initializeBMA() 587 | { 588 | Wire.beginTransmission(BMA250); 589 | Wire.write(0x0F); //set g 590 | Wire.write(GSEL); 591 | Wire.endTransmission(); 592 | Wire.beginTransmission(BMA250); 593 | Wire.write(0x10); //set bandwith 594 | Wire.write(BW); 595 | Wire.endTransmission(); 596 | return(0); 597 | } 598 | 599 | long readVcc() { //trick to read the Vin using internal 1.1 v as a reference 600 | long result; 601 | // Read 1.1V reference against AVcc 602 | ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 603 | delay(3); // Wait for Vref to settle 604 | ADCSRA |= _BV(ADSC); // Convert 605 | while (bit_is_set(ADCSRA,ADSC)); 606 | result = ADCL; 607 | result |= ADCH<<8; 608 | result = 1126400L / result; // Back-calculate AVcc in mV 609 | return result; 610 | } 611 | 612 | int freeRam () { 613 | extern int __heap_start, *__brkval; 614 | int v; 615 | return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 616 | } 617 | 618 | 619 | 620 | -------------------------------------------------------------------------------- /_20140630_CavePearl_ModularAdjustableCode/_20140630_CavePearl_ModularAdjustableCode.ino: -------------------------------------------------------------------------------- 1 | /* Cave Pearl Datalogger script (v19) by Edward Mallon 2 | * 3 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 4 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 5 | * Licensed under the GPL v3 license. See http://www.gnu.org/licenses/ for details on reuse and redistribution. 6 | * 7 | * This script incorporates the work of many other people for the libraries and some sensor functions. I have done my best 8 | * to site these sources directly in the comments with each section, and I make no claims whatsoever on those sections of code. 9 | * That being said, the overall integration of these components into a full datalogging system is a work that I have spent 10 | * many weeks of hard work on, and the functions related to overall data handling, and coordinated operation, are my own creations. 11 | * I would appreciate credit for that if you use this software directly, or as the basis for your own similar datalogging project. 12 | * I am happy for everyone to take this work as a starting point, and develop it in any way they see fit with one exception: 13 | * The GNU General Public License does not permit incorporating this program into proprietary programs. 14 | * 15 | * Electronic components for the datalogger platform: 16 | * TinyDuino Processor board (unregulated), TinyShield Proto, TinySheild microSD, 17 | * TinyShield Ambient Light sensor (hacked) for vregulated I2C lines, DS3232 Rtc, AT24C32 I2C eeprom 18 | * 19 | * Sensors supported included in this build: 20 | * HMC5883 Compass, DS18B20 Temp, TMP102 Temp, BMA180 Acc, BMA250 Acc, Ms5803-02 & 05 Pressure sensors 21 | * *uncomment defines at the beginning of the script for each sensor you have connected 22 | * 23 | * HOWEVER: THIS SCRIPT IS NOT PLUG-&-PLAY. 24 | * YOU will have to edit some of the str.printstatements that load our sensor data into the eeprom buffer, 25 | * and change the number of eeprom pages being used to store that data 26 | * THEN change then number of eeprom pages written to the SD card in the data writing function to match the # of pages you loaded with sensor data 27 | * And the header information that gets printed by that routine at the top of the data file: "YYYY/MM/DD HH:MM,Batt(mV),Sensor1, Sensor 2, ETC..." 28 | * In that routine you also have to change the limit set for: if(BytesWrittentoSD > NUMBER) so you don't exceed the 512 byte SD card writing buffer 29 | * Each cycle writes (32bytes * number of pages) + 2bytes for CR & termination character 30 | * so you have to sync BEFORE your next cycle IF that next cycle would put you over the 512 byte limit 31 | */ 32 | 33 | 34 | #include // I2C lib needs 128 byte Serial buffer 35 | #include // not used here, but needed to prevent a RTClib compile error....grrr! 36 | #include // Date, Time and Alarm functions by https://github.com/MrAlvin/RTClib based largely on https://github.com/jcw 37 | #include 38 | #include 39 | #include // from http://arduiniana.org/ 40 | #include // needs 512 byte buffer, from https://code.google.com/p/sdfatlib/downloads/list 41 | SdFat sd; /*Create the objects to talk to the SD card*/ 42 | SdFile file; 43 | const byte chipSelect = 10; //sd card chip select pin 44 | 45 | #define SampleIntervalMinutes 15 // power-down time in minutes before interupt triggers the next sample 46 | //#define SampleIntSeconds 20 // this is ONLY used for DEBUGGING! otherwise SET to 0! Must Set minutes to zero for sub minute alarms to occur! 47 | 48 | #define SamplesPerCycle 42 // MAX # of sample cycles to buffer in eeprom before sd card write 49 | //The AT25C32 is internally organized into (32,768 bits)=4096 bytes - beyond 4096 characters it rewrites over top of the old data 50 | //(128 x 32byte writes fill entire 4096 byte block) so MAX 64 wout compass (2 pgwrites/cycle) but max=42 if compass is installed! (3 pgwrites/cycle) 51 | unsigned int countLogs = 0; // # records have been written to each file so far 52 | unsigned int fileInterval = 2800; // #of log records before new logfile is made usually 2880 53 | /* count each time a log is written into each file. Must be less than 65,535 counts per file. If the sampleinterval is 15min, 54 | and fileInterval is 2880 seconds, then 96samples/day * 30days/month = 30 day intervals */ 55 | char FileName[] = "LOG00000.CSV"; //the first file name 56 | byte Cycle=0; 57 | 58 | #define filterSamples 7 // #of ACCELEROMETER samples for filtering- odd number, no smaller than 3 - works great at 13 & good at 7-9 samples 59 | // too many sampels and you will run out of free ram! 60 | 61 | //Comment out the sensors you are not using (uncomment all to verify code though) 62 | 63 | //****** AND ****** dont forget to edit the DATA file header in SETUP so that the config is written to the SD card file 64 | 65 | //#define BMA180_ADDRESS 0x40 66 | //#define BMA250_ADDRESS 0x18 67 | #define TS_TMP102 INSTALLED 68 | //#define TS_DS18B20 INSTALLED 69 | //#define HMC5883_ADDRESS 0x1E 70 | //#define MS5803_02_ISON 0x76//(CSB pin 3 tied to Vdd) 71 | //#define MS5803_05_ISON 0x76//(CSB pin 3 tied to Vdd) 72 | 73 | #define unregulatedMCU 1 //tiny duino can read vcc directly 74 | //#define vRegulatedMCU 1 //need to use a voltage divider and analog pin 75 | int Vcc; //the supply voltage (via 1.1 internal band gap OR analog read) 76 | int Vcc2; //the post SD card write voltage 77 | //int Vdelta; //change in supply voltage after each SD write cycle...to track battery conditioin 78 | const float referenceVolts = 3.3; 79 | // R1 = 10000 from a pin to input voltage // R2 = 10000 from analog pin to ground // - max measurable input voltage of 6.6v 80 | const float resistorFactor = 511; // = 1023.0 * (R2/(R1 + R2)); 81 | 82 | 83 | #define ECHO_TO_SERIAL // for debugging 84 | #ifdef ECHO_TO_SERIAL 85 | //#define WAIT_TO_START 86 | /* Wait for serial input in setup(), only if serial is enabled. You don't want to define WAIT_TO_START unless ECHO_TO_SERIAL is defined, 87 | because it would wait forever to start if you aren't using the serial monitor! */ 88 | #endif 89 | 90 | 91 | // 3 color indicator LED pin connections- if there is only one led set all the defines to the same pin 92 | #define RED_PIN 3 //will probably need this interrupt capable pin later... 93 | #define GREEN_PIN 4 94 | #define BLUE_PIN 5 95 | 96 | //Global variables 97 | //****************** 98 | byte bytebuffer =0; 99 | //int intbuffer=0; //not used yet 100 | 101 | //AT24C32 I2C eeprom 102 | //****************** 103 | #define EEPROM_ADDRESS 0x57 // I2C Buss address of AT24C32 32K EEPROM (first block) 104 | #define EEPromPageSize 32 // 32 bytes is page size for the AT24C32 105 | unsigned int CurrentPageStartAddress = 0; // set to zero at the start of each cycle 106 | char EEPROMBuffer[28]; // this buffer contains a string of ascii because I am using the pstring function to load it 107 | uint8_t BytesWrittentoSD = 0; 108 | 109 | //DS3231 RTC 110 | //********** 111 | #define DS3231_ADDRESS 104 112 | RTC_DS3231 RTC; //DS3231 will function with a VCC ranging from 2.3V to 5.5V 113 | byte Alarmhour = 1; 114 | byte Alarmminute = 1; 115 | byte Alarmday = 1; //only used for sub second alarms 116 | byte Alarmsecond = 1; //only used for sub second alarms 117 | byte INTERRUPT_PIN = 2; // SQW is soldered to this pin on the arduino 118 | volatile boolean clockInterrupt = false; 119 | char CycleTimeStamp[ ]= "0000/00/00,00:00"; //16 characters without seconds! 120 | 121 | // ACC common variables 122 | // ******************** 123 | // this is alot of memory to eat up just for acclerometer smoothing 124 | #if defined(BMA250_ADDRESS) || defined(BMA180_ADDRESS) 125 | int rawACCx [filterSamples]; // raw sensor values for x 126 | int rawACCy [filterSamples]; // raw sensor values for y 127 | int rawACCz [filterSamples]; // raw sensor values for z 128 | #endif 129 | int smoothACCx = 0; // smoothed x data 130 | int smoothACCy = 0; // smoothed y data 131 | int smoothACCz = 0; // smoothed z data 132 | 133 | // Temperature sensor common variables 134 | // *********************************** 135 | int TEMP_Raw = 0; 136 | float TEMP_degC = 0.0; 137 | uint8_t wholeTemp=0; 138 | uint8_t fracTemp=0; 139 | 140 | #ifdef TS_TMP102 141 | int TMP102_ADDRESS = 0x48; // 72=base address (3 others possible) 142 | byte errorflag=0; //used in tmp102 functions... might not be needed after error process is integrated 143 | #endif 144 | 145 | #ifdef TS_DS18B20 //variables for DS18B20 temperature sensor 146 | #include // from http://www.pjrc.com/teensy/td_libs_OneWire.html only need if DS18B20 is connected! 147 | // Also see Dallas Temperature library by Miles Burton: http://milesburton.com/Dallas_Temperature_Control_Library 148 | const byte DS18B20_PIN=4; // DS18B20 Data on digital pin 4 will have to move this with 3 color led! 149 | OneWire ds(DS18B20_PIN); 150 | byte addr[8]; 151 | #endif 152 | 153 | // Compass 154 | // ******* 155 | int CompassX = 0; 156 | int CompassY = 0; 157 | int CompassZ = 0; 158 | 159 | // MS5803-0X pressure sensors 160 | // ************************** 161 | 162 | // D1 and D2 need to be unsigned 32-bit integers (long 0-4294967295) 163 | uint32_t D1 = 0; // Store D1 value = uncompensated pressure value 164 | uint32_t D2 = 0; // Store D2 value = uncompensated temperature value 165 | 166 | #if defined(MS5803_02_ISON) || defined(MS5803_05_ISON) 167 | 168 | //variables for MS5803 functions 169 | #define MS5803_I2C_ADDRESS 0x76 // or 0x77 170 | #define CMD_RESET 0x1E // ADC reset command 171 | #define CMD_ADC_READ 0x00 // ADC read command 172 | #define CMD_ADC_CONV 0x40 // ADC conversion command 173 | #define CMD_ADC_D1 0x00 // ADC D1 conversion 174 | #define CMD_ADC_D2 0x10 // ADC D2 conversion 175 | #define CMD_ADC_256 0x00 // ADC resolution=256 176 | #define CMD_ADC_512 0x02 // ADC resolution=512 //default after reset 177 | #define CMD_ADC_1024 0x04 // ADC resolution=1024 178 | #define CMD_ADC_2048 0x06 // ADC resolution=2048 179 | #define CMD_ADC_4096 0x08 // ADC resolution=4096 180 | //resolutions at these oversample ratios are 0.084 / 0.054 / 0.036 / 0.024 mbar // 181 | uint8_t _Resolution = 512; //oversampling rate 182 | // Create array to hold the 8 sensor calibration coefficients 183 | unsigned int sensorCoeffs[8]; // unsigned 16-bit integer (0-65535) 184 | // bytes to hold the results from I2C communications with the sensor 185 | byte HighByte; 186 | byte MidByte; 187 | byte LowByte; 188 | 189 | float mbar; // Store pressure in mbar. 190 | float tempC; // Store temperature in degrees Celsius 191 | 192 | int wholembar=0; 193 | int fracmbar=0; 194 | 195 | // float tempF; // Store temperature in degrees Fahrenheit 196 | // float psiAbs; // Store pressure in pounds per square inch, absolute 197 | // float psiGauge; // Store gauge pressure in pounds per square inch (psi) 198 | // float inHgPress; // Store pressure in inches of mercury 199 | // float mmHgPress; // Store pressure in mm of mercury 200 | 201 | // These three variables are used for the conversion steps (which takes 3K more memory than I have left) 202 | // generally I only use these during debugging... 203 | // They should be signed 32-bit integer initially 204 | // i.e. signed long from -2147483648 to 2147483647 205 | int32_t mbarInt; // pressure in mbar, initially as a signed long integer 206 | int32_t dT = 0; 207 | // These values need to be signed 64 bit integers 208 | // (long long = int64_t) 209 | int64_t TEMP = 0; //I could not get the MS5803-02 lib working unless this was 64 210 | int64_t Offset = 0; 211 | int64_t Sensitivity = 0; 212 | int64_t T2 = 0; 213 | int64_t OFF2 = 0; 214 | int64_t Sens2 = 0; 215 | 216 | #endif 217 | 218 | 219 | /********************************************** 220 | * * * * * * SETUP * * * * * 221 | ***********************************************/ 222 | // errors in setup will always call error routine that halts the system 223 | void setup () { 224 | 225 | pinMode(INTERRUPT_PIN, INPUT); 226 | digitalWrite(INTERRUPT_PIN, HIGH);//pull up the interrupt pin 227 | 228 | pinMode(RED_PIN, OUTPUT); 229 | digitalWrite(RED_PIN, LOW); // error state 230 | pinMode(GREEN_PIN, OUTPUT); 231 | digitalWrite(GREEN_PIN, HIGH); // sensor reads 232 | pinMode(BLUE_PIN, OUTPUT); 233 | digitalWrite(BLUE_PIN, LOW); // eeprom & SD card writes 234 | 235 | Serial.begin(9600); 236 | Wire.begin(); 237 | RTC.begin(); 238 | 239 | // check RTC 240 | //********** 241 | clearClockTrigger(); //stops RTC from holding the interrupt low if system reset just occured 242 | RTC.turnOffAlarm(1); 243 | DateTime now = RTC.now(); 244 | DateTime compiled = DateTime(__DATE__, __TIME__); 245 | if (now.unixtime() < compiled.unixtime()) { //checks if the RTC is not set yet 246 | Serial.println(F("RTC is older than compile time! Updating")); 247 | // following line sets the RTC to the date & time this sketch was compiled 248 | RTC.adjust(DateTime(__DATE__, __TIME__)); 249 | Serial.println(F("Clock updated....")); 250 | } 251 | 252 | // startup delays if needed 253 | //************************* 254 | #ifdef ECHO_TO_SERIAL 255 | serial_boilerplate(); 256 | #endif 257 | 258 | delay(8000); // delay here just to prevent power stutters from writing multiple headers to the sd card 259 | 260 | #ifdef WAIT_TO_START // only triggered if WAIT_TO_START is defined at beging of code 261 | Serial.println(F("Type any character to start")); 262 | while (!Serial.available()); 263 | #endif 264 | 265 | //Temp sensor(s) init 266 | //********************** 267 | #ifdef TS_TMP102 268 | initTMP102(); 269 | #endif 270 | 271 | #ifdef TS_DS18B20 272 | if ( !ds.search(addr)) 273 | { 274 | Serial.println(F("---> ERROR: Did not find the DS18B20 Temperature Sensor!")); 275 | return; 276 | } 277 | else 278 | { 279 | Serial.print(F("DS18B20 found at ROM address =")); 280 | for(byte i = 0; i < 8; i++) { 281 | Serial.write(' '); 282 | Serial.print(addr[i], HEX); 283 | } 284 | Serial.println(); 285 | } 286 | #endif 287 | 288 | //Accelerometer init 289 | //********************** 290 | #ifdef BMA250_ADDRESS 291 | initBMA250(); 292 | #endif 293 | 294 | #ifdef BMA180_ADDRESS 295 | initBMA180(); 296 | #endif 297 | 298 | //Compass init 299 | //********************** 300 | #ifdef HMC5883_ADDRESS 301 | initHMC5883(); 302 | #endif 303 | 304 | 305 | #if defined(MS5803_I2C_ADDRESS) 306 | // Initialize the MS5803 sensor. This will report the 307 | // conversion coefficients to the Serial terminal if present. 308 | // If you don't want all the coefficients printed out, 309 | // set sensor.initializeMS_5803(false) otherwise send true 310 | 311 | if (initializeMS_5803(true)) { 312 | Serial.println( "MS5803 CRC check OK." ); 313 | } 314 | else { 315 | Serial.println( "MS5803 CRC check FAILED!" ); 316 | } 317 | #endif 318 | 319 | //get the SD card ready 320 | //********************** 321 | pinMode(chipSelect, OUTPUT); //make sure that the default chip select pin is set to output, even if you don't use it 322 | 323 | #ifdef ECHO_TO_SERIAL 324 | Serial.print(F("Initializing SD card...")); 325 | #endif 326 | 327 | // Initialize SdFat or print a detailed error message and halt 328 | // Use half speed like the native library. // change to SPI_FULL_SPEED for more performance. 329 | if (!sd.begin(chipSelect, SPI_HALF_SPEED)) { 330 | Serial.println(F("Cound not Initialize Sd Card")); 331 | error(); 332 | } 333 | 334 | #ifdef ECHO_TO_SERIAL 335 | Serial.println(F("SD card initialized.")); 336 | Serial.print(F("The sample interval for this series is: ")); 337 | Serial.print(SampleIntervalMinutes); 338 | Serial.print(F(" minutes")); 339 | #ifdef SampleIntSeconds 340 | Serial.print(F(" ")); 341 | Serial.print(SampleIntervalMinutes); 342 | Serial.print(F(" Seconds ")); 343 | #endif 344 | Serial.println(F(" ")); 345 | 346 | Serial.println(F("YYYY/MM/DD HH:MM, Vcc(mV), accX = , accY = , accZ = , Raw Temp, Temp (C), CompassX, CompassY, CompassZ,D1(Raw MS5803 Pressure), D2(Raw MS5803 Temperature), ")); 347 | delay(50); //short delay to clear serial com lines 348 | #endif 349 | 350 | // open the file for write at end like the Native SD library 351 | // see http://forum.arduino.cc/index.php?topic=49649.0 352 | // O_CREAT = create the file if it does not exist 353 | if (!file.open(FileName, O_RDWR | O_CREAT | O_AT_END)) { 354 | Serial.println(F("1st open LOG.CSV fail")); 355 | error(); 356 | } 357 | file.println(F("Unit#:x, Data platform:Y, MCU: TinyDuino, TempSensor:TMP102, ACC: Bma180, Compass:HMC5883, MS5803"));// edit this line with specifics before each upload 358 | file.println(F(" ")); 359 | 360 | #if defined(MS5803_I2C_ADDRESS) //write cal constants to the sd card 361 | 362 | file.println(F("Ms5803-2A Pressure sensor Calibration constants are:")); 363 | file.print(F("C1=")); 364 | file.print(sensorCoeffs[1]); 365 | file.println(F(" =SENS(t1)")); 366 | file.print(F("C2=")); 367 | file.print(sensorCoeffs[2]); 368 | file.println(F(" =OFF(t1)")); 369 | file.print(F("C3=")); 370 | file.print(sensorCoeffs[3]); 371 | file.println(F(" =TCS")); 372 | file.print(F("C4=")); 373 | file.print(sensorCoeffs[4]); 374 | file.println(F(" =TCO")); 375 | file.print(F("C5=")); 376 | file.print(sensorCoeffs[5]); 377 | file.println(F(" =RTreff")); 378 | file.print(F("C6=")); 379 | file.print(sensorCoeffs[6]); 380 | file.println(F(" =TEMPSENS")); 381 | file.println(F(" ")); 382 | 383 | #endif 384 | 385 | file.print(F("The sample interval for this series is: ")); 386 | file.print(SampleIntervalMinutes); 387 | file.print(F(" minutes")); 388 | #ifdef SampleIntSeconds 389 | Serial.print(F(" ")); 390 | Serial.print(SampleIntSeconds); 391 | Serial.print(F(" Seconds ")); 392 | #endif 393 | file.println(F(" ")); 394 | file.println(F("YYYY/MM/DD HH:MM, Vcc(mV), accX = , accY = , accZ = , Raw Temp , Temp (C), CompassX, CompassY, CompassZ, ")); 395 | file.println(F(" ")); 396 | delay(100); //short delay to clear coms 397 | file.close(); 398 | 399 | digitalWrite(GREEN_PIN, LOW); 400 | 401 | DIDR0 = 0x0F; // disable the digital inputs on analog 0..3 402 | } 403 | 404 | /*********************************************** 405 | * * * * * * MAIN LOOP * * * * * * 406 | ***********************************************/ 407 | // errors during main loop will only call error routine & halt the system if ECHO_TO_SERIAL is defined (ie: we are in debug mode) 408 | // that way if one sensor dies in the field we can still get data from the others 409 | void loop () 410 | { 411 | // keep track of how many lines have been written to a file 412 | // after so many lines, start a new file 413 | if(countLogs >= fileInterval){ 414 | digitalWrite(BLUE_PIN, HIGH); 415 | delay(1); 416 | digitalWrite(BLUE_PIN, LOW); 417 | createLogFile(); // create a new file 418 | countLogs = 0; // reset our counter to zero 419 | digitalWrite(BLUE_PIN, HIGH); 420 | delay(1); 421 | digitalWrite(BLUE_PIN, LOW); 422 | } 423 | 424 | CurrentPageStartAddress = 0; //yes I know I am burning out the first block of the eeprom 425 | 426 | for (int Cycle = 0; Cycle < SamplesPerCycle; Cycle++) { //this counts from 0 to (SamplesPerCycle-1) 427 | 428 | if (clockInterrupt) { // old location of this call.... why was it here before? 429 | clearClockTrigger(); 430 | digitalWrite(INTERRUPT_PIN, HIGH);//set weak internal pull up the interrupt pin 431 | } 432 | 433 | digitalWrite(GREEN_PIN, HIGH); 434 | delay(1); 435 | digitalWrite(GREEN_PIN, LOW); //sample heartbeat pip 436 | 437 | DateTime now = RTC.now(); // Read the time and date from the RTC 438 | 439 | //sprintf(CycleTimeStamp, "%04d/%02d/%02d %02d:%02d:%02d", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second()); 440 | //Time read always occurs <1 sec after interrupt, so seconds data is always "00" - so I dont record it any more 441 | sprintf(CycleTimeStamp, "%04d/%02d/%02d %02d:%02d", now.year(), now.month(), now.day(), now.hour(), now.minute()); 442 | 443 | Vcc = (readVcc()); 444 | if (Vcc < 2800){ 445 | Serial.println(F("Supply voltage TOO LOW!")); 446 | error(); 447 | } 448 | 449 | #ifdef vRegulatedMCU //3400mv is minimum allowed input to the voltage regulator 450 | if ((Vcc-700) < 2800){ 451 | Serial.println(F("Supply voltage TOO LOW!")); 452 | error(); 453 | } 454 | #endif 455 | 456 | //Read the accelerometer: 457 | #ifdef BMA180_ADDRESS 458 | readBMA180(); 459 | #endif 460 | //or 461 | #ifdef BMA250_ADDRESS 462 | readBMA250(); 463 | #endif 464 | 465 | //Read the compass: 466 | #ifdef HMC5883_ADDRESS 467 | readHMC5883(); 468 | #endif 469 | 470 | #if defined(MS5803_I2C_ADDRESS) 471 | // Use readSensor() function to get pressure and temperature reading. 472 | readSensor(); 473 | #endif 474 | 475 | //Read the temperature: 476 | #ifdef TS_TMP102 477 | TEMP_Raw =readTMP102(); 478 | TEMP_degC =TEMP_Raw*0.0625; 479 | wholeTemp = (int)TEMP_degC; 480 | fracTemp= (TEMP_degC - wholeTemp) * 1000; // split float into 2 intergers 481 | #endif 482 | // or 483 | #ifdef TS_DS18B20 484 | // Must do this reading last due to 1 second of sleeping while waiting for sensor! 485 | TEMP_Raw =readDS18B20Temp(); 486 | TEMP_degC =TEMP_Raw/16.00; 487 | wholeTemp = (int)TEMP_degC; 488 | fracTemp= (TEMP_degC - wholeTemp) * 1000; // Float split into 2 intergers 489 | #endif 490 | 491 | 492 | 493 | //serial output for debugging - comment out ECHO_TO_SERIAL to eliminate 494 | #ifdef ECHO_TO_SERIAL 495 | Serial.print(CycleTimeStamp); 496 | Serial.print(F(" Cycle: ")); 497 | Serial.print(Cycle); 498 | Serial.print(F(", Vcc= ")); 499 | Serial.println(Vcc); 500 | Serial.print(F(", ACCx= ")); 501 | Serial.print(smoothACCx); 502 | Serial.print(F(", ACCy= ")); 503 | Serial.print(smoothACCy); 504 | Serial.print(F(", ACCz= ")); 505 | Serial.println(smoothACCz); 506 | 507 | #if defined(MS5803_I2C_ADDRESS) 508 | Serial.print(F(" D1 = ")); 509 | Serial.print(D1); 510 | Serial.print(F(" D2 = ")); 511 | Serial.print(D2); 512 | Serial.print(F(" MS5803 Pressure = ")); 513 | wholembar = (int)mbar; 514 | fracmbar = (mbar - wholembar) * 100; 515 | Serial.print(wholembar); 516 | Serial.print(F(".")); 517 | Serial.print(fracmbar); 518 | //Serial.print(mbar); // it takes one whole K to print floats! dont do it! 519 | Serial.print(F(" mbar ")); 520 | wholeTemp = (int)tempC; 521 | fracTemp= (tempC - wholeTemp) * 1000; 522 | Serial.print(F(" MS5803 Temp = ")); 523 | //Serial.print(tempC); 524 | Serial.print(wholeTemp); 525 | Serial.print(F(".")); 526 | Serial.print(fracTemp); //avoid sending floats to serial print - it eats sram! 527 | Serial.print(F("C")); 528 | #endif 529 | 530 | 531 | Serial.print(F(", Temp C: ")); 532 | Serial.print(wholeTemp); 533 | Serial.print(F(".")); 534 | Serial.print(fracTemp); //avoid sending floats to serial print - it eats sram! 535 | Serial.print(F(", Free Ram: ")); 536 | Serial.print(freeRam()); //only use this for debugging 537 | Serial.println(F(" ")); //terminate line 538 | 539 | #ifdef HMC5883_ADDRESS 540 | Serial.print(F(", CompX: ")); 541 | Serial.print(CompassX); 542 | Serial.print(F(" CompY: ")); 543 | Serial.print(CompassY); 544 | Serial.print(F(" CompZ: ")); 545 | Serial.println(CompassZ); 546 | #endif 547 | 548 | delay(50); //short delay to clear serial com lines 549 | #endif 550 | 551 | //Construct first char string of 28 bytes - end of buffer is filled with blank spaces flexibly with pstring 552 | //but could contruct the buffer with sprintf if I wasn't changing my sensors so often! 553 | 554 | PString str(EEPROMBuffer, sizeof(EEPROMBuffer)); 555 | str = CycleTimeStamp; //17 / 16 characters without seconds plus comma 556 | str.print(F(",")); 557 | str.print(Vcc); // 5 / 4 char typical: 4096, 558 | str.print(F(",")); 559 | str.print(smoothACCx); // 6 5 or 6char: +_1023 from BMA250 OR (+- 16,384) from BMA180 560 | str.print(F(" ")); // just filler spaces for the end of the string to accomodate changes in data size 561 | //typical: 0000/00/00,00:00,4500,-1200 562 | 563 | digitalWrite(BLUE_PIN, HIGH); 564 | delay(1); 565 | digitalWrite(BLUE_PIN, LOW); 566 | Write_i2c_eeprom_page(EEPROM_ADDRESS, CurrentPageStartAddress, EEPROMBuffer); // whole page is written at once here 567 | CurrentPageStartAddress += EEPromPageSize; 568 | 569 | //Construct second char string of 28 bytes to complete the record 570 | str = ","; 571 | str.print(smoothACCy); 572 | str.print(F(",")); 573 | str.print(smoothACCz); 574 | str.print(F(",")); 575 | //str.print(TEMP_Raw); //4 digits both 12 bit sensors, so 4095 is largest value 576 | //str.print(F(",")); 577 | str.print(wholeTemp); //two digits positive 578 | str.print(F(".")); 579 | str.print(fracTemp); //3 digits, because *1000 580 | str.print(F(",")); 581 | str.print(D1); 582 | str.print(F(" ")); 583 | //typical: ,-1255,-255,498,21.56 584 | //can calculate TMP celcius later with deg_c = TMP102_raw*0.0625; 585 | 586 | //24 bit raw ADC value for D1 & D2 max = 16777216 = 8 characters! 9 with comma for each value! 587 | 588 | digitalWrite(BLUE_PIN, HIGH); 589 | delay(1); 590 | digitalWrite(BLUE_PIN, LOW); 591 | Write_i2c_eeprom_page(EEPROM_ADDRESS, 592 | CurrentPageStartAddress, EEPROMBuffer); // 28 bytes/page is max whole page is written at once here 593 | CurrentPageStartAddress += EEPromPageSize; 594 | 595 | #if defined(MS5803_I2C_ADDRESS) || defined(HMC5883_ADDRESS) // if needed construct a third char string 596 | //Construct third char string of 28 bytes to complete the record 597 | str = ","; 598 | str.print(D2); // 8 characters 599 | str.print(F(",")); 600 | 601 | // if(CompassX==0) then print the first order MS5803 stuff.. 602 | str.print(CompassX); //max 18 characters from compass 603 | str.print(F(",")); 604 | str.print(CompassY); 605 | str.print(F(",")); 606 | str.print(CompassZ); 607 | str.print(F(",")); 608 | #ifdef SampleIntSeconds 609 | str.print(F("V2,")); 610 | str.print(Vcc2); //just recording this in when I am in debugging mode 611 | str.print(F(",")); 612 | #endif 613 | str.print(F(" ")); 614 | 615 | digitalWrite(BLUE_PIN, HIGH); 616 | delay(1); 617 | digitalWrite(BLUE_PIN, LOW); 618 | Write_i2c_eeprom_page(EEPROM_ADDRESS, CurrentPageStartAddress, EEPROMBuffer); // 28 bytes/page is max whole page is written at once here 619 | CurrentPageStartAddress += EEPromPageSize; 620 | 621 | #endif 622 | 623 | // IF full set of sample cycles is complete, run a loop to dump data to the sd card 624 | // BUT only if Vcc is above 2.85 volts so we have enough juice! 625 | if (Cycle==(SamplesPerCycle-1) && Vcc >= 2850){ 626 | digitalWrite(RED_PIN, HIGH); 627 | 628 | // this for debugging only 629 | #ifdef ECHO_TO_SERIAL 630 | Serial.println(F(" --Writing to SDcard --")); 631 | delay (10); 632 | //Serial.print(F("Current eeprom page address:"));Serial.print(CurrentPageStartAddress ); delay (10); 633 | //Serial.print(F("-now set to zero & Cycle:"));Serial.println(Cycle); delay (10); 634 | #endif 635 | 636 | file.open(FileName, O_RDWR | O_AT_END); 637 | // open the file for write at end like the Native SD library 638 | // if (!file.open(FileName, O_RDWR | O_AT_END)) { 639 | // error("L open file fail"); 640 | //} 641 | // file.print(F("EEPROM page address AT start:"));file.println(CurrentPageStartAddress ); // this for debuggin only 642 | 643 | CurrentPageStartAddress=0; //reset the page counter back to the beginning of the eeprom stack 644 | for (int i = 0; i < SamplesPerCycle; i++) { //loop to read from I2C ee and write to SD card 645 | 646 | Read_i2c_eeprom_page(EEPROM_ADDRESS, CurrentPageStartAddress, EEPROMBuffer, sizeof(EEPROMBuffer) ); //there will be a few blank spaces 647 | CurrentPageStartAddress += EEPromPageSize; 648 | file.write(EEPROMBuffer,sizeof(EEPROMBuffer)); 649 | BytesWrittentoSD = BytesWrittentoSD + sizeof(EEPROMBuffer); 650 | 651 | Read_i2c_eeprom_page(EEPROM_ADDRESS, CurrentPageStartAddress, EEPROMBuffer, sizeof(EEPROMBuffer) ); 652 | CurrentPageStartAddress += EEPromPageSize; 653 | file.write(EEPROMBuffer,sizeof(EEPROMBuffer)); 654 | BytesWrittentoSD = BytesWrittentoSD + sizeof(EEPROMBuffer); 655 | 656 | #if defined(MS5803_I2C_ADDRESS) || defined(HMC5883_ADDRESS) //the compass or pressure sensor adds a third data line to each cycle 657 | Read_i2c_eeprom_page(EEPROM_ADDRESS, CurrentPageStartAddress, EEPROMBuffer, sizeof(EEPROMBuffer) ); 658 | CurrentPageStartAddress += EEPromPageSize; 659 | file.write(EEPROMBuffer,sizeof(EEPROMBuffer)); 660 | BytesWrittentoSD = BytesWrittentoSD + sizeof(EEPROMBuffer); 661 | #endif 662 | 663 | file.println(F(" ")); //add a carridge return to the file 664 | BytesWrittentoSD = BytesWrittentoSD + 2; //why did I add this little bit? 665 | 666 | countLogs++; 667 | // An application which writes to a file using print(), println() or write() must call sync() 668 | // at the appropriate time to force data and directory information to be written to the SD Card. approximately 512 bytes 669 | if(BytesWrittentoSD > 440) { 670 | syncTheFile; 671 | BytesWrittentoSD=0; 672 | } //might need to lower this 673 | } 674 | 675 | file.close(); 676 | CurrentPageStartAddress=0; 677 | 678 | Vcc2 = (readVcc()); 679 | if (Vcc2 < 2800){ 680 | Serial.println(F("Supply voltage TOO LOW!")); //2.7 volts is listed as the minimum safe write voltage for Sandisk mem cards 681 | delay(10); //wait till the SD card is back in sleep mode (5ms) then go to error state 682 | error(); 683 | // Vdelta = Vcc-Vcc2; //also could use Vdelta to track the power left in the batteries? 684 | } 685 | 686 | #ifdef vRegulatedMCU //3400mv is minimum allowed input on the voltage regulated system 687 | if ((Vcc2-700) < 2800){ 688 | Serial.println(F("Supply voltage TOO LOW!")); 689 | delay(10); 690 | error(); 691 | } 692 | #endif 693 | 694 | 695 | digitalWrite(RED_PIN, LOW); 696 | } 697 | 698 | // setNextAlarmTime(); 699 | Alarmhour = now.hour(); 700 | Alarmminute = now.minute()+SampleIntervalMinutes; 701 | Alarmday = now.day(); 702 | //Alarmsecond = now.second()+SampleIntSeconds; 703 | if (SampleIntervalMinutes > 0) //then our alarm is in (SampleInterval) minutes 704 | { 705 | if (Alarmminute > 59) { //error catch - if alarmminute=60 the interrupt never triggers due to rollover! 706 | Alarmminute =0; 707 | Alarmhour = Alarmhour+1; 708 | if (Alarmhour > 23) { 709 | Alarmhour =0; 710 | } 711 | } 712 | RTC.setAlarm1Simple(Alarmhour, Alarmminute); 713 | } 714 | else 715 | { // for testing and debug I sometimes want the alarms more frequent than 1 per minute. 716 | Alarmsecond = now.second()+SampleIntSeconds; 717 | if (Alarmsecond >59){ 718 | Alarmsecond =0; 719 | Alarmminute = Alarmminute+1; 720 | if (Alarmminute > 59) 721 | { //error catch - if alarmminute=60 the interrupt never triggers due to rollover! 722 | Alarmminute =0; 723 | Alarmhour = Alarmhour+1; 724 | if (Alarmhour > 23) { //uhoh a day rollover, but we dont know the month..so we dont know the next day number? 725 | Alarmhour =0; 726 | delay(327670); 727 | delay(327670); 728 | delay(327670); //Just wait for a minute.. 729 | DateTime now = RTC.now(); //now start the numbers again with the new day already rolled over 730 | Alarmday = now.day(); 731 | Alarmhour = now.hour(); 732 | Alarmminute = now.minute(); 733 | Alarmsecond = now.second()+SampleIntSeconds; 734 | } 735 | } 736 | } 737 | RTC.setA1Time(Alarmday, Alarmhour, Alarmminute, Alarmsecond, 0b00001000, false, false, false); 738 | //The variables ALRM1_SET bits and ALRM2_SET are 0b1000 and 0b111 respectively. 739 | //setA1Time(byte A1Day, byte A1Hour, byte A1Minute, byte A1Second, byte AlarmBits, bool A1Dy, bool A1h12, bool A1PM) 740 | } 741 | RTC.turnOnAlarm(1); 742 | 743 | #ifdef ECHO_TO_SERIAL 744 | Serial.println(F(" ")); 745 | Serial.print(F(" Alarm Set:")); 746 | Serial.print(now.hour(), DEC); 747 | Serial.print(':'); 748 | Serial.print(now.minute(), DEC); 749 | Serial.print(F(" Sleep:")); 750 | Serial.print(SampleIntervalMinutes); 751 | Serial.print(F(" min.")); 752 | #ifdef SampleIntSeconds 753 | Serial.print(SampleIntSeconds); 754 | Serial.print(F(" sec.")); 755 | # endif 756 | Serial.println(F(" ")); 757 | delay(50); //a delay long enought to boot out the serial coms 758 | #endif 759 | 760 | sleepNwait4RTC(); //the sleep call is inside the main cycle counter loop 761 | 762 | } //samples per cycle loop terminator 763 | } //the main void loop terminator 764 | 765 | 766 | 767 | // ************************************************************************************************************ 768 | // * * * * * COMMON FUNCTIONS * * * * * 769 | // ************************************************************************************************************ 770 | 771 | /********************************************** 772 | * SD card funtions : Create file & SYNC 773 | ***********************************************/ 774 | 775 | // from http://forums.adafruit.com/viewtopic.php?f=31&t=17964 776 | 777 | void createLogFile(void) { 778 | // create a new file, up to 100,000 files allowed 779 | // we will create a new file every time this routine is called 780 | // If we are creating another file after fileInterval, then we must 781 | // close the open file first. 782 | if (file.isOpen()) { 783 | file.close(); 784 | } 785 | for (uint16_t i = 0; i < 100000; i++) { 786 | FileName[3] = i/10000 + '0'; 787 | FileName[4] = i/1000 + '0'; 788 | FileName[5] = i/100 + '0'; 789 | FileName[6] = i/10 + '0'; 790 | FileName[7] = i%10 + '0'; 791 | // O_CREAT - create the file if it does not exist 792 | // O_EXCL - fail if the file exists O_WRITE - open for write 793 | if (file.open(FileName, O_CREAT | O_EXCL | O_WRITE)) break; 794 | //if you can open a file with the new name, break out of the loop 795 | } 796 | 797 | // clear the writeError flags generated when we broke the new name loop 798 | file.writeError = 0; 799 | 800 | if (!file.isOpen()) { 801 | Serial.println(F(" Disk Full Error")); 802 | error(); 803 | } 804 | Serial.print(F("Logging to: ")); 805 | Serial.println(FileName); 806 | 807 | // fetch the time //is this what takes away 5 minutes from our clock? 808 | DateTime now = RTC.now(); 809 | // set creation date time 810 | if (!file.timestamp(T_CREATE,now.year(),now.month(),now.day(),now.hour(), 811 | now.minute(),now.second() )) { 812 | Serial.println(F("Can't timestamp the new file")); 813 | error(); 814 | } 815 | // set write/modification date time 816 | if (!file.timestamp(T_WRITE,now.year(),now.month(),now.day(),now.hour(), 817 | now.minute(),now.second() )) { 818 | Serial.println(F("Can't write to the new file")); 819 | error(); 820 | } 821 | // set access date 822 | if (!file.timestamp(T_ACCESS,now.year(),now.month(),now.day(),now.hour(), 823 | now.minute(),now.second() )) { 824 | Serial.println(F("Can't set new file access date")); 825 | error(); 826 | } 827 | file.sync(); 828 | //file.close(); 829 | //file.open(FileName, O_RDWR | O_AT_END); 830 | 831 | // write the file as a header: 832 | file.print(F("The sample interval for this series is:")); 833 | Serial.print(SampleIntervalMinutes); 834 | Serial.println(F(" minutes")); 835 | Serial.println(F(" ")); 836 | file.println(F("YYYY/MM/DD HH:MM, Vcc(mV), accX = , accY = , accZ = , Raw Temp, Temp (C), CompassX, CompassY, CompassZ, ")); 837 | Serial.println(F(" ")); 838 | file.close(); 839 | 840 | #ifdef ECHO_TO_SERIAL 841 | Serial.println(F("New log file created on the SD card!")); 842 | delay(100); //short delay to clear serial com lines 843 | #endif // ECHO_TO_SERIAL 844 | 845 | // write out the header to the file, only upon creating a new file 846 | if (file.writeError) { 847 | // check if error writing 848 | Serial.println(F(" Can't write new file header")); 849 | error(); 850 | } 851 | 852 | // if (!file.sync()) { 853 | // check if error writing 854 | // Serial.println(F("File Syncing Error"));error(); 855 | // } 856 | 857 | } 858 | 859 | // ***********************************************/ 860 | 861 | void syncTheFile(void) 862 | { 863 | /* don't sync too often - requires 2048 bytes of I/O to SD card. 512 bytes of I/O if using Fat16 library */ 864 | 865 | digitalWrite(RED_PIN, HIGH); 866 | delay(1); 867 | digitalWrite(RED_PIN, LOW); /* blink LED to show we are syncing data to the card & updating FAT!*/ 868 | 869 | if (!file.sync()) { 870 | Serial.println(F("File Sync error")); 871 | error(); //terminal error if you cant save data to sd card 872 | } // 15-20 ms for syncing 873 | 874 | digitalWrite(RED_PIN, HIGH); 875 | delay(1); 876 | digitalWrite(RED_PIN, LOW); 877 | } 878 | 879 | /***************************************************************************************************************** 880 | * i2c EEPROM READ & WRITE PAGEs 881 | *******************************************************************************************************************/ 882 | 883 | // Address is a page address 884 | // But data can be maximum of 28 bytes, because the Wire library has a buffer of 32 bytes 885 | void Write_i2c_eeprom_page( int deviceaddress, unsigned int eeaddress, char* data) 886 | { 887 | unsigned char i=0; 888 | unsigned int address; 889 | address=eeaddress; 890 | Wire.beginTransmission(deviceaddress); 891 | Wire.write((int)((address) >> 8)); // MSB 892 | Wire.write((int)((address) & 0xFF)); // LSB 893 | do{ 894 | Wire.write((byte) data[i]); 895 | i++; 896 | } 897 | while(data[i]); 898 | Wire.endTransmission(); 899 | delay(10); // data sheet says 5ms for page write 900 | } 901 | 902 | void Read_i2c_eeprom_page( int deviceaddress, unsigned int eeaddress,char* data, unsigned int num_chars) 903 | { 904 | unsigned char i=0; 905 | Wire.beginTransmission(deviceaddress); 906 | Wire.write((int)(eeaddress >> 8)); // MSB 907 | Wire.write((int)(eeaddress & 0xFF)); // LSB 908 | Wire.endTransmission(); 909 | Wire.requestFrom(deviceaddress,(num_chars-1)); 910 | while(Wire.available()) data[i++] = Wire.read(); 911 | } 912 | 913 | /********************************************** 914 | * SLEEP and wait for RTC 915 | ***********************************************/ 916 | //defs needed for stopping the ADC during sleep mode 917 | #ifndef cbi 918 | #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) 919 | #endif 920 | #ifndef sbi 921 | #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) 922 | #endif 923 | 924 | void sleepNwait4RTC() 925 | { 926 | cbi(ADCSRA,ADEN); // Switch ADC OFF: worth 334 µA during sleep 927 | set_sleep_mode(SLEEP_MODE_PWR_DOWN); 928 | sleep_enable(); 929 | attachInterrupt(0,clockTrigger, LOW); 930 | sleep_mode(); 931 | //HERE AFTER WAKING UP 932 | sleep_disable(); 933 | detachInterrupt(0); 934 | sbi(ADCSRA,ADEN); // Switch ADC converter back ON 935 | } 936 | /********************************************** 937 | * CLOCK TRIGGER FLAG 938 | ***********************************************/ 939 | void clockTrigger() { 940 | clockInterrupt = true; //do something quick, flip a flag, and handle in loop(); 941 | } 942 | /********************************************** 943 | * CLEAR CLOCK TRIGGER 944 | ***********************************************/ 945 | // clear alarm interupt from http://forum.arduino.cc/index.php?topic=109062.0 946 | void clearClockTrigger() 947 | { 948 | Wire.beginTransmission(0x68); //Tell devices on the bus we are talking to the DS3231 949 | Wire.write(0x0F); //Tell the device which address we want to read or write 950 | Wire.endTransmission(); //Before you can write to and clear the alarm flag you have to read the flag first! 951 | Wire.requestFrom(0x68,1); // Read one byte 952 | bytebuffer=Wire.read(); // In this example we are not interest in actually using the bye 953 | Wire.beginTransmission(0x68); //Tell devices on the bus we are talking to the DS3231 954 | Wire.write(0x0F); //Tell the device which address we want to read or write 955 | Wire.write(0b00000000); //Write the byte. The last 0 bit resets Alarm 1 956 | Wire.endTransmission(); 957 | clockInterrupt=false; //Finally clear the flag we use to indicate the trigger occurred 958 | } 959 | 960 | /********************************************** 961 | * SLEEP and wait for watchdog timer 962 | ***********************************************/ 963 | // you must use one of the setWTD_125ms() functions before you call this.. otherwise you sleep forever! 964 | void sleepNwait4WDT() { //uses the wdt's internal int..so no need for attaching int to a pin here 965 | ADCSRA |= (0< 0) 1108 | { 1109 | Serial.print(F("FAIL in I2C reg write! Result code is ")); 1110 | Serial.println(result); 1111 | 1112 | #ifdef ECHO_TO_SERIAL //only call halt on error if in debug mode 1113 | error(); 1114 | #endif 1115 | } 1116 | //else 1117 | //{ 1118 | // Serial.println(" "); 1119 | //} 1120 | delay(10); //sensors often need some settling time after register writing (BMA180 does) 1121 | 1122 | return result; 1123 | } 1124 | 1125 | /********************************************** 1126 | * BOILERPLATE 1127 | ***********************************************/ 1128 | void serial_boilerplate() 1129 | { 1130 | Serial.println(F("The Cave Pearl: An Open Source Hydrometric Pendulum")); 1131 | Serial.println(F("===================================================")); 1132 | Serial.println(); 1133 | Serial.println(F("Developed by Edward Mallon: http://edwardmallon.wordpress.com/")); 1134 | Serial.println(); 1135 | } 1136 | 1137 | /********************************************** 1138 | * FREE RAM AVAILIABLE 1139 | ***********************************************/ 1140 | // from: http://learn.adafruit.com/memories-of-an-arduino/measuring-free-memory 1141 | 1142 | int freeRam () 1143 | { 1144 | extern int __heap_start, *__brkval; 1145 | int v; 1146 | return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 1147 | } 1148 | 1149 | 1150 | /********************************************** 1151 | * ERROR HANDLER 1152 | ***********************************************/ 1153 | // I should really figure out how to turn this into a perminant sleep function 1154 | // more advanced debugging: http://forum.arduino.cc/index.php?topic=203282.0 1155 | void error() 1156 | { 1157 | digitalWrite(RED_PIN, HIGH); 1158 | sleepNwait4WDT(); //since we have gone to sleep without setting the wdt, this is sleep forever! 1159 | //while (1); //or could start an endless loop, 1160 | } 1161 | 1162 | // ************************************************************************************************************ 1163 | // * * * * * * * * * * SENSOR FUNCTIONS * * * * * * * * * * * * * 1164 | // ************************************************************************************************************ 1165 | 1166 | // ************************************************************************************************************ 1167 | // I2C TMP102 TEMPERATURE SENSOR 1168 | // ************************************************************************************************************ 1169 | // writes 2 bytes to registers, instead of one, so not itegrated with I2C write byte functions yet! 1170 | 1171 | #if defined(TS_TMP102) 1172 | 1173 | #define TMP102_CFG_default_byte1 B01100001 // 12 bit rez WITH ShutDown bit turned ON 1174 | #define TMP102_CFG_default_byte2 B10100000 // just the defaults from pg 7 1175 | #define TMP102_OneShotBit B10000000 // one-shot by ORing D7 of CFG byte 1 to 1 1176 | // err1-byte pointer to write to tmp102 BEFORE reading back 2 bytes of data from that register 1177 | #define TMP102_TEMP_REG_pointer 0x00 // temperature register, read only, 16bits 1178 | #define TMP102_CONF_REG_pointer 0x01 // config register, read/write, 16 bits 1179 | 1180 | void initTMP102() 1181 | { 1182 | #ifdef ECHO_TO_SERIAL 1183 | Serial.println(F("Initializing TMP102 Temperature sensor...")); 1184 | delay(10); 1185 | #endif 1186 | 1187 | Wire.beginTransmission(TMP102_ADDRESS); 1188 | Wire.write(TMP102_CONF_REG_pointer); 1189 | Wire.write(TMP102_CFG_default_byte1); //Sets to 12bit, sd mode on 1190 | Wire.write(TMP102_CFG_default_byte2); //none of these settings matter in one shot mode, at my temperature range, but set them to defaults anyway 1191 | errorflag = Wire.endTransmission(); 1192 | if ( errorflag != 0) { 1193 | Serial.print (F("Initial control reg writing on TMP102 failed!")); 1194 | error(); 1195 | errorflag=0; 1196 | } 1197 | 1198 | // set one-shot bit to "1" - starts a single conversion then sleeps the sensor 1199 | Wire.beginTransmission(TMP102_ADDRESS); 1200 | Wire.write(TMP102_CONF_REG_pointer); // Select control register. 1201 | Wire.write(TMP102_CFG_default_byte1 | TMP102_OneShotBit); // Start one-shot conversion 40μA during conv 1202 | //Wire.write(TMP102_CFG_default_byte2); //dont need to bother writing the second byte 1203 | errorflag = Wire.endTransmission(); 1204 | if ( errorflag != 0) { 1205 | Serial.print (F("OOPS! Problem setting OneSHOT bit on TMP102! ")); 1206 | error(); 1207 | errorflag=0; 1208 | } 1209 | TEMP_Raw=readTMP102(); 1210 | 1211 | #ifdef ECHO_TO_SERIAL 1212 | Serial.print(F("Success: TMP102 has been initialized: First Raw read=")); 1213 | Serial.print(TEMP_Raw); 1214 | Serial.println(F(" ")); 1215 | #endif 1216 | 1217 | } 1218 | 1219 | int readTMP102() 1220 | { 1221 | //float deg_c; 1222 | errorflag=0; 1223 | // start by resetting the one shot bit back to zero 1224 | Wire.beginTransmission(TMP102_ADDRESS); 1225 | Wire.write(TMP102_CONF_REG_pointer); 1226 | Wire.write(TMP102_CFG_default_byte1); //Sets to 12bit, sd mode on 1227 | errorflag = Wire.endTransmission(); 1228 | if ( errorflag != 0) { 1229 | Serial.print (F("TMP102 clearing OS bit in CFG reg failed...")); 1230 | 1231 | #ifdef ECHO_TO_SERIAL //if echo is on, we are in debug mode, and errors force a halt. 1232 | error(); 1233 | #endif 1234 | 1235 | errorflag=0; 1236 | } 1237 | // now seting the one-shot bit to "1" will start a single conversion 1238 | Wire.beginTransmission(TMP102_ADDRESS); 1239 | Wire.write(TMP102_CONF_REG_pointer); // point at the control register. 1240 | Wire.write(TMP102_CFG_default_byte1 | TMP102_OneShotBit); // ORing the bits together 1241 | //Wire.write(TMP102_CFG_default_byte2); //I don't need to bother writing the second byte? 1242 | errorflag = Wire.endTransmission(); 1243 | if ( errorflag != 0) { 1244 | Serial.print (F("OOPS! problem setting OneSHOT bit on TMP102")); 1245 | 1246 | #ifdef ECHO_TO_SERIAL //if echo is on, we are in debug mode, and errors force a halt. 1247 | error(); 1248 | #endif 1249 | 1250 | errorflag=0; 1251 | } 1252 | 1253 | //delay(28); OR: 1254 | setWTD_32ms(); 1255 | sleepNwait4WDT(); 1256 | // conversion: 26ms according to the sheet 1257 | // during the conversion the OS bit will temporarily read "0", then revert to "1" after the conversion so you could check for that 1258 | 1259 | Wire.beginTransmission(TMP102_ADDRESS); //now read the temp 1260 | Wire.write(TMP102_TEMP_REG_pointer); // Select temperature register. 1261 | errorflag = Wire.endTransmission(); 1262 | if ( errorflag != 0) { 1263 | Serial.print (F("Can't set temp reg pointer on TMP102")); 1264 | 1265 | #ifdef ECHO_TO_SERIAL //if echo is on, we are in debug mode, and errors force a halt. 1266 | error(); 1267 | #endif 1268 | 1269 | errorflag=0; 1270 | } 1271 | Wire.requestFrom(TMP102_ADDRESS, 2); 1272 | const byte TempByte1 = Wire.read(); // MSByte, should be signed whole degrees C. 1273 | const byte TempByte2 = Wire.read(); // unsigned because I am not reading any negative temps 1274 | const int Temp16 = (TempByte1 << 4) | (TempByte2 >> 4); // builds 12-bit value 1275 | //TEMP_degC = Temp16*0.0625; 1276 | return Temp16; 1277 | } 1278 | #endif 1279 | 1280 | // ************************************************************************************************************ 1281 | // DS18B20 ONE WIRE TEMPERATURE 1282 | // ************************************************************************************************************ 1283 | // this returns the temperature from one DS18S20 using 12 bit conversion 1284 | // also see Dallas Temperature Control library by Miles Burton: http://milesburton.com/Dallas_Temperature_Control_Library 1285 | 1286 | #if defined(TS_DS18B20) 1287 | 1288 | int readDS18B20Temp() 1289 | { 1290 | //byte data[12]; 1291 | byte data[2]; 1292 | ds.reset(); 1293 | ds.select(addr); 1294 | ds.write(0x44); // start conversion, read temperature and store it in the scratchpad 1295 | 1296 | //this next bit creates a 1 second WDT delay for the DS18b20 temp conversion 1297 | //The time needed between the CONVERT_T command and the READ_SCRATCHPAD command has to be at least 1298 | //750 millisecs (can be shorter if using a D18B20 type with resolutions < 12 bits) 1299 | //if you start getting "85" all the time you did not wait long enough 1300 | // power saving during sleep from http://www.gammon.com.au/forum/?id=11497 1301 | 1302 | MCUSR = 0; // clear various "reset" flags 1303 | WDTCSR = bit (WDCE) | bit (WDE); // allow changes, disable reset 1304 | // set interrupt mode and an interval 1305 | WDTCSR = bit (WDIE) | bit (WDP2) | bit (WDP1); //this creates a 1 sec wdt delay for the temp conversion 1306 | wdt_reset(); // pat the dog 1307 | set_sleep_mode (SLEEP_MODE_PWR_DOWN); 1308 | sleep_enable(); 1309 | sleep_cpu (); 1310 | // resume here after wdt interrupt happens - cancel sleep as a precaution 1311 | sleep_disable(); 1312 | delay(3); 1313 | 1314 | byte present = ds.reset(); 1315 | ds.select(addr); 1316 | ds.write(0xBE); // Read Scratchpad 1317 | for (int i = 0; i < 2; i++) 1318 | { // we read 9 bytes? but you only use two of them? 1319 | data[i] = ds.read(); 1320 | } 1321 | byte MSB = data[1]; 1322 | byte LSB = data[0]; 1323 | int tempRaw = ((MSB << 8) | LSB); //using two's compliment 1324 | //TEMP_degC = tempRaw / 16; 1325 | return tempRaw; 1326 | } 1327 | 1328 | #endif 1329 | 1330 | // ************************************************************************************************************ 1331 | // I2C Compass HMC5883 1332 | // ************************************************************************************************************ 1333 | // I2C adress: 0x3C (8bit) 0x1E (7bit) 1334 | // ************************************************************************************************************ 1335 | // sensor output ranges: -2048 to 2047 1336 | // Sensor Field Range ± 1.3 Ga (default) Gain: 1090 LSb/Gauss (default) Digital resolution: 0.92 mG/LSb 1337 | 1338 | #if defined(HMC5883_ADDRESS) 1339 | 1340 | void initHMC5883() 1341 | { 1342 | //Put the HMC5883 into operating mode 1343 | Wire.beginTransmission(HMC5883_ADDRESS); 1344 | Wire.write(0x02); // Mode register 1345 | Wire.write(0x00); // Continuous measurement mode 1346 | Wire.endTransmission(); 1347 | #ifdef ECHO_TO_SERIAL 1348 | Serial.println(F(" HMC5883 compass has been initialized")); 1349 | #endif 1350 | } 1351 | 1352 | void readHMC5883() 1353 | { 1354 | uint8_t ReadBuff[6]; 1355 | 1356 | // Read the 6 data bytes from the HMC5883 - probably should add smoothing to this too? 1357 | Wire.beginTransmission(HMC5883_ADDRESS); 1358 | Wire.write(0x03); 1359 | Wire.endTransmission(); 1360 | Wire.requestFrom(HMC5883_ADDRESS,6); 1361 | 1362 | for(int i = 0; i < 6;i++) 1363 | { 1364 | ReadBuff[i] = Wire.read(); 1365 | } 1366 | 1367 | CompassX = ReadBuff[0] << 8; 1368 | CompassX |= ReadBuff[1]; 1369 | 1370 | CompassY = ReadBuff[4] << 8; 1371 | CompassY |= ReadBuff[5]; 1372 | 1373 | CompassZ = ReadBuff[2] << 8; 1374 | CompassZ |= ReadBuff[3]; 1375 | } 1376 | 1377 | #endif 1378 | 1379 | 1380 | // ************************************************************************************************************ 1381 | // I2C Accelerometer BMA180 14bit (+- 16,384) 1382 | // ************************************************************************************************************ 1383 | /*0x40 = address of the accelerometer with SDO pulled up to VCC (0x41 if SDO pulled down to GND) 1384 | BMA180 default values: see page 26 of datasheet: DEF_PMODE =0, DEF_SCALE =250, bandwidth default =20 HZ */ 1385 | 1386 | #if defined(BMA180_ADDRESS) 1387 | 1388 | #define BMA180_CMD_BW_TCS 0x20 1389 | //bits 4-7 of this register are the filtering bandwidth bits, 0-3 are the temp compensation bits (page 46) 1390 | #define cmd_bandwidth_MASK B11110000 1391 | #define BMA180_BW_10HZ 0x00 //to filter down to 10hz, the sensor reads 253 samples, so it takes quite a while! 1392 | #define BMA180_RANGEnSMP 0X35 //7.7.1 address of combined Offx, range & smp_skp register (53 decimal) - 2G default sensitivity 1393 | //and the three sensitivity range bits to put into that register are: 1394 | #define range_MASK B00001110 1395 | #define BMA180_RANGE_1G 0x00 1396 | /* the set of Data Register addresses to read out */ 1397 | #define BMA180_CMD_CHIP_ID 0x00 1398 | //#define BMA180_CMD_VERSION 0x01 1399 | #define BMA180_CMD_ACC_X_LSB 0x02 /* First of 6 registers of accel data */ 1400 | #define BMA180_CMD_ACC_X_MSB 0x03 1401 | #define BMA180_CMD_ACC_Y_LSB 0x04 1402 | #define BMA180_CMD_ACC_Y_MSB 0x05 1403 | #define BMA180_CMD_ACC_Z_LSB 0x06 1404 | #define BMA180_CMD_ACC_Z_MSB 0x07 1405 | //#define BMA180_CMD_TEMP 0x08 1406 | /* the device status registers - info about alert/interrupt & if data is availiable to read out*/ 1407 | #define BMA180_CMD_STATUS_REG1 0x09 //1st tap, alert, slope signs, offset, ee_write 1408 | //#define BMA180_CMD_STATUS_REG2 0x0A //tap and slope sense bits 1409 | //#define BMA180_CMD_STATUS_REG3 0x0B //interrupt statuses from the tap sensing 1410 | //#define BMA180_CMD_STATUS_REG4 0x0C //high signs, x&y&z tapsense 1411 | #define BMA180_CMD_RESET 0x10 1412 | /* reset register: set to 0 for soft reset -all register values will reset*/ 1413 | #define BMA180_CMD_CTRL_REG0 0x0D // EE_W enable write control is bit 4 of this register address! 1414 | #define BMA180_CMD_CTRL_REG1 0x0E // contains the offsets for x, y,z 1415 | #define BMA180_CMD_CTRL_REG2 0x0F // unlocking eeprom register 1416 | //#define BMA180_CMD_CTRL_REG3 0x21 // configure different interrupt trigger bits in this register 1417 | //#define BMA180_CMD_CTRL_REG4 0x22 // low_hy, mot_cd_r, ff_cd_tr, offset_finetuning 1418 | /* CTRL_REGISTER 0 BIT MASKS - the really important ones! see page 26 for defaults*/ 1419 | #define ctrl_reg0_dis_wake_up_MASK B00000001 1420 | /* BIT(0) set to 1 and unit sleeps automatically for wake_up_dur (7.7.9) then takes readings, 1421 | set this register bit to 0 to disable the automatic sleep&wake-up mode */ 1422 | #define ctrl_reg0_sleep_MASK B00000010 1423 | /* BIT(1) chip will sleep if this bit set to 1 and wake when set to 0 1424 | Sleep bit should not be set to "1", when wake up mask is set to "1", wait 10ms before any eeprom operation on wake from sleep*/ 1425 | #define ctrl_reg0_ee_w_MASK B00010000 1426 | /* BIT(4) set this to 1 to Unlock writing to addr from 0x20 to 0x50, (default)=0 on reset 1427 | 7.10.3 ee_w This bit must be written 1 to be able to write anything into image registers, resetting ee_w to 0 will prevent any register updates*/ 1428 | // No serial transaction should occur within minimum 10 us after soft_reset command 1429 | /* BMA180_CTRL_REG3 MASK */ 1430 | //#define ctrl_reg3_new_data_int_MASK 0x01 /* BIT(1) Set to 1, for Intrupt to occur when new accel data is ready in all three channels */ 1431 | 1432 | 1433 | void initBMA180() { 1434 | 1435 | #ifdef ECHO_TO_SERIAL 1436 | Serial.println(F("Initializing BMA180 accelerometer...")); 1437 | delay(10); 1438 | #endif 1439 | 1440 | i2c_writeRegByte(BMA180_ADDRESS,BMA180_CMD_RESET,0xB6); //B6 (hex) forces the reset - can be done before the ee bit is set? 1441 | Serial.print(F("Soft Reset ")); 1442 | delay(10); //delay serial comms after reset 1443 | //Control, status & image registers are reset to values stored in the EEprom. 1444 | //puts the BMA in wake-up mode & default low noise mode "00": BW=1200 Noise 150 ug/rt pg28 1445 | 1446 | int id = i2c_readRegByte(BMA180_ADDRESS, BMA180_CMD_CHIP_ID); 1447 | if(id == 0x03) 1448 | { 1449 | #ifdef ECHO_TO_SERIAL 1450 | Serial.print(F("BMA180 Chip found at: ")); 1451 | Serial.print(id); 1452 | delay(10); 1453 | #endif 1454 | if (i2c_writeRegBits(BMA180_ADDRESS,BMA180_CMD_CTRL_REG0,1, ctrl_reg0_ee_w_MASK) == 0) //enable register writing 1455 | { 1456 | #ifdef ECHO_TO_SERIAL 1457 | Serial.print(F(" BMA180 Write Init Pass")); 1458 | delay(10); 1459 | #endif 1460 | 1461 | // disable wakeup mode because we will be sleeping the sensor manually 1462 | i2c_writeRegBits(BMA180_ADDRESS,BMA180_CMD_CTRL_REG0,0, ctrl_reg0_dis_wake_up_MASK); 1463 | #ifdef ECHO_TO_SERIAL 1464 | Serial.print(F(" Wake up mode disabled, ")); 1465 | #endif 1466 | 1467 | // Connect to the bw_tcs register and set the BW filtering level to 10Hz, Only bits 4-7 of the register hold this data 1468 | i2c_writeRegBits(BMA180_ADDRESS,BMA180_CMD_BW_TCS,BMA180_BW_10HZ,cmd_bandwidth_MASK); 1469 | #ifdef ECHO_TO_SERIAL 1470 | Serial.print(F(" Filtering level set to 10HZ, ")); 1471 | delay(10); 1472 | #endif 1473 | 1474 | // Connect to the offset_lsb1 register and set the range 1475 | i2c_writeRegBits(BMA180_ADDRESS,BMA180_RANGEnSMP,BMA180_RANGE_1G,range_MASK); 1476 | 1477 | #ifdef ECHO_TO_SERIAL 1478 | Serial.print(F(" Range set to 1G,")); 1479 | delay(10); 1480 | #endif 1481 | // since this is a tilt sensing application, I am using the 1g range, which is factory calibrated 1482 | // To enable the factory calibrated offset registers to be used by the sensors DAC 1483 | // en_offset_x, en_offset_y, en_offset_z control bits are set to 1 1484 | // p49: to regulate all axis, it is necessary to enable the en_offset bits sequentially 1485 | 1486 | i2c_writeRegBits(BMA180_ADDRESS,BMA180_CMD_CTRL_REG1,0,B10000000); //en_offset_x 1487 | i2c_writeRegBits(BMA180_ADDRESS,BMA180_CMD_CTRL_REG1,0,B01000000); //en_offset_y 1488 | i2c_writeRegBits(BMA180_ADDRESS,BMA180_CMD_CTRL_REG1,0,B00100000); //en_offset_z 1489 | #ifdef ECHO_TO_SERIAL 1490 | Serial.println(F(" Factory offsets enabled,")); 1491 | delay(30); 1492 | #endif 1493 | //BMAtemperature = i2c_readReg(BMA180, BMA180_CMD_TEMP); 1494 | //Serial.print("Temperature = ");Serial.println(BMAtemperature); 1495 | 1496 | //final step in setup is to disable register writing 1497 | i2c_writeRegBits(BMA180_ADDRESS,BMA180_CMD_CTRL_REG0,0, ctrl_reg0_ee_w_MASK); 1498 | delay(15); 1499 | 1500 | } 1501 | else 1502 | { 1503 | Serial.println(F(" BMA180 Write Init Fail! ")); 1504 | delay(10); 1505 | error(); 1506 | } 1507 | } 1508 | else 1509 | { 1510 | Serial.println(F(" BMA180 Chip Detect Fail! ")); 1511 | delay(10); 1512 | error(); 1513 | } 1514 | 1515 | readBMA180(); //just to get the sensor arrays loaded 1516 | 1517 | #ifdef ECHO_TO_SERIAL 1518 | Serial.println(F("...BMA180 has been initialized")); 1519 | delay(10); 1520 | #endif 1521 | } 1522 | 1523 | 1524 | void readBMA180() 1525 | { 1526 | // read in the 3 axis data, each one is 14 bits = +- 16,383 for integer values 1527 | // note negative values in the directions of the arrows printed on the breakout board! 1528 | 1529 | for (int thisReading = 0; thisReading < filterSamples; thisReading++){ //fill the smoothing arrays 1530 | 1531 | bytebuffer = i2c_readRegByte(BMA180_ADDRESS, BMA180_CMD_ACC_X_MSB); 1532 | rawACCx[thisReading] = bytebuffer << 8; // puts the most sig bits on the corect side - I am reading 14 bits total 1533 | bytebuffer = i2c_readRegByte(BMA180_ADDRESS, BMA180_CMD_ACC_X_LSB); 1534 | rawACCx[thisReading] |= bytebuffer >> 2; //this shift gets rid of two non-value bits in LSB register 1535 | 1536 | bytebuffer = i2c_readRegByte(BMA180_ADDRESS, BMA180_CMD_ACC_Y_MSB); 1537 | rawACCy[thisReading] = bytebuffer << 8; 1538 | bytebuffer = i2c_readRegByte(BMA180_ADDRESS, BMA180_CMD_ACC_Y_LSB); 1539 | rawACCy[thisReading] |= bytebuffer >> 2; // what about adding the offset here? 1540 | 1541 | bytebuffer = i2c_readRegByte(BMA180_ADDRESS, BMA180_CMD_ACC_Z_MSB); 1542 | rawACCz[thisReading] = bytebuffer << 8; 1543 | bytebuffer = i2c_readRegByte(BMA180_ADDRESS, BMA180_CMD_ACC_Z_LSB); 1544 | rawACCz[thisReading] |= bytebuffer >> 2; 1545 | 1546 | // we have the internal BMA bandwith filter set to 10 Hz so its not going to give new data without some time! 1547 | setWTD_125ms(); 1548 | sleepNwait4WDT(); 1549 | 1550 | } 1551 | // Now send those readings out to the digital smoothing function 1552 | smoothACCx = digitalSmooth(rawACCx); 1553 | smoothACCy = digitalSmooth(rawACCy); 1554 | smoothACCz = digitalSmooth(rawACCz); 1555 | } 1556 | 1557 | #endif 1558 | 1559 | 1560 | // ************************************************************************************************************ 1561 | // I2C Accelerometer BMA 250 10 bit (+- 1023) 1562 | // ************************************************************************************************************ 1563 | // see http://www.bosch-sensortec.com/de/homepage/products_3/3_axis_sensors/acceleration_sensors/bma250_1/bma250 1564 | // for more registers http://asf.atmel.com/docs/latest/xmegaau/html/bma250_8h.html 1565 | 1566 | #if defined(BMA250_ADDRESS) 1567 | //#define BMA250_FIXED_DEVID 0x03 1568 | //#define BMA250_REG_DEVID 0x00 1569 | //#define BMA250_REG_OFSX 0x16 1570 | //#define BMA250_REG_OFSX_HIGH 0x1A 1571 | #define BMA250_REG_BW_RATE 0x10 1572 | //#define BMA250_BW_MASK 0x1f 1573 | //#define BMA250_BW_200HZ 0x0d 1574 | //#define BMA250_BW_100HZ 0x0c 1575 | //#define BMA250_BW_50HZ 0x0b 1576 | //#define BMA250_BW_25HZ 0x0a 1577 | #define BMA250_BW_8HZ 0x08 1578 | //#define BMA250_REG_POWER_CTL 0x11 1579 | #define BMA250_REG_DATA_FORMAT 0x0f 1580 | //#define BMA250_RANGE_MASK 0x0f 1581 | #define BMA250_RANGE_2G 0x03 1582 | //#define BMA250_RANGE_4G 0x05 1583 | //#define BMA250_RANGE_8G 0x08 1584 | //#define BMA250_RANGE_16G 0x0C 1585 | //#define BMA250_REG_DATAXLOW 0x02 1586 | //#define BMA250_REG_DATA_RESOLUTION 0x14 1587 | //#define BMA250_MEASURE_MODE 0x80 1588 | //#define BMA250_SELF_TEST 0x32 1589 | //#define BMA250_SELF_TEST_AXIS_X 0x01 1590 | //#define BMA250_SELF_TEST_AXIS_Y 0x02 1591 | //#define BMA250_SELF_TEST_AXIS_Z 0x03 1592 | //#define BMA250_SELF_TEST_POSITIVE 0x00 1593 | //#define BMA250_SELF_TEST_NEGATIVE 0x04 1594 | //#define BMA250_INT_REG_1 0x16 1595 | //#define BMA250_INT_REG_2 0x17 1596 | #define BMA250_CMD_ACC_X_LSB 0x02 /* First of 6 registers of accel data */ 1597 | #define BMA250_CMD_ACC_X_MSB 0x03 1598 | #define BMA250_CMD_ACC_Y_LSB 0x04 1599 | #define BMA250_CMD_ACC_Y_MSB 0x05 1600 | #define BMA250_CMD_ACC_Z_LSB 0x06 1601 | #define BMA250_CMD_ACC_Z_MSB 0x07 1602 | 1603 | byte initBMA250() 1604 | { 1605 | #ifdef ECHO_TO_SERIAL 1606 | Serial.println(F("Init BMA250...")); 1607 | #endif 1608 | 1609 | i2c_writeRegByte(BMA250_ADDRESS,BMA250_REG_DATA_FORMAT,BMA250_RANGE_2G); //select 2G range 1610 | i2c_writeRegByte(BMA250_ADDRESS,BMA250_REG_BW_RATE,BMA250_BW_8HZ); //actually 7.81Hz bandwith, 64ms update 1611 | 1612 | #ifdef ECHO_TO_SERIAL 1613 | Serial.println(F("...BMA250 accelerometer has been initialized")); 1614 | #endif 1615 | 1616 | return(0); 1617 | } 1618 | 1619 | // from BMA250_I2C_Sketch.pde -BMA250 Accelerometer using I2C from www.dsscircuits.com/accelerometer-bma250.html 1620 | byte readBMA250() 1621 | { 1622 | 1623 | for (int thisReading = 0; thisReading < filterSamples; thisReading++){ //fill the smoothing arrays 1624 | 1625 | bytebuffer = i2c_readRegByte(BMA250_ADDRESS, BMA250_CMD_ACC_X_MSB); 1626 | rawACCx[thisReading] = bytebuffer << 8; // puts the most sig bits on the corect side 1627 | bytebuffer = i2c_readRegByte(BMA250_ADDRESS, BMA250_CMD_ACC_X_LSB); 1628 | rawACCx[thisReading] |= bytebuffer >> 6; //this shift gets rid of 6 non-value bits in LSB register 1629 | 1630 | bytebuffer = i2c_readRegByte(BMA250_ADDRESS, BMA250_CMD_ACC_Y_MSB); 1631 | rawACCy[thisReading] = bytebuffer << 8; 1632 | bytebuffer = i2c_readRegByte(BMA250_ADDRESS, BMA250_CMD_ACC_Y_LSB); 1633 | rawACCy[thisReading] |= bytebuffer >> 6; // what about adding the offset here? 1634 | 1635 | bytebuffer = i2c_readRegByte(BMA250_ADDRESS, BMA250_CMD_ACC_Z_MSB); 1636 | rawACCz[thisReading] = bytebuffer << 8; 1637 | bytebuffer = i2c_readRegByte(BMA250_ADDRESS, BMA250_CMD_ACC_Z_LSB); 1638 | rawACCz[thisReading] |= bytebuffer >> 6; 1639 | 1640 | //delay(135); // we have the internal BMA bandwith filter set to 7.81 Hz so its not going to give new data without some time! 1641 | setWTD_125ms(); //might need a touch more time... 1642 | sleepNwait4WDT(); 1643 | } 1644 | // Now send those readings out to the digital smoothing function - probably dont need to smooth as much as BMA180 1645 | smoothACCx = digitalSmooth(rawACCx); 1646 | smoothACCy = digitalSmooth(rawACCy); 1647 | smoothACCz = digitalSmooth(rawACCz); 1648 | } 1649 | #endif 1650 | 1651 | // ************************************************************************************************************ 1652 | // Accelerometer SMOOTHING FUNCTION 1653 | // ************************************************************************************************************ 1654 | // this smoothing function based on Paul Badger's http://playground.arduino.cc/Main/DigitalSmooth 1655 | // "int *inputArray" passes an array to the function - the asterisk indicates the array name is a pointer 1656 | int digitalSmooth(int *inputArray){ 1657 | int j, k, temp, top, bottom; 1658 | long total; 1659 | static int i; 1660 | boolean done; 1661 | 1662 | done = 0; // flag to know when we're done sorting 1663 | while(done != 1){ // simple swap sort, sorts numbers from lowest to highest 1664 | done = 1; 1665 | for (j = 0; j < (filterSamples - 1); j++){ 1666 | if (inputArray[j] > inputArray[j + 1]){ // numbers are out of order - swap 1667 | temp = inputArray[j + 1]; 1668 | inputArray [j+1] = inputArray[j] ; 1669 | inputArray [j] = temp; 1670 | done = 0; 1671 | } 1672 | } 1673 | } 1674 | 1675 | #ifdef ECHO_TO_SERIAL 1676 | Serial.println(F("Sorted Raw ACC readings:")); 1677 | for (j = 0; j < (filterSamples); j++){ // print the array for debugging 1678 | Serial.print(inputArray[j]); 1679 | Serial.print(F(" ")); 1680 | } 1681 | Serial.println(F(" ")); 1682 | #endif 1683 | 1684 | // throw out top and bottom 15% of samples - limit to throw out at least one from top and bottom 1685 | bottom = max(((filterSamples * 15) / 100), 1); 1686 | top = min((((filterSamples * 85) / 100) + 1 ), (filterSamples - 1)); // the + 1 is to make up for asymmetry caused by integer rounding 1687 | k = 0; 1688 | total = 0; 1689 | for ( j = bottom; j< top; j++){ 1690 | total += inputArray[j]; // total remaining indices 1691 | k++; 1692 | // Serial.print(sensSmoothArray[j]);Serial.print(" "); //more debugging 1693 | } 1694 | // Serial.println(); Serial.print("average = "); Serial.println(total/k); //more debugging 1695 | return total/k; // divide by number of samples 1696 | 1697 | } 1698 | 1699 | // ************************************************************************************************************ 1700 | // MS5803 functions sensor spec http://www.meas-spec.com/downloads/MS5803-02BA.pdf 1701 | // ************************************************************************************************************ 1702 | // 1703 | // ALL of these MS5803 functions are based on Luke Millers libraries at https://github.com/millerlp?tab=repositories 1704 | // The only reason I re-juggled his excellent 2Bar and 5Bar sensor libraries into the combined code here (in June 2014), is because I did not have enough free ram left in my 1705 | // script to load even one of original the libraries. Using his code here means that I must release this version of the Cave Pearl codebase under 1706 | // GPL license, https://github.com/millerlp/MS5803_02/blob/master/LICENSE.md and I am cool with that. 1707 | 1708 | #if defined(MS5803_I2C_ADDRESS) 1709 | 1710 | void sendCommandMS5803(byte command){ 1711 | Wire.beginTransmission(0x76); //MS5803-02 i2c address, same for all? 1712 | Wire.write(command); 1713 | Wire.endTransmission(); 1714 | } 1715 | 1716 | 1717 | //======================================================= 1718 | 1719 | boolean initializeMS_5803(boolean Verbose) { 1720 | Wire.begin(); 1721 | // Reset the sensor during startup 1722 | resetSensor(); 1723 | 1724 | if (Verbose) { 1725 | // Display the oversampling resolution or an error message 1726 | Serial.print(F("Oversampling setting: ")); 1727 | Serial.println(_Resolution); 1728 | } 1729 | 1730 | // Read sensor coefficients 1731 | for (int i = 0; i < 8; i++ ){ 1732 | // The PROM starts at address 0xA0 1733 | Wire.beginTransmission(MS5803_I2C_ADDRESS); 1734 | Wire.write(0xA0 + (i * 2)); 1735 | Wire.endTransmission(); 1736 | Wire.requestFrom(MS5803_I2C_ADDRESS, 2); 1737 | while(Wire.available()) { 1738 | HighByte = Wire.read(); 1739 | LowByte = Wire.read(); 1740 | } 1741 | sensorCoeffs[i] = (((unsigned int)HighByte << 8) + LowByte); 1742 | if (Verbose){ 1743 | // Print out coefficients 1744 | Serial.print("C"); 1745 | Serial.print(i); 1746 | Serial.print(" = "); 1747 | Serial.println(sensorCoeffs[i]); 1748 | delay(10); 1749 | } 1750 | } 1751 | // The last 4 bits of the 7th coefficient form a CRC error checking code. 1752 | unsigned char p_crc = sensorCoeffs[7]; 1753 | // Use a function to calculate the CRC value 1754 | unsigned char n_crc = MS_5803_CRC(sensorCoeffs); 1755 | 1756 | if (Verbose) { 1757 | Serial.print(F("p_crc: ")); 1758 | Serial.println(p_crc); 1759 | Serial.print(F("n_crc: ")); 1760 | Serial.println(n_crc); 1761 | } 1762 | // If the CRC value doesn't match the sensor's CRC value, then the 1763 | // connection can't be trusted. Check your wiring. 1764 | if (p_crc != n_crc) { 1765 | return false; 1766 | } 1767 | // Otherwise, return true when everything checks out OK. 1768 | return true; 1769 | } 1770 | 1771 | //------------------------------------------------------------------ 1772 | void readSensor() { 1773 | // Choose from CMD_ADC_256, 512, 1024, 2048, 4096 for mbar resolutions 1774 | // of 1, 0.6, 0.4, 0.3, 0.2 respectively. Higher resolutions take longer 1775 | // to read. 1776 | if (_Resolution == 256){ 1777 | D1 = MS_5803_ADC(CMD_ADC_D1 + CMD_ADC_256); // read raw pressure 1778 | D2 = MS_5803_ADC(CMD_ADC_D2 + CMD_ADC_256); // read raw temperature 1779 | } 1780 | else if (_Resolution == 512) { 1781 | D1 = MS_5803_ADC(CMD_ADC_D1 + CMD_ADC_512); // read raw pressure 1782 | D2 = MS_5803_ADC(CMD_ADC_D2 + CMD_ADC_512); // read raw temperature 1783 | } 1784 | else if (_Resolution == 1024) { 1785 | D1 = MS_5803_ADC(CMD_ADC_D1 + CMD_ADC_1024); // read raw pressure 1786 | D2 = MS_5803_ADC(CMD_ADC_D2 + CMD_ADC_1024); // read raw temperature 1787 | } 1788 | else if (_Resolution == 2048) { 1789 | D1 = MS_5803_ADC(CMD_ADC_D1 + CMD_ADC_2048); // read raw pressure 1790 | D2 = MS_5803_ADC(CMD_ADC_D2 + CMD_ADC_2048); // read raw temperature 1791 | } 1792 | else if (_Resolution == 4096) { 1793 | D1 = MS_5803_ADC(CMD_ADC_D1 + CMD_ADC_4096); // read raw pressure 1794 | D2 = MS_5803_ADC(CMD_ADC_D2 + CMD_ADC_4096); // read raw temperature 1795 | } 1796 | 1797 | // Calculate 1st order temperature, dT is a long integer 1798 | // D2 is originally cast as an uint32_t, but can fit in a int32_t, so we'll 1799 | // cast both parts of the equation below as signed values so that we can 1800 | // get a negative answer if needed 1801 | 1802 | dT = (int32_t)D2 - ( (int32_t)sensorCoeffs[5] * 256 ); 1803 | 1804 | // Use integer division to calculate TEMP. It is necessary to cast 1805 | // one of the operands as a signed 64-bit integer (int64_t) so there's no 1806 | // rollover issues in the numerator. 1807 | 1808 | TEMP = 2000 + ((int64_t)dT * sensorCoeffs[6]) / 8388608LL; //this line would not compile until I declared TEMP to be int64_t at start 1809 | // Recast TEMP as a signed 32-bit integer 1810 | TEMP = (int32_t)TEMP; 1811 | 1812 | /*********************************************************************************************** 1813 | * // NOTE: I do not have enough ram left in this CODEBUILD for ANY second order calculations! (Needs >6K! free) 1814 | * // Just including them here for completeness since I will need to do these later in excel... 1815 | *************************************************************************************************/ 1816 | 1817 | #if defined(MS5803_02_ISON) //calculations specific to the 2 bar sensor 1818 | 1819 | /* 1820 | for the MS5803-02 sensor: 1821 | // All operations from here down are done as integer math until we make the final calculation of pressure in mbar. 1822 | // 2nd order temperature compensation (see pg 9 of MS5803 data sheet) 1823 | // I have tried to insert the fixed values wherever possible (i.e. 2^31 is hard coded as 2147483648). 1824 | if (TEMP < 2000) { 1825 | // For 2 bar model 1826 | T2 = ((uint64_t)dT * dT) / 2147483648 ; // 2^31 = 2147483648 1827 | T2 = (int32_t)T2; // recast as signed 32bit integer 1828 | OFF2 = (61 * ((TEMP-2000) * (TEMP-2000))) / 16 ; 1829 | Sens2 = 2 * ((TEMP-2000) * (TEMP-2000)) ; 1830 | } 1831 | else { // if TEMP is > 2000 (20.0C) 1832 | // For 2 bar model 1833 | T2 = 0; 1834 | OFF2 = 0; 1835 | Sens2 = 0; 1836 | } 1837 | // Additional compensation for very low temperatures (< -15C) 1838 | if (TEMP < -1500) { 1839 | // For 2 bar model 1840 | OFF2 = OFF2 + 20 * ((TEMP+1500)*(TEMP+1500)); 1841 | Sens2 = Sens2 + 12 * ((TEMP+1500)*(TEMP+1500)); 1842 | } 1843 | */ 1844 | 1845 | // Calculate initial Offset and Sensitivity For 2 bar sensor 1846 | // THESE CALCS TAKE 1K OF PROG MEM TO PERFORM! 1847 | Offset = (int64_t)sensorCoeffs[2] * 131072 + (sensorCoeffs[4] * (int64_t)dT) / 64; 1848 | Sensitivity = (int64_t)sensorCoeffs[1] * 65536 + (sensorCoeffs[3] * (int64_t)dT) / 128; 1849 | 1850 | #endif 1851 | 1852 | #if defined(MS5803_05_ISON) //calculations specific to the 5 bar sensor 1853 | /* // Do 2nd order temperature compensation (see pg 9 of MS5803-05 data sheet) 1854 | if (TEMP < 2000) { 1855 | // For 5 bar model 1856 | // If temperature is below 20.0C 1857 | T2 = 3 * ((uint64_t)dT * dT) / POW_2_33 ; // 2^33 = 8589934592 1858 | T2 = (int32_t)T2; // recast as signed 32bit integer 1859 | OFF2 = 3 * ((TEMP-2000) * (TEMP-2000)) / 8 ; 1860 | Sens2 = 7 * ((TEMP-2000) * (TEMP-2000)) / 8 ; 1861 | } else { // if TEMP is > 2000 (20.0C) 1862 | // For 5 bar sensor 1863 | T2 = 0; 1864 | OFF2 = 0; 1865 | Sens2 = 0; 1866 | } 1867 | // Additional compensation for very low temperatures (< -15C) 1868 | if (TEMP < -1500) { 1869 | // For 5 bar sensor 1870 | // Leave OFF2 alone in this case 1871 | Sens2 = Sens2 + 3 * ((TEMP+1500)*(TEMP+1500)); 1872 | } 1873 | */ 1874 | // Calculate initial Offset and Sensitivity For 5 bar sensor - these two lines take 1K of prog space! 1875 | 1876 | Offset = (int64_t)sensorCoeffs[2] * 262144 + (sensorCoeffs[4] * (int64_t)dT) / 32; 1877 | Sensitivity = (int64_t)sensorCoeffs[1] * 131072 + (sensorCoeffs[3] * (int64_t)dT) / 128; 1878 | 1879 | #endif 1880 | 1881 | /* 1882 | // Adjust TEMP, Offset, Sensitivity values based on the 2nd order 1883 | // temperature correction above. (But Since I did not calculate any of the 2nd order values...skiping this) 1884 | TEMP = TEMP - T2; // both should be int32_t 1885 | Offset = Offset - OFF2; // both should be int64_t 1886 | Sensitivity = Sensitivity - Sens2; // both should be int64_t 1887 | */ 1888 | 1889 | // Final compensated pressure calculation. We first calculate the pressure 1890 | // as a signed 32-bit integer (mbarInt), then convert that value to a 1891 | // float (mbar). [same calc for the 2 & 5 bar sensor...] 1892 | 1893 | // THESE FIRST ORDER CALCS TAKE 1K OF PROG MEM TO PERFORM! 1894 | mbarInt = ((D1 * Sensitivity) / 2097152 - Offset) / 32768; 1895 | mbar = (float)mbarInt / 100; 1896 | tempC = (float)TEMP / 100; 1897 | 1898 | /* // Start other temperature conversions by converting mbar to psi absolute 1899 | // psiAbs = mbar * 0.0145038; 1900 | // // Convert psi absolute to inches of mercury 1901 | // inHgPress = psiAbs * 2.03625; 1902 | // // Convert psi absolute to gauge pressure 1903 | // psiGauge = psiAbs - 14.7; 1904 | // // Convert mbar to mm Hg 1905 | // mmHgPress = mbar * 0.7500617; 1906 | // // Convert temperature to Fahrenheit 1907 | // tempF = (tempC * 1.8) + 32; 1908 | */ 1909 | } 1910 | 1911 | //------------------------------------------------------------------ 1912 | // Function to check the CRC value provided by the sensor against the 1913 | // calculated CRC value from the rest of the coefficients. 1914 | // Based on code from Measurement Specialties application note AN520 1915 | // http://www.meas-spec.com/downloads/C-Code_Example_for_MS56xx,_MS57xx_%28except_analog_sensor%29_and_MS58xx_Series_Pressure_Sensors.pdf 1916 | unsigned char MS_5803_CRC(unsigned int n_prom[]) { 1917 | int cnt; // simple counter 1918 | unsigned int n_rem; // crc reminder 1919 | unsigned int crc_read; // original value of the CRC 1920 | unsigned char n_bit; 1921 | n_rem = 0x00; 1922 | crc_read = sensorCoeffs[7]; // save read CRC 1923 | sensorCoeffs[7] = (0xFF00 & (sensorCoeffs[7])); // CRC byte replaced with 0 1924 | for (cnt = 0; cnt < 16; cnt++) 1925 | { // choose LSB or MSB 1926 | if (cnt%2 == 1) { 1927 | n_rem ^= (unsigned short)((sensorCoeffs[cnt>>1]) & 0x00FF); 1928 | } 1929 | else { 1930 | n_rem ^= (unsigned short)(sensorCoeffs[cnt>>1] >> 8); 1931 | } 1932 | for (n_bit = 8; n_bit > 0; n_bit--) 1933 | { 1934 | if (n_rem & (0x8000)) 1935 | { 1936 | n_rem = (n_rem << 1) ^ 0x3000; 1937 | } 1938 | else { 1939 | n_rem = (n_rem << 1); 1940 | } 1941 | } 1942 | } 1943 | n_rem = (0x000F & (n_rem >> 12));// // final 4-bit reminder is CRC code 1944 | sensorCoeffs[7] = crc_read; // restore the crc_read to its original place 1945 | // Return n_rem so it can be compared to the sensor's CRC value 1946 | return (n_rem ^ 0x00); 1947 | } 1948 | 1949 | //----------------------------------------------------------------- 1950 | // Send commands and read the temperature and pressure from the sensor 1951 | unsigned long MS_5803_ADC(char commandADC) { 1952 | // D1 and D2 will come back as 24-bit values, and so they must be stored in 1953 | // a long integer on 8-bit Arduinos. 1954 | long result = 0; 1955 | // Send the command to do the ADC conversion on the chip 1956 | Wire.beginTransmission(MS5803_I2C_ADDRESS); 1957 | Wire.write(CMD_ADC_CONV + commandADC); 1958 | Wire.endTransmission(); 1959 | // Wait a specified period of time for the ADC conversion to happen 1960 | // See table on page 1 of the MS5803 data sheet showing response times of 1961 | // 0.5, 1.1, 2.1, 4.1, 8.22 ms for each accuracy level. 1962 | switch (commandADC & 0x0F) 1963 | { 1964 | case CMD_ADC_256 : 1965 | delay(1); // 1 ms 1966 | break; 1967 | case CMD_ADC_512 : 1968 | delay(3); // 3 ms 1969 | break; 1970 | case CMD_ADC_1024: 1971 | delay(4); 1972 | break; 1973 | case CMD_ADC_2048: 1974 | delay(6); 1975 | break; 1976 | case CMD_ADC_4096: 1977 | delay(10); 1978 | break; 1979 | } 1980 | // Now send the read command to the MS5803 1981 | Wire.beginTransmission(MS5803_I2C_ADDRESS); 1982 | Wire.write((byte)CMD_ADC_READ); 1983 | Wire.endTransmission(); 1984 | // Then request the results. This should be a 24-bit result (3 bytes) 1985 | Wire.requestFrom(MS5803_I2C_ADDRESS, 3); 1986 | while(Wire.available()) { 1987 | HighByte = Wire.read(); 1988 | MidByte = Wire.read(); 1989 | LowByte = Wire.read(); 1990 | } 1991 | // Combine the bytes into one integer 1992 | result = ((long)HighByte << 16) + ((long)MidByte << 8) + (long)LowByte; 1993 | return result; 1994 | } 1995 | 1996 | //---------------------------------------------------------------- 1997 | // Sends a power on reset command to the MS5803 sensor. 1998 | void resetSensor() { 1999 | Wire.beginTransmission(MS5803_I2C_ADDRESS); 2000 | Wire.write(CMD_RESET); 2001 | Wire.endTransmission(); 2002 | delay(10); 2003 | } 2004 | 2005 | #endif 2006 | 2007 | 2008 | /***************************************************** 2009 | * RETIRED FUNCTIONS 2010 | ******************************************************/ 2011 | 2012 | /* the ds3231 RTC temp reading routine is now retired from the main codebuild, just including it here in case someone else wants it 2013 | //the following variables should be defined at start for this function 2014 | //byte tMSB, tLSB; float RTCTempfloat; int temp3231; uint8_t wRTCtemp,fRTCtemp; 2015 | // also see https://github.com/mizraith/RTClib or https://github.com/akafugu/ds_rtc_lib for more DS3231 specific libs 2016 | could also use RTC.getTemperature() from the library here as in: 2017 | RTC.convertTemperature(); //convert current temperature into registers 2018 | Serial.print(RTC.getTemperature()); //read registers and display the temperature */ 2019 | // get temp from http://forum.arduino.cc/index.php/topic,22301.0.html 2020 | //RTCTempfloat= get3231Temp(); wRTCtemp = (int)RTCTempfloat; fRTCtemp= (RTCTempfloat - wRTCtemp) * 100; // Float split into 2 intergers 2021 | 2022 | /*float get3231Temp() 2023 | { 2024 | //temp registers (11h-12h) get updated automatically every 64s 2025 | Wire.beginTransmission(DS3231_ADDRESS); 2026 | Wire.write(0x11); 2027 | Wire.endTransmission(); 2028 | Wire.requestFrom(DS3231_ADDRESS, 2); 2029 | 2030 | if(Wire.available()) { 2031 | tMSB = Wire.read(); //2's complement int portion 2032 | tLSB = Wire.read(); //fraction portion 2033 | 2034 | temp3231 = ((((short)tMSB << 8 | (short)tLSB) >> 6) / 4.0); 2035 | // Allows for readings below freezing - Thanks to Coding Badly 2036 | //temp3231 = (temp3231 * 1.8 + 32.0); // Convert Celcius to Fahrenheit 2037 | return temp3231; 2038 | 2039 | } 2040 | else { 2041 | temp3231 = 255.0; //Use a value of 255 as error flag 2042 | } 2043 | 2044 | return temp3231; 2045 | } 2046 | */ 2047 | 2048 | 2049 | /********************************************** 2050 | * old ERROR HANDLER 2051 | ********************************************** 2052 | * // always write error messages to the serial monitor but this routine wastes 2053 | * // everything passed to the string from the original call is in sram! 2054 | * 2055 | * void error(char *str) 2056 | * { 2057 | * Serial.print(F("error in: ")); 2058 | * Serial.println(str); 2059 | /* this next statement will start an endless loop, basically stopping all 2060 | * operation upon any error. Change this behavior if you want. 2061 | * digitalWrite(RED_PIN, HIGH); 2062 | * while (1); 2063 | * } 2064 | */ 2065 | 2066 | //************************************ 2067 | //MS5803-05 -OR- MS5803-02 init 2068 | //************************************ 2069 | /* THIS is based on the OPENROV project code by WALT HOLM 2070 | // https://github.com/OpenROV/openrov-software/blob/master/arduino/Test%20Code/Walts_Depth_Sensor_Rev1.ino 2071 | 2072 | #if defined(MS5803_02_ADR) || defined(MS5803_05_ADR) 2073 | 2074 | // Reset the device and check for device presence // left at default 512 oversampling after reset 2075 | sendCommandMS5803(Reset); 2076 | delay(1000); //how long does this delay have to be??? 2077 | setWTD_125ms(); //use the sleep instead of delays 2078 | sleepNwait4WDT(); 2079 | Serial.println(F("MS5803 is reset")); 2080 | 2081 | // Get the calibration constants and store in array (note this code is from 02 bar sensor!) 2082 | for (byte i = 0; i < 8; i++) 2083 | { 2084 | sendCommandMS5803(PromBaseAddress + (2*i)); 2085 | Wire.requestFrom(0x76, 2); //dev address is 0x76 2086 | while(Wire.available()){ 2087 | ByteHigh = Wire.read(); 2088 | ByteLow = Wire.read(); 2089 | } 2090 | CalConstant[i] = (((unsigned int)ByteHigh << 8) + ByteLow); 2091 | } 2092 | 2093 | #ifdef ECHO_TO_SERIAL 2094 | Serial.println(F("Ms5803-2 Pressure sensor Calibration constants are:")); 2095 | for (byte i=0; i < 8; i++){ 2096 | Serial.print(F("C")); 2097 | Serial.print(i); 2098 | Serial.print(F(":,")); 2099 | Serial.println(CalConstant[i]); 2100 | } 2101 | Serial.println(F(" ")); 2102 | #endif 2103 | 2104 | // could do some crc checking here 2105 | 2106 | #endif 2107 | */ 2108 | 2109 | /* 2110 | //Read Pressure Sensor: Based on the OPEN ROV code 2111 | #if defined(MS5803_02_ADR) || defined(MS5803_05_ADR) 2112 | 2113 | // Read the Ms5803 for the RAW ADC Temperature and ADC Pressure values, just read the raw D1 &D2 values & Calculate later in Excel 2114 | 2115 | sendCommandMS5803(D1_512); //start D1 conversion 2116 | digitalWrite(GREEN_PIN, HIGH); 2117 | delay(10);// conversion delay for each oversample ratio is 1.1 / 2.1 / 4.1 / 9 ms 2118 | digitalWrite(GREEN_PIN, LOW); 2119 | sendCommandMS5803(AdcRead); 2120 | Wire.requestFrom(0x76, 3); 2121 | while(Wire.available()) 2122 | { 2123 | ByteHigh = Wire.read(); 2124 | ByteMiddle = Wire.read(); 2125 | ByteLow = Wire.read(); 2126 | } 2127 | rawMS5803pressure = ((long)ByteHigh << 16) + ((long)ByteMiddle << 8) + (long)ByteLow; 2128 | //24 bit ADC value for D1 & D2 max = 16777216 2129 | 2130 | #ifdef ECHO_TO_SERIAL 2131 | Serial.print(F("D1(Raw Pressure): ")); 2132 | Serial.print(rawMS5803pressure); 2133 | #endif 2134 | 2135 | sendCommandMS5803(D2_512); //start D2 conversion 2136 | delay(10); 2137 | sendCommandMS5803(AdcRead); 2138 | Wire.requestFrom(0x76, 3); 2139 | while(Wire.available()) 2140 | { 2141 | ByteHigh = Wire.read(); 2142 | ByteMiddle = Wire.read(); 2143 | ByteLow = Wire.read(); 2144 | } 2145 | rawMS5803temp = ((long)ByteHigh << 16) + ((long)ByteMiddle << 8) + (long)ByteLow; 2146 | 2147 | #ifdef ECHO_TO_SERIAL 2148 | Serial.print(F(" D2(Raw Temp): ")); 2149 | Serial.println(rawMS5803temp); 2150 | #endif 2151 | 2152 | #endif 2153 | */ 2154 | 2155 | 2156 | 2157 | 2158 | 2159 | 2160 | 2161 | 2162 | 2163 | 2164 | --------------------------------------------------------------------------------