Category Archives: Logger Scripts & Code Tricks

My long and winding path learning how to program and Arduino. You can find a bread crumb trail of old & new code builds for the logger at the Project’s GitHub:
https://github.com/EKMallon?tab=repositories

What’s running in the currently deployed logger prototypes

Before I dive into optimizing the code for better power management, I thought I would post the script that is actually running (hopefully!) right now in the deployed units. This code was loaded on December 15th, 2013, and I managed to buffer 3 data read cycles before each SD card write cycle with the simplest method possible – I created two more sets of variables to hold the data.  So this is my starting point for the next round of development; if you notice any serious errors here (yes, I know strings! ugh!) please feel free to leave me a comment so I can improve things. Also note that I commented out all the print statements before compiling the final sketch.

// Date, Time and Alarm functions using a DS3231 RTC connected via I2C and Wire lib by https://github.com/MrAlvin/RTClib
// based largely on Jean-Claude Wippler from JeeLab’s excellent RTC library https://github.com/jcw
// clear alarm interupt from http://forum.arduino.cc/index.php?topic=109062.0
// get temp from http://forum.arduino.cc/index.php/topic,22301.0.html which does not use the RTCLIB!
// BMA250_I2C_Sketch.pde -BMA250 Accelerometer using I2C from http://www.dsscircuits.com/accelerometer-bma250.html
// combined with internal voltage reading trick //forum.arduino.cc/index.php/topic,15629.0.html
// floats to string conversion: http://dereenigne.org/arduino/arduino-float-to-string

// free memory code tricks:
// http://playground.arduino.cc/Code/AvailableMemory#.UwUugfldUyI

// free mem stabilzes around 616 with this three cycle buffer code..
// so each extra set of buffered variables adds about 57 bytes to the ram usage

#include <SD.h>
#include <Wire.h>
#include <SPI.h> // not used here, but needed to prevent a RTClib compile error
#include <avr/sleep.h>
#include <RTClib.h>

#ifndef cbi //defs for stopping the ADC during sleep mode
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

#define DS3231_I2C_ADDRESS 104 //for the RTC temp reading function

#define BMA250 0x18
#define BW 0x08 //7.81Hz bandwith
#define GSEL 0x03 // set range 0x03 – 2g, 0x05 – 4, 0x08 – 8g, 0x0C – 16g

RTC_DS3231 RTC;
byte Alarmhour = 1;
byte Alarmminute = 1;
byte dummyRegister;
byte INTERRUPT_PIN = 2;
//volatile int state = LOW;
volatile boolean clockInterrupt = false;
byte SampleInterval = 30; // power-down time in minutes before interupt triggers next sample

byte tMSB, tLSB; //for the RTC temp reading function
float temp3231;

const byte chipSelect = 10; //sd card chip select

uint8_t dataArray[16]; //variables for accellerometer reading – why is the temp a float value?
int8_t BMAtemp; //Ok so this thing is an interger
float BMAtempfloat;
int x,y,z;

String BMAdata; //for passing back data from bma read function
String BMAdata1;
String BMAdata2 = “0000,0000,0000,0000”;
String BMAdata3 = “0000,0000,0000,0000”;
char TimeStampbuffer1[ ]= “0000/00/00,00:00:00, “;
char TimeStampbuffer2[ ]= “0000/00/00,00:00:00, “;
char TimeStampbuffer3[ ]= “0000/00/00,00:00:00, “;
float Temp3231a =0.0;
float Temp3231b =0.0;
float Temp3231c =0.0;
int Vcc1=0; //the supply voltage via 1.1 internal and gap
int Vcc2=0;
int Vcc3=0;
byte cycle=1;

int ledpin = 13; //led indicator pin not used in this code

