Trying to reduce the use of SRAM

I have an Arduino + ENC28J60 in a greenhouse set up to monitor temperature and humidity. At the moment, my sketch uploads OK but doesn’t do anything. My hunch is that it uses to much SRAM memory. Any Suggestions to make it more efficient?

#include "etherShield.h"
#include "ETHER_28J60.h"

int outputPin = 6;

static uint8_t mac[6] = {0x54, 0x55, 0x58, 0x10, 0x00, 0x24};   // this just needs to be unique for your network, 
                                                           
static uint8_t ip[4] = {192, 168, 1, 15}; // IP address for the webserver

static uint16_t port = 80; // Use port 80 - the standard for HTTP

ETHER_28J60 e;

void setup()
{ 
  e.setup(mac, ip, port);
  pinMode(outputPin, OUTPUT);
}

void loop()
{
  char* params;
  if (params = e.serviceRequest())
  {
    e.print("<h1><a href='/?led=off'>Arduino Web Remote</a></h1>");
    if (strcmp(params, "?led=on") == 0)
    {
      digitalWrite(outputPin, HIGH);
      e.print("<a href='?led=off'><button style='border: 1px solid #ff0000; border-left: 10px solid #ff0000' type='button'>LED IS ON</button></a>");
    }
    else if (strcmp(params, "?led=off") == 0)
    {
      digitalWrite(outputPin, LOW);
      e.print("<a href='?led=on'><button style='border: 1px solid #000; border-left: 10px solid #000' type='button'>LED IS OFF</button></a>");
    }
    e.respond();
  }
}

This sketch doesn't give out temperature or humidity values, it's for turning an LED on or off. Where is your actual sketch?

#include "etherShield.h"
#include "ETHER_28J60.h"
//#include "OneWire.h"
#include "DHT.h"
#include "Wire.h"
#include "LiquidCrystal.h"
#define DHTPIN1 A0
//#define DHTPIN2 A1
#define DHTTYPE DHT11
DHT dht1(DHTPIN1, DHTTYPE);
//DHT dht2(DHTPIN2, DHTTYPE);

const int fanPin = 2;
const int valvePin = 3;
const int ventPin = 4;
const int WindowMotorSource1 = 5;
const int WindowMotorSource2 = 6;
const int WindowMotorSink1 = 7;
const int WindowMotorSink2 = 8;
//const int DS18S20_Pin = 9;
const int ethernet_cs = 10;
//const int MOSI = 11;
//const int MISO = 12
//const int SCK = 13; 
//DHTPIN A0
const int photocellPin = A3;
int photocellReading;
long interval = 3000;
long previousMillis = 0;

long mistTime = 7000;
long ventTime = 30000;
long fanTime = 300000;

long previousMistTime = 0;
long previousFanTime = 0;
long previousMotorRuntime = 0;
long previousVentTime = 0;

byte originalState = 0;
byte Misted = 1;
byte notMisted = 0;
byte notAirCirculated = 0;
byte AirCirculated = 1;
byte Vented = 1;
byte notVented = 1;

byte  windowMotorOpeningState = 0;
byte  windowMotorClosingState = 0;

byte windowState = 0;

int  repetitionCounter = 0;
int Repetitions = 100; // 3 sec rep. cycle * X = time between mistings
const int DaylightThreshold= 100;
LiquidCrystal lcd(0);


static uint8_t mac[6] = {
  0x54, 0x55, 0x58, 0x10, 0xA0, 0x24};   // this just needs to be unique for your network, 

static uint8_t ip[4] = {
  192, 168, 1, 15}; // IP address for the webserver

static uint16_t port = 80; // Use port 80 - the standard for HTTP
//OneWire ds(DS18S20_Pin);
ETHER_28J60 e;

void setup()
{ 
   Serial.begin(9600);  
   Serial.println(F("arduino greenhouse"));
  dht1.begin();
  lcd.begin(16, 2);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  //pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);

  e.setup(mac, ip, port);


}

void loop()
{
  processClient();
  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > interval) {

    previousMillis = currentMillis; 
    checkHumidty();
    checkTemp();
    printConditions();
    repetitionCounter++;
  }

  checkMistingTime();
  checkFanTime();
  checkVentingTime();
  checkWindowMotorRuntime();
 checkWindowVentState();

  //Serial.println(repetitionCounter);
}

