Display Text on Arduino LCD from Web Page

The tutorial on how to send text from a web page to an Arduino LCD sets the Arduino, Ethernet shield and micro SD card up as a web server with LCD attached. Two HTML text inputs allow text to be sent to each line of the LCD from the web page hosted by the Arduino.

The image below shows the web page in a web browser that has sent text to the LCD.

Sending Text from a Web Page to Arduino LCD

Sending Text from a Web Page to Arduino LCD

Text is sent to the Arduino from the web browser over the network with an HTTP GET request when the button on the web page is clicked.

Go to the tutorial now →

HTML Text Box to Send Text to Arduino Web Server

An Arduino and Ethernet shield are used as a web server to host a web page that contains a text box. Text can be typed into the web page text box using a web browser and sent to the Arduino by clicking a button on the web page.

An HTML textarea is used in an HTML form to create the text box. JavaScript is used to send the text to the Arduino using a HTTP GET request when the button on the web page is clicked. This is useful for any Arduino project that needs to receive text from a web page using a text box.

The Arduino code for this project follows the format of the Ajax I/O web server from the Arduino Ethernet shield web server tutorial, except that it calls the JavaScript function that sends the GET request when the button on the web page is clicked rather than periodically sending the GET request to the Arduino web server.

The video below shows the Arduino web page being accessed by a web browser and text being sent to the Arduino.

 

Arduino Hardware, Software and HTML Page Setup

Hardware

An Arduino Uno and Arduino Ethernet shield with 2GB micro SD card were used to test the project. Most Arduino boards that are compatible with the Ethernet shield should work.

Setup

Copy the HTML from below to a file called index.htm on the micro SD card and insert it into the Ethernet shield micro SD card socket. Load the Arduino sketch from below to the Arduino — first change the MAC and IP address in the sketch to suit your own network. In the Arduino IDE Serial Monitor window, set the baud rate at the bottom of the window to 115200.

Running the Project

With the Arduino connected to the Ethernet network, first open the Serial Monitor window, then open a web browser and surf to the IP address set in the sketch. Text can be typed into the text box on the web page and sent to the Arduino. The Arduino will display the text in the Serial Monitor window if the line of text is not too long (the length is set by buffer arrays in the Arduino code).

Arduino Text Box Sketch

The Arduino text box sketch listing called text_area is shown below. Copy and paste it to the Arduino IDE.

/*--------------------------------------------------------------
  Program:      text_area

  Description:  Arduino web server that gets text from an HTML
                textarea text box on the hosted web page.
                The web page is stored on the micro SD card.
  
  Date:         23 June 2015
 
  Author:       W.A. Smith, http://startingelectronics.org
--------------------------------------------------------------*/

#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>
// size of buffer used to capture HTTP requests
#define REQ_BUF_SZ   90
// size of buffer that stores the incoming string
#define TXT_BUF_SZ   50

// MAC address from Ethernet shield sticker under board
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 0, 20);   // IP address, may need to change depending on network
EthernetServer server(80);       // create a server at port 80
File webFile;                    // the web page file on the SD card
char HTTP_req[REQ_BUF_SZ] = {0}; // buffered HTTP request stored as null terminated string
char req_index = 0;              // index into HTTP_req buffer
char txt_buf[TXT_BUF_SZ] = {0};  // buffer to save text to

void setup()
{
    // disable Ethernet chip
    pinMode(10, OUTPUT);
    digitalWrite(10, HIGH);
    
    Serial.begin(115200);       // for debugging
    
    // initialize SD card
    Serial.println("Initializing SD card...");
    if (!SD.begin(4)) {
        Serial.println("ERROR - SD card initialization failed!");
        return;    // init failed
    }
    Serial.println("SUCCESS - SD card initialized.");
    // check for index.htm file
    if (!SD.exists("index.htm")) {
        Serial.println("ERROR - Can't find index.htm file!");
        return;  // can't find index file
    }
    Serial.println("SUCCESS - Found index.htm file.");
    
    Ethernet.begin(mac, ip);  // initialize Ethernet device
    server.begin();           // start to listen for clients
}