void setup () {

pinMode(INTERRUPT_PIN, INPUT);
digitalWrite(INTERRUPT_PIN, HIGH);//pull up the interrupt pin
pinMode(13, OUTPUT); // initialize the LED pin as an output.
digitalWrite(13, HIGH); // turn the LED on to warn against SD card removal

Serial.begin(9600);
Wire.begin();
RTC.begin();
//RTC.adjust(DateTime(__DATE__, __TIME__)); //set the time with code compile time only run this once!
clearClockTrigger(); //stops RTC from holding the interrupt low if system reset
// time for next alarm
DateTime now = RTC.now();
Alarmhour = now.hour();
Alarmminute = now.minute()+ SampleInterval ;
if (Alarmminute > 59) { //error catch – if Alarmminute=60 the interrupt never triggers due to rollover
Alarmminute = 0; Alarmhour = Alarmhour+1; if (Alarmhour > 23) {Alarmhour =0;}
}

initializeBMA(); //initialize the accelerometer – do I have to do this on every wake cycle?

//get the SD card ready
pinMode(chipSelect, OUTPUT); //make sure that the default chip select pin is set to output, even if you don’t use it
//Serial.print(F(“Initializing SD card…”));
if (!SD.begin(chipSelect)) { // see if the card is present and can be initialized:
Serial.println(F(“Card failed, or not present”)); // don’t do anything more:
return;
}
//Serial.println(F(“card initialized.”));
File dataFile = SD.open(“datalog.txt”, FILE_WRITE); //PRINT THE DATA FILE HEADER
if (dataFile) { // if the file is available, write to it:
dataFile.println(F(“YYYY/MM/DD HH:MM:SS, Vcc(mV), X = , Y = , Z = , BMATemp (C) , RTC temp (C)”));
dataFile.close();
}
else { //if the file isn’t open, pop up an error:
Serial.println(F(“Error opening datalog.txt file!”));
}
digitalWrite(13, LOW);
}

void loop () {

if (clockInterrupt) {
clearClockTrigger();
}

//read in our data
read3AxisAcceleration(); //loads up the dataString
DateTime now = RTC.now(); // Read the time and date from the RTC

if (cycle==1){
BMAdata1 = BMAdata;
Vcc1 = (readVcc());
Temp3231a = get3231Temp();
sprintf(TimeStampbuffer1, “%04d/%02d/%02d %02d:%02d:%02d,”, now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second());

//Serial.print(TimeStampbuffer1); Serial.print(Vcc1); Serial.print(“,”);
//Serial.print(BMAdata1); Serial.print(“,”); Serial.println(Temp3231a);
//Serial.println(freeRam());
//delay(100);
}

if (cycle==2){
BMAdata2 = BMAdata;
Vcc2 = int(readVcc());
Temp3231b = get3231Temp();
sprintf(TimeStampbuffer2, “%04d/%02d/%02d %02d:%02d:%02d,”, now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second());
//Serial.println(“Timestamp Y/M/D, HH:MM:SS, Vcc = , X = , Y = , Z = , BMATemp (C) , RTC temp (C)”);
//Serial.print(TimeStampbuffer2); Serial.print(Vcc2); Serial.print(“,”);
//Serial.print(BMAdata2); Serial.print(“,”); Serial.println(Temp3231b);
//Serial.println(freeRam());
//delay(100);
}

if (cycle==3){ //only write to mem card on this cycle
BMAdata3 = BMAdata;
Vcc3 = int(readVcc());
Temp3231c = get3231Temp();
sprintf(TimeStampbuffer3, “%04d/%02d/%02d %02d:%02d:%02d,”, now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second());
//Serial.println(“Timestamp Y/M/D, HH:MM:SS, Vcc = , X = , Y = , Z = , BMATemp (C) , RTC temp (C)”);
//Serial.print(TimeStampbuffer3); Serial.print(Vcc3); Serial.print(“,”);
//Serial.print(BMAdata3); Serial.print(“,”); Serial.println(Temp3231c);
//Serial.println(freeRam());
//delay(100);

// the whole dataset looks like 0000/00/00 00:00:00,0000,0000,0000,0000,00000,00000
// if Vcc too low, dont write to the sd card
if (Vcc1 > 2850){
//Serial.println(F(“-write cycle performed-“)); delay (50);//for debugging only

File dataFile = SD.open(“datalog.txt”, FILE_WRITE);
if (dataFile) { // if the file is available, write to it:
//here we do the two writes at one time – hopefully saving power only writing every second cycle
dataFile.print(TimeStampbuffer1);dataFile.print(Vcc1); dataFile.print(“,”);
dataFile.print(BMAdata1); dataFile.print(“,”); dataFile.println(Temp3231a);

dataFile.print(TimeStampbuffer2);dataFile.print(Vcc2); dataFile.print(“,”);
dataFile.print(BMAdata2); dataFile.print(“,”); dataFile.println(Temp3231b);

dataFile.print(TimeStampbuffer3);dataFile.print(Vcc3); dataFile.print(“,”);
dataFile.print(BMAdata3); dataFile.print(“,”); dataFile.println(Temp3231c);

dataFile.close();
}
else { //if the file isn’t open, pop up an error:
Serial.println(F(“Error opening datalog.txt file”));
}
}
}
// setNextAlarmTime();
Alarmhour = now.hour(); Alarmminute = now.minute()+SampleInterval;
if (Alarmminute > 59) { //error catch – if alarmminute=60 the interrupt never triggers due to rollover!
Alarmminute =0; Alarmhour = Alarmhour+1; if (Alarmhour > 23) {Alarmhour =0;}
}
RTC.setAlarm1Simple(Alarmhour, Alarmminute);
RTC.turnOnAlarm(1);

//print lines commented out for deployment
//Serial.print(F(“Alarm Enabled at: “));
//Serial.print(now.hour(), DEC); Serial.print(‘:’); Serial.println(now.minute(), DEC);
//Serial.print(F(“Going to Sleep for “)); Serial.print(SampleInterval);Serial.println(F(” minutes.”));
//delay(100); //a delay long enought to boot out the serial coms

cycle ++;
if (cycle>3){
cycle=1;}

sleepNow();

//Serial.println(F(“Alarm 1 has been Triggered!”));
}
void sleepNow() {
//digitalWrite(13, LOW);
cbi(ADCSRA,ADEN); // Switch ADC OFF
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
attachInterrupt(0,clockTrigger, LOW);
sleep_mode();
//HERE AFTER WAKING UP
sleep_disable();
detachInterrupt(0);
sbi(ADCSRA,ADEN); // Switch ADC converter ON
//digitalWrite(13, HIGH);
}

