I have been working on a sketch to record my electrical power usage to a SD card and transmit the data via xBee using the Serial.print command. I have been using Seeeduino Stalker 168 and 328. The 328 works fine but the 168 will not work using both the Serial.print and the Filelogger statements. If I comment out the Serial.print statements, the filelogger works and if I comment out the filelogger statements, the Serial.print works.
The problem is that the 168 does not have enough RAM to run the sketch. I adjusted the RX_BUFFER_SIZE to 8 to maximize RAM. Does anybody have any ideals about modifying the sketch to get it to run on the 168? The filelogger library seems to use a good size piece of RAM so I would like to know if there is a way to reduce its usage.
Here is the sketch:
/*
* Meter reading program using Itron smart meter
*
* StalkerMeterLogger.pde
* Sketch writes incoming data from IR detector
*
* CRS8291 - Arduino forum username
*
* Data output in following format with example
* siteID, unixTime, watts, totalWatts, 15MinuteDemand, max15MinuteDemand, temperature degrees K
* 14,1288310640,200,79859,12000,12236,29315
*
*/
#include "FileLogger.h" // http://code.google.com/p/arduino-filelogger/
#include <Time.h>
#include <Wire.h>
#include <DS1307RTC.h> // a basic DS1307 library - http://www.arduino.cc/playground/Code/Time
const int ledPin = 8; // LED watt indicator initialization.
int ledState = LOW; // watt LED indicator lamp
unsigned long ledOnTime = 0; // start time of LED pulse count on time
byte siteID[2]= {'1','4'};
byte delimiter[1]= {','};
byte crlf[2]= {0x0D,0x0A};
volatile unsigned int wattSensor = 0; // Counts power pulses in interrupt, 1 pulse = 1 watt
unsigned int wattSensorCount; //number of watts during logging interval
unsigned long totalWatts = 0; // Total power used since the sketch started ???
unsigned long oldtime=0; //last time loop has ran
unsigned int demandMinutes[15]; //Array that holds each powerusage reading done during the last 15 minutes
unsigned int demandMinutesKwh=0; //Average of last 15 minutes in Kwh
unsigned int maxDemandKwh=0; //Maximum 15 minute demand in Kwh
const int resetDay = 1; //day of month to reset counters, 1-31
const int resetHour = 0; //hour of day to reset counters, 0-23
const int resetMinute = 0; //minute of hour to reset counters, 0-59
const int tempPin = 1; //the analog pin the TMP36's Vout (sense) pin is connected to
unsigned int temperatureK; //temperatue in degrees kelvin, used to eliminate negative temperatures
void setup(void)
{
pinMode(ledPin, OUTPUT); // LED watt indicator initialization
attachInterrupt(1, wattSensorInterrupt, FALLING);
for (int i=0; i<15 ;i++) //Initialize last fifteen minute Kwh to 0
demandMinutes[i]=0;
setSyncProvider(RTC.get); // the function to get the time from the RTC
// Serial.begin(9600);
// int calcRam = freeRam();
// Serial.print("Free RAM: ");
// Serial.println(calcRam);
}
void loop(void)
{
time_t t = now();
// turn watt led off if 50 ms has passed since watt counted
if (digitalRead(ledPin) == HIGH && millis() - ledOnTime >= 50) {
digitalWrite(ledPin, LOW);
}
if( minute(t) != oldtime) //1 minute interval for data reporting
{
wattSensorCount = wattSensor; //get the count from the interrupt handler
wattSensor = 0; //reset the watts count
wattSensor = 300; //=18kwh, used for testing, comment out or delete for normal operation
totalWatts = totalWatts + wattSensorCount; //total watts counter
oldtime = minute(t); //use this for one minute interval
calculateDemand(); // Calculate 15 minute demand
measureTemperature(); //measure temperature in degrees Kelvin
/*
Serial.print("14,"); // print site id
Serial.print(t); //print unix time
Serial.print(',');
Serial.print(wattSensorCount); //print watts per minute
Serial.print(',');
Serial.print(totalWatts); //print accumulated watts
Serial.print(',');
Serial.print(demandMinutesKwh); //print 15 minute demand
Serial.print(',');
Serial.print(maxDemandKwh); //print max 15 minute demand
Serial.print(',');
Serial.print(temperatureK); //print temperature in degrees Kelvin
Serial.println();
*/
FileLogger::append("data.txt", siteID, 3); //print site id
write_long(t); //print unix time
FileLogger::append("data.txt", delimiter, 1);
write_long(wattSensorCount); //print watts per minute
FileLogger::append("data.txt", delimiter, 1);
write_long(totalWatts); //print accumulated watts
FileLogger::append("data.txt", delimiter, 1);
write_long(demandMinutesKwh); //print 15 minute demand
FileLogger::append("data.txt", delimiter, 1);
write_long(maxDemandKwh); //print max 15 minute demand
FileLogger::append("data.txt", delimiter, 1);
write_long(temperatureK); //print temperature in degrees Kelvin
FileLogger::append("data.txt", crlf, 2);
//reset totalWatts and maxDemandKwh to zero once a month
if ((day(t) == resetDay) && (hour(t) == resetHour)) {
if ((minute(t) == resetMinute)) {
totalWatts = 0;
maxDemandKwh = 0;
}
}
}
}
void calculateDemand() //calculates rolling 15 minute average of one minute Kw usage
{
for (int i=0; i<15 ;i++) //Block move previous 14 minutes by one step
demandMinutes[i]=demandMinutes[i+1];
demandMinutes[14]=wattSensorCount; //Assign latest one minute average to 15 minute average array
demandMinutesKwh=0; //Reset demandMinutesKwh to 0
for (int i=0; i<15 ;i++) //Calculate new 15 minute demand
demandMinutesKwh=demandMinutesKwh+demandMinutes[i];
demandMinutesKwh=demandMinutesKwh*4;
if (demandMinutesKwh > maxDemandKwh) //Assign maxDemandKwh to demandMinutesKwh if new high demand
maxDemandKwh=demandMinutesKwh;
}
void measureTemperature (void) {
unsigned int tempReading = 0; // the analog reading from the sensor
analogRead(tempPin); //discard first reading
for (int i = 0; i < 50; i++) {
tempReading = tempReading + analogRead(tempPin);
}
unsigned int voltage = tempReading * 329 / 1024 /50;
temperatureK = (((voltage - 50) * 100) + 27315); // degrees K * 100 to save as integer
}
void write_long(uint32_t number) //break data into byte array for writing to FileLogger
{
uint8_t buf[10];
uint8_t i=0;
do {
i++;
buf[sizeof(buf) - i] = number%10 + '0';
number /= 10;
}
while (number);
FileLogger::append("data.txt", &buf[sizeof(buf) - i], i);
}
void wattSensorInterrupt() // routine called when external interrupt is triggered
{
wattSensor = wattSensor + 1; //Update number of pulses, 1 pulse = 1 watt
ledOnTime = millis();
digitalWrite(ledPin, HIGH);
}
/*
// this function will return the number of bytes currently free in RAM
int freeRam(void)
{
extern int __bss_end;
extern int *__brkval;
int free_memory;
if((int)__brkval == 0) {
free_memory = ((int)&free_memory) - ((int)&__bss_end);
}
else {
free_memory = ((int)&free_memory) - ((int)__brkval);
}
return free_memory;
}
*/
edit: Currently the Serial.print is commented out for the filelogger to work.