void loop()
{
    EthernetClient client = server.available();  // try to get client

    if (client) {  // got client?
        boolean currentLineIsBlank = true;
        while (client.connected()) {
            if (client.available()) {   // client data available to read
                char c = client.read(); // read 1 byte (character) from client
                // limit the size of the stored received HTTP request
                // buffer first part of HTTP request in HTTP_req array (string)
                // leave last element in array as 0 to null terminate string (REQ_BUF_SZ - 1)
                if (req_index < (REQ_BUF_SZ - 1)) {
                    HTTP_req[req_index] = c;          // save HTTP request character
                    req_index++;
                }
                // last line of client request is blank and ends with \n
                // respond to client only after last line received
                if (c == '\n' && currentLineIsBlank) {
                    // send a standard http response header
                    client.println("HTTP/1.1 200 OK");
                    // remainder of header follows below, depending on if
                    // web page or XML page is requested
                    // Ajax request - send XML file
                    if (StrContains(HTTP_req, "ajax_inputs")) {
                        // send rest of HTTP header
                        client.println("Content-Type: text/xml");
                        client.println("Connection: keep-alive");
                        client.println();

                        // print the received text to the Serial Monitor window
                        // if received with the incoming HTTP GET string
                        if (GetText(txt_buf, TXT_BUF_SZ)) {
                          Serial.println("\r\nReceived Text:");
                          Serial.println(txt_buf);
                        }
                    }
                    else {  // web page request
                        // send rest of HTTP header
                        client.println("Content-Type: text/html");
                        client.println("Connection: keep-alive");
                        client.println();
                        // send web page
                        webFile = SD.open("index.htm");        // open web page file
                        if (webFile) {
                            while(webFile.available()) {
                                client.write(webFile.read()); // send web page to client
                            }
                            webFile.close();
                        }
                    }
                    // reset buffer index and all buffer elements to 0
                    req_index = 0;
                    StrClear(HTTP_req, REQ_BUF_SZ);
                    break;
                }
                // every line of text received from the client ends with \r\n
                if (c == '\n') {
                    // last character on line of received text
                    // starting new line with next character read
                    currentLineIsBlank = true;
                } 
                else if (c != '\r') {
                    // a text character was received from client
                    currentLineIsBlank = false;
                }
            } // end if (client.available())
        } // end while (client.connected())
        delay(1);      // give the web browser time to receive the data
        client.stop(); // close the connection
    } // end if (client)
}

// extract text from the incoming HTTP GET data string
// returns true only if text was received
// the string must start with "&txt=" and end with "&end"
// if the string is too long for the HTTP_req buffer and
// "&end" is cut off, then the function returns false
boolean GetText(char *txt, int len)
{
  boolean got_text = false;    // text received flag
  char *str_begin;             // pointer to start of text
  char *str_end;               // pointer to end of text
  int str_len = 0;
  int txt_index = 0;
  
  // get pointer to the beginning of the text
  str_begin = strstr(HTTP_req, "&txt=");
  if (str_begin != NULL) {
    str_begin = strstr(str_begin, "=");  // skip to the =
    str_begin += 1;                      // skip over the =
    str_end = strstr(str_begin, "&end");
    if (str_end != NULL) {
      str_end[0] = 0;  // terminate the string
      str_len = strlen(str_begin);

      // copy the string to the txt buffer and replace %20 with space ' '
      for (int i = 0; i < str_len; i++) {
        if (str_begin[i] != '%') {
          if (str_begin[i] == 0) {
            // end of string
            break;
          }
          else {
            txt[txt_index++] = str_begin[i];
            if (txt_index >= (len - 1)) {
              // keep the output string within bounds
              break;
            }
          }
        }
        else {
          // replace %20 with a space
          if ((str_begin[i + 1] == '2') && (str_begin[i + 2] == '0')) {
            txt[txt_index++] = ' ';
            i += 2;
            if (txt_index >= (len - 1)) {
              // keep the output string within bounds
              break;
            }
          }
        }
      }
      // terminate the string
      txt[txt_index] = 0;
      got_text = true;
    }
  }

  return got_text;
}

// sets every element of str to 0 (clears array)
void StrClear(char *str, char length)
{
    for (int i = 0; i < length; i++) {
        str[i] = 0;
    }
}

// searches for the string sfind in the string str
// returns 1 if string found
// returns 0 if string not found
char StrContains(char *str, char *sfind)
{
    char found = 0;
    char index = 0;
    char len;

    len = strlen(str);
    
    if (strlen(sfind) > len) {
        return 0;
    }
    while (index < len) {
        if (str[index] == sfind[found]) {
            found++;
            if (strlen(sfind) == found) {
                return 1;
            }
        }
        else {
            found = 0;
        }
        index++;
    }

    return 0;
}


Text Box HTML Page

