Temperature data logger project - using Stalker

Hi,

Just a quick note to say that we have published our second data logger project - this time for 2 x LM35 temperature sensors:

airsensor.co.uk/component/zo … nsors.html

Hopefully this will provide a useful guide to getting started with the Stalker board - enjoy.

Hi,

This is my first Stalker project and I’m having some difficulties. Please could someone help me?

I basically want to use this program to detect the output from four different sensors (pressurePin0, pressurePin1, tempPin, betteryPin) and record these outputs, along with the present time and date, onto a logdata.csv file on a 1GB SDcard. The airsensor sketch at the link posted by cambo works great, it is when I try to use my modified version of this sketch (posted at the bottom of this post) that I struggle.

The symtoms of the problem are as following:

i) The time and date that is logged on the SDcard is not the time and date set using the ds1307.pde example from the RTClib library. It seems to jump to 04:00:00, 10/01/1984 every time the board is reset. In the airsensor code provided above this is not the case: the clock displays the expected RTC time correctly and continues on normally after the board is reset.

ii) The logging always stops after 5 minutes. Regardless of the logging interval, the last log that is displayed on the SDcard data is always the last log before the entry that completes 5 minutes. E.g. if the logging interval is three seconds, the last entry will always be 04:04:57. The loop then just seems to stop - even though the board remains powered. No file logging error is displayed by the fileLedPin. In the airsensor code, the logging continues past 5 minutes with no problem.

Clearly I could get over symptom (i) without to much trouble just by noting the correct start time and date. But in order to make a decent data logger, symptom (ii) is being a bit of a nightmare!

Many thanks for any help that can be offered!

Ed

CODE:

/*

05/11/2010 SimpleLM35Logger (modified)

This sketch logs the output from four sensors
every 3 seconds. During the sensor detection
phase, an averaging loop records the outputs of
each sensor and adds them to a total. The first
two sensors are read on the ADC with a reference
voltage of 1.1V, the second two with 3.3V. After
the averages are taken the data is recorded on
the SDcard along with the time and date of the
log.

Written by Michael Margolis, modified by Edward
Matos

Copyright Michael Margolis 2010
In association with www.airsensor.co.uk

*/
  
#include <Fat16.h>  // the SD Card library - http://code.google.com/p/fat16lib/
#include <Wire.h>  
#include <Time.h>  
#include <DS1307RTC.h> // a basic DS1307 library - http://www.arduino.cc/playground/Code/Time

const int  fileLedPin  =  6;  // LED to indicate a file error
const int  goodLedPin  =  5;  // LED to indicate a successful log

const int logInterval = 3; // the interval in seconds between each log
const float n = 5.0;       // number of samples taken for average loop (milliseconds)
const int t = 100;         // time between each averaging sample (milliseconds) - make sure (n * t + 1000) / 1000 < logInterval

// holders for sensor values
float pressure0 = 0;
float pressure1 = 0;
float temp = 0;
float battery = 0;

// holders for sensor values before averaging
float val1 = 0;
float val2 = 0;
float val3 = 0;
float val4 = 0;

int throw_away = 0; // a variable defined for taking readings and throwing them away
 
const char *fileName = "logdata.csv";  // the name of the log file
 
SdCard card;
Fat16 LogFile;
 
// Sensor pins
const int pressurePin0 = 0; // the analog pin the first pressure sensor is connected to
const int pressurePin1 = 1; // the analog pin the second pressure sensor is connected to
const int tempPin = 2;      // the analog pin the temperature sensor is connected to
const int batteryPin = 3;   // the analog pin the battery voltage sensor is connected to


void setup(void)
{
  pinMode(fileLedPin, OUTPUT);
  pinMode(goodLedPin, OUTPUT);
  
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
 
  // initialize the SD card
  if (!card.init())
     error(1);
  
  // initialize a FAT16 volume
  if (!Fat16::init(&card))
      error(2);
 
  // open file for append, create if it doesn't exist  
  if (!LogFile.open(fileName, O_CREAT | O_APPEND | O_WRITE)) 
      error(3);
 
  // clear write error
  LogFile.writeError = false;
  LogFile.println("Time,Date,Pressure0(AREF=1.1),Pressure1(AREF=1.1),Temperature(AREF=3.3),Battery(AREF=3.3)");
}
 
