In this fifth post for my enc28j60 tutorial, I’m going to show you how to use your ethernet shield to make Arduino act like a web server.
World Wide Web
Amongs the network services, the most used one is surely the web service: everytime you “surf” on a website, the program you use (named browser) connects to the web server hosting that site using HTTP protocol and gets the content (pages, images, videos…) to show.
Web pages are composed using a markup language named HTML; this language uses tags to describe page content.
The main advantages in using HTTP to talk with Arduino on a network connection are:
[checklist]
- you don’t need to develop a dedicated client, you can use a common internet browser (Internet Explorer, Firefox…);
- HTTP protocol is textual, you can easily manage it with Arduino’s string functions;
- HTML language is also textual, you can easily create pages -also dynamic ones- with Arduino.
[/checklist]
Program
I’m going to show you a simple program that prints on serial connection browser‘s requests and answers with a simple HTML page. This program is useful to understand how to use HTTP functions and also to find out which informations a browser sends within the request (you’ll learn how to use those informations in a coming post).
The complete sketch is available on GitHub’s repository, here is the most important code:
word len = ether.packetReceive(); word pos = ether.packetLoop(len); |
In the loop I save in a variable the return value of packetLoop() method: this value is the position, within the rx buffer, where browser’s request starts.
if(pos) { Serial.println("---------- NEW PACKET ----------"); Serial.println((char *)Ethernet::buffer + pos); Serial.println("--------------------------------"); Serial.println(); |
If pos is greater than zero, I really received a correct request and I can print it on serial port (buffer + pos is the position to start).
BufferFiller bfill = ether.tcpOffset(); |
To store the response I’m going to send to client’s browser, I use a BufferFiller object. This object inherits from Print class and its constructor gets as parameter the ethernet’s buffer address (tcpOffset) where the response has to be saved.
bfill.emit_p(PSTR("HTTP/1.0 200 OK\r\n" "Content-Type: text/html\r\nPragma: no-cache\r\n\r\n" "<html><body><h1>BasicServer Demo</h1></body></html>")); |
With emit_p() method I can save data in the buffer: for this example I create a simple HTML page that shows BasicServer Demo text. To save RAM memory space, I use PSTR() macro that stores strings in the PROGRAM.
ether.httpServerReply(bfill.position()); |
At last, with httpServerReply() method, I send the response to the browser. This method needs, as a parameter, the number of characters to be sent. I can get the number of characters BufferFiller contains with its method position().
Loaded the sketch, you can check if it’s ok typing in the address bar of your browser the IP address of your Arduino… the result should be like this:
And on your serial monitor:
You may ask why the browser sent two requests, one for the page “/” (that is the site’s homepage) and one for the image favicon.ico. That is the icon some sites show next to their address; here’s for example the icon from DangerousPrototypes:
sono assolutamente digiuno di informatica ed elettronica, ma ho molto apprezzato i tutorial per arduino che mi hanno aiutato a capire come connetterlo ad una rete. Vorrei ancora avere indicazioni per trasmettere dati a google spreadsheet (magari usando i moduli) e anche come impostare una porta diversa dalla 80 sulla quale ho già un altro webservver. grazie per il lavoro già fatto che ha condiviso.
Hai provato questa nuova libreria per ENC28j60 ??
https://github.com/turicas/Ethernet_ENC28J60
Ciao Mario,
no, non l’ho ancora provata… ad un primo sguardo sembra condividere molto codice di base con la EtherCard, anche se qualche parte sembra scritta in maniera più “pulita”…
Hello,
I found your tutorials very interesting. I have a question if you can help me.
I am trying to create a temperature sensor on a web page. I use ENC28j60 and the ethercard library.
How can i write down on the webpage the temperature that my sensor is sensing and another variable from my arduino program?
Another question is how to make buttons on the webpage act on a variable in my program.
Regards.
Hi Ciprian,
I’m working on a new tutorial with a more complex webserver… stay tuned 😉
ciao luca,
complimenti per il tutorial.
Sono riuscito a eseguirlo e ad integrarlo in una mia applicazione che legge degli impulsi da un contalitri e al momento li spedisce sulla seriale.
Tramite un timer, eseguo il codice relativo alla parte ethernet e riesco correttamente a collegarmi al server e visualizzare sul browser la pagina demo che hai proposto. In questa pagina, vorrei inserire il valore dei miei impulsi che è salvato in una variabile di tipo int. Ho provato a creare una stringa contenente la risposta HTTP ma quando faccio bfill.emit_p(PSTR(miastringa)); il compilatore mi da questo errore:
initializer fails to determine size of ‘__c’
Sono abbastanza nuovo di Arduino per cui non conosco ancora bene la sintassi e le best practices….hai un consiglio da darmi ?
Grazie!
Ciao Ettore!
“miastringa” è una stringa statica oppure una tua variabile?
Luca, thanks for your great tutorial, I have a question: I’d like to connect 3-4 EthernetArduinos via Ethernet and allow them to share files stored on their respective SD cards.
I’ve found examples for making the Arduino a web-server, but it needs a DHCP server being provided by e.g. a PC.
And it doesnt really allow one arduino to access the files on the other arduino’s SD card.
I was wondering if you think this would be possible and maybe give me a few pointers how to best go about it. Thank you in advance!
Peter
Hi Peter
you don’t need a DHCP server, you can configure ethernet shield with a static IP address using staticSetup().
I wasn’t able to find an example using SD card with enc28j60 shield… I’m working on it! 😉
Ciao Luca,
During the last days I learned a lot from you about the EtherCard library and collaboration with Arduino – Thanks!
However, I still got one for you: With “smaller” Arduinos I run into buffer size limitations. Do you know whether there is a way to split the response to the server in smaller chunks allowing to keep the message within the buffer size limits?
Thanks a lot in advance!
Axel
Hi Axel!
Unfortunately at the moment the EtherCard library doesn’t support TCP fragmentation and you’re required to buffer the entire packet in Arduino’s memory… The developers are working on a rewritten version of the library so keep an eye on its Github repository!
Hi!
how I can send a string to indicate the state of a digital input?
Thanks
Hi Pedro,
are you trying to display the state of a digital pin on a webpage? Or send it to a script/program?
Do the tutorials for the enc28j60 also work with ethernet shield & W5100?
no, the two ICs are very different… for W5100 you can refer to the official Arduino documentation.
Hi Luca!
Do you have any news about TCP fragmentation? I am working on this behavior and it getting me crazy!
Do you have contact with EtherCard developers? Do you think they would interest in my work?
Take a look at: https://github.com/renatoaloi
Please, if you can send me some feedback it will be very nice for my work. Thanks!
Renato
Hi Renato,
no, at the moment my workaround is the use of Yun, where the ethernet connection is managed by a Linux distribution. I contacted the authors of EtherCard via Github, I think they may be interested as I know they are rewriting the library to support such functionalities!
Hi, congratulations for tutorial!
Please help me..
In my serial monitor:
BasicServer Demo
Ethernet controller initialized
Failed to get configuration from DHCP
IP Address: 0.0.0.0
Netmask: 0.0.0.0
Gateway: 0.0.0.0
What wrong¿?
Hi Maryori,
it’s hard to find out what’s wrong… it seems that Arduino doesn’t receive a valid address: is a DHCP server active in your network? Try changing the Mac address in the sketch, it may help.
Ciao Luca,
vorrei usare il tuo code e ho provato a modificarlo solo che mi da sempre un errore il code sarebbe:
String temp = “hello”;
BufferFiller bfill = ether.tcpOffset();
bfill.emit_p(PSTR(“HTTP/1.0 200 OK\r\n”
“Content-Type: text/html\r\nPragma: no-cache\r\n\r\n”
“” + temp + “”));
ether.httpServerReply(bfill.position());
l’errore é:
bfill.emit_p(PSTR(temp));
error: array must be initialized with a brace-enclosed initializer
exit status 1
initializer fails to determine size of ‘__c’
hai qualche idea?
grazie mille!