Copy the HTML below and save it to a file called index.htm on the SD card.

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Text Box using textarea</title>
        <script>

        strText = "";
        
        function SendText()
        {
            nocache = "&nocache=" + Math.random() * 1000000;
            var request = new XMLHttpRequest();
            
            strText = "&txt=" + document.getElementById("txt_form").form_text.value + "&end=end";
            
            request.open("GET", "ajax_inputs" + strText + nocache, true);
            request.send(null);
        }
        </script>
    </head>

    <body onload="GetArduinoIO()">
        <form id="txt_form" name="frmText">
            <textarea name="form_text" rows="10" cols="40"></textarea>
        </form>
        <input type="submit" value="Send Text" onclick="SendText()" />
    </body>

</html>

How the Text Box Sketch Works

JavaScript embedded in the web page sends the text from the text box to the Arduino as part of a HTTP GET request when the button on the web page is clicked.

Format of the String

This image shows what the string looks like before it is sent to the Arduino.

HTML Text Box and Text String

HTML Text Box and Text String

The text from the text box is put between &txt= and &end=end before being sent. The Arduino uses this text to find the string in the incoming HTTP GET request.

When the text reaches the Arduino, it has been altered with the spaces in the text changed to %20 as shown in the image below.

String from the Text Box Received by Arduino

String from the Text Box Received by Arduino

The Arduino sketch must change %20 in the text back to spaces.

Processing the String in the Arduino Sketch

The function GetText() is used to get the text box string from the incoming HTTP GET request. The HTTP_req array holds the beginning of the incoming GET request as shown in the above image — starting with GET /ajax_inputs&txt…

The GetText() function first gets a pointer to the beginning of the text box string by searching for &txt= and then terminating the string when it finds &end. A for loop is used to copy the string to the txt array (which is a pointer to the global txt_buf array). While the copying is taking place, the code looks for spaces that are encoded as %20 and changes them into spaces.

Limitations of the Arduino Text Box Sketch

The sketch is limited by the size of the buffer that saves the incoming HTTP GET request as well as the size of the array that stores the string from the text box. These two array buffers have been kept small so that the code will be able to run on an Arduino Uno.

If the string from the text box is too big for the HTTP buffer on the Arduino so that the string is truncated before the terminating &end, then the text will not be displayed in the Serial Monitor window because the GetText() function will return false.

This is just a simple demonstration that uses GET to send text. It would be better to send the text using POST instead and this will be added as a tutorial at a later stage.

 

Improved Arduino Live Cricket Score Ticker

The new Arduino live cricket score ticker code improves on the previous version of the ticker by saving the XML live cricket results to a file on an SD card. This allows the cricket score data to be randomly accessed for the desired data. A micro SD card inserted into the micro SD card socket on the Arduino Ethernet shield is used for saving the XML file.

Parsing XML using Arduino

XML parsing functions used in this project can be used with similar Arduino projects that need to parse XML files. The functions are used to search for specified tags in the XML file and if found can then be used to find child tags in the parent tags. The functions are used to drill down to the desired child tag in order to extract the required data from these tags.

With the XML file saved to SD card, it is possible for a sketch to reliably parse the file even if the order of the tag attributes is changed. The previous ticker code tried to parse the XML file on the fly as it gets sent to the Arduino and therefore relies on the tags and attributes being in a specific order.

Memory Limitations

An Arduino MEGA is needed for the new ticker because the Arduino Uno does not have enough memory to run the sketch. The blog post that compares the amount of memory used by various sketches shows some example sketches and how much of the Arduino Uno memory they use. From this comparison, it can be seen that the Arduino Uno memory can get used up fairly quickly as sketches start to use more libraries and get slightly more complex than some of the example sketches.

Go to the Improved Arduino Cricket Score Ticker Code →

A Comparison of Arduino Sketch Sizes in Memory

A comparison of several Arduino sketches from the Arduino code examples, as well as some code that uses a combination of library functions, shows how much memory is used in an Arduino Uno. This gives a rough idea of what the Arduino Uno is capable of handling in terms of memory usage / sketch size before having to move up to an Arduino that has more memory such as the Arduino MEGA.

Memory Usage in the Arduino IDE

Older versions of the Arduino IDE only showed the amount of Flash memory (non-volatile memory) used by an Arduino sketch at compile time i.e. when the Verify icon is clicked on the toolbar.