void loop(void)
{

   time_t timeStamp = now();  
   //LogFile.print(timeStamp); 
   //LogFile.print(',');    
   printDateTime(timeStamp);
   
  // Reset sensor averaging holders
  val1 = 0;
  val2 = 0;
  val3 = 0;
  val4 = 0;
  throw_away = 0;
   
   for(int i=0; i < n; i++) { // take n readings from pressure all sensors
   
    // set analog reference voltage to 1.1V
    // read first value, throw it away and 
    // wait for 10ms to ensure this happens
    // properly
    analogReference(INTERNAL);
    throw_away = analogRead(pressurePin0);
    delay(10);
    
    //read sensor values and add them to averaging holders
    val1 = val1 + analogRead(pressurePin0);
    val2 = val2 + analogRead(pressurePin1);

    // set analog reference voltage to 3.3V
    // read first value, throw it away and 
    // wait for 10ms to ensure this happens
    // properly    
    analogReference(DEFAULT);
    throw_away = analogRead(tempPin);
    delay(10);
    
    //read sensor values and add them to averaging holders
    val3 = val3 + analogRead(tempPin);
    val4 = val4 + analogRead(batteryPin);    
    
    delay(t-20);
   }


    // Leave in misterious delay which was in original code... don't
    // want to take it out just in case but can make use it to display
    // a LED every time a reading is taken
    digitalWrite(goodLedPin, HIGH);  
    delay (1000);
    digitalWrite(goodLedPin, LOW);
   
   // Evaluate averages
   pressure0 = val1 / n;
   pressure1 = val2 / n;
   temp = val3 / n;
   battery = val4 / n;
   
   LogFile.print(pressure0,1);
   LogFile.print(",");
   LogFile.print(pressure1,1);
   LogFile.print(",");
   LogFile.print(temp,1);
   LogFile.print(",");
   LogFile.println(battery,1);   
 
   // write the data to the card at the end of every line 
    if (!LogFile.sync())
        error(4); 

    // Delay next reading by stipulated amount
    while(now() < (timeStamp + logInterval)) {
      delay(10);}

   
}
 
// routine handle file errors 
void error(int err)
{
  // blink forever
 while(1)
 {
   digitalWrite(fileLedPin, HIGH);
   delay(err * 200);
   digitalWrite(fileLedPin, LOW);
   delay(200);  
 }     
}
 
void printDateTime(time_t t)
{
  printDigits(hour(t),':' ); 
  printDigits(minute(t),':' ); 
  printDigits(second(t),',' );  // uncomment this to print seconds (and replace the comma above with colon)
  // print a space here if you need it
  printDigits(day(t),'//' );  
  printDigits(month(t),'//' );   
//  LogFile.print(year(t));  // prints year using 4 digits
  LogFile.print(year(t)-2000);  // prints year using 2 digits
  LogFile.print(',');
}
 
void printDigits(int digits, char seperator)
{
  // utility function time with leading 0
  if(digits < 10)
    LogFile.print('0');
  LogFile.print(digits);
  LogFile.print(seperator);  
}

To reduce the size of the serial buffer, go to the directory where you installed the core Arduino code and navigate to the directory: hardware\arduino\cores\arduino

Open the file named HardwareSerial.cpp in a text editor and change the following line from:
#define RX_BUFFER_SIZE 128
To
#define RX_BUFFER_SIZE 32

Save the file and compile and run the sketch below:

[code]// on a 128 stalker this sketch requires the Arduino core serial buffer to be reduced to 32 bytes
#include <Fat16.h> // the SD Card library - http://code.google.com/p/fat16lib/
#include <Wire.h>
#include <Time.h>
#include <DS1307RTC.h> // a basic DS1307 library - http://www.arduino.cc/playground/Code/Time
#include <avr/pgmspace.h>

const int fileLedPin = 6; // LED to indicate a file error
const int goodLedPin = 5; // LED to indicate a successful log

const int logInterval = 3; // the interval in seconds between each log
const float n = 5.0; // number of samples taken for average loop (milliseconds)
const int t = 100; // time between each averaging sample (milliseconds) - make sure (n * t + 1000) / 1000 < logInterval

// the log header string is stored in program flash memory to save RAM
const char headerString[] PROGMEM = “Time,Date,Pressure0(AREF=1.1),Pressure1(AREF=1.1),Temperature(AREF=3.3),Battery(AREF=3.3)”;

// holders for sensor values
float pressure0 = 0;
float pressure1 = 0;
float temp = 0;
float battery = 0;

// holders for sensor values before averaging
float val1 = 0;
float val2 = 0;
float val3 = 0;
float val4 = 0;

int throw_away = 0; // a variable defined for taking readings and throwing them away

const char *fileName = “logdata.csv”; // the name of the log file

SdCard card;
Fat16 LogFile;

// Sensor pins
const int pressurePin0 = 0; // the analog pin the first pressure sensor is connected to
const int pressurePin1 = 1; // the analog pin the second pressure sensor is connected to
const int tempPin = 2; // the analog pin the temperature sensor is connected to
const int batteryPin = 3; // the analog pin the battery voltage sensor is connected to

