---

Friday, March 26, 2010

Simplified Ethernet Library for 28J60 Shield










With an Ethernet shield you can transform your Arduino into a tiny little web server. Not only that but a web server with Inputs and Outputs. So you can use it to measure things on an analog input and then access those readings from anywhere on the Internet. Or, if you like, you can use it as a remote control to turn things on and off.

There are two flavours of ethernet shield for the Arduino. There is the official one, based on the Wiznet W5100 chip and the unofficial but significantly cheaper board based on the 28J60 chip.

Nuelectronics sell a board based on this chip and have also produced a library to use it. There are also clones of this to be found on eBay, some of which have a neat little prototying area (see above)

The Nuelectronics library is very thorough, but not the easiest library in the world to use, so I decided to write a library that wrapped up this library with a simpler interface.

You can download the library from here but you will also need to download the Nuelectronics library from here.

Install both libraries into your Arduino environment by unzipping them into a folder called 'libraries' in your sketches directory.

You can now create a simple sketch like this hello world web server example:










#include "etherShield.h"
#include "ETHER_28J60.h"
static uint8_t mac[6] = {0x54, 0x55, 0x58, 0x10, 0x00, 0x24};                                        
static uint8_t ip[4] = {192, 168, 1, 15};                         
static uint16_t port = 80;
ETHER_28J60 ethernet;

void setup()
  ethernet.setup(mac, ip, port);
}

void loop()
{
  if (ethernet.serviceRequest())
  {
    ethernet.print("<H1>Hello World</H1>");
    ethernet.respond();
  }
}

This example just displays Hello World when you connect to it in a browser.

I have included some other examples that display the values at the analog ports, set a digital output and also echo the request parameters.


This is all heavily influenced by a posting I saw and now cannot find by some who had done a very similar thing to this. If you are reading this, please let me know so that I can give you the credit you deserve. I just kind of did things a slightly different way, and put it in a library rather than a set of functions.


The API is documented below:


Setup.
void setup(uint8_t macAddress[], uint8_t ipAddress[], uint16_t port);


Example:

static uint8_t mac[6] = {0x54, 0x55, 0x58, 0x10, 0x00, 0x24};                                                        
static uint8_t ip[4] = {192, 168, 1, 15};                         
static uint16_t port = 80;
ETHER_28J60 ethernet;

void setup()
  ethernet.setup(mac, ip, port);
}
You will need to find an ipAddress that is both in a valid range and unused on your local network.

The mac address just has to be unique on your network, so unless you have two of these boards on the network, the value above will be fine.

Servicing Web Requests


char* serviceRequest();
Example:




void loop()
{
  char* params;
  if (params = e.serviceRequest())
  {
    e.print("<H1>Web Remote</H1>");
    if (strcmp(params, "?cmd=on") == 0)
    {
      digitalWrite(outputPin, HIGH);
      e.print("<A HREF='?cmd=off'>Turn off</A>");
    }
    else
    {
      digitalWrite(outputPin, LOW);
      e.print("<A HREF='?cmd=on'>Turn on</A>");
    }
    e.respond();
  }
}

serviceRequest either returns null if there has not been an incoming web request to service, or it returns a string containing the request parameter string for the incoming request. The request string includes the '?' character.

In the example above, if the request parameter string is '?cmd=on' then the digital output is set high and the hyperlink to turn the output off is rendered. Otherwise, the digital output is set low and the hyperlink to turn it on is rendered.

This also shows how to write the response and make the final response to the browser's request.

Writing the Response

void print(char* text)
- adds a string of HTML to the response to be returned.

void print(int value);
- adds an integer displayed in decimal form to the response.

void respond();
- commits the response back to the requesting browser.

Some things to watch.
The board consumes about 250mA which seems a lot to me. When driven from a power adaptor rather than USB, that makes the Arduino board get pretty hot around the voltage regulator. So just be careful, particularly if you plan to put your project in a box.

If you start to get strange things happening with the code, and you are using a 168 Arduino, you may well be running out of memory. The examples in the library will work with a 168, but to do anything more substantial use a 328.


About the Author
These are my books. Click on the image below to find out more about them.


                                                                                                                           