Newer versions of the Arduino IDE now show both the amount of Flash memory and SRAM memory that a sketch will use after compiling. The amount of SRAM memory used does not include local variables, however the compiler message shows the amount of SRAM left for local variables.

Arduino IDE Showing Sketch Memory Usage

Arduino IDE Showing Sketch Memory Usage

 

 

 

 

 

 

 

 

 

 

 

The above image shows the Arduino IDE after compiling. The area below the sketch shows the messages from the compiler that displays the sketch memory usage.

Arduino Sketch Memory Usage Examples

The examples below show the memory usage reported by the Arduino IDE compiler. Arduino IDE version 1.6.4 compiling for an Arduino Uno is used for all the examples.

Most of the sketches can be found in the Arduino IDE examples under File –> Examples as shown below, a link is given to sketches that are not found in with the IDE examples. The SRAM usage does not include SRAM used by local variables. The Flash memory maximum size of 32,256 bytes is the Arduino Uno Flash memory size of 32,768 bytes, minus 0.5kB used for the boot loader program.

Blinking An LED

File –> Examples –> 01.Basics –> Blink
This simple sketch blinks the on-board LED on and off at a set interval.

Flash usage: 1,030 bytes (3%) of 32,256
SRAM usage: 9 bytes of 2,048

Reading Analog Input

File –> Examples –> 01.Basics –> AnalogReadSerial
Reads a single analog value and prints it to the serial port.

Flash usage: 2,382 bytes (7%) of 32,256
SRAM usage: 184 bytes (8%) of 2,048

Reading Digital Input

File –> Examples –> 01.Basics –> DigitalReadSerial
Reads the state of a single digital input and prints the result to the serial port.

Flash usage: 2,704 bytes (8%) of 32,256
SRAM usage: 184 bytes (8%) of 2,048

Using the String Object

File –> Examples –> 08.Strings –> StringLength
Measures the length of a string sent over the serial port using a String object.

Flash usage: 3,966 bytes (12%) of 32,256
SRAM usage: 300 bytes (14%) of 2,048

Getting SD Card Information

File –> Examples –> SD –> CardInfo
Used for testing a SD card.

Flash usage: 1,502 bytes (35%) of 32,256
SRAM usage: 1,348 bytes (65%) of 2,048

Writing To and Reading From the SD Card

File –> Examples –> SD –> ReadWrite
Writes text to a file on an SD card and then reads the text back from the file.

Flash usage: 12,930 bytes (40%) of 32,256
SRAM usage: 992 bytes (48%) of 2,048

A Simple Web Server

File –> Examples –> Ethernet –> WebServer
A simple web server that hosts a web page displaying values read from analog pins. Does not used the SD card.

Flash usage: 12,612 bytes (39%) of 32,256
SRAM usage: 552 bytes (26%) of 2,048

A Simple Web Client

File –> Examples –> Ethernet –> WebClient
A web client that fetches a web page from the Internet.

Flash usage: 14,568 bytes (45%) of 32,256
SRAM usage: 673 bytes (32%) of 2,048

Printing Text to a LCD

File –> Examples –> LiquidCrystal –> HelloWorld
Prints a message to an LCD.

Flash usage: 2,328 bytes (7%) of 32,256
SRAM usage: 55 bytes (2%) of 2,048

Displaying Text from the Serial Port on the LCD

File –> Examples –> LiquidCrystal –> SerialDisplay
Display text sent over the serial port to the Arduino.

Flash usage: 3,182 bytes (9%) of 32,256
SRAM usage: 214 bytes (10%) of 2,048

Web Server that Uses the SD Card

Basic web server that hosts a web page on the SD card from the Arduino Ethernet tutorial.

Flash usage: 22,806 bytes (70%) of 32,256
SRAM usage: 1,274 bytes (62%) of 2,048

Web Server that Uses the SD Card and LCD

This code is based on the above SD card web server, but also uses an LCD display to show some text during initialization and to display the amount of free SRAM.

#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>
#include <LiquidCrystal.h>

// MAC address from Ethernet shield sticker under board
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 0, 20); // IP address, may need to change depending on network
EthernetServer server(80);  // create a server at port 80

File webFile;
// have to change the pin numbers from the example defaults when using the Ethernet shield
LiquidCrystal lcd(3, 2, 8, 7, 6, 5);

int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