void setup(void)
{
pinMode(fileLedPin, OUTPUT);
pinMode(goodLedPin, OUTPUT);

setSyncProvider(RTC.get); // the function to get the time from the RTC

// initialize the SD card
if (!card.init())
error(1);

// initialize a FAT16 volume
if (!Fat16::init(&card))
error(2);

// open file for append, create if it doesn’t exist
if (!LogFile.open(fileName, O_CREAT | O_APPEND | O_WRITE))
error(3);

// clear write error
LogFile.writeError = false;
logFlashStr(headerString);
}

void loop(void)
{

time_t timeStamp = now();
//LogFile.print(timeStamp);
//LogFile.print(’,’);
printDateTime(timeStamp);

// Reset sensor averaging holders
val1 = 0;
val2 = 0;
val3 = 0;
val4 = 0;
throw_away = 0;

for(int i=0; i < n; i++) { // take n readings from pressure all sensors

// set analog reference voltage to 1.1V
// read first value, throw it away and 
// wait for 10ms to ensure this happens
// properly
analogReference(INTERNAL);
throw_away = analogRead(pressurePin0);
delay(10);

//read sensor values and add them to averaging holders
val1 = val1 + analogRead(pressurePin0);
val2 = val2 + analogRead(pressurePin1);

// set analog reference voltage to 3.3V
// read first value, throw it away and 
// wait for 10ms to ensure this happens
// properly    
analogReference(DEFAULT);
throw_away = analogRead(tempPin);
delay(10);

//read sensor values and add them to averaging holders
val3 = val3 + analogRead(tempPin);
val4 = val4 + analogRead(batteryPin);    

delay(t-20);

}

// Leave in misterious delay which was in original code... don't
// want to take it out just in case but can make use it to display
// a LED every time a reading is taken
digitalWrite(goodLedPin, HIGH);  
delay (1000);
digitalWrite(goodLedPin, LOW);

// Evaluate averages
pressure0 = val1 / n;
pressure1 = val2 / n;
temp = val3 / n;
battery = val4 / n;

LogFile.print(pressure0,1);
LogFile.print(",");
LogFile.print(pressure1,1);
LogFile.print(",");
LogFile.print(temp,1);
LogFile.print(",");
LogFile.println(battery,1);

// write the data to the card at the end of every line
if (!LogFile.sync())
error(4);

// Delay next reading by stipulated amount
while(now() < (timeStamp + logInterval)) {
  delay(10);}

}

// routine handle file errors
void error(int err)
{
// blink forever
while(1)
{
digitalWrite(fileLedPin, HIGH);
delay(err * 200);
digitalWrite(fileLedPin, LOW);
delay(200);
}
}

void printDateTime(time_t t)
{
printDigits(hour(t),’:’ );
printDigits(minute(t),’:’ );
printDigits(second(t),’,’ ); // uncomment this to print seconds (and replace the comma above with colon)
// print a space here if you need it
printDigits(day(t),’//’ );
printDigits(month(t),’//’ );
// LogFile.print(year(t)); // prints year using 4 digits
LogFile.print(year(t)-2000); // prints year using 2 digits
LogFile.print(’,’);
}

void printDigits(int digits, char seperator)
{
// utility function time with leading 0
if(digits < 10)
LogFile.print(‘0’);
LogFile.print(digits);
LogFile.print(seperator);
}

// log a string from flash memory
void logFlashStr(const prog_char str[])
{
char c;
if(!str)
return;
while((c = pgm_read_byte(str++)))
{
LogFile.print(c,BYTE);
}
}
[/code]

The first couple of lines got missed off my post above. It should say:

If you are running a 168 Stalker then you have probably run out of RAM. The SD card software uses more than half of the total RAM and when added to the memory used by the Arduino Serial, Wire and core software, there is not much left for a sketch.

You can free up more memory with the tips given in the previous post

Sorry for the delay on this, things have been a bit too hectic recently to find some private time with my hobbie electronics :slight_smile:

I just tried this and it works a treat. Magic. Thank you very much for your help.

Unfortunately I haven’t got a clue what I just did. Would you be able to tell me what implications this change of the “buffer size” has on the sketch? This is because I’d like to make some further modifications and I need to know whether there are any new limits I need to work with!

The change reduces the size of the serial buffer which frees up RAM for your sketch. This means that if you had a sketch that used Serial and received more than 32 characters before the sketch could read them , some characters could be lost.

The logging sketch does not use Serial so this won’t matter, but the change to the Serial buffer will affect all your sketches so if you have other applications that receive big chunks of serial data then you can set the smaller buffer only when you compile the logging sketch and restore the buffer back to 128 bytes for your other applications.

Crystal clear. Thanks again.