void clockTrigger() {
clockInterrupt = true; //do something quick, flip a flag, and handle in loop();
}

void clearClockTrigger()
{
Wire.beginTransmission(0x68); //Tell devices on the bus we are talking to the DS3231
Wire.write(0x0F); //Tell the device which address we want to read or write
Wire.endTransmission(); //Before you can write to and clear the alarm flag you have to read the flag first!
Wire.requestFrom(0x68,1); // Read one byte
dummyRegister=Wire.read(); // In this example we are not interest in actually using the bye
Wire.beginTransmission(0x68); //Tell devices on the bus we are talking to the DS3231
Wire.write(0x0F); //Tell the device which address we want to read or write
Wire.write(0b00000000); //Write the byte. The last 0 bit resets Alarm 1
Wire.endTransmission();
clockInterrupt=false; //Finally clear the flag we use to indicate the trigger occurred
}

// could also use RTC.getTemperature() from the library here as in:
// RTC.convertTemperature(); //convert current temperature into registers
// Serial.print(RTC.getTemperature()); //read registers and display the temperature

float get3231Temp()
{
//temp registers (11h-12h) get updated automatically every 64s
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(0x11);
Wire.endTransmission();
Wire.requestFrom(DS3231_I2C_ADDRESS, 2);

if(Wire.available()) {
tMSB = Wire.read(); //2’s complement int portion
tLSB = Wire.read(); //fraction portion

temp3231 = ((((short)tMSB << 8 | (short)tLSB) >> 6) / 4.0); // Allows for readings below freezing – Thanks to Coding Badly
//temp3231 = (temp3231 * 1.8 + 32.0); // Convert Celcius to Fahrenheit
return temp3231;

}
else {
temp3231 = 255.0; //Use a value of 255 to error flag that we did not get temp data from the ds3231
}

return temp3231;
}
byte read3AxisAcceleration()
{
Wire.beginTransmission(BMA250);
Wire.write(0x02);
Wire.endTransmission();
Wire.requestFrom(BMA250,7);
for(int i = 0; i < 7;i++)
{
dataArray[i] = Wire.read();
}
if(!bitRead(dataArray[0],0)){return(0);}

BMAtemp = dataArray[6];
x = dataArray[1] << 8;
x |= dataArray[0];
x >>= 6;
y = dataArray[3] << 8;
y |= dataArray[2];
y >>= 6;
z = dataArray[5] << 8;
z |= dataArray[4];
z >>= 6;

BMAdata = String(“”); //clear out the datastring
BMAdata += String(x);
BMAdata += “,”;
BMAdata += String(y);
BMAdata += “,”;
BMAdata += String(z);
BMAdata += “,”;
BMAtempfloat = (BMAtemp*0.5)+24.0;
// add digits of BMAtempfloat value to datastring
BMAdata += ((int)BMAtempfloat);
BMAdata += “.”;
int temp = (BMAtempfloat – (int)BMAtempfloat) * 100;
BMAdata += (abs(temp));
//this also works to convert float to string
//dtostrf(floatVariable2convert, minStringWidthIncDecimalPoint, numVarsAfterDecimal, charBuffer);
//for example: dtostrf(BMAtempfloat, 5, 2, dtostrfbuffer); dataString += dtostrfbuffer;
}
byte initializeBMA()
{
Wire.beginTransmission(BMA250);
Wire.write(0x0F); //set g
Wire.write(GSEL);
Wire.endTransmission();
Wire.beginTransmission(BMA250);
Wire.write(0x10); //set bandwith
Wire.write(BW);
Wire.endTransmission();
return(0);
}

