ESP8266 as an Arduino

ESP8266 on a carrier board.

The ESP8266 is a microcontroller WiFi module that allows you to connect to WiFi access points, or even create one. It is available as a tiny module or as a module on a carrier board. The one I chose is an ESP-12, with a "large" white carrier board.

This tutorial is different in that we will see how to replace the Arduino, in some cases, with the ESP8266 by itself. It has a 32-bit microcontroller on it, and thanks to the amazing work of many people, you can program your ESP8266 with the Arduino IDE.

Espressif makes the ESP8266. Their code gurus, along with many others, have contributed to the ESP8266 Arduino core, a collection of code that makes the ESP8266 "just another Arduino". You can pretty much write any code you would for an Arduino and run it on the ESP8266. Of course there is a limit to the I/O on some of the modules, but the Flash on the ESP-12 module is 4MB and the RAM is 80kB! Add to that the 80MHz 32-bit processor and you have a pretty impressive little Arduino.

A "Hello world" program on the ESP8266 turns out to be over 225kB, but that includes the core code. A program to go out on WiFi and download a page using HTTPS protocol is only 276kB. The only drawback I've found so far is the watchdog timer. There is a software timer and a hardware timer. You can disable the software timer. You can't disable the hardware timer. That means you have one second to finish setup() or loop() to prevent a dump and reset. I found this by fetching a web page into a string and pushing it out a software serial port at 9600 Baud. The wdt fired every time, even when I thought it was disabled. You can add "delay(1)" to your already time consuming loops and it will reset the watchdog, but outputting a string gives you no opportunity to break. Just something to keep in mind.

Programming and debugging are done at 115,200 Baud, the default for the module. It still takes a while to move a sketch to the module.

To begin, you must install the ESP8266 board files in the Arduino IDE. That is easy enough to do. Open the Arduino preferences and add one URL to the "Additional Boards Manager URLs". If there is already one there, use a comma to separate the URLs.

http://arduino.esp8266.com/package_esp8266com_index.json


Arduino board manager setting.
Windows Menu
Arduino board manager setting.
Windows Preferences

Arduino board manager setting.
Mac Menu
Arduino board manager setting.
Mac Preferences

To import the boards, close the Arduino IDE and re-open it. Hover on the "Tools->Board:" menu option and at the top of the pop-out menu is "Boards Manager". Click on that. When the Boards Manager opens, scroll to the bottom. You should see the esp8266 entry.

Arduino board manager setting.
Boards Manager Entry for ESP8266

Click on the entry and it changes to indicate you can install the boards:

Arduino board manager.
Boards Manager Entry for ESP8266 Install

Click on "Install" and after a few seconds of grinding the Boards Manager refreshes. Scroll down again to see that it says "Installed" in green after the name. If you click on the panel, a "Remove" button appears. You could click that to remove the ESP8266 from the Boards Manager, but don't. If all has gone well, clicking on the "Tools->Board:" menu option will now show you a list of ESP8266 boards at the bottom.

Arduino ESP8266 boards.
Your new ESP8266 options

These boards are the available choices. If your specific board is not mentioned, don't dispair. One of the choices will probably work fine. I have an ESP-12 module on a carrier board. As you can see, I chose the ESPino ESP-12 Module. The ESPino is just a USB to TTL converter with an ESP-12 module riding on it. All of the functionality is in the ESP-12.

I used an FTDI 3.3V USB to TTL dongle to upload the blink sketch below. The ESPP will require an external 3.3V power supply - the dongle does not have enough power to drive the ESPP8266! In fact, only run TX, RX, and ground to the ESPP8266 from the dongle.


void setup() {

  pinMode(5, OUTPUT);
  digitalWrite(5, HIGH);
}

void loop() {

  delay(500);
  digitalWrite(5,LOW);
  delay(500);
  digitalWrite(5, HIGH);

}
		

The ESP8266 requires a three pullup resistors and one pulldown resistor to set it up for programming. The schematic diagram shows where to place the resistors. The ability to ground GPIO0 and then reset the ESP is a requirement to enter programming mode. You can leave GPIO0 grounded as long as you are developing code on the device, but you will need to reset it to enter programming mode. With GPIO0 grounded, anything that resets the device puts it in programming mode. Removing the ground from GPIO0 causes resets to act like normal resets - on reset it will run whatever code is there.

