Ethernet shield slowing Arduino to a crawl

Good evening everyone.

I have been working on a project that does some data acquisition (water pH and temperature) and is supposed to post the data to Pachube.

The code and the hardware is working fine, until I attach the (Arduino) Ethernet shield to Arduino (Uno). When I do that, it seems that the whole thing becomes incredibly slow (specifically, I have a few input buttons that each run a routine, and when pressed they worked just fine without the shield, but with the shield I have to keep pressing on them for about 3 seconds until the board registers the button press). Is the shield that much of a processor hog?

The connections are as follows:

Digital pins:
Out: 2, 3, 5, 6, 7, 9 - LCD display

Analog pins:
In: A0, A1 - pH and temperature sensor
A2, A3, A4, A5 - 4 pushbuttons (used as digital inputs on analog pins)

Arduino powered by 9VDC 2.1mm jack.

I'm using SPI.h library so digital 10, 11, 12 and 13 are used by it, and the ethernet shield reserves digital 4 for the SD card (which I have to put as a high output to disable).

I'm at a loss what to try. I am only transfering data through ethernet every 15 minutes so high transfer load doesn't seem to be the issue.

The whole code is attached next.

Thank you very much for your help and input. Hope that someone can aid me in this issue.

#include <LiquidCrystal.h>
#include <SPI.h>
#include <Ethernet.h>
#include <stdio.h>
#include <string.h>
#include "float2string.h"


#define GAIN  10
#define VREF  2.366
#define PHSENSOR  0                  
#define TEMPSENSOR  1          
#define RESET_PIN 8                
#define GAS_CONSTANT_R  8.31451
#define FARADAY_CONSTANT_F  96485
#define NERNST  59.16
#define SAMPLES  200       
#define PACHUBE_API_KEY  "XXX"
#define PACHUBE_FEED_ID  99999                 
#define T_PACHUBE_UPDATE 900000        //pachube upload time, every 15 minutes = 900000 ms


float setPoint = 7.00;                  
float interval_SP = 0.05;              
unsigned long timer_upload = 0;         
unsigned long timer_upload_old = 0;   
int buttonState0 = 0;                   //Calibration button state, HIGH/LOW
int buttonState1 = 0;                   //Up button state, HIGH/LOW
int buttonState2 = 0;                   //Down button state, HIGH/LOW
int buttonState3 = 0;                   //OK button state, HIGH/LOW
float temp_mv = 0;                      
float ph_mv = 0;                        
float ph_calib7 = 0;                    
float ph_calib4 = 1;                    
float T = 0;                            
float E = 0;                            
float PH = 0;                           
char temp_str[6];                       
char ph_str[6];                         
char sp_str[6];                         
int comm_status = 0;                    //ethernet link state, ON/OFF
int valve_status = 0;                   //solenoid valve state, NOT YET IMPLEMENTED



byte mac[] = { 0x91, 0xA1, 0xDB , 0x00, 0x6F, 0x2C };
byte ip[] = { 10, 0, 0, 177 };
byte server[] = { 173, 203, 98, 29 };            // pachube.com
byte gateway[] = { 10, 0, 0, 1 };
byte mask[] = { 255, 255, 255, 0 };
int port = 80;


Client client(server, port);                /* Client listening on port 80		*/

LiquidCrystal lcd(9, 7, 6, 5, 3, 2);



void setup()
{
  lcd.begin(16, 4);                   
    
  pinMode (A2, INPUT);         //defines OK button as a digital in, on an analog pin
  pinMode (A3, INPUT);         //defines calibration button as a digital in, on an analog pin
  pinMode (A4, INPUT);          //defines up button as a digital in, on an analog pin
  pinMode (A5, INPUT);         //defines down button as a digital in, on an analog pin
  
  pinMode(RESET_PIN, OUTPUT);
  
  pinMode (4, OUTPUT);                  //disable SD card slot on ethernet shield, due to SPI bus
  digitalWrite (4, HIGH);
     
  
// Fix to kick-start Ethernet on power-up, power-failure by using reset signal from Arduino to reset-pin on Ethernet Shield
  // Start fix
  digitalWrite(RESET_PIN, LOW);				/* Take Ethernet reset line low		*/
  delay(200);						/* momentarily				*/
  digitalWrite(RESET_PIN, HIGH);			/* Bring it up again			*/
  delay(2000);					        /* Allow Ethernet time to boot		*/
  // End of fix
  
 
  Ethernet.begin(mac, ip, gateway, mask);            
  Serial.begin(9600);
  delay(1000);                                      

  
}



unsigned int readADC(unsigned char channel) {

  double d = 0;
  int i = 0;
 
  for (i = 0; i < SAMPLES; i++)
  {  
    d = d + analogRead(channel);   
  }
  d = d / i;                        

  return (unsigned int)(d);
}