long readVcc() { //trick to read the Vin using internal 1.1 v as a refrence
long result;
// Read 1.1V reference against AVcc
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
delay(3); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Convert
while (bit_is_set(ADCSRA,ADSC));
result = ADCL;
result |= ADCH<<8;
result = 1126400L / result; // Back-calculate AVcc in mV
return result;
}

int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v – (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}

Field Report 2013-12-15: Tweaking the Code

IMGP0554We had more diving with UNAM, and a few days of work with Trish’s own students ahead of us. But as luck would have it I had a nasty run in with señor Moctezuma, so I was forced to bow out of field work for a few days.  And now that we knew the data loggers were working, we were flirting with the idea that we could simply leave the data loggers running in another system, and come back to get them some time in the spring. I knew that the power consumption was only projecting out to about 45 days (with 15 minute sample intervals), so I had some real work to do if we were going to try a deployment of months!

I parked myself, and my little loggers, at a local restaurant where the internet connection actually worked, and the owner was friendly to researchers; despite the fact that they often spend their whole day glued to a laptop, when everyone else was out at the beach.  The waiters soon learned to ignore the guy in the corner with the laptop that had wires coming out of it…especially since he seemed to subsist on coffee alone.

I will just summarize a few notes from the daily progress journal here:

December 11th:

I examined the logger files from the 3 day test run, and there is more noise in the rubber end cap units data…I bet that’s from vortex shedding off the flat surface!

If we are going to leave these things running, they will eventually run out of power, so I need to protect the SD cards from brown out, or I risk all my data . I implemented low VCC cutoff in the code using the internal bandgap trick from this Arduino playground forum, but was left wondering if the one from Adafruit might work better?

Also posted to the Tiny circuits forum about the inconsistent behavior of the LED indicators. One unit blinks as expected when writing to the SD card. The other unit does not?  Also tried to implement a special “start up went ok” one time loop, but it did not go.
(Evidently the SD card attached to SPI bus as follows: MOSI – pin 11,MISO – pin 12, and CLK – pin 13 which is the same pin as the internal led…)

December 12th:

Yesterdays overnight tests worked fine in Unit1, giving approximately 30 readings per 16mv drop on VCC (with 6 cells) but Unit 2 showed the same drop in only 8 reads cycles. This is worse than the 3AA performance! Perhaps I have a bad cell in the powersupply? or just a bad solder joint that is letting one bank suck power from the other? Will run another overnight test tonight….

December 13th:

I duplicated the main loop data reads, with a second set of variables to cut the SD card access by ½. On an overnight run test, at one minute samples, this buffering of only one set of readings reduced the power drain by more than 50%, so obviously the SD card writing is the big achilles heel in the system.

And “Half your RAM will be taken up with the SD card’s 512 byte buffer, so you only have 512 bytes left to play with.” I need to concatenate those print statements into 512 byte strings?

I discovered that you can store constant unchanging things in the flash, like string literals.  But only if the function you are using them with supports it (which the SD card functions unfortunately don’t) – so anything with print or println with the contents in quotes can be “flashified”.

Found a snippet of code to monitor “Free memory”

December 14th:

Last days in the field now: I spent the most of the day doing multiple “elegant” for/while loops, with array variables, only to watch the free memory whittle down, cycle by cycle, bit by bit, till the “heap hit the stack” and the units start spewing junk characters faster than infinite number of monkeys….

Finally, that evening, I went back to the “dumb&simple” method. So I just copy/paste the entire block of data reading code again, and make a new set of variables for that loop. With three “buffer cycles” for each SD write cycle, its stable. But there is not enough ram to buffer 4 cycles though, so this will have to do.

