I am using your assembled data logging shield on 10 weather stations and am having some idiosyncratic issues. I am connecting them to the Sparkfun Arduino Pro 5v. For two months during summer 2014, they worked great. This year, 5 out of 10 do not log any data.
Any help or advice would be helpful!
FYI: New SD cards were purchase at the beginning of June and they have all been formatted using Fat 32.
Below are the problems (summarized for the most recent 10 day measurement cycle):
[*] 2 out of 10 don't don't create any logger files. The SD led flashes slowly and consistently in Red.
[*] 1/10 created a file but only logged data for 5 out of 10 days. The SD led flashes fast and consistent in red.
[*] 1/10 created 99 blank logger files but no LEDs were flashing.
[*]3/10 didn't log any files but no led's were blinking.
[*]2/10 do not maintain the correct date. Nearly all shields required multiple upload cycles to get the data correct. (Batteries were removed for several minutes in between each upload).
[*]1/10 is working great.
The setup is as follows:
[*]Arduino Pro 5v
[*]Adafruit Datalogger shield
[*]Large solar panel, Powerboost 500, LiPo charger, 2500 mah LiPo batteries (All from Adafruit)
[*]SHT-15/45 temp/humidity sensor
[*]2 thermistors
[*]Watermark 200ss soil moisture senor
[*][New this year]Fascinating electronics anemometer
[*][New this year]A diode for solar radiation. http://www.instesre.org/construction/py ... ometer.htm
[*][*]The Adafruit ADS1115 breakout board to increase the resolution of the diode above.
Code: Select all
//--------Libraries---------------------------------------------------------
#include <Sensirion.h> // Interpret output from Sensiron SHT sensors
#include <SPI.h> // ???
#include <SD.h> // Communicate with the SD card and datalogger shield
#include <RTClib.h> // Communicate with the real time clock
#include <Wire.h> // i2c functions
#include <Narcoleptic.h> // low-power sleep routine
#include <Adafruit_ADS1015.h> //16-bit gain amplifier for pyranometer
//---------Commonly changed parameters----------------------------------------
const int n_avg = 10; //Number of samples to average at each time
// ------- Declare Variables ---------------------------------------------------
//Sleeptime
// low-power sleep counter (1 * 8sec = 8 sec)
const int sleepint = 7; // low-power sleep counter (7 * 8sec = 56 sec)
//Real Time Clock (RTC)
DateTime now;
uint32_t m; // how many milliseconds between grabbing data and logging it. 1000 ms is once a second
//#define LOG_INTERVAL interval // mills between entries (reduce to take more/faster data)
#define ECHO_TO_SERIAL 0 // echo data to serial port
//Adafruit Datalogger Shield
// the logging file
File logfile;
//Pyranometer
Adafruit_ADS1115 ads1115;
float DtoA;
const byte gain = 16;
float adc0; //,adc1,adc2,adc3; //analog to digital variable
// Anemometer Stuff
volatile long rpsTops;
float rps;
float mph;
volatile unsigned long anem_now;
volatile unsigned long anem_later;
volatile float deltatime;
volatile unsigned long last_micros;
//SHT-75 Temperature/Humidity sensor
uint16_t rawData;
float sht_temp;
float sht_humid;
float sht_dewpt;
//Thermistors (NTCLE100E3-->Brown-Black-Orange)
float therm_avg1;
float therm_avg2;
const int therm_nominal = 10000; // resistance at 25 degrees C
const int temp_nominal = 25; // temp. for nominal resistance (almost always 25 C)
const int b_coef = 3977; // The beta coefficient of the thermistor (usually 3000-4000)
const int series_resistor = 10000; // the value of the 'other' resistor
//Watermark 200ss soil moisture sensor
int mV; // single mV value
int ADval; // single ADC value
int ADvalp1[n_avg]; // array of ADC values, polarity 1
int ADvalp2[n_avg]; // array of ADC values, polarity 2
int ADval1; // average ADC value for polarity 1
int ADval2; // average ADC value for polarity 2
long R1; // resistance for first polarity
long R2; // resistance for reverse polarity
long R2a; // intermediate value in R calcualtion
float Rwm; // final resistance of Watermark
const long R_ref_wm = 10000; // 10k fixed resistor value for Watermark half bridge
const long ADCmax = 1024;
long Vcc; // supply/Aref voltage read with secret voltmeter
float kPa; // array to hold Watermark potentials
float kPa1; // intermediate values in kPa calculation
float kPa2;
//Voltage measurement
const int band_gap_ref = 14; // special indicator that we want to measure the bandgap
const int aref_voltage = 5; // we tie 3.3V to ARef and measure it with a multimeter!
const int bandgap_voltage = 1.1; // this is not super guaranteed but its not -too- off
float supplyvoltage;
// ------- Declare Pins --------------------------------------------------------
//Thermistors
#define therm_pin1 A0 //Soil temperature thermistor
#define therm_pin2 A1 //Litter temperature thermistor
//Watermark 200ss sensor
const int wm_p1 = 5; // AC half bridge - Watermark 200ss leg
const int wm_p2 = 4; // AC half bridge - 10k leg
const int wm_pin = A2; // Watermark 200ss output from AC half bridge
//SHT-75 Temperature/Humidity Sensor
const uint8_t dataPin = 9; // SHT serial data
const uint8_t sclkPin = 8; // SHT serial clock
const uint8_t ledPin = 13; // Arduino built-in LED
const uint8_t sht_pwr = 2;
// Anemometer
const byte rpssensor = 3;
//Datalogger Shield
const int dlogger_pin = 10;
//LEDs
#define redLEDpin 2
#define greenLEDpin 3
//Initialize sensor library objects
Sensirion sht = Sensirion(dataPin, sclkPin); // define the sensiron object
RTC_DS1307 RTC; // define the Real Time Clock object
// --------------------- Setup -------------------------------------------------
void setup(void)
{
delay(15); // Wait 15 ms before first cmd
Wire.begin(); // enable i2c bus
ads1115.begin();
Serial.print("Gain setting = ");
switch(gain) {
case 1: {ads1115.setGain(GAIN_ONE); DtoA=4.096/32768;
Serial.println("GAIN_ONE"); break;}
case 2: {ads1115.setGain(GAIN_TWO); DtoA=2.048/32768;
Serial.println("GAIN_TWO"); break;}
case 3: {ads1115.setGain(GAIN_TWOTHIRDS); DtoA=6.144/32768;
Serial.println("GAIN_TWOTHIRDS"); break;}
case 4: {ads1115.setGain(GAIN_FOUR); DtoA=1.024/32768;
Serial.println("GAIN_FOUR"); break;}
case 8: {ads1115.setGain(GAIN_EIGHT); DtoA=0.512/32768;
Serial.println("GAIN_EIGHT"); break;}
case 16: {ads1115.setGain(GAIN_SIXTEEN); DtoA=0.256/32768;
Serial.println("GAIN_SIXTEEN"); break;}
default: {Serial.println("Oops... no such gain setting!"); return; }
}
Serial.print("DtoA = ");Serial.println(DtoA,8);
initializeSD();
RTC.begin();
//RTC.adjust(DateTime(__DATE__, __TIME__));
if (! RTC.isrunning()) {
Serial.println("RTC is NOT running!");
// following line sets the RTC to the date & time this sketch was compiled
RTC.adjust(DateTime(__DATE__, __TIME__));
}
analogReference(DEFAULT); // use default (3.3v supply) ADC Vref
pinMode(wm_p1, OUTPUT); // make pins for AC half bridge an output
pinMode(wm_p2, OUTPUT);
pinMode(dlogger_pin, OUTPUT);
pinMode(sht_pwr, OUTPUT);
pinMode(rpssensor, INPUT_PULLUP);
// use debugging LEDs
pinMode(redLEDpin, OUTPUT);
pinMode(greenLEDpin, OUTPUT);
delay(15);
}
// -------------------------------- Main Loop ----------------------------------
void loop(void) // main program
{
readRTC(); // read RTC
//if(now.minute() == 0 || now.minute() == 2 || now.minute() == 6 || now.minute() == 6 || now.minute() == 8|| now.minute() == 10|| now.minute() == 12|| now.minute() == 14|| now.minute() == 16|| now.minute() == 18|| now.minute() == 20|| now.minute() == 22|| now.minute() == 24|| now.minute() == 26|| now.minute() == 28|| now.minute() == 30|| now.minute() == 32|| now.minute() == 34|| now.minute() == 36|| now.minute() == 38|| now.minute() == 40|| now.minute() == 42|| now.minute() == 44|| now.minute() == 46|| now.minute() == 48|| now.minute() == 50|| now.minute() == 52|| now.minute() == 54|| now.minute() == 56|| now.minute() == 58)
//if(now.minute() == 0 || now.minute() == 30) // take measurements every 30 minutes
//if(now.second() == 0 || now.second() == 10 || now.second() == 20 || now.second() == 30 || now.second() == 40 || now.second() == 50)
// Doesn't work unless sleep is < 10 sec--take measurements every 10 seconds
// take measurements every 15 minutes
if(now.minute() == 0 || now.minute() == 15 || now.minute() == 30 || now.minute() == 45)
{
readpyrano();
therm_avg1 = readThermistor(therm_pin1);
therm_avg2 = readThermistor(therm_pin2);
readSHT75();
readWM(); // read Watermark
readVcc();
rpsTops = 0; //Set NbTops to 0 ready for calculations
anem_now=micros();
attachInterrupt(1, readrps, FALLING);
delay(2000); //counts for the duration specified
detachInterrupt(1);
anem_later=micros();
deltatime=((float)anem_later- (float)anem_now)/1000000;
rps = (rpsTops)/deltatime;
mph = 1.758*(rps)+2.121;
//PrintToSerial(); // print to screen
LogToRam();
writetodisk();
sleepytime();
}
sleepytime();
}
// =============================== End Main Loop ================================
// ****************************** Subroutines ***********************************
//---------- low-power sleep -----------------------------------------------------------
void sleepytime() // based on Narcoleptic library routine
{
//ADCSRA = 0; // disable ADC
for(byte i=1; i<=sleepint; i++) // loop through several times
{
Narcoleptic.delay(8000); // maximium sleep for ATmega328 is 8 sec
}
//ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADEN); // set prescaler to 128 and enable ADC
}
void PrintToSerial()
{
#if ECHO_TO_SERIAL
Serial.print(m); // milliseconds since start
Serial.print(", ");
Serial.print(now.unixtime()); // seconds since 1/1/1970
Serial.print(", ");
Serial.print('"');
Serial.print(now.year(), DEC);
Serial.print("/");
Serial.print(now.month(), DEC);
Serial.print("/");
Serial.print(now.day(), DEC);
Serial.print(" ");
Serial.print(now.hour(), DEC);
Serial.print(":");
Serial.print(now.minute(), DEC);
Serial.print(":");
Serial.print(now.second(), DEC);
Serial.print('"');
Serial.print(", ");
Serial.print(adc0,8);
Serial.print(", ");
Serial.print(therm_avg1);
Serial.print(", ");
Serial.print(therm_avg2);
Serial.print(", ");
Serial.print(sht_temp);
Serial.print(", ");
Serial.print(sht_humid);
Serial.print(", ");
Serial.print(sht_dewpt);
Serial.print(", ");
Serial.print(kPa,DEC);
Serial.print(", ");
Serial.print(rpsTops);
Serial.print(", ");
Serial.print(deltatime);
Serial.print(", ");
Serial.print(rps);
Serial.print(", ");
Serial.print(mph);
//Serial.print(", ");
//Serial.print(supplyvoltage);
Serial.print(", ");
Serial.println(Vcc);
#endif //ECHO_TO_SERIAL
}
void initializeSD()
{
#if WAIT_TO_START
Serial.println("Type any character to start");
while (!Serial.available());
#endif //WAIT_TO_START
// initialize the SD card
Serial.print("Initializing SD card...");
// make sure that the default chip select pin is set to
// output, even if you don't use it:
pinMode(dlogger_pin, OUTPUT);
// see if the card is present and can be initialized:
if (!SD.begin(dlogger_pin)) {
error("Card failed, or not present");
}
Serial.println("card initialized.");
// create a new file
char filename[] = "LOGGER00.CSV";
for (byte i = 0; i < 100; i++) {
filename[6] = i/10 + '0';
filename[7] = i%10 + '0';
if (! SD.exists(filename)) {
// only open a new file if it doesn't exist
logfile = SD.open(filename, FILE_WRITE);
break; // leave the loop!
}
}
if (! logfile) {
error("couldnt create file");
}
Serial.print("Logging to: ");
Serial.println(filename);
// connect to RTC
if (!RTC.begin()) {
logfile.println("RTC failed");
#if ECHO_TO_SERIAL
Serial.println("RTC failed");
#endif //ECHO_TO_SERIAL
}
logfile.println("millis,stamp,datetime,sol_rad_vlt,therm_avg1,therm_avg2,sht_temp,sht_humid,sht_dewpt,wm200ss_kPa,rpsTops,delta_time,rps,mph,supplyvoltage");
#if ECHO_TO_SERIAL
Serial.println("millis,stamp,datetime,sol_rad_vlt,therm_avg1,therm_avg2,sht_temp,sht_humid,sht_dewpt,wm200ss_kPa,rpsTops,delta_time,rps,mph,supplyvoltage");
#endif //ECHO_TO_SERIAL
}
void LogToRam()
{
// milliseconds since start
logfile.print(m);
logfile.print(", ");
// log time
logfile.print(now.unixtime()); // seconds since 1/1/1970
logfile.print(", ");
logfile.print('"');
logfile.print(now.year(), DEC);
logfile.print("/");
logfile.print(now.month(), DEC);
logfile.print("/");
logfile.print(now.day(), DEC);
logfile.print(" ");
logfile.print(now.hour(), DEC);
logfile.print(":");
logfile.print(now.minute(), DEC);
logfile.print(":");
logfile.print(now.second(), DEC);
logfile.print('"');
logfile.print(", ");
logfile.print(adc0,8);
logfile.print(", ");
logfile.print(therm_avg1);
logfile.print(", ");
logfile.print(therm_avg2);
logfile.print(", ");
logfile.print(sht_temp);
logfile.print(", ");
logfile.print(sht_humid);
logfile.print(", ");
logfile.print(sht_dewpt);
logfile.print(", ");
logfile.print(kPa,DEC);
logfile.print(", ");
logfile.print(rpsTops);
logfile.print(", ");
logfile.print(deltatime);
logfile.print(", ");
logfile.print(rps);
logfile.print(", ");
logfile.print(mph);
logfile.print(", ");
//logfile.print(supplyvoltage);
//logfile.print(", ");
logfile.println(Vcc);
}
void writetodisk()
{
// Now we write data to disk! Don't sync too often - requires 2048 bytes of I/O to SD card
// which uses a bunch of power and takes time
//if ((millis() - syncTime) < SYNC_INTERVAL) return;
//syncTime = millis();
// blink LED to show we are syncing data to the card & updating FAT!
digitalWrite(redLEDpin, HIGH);
//logfile.close();
logfile.flush();
digitalWrite(redLEDpin, LOW);
}
void readRTC()
{
m = millis(); // log milliseconds since starting
now = RTC.now(); // fetch the time
}
void readpyrano()
{
byte i;
int16_t avg_reading;
int16_t samples[n_avg];
// take N samples in a row, with a slight delay
for (i=0; i< n_avg; i++) {
samples[i] = ads1115.readADC_SingleEnded(0);
delay(50);
}
// average all the samples out
avg_reading = 0;
for (i=0; i< n_avg; i++) {
avg_reading += samples[i];
}
avg_reading /= n_avg;
adc0=avg_reading*DtoA;
}
//// This is the function that interrupt calls to measure rps
void readrps () {
if((long)(micros() - last_micros) >= 15 * 1000) {
// debounce of REED contact. With 15ms speed more than 150 km/h can be measured
rpsTops++;
last_micros = micros();
}
}
void readWM()
{
byte i;
readVcc();
// read supply/ADC ref voltage
int AChb = wm_pin; // set ADC channel
for(i=1; i<=n_avg; i++) // take n_avg readings with each polarity
{
digitalWrite(wm_p1,HIGH); // set 1st polarity
digitalWrite(wm_p2,LOW);
delay(15);
ADvalp1[i] = analogRead(AChb); // read voltage at voltage divider
delay(15);
digitalWrite(wm_p1,LOW); // switch polarity
digitalWrite(wm_p2,HIGH);
delay(15);
ADvalp2[i] = analogRead(AChb); // read voltage
delay(15);
}
digitalWrite(wm_p2,LOW); // turn off voltage to Watermarks
ADval1 = 0; // initialize totals
ADval2 = 0;
for(i=2; i<=n_avg; i++) // skip first reading
{
ADval1 = ADval1 + ADvalp1[i]; // total last (n_avg-1) readings
ADval2 = ADval2 + ADvalp2[i];
}
ADval1 /= (n_avg-1); // calculate average at 1st polarity
ADval2 /= (n_avg-1); // calculate average at 2nd polarity
R1 = R_ref_wm * ADCmax / long(ADval1) - R_ref_wm; // calculate Rwm under first polarity
R2a = ADCmax*1000L / long(ADval2) - 1000L; // calculate Rwm under reverse polarity
R2 = R_ref_wm*1000L / R2a;
Rwm = (R1 + R2) / 2.0; // calculate average to get final Rwm
if(Rwm > 30800) Rwm = 30800; // check for out-of-range value
kPa1 = 4.093 + Rwm*3.213 / 1000.0; // apply Schock calibration equation
kPa2 = 1.0 - 0.009733*Rwm / 1000.0 - 0.01205 * 24.0;
kPa = kPa1 / kPa2;
if(kPa < 0) // check for out-of-range readings
{
kPa = 254;
}
else if(kPa > 250)
{
kPa = 250;
}
}
void readSHT75()
{
digitalWrite(sht_pwr, HIGH);
delay(15);
sht.measTemp(&rawData); // sht.meas(TEMP, &rawData, BLOCK)
sht_temp = sht.calcTemp(rawData);
sht.measHumi(&rawData); // sht.meas(HUMI, &rawData, BLOCK)
sht_humid = sht.calcHumi(rawData, sht_temp);
sht_dewpt = sht.calcDewpoint(sht_humid, sht_temp);
digitalWrite(sht_pwr, LOW);
}
float readThermistor(int THERMISTORPIN)
{
byte i;
float avg_reading;
int samples[n_avg];
// take N samples in a row, with a slight delay
for (i=0; i< n_avg; i++) {
samples[i] = analogRead(THERMISTORPIN);
delay(15);
}
// average all the samples out
avg_reading = 0;
for (i=0; i< n_avg; i++) {
avg_reading += samples[i];
}
avg_reading /= n_avg;
avg_reading = 1023 / avg_reading - 1; // convert the value to resistance
avg_reading = series_resistor / avg_reading;
float steinhart;
steinhart = avg_reading / therm_nominal; // (R/Ro)
steinhart = log(steinhart); // ln(R/Ro)
steinhart /= b_coef; // 1/B * ln(R/Ro)
steinhart += 1.0 / (temp_nominal + 273.15); // + (1/To)
steinhart = 1.0 / steinhart; // Invert
steinhart -= 273.15; // convert to C
return(steinhart);
}
//--------- secret voltmeter -----------------------------------------------------------
void readVcc() // using internal ATmega328 voltage
{ // read internal 1.1V ref against Vcc
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
delay(31); // wait for Vref to settle
ADCSRA |= _BV(ADSC); // convert to mV
while (bit_is_set(ADCSRA,ADSC));
Vcc = ADCL;
Vcc |= ADCH<<8;
Vcc = 1126400L / Vcc; // back-calculate Vcc in mV
}
void error(char *str)
{
Serial.print("error: ");
Serial.println(str);
// red LED indicates error
digitalWrite(redLEDpin, HIGH);
while(1);
}