Ethernet + SD card (FAT32) code becomes too long for my UNO

Hey guys.

I really hope you guys can help my since I’ve been trying to fix this problem for ages now.
I’m doing a datalogging system for my university outside bar, that should be able to

  • Log the time of each sold beer on a SD-card
  • Create live logging on Xively (the former Pachube)

Additional info:

  • I’ve connected my arduino Ethernet to a 3G router, so that it is disconnected from a computer (since this is not an option) but still has internet access.
  • I use a Real Time Clock with a DS1302 chip. Sometimes, the 3G connection is bad so I need to get the timestamp for the SDfile without internet connection.
  • My SD card is a FAT32 so I can’t use the tinyFat lib that doesn’t take up too much space and have to use the original SD library.

Here is my problem - I’ve finally fixed the ethernet + SD card problem, but not my code is at 34 kB and cannot be coded to my arduino ethernet (32 kB capacity).

I’ve got pushbuttons on pins 2,3,5 and 6 to register whenever a beer, soda or shot has been sold.

I’m still very new to coding so I apologise for the messy coding.

#include <SD.h>
#include <SPI.h>
#include <Ethernet.h>
#include <HttpClient.h>
#include <Xively.h>
#include <DS1302.h> //Clock

//Ethernet
byte mac[] = { 
  0x90, 0xA2, 0xDA, 0x0E, 0xE1, 0x7B};
const int chipSelect = 4; //

DS1302 rtc(8,9,7); //Setup clock
File dataFile;//SD

//Setting up xively key
char xivelyKey[] = "XIVELYKEY_;

int timeInterval = 5000; 
long lastReset;

int beer_total;
int soda_total;
int shot_total;

int beer_pin = 2;         // the number of the input pin
int beer;
int state_beer = HIGH;      // the current state of the output pin
int previous_beer = LOW;    // the previous beer_reading from the input pin
int beer_reading;           // the current beer_reading from the input pin

int sixpack_pin=3;
int sixpack;
int sixpack_reading;
int state_sixpack = HIGH;      // the current state of the output pin
int previous_sixpack = LOW;    // the previous beer_reading from the input pin

int soda_pin=5;
int soda;
int soda_reading;
int state_soda = HIGH;      // the current state of the output pin
int previous_soda = LOW;

int shot_pin = 6;         // the number of the input pin
int shot;
int state_shot = HIGH;      // the current state of the output pin
int previous_shot = LOW;    // the previous shot_reading from the input pin
int shot_reading; 


// the follow variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long time = 0;         // the last time the output pin was toggled
long debounce = 200;   // the debounce time, increase if the output flickers


// Xively channels
char sensorId1[]= "CHANNEL1";
char sensorId2[] = "CHANNEL2";
char sensorId3[]="CHANNEL3";

XivelyDatastream datastreams[] = {
  XivelyDatastream(sensorId1, strlen(sensorId1), DATASTREAM_INT),
  XivelyDatastream(sensorId2, strlen(sensorId2), DATASTREAM_INT),
  XivelyDatastream(sensorId3, strlen(sensorId3), DATASTREAM_INT),

};
// Finally, wrap the datastreams into a feed
XivelyFeed feed(FEED_ID, datastreams, 3 /* number of datastreams */);

EthernetClient client;
XivelyClient xivelyclient(client);

void setup() {
  Serial.begin(9600);

  // disable w5100 while setting up SD
  pinMode(10,OUTPUT);
  digitalWrite(10,HIGH);

  Serial.print("Starting SD..");
  if(!SD.begin(4)) Serial.println("failed");
  else Serial.println("ok");
  
  dataFile = SD.open("datalog1.txt", FILE_WRITE);
  if (! dataFile) {
    Serial.println("error opening datalog.txt");
    // Wait forever since we cant write data
    while (1) ;
  }

  Serial.print("Starting ethernet..");
  if(!Ethernet.begin(mac)) Serial.println("failed");
  else Serial.println("ok");
  // Ethernet.begin() returns with its SPI enabled, so disable it
  digitalWrite(10,HIGH);
}