void setup()
{
    // set up the LCD's number of columns and rows:
    lcd.begin(16, 2);
    // Print a message to the LCD.
    lcd.print("Initializing...");
  
    Ethernet.begin(mac, ip);  // initialize Ethernet device
    server.begin();           // start to listen for clients
    Serial.begin(9600);       // for debugging
    
    // initialize SD card
    Serial.println("Initializing SD card...");
    if (!SD.begin(4)) {
        Serial.println("ERROR - SD card initialization failed!");
        return;    // init failed
    }
    Serial.println("SUCCESS - SD card initialized.");
    // check for index.htm file
    if (!SD.exists("index.htm")) {
        Serial.println("ERROR - Can't find index.htm file!");
        return;  // can't find index file
    }
    Serial.println("SUCCESS - Found index.htm file.");
    lcd.setCursor(0, 1);
    lcd.print("Done.");
}

void loop()
{
    EthernetClient client = server.available();  // try to get client

    if (client) {  // got client?
        boolean currentLineIsBlank = true;
        while (client.connected()) {
            if (client.available()) {   // client data available to read
                char c = client.read(); // read 1 byte (character) from client
                // last line of client request is blank and ends with \n
                // respond to client only after last line received
                if (c == '\n' && currentLineIsBlank) {
                    // send a standard http response header
                    client.println("HTTP/1.1 200 OK");
                    client.println("Content-Type: text/html");
                    client.println("Connection: close");
                    client.println();
                    // send web page
                    webFile = SD.open("index.htm");        // open web page file
                    if (webFile) {
                        while(webFile.available()) {
                            client.write(webFile.read()); // send web page to client
                        }
                        webFile.close();
                    }
                    lcd.clear();
                    lcd.setCursor(0, 0);
                    lcd.print("Free RAM:");
                    lcd.setCursor(0, 1);
                    lcd.print(freeRam());
                    break;
                }
                // every line of text received from the client ends with \r\n
                if (c == '\n') {
                    // last character on line of received text
                    // starting new line with next character read
                    currentLineIsBlank = true;
                } 
                else if (c != '\r') {
                    // a text character was received from client
                    currentLineIsBlank = false;
                }
            } // end if (client.available())
        } // end while (client.connected())
        delay(1);      // give the web browser time to receive the data
        client.stop(); // close the connection
    } // end if (client)
}

Flash usage: 24,100 bytes (74%) of 32,256
SRAM usage: 1,338 bytes (65%) of 2,048

Finding the Amount of Available SRAM at Runtime

The above sketch uses the freeRam() function from the Arduino Playground article on available memory to display the amount of available SRAM at runtime (while the sketch is running as opposed to at compile time).

The compiler shows the amount of free memory as 710 bytes available for local variables. The amount of free memory shown by the freeRam() function is 657 bytes at the time that the web page has been sent to the client. This available SRAM now takes into account the local variables that are in use and this is the reason that the runtime RAM available is less than the compile time RAM.

Comparing the Memory Usage Results

From the above memory usage results, it can be seen that some of the simpler sketches use less than 15% of available Flash and less than 15% of available SRAM. These are very simple sketches that only demonstrate a single principle.

The SD card read / write example starts approaching the half way mark of the available memory resources with the web client and  simple web server using less than half the memory resources.

As soon as more libraries are used together, memory usage goes over the 50% mark as is the case with the SD card web server at 70% Flash memory usage and  62% SRAM usage. This is still a relatively simple web server hosting a single static web page, but now including the SD card library.

When the LCD is added to the SD card web server, memory usage goes up to 74% for Flash and 65% for SRAM.

From the above, we can see that a simple sketch that uses multiple libraries can quickly use up available memory resources on an Arduino Uno. There are some techniques for making more efficient use of memory. One of the simplest ways to free up RAM is to use the F() macro to keep text in Flash memory so that it does not get copied to RAM at all. The F() macro can be applied to strings that are constant and aren’t modified at runtime.

Freeing Up SRAM

The same sketch above can be modified using the F() macro to put the text strings that are sent from the Arduino over the serial port, to the LCD and to the Ethernet client into Flash memory. For example, the string in the following line of code:

Serial.println("Initializing SD card...");

can be put into Flash memory like this:

Serial.println(F("Initializing SD card..."));

by putting the string including the opening and closing quotation marks into the brackets of the F() macro.

The above sketch will then look like this:

#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>
#include <LiquidCrystal.h>

// MAC address from Ethernet shield sticker under board
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 0, 20); // IP address, may need to change depending on network
EthernetServer server(80);  // create a server at port 80

File webFile;
// have to change the pin numbers from the example defaults when using the Ethernet shield
LiquidCrystal lcd(3, 2, 8, 7, 6, 5);