December 15, 2013

Returning home after a day of fieldwork in a bug infested swamp.

Returning home after a day of fieldwork in a bug infested swamp.

From the overnight run tests: Even with the ram buffering Unit 2 it’s still drawing the power supply down three times as fast as Unit 1 with the same code? Grrr. Have to leave for fieldwork now.

Came back from field work at 8pm, but had to fix a Ph meter before I could check the run log. Unit 2 is still wonky, but our final deployment is tomorrow!  I just pulled it apart and replaced every board I had spares for. Will leave it running over night to see if that helps…

OMG! I popped a spare 128mb SD Sandisk card in for that last hour long test run after replacing the boards in unit 2, and even with read cycles every minute I saw only one 16mv drop on the power supply in over 60 readings! Those smaller size memory cards must draw way less power than the 2Gb Sandisk ones I had been using. Unit 2 is now set to run at least twice as long as Unit 1 – I might get 6 months or more out of it now. I wish I had discovered this months ago!

Last coding task of the day was to set the ChronoDots to wake the processor every 30 minutes. That’s a very long sampling cycle, but we may not be back down here for many months, so we are really stretching it out every way we can.

And talkin’ the talk…

Now that I think about it, that last bit of bloggy catharsis will probably be read to the end by maybe three people on the whole internet…if I include my mom. I’m sure the real coders felt a yawn coming on at the second line, and aside from the two other newbies out there at the “Just reading anything I can find.” stage, everyone else is probably thinking “Ok! Enough already… just gimme the code!”

So here you go. My first stable datalogger build* for a Tinyduino stack consisting of: a processor board, a BMA250 accelerometer sheild,  the microSD adapter, and a protoboard, jumpered to a chronodot RTC. The whole thing runs ‘unregulated’ off of 3 AA batteries, so I keep an eye on the bandgap voltage to (hopefully) stop data writes to the SD card when the battery voltage gets too low. But this part has not been tested yet, so don’t trust your life, or data for your thesis, to that kludge. Build yourself a real voltage divider!

*This scrapbook of code was cobbled together from the work of other people who actually know what they are doing, and my only real contribution was the hours I spent wading through forum threads collecting examples, before bolting this Frankenstein together.  So I take no credit for any of it, and provide no guarantees whatsoever that it wont brick your system the first time you run it. I also hope that anyone I’ve missed in the credits, forgives the accidental oversight, as some details get lost in the process of all that cutting and pasting.

// Date, Time and Alarm functions using a DS3231 chronodot RTC connected via I2C // and Wire library from https://github.com/MrAlvin/RTClib
// based largely on Jean-Claude Wippler from JeeLab’s https://github.com/jcw
// Clear alarm interupt code from http://forum.arduino.cc/index.php?topic=109062.0
// Get temp from http://forum.arduino.cc/index.php/topic,22301.0.html [which does not use the RTCLIB!]
// BMA250_I2C_Sketch.pde – from
// https://tiny-circuits.com/learn/using-the-accelerometer-tinyshield/
// which links to
// http://www.dsscircuits.com/accelerometer-bma250.html
// combined with internal voltage reading trick from:
// http://forum.arduino.cc/index.php/topic,15629.0.html
// floats to string conversion: http://dereenigne.org/arduino/arduino-float-to-string

//note: angle brackets which should be around library names are missing here due to formatting weirdness in WordPress

#include SD.h
#include Wire.h
#include SPI.h // not used here, but needed to prevent a RTClib compile error
#include avr/sleep.h
#include RTClib.h

#ifndef cbi //defs for stopping the ADC during sleep mode
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

#define DS3231_I2C_ADDRESS 104 //for the RTC temp reading function

#define BMA250 0x18
#define BW 0x08 //7.81Hz bandwith
#define GSEL 0x03 // set range 0x03 – 2g, 0x05 – 4, 0x08 – 8g, 0x0C – 16g
//#define DELAY 10000 is this line an orphan?

RTC_DS3231 RTC;
byte Alarmhour = 1;
byte Alarmminute = 1;
byte dummyRegister;
int INTERRUPT_PIN = 2;
volatile int state = LOW;
volatile boolean clockInterrupt = false;
int SampleInterval = 1;
// power-down time in minutes before interupt triggers next sample

byte tMSB, tLSB; //for the RTC temp reading function
float temp3231;

const int chipSelect = 10; //sd card chip select

uint8_t dataArray[16];
//variables for accellerometer reading
int8_t BMAtemp;
float BMAtempfloat;
int x,y,z;
String BMAdata; //for passing back data from bma read function
char TimeStampbuffer[ ]= “0000/00/00,00:00:00, “;

int ledpin = 13; //led indicator pin

void setup () {

pinMode(INTERRUPT_PIN, INPUT);
digitalWrite(INTERRUPT_PIN, HIGH);//pull up the interrupt pin
pinMode(13, OUTPUT); // initialize the LED pin as an output.
digitalWrite(13, HIGH); // turn the LED on to warn against SD card removal

Serial.begin(9600);
Wire.begin();
RTC.begin();
//RTC.adjust(DateTime(__DATE__, __TIME__));
//the above line set the time with code compile time – you only run this line ONCE!
clearClockTrigger(); //stops RTC from holding the interrupt low if system reset
// time for next alarm
DateTime now = RTC.now();
Alarmhour = now.hour();
Alarmminute = now.minute()+ SampleInterval ;
if (Alarmminute > 59) { //error catch – if Alarmminute=60 the interrupt never triggers due to rollover
Alarmminute = 0; Alarmhour = Alarmhour+1; if (Alarmhour > 23) {Alarmhour =0;}
}

initializeBMA(); //initialize the accelerometer

//get the SD card ready
pinMode(chipSelect, OUTPUT); //make sure that the default chip select pin is set to output, even if you don’t use it
Serial.print(“Initializing SD card…”);
if (!SD.begin(chipSelect)) { // see if the card is present and can be initialized:
Serial.println(“Card failed, or not present”); // don’t do anything more:
return;
}
Serial.println(“card initialized.”);
File dataFile = SD.open(“datalog.txt”, FILE_WRITE); //PRINT THE DATA FILE HEADER
if (dataFile) { // if the file is available, write to it:
dataFile.println(“YYYY/MM/DD, HH:MM:SS, Vcc(mV), X = , Y = , Z = , BMATemp (C) , RTC temp (C)”);
dataFile.close();
}
else { //if the file isn’t open, pop up an error:
Serial.println(“Error opening datalog.txt file!”);
}
}

void loop () {

if (clockInterrupt) {
clearClockTrigger();
}

//read in our data
BMAdata = String(“”); //clear out the datastring
read3AxisAcceleration(); //loads up the dataString
DateTime now = RTC.now(); // Read the time and date from the RTC
sprintf(TimeStampbuffer, “%04d/%02d/%02d,%02d:%02d:%02d,”, now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second());
Serial.println(“Timestamp Y/M/D, HH:MM:SS, Vcc = , X = , Y = , Z = , BMATemp (C) , RTC temp (C)”);
Serial.print(TimeStampbuffer); Serial.print(readVcc()); Serial.print(“,”);
Serial.print(BMAdata); Serial.print(“,”); Serial.println(get3231Temp());

//write data to the SD card
// note that only one file can be open at a time,so you have to close this one before opening another.
File dataFile = SD.open(“datalog.txt”, FILE_WRITE);

if (dataFile) { // if the file is available, write to it:
dataFile.print(TimeStampbuffer);dataFile.print(readVcc()); dataFile.print(“,”);
dataFile.print(BMAdata); dataFile.print(“,”); dataFile.println(get3231Temp());
dataFile.close();
}
else { //if the file isn’t open, pop up an error:
Serial.println(“Error opening datalog.txt file”);
}

// setNextAlarmTime();
Alarmhour = now.hour(); Alarmminute = now.minute()+SampleInterval;
if (Alarmminute > 59) { //error catch – if alarmminute=60 the interrupt never triggers due to rollover!
Alarmminute =0; Alarmhour = Alarmhour+1; if (Alarmhour > 23) {Alarmhour =0;}
}
RTC.setAlarm1Simple(Alarmhour, Alarmminute);
RTC.turnOnAlarm(1);

Serial.print(“Alarm Enabled at: “);
Serial.print(now.hour(), DEC); Serial.print(‘:’); Serial.println(now.minute(), DEC);
Serial.print(“Going to Sleep for “); Serial.print(SampleInterval);Serial.println(” minutes.”);
delay(100);
//a delay long enough to boot out the serial coms before sleeping.

sleepNow();

//Serial.println(“Alarm 1 has been Triggered!”);
}