void processClient()
{
  digitalWrite(10, LOW);
  char* params;
  if (params = e.serviceRequest())
  {
    
    e.print("<h1>Greenhouse</h1>");
    e.print("
");
    e.print("<h3><a href='/?valve=off'>Web Remote</a></h1>");
    e.print("
");
    e.print("Brightness: ");
    e.print(photocellReading);
    float h = dht1.readHumidity();
    float t = dht1.readTemperature();
    if (isnan(t) || isnan(h)) {
      e.print("Failed to read from DHT");
    }
    else {
      e.print("
");
      e.print("Humidity: ");
      e.print(h);
      e.print("   Temperature: ");
      e.print(t);
      e.print("
");
      e.print("Time since last misting cycle: ");
      int timeSince = 3000 * repetitionCounter;
      e.print(timeSince);
      e.print("
");
      if (windowState == 1)
      {
        e.print("Window vent is OPEN.");
      }
      else 
      {
        e.print("Window vent is closed.");
      }
    }
    e.print("
");
    e.print("<button type='button' onclick=location.href='?valve=off'>VALVE</button>");
    e.print("<button type='button' onclick=location.href='?fan=off'>FAN</button>");
    if (strcmp(params, "?valve=on") == 0)
    {
      digitalWrite(valvePin, HIGH);

      e.print("<a href='?valve=off'><button style='border: 1px solid #ff0000; border-left: 10px solid #ff0000' type='button'>VALVE IS ON</button></a>");

    }
    else if (strcmp(params, "?valve=off") == 0)
    {
      digitalWrite(valvePin, LOW);
      e.print("<a href='?valve=on'><button style='border: 1px solid #000; border-left: 10px solid #000' type='button'>VALVE IS OFF</button></a>");
    }
    else if (strcmp(params, "?fan=on") == 0)
    {
      digitalWrite(fanPin, HIGH);
      e.print("<a href='?fan=off'><button style='border: 1px solid #ff0000; border-left: 10px solid #ff0000' type='button'>FAN IS ON</button></a>");
    }
    else if (strcmp(params, "?fan=off") == 0)
    {
      digitalWrite(fanPin, LOW);
      e.print("<a href='?fan=on'><button style='border: 1px solid #000; border-left: 10px solid #000' type='button'>FAN IS OFF</button></a>");
    }
    e.respond();
  }
}

void checkHumidty()
{ Serial.println(F("humidity check"));
  photocellReading = analogRead(photocellPin);
Serial.println(photocellReading);
  if(photocellReading > DaylightThreshold)
  {
    if (repetitionCounter > Repetitions)
    {
      float h = dht1.readHumidity();
      Serial.println(h);
      if (h < 50)
      {
        digitalWrite (fanPin, HIGH);

        digitalWrite (valvePin, HIGH);
        //Serial.println ("humidifying");
        notAirCirculated++;
        notMisted++;
        previousMistTime = millis();
        previousFanTime = millis();
        repetitionCounter = 0;
      }

    }
    else 
    {
      // Serial.println("not enough repetitions");
    }
  }
  else
  {
    // Serial.println("not daytime"); 
  }
}
void checkTemp()
{ 
  Serial.println(F("Temp check"));
  float t = dht1.readTemperature();
  Serial.println(t);
  if (t > 27)
  {

    digitalWrite (valvePin, HIGH);
    digitalWrite (fanPin, HIGH);

    notAirCirculated = 1;
    notMisted = 1;

  }
  if (t > 33 && windowState == 0)
  {
    digitalWrite (WindowMotorSource1, HIGH);
    digitalWrite (WindowMotorSink1, HIGH);
    unsigned long currentMotorRuntime = millis();
    windowMotorOpeningState = 1;
    windowState = 1;
    digitalWrite (ventPin, HIGH);
    notVented = 1;
    
  }
  if  (t > 33 && windowState == 1)
  {
    if (notVented == 0)
    {
      digitalWrite (ventPin, HIGH);
      notVented = 1;
    }
  }
}


void printConditions()
{
  lcd.clear();
  float h = dht1.readHumidity();
  float t = dht1.readTemperature();
  if (isnan(t) || isnan(h)) 
  {
    //Serial.println("Failed to read from DHT");
  }
  else 
  {
    lcd.print(F("Hum: "));
    lcd.print(h);
    lcd.setCursor(0, 1);
    lcd.print(F("Temp: "));
    lcd.print(t);
  }
}

void checkMistingTime()
{
  if (notMisted == Misted)
  {  
    unsigned long currentMistTime = millis();
    if (currentMistTime - previousMistTime > mistTime ) 
    {
      previousMistTime = currentMistTime;
      digitalWrite (valvePin, LOW);
      notMisted = originalState;
    }
  }
}

void checkFanTime()
{
  if (notAirCirculated == AirCirculated)
  {  
    unsigned long currentFanTime = millis();
    if(currentFanTime - previousFanTime > fanTime) 
    {  
      previousFanTime = currentFanTime;
      digitalWrite (fanPin, LOW);
      notAirCirculated = originalState;
    }
  }
}

void checkVentingTime()
{
  if (notVented == Vented)
  {
    unsigned long currentVentTime = millis();
    if (currentVentTime - previousVentTime > ventTime)
    {
      previousVentTime = currentVentTime;
      digitalWrite (ventPin, LOW);  
      notVented == originalState;
    }
  }
}
void checkWindowMotorRuntime()
{
  
  unsigned long currentMotorRuntime = millis();
  if (windowMotorOpeningState == 1)
  {
    if(currentMotorRuntime - previousMotorRuntime > interval)
    {
      previousMotorRuntime = currentMotorRuntime;
      digitalWrite (WindowMotorSource1, LOW);
      digitalWrite (WindowMotorSink1, LOW);
      windowMotorOpeningState = originalState;
    }
  }
  if (windowMotorClosingState == 1)
  {
    if(currentMotorRuntime - previousMotorRuntime > interval)
    {
      previousMotorRuntime = currentMotorRuntime;
      digitalWrite (WindowMotorSource2, LOW);
      digitalWrite (WindowMotorSink2, LOW);
      windowMotorClosingState = originalState;
    }
  }
}
void checkWindowVentState()
{
  if (windowState == 1)
  {
    long timeSince = repetitionCounter * 3000;
    if (timeSince > fanTime)
    {
      float t = dht1.readTemperature();
      if (t < 33) 
      {
        digitalWrite (WindowMotorSource2, HIGH);
        digitalWrite (WindowMotorSink2, HIGH);
        windowState = originalState;
        windowMotorClosingState == 1;
      }
    }
  }
}

Hmmm... still looking for answers here... I was hoping someone might look at my code and offer some constructive criticism/suggestions to make it more memory efficient before I reach for a bigger hammer (ie. an atmega 1284pu). Thanks!

First question was how do I assemble a neat package containing several floats,

Why does the package need to be neat? Are you going to put it under a Christmas tree?

Converting each float to a string, using dtostrf(), and then concatenating them into a char array, using strcat() is one possibility.

send via LAN

I don't know. Perhaps the e.print() method?

parse it on the other end?

Parsing is a matter of undoing the packaging operation. We have no idea how you are packaging the data.

Second, I was hoping someone might look at my code and offer some constructive criticism/suggestions to make it more memory efficient before I reach for a bigger hammer

Consistent use of the F() macro comes to mind.

Thanks PaulS. And no it does not need to be neat, lol.

Converting each float to a string, using dtostrf(), and then concatenating them into a char array, using strcat() is one possibility.

Could I badger you for a more detail? How do I use dtostrf() and strcat()?

Consistent use of the F() macro comes to mind.

My understanding is that I can only use F() macro on certain prints likeSerial.print(F("temperature")). I tried it for some e.print() and I get this compiler error: invalid conversion from '__FlashStringHelper*' to 'int'. How can i be more consistent with F() macro?

Could I badger you for a more detail? How do I use dtostrf() and strcat()?

Did google fail you? Hard to believe.

My understanding is that I can only use F() macro on certain prints like

True. But how many do you have that print constant strings that do not use the F() macro?

Could I badger you for a more detail? How do I use dtostrf() and strcat()?

Did google fail you? Hard to believe.

I'll take that as a no... Google, here I come.

how many do you have that print constant strings that do not use the F() macro?

Off the top of my head: 2. (The rest should be commented out and are only for debugging.) I print temp and humidity to the lcd every three seconds. Both of which use F():

lcd.print(F("Hum: "));
    lcd.print(h);
    lcd.setCursor(0, 1);
    lcd.print(F("Temp: "));
    lcd.print(t);

I just discovered that the adafruit library I have been using for the I2C lcd display uses almost 1600 bytes of ram! :astonished: I got the rest of the sketch to under 300bytes but it still won't run.

I just discovered that the adafruit library I have been using for the I2C lcd display uses almost 1600 bytes of ram

Which one is that?

Goolge found this one.

Interesting, it seems i have been using a different library found here:https://github.com/adafruit/LiquidCrystal I will check out the other one and see if it does better.

Here is the code I am using to check memory use of the “lean” library:

#include <Wire.h>
#include <LiquidTWI2.h>

// Connect via i2c, default address #0 (A0-A2 not jumpered)
LiquidTWI2 lcd(0);
int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}
void setup() {
    
  Serial.begin(57600);
    Serial.println(F("\n[memCheck]"));
    Serial.println(freeRam());
  // set the LCD type
  lcd.setMCPType(LTI_TYPE_MCP23008); 
//  lcd.setMCPType(LTI_TYPE_MCP23017); 
  // set up the LCD's number of rows and columns:
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print(F("hello, world!"));
Serial.println(F("hello"));

}

void loop() {
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.setCursor(0, 1);
  // print the number of seconds since reset:
  lcd.print(millis()/1000);

  lcd.setBacklight(HIGH);
  delay(500);
  lcd.setBacklight(LOW);
  delay(500);
}

and here is the result in serial monitor:

[memCheck]
1607

Am I going about this the right way?

other tip. All the time related variables you use to compare with millis() should be unsigned long as millis() itself returns this type.

1607 ==> you're doing quite well imho ;)

You could check what an empty sketch takes with just the freeRAM() check to have some reference..

Thank you, I'll make a note to fix the variable types. The 1600 bytes is being used strictly to print two lines to an I2c display. The other 350 lines of code in the sketch uses less than 300 bytes... I think have been looking at this backwards. Its not 1600 bytes used but 1600 bytes free. Oops... yea, this makes more sense now.

seanz2003:
I have an Arduino + ENC28J60 in a greenhouse set up to monitor temperature and humidity. At the moment, my sketch uploads OK but doesn’t do anything. My hunch is that it uses to much SRAM memory. Any Suggestions to make it more efficient?

    e.print("<h1><a href='/?led=off'>Arduino Web Remote</a></h1>");


   e.print(“LED IS ON”);

All those strings are stored in SRAM unless you tell it otherwise. They quickly eat it up.

See this page: http://www.arduino.cc/en/Reference/PROGMEM

See this page: http://www.arduino.cc/en/Reference/PROGMEM

that is what I have been looking for, thank you

I got the sketch running using progmem, but not without issues though. The sketch is a webremote the works with two html buttons to turn on and off certain pins. Controlling two buttons is no problem. Three buttons: problems. Four Buttons; more problems. With three buttons, I can click a button to turn on a pin and the sketch will continue to loop. But if I click the button again to turn off the pin the sketch freezes and I have to reset the arduino. With four html buttons, the sketch will continue to run but the buttons do nothing. Here is the sketch so far:

#include <EEPROM.h>
#include "etherShield.h"
#include "ETHER_28J60.h"

#include <avr/pgmspace.h>
#include "DHT.h"
#include "Wire.h"
#include "LiquidCrystal.h"

#define DHTPIN1 A0
#define DHTPIN2 A1
#define photocellPin A3
#define fanPin 2
#define valvePin 3
#define ventPin 4
#define motorRun 5
#define motorReverse 6


#define ethernet_cs 10
#define DaylightThreshold 100
#define DHTTYPE DHT11
DHT dht1(DHTPIN1, DHTTYPE);
DHT dht2(DHTPIN2, DHTTYPE);

int photocellReading;

unsigned long interval = 3000; 

unsigned long mistTime = 7000;
unsigned long ventTime = 30000;
unsigned long fanTime = 300000;
unsigned long previousMillis = 0;
unsigned long previousMistTime = 0;
unsigned long previousFanTime = 0;
unsigned long previousMotorRuntime = 0;
unsigned long previousVentTime = 0;

int  repetitionCounter = 0; 

LiquidCrystal lcd(0);

static uint8_t mac[6] = {
  0x54, 0x55, 0x58, 0x10, 0xA0, 0x24};   // this just needs to be unique for your network, 

static uint8_t ip[4] = {
  192, 168, 1, 15}; // IP address for the webserver

static uint16_t port = 80; // Use port 80 - the standard for HTTP

ETHER_28J60 e;


prog_char string_0[] PROGMEM = "<h1><a href='/?valve=off'>Greenhouse Arduino</a></h1>";   // "String 0" etc are strings to store - change to suit.
prog_char string_1[] PROGMEM = "
";
prog_char string_2[] PROGMEM = "Brightness: ";
prog_char string_3[] PROGMEM = "Failed to read from DHT";
prog_char string_4[] PROGMEM = "Humidity: ";
prog_char string_5[] PROGMEM = "   Temperature: ";
prog_char string_6[] PROGMEM = "Time since last misting cycle: ";
prog_char string_7[] PROGMEM = "Window vent is OPEN.";
prog_char string_8[] PROGMEM = "Window vent is closed.";
prog_char string_9[] PROGMEM = "<button type='button' onclick=location.href='?valve=off'>VALVE</button>";
prog_char string_10[] PROGMEM = "<button type='button' onclick=location.href='?fan=off'>FAN</button>";
prog_char string_11[] PROGMEM = "<button type='button' onclick=location.href='?vent=off'>VENT</button>";
prog_char string_12[] PROGMEM = "<button type='button' onclick=location.href='?window=off'>WINDOW</button>";
prog_char string_13[] PROGMEM = "<a href='?valve=off'><button style='border: 1px solid #ff0000; border-left: 10px solid #ff0000' type='button'>VALVE IS ON</button></a>";
prog_char string_14[] PROGMEM = "<a href='?valve=on'><button style='border: 1px solid #000; border-left: 10px solid #000' type='button'>VALVE IS OFF</button></a>";
prog_char string_15[] PROGMEM = "<a href='?fan=off'><button style='border: 1px solid #ff0000; border-left: 10px solid #ff0000' type='button'>FAN IS ON</button></a>";
prog_char string_16[] PROGMEM = "<a href='?fan=on'><button style='border: 1px solid #000; border-left: 10px solid #000' type='button'>FAN IS OFF</button></a>";

prog_char string_17[] PROGMEM = "<a href='?window=off'><button style='border: 1px solid #ff0000; border-left: 10px solid #ff0000' type='button'>WINDOW IS ON</button></a>";
prog_char string_18[] PROGMEM = "<a href='?window=on'><button style='border: 1px solid #000; border-left: 10px solid #000' type='button'>WINDOW IS OFF</button></a>";
prog_char string_19[] PROGMEM = "<a href='?vent=off'><button style='border: 1px solid #ff0000; border-left: 10px solid #ff0000' type='button'>VENT IS ON</button></a>";
prog_char string_20[] PROGMEM = "<a href='?vent=on'><button style='border: 1px solid #000; border-left: 10px solid #000' type='button'>VENT IS OFF</button></a>";
prog_char string_21[] PROGMEM = "  minutes";

PROGMEM const char *string_table[] = 	   
{   
  string_0,
  string_1,
  string_2,
  string_3,
  string_4,
  string_5, 
  string_6,
  string_7,
  string_8,
  string_9,
  string_10,
  string_11,
  string_12,
  string_13,
  string_14,
  string_15,
  string_16,
  string_17,
  string_18,
  string_19,
  string_20,
  string_21};    
 

char buffer[155];

int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}
void setup()
{ 
  dht1.begin();
  lcd.begin(16, 2);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, INPUT);
  digitalWrite(7, HIGH);
  //pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  for (int i = 0; i < 6; i++)
    EEPROM.write(i, 0);
  EEPROM.write(7, 100); // repetitions
  e.setup(mac, ip, port);

  Serial.begin(57600);
  Serial.println(F("\n[memCheck]"));
  Serial.println(freeRam());
}

void loop()
{
  processClient();

  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > interval) {

    previousMillis = currentMillis; 
    checkHumidty();
    checkTemp();
    printConditions();
    repetitionCounter++;
  }

  checkMistingTime();
  checkFanTime();
  checkVentingTime();
  checkWindowMotorRuntime();
  checkWindowVentState();

  //Serial.println(repetitionCounter);
}




}

and more code:

void processClient()
{
  digitalWrite(10, LOW);
  char* params;
  if (params = e.serviceRequest())
  {
    Serial.write(params);
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[0])));
    e.print(buffer);
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[1])));
    e.print(buffer);
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[2])));
    e.print(buffer);
    photocellReading = analogRead(photocellPin);
     e.print(photocellReading);
      //strcpy_P(buffer, (char*)pgm_read_word(&(string_table[1])));
    //e.print(buffer);
    float h = dht1.readHumidity();
    float t = dht1.readTemperature();
    if (isnan(t) || isnan(h)) {
      strcpy_P(buffer, (char*)pgm_read_word(&(string_table[3])));
    e.print(buffer);
      
    }
    else {
       strcpy_P(buffer, (char*)pgm_read_word(&(string_table[1])));
    e.print(buffer);
       strcpy_P(buffer, (char*)pgm_read_word(&(string_table[4])));
    e.print(buffer);
      e.print(h);
      
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[5])));
    e.print(buffer);
      
      e.print(t);
       strcpy_P(buffer, (char*)pgm_read_word(&(string_table[1])));
    e.print(buffer);
     
       strcpy_P(buffer, (char*)pgm_read_word(&(string_table[6])));
    e.print(buffer);
     
      int timeSince = repetitionCounter/20;
      e.print(timeSince);
      strcpy_P(buffer, (char*)pgm_read_word(&(string_table[21])));
    e.print(buffer);
      
       strcpy_P(buffer, (char*)pgm_read_word(&(string_table[1])));
    e.print(buffer);
      byte windowState = EEPROM.read(5);
      if (windowState == 1)
      {
        
         strcpy_P(buffer, (char*)pgm_read_word(&(string_table[7])));
    e.print(buffer);
      }
      else 
      {
       
         strcpy_P(buffer, (char*)pgm_read_word(&(string_table[8])));
    e.print(buffer);
      }
    }
    
     strcpy_P(buffer, (char*)pgm_read_word(&(string_table[1])));
    e.print(buffer);
        
     strcpy_P(buffer, (char*)pgm_read_word(&(string_table[9])));
    e.print(buffer);
    
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[10])));
    e.print(buffer);/*
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[11])));
    e.print(buffer);
    
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[12])));
    e.print(buffer);*/
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[1])));
    e.print(buffer);
    if (strcmp(params, "?valve=on") == 0)
    {  
      digitalWrite(valvePin, HIGH);
      
       strcpy_P(buffer, (char*)pgm_read_word(&(string_table[13])));
    e.print(buffer);

    }
    else if (strcmp(params, "?valve=off") == 0)
    {
      digitalWrite(valvePin, LOW);
      
       strcpy_P(buffer, (char*)pgm_read_word(&(string_table[14])));
     e.print(buffer);
       Serial.write(buffer);
   
    }
    else if (strcmp(params, "?fan=on") == 0)
    {
      digitalWrite(2, HIGH);
      
       strcpy_P(buffer, (char*)pgm_read_word(&(string_table[15])));
    e.print(buffer);
    }
    else if (strcmp(params, "?fan=off") == 0)
    {
      digitalWrite(2, LOW);
      
       strcpy_P(buffer, (char*)pgm_read_word(&(string_table[16])));
    e.print(buffer);
    }
     /*
    else if (strcmp(params, "?vent=on") == 0)
    {
      digitalWrite(4, HIGH);
      
       strcpy_P(buffer, (char*)pgm_read_word(&(string_table[19])));
    e.print(buffer);
    }
     else if (strcmp(params, "?vent=off") == 0)
    {
      digitalWrite(4, LOW);
      
       strcpy_P(buffer, (char*)pgm_read_word(&(string_table[20])));
    e.print(buffer);
    }
    
    
    else if (strcmp(params, "?win=on") == 0)
    {
      digitalWrite (motorRun, HIGH);
      unsigned long currentMotorRuntime = millis();
      EEPROM.write(3, 1);
     
       strcpy_P(buffer, (char*)pgm_read_word(&(string_table[17])));
    e.print(buffer);
    }
     else if (strcmp(params, "?win=off") == 0)
    {
      digitalWrite (motorRun, HIGH);
      digitalWrite (motorReverse, HIGH);
      EEPROM.write(4, 1);
      //e.print("<a href='?fan=on'><button style='border: 1px solid #000; border-left: 10px solid #000' type='button'>FAN IS OFF</button></a>");
       strcpy_P(buffer, (char*)pgm_read_word(&(string_table[18])));
    e.print(buffer);
    }*/
    
    e.respond();
  }
}

As far as troubleshooting goes, I am writing "params" to serial so I can see when I get a "hit", then I write "buffer" (from the string array) to see what information is sent out through ethernet. When it is working with two buttons, I can see the internet query as well as the arduino's response. But if I add more buttons, the arduino never gives a response and the sketch stops. Seems to me like a memory issue but a memory check shows I have more than 700 bytes of free SRAM. Any ideas?