The ADC (Analog-to-Digital Converter) in the ESP8266 allows the microcontroller to read analog signals and convert them into digital values for processing. Essential for interfacing with sensors and analog devices.
The ADC samples the input voltage on ADC0. The voltage is compared to the internal reference and mapped to a digital value within the 10-bit resolution. The digital value can then be read in code.
Accessible via GPIO0 (A0). Connect sensors ensuring voltage does not exceed 1.0 V to protect the ADC.
Example using Arduino IDE:
void setup() {
Serial.begin(115200); // Initialize serial communication
}
void loop() {
int adcValue = analogRead(A0); // Read ADC value
float voltage = adcValue * (1.0 / 1023.0); // Convert to 0-1V
Serial.print("ADC Value: ");
Serial.print(adcValue);
Serial.print(" | Voltage: ");
Serial.println(voltage);
delay(1000); // Wait 1 second
}
The ESP8266 ADC is a versatile feature for sensor monitoring and data acquisition. Its integration with the microcontroller makes it a key tool for IoT and embedded applications.
The I2C (Inter-Integrated Circuit) protocol allows multiple slave devices to communicate with a single master using two wires: SDA and SCL. The ESP8266 can act as an I2C master to control peripherals like sensors and displays.
The ESP8266 does not have hardware I2C, it is entirely software based and does not support slave mode.
The ESP8266 initiates communication by sending a start condition followed by the slave address, reads or writes data, and ends with a stop condition. The master controls the clock line for synchronized communication.
Example code using Arduino IDE:
#include <Wire.h>
#define SENSOR_ADDRESS 0x50 // Replace with your sensor's I2C address
void setup() {
Wire.begin(); // Join I2C bus as master
Serial.begin(115200); // Initialize serial communication
}
void loop() {
Wire.beginTransmission(SENSOR_ADDRESS); // Start communication
Wire.write(0x00); // Send command
Wire.endTransmission(); // End transmission
delay(100);
Wire.requestFrom(SENSOR_ADDRESS, 2); // Request 2 bytes
while (Wire.available()) {
int data = Wire.read();
Serial.println(data);
}
delay(1000); // Wait 1 second
}
Operating the ESP8266 as an I2C master enables reliable communication with various peripherals, making it ideal for sensor interfacing and IoT applications.
The ESP8266 features a basic I2S interface for audio output. It supports transmit (TX) only in master mode. I2S input (RX) is not supported. Commonly used for sending audio to an I2S DAC or amplifier.
GPIO3 (RX) – I2S Data Out (DOUT)GPIO0 – I2S Word Select (WS / LRCLK)GPIO2 – I2S Clock (SCK / BCLK)
#include <Arduino.h>
extern "C" {
#include "i2s_reg.h"
#include "i2s.h"
}
#define SAMPLE_RATE 44100
#define PI 3.14159265
uint16_t sineWave[256];
void setupI2S() {
i2s_begin();
i2s_set_rate(SAMPLE_RATE);
}
void generateSineWave() {
for (int i = 0; i < 256; i++) {
sineWave[i] = 0x8000 + 0x7FFF * sin(2 * PI * i / 256);
}
}
void setup() {
generateSineWave();
setupI2S();
}
void loop() {
for (int i = 0; i < 256; i++) {
while (!i2s_available()) delayMicroseconds(10);
i2s_write_sample(sineWave[i]);
}
}
Note: Use the i2s library available in ESP8266 Arduino core. Output is 16-bit mono, typically connected to an I2S DAC or class D amplifier.
Resources: ESP8266Audio, esp8266/Arduino
The SPI (Serial Peripheral Interface) is a synchronous serial communication protocol used for short-distance communication in embedded systems. The ESP8266 supports SPI in master and slave modes to interface with peripherals such as sensors, displays, and memory devices.
In master mode, the ESP8266 initiates communication and controls the clock line (SCK). It reads and writes data to one or multiple slaves and manages data flow effectively.
#include <SPI.h>
void setup() {
SPI.begin(); // Initialize SPI as master
pinMode(15, OUTPUT); // Set CS pin as output
digitalWrite(15, HIGH); // Deselect the slave
}
void loop() {
digitalWrite(15, LOW); // Select the slave
byte response = SPI.transfer(0x01); // Send a byte and receive response
digitalWrite(15, HIGH); // Deselect the slave
Serial.print("Response: ");
Serial.println(response, HEX); // Print response in hex
delay(1000); // Wait 1 second
}
In slave mode, the ESP8266 responds to commands from the master device and can send data back. The slave must wait for the master to initiate communication.
#include <SPI.h>
volatile byte dataReceived = 0;
void setup() {
SPI.begin(); // Initialize SPI
pinMode(15, INPUT); // CS pin as input
SPCR |= _BV(SPE); // Enable SPI in slave mode
}
ISR(SPI_STC_vect) {
dataReceived = SPDR; // Read received data
SPDR = dataReceived; // Echo back
}
void loop() {
if (dataReceived) {
Serial.print("Data received: ");
Serial.println(dataReceived, HEX); // Print received data
dataReceived = 0;
}
}
The ESP8266's SPI support in master and slave modes provides flexible, high-speed communication with various peripherals, essential for sensors, displays, and other fast data applications.
The ESP8266 features simple hardware timers used for scheduling tasks, handling delays, and generating PWM signals. Efficient use is critical due to limited timer resources.
Internal clock divided using a prescaler to control counting frequency, adjusting event timing.
Alarm triggers an interrupt, allowing time-critical tasks to be executed. Limited hardware makes these interrupts essential for precise operations.
ESP8266’s single hardware timer is essential for precise timing. Software timers can extend functionality but rely on interrupts, which may impact performance under heavy load.
Generate a 1kHz signal by toggling a pin using the hardware timer.
void setup() {
pinMode(2, OUTPUT);
timer1_attachInterrupt(togglePin);
timer1_enable(TIM_DIV1, TIM_EDGE, TIM_LOOP);
timer1_write(80000000 / (2 * 1000));
}
void togglePin() {
digitalWrite(2, !digitalRead(2));
}
void loop() {}
Generate a 25kHz PWM signal with 50% duty cycle on GPIO5.
void setup() {
pinMode(5, OUTPUT);
analogWriteFreq(25000);
analogWrite(5, 128);
}
void loop() {}
Generate a single pulse on a GPIO pin using one-shot timer mode.
void setup() {
pinMode(4, OUTPUT);
digitalWrite(4, LOW);
timer1_attachInterrupt(generatePulse);
timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE);
timer1_write(50000);
}
void generatePulse() {
digitalWrite(4, HIGH);
delayMicroseconds(100);
digitalWrite(4, LOW);
}
void loop() {}
Measure input signal frequency on GPIO12 using interrupts.
volatile unsigned long pulseCount = 0;
unsigned long prevMillis = 0;
unsigned long frequency = 0;
void IRAM_ATTR countPulse() {
pulseCount++;
}
void setup() {
pinMode(12, INPUT);
attachInterrupt(digitalPinToInterrupt(12), countPulse, RISING);
prevMillis = millis();
}
void loop() {
if (millis() - prevMillis >= 1000) {
frequency = pulseCount;
pulseCount = 0;
prevMillis = millis();
Serial.print("Frequency: ");
Serial.println(frequency);
}
}
Trigger an interrupt every 5 seconds using the hardware timer.
volatile bool timerFlag = false;
void IRAM_ATTR onTimer() {
timerFlag = true;
}
void setup() {
Serial.begin(115200);
timer1_attachInterrupt(onTimer);
timer1_enable(TIM_DIV16, TIM_EDGE, TIM_LOOP);
timer1_write(5000000);
}
void loop() {
if (timerFlag) {
Serial.println("Timer interrupt triggered");
timerFlag = false;
}
}
The ESP8266 microcontroller does not include a hardware Real-Time Clock (RTC). However, ESPConfig by Peter Dunne can provide real-time functionality by using NTP (Network Time Protocol) over Wi-Fi to synchronize time.
While NTP allows the ESP8266 to maintain accurate time when connected to the network, it has limitations: it requires Wi-Fi connectivity and periodic updates, and cannot maintain time during power loss or extended offline periods.
For applications where reliable timekeeping is a system requirement, you have two additional options:
Interrupts are a powerful feature in microcontrollers that allow the processor to respond to events without polling. The ESP8266 supports various types of interrupts that can enhance the responsiveness and efficiency of applications.
External interrupts can be triggered by changes in the state of a GPIO pin, such as rising or falling edges. The ESP8266 can respond to these changes to perform actions quickly.
#define BUTTON_PIN 4 // GPIO pin for button
void ICACHE_RAM_ATTR handleButtonPress() {
// Code to execute when button is pressed
}
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP); // Set button pin as input
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), handleButtonPress, FALLING);
}
void loop() {
// Main loop does other tasks
}
Serial interrupts can be used to respond to incoming data on the serial interface. This is useful for processing data as it arrives.
volatile bool dataReady = false;
void ICACHE_RAM_ATTR onReceive() {
dataReady = true; // Flag that data has been received
}
void setup() {
Serial.begin(115200);
Serial.setTimeout(100); // Set a timeout for Serial read
attachInterrupt(digitalPinToInterrupt(0), onReceive, RISING);
}
void loop() {
if (dataReady) {
String input = Serial.readString();
Serial.println("Received: " + input);
dataReady = false; // Clear the flag
}
}
Timer interrupts allow code to execute at defined intervals, enabling precise timing for tasks such as periodic sensor readings.
volatile bool timerFlag = false;
void IRAM_ATTR onTimer() {
timerFlag = true; // Set flag for main loop
}
void setup() {
Timer1.attachInterrupt(onTimer); // Attach interrupt
Timer1.enable(TIMER1); // Start timer
}
void loop() {
if (timerFlag) {
// Execute periodic task
timerFlag = false; // Reset flag
}
}
SPI interrupts are typically managed through callback functions when using libraries. However, you can still handle events by checking the SPI buffer in a regular loop or using an external interrupt to signal when data is ready.
#define SPI_CS_PIN 15
void ICACHE_RAM_ATTR handleSPI() {
// Handle SPI data reception
}
void setup() {
pinMode(SPI_CS_PIN, OUTPUT);
attachInterrupt(digitalPinToInterrupt(SPI_CS_PIN), handleSPI, FALLING);
}
void loop() {
// Main loop can perform other tasks
}
WiFi events can trigger interrupts when the ESP8266 connects to a network or receives data. You can use callback functions to handle these events.
void onWiFiEvent(WiFiEvent_t event) {
switch (event) {
case SYSTEM_EVENT_STA_START:
Serial.println("WiFi started");
break;
case SYSTEM_EVENT_STA_CONNECTED:
Serial.println("Connected to WiFi");
break;
// Handle other events
}
}
void setup() {
WiFi.onEvent(onWiFiEvent); // Attach WiFi event handler
WiFi.begin("yourSSID", "yourPASSWORD"); // Start WiFi connection
}
void loop() {
// Main loop can perform other tasks
}
The ESP8266 offers versatile interrupt capabilities across various functionalities, enabling efficient and responsive applications. By leveraging these interrupts, developers can create responsive and efficient systems that interact seamlessly with external events.
Unlike some modern microcontrollers, the ESP8266 does not provide true Direct Memory Access (DMA) support. While certain peripherals like UART and SPI have internal FIFOs that can handle small buffers autonomously, these are not full DMA engines. All larger data transfers still require CPU intervention, limiting high-speed or low-latency operations.
Implications:
The ESPconfig library by Peter Dunne simplifies configuration of ESP8266 and ESP32 devices. It supports WiFi setup, OTA updates, and web-based management. The library allows operation in WiFi client, access point, and relay modes.
Source Code: ESPconfig GitHub
#include "sysconfig8266.h";
void setup() {
Serial.begin(115200);
sysConfig.init();
Serial.println("Ready.");
}
void loop() {
sysConfig.run();
}
The ESPconfig library initializes WiFi, OTA, NTP, and optional Bluetooth (ESP32 only). It runs a web-based configuration portal if WiFi credentials are missing or connection fails.
The Admin Page uses Unicode glyphs as icons to reduce overhead.
The Information page shows device overview and details.
// Connect ESP8266 to an existing WiFi network
#include <ESP8266WiFi.h>
const char* ssid = "your_SSID";
const char* password = "your_PASSWORD";
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
Serial.println("Connecting to WiFi...");
while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.print("."); }
Serial.println("\nWiFi connected.");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
}
void loop() { }
Connects ESP8266 to a WiFi network and prints its IP address.
// ESP8266 as WiFi Access Point with web server
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
const char* ssid = "ESP8266_Access_Point";
const char* password = "12345678";
ESP8266WebServer server(80);
void handleRoot() { server.send(200, "text/plain", "Hello from ESP8266!"); }
void setup() {
Serial.begin(115200);
WiFi.softAP(ssid, password);
Serial.print("Access Point IP: "); Serial.println(WiFi.softAPIP());
server.on("/", handleRoot);
server.begin();
Serial.println("Web server started.");
}
void loop() { server.handleClient(); }
ESP8266 creates a WiFi network and runs a basic web server.
// ESP8266 as Client and AP simultaneously
#include <ESP8266WiFi.h>
const char* ssid = "your_SSID";
const char* password = "your_PASSWORD";
const char* apSSID = "ESP8266_Relay";
const char* apPassword = "relay_pass";
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.print("."); }
Serial.println("\nConnected to WiFi. IP: "); Serial.println(WiFi.localIP());
WiFi.softAP(apSSID, apPassword);
Serial.print("Access Point IP: "); Serial.println(WiFi.softAPIP());
}
void loop() { }
Extends WiFi coverage by acting as both client and access point.
The ESP8266 is a low-cost Wi-Fi microchip with full TCP/IP stack and microcontroller capabilities. It is widely used in IoT applications due to affordability, ease of use, and robust features.
The ESP8266 can be programmed using the Arduino IDE via a USB-to-serial adapter. Example code to connect to Wi-Fi:
#include <ESP8266WiFi.h>
const char* ssid = "your_SSID";
const char* password = "your_PASSWORD";
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi!");
}
void loop() {
// Your main code
}
Image: from GitHub "Googler00tGER / NodeMCU‑ESP12E‑pinouts". Check the repo for license. (GitHub repo)
The ESP8266 is a popular choice in the maker and IoT communities due to its low cost, simplicity, and versatility, suitable for both simple Wi-Fi devices and complex IoT systems.
| Board | CPU Speed | RAM | Flash Memory | Peripherals | Operating Voltage | Other Specifications |
|---|---|---|---|---|---|---|
| ESP8266-01 | 80 MHz | 64 KB | 512 KB - 1 MB | 2 GPIO, UART, SPI | 3.3V | Basic Wi-Fi module, minimal GPIO |
| ESP8266 NodeMCU | 80/160 MHz | 128 KB | 4 MB | 11 GPIO, UART, SPI, I2C, ADC, PWM | 3.3V | Popular development board, Lua-based firmware, USB interface |
| ESP8266 WeMos D1 Mini | 80/160 MHz | 128 KB | 4 MB | 11 GPIO, UART, SPI, I2C, ADC, PWM | 3.3V | Compact size, Arduino IDE compatible, widely used in IoT projects |
| ESP8285 ESP-M2 | 80/160 MHz | 64 KB | 1 MB | 8 GPIO, UART, SPI | 3.3V | Built-in flash, space-constrained designs |
| ESP8285 ESP-01F | 80/160 MHz | 64 KB | 1 MB | 4 GPIO, UART, SPI | 3.3V | Miniature form factor, built-in flash |
| ESP8266 ESP-12E | 80/160 MHz | 128 KB | 4 MB | 17 GPIO, UART, SPI, I2C, ADC | 3.3V | Popular variant for IoT applications |
| ESP8266 ESP-12F | 80/160 MHz | 128 KB | 4 MB | 17 GPIO, UART, SPI, I2C, ADC | 3.3V | Improved antenna design compared to ESP-12E |
| ESP8266 Huzzah | 80/160 MHz | 128 KB | 4 MB | 9 GPIO, UART, SPI, I2C, ADC | 3.3V | Adafruit's breadboard-friendly ESP8266 version |
ESP8266EX® is a trademark of Espressif Systems. Visit Espressif Systems website. Download ESP8266EX Datasheet (PDF).
© 2025 Espressif Systems. All rights reserved.
Sources for ESP8266EX and various ESP32 modules (Classic, S2, C3, C6, S3). Ideal for IoT and WiFi/BLE projects.