Remember the ESP8266 is 3.3V and not 5V tolerant, so only run it on 3.3V, and with 3.3V USB to TTL cables! Also, if you get errors uploading, make sure you did the steps above.

To upload this sketch, you need to ground GPIO0 and push the reset switch. The ESP8266 will be put in upload mode. When the upload is done, the sketch will start running. If you reset with GPIO0 still grounded, the sketch will not start running because the ESP8266 will be in programming mode. To exit programming mode, remove the ground from GPIO0.

There are many sketches in the examples that come with the ESP8266 board files. Try a few of them out to get a feel for how simple it is to use the device and you may not go back to Arduino hardware if you just need WiFi and a microcontroller.

The following code POSTs a value to a secure server (this server) and prints the response. You'll want to plug in your own router's SSID and password. If a website is not secured with an SSL certificate, you can use the standard WiFiClient class, rather than the WiFiClientSecure class. The WiFiClientSecure class uses whatever cert the website offers, without checking, so it is not safe from man-in-the-middle attacks. You can check the cert yourself with a method of WiFiClientSecure, but it isn't part of this tutorial.

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>

const char* ssid     = "ssid";
const char* password = "password";
const char* host = "www.arduino-board.com";
const int httpsPort = 443;

void setup() {

  Serial.begin(115200);
  delay(1250);
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(250);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("WiFi connected (");

  Serial.print(WiFi.localIP());
  Serial.println(")");
  
  // Create TLS connection
  WiFiClientSecure client;
  Serial.print("connecting to ");
  Serial.println(host);
  if (!client.connect(host, httpsPort)) {
    Serial.println("connection failed");
    return;
  }

  String url = "/util/returnAgent";
  String content = "var=0123456789";

  client.print(String("POST ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "User-Agent: My User Agent\r\n" +
               "Content-Length: " + content.length() + "\r\n" +
               "Content-Type: application/x-www-form-urlencoded\r\n\r\n" + content);

  Serial.println("request sent");
  while (client.connected()) {
    String line = client.readStringUntil('\n');
    line.trim();
    Serial.println(line);
  }
  Serial.println("closing connection");
}

void loop() {
}
			

The result is something like this:

connecting to DAENET
...
WiFi connected
IP address: 192.168.1.73
connecting to www.arduino-board.com
request sent
HTTP/1.1 200 OK
Date: Fri, 03 Jun 2016 20:10:03 GMT
Server: Apache/2.4.12
X-Powered-By: PHP/5.4.43
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Set-Cookie: PHPSESSID=8e325371b103a5b483315d98454e1c0b; path=/
Vary: Accept-Encoding,User-Agent
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8

1a
0123456789 : My User Agent
0

closing connection
			

One more example. This one goes out to the NIST and gets the current time. If you have a few "getDateTime() failed" errors, increase the delay on line 21. If you get "Error connecting", don't look too hard for a solution on your end - these may be the busiest servers in the world. Be very careful with the 60 second delay at the end. If you hit them twice in a 4 second period they will blacklist your IP address, and you won't be allowed to use the service.

#include <ESP8266WiFi.h>
#include <WiFiClient.h>

const char* ssid     = "SSID";
const char* password = "PASSWORD";

const char* timeHost = "time.nist.gov";
const int timePort = 13;
const char* timeReq = "HEAD / HTTP/1.1\r\nAccept: */*\r\nUser-Agent: Mozilla/4.0 (compatible; ESP8266 ESP-12;)\r\n\r\n";

WiFiClient timeDateClient;

String getDateTime() {

  int retry = 3;
  while (!timeDateClient.connect(timeHost, timePort) && --retry)
  {
    delay(5000);
  }
  if (!retry)
  {
    return "Error connecting";
  }
  timeDateClient.print(timeReq);
  
  delay(750);
  
  String line = "Error no data";
  if (timeDateClient.available())
  {
    line = timeDateClient.readStringUntil('\r');
    line.trim();
  }
  return line;
}

void setup() {

  Serial.begin(115200);
  delay(1250);
}

void loop() {
  
  if (WiFi.status() != WL_CONNECTED) {
    Serial.print("\nConnecting to ");
    Serial.println(ssid);
    WiFi.begin(ssid, password);
  
    while (WiFi.status() != WL_CONNECTED) {
      delay(250);
      Serial.print(".");
    }
    Serial.println("");
    Serial.print("WiFi connected (");
    Serial.print(WiFi.localIP());
    Serial.println(")");
  }

  // Get the date and time from the NIST servers.
  Serial.println(getDateTime());
  delay(60000);
}
			

It will print out cryptic text like this:

57544 16-06-05 01:30:33 50 0 0 817.7 UTC(NIST) *
57544 16-06-05 01:31:34 50 0 0 180.1 UTC(NIST) *
57544 16-06-05 01:33:42 50 0 0 358.2 UTC(NIST) *
57544 16-06-05 01:34:44 50 0 0 736.5 UTC(NIST) *

The meaning of these lines is:

	57544 16-06-05 05:26:46 50 0 0 660.0 UTC(NIST) *
	DDDDD YR-MO-DA HH:MM:SS TT L H msADV HHHHHHHHH OTM
			
DDDDD The Modified Julian Date (MJD). The MJD has a starting point of midnight on November 17, 1858. You can obtain the MJD by subtracting exactly 2 400 000.5 days from the Julian Date, which is an integer day number obtained by counting days from the starting point of noon on 1 January 4713 B.C. (Julian Day zero).
YR-MO-DA YR-MO-DA is the date. It shows the last two digits of the year, the month, and the current day of month.
HH:MM:SS HH:MM:SS is the time in hours, minutes, and seconds. The time is always sent as Coordinated Universal Time (UTC). An offset needs to be applied to UTC to obtain local time. For example, Mountain Time in the U. S. is 7 hours behind UTC during Standard Time, and 6 hours behind UTC during Daylight Saving Time.
TT TT is a two digit code (00 to 99) that indicates whether the United States is on Standard Time (ST) or Daylight Saving Time (DST). It also indicates when ST or DST is approaching. This code is set to 00 when ST is in effect, or to 50 when DST is in effect. During the month in which the time change actually occurs, this number will decrement every day until the change occurs. For example, during the month of November, the U.S. changes from DST to ST. On November 1, the number will change from 50 to the actual number of days until the time change. It will decrement by 1 every day until the change occurs at 2 a.m. local time when the value is 1. Likewise, the spring change is at 2 a.m. local time when the value reaches 51.
L L is a one-digit code that indicates whether a leap second will be added or subtracted at midnight on the last day of the current month. If the code is 0, no leap second will occur this month. If the code is 1, a positive leap second will be added at the end of the month. This means that the last minute of the month will contain 61 seconds instead of 60. If the code is 2, a second will be deleted on the last day of the month. Leap seconds occur at a rate of about one per year. They are used to correct for irregularity in the earth's rotation. The correction is made just before midnight UTC (not local time).
H H is a health digit that indicates the health of the server. If H = 0, the server is healthy. If H = 1, then the server is operating properly but its time may be in error by up to 5 seconds. This state should change to fully healthy within 10 minutes. If H = 2, then the server is operating properly but its time is known to be wrong by more than 5 seconds. If H = 3, then a hardware or software failure has occurred and the amount of the time error is unknown. If H = 4 the system is operating in a special maintenance mode and both its accuracy and its response time may be degraded. This value is not used for production servers except in special circumstances. The transmitted time will still be correct to within ±1 second in this mode.
msADV msADV displays the number of milliseconds that NIST advances the time code to partially compensate for network delays. The advance is currently set to 50.0 milliseconds.
UTC(NIST) The label UTC(NIST) is contained in every time code. It indicates that you are receiving Coordinated Universal Time (UTC) from the National Institute of Standards and Technology (NIST).
OTM OTM (on-time marker) is an asterisk (*). The time values sent by the time code refer to the arrival time of the OTM. In other words, if the time code says it is 12:45:45, this means it is 12:45:45 when the OTM arrives.

So for projects which require WiFi and significant horsepower, the ESP8266 may be just what you need. At anywhere from $2 to $6 each, they are an economical alternative, too.

Arduino Board Logo

 

Arduino-Board is the go-to source for information on many available Arduino and Arduino-like boards, tutorials and projects.

Help and Support

Arduino-Board

Stay updated

Sign up if you would like to receive our once monthly newsletter.