void processData(void)
{
 
  ph_mv = readADC(PHSENSOR);                                                     
  temp_mv = readADC(TEMPSENSOR);                                                  
 

  T = (100 * temp_mv * 5.0 / 1024);                                                                                                    
  E = (((ph_mv - ph_calib7) * 5.0 / 1024) - VREF) / (GAIN * ph_calib4);                   
  PH= ((-1 * FARADAY_CONSTANT_F * E) / (2.303 * GAS_CONSTANT_R * (273.15 + T))) + 7.0;    
  
  
  floatToString(temp_str, T, 1);
  floatToString(ph_str, PH, 2);
  floatToString(sp_str, setPoint, 2);
    
  
  lcd.setCursor (0,0);
  lcd.print("T=");
  lcd.print(temp_str);
  lcd.print((char)223);         // degree symbol
  lcd.print("C");
  
  lcd.setCursor (0,1);
  lcd.print("SetPoint=");
  lcd.print(sp_str);
  
  lcd.setCursor (-4,2);
  lcd.print("pH=");
  lcd.print(ph_str);

  lcd.setCursor (-4,3);
  if (comm_status == 0) {lcd.print("Com:off");}     
  if (comm_status == 1) {lcd.print("Com:on");}

  lcd.setCursor (5,3);
  if (valve_status == 0) {lcd.print("Vlv:off");}     
  if (valve_status == 1) {lcd.print("Vlv:on");}
  
  
  if (timer_upload - timer_upload_old > T_PACHUBE_UPDATE)        //uploads to pachube every T_PACHUBE_UPDATE seconds
  {
    timer_upload_old = timer_upload; 
    
    String dataString = String(temp_str);                        
    dataString = dataString + ",";
    dataString = dataString + String(ph_str);
  
    pachube_PUT(dataString);       
  }
    
  if (timer_upload - timer_upload_old < 0)                //when millis() overflows, updates value after first failed check
  {
    timer_upload_old = timer_upload;
  }
 
}



float calibration_ph7()
{
  do
  {
          
    buttonState3 = digitalRead(A2);
      
    if (buttonState3 == HIGH)
    {
      if (ph_mv != 0) 
      {
        ph_calib7 = ph_mv;
      }
      else 
      {
        ph_calib7 = 0;
      }
    
        buttonState0 = 0;
        buttonState3 = 0;
        break;
     }
  } 
  
  while (buttonState3 != HIGH);
  
}


    
float calibration_ph4()
{
  
  float difference = 0;
  float new_gain = 0;
  
  do
  {
      
    buttonState3 = digitalRead(A2);
    
    if (buttonState3 == HIGH)
    {
      if (ph_mv != ((NERNST * 3) * GAIN) + (VREF - ph_calib7))      
      {
        difference = ((NERNST * 3) * GAIN) + (VREF - ph_calib7) - ph_mv;       
        new_gain = (((((NERNST * 3) * GAIN) + (VREF - ph_calib7)) - difference) * GAIN) / (((NERNST * 3) * GAIN) + (VREF - ph_calib7));   
        ph_calib4 = new_gain / GAIN;                                   
      }
    
      else 
      {
        ph_calib4 = 1; 
      }
    
      buttonState0 = 0;
      buttonState3 = 0;
      break;
    
    }
  }
  
  while (buttonState3 != HIGH);
  
}



void pachube_PUT(String dataString) 
{
  client.print("PUT /api/feeds/");
  client.print(PACHUBE_FEED_ID);
  client.println(".csv HTTP/1.0"); 			
  client.println("Host: www.pachube.com");
  client.print("X-PachubeApiKey: ");
  client.println(PACHUBE_API_KEY);
  client.print("Content-Length: ");
  client.println(dataString.length(), DEC);	        
  client.println("Content-Type: text/csv");
  client.println("Connection: close");    
  client.println();
  client.println(dataString);			      
}



void loop(void)
{
  
  if (client.connected() == 0)
  {
    comm_status = 0;
    client.connect();
  }
  else
  {
    comm_status = 1;
  }

  timer_upload = millis();            
  
  processData();
     
  buttonState0 = digitalRead(A3);    //checks Calib  button for a press every cycle
  buttonState1 = digitalRead(A4);    //checks Up button for a press every cycle
  buttonState2 = digitalRead(A5);    //checks Down button for a press every cycle
 
  if (buttonState0 == HIGH)            //THIS IS TAKING LIKE 3 SECONDS TO REGISTER A PRESS, WITH ETH SHIELD ON
  {
      calibration_ph7();
      calibration_ph4();
  }
  
  if (buttonState1 == HIGH)           //THIS IS TAKING LIKE 3 SECONDS TO REGISTER A PRESS, WITH ETH SHIELD ON
  {
      setPoint = setPoint + interval_SP;
      delay(150);
  }
  
  if (buttonState2 == HIGH)           //THIS IS TAKING LIKE 3 SECONDS TO REGISTER A PRESS, WITH ETH SHIELD ON
  {
      setPoint = setPoint - interval_SP;
      delay(150);
  }
  
}

You should connect, send the request, get the response, and close the connection when the server closes it (that is how you know it is finished sending). You are not doing the last two things.

I would move the entire connect, request, response and close into this routine. Something like this:

void pachube_PUT(String dataString) 
{
   if(client.connect())
   {
      // send request. You are doing this part.
      // get response until server closes the connection. You are not doing this.
      // client.stop() when server closes the connection. You are not doing this.
   }
   else
   {
      Serial.println("connection failed");
   }
}

Thank you for the input.

I'll only have a chance to go to the lab and test it next thursday. So you're saying that keeping the connection open all the time hogs the processing power? I can see why. I'll test it and then give some feedback.

It doesn't do anything to hog anything on the Arduino. The ethernet connection is handled by the w5100 chip on the shield.

However, if you try to keep the connection open for 15 minutes, that may cause problems.

My recommendation: Connect, send, receive, close. Wait 15 minutes. Connect, send, receive, close. Wait 15 minutes...

Alright I will test that next thursday.

I just remembered that although I didn't have the shield connected when running the first tests, I was running the exact same code, and it was working fine. It was when I connected the shield (and even without a cat5 cable on, so no physical connection for data transfer) that the problem began.

Thanks again.

Every iteration through the loop, it will wait for that connection attempt to timeout. If you try that only once every 15 minutes, you won't notice nearly as much. And when it can connect, it should move right along.

You seem to have nailed it on the head. I just commented the client.connect() line and it started working great again. I'll change it to only connect when it's time to send the data. Thank you very much :slight_smile: