I'm working on a datalogger to track the movements of birds and I am looking for some guidance. I am able to sample at 50Hz for 18hrs and I would really like to extend the battery beyond 24hrs. I am using a 350mAh battery because weight is a factor, but I could go slightly bigger. Is there anything I could do from a programming standpoint to reduce power consumption? I am using an Adafruit Featherlogger M0 with a LSM9DS0 sensor.
/*
Connections (USES SPI)
Note: M0 to 9DS0
Connect Pin 24 to SCL
Connect Pin 22 to SDOG and SDOXM (MISO)
Connect Pin 23 to SDA (MOSI)
Connect Pin 10 to CSXM
Connect Pin 09 to CSG
Connect 3V to 3V3 (could also go to VIN)
Connect GND to GND
*/
#include <RTCZero.h>
#include <SPI.h>
#include <SdFat.h>
SdFat SD;
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_LSM9DS0.h>
#define LSM9DS0_XM_CS 10
#define LSM9DS0_GYRO_CS 9
//Hardware SPI (Creates a unique Sensor ID)
Adafruit_LSM9DS0 lsm = Adafruit_LSM9DS0(LSM9DS0_XM_CS, LSM9DS0_GYRO_CS, 1000);
#define cardSelect 4 // Set the pin for uSD
#define RED 13 // Red LED Pin #13
#define GREEN 8 // Green LED Pin #8
#define VBATPIN A7 // Bat Volt Pin A7
// Number of samples to buffer before flush called.
#define SamplesPerCycle 10000
// Number of lines of data per file
#define SamplesPerFile 60000
byte hours = 1;
byte minutes = 1;
byte seconds = 1;
byte day = 1;
byte month = 1;
byte year = 17;
// Variable used to keep track of changes in seconds, minutes, hours, days, months
byte timekeeper = 0;
// delay to adjust sampling rate
// 20ms = ~30Hz
// 11ms = ~50Hz
// 0ms = ~100HZ
byte samplingRateDelay = 11;
RTCZero rtc;
File logfile;
File settingsFile;
char filename[16]; // Array for file name data logged to named in setup
char settingsFilename[15]; // Array for file name of Settings File to log settings of Deployment
float measuredvbat; // Variable for battery voltage
unsigned int CurrentCycleCount; // Num of samples in current cycle, before uSD flush call
unsigned int CurrentFileCount; // Num of samples in current file
unsigned long milli; //used to store the milliseconds since the program started
void setup() {
// Setup RTC and set time
rtc.begin();
rtc.setTime(hours, minutes, seconds);
rtc.setDate(day, month, year);
strcpy(filename, "ANALOG000.CSV");
strcpy(settingsFilename, "InitVal00.TXT");
/* Initialise the sensor */
if(!lsm.begin())
{
while(1);
}
lsm.setupAccel(lsm.LSM9DS0_ACCELRANGE_2G);
lsm.setupMag(lsm.LSM9DS0_MAGGAIN_2GAUSS);
lsm.setupGyro(lsm.LSM9DS0_GYROSCALE_245DPS);
CreateSettingsFile();
CreateFile();
}
void loop() {
CurrentCycleCount += 1; // Increment samples in current uSD flush cycle
CurrentFileCount += 1; // Increment samples in current file
WriteToSD(); // Output to uSD card stream
// Code to limit the number writes to the uSD
if( CurrentCycleCount >= SamplesPerCycle ) {
logfile.flush(); //is this power hungry?
CurrentCycleCount = 0;
}
// Code to increment files limiting number of lines in each
if( CurrentFileCount >= SamplesPerFile ) {
if (logfile.isOpen()) {
logfile.close();
}
CreateFile();
CurrentFileCount = 0;
}
}
//capture sensor settings, sampling rate, associated log files and battery status
void CreateSettingsFile(void)
{
if (!SD.begin(cardSelect)) {
error(2); // 2 red flashes means no card or init failed.
}
//increments the value of the ## in filename (Max is 99)
for (uint8_t i = 0; i < 100; i++) {
settingsFilename[7] = '0' + i/10;
settingsFilename[8] = '0' + i%10;
if (! SD.exists(settingsFilename)) {
break;
}
}
settingsFile = SD.open(settingsFilename, FILE_WRITE);
writeDeploymentDetails();
if( ! settingsFile ) {
error(3);
}
settingsFile.close();
}
// Create new Log file
void CreateFile()
{
if (!SD.begin(cardSelect)) {
error(2); // 2 red flashes means no card or init failed.
}
//increments the value of the ### in filename (Max is 999)
for (uint8_t i = 0; i < 1000; i++) {
filename[6] = '0' + i/100;
filename[7] = '0' + (i%100)/10;
filename[8] = '0' + i%10;
if (! SD.exists(filename)) {
break;
}
}
//log the newly created file name to the settings file
settingsFile = SD.open(settingsFilename, FILE_WRITE);
settingsFile.print(filename);
// Was giving 5V bat voltage, not sure why
settingsFile.print(" Battery Voltage: "); settingsFile.println(BatteryVoltage ());
settingsFile.close();
delay(10);
logfile = SD.open(filename, FILE_WRITE);
writeHeader();
if( ! logfile ) {
error(3);
}
}
// Write data header to file of uSD.
void writeHeader() {
logfile.println("YYYY-MM-DD hh:mm:ss,Timestamp(Ms),ACCELX,ACCELY,ACCELZ,MAGX,MAGY,MAGZ,GYRX,GYRY,GYRZ,TEMP");
}
// Print data and time followed by battery voltage to SD card
void WriteToSD() {
sensors_event_t accel, mag, gyro, temp;
lsm.getEvent(&accel, &mag, &gyro, &temp);
// Formatting for file output yyyy-mm-dd hh:mm:ss
timekeeper = rtc.getSeconds();
if(seconds != timekeeper) {
seconds = timekeeper;
timekeeper = rtc.getMinutes();
if(minutes != timekeeper){
minutes = timekeeper;
blink(RED,3);
timekeeper = rtc.getHours();
if(hours != timekeeper){
hours = timekeeper;
timekeeper = rtc.getDay();
if(day != timekeeper){
day = timekeeper;
timekeeper = rtc.getMonth();
if(month != timekeeper){
month = timekeeper;
}
}
}
}
}
//How do I get all this to happen in fewer print calls
//Is a StringBuffer a better option?
logfile.print("20");
logfile.print(year);
logfile.print("-");
logfile.print(month);
logfile.print("-");
logfile.print(day);
logfile.print(" ");
logfile.print(hours);
logfile.print(":");
if(minutes < 10)
logfile.print('0');
logfile.print(minutes);
logfile.print(":");
if(seconds < 10)
logfile.print('0');
logfile.print(seconds); logfile.print(",");
// sensor timestamp
logfile.print(accel.timestamp); logfile.print(",");
// print accelleration data to the log file:
logfile.print(accel.acceleration.x); logfile.print(",");
logfile.print(accel.acceleration.y); logfile.print(",");
logfile.print(accel.acceleration.z); logfile.print(",");
// print magnetometer data to the log file:
logfile.print(mag.magnetic.x); logfile.print(",");
logfile.print(mag.magnetic.y); logfile.print(",");
logfile.print(mag.magnetic.z); logfile.print(",");
// print gyroscopic data to the log file:
logfile.print(gyro.gyro.x); logfile.print(",");
logfile.print(gyro.gyro.y); logfile.print(",");
logfile.print(gyro.gyro.z); logfile.print(",");
// print temperature data
logfile.println(temp.temperature);
delay(samplingRateDelay);
}
// blink out an error code
void error(uint8_t errno) {
while(1) {
uint8_t i;
for (i=0; i<errno; i++) {
digitalWrite(13, HIGH);
delay(100);
digitalWrite(13, LOW);
delay(100);
}
for (i=errno; i<10; i++) {
delay(200);
}
}
}
// blink out an error code, Red on pin #13 or Green on pin #8
void blink(uint8_t LED, uint8_t flashes) {
uint8_t i;
for (i=0; i<flashes; i++) {
digitalWrite(LED, HIGH);
delay(100);
digitalWrite(LED, LOW);
delay(100);
}
}
// Measure battery voltage using divider on Feather M0
float BatteryVoltage () {
measuredvbat = analogRead(VBATPIN); //Measure the battery voltage at pin A7
measuredvbat *= 2; // we divided by 2, so multiply back
measuredvbat *= 3.3; // Multiply by 3.3V, our reference voltage
measuredvbat /= 1024; // convert to voltage
return measuredvbat;
}
// Writes to a TXT file about the setting
void writeDeploymentDetails(void)
{
settingsFile.print("Init. Time: ");
settingsFile.print("20");
settingsFile.print(year);
settingsFile.print("/");
settingsFile.print(month);
settingsFile.print("/");
settingsFile.print(day);
settingsFile.print(" ");
settingsFile.print(hours);
settingsFile.print(":");
if(minutes < 10)
settingsFile.print('0');
settingsFile.print(minutes);
settingsFile.print(":");
if(seconds < 10)
settingsFile.print('0');
settingsFile.println(seconds);
settingsFile.print("Sampling Rate Delay: ");
settingsFile.println(samplingRateDelay);
settingsFile.print("Num of Samples before Flush: ");
settingsFile.println(SamplesPerCycle);
settingsFile.print("Num of Samples per CSV: ");
settingsFile.println(SamplesPerFile);
settingsFile.println(F("Log Files and Bat.Volt:"));
}
Any thoughts or guidance would be greatly appreciated.