void sleepNow() {
digitalWrite(13, LOW);
cbi(ADCSRA,ADEN); // Switch ADC OFF
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
attachInterrupt(0,clockTrigger, LOW);
sleep_mode();
//HERE AFTER WAKING UP
sleep_disable();
detachInterrupt(0);
sbi(ADCSRA,ADEN); // Switch ADC converter ON
pinMode(13, OUTPUT); digitalWrite(13, HIGH);
// turn the LED on to warn against SD card removal
// But I have some conflict between the SD chip select line, and the led – so the darned thing never lit!
}

void clockTrigger() {
clockInterrupt = true; //do something quick, flip a flag, and handle in loop();
}

void clearClockTrigger()
{
Wire.beginTransmission(0x68); //Tell devices on the bus we are talking to the DS3231
Wire.write(0x0F); //Tell the device which address we want to read or write
Wire.endTransmission(); //Before you can write to and clear the alarm flag you have to read the flag first!
Wire.requestFrom(0x68,1); // Read one byte
dummyRegister=Wire.read(); // In this example we are not interest in actually using the bye
Wire.beginTransmission(0x68); //Tell devices on the bus we are talking to the DS3231
Wire.write(0x0F); //Tell the device which address we want to read or write
Wire.write(0b00000000); //Write the byte. The last 0 bit resets Alarm 1
Wire.endTransmission();
clockInterrupt=false; //Finally clear the flag we used to indicate the trigger occurred
}

// could also use RTC.getTemperature() from the library here as in:
//RTC.convertTemperature(); //convert current temperature into registers
//Serial.print(RTC.getTemperature()); //read registers and display the temperature

float get3231Temp()
{
//temp registers (11h-12h) get updated automatically every 64s
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(0x11);
Wire.endTransmission();
Wire.requestFrom(DS3231_I2C_ADDRESS, 2);

if(Wire.available()) {
tMSB = Wire.read(); //2’s complement int portion
tLSB = Wire.read(); //fraction portion

temp3231 = ((((short)tMSB << 8 | (short)tLSB) >> 6) / 4.0); // Allows for readings below freezing – Thanks to Coding Badly
//temp3231 = (temp3231 * 1.8 + 32.0); // Convert Celcius to Fahrenheit
return temp3231;

}
else {
temp3231 = 255.0; //Use a value of 255 to error flag that we did not get temp data from the ds3231
}

return temp3231;
}

byte read3AxisAcceleration()
{
Wire.beginTransmission(BMA250);
Wire.write(0x02);
Wire.endTransmission();
Wire.requestFrom(BMA250,7);
for(int i = 0; i < 7;i++)
{
dataArray[i] = Wire.read();
}
if(!bitRead(dataArray[0],0)){return(0);}

BMAtemp = dataArray[6];
x = dataArray[1] << 8; x |= dataArray[0]; x >>= 6;
y = dataArray[3] << 8; y |= dataArray[2]; y >>= 6;
z = dataArray[5] << 8; z |= dataArray[4]; z >>= 6;

BMAdata += String(x);
BMAdata += “,”;
BMAdata += String(y);
BMAdata += “,”;
BMAdata += String(z);
BMAdata += “,”;
BMAtempfloat = (BMAtemp*0.5)+24.0;
// add digits of BMAtempfloat value to datastring
BMAdata += ((int)BMAtempfloat);
BMAdata += “.”;
int temp = (BMAtempfloat – (int)BMAtempfloat) * 100;
BMAdata += (abs(temp));
//the following 2 lines also to convert float to string
//dtostrf(floatVariable2convert, minStringWidthIncDecimalPoint, numVarsAfterDecimal, charBuffer);
//for example: dtostrf(BMAtempfloat, 5, 2, dtostrfbuffer); dataString += dtostrfbuffer;
}

byte initializeBMA()
{
Wire.beginTransmission(BMA250);
Wire.write(0x0F); //set g
Wire.write(GSEL);
Wire.endTransmission();
Wire.beginTransmission(BMA250);
Wire.write(0x10); //set bandwith
Wire.write(BW);
Wire.endTransmission();
return(0);
}

long readVcc() { //trick to read the Vin using internal 1.1 v as a refrence
long result;
// Read 1.1V reference against AVcc
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
delay(2); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Convert
while (bit_is_set(ADCSRA,ADSC));
result = ADCL;
result |= ADCH<<8;
result = 1126400L / result; // Back-calculate AVcc in mV
return result;
}