52 comments:

Ben said...

AMAZING, so much easier to understand than the nuelectronics one, i've set it up with your code fine, but i've got a php file on my webserver than takes a GET value in a variable "Value" and put thats variables value into a mysql db.
What i cant work out is how, using your code, i can send the url with "GET http://localhost/index.php?value=(analog value)"

If you could put a bit of sample code that would be great!

Thanks

Simon Monk said...

Thanks Ben, glad you liked it.

Unfortunately the code that I wrote only lets the Arduino and Ethershield act as a web server. So it can serve HTML but not itself send web requests. That was going to be phase 2, but I wouldn't hold your breath, it will be a while before I get to it.

However, all is not lost. What you could do is use a javascript timer on your PHP to poll the Arduino periodically to get the reading and then put that reading into the database.

Hope this helps.

Simon.

Jean-Claude Wippler said...

There's another library here if you're interested - http://news.jeelabs.org/2010/05/31/jeenode-as-web-server/

Trystan Lea said...

Hello Simon, Thanks for putting this together, it is much easier to understand! did you have a go at making a client library? you inspired me to have a go at making one and I think its worked out quite well. I have documented it here: http://openenergymonitor.org/emon/node/80
It would be cool to see if we could combine both libraries in to one. I will try to have a go when I next get a moment and let you know.
Thanks, Trystan

Simon Monk said...

Trystan, I really haven't had the time. Your library looks great, so please feel free to combine the two. I'd just appreciate a credit in the header file :-)

PS Your open energy stuff looks really interesting.

Trystan Lea said...

Cool will do!

Unknown said...

Simon, you should help me out and serve up the Nuelectronics library as well as the website is dead.

Simon Monk said...

Hi, Nueclectronics site is back up.

Unknown said...

I can't make it work,
I've plug my Arduino Duemilanove with an eBay Ethernet board with the ENC28J60 on it (made by ekitszone or something).

Well when I plug the Arduino on it recognize it and I can program it well.

Then, I unplug the USB and plug the ethernet board and then plug back the USB.

At this point the USB does not recognize the arduino and when trying to access the IP that I've set (10.0.0.15) I get a request time out.

Any clues ?
Is it normal that the arduino is not being recognized by the USB when the ethernet is pluged on it ?


Thanks a lot
Yaniv

Unknown said...
This comment has been removed by the author.
Simon Monk said...

Yaniv,
With that hardware, you cannot use USB at the same time as Ethernet, as they both use pins 0 and 1 for serial communication.

Anonymous said...

Hello Simon,
your library is the most useful enhancement to my little development environment since Emacs. :)
I'm pretty new to the Arduino (and electronics at all) but I'm a very big fried of understandability and simplicity (especially in technics related stuff).

For my personal use, I made a little code-cleanup (nothing to speak of) and merged the etherShield library with your one into a single folder.

In this sense: great work!

Michael

PS: As you might already noted: english isn't my native language. :)

Anonymous said...

And I forgot: is it critical to increase the BUFFER_SIZE? 500 was too little for my needs, so I set it to 1000.

Michael

Simon Monk said...

Thanks Anonymous, glad it has been useful.

Are you going to post your enhancements somewhere?

Anonymous said...

My Changes aren't enhancements. I just changes the Indent style, renamed your class and library to Ethernet28J60 etc. As I already said it is nothing to speak of. The functionality is still the same. :)

Anonymous said...

Hi Simon!
I use Your library and examples to create Web-server with analog temperature sensor and controlled LED.
I use MK-duino http://mk-duino.narod.ru/ and MMX-ENC28J60 http://int.com.ua/index.php?option=com_content&task=view&id=31&Itemid=46
Server sends Temperature value and recives command to switch LED On/Off.
Arduino sends HTML page with instructioncon to auto-refresh it's content:
"<meta http-equiv=refresh content=1>"
But some time Arduino hung-up.
I guess this is result of Stack overflow.
Do You have any solution to this problem?
Vladimir

Simon Monk said...

Yes you are probably out of memory.

Are you using a 328 chip? That gives you a massive 2K to use. Instead of the 1K in a 168.

Anonymous said...

