4

During the last two months I have been working on a project that consists of using a Seeeduino Stalker V2.3, two AM2305 sensors, a TSL2561 sensor, an HC-05 XBee module, a 1,800 mAh 3.7V LiPo, a 7 cm x 7 cm 5V solar cell, and a waterproof suction box, to assemble a portable and waterproof environmental data logger that can be used to take samples on a continuous basis (1 sample every 30 minutes, 48 samples per day).

After struggling to make my logger work, I finally did it last week. It all runs fine, except that the intervals between readings are incorrect. When I program my board to store samples every 30 minutes (1,800,000), it takes them every 30 minutes and some extra seconds. When I try the same but with a rate of 1 sample every 10 seconds, my device logs data every 13 seconds more or less...

Here is the code I have been using:

#include "SPI.h"
#include "Wire.h"
#include "SD.h"
#include "DS3231.h"**

DS3231 clock;
RTCDateTime dt;

#include "DHT.h"

#define DHTPIN 8
#define DHTTYPE DHT21
DHT dht1(DHTPIN, DHTTYPE);
#define DHTPIN2 7
DHT dht2(DHTPIN2, DHTTYPE);
#include "TSL2561.h"
TSL2561 tsl(TSL2561_ADDR_FLOAT);

const int chipSelect = 10;
int XBEE = 5;
int FLASH = 4;

void setup() {
  pinMode(5, OUTPUT);
  digitalWrite(XBEE, HIGH);
  Serial.begin(9600);
  Wire.begin();
  clock.begin();
  analogReference(INTERNAL);
  pinMode(10, OUTPUT);
  pinMode(4, INPUT);
  SD.begin(10);
  dht1.begin();
  dht2.begin();
  Serial.println("EcoLOGGER DE PRUEBA PARA GENERACION DE DATOS ...");
  Serial.println(" ");
  delay(3000);
  Serial.println("RECUERDA QUE ESTE PROYECTO NO HUBIERA SIDO POSIBLE SIN LA AYUDA DE LA COMUNIDAD ARDUINO...");
  Serial.println(" ");
  delay(3000);
}

int counter = 0;

void loop() {
  float h = dht1.readHumidity();
  float t = dht1.readTemperature();
  float f = dht1.readTemperature(true);
  float h2 = dht2.readHumidity();
  float t2 = dht2.readTemperature();
  float f2 = dht2.readTemperature(true);
  dt = clock.getDateTime();
  if (tsl.begin()) {
  } else {
    while (1);
  }
  tsl.setGain(TSL2561_GAIN_0X);
  tsl.setTiming(TSL2561_INTEGRATIONTIME_402MS);
  uint16_t x = tsl.getLuminosity(TSL2561_FULLSPECTRUM);
  uint32_t lum = tsl.getFullLuminosity();
  uint16_t ir, full;
  ir = lum >> 16;
  full = lum & 0xFFFF;
  float vis = full-ir;
  Serial.print("Muestreo: ");
  Serial.println(counter);
  Serial.print("Fecha: ");
  Serial.print(dt.day);
  Serial.print('/');
  Serial.print(dt.month);
  Serial.print('/');
  Serial.println(dt.year);
  Serial.print("Hora: ");
  Serial.print(dt.hour);
  Serial.print(':');
  Serial.print(dt.minute);
  Serial.print(':');
  Serial.println(dt.second);
  Serial.print("Temperatura sistema: ");
  Serial.print(clock.readTemperature());
  Serial.println("*C ");
  Serial.print("Voltaje bateria: ");
  Serial.print(analogRead(A7) * (1.1 / 1024)* (10+2)/2);
  Serial.println(" V ");
  Serial.print("Carga bateria: ");
  Serial.print(-149.4 + 59.52 * (analogRead(A7) * (1.1 / 1024)* (10+2)/2));
  Serial.println("% ");
  Serial.print("Luz FULL: ");
  Serial.println(full);
  Serial.print("Temperatura ambiente: ");
  Serial.print(t);
  Serial.println(" *C ");
  Serial.print("Humedad relativa: ");
  Serial.print(h);
  Serial.println("%");
  Serial.print("Temperatura suelo: ");
  Serial.print(t2);
  Serial.println(" *C ");
  Serial.print("Humedad suelo: ");
  Serial.print(h2);
  Serial.println("%");
  Serial.println(" ");
  digitalWrite (FLASH, HIGH);
  File dataFile = SD.open("datalog.txt", FILE_WRITE);
  if (dataFile) {
    dataFile.print(" Muestreo: ");
    dataFile.print(counter);
    dataFile.print(",");
    dataFile.print(" Fecha: ");
    dataFile.print(dt.day);
    dataFile.print('/');
    dataFile.print(dt.month);
    dataFile.print('/');
    dataFile.print(dt.year);
    dataFile.print(",");
    dataFile.print(" Hora: ");
    dataFile.print(dt.hour);
    dataFile.print(':');
    dataFile.print(dt.minute);
    dataFile.print(':');
    dataFile.print(dt.second);
    dataFile.print(",");
    dataFile.print(" Temperatura sistema: ");
    dataFile.print(clock.readTemperature());
    dataFile.print("*C ");
    dataFile.print(",");
    dataFile.print(" Voltaje bateria: ");
    dataFile.print(analogRead(A7) * (1.1 / 1024)* (10+2)/2);
    dataFile.print(" V ");
    dataFile.print(",");
    dataFile.print(" Porcentaje carga: ");
    dataFile.print(-149.4 + 59.52 * (analogRead(A7) * (1.1 / 1024)* (10+2)/2));
    dataFile.print("% ");
    dataFile.print(",");
    dataFile.print(" Luz FULL: ");
    dataFile.print(full);
    dataFile.print(",");
    dataFile.print(" Temperatura ambiente: ");
    dataFile.print(t);
    dataFile.print(" *C ");
    dataFile.print(",");
    dataFile.print(" Humedad relativa: ");
    dataFile.print(h);
    dataFile.print("%");
    dataFile.print(",");
    dataFile.print(" Temperatura suelo: ");
    dataFile.print(t2);
    dataFile.print(" *C ");
    dataFile.print(",");
    dataFile.print(" Humedad suelo: ");
    dataFile.print(h2);
    dataFile.print("%");
    dataFile.println("");
    dataFile.close();
    digitalWrite (FLASH, LOW);
  } else {
    Serial.println("");
    Serial.println("IMPOSIBLE GUARDAR DATOS");
    Serial.println("");
  }
  counter++;
  if (counter > 5) {
    delay (1000);
    digitalWrite (XBEE, LOW);
    delay (1799000);
  } else
    digitalWrite (XBEE, HIGH);
  delay (10000);
}