void loop() {
  // make a string for assembling the data to log:

  beer_reading = digitalRead(beer_pin);
  sixpack_reading = digitalRead(sixpack_pin);
  soda_reading = digitalRead(soda_pin);
  shot_reading = digitalRead(shot_pin);

  // if the input just went from LOW and HIGH and we've waited long enough
  // to ignore any noise on the circuit, toggle the output pin and remember
  // the time
  if (beer_reading == HIGH && previous_beer == LOW && millis() - time > debounce) {
    if (state_beer == HIGH)
     beer_total++;

sdCardCode();
    time = millis();    
  }
  if (sixpack_reading == HIGH && previous_sixpack == LOW && millis() - time > debounce) {
    if (state_sixpack == HIGH)
      beer_total=beer_total+6;


    time = millis();    
  }

  if (soda_reading == HIGH && previous_soda == LOW && millis() - time > debounce) {
    if (state_soda == HIGH)
      soda_total++;

sdCardCode();

    time = millis();    
  }
  if (shot_reading == HIGH && previous_shot == LOW && millis() - time > debounce) {
    if (state_shot == HIGH)
      shot_total++;


    time = millis();    
  }
  previous_beer = beer_reading;
  previous_sixpack = sixpack_reading;
  previous_soda = soda_reading;
  previous_shot = shot_reading;
  
    if (millis()-lastReset >= timeInterval) { 
    ethernetCode();
  }
}


void sdCardCode() {
  // ...
  digitalWrite(10, HIGH);
  digitalWrite(4, LOW);  // SD Card ACTIVE
  // code that sends to the sd card slave device over SPI
  // using SPI.transfer() etc.

  String dataString = "";    
  dataString += String((rtc.getTimeStr())); //tid
  dataString += ",";
  dataString += String(beer_total);
  dataString += ","; 
  dataString += String(soda_total);
  dataString += ","; 
  dataString += String(shot_total);

  dataFile.println(dataString);

  // print to the serial port too:
  Serial.println(dataString);

  // The following line will 'save' the file to the SD card after every
  // line of data

  dataFile.flush();
  digitalWrite(4, HIGH); // SD Card not active
  lastReset = millis();
}

void ethernetCode() {
  // ...
  digitalWrite(10, LOW);  // Ethernet ACTIVE
  // code that sends to the ethernet slave device over SPI
  // using SPI.transfer() etc.
  datastreams[0].setInt(beer);
  datastreams[1].setInt(soda);
  datastreams[2].setInt(shot);


  Serial.println("Uploading it to Xively");
  int ret = xivelyclient.put(feed, xivelyKey);
  Serial.print("xivelyclient.put returned ");
  Serial.println(ret);

  Serial.println();
  digitalWrite(10, HIGH); // Ethernet not active
  // ...
}

Bright minds, please help me! :slight_smile:

Mega 2560?

That could be an option. I was just hoping to reduce this code with "only" 2kB so I didn't need to go but a mega and a ethernet shield (since I'm using a Ardiono Ethernet now) :)

Try to reduce the code size by using shorter static strings and eliminate (comment out) the Serial.print() debug strings as you debug each section of code.

Thank you very much SurferTim. I really appreciate your help and time.

I have changed my code to upload to google charts instead and reduced the static strings and now have a much shorter code. Thanks. But now (when my code is running) I see that there are some problems with the combination of SD and ethernet (I think).

I tried to find a solution and stumbled upon your name on an other post regarding SD and ethernet. I've used the coding from that example.

void setup()
{
  Serial.begin(9600);

  // disable SD SPI while starting w5100
  // or you will have trouble
  pinMode(4, OUTPUT);
  digitalWrite(4,HIGH);   

  Ethernet.begin(mac, ip);
  server.begin();
  
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
  
  // this corrects a bug in the Ethernet.begin() function
  // even tho the call to Ethernet.localIP() does the same thing
  digitalWrite(10,HIGH);

  if (!SD.begin(4)) 
     Serial.println("SD initialization failed.");
  // SD.begin() returns with the SPI disabled, so you need not disable it here
    
  Serial.print("server is (still?) at ");
  Serial.println(Ethernet.localIP());

My new code is over 9500 characters so i can't post it to this forum (might not be necessary but here it is https://dl.dropboxusercontent.com/u/4193273/SD_Ethernet/SD_Ethernet.ino)

When I open my serial communication it never stops printing:

"Server isServer is Server isServer is Server isServer is "

Any suggestions? Once again, many thanks for your help! :)

It sounds like you are running out of SRAM and it is causing your code to restart when it overflows (wraps around). Go through your code and use the F() function with your static strings.

  Serial.print(F("server is at "));
  Serial.println(Ethernet.localIP());

Thanks a lot, it works now! I'll name my first born "Sufer Tim". Thank!

I had this same problem and used all the tricks to reduce memory. The problem is that using the F() function, passing by reference instead of value, etc. reduces memory by a couple bytes here and a couple bytes there. What I needed was a major reduction. It turns out that the SD library is a real pig when it comes to memory. It turns out that the SdFat library provides almost the same functionality with a much smaller memory footprint. When I switched to using SdFat, I freed up enough memory to add even more functionality on a UNO.

Of course, I then decided to add a web interface that required me to move to a Mega...

jimbarstow:
Of course, I then decided to add a web interface that required me to move to a Mega…

I think that is usually the way it goes.