int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

void setup()
{
    // set up the LCD's number of columns and rows:
    lcd.begin(16, 2);
    // Print a message to the LCD.
    lcd.print(F("Initializing..."));
  
    Ethernet.begin(mac, ip);  // initialize Ethernet device
    server.begin();           // start to listen for clients
    Serial.begin(9600);       // for debugging
    
    // initialize SD card
    Serial.println(F("Initializing SD card..."));
    if (!SD.begin(4)) {
        Serial.println(F("ERROR - SD card initialization failed!"));
        return;    // init failed
    }
    Serial.println(F("SUCCESS - SD card initialized."));
    // check for index.htm file
    if (!SD.exists("index.htm")) {
        Serial.println(F("ERROR - Can't find index.htm file!"));
        return;  // can't find index file
    }
    Serial.println(F("SUCCESS - Found index.htm file."));
    lcd.setCursor(0, 1);
    lcd.print(F("Done."));
}

void loop()
{
    EthernetClient client = server.available();  // try to get client

    if (client) {  // got client?
        boolean currentLineIsBlank = true;
        while (client.connected()) {
            if (client.available()) {   // client data available to read
                char c = client.read(); // read 1 byte (character) from client
                // last line of client request is blank and ends with \n
                // respond to client only after last line received
                if (c == '\n' && currentLineIsBlank) {
                    // send a standard http response header
                    client.println(F("HTTP/1.1 200 OK"));
                    client.println(F("Content-Type: text/html"));
                    client.println(F("Connection: close"));
                    client.println();
                    // send web page
                    webFile = SD.open("index.htm");        // open web page file
                    if (webFile) {
                        while(webFile.available()) {
                            client.write(webFile.read()); // send web page to client
                        }
                        webFile.close();
                    }
                    lcd.clear();
                    lcd.setCursor(0, 0);
                    lcd.print(F("Free RAM:"));
                    lcd.setCursor(0, 1);
                    lcd.print(freeRam());
                    break;
                }
                // every line of text received from the client ends with \r\n
                if (c == '\n') {
                    // last character on line of received text
                    // starting new line with next character read
                    currentLineIsBlank = true;
                } 
                else if (c != '\r') {
                    // a text character was received from client
                    currentLineIsBlank = false;
                }
            } // end if (client.available())
        } // end while (client.connected())
        delay(1);      // give the web browser time to receive the data
        client.stop(); // close the connection
    } // end if (client)
}

This changes the original sketch memory usage from:
Flash: 24,100 bytes (74%)
SRAM: 1,338 bytes (65%) — 710 bytes for local variables
Runtime SRAM available: 657 bytes

To:
Flash: 24,170 bytes (74%)
SRAM: 1,086 bytes (53%) — 962 bytes for local variables
Runtime SRAM available: 909 bytes

Which frees up 253 bytes of memory for local variables.

The image below shows the above sketch running and reporting back the number of free bytes of SRAM available from the freeRam() function.

Arduino SD Card Web Server with LCD

Arduino SD Card Web Server with LCD Displaying Free SRAM after using the F() Macro

From this comparison of sketches on the Arduino Uno, it can be seen that the main limiting factor on the Arduino Uno is the amount of available memory. A relatively short sketch that uses functions or objects from several libraries can quickly use up 70% of available memory. Any sketch that gets slightly more complex can start approaching the 100% memory usage mark.

When available RAM becomes limited, there is good chance that the sketch can start exhibiting unexpected behaviour and even crash as the unavailability of RAM results in variables being overwritten. One technique has been shown that can help to reduce the amount of RAM used by a sketch.

How to Save a File from the Internet to an Arduino

The article on saving a web file to an Arduino shows how to get any file from the Internet using an Arduino and Ethernet shield and save the file to an SD card inserted into the Ethernet shield.

Two sketches are provided in the article — the first sketch saves the incoming HTTP header and the requested file. If a project requires further information from the HTTP header, it can be obtained from the file instead of trying to process the incoming header on-the-fly.

The second sketch in the article strips off the incoming HTTP header and saves only the requested file to the SD card.

Saving a web file to SD card first before accessing data from it allows the data to be randomly accessed in the file instead of trying to find data from the file in the incoming stream of bytes. This is useful for retrieving data from an XML file such as from a live sports or weather feed. Specific data fields can be randomly accessed from the saved file and then used by the Arduino.

Go to the Arduino Web File Article →