I have been trying to find possible solutions, but I am just lost. Do any of you have an idea of what could be going on?

Thank you in advance :)

  • 1
    How accurate do you think delay() is? And how much time does the sketch take when not in delay(). All this adds up. Check for instance how accurate the clock crystal/resonance is. Consider using an external RTC or try getting the Arduino Team to implement something that actually could work as a stable timer (< 1 second drift per month). – Mikael Patel Feb 17 '16 at 23:45
  • It might also matter that most Arduinos are slow, that means all data transfer and calculations take time. – Avamander Feb 18 '16 at 13:50
  • Thank you @MikaelPatel, I now realize that delay() is good for learning arduino but not for implementing real world ideas... I will try to use the DS3231 RTC that comes on the Seeeduino stalker V2.3 to trigger my readings... I still have to think of a way of implementing this idea on code... Any advices? – OpenAGRO Feb 19 '16 at 17:34
3

The problem is that you are using delay().

delay() will wait, from the moment delay() is called, for the given number of milliseconds.

That is, in more structured terms:

  1. Do something
  2. Do something else
  3. Do something more
  4. Wait 30 minutes

That will only take precisely 30 minutes if steps 1 to 3 take absolutely no time at all. And that will never be the case. Things take time. Reading from sensors, writing to SD cards, etc, all take time.

So waiting for 30 minutes between doing things means that every 30 minutes will be slightly later than the one before.

And as you saw the difference is more pronounced when you have 10 seconds instead - it ends up as 13 seconds. So your other actions - reading from sensors, writing to SD card, etc, must be taking about 3 seconds each time.

So instead of "Stop everything for half an hour", you need to think slightly differently:

  1. Look at the time.
  2. Decide if 30 minutes have passed since the last time you ran the code
  3. Remember the time so you can know when 30 minutes have elapsed next time
  4. Do your sensor/SD actions.

Since you're now keying things happening on the difference between now and when you last started to do things you get a 30 minute total delay, rather than a 30 minute delay plus other bits.

For an example of how this is done programatically you can look at the BlinkWithoutDelay example in the Arduino IDE.

  • Thank you for your comment. I have been reading some info about your statements and it seems that there are several ways to get rid of delay() function... I think the "Millis()" function is a very straightforward technique, but if it depends on a clock that is prone to give outputs with only 90% of accuracy (on-board clock cycle, as mentioned by @PaulMurrayCbr) I don't think it is going to be useful for my porpues. So I'm thinking of "asking the time" to the Stalker's on-board DS3231 RTC, but I cannot think clearly of its implementation on code... I suppose I should use if, else... – OpenAGRO Feb 19 '16 at 17:28
  • Do you have any recomendations? Thank you again for your help :) – OpenAGRO Feb 19 '16 at 17:30
  • You can use an RTC in just the same way as millis(). Take a look at the Time.h library for help manipulating times. – Majenko Feb 19 '16 at 18:37
2

The second problem is that delay() on the arduino uses the on-board clock cycle. This is powered by a resonator, which can be off by as much as 10%. If you need accurate timings and timestamps, you will want to use a Real-Time Clock (RTC) module.

Instead of using delay, the loop() asks the RTC what time it is, and uses that to determine if it's time to take another reading.

Another very common thing for this type of monitoring is for the arduino to go into sleep mode and be woken by a tick from the RTC every second (or longer), in order to extend the battery life.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.