use ATmega8 with 1K RAM.
In past I had program AVR Butterfly with ATmega169. It has special methods for string constants located in Flash instead of RAM.
May be You will improve Your Library to use Flash ?

My e-m: kvi(at)mksat(point)net
Vladimir

Anonymous said...

Hi, Simon.
Is it possible to reduce buffer size here?
...\libraries\ETHER_28J60\ETHER_28J60.cpp
...
#define BUFFER_SIZE 500
...
I need web-server examle will works with 1K RAM without hung-up.
Vladimir

Simon Monk said...

You probably could - give it a go, you have the source code.

Anonymous said...

Hi, Simon.
I have tested examle "ethershield_webserver.pde"with ATmega8 with refresh option in HTML body
"< meta http-equiv=refresh content=1>".
It's work without hung-up.
But Your's example "ServeReadings.pde" with refresh option goes to hung-up after 2 minutes.
I am sorry that Your library "ETHER_28J60" has bugs.
I like Your library. I hope You will fixe bugs.
Vladimir

Anonymous said...

Hi, Simon.
What is start value for "plen" in first call "print()" in "ETHER_28J60.cpp"?
Vladimir

Simon Monk said...

Hi Vladimir,
Sadly I just don't have time to look into this at the moment. Please feel free to adapt / mend the library in any way you want.

Simon.

kauczuk said...

Gr8 job. I hope you will come back to this project in the future. I will try to implement the library for Arduino Mega. I let you know..

ubiquit23 said...

great job! thank you very much that you gave that nice piece of cod to the community.

greetings from Germany

Turicas' blog - criativo, né? said...

Hello Simon, good job!
I did not see all your code, but it appears that you wrote a whole HTTP-server library (not only TCP/IP stack).
Well, I started a project with the goal of turn the Ethernet examples found on Arduino's IDE compatbile with ENC28J60, so I'm rewriting all the socket layer, based on nuelectronics etherShield Library.

For now, TCP server connections work (with some limitations) and the web server example is working fine.

If do you want to know more, please see:

- Topic on Arduino Forum: http://arduino.cc/forum/index.php/topic,56057.0.html
- Project on GitHub: http://github.com/turicas/Ethernet_ENC28J60

Suven said...

Hi, first of all thank you for creating this wonderful library.
You seem to be the only one on the planet to be able to make sense of the Nuelectronics library!

Is it possible to send json strings using your library?If yes then how.

Also if say for example I type in this into my browser "http://192.168.1.15/{"name":"John","age":25}"
how can I retrieve the exact string which follows the / which in this case would be : {"name":"John","age":25}
Thank a lot in advance.

Simon Monk said...

Thanks very much.
You probably could use JSON. But then you would have to parse them on the Arduino.
I would just stick to a simple request parameter as in the examples with the library.

Suven said...

Hi Simon,
do you think it is possible to send multiple packets before closing the connection?
What i intend to do is to have an sdcard board attached to the arduino and enc28j60, read individual characters from a file on the sd card, fill the buffer with these and send the contents of the buffer as a packet over the ethernet. Then continue reading the file, begin filling the buffer again and send the packet again when the buffer is full.
Thanks.

Simon Monk said...

It should be ok yes. Give it a try :)

Suven said...

Hi Simon,
I tried sending the contents of a file from the sd card over ethernet using the enc28j60 and an arduuino uno but the problem is that the size of file that can be sent is limited by the buffer size defined and in the present library there is no way to send more than one packet.
How do you suggest i send multiple packets before closing the connection? Can you help me with this?
Thanks!

orengo said...

Dear, It´s a great Lib. But when I use a html temperatura with two decimals. It´s don´t works.

e.print(tempC);

The result is 28 not 28.34 !

How I public with decimals numbers.

Best for you.

JORGE ORENGO

Sinu said...

when I try compiling, say this error:

C:\DOCUME~1\AREATE~1\CONFIG~1\Temp\build2823184158983767047.tmp/HelloWorld.cpp:24: undefined reference to `ETHER_28J60::setup(unsigned char*, unsigned char*, unsigned int)'

Whats happend?? thanks.

Sinu

Simon Monk said...

Hi, it probably means your library is not installed in the right place. Or, you have not restarted Arduino after adding the library.

Carl said...

How to set gateway (Want make public webserver for led controlling).

Özden Özdemir said...

Hi Simon,
Thank you for the library you shared. I am getting following copliler errors and I don't know how to fix it.
C:\Program Files\arduino-0022\libraries\ETHER_28J60\ETHER_28J60.cpp: In member function 'char* ETHER_28J60::serviceRequest()':
C:\Program Files\arduino-0022\libraries\ETHER_28J60\ETHER_28J60.cpp:102: error: 'class EtherShield' has no member named 'ES_init_len_info'
C:\Program Files\arduino-0022\libraries\ETHER_28J60\ETHER_28J60.cpp:103: error: 'class EtherShield' has no member named 'ES_get_tcp_data_pointer'
C:\Program Files\arduino-0022\libraries\ETHER_28J60\ETHER_28J60.cpp:108: error: 'class EtherShield' has no member named 'ES_make_tcp_ack_from_any'
C:\Program Files\arduino-0022\libraries\ETHER_28J60\ETHER_28J60.cpp: In member function 'void ETHER_28J60::respond()':
C:\Program Files\arduino-0022\libraries\ETHER_28J60\ETHER_28J60.cpp:158: error: 'class EtherShield' has no member named 'ES_make_tcp_ack_from_any'
C:\Program Files\arduino-0022\libraries\ETHER_28J60\ETHER_28J60.cpp:159: error: 'class EtherShield' has no member named 'ES_make_tcp_ack_with_data'
Thanks in advance.
Ozden

Özden Özdemir said...
This comment has been removed by the author.
Anonymous said...

Hi, your lib work with this hardware?

http://www.ebay.co.uk/itm/ENC28J60-Ethernet-LEN-Network-Module-51-AVR-STM32-/180702040803?pt=LH_DefaultDomain_3&hash=item2a12ae52e3

Many thanks,
Vitor

Anonymous said...

Hi. Sorry for bothering.
I'd like to know if is there any way to increse the buffer that it's used on the ethernet.print function.

Thanks in advance.

Simon Monk said...

To increase the buffer size, find the file arduino/libraries/ETHER_28J60.cpp and modify BUFFER_SIZE

SI.

Pedro said...

Hi... I'm using your lib in a sketch (http://arduino.cc/forum/index.php/topic,74761.0.html) after a few interactions the arduino stops responding. Can you give me any idea/hint to solve this?
Thanks in advance,

Pedro

Simon Monk said...

Hi Pedro. A common reason for unexpected halting is that you have run out of memory in your sketch.

Anonymous said...

How i extension code for second,third led on/off?I try but no load...I make pulse on / off a/c and i want to change mode heat,cool,dry,fan,auto...buffer size?Thanks.

Anton Smirnov said...

Hello, Simon.

Thank you for the wrapper.
Does it support HTTP POST?

Thanks, 4ntoine.

Simon Monk said...

Sorry, no HTTP Post.

123 said...

hi Simon, Im using an ATmega to detect some values,this part i finished,now i would like to send the measured values via ENC28j60 to internet and open it as a HTML... do you have an C-code demonstrating the HTML in C?? or an example showing that... thanx

123 said...

hi Simon, Im using an ATmega to detect some values,this part i finished,now i would like to send the measured values via ENC28j60 to internet and open it as a HTML... do you have an C-code demonstrating the HTML in C?? or an example showing that... thanx

123 said...

hi Simon, Im using an ATmega to detect some values,this part i finished,now i would like to send the measured values via ENC28j60 to internet and open it as a HTML... do you have an C-code demonstrating the HTML in C?? or an example showing that... thanx

Omnimusha said...

hi, great job.
a wed client example ?

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

SukkoPera said...

Hi Simon, thanks for your work. I have a question: does your library use the ENC28J60's internal RAM for packet buffering?

SukkoPera said...

Hi Simon, thanks for your work. I have a question: does your library use the ENC28J60's internal RAM for packet buffering?

SukkoPera said...

Hi Simon, thanks for your work. I have a question: does your library use the ENC28J60's internal RAM for packet buffering?