This lesson takes you from understanding microcontrollers in theory to working with the two most widely used boards in IoT — the Arduino Uno and the ESP32.
The Arduino Uno — Key Specifications
| Specification |
Value |
| Microcontroller |
ATmega328P (8-bit AVR) |
| Clock Speed |
16 MHz |
| Flash Memory |
32 KB (0.5 KB used by bootloader) |
| SRAM |
2 KB |
| Operating Voltage |
5 V |
| Digital I/O Pins |
14 (of which 6 support PWM output) |
| Analog Input Pins |
6 (A0–A5), 10-bit ADC (0–1023) |
| DC Current per Pin |
40 mA maximum |
| USB Interface |
USB-B (square type), for programming and serial monitor |
Arduino Uno Pinout Reference
| Pin / Group |
Description |
| Digital Pins 0–13 |
GPIO digital I/O. Pins 0 (RX) and 1 (TX) used by Serial. Avoid for GPIO if using Serial. |
| Pins 3,5,6,9,10,11 |
PWM-capable digital pins (marked ~ on board). Output 0–255 via analogWrite(). |
| Analog Pins A0–A5 |
Analog input: reads 0–5 V and returns 0–1023 via analogRead(). Can also be used as digital GPIO. |
| 5V Pin |
Regulated 5 V output. Use to power 5 V sensors. Max ~400 mA total. |
| 3.3V Pin |
Regulated 3.3 V output. Max ~50 mA. Insufficient for ESP32 (which needs 500 mA+). |
| Pin 13 (LED_BUILTIN) |
Connected to the onboard LED. HIGH = ON, LOW = OFF. Use for quick testing. |
The ESP32 — Key Specifications
| Specification |
Value |
| Microcontroller |
Xtensa LX6 dual-core 32-bit processor (Espressif ESP32) |
| Clock Speed |
Up to 240 MHz (dual core) |
| Flash Memory |
4 MB (varies: 4 MB to 16 MB) |
| SRAM |
520 KB internal + external PSRAM option |
| Operating Voltage |
3.3 V (GPIO logic level — NOT 5 V tolerant!) |
| Digital I/O Pins |
34 programmable GPIO pins |
| Analog Input |
18 channels, 12-bit ADC (0–4095) |
| Wi-Fi |
802.11 b/g/n, 2.4 GHz (built-in) |
| Bluetooth |
Bluetooth 4.2 Classic + BLE (built-in) |
| PWM |
16 independent PWM channels |
| DAC |
2 × 8-bit Digital-to-Analog Converter outputs |
| Deep Sleep Current |
~10 µA (excellent for battery IoT) |
WARNING
ESP32 GPIO pins operate at 3.3 V logic. Applying 5 V to any GPIO pin WILL damage the chip over time. Always use a voltage divider or level shifter when interfacing with 5 V Arduino signals or sensors.
ESP32 Pinout — Key Pins
| Pin |
Function |
| GPIO 0 |
Boot mode selection. Must be HIGH for normal boot. Pull LOW to enter flash mode. |
| GPIO 2 |
Connected to onboard LED on most DevKit boards. HIGH = LED ON. |
| GPIO 34,35,36,39 |
Input-only pins — no internal pull-up/down. Good for analog inputs. |
| GPIO 6–11 |
Connected to internal Flash memory — NEVER use as GPIO. |
| GPIO 21 (SDA) |
Default I2C Data pin. Use for OLED displays, BME280, etc. |
| GPIO 22 (SCL) |
Default I2C Clock pin. |
| 3V3 Pin |
3.3 V regulated output. Powers sensors. Max ~600 mA from USB. |
| EN (Enable) |
Active-HIGH enable pin. Pull LOW to reset the ESP32. |
NOTE
Different ESP32 development boards (NodeMCU-32S, WROOM, WROVER) have slightly different pin layouts. Always check the specific pinout diagram for YOUR board before wiring.
Setting Up the Development Environment
Arduino IDE Installation
| Step |
Action |
| Step 1 |
Download Arduino IDE 2.x from arduino.cc/en/software. Choose your OS. |
| Step 2 |
Install the IDE. On Windows, accept driver installation for USB-Serial chip. |
| Step 3 |
Connect Arduino Uno via USB. Go to Tools → Board → Arduino AVR Boards → Arduino Uno. |
| Step 4 |
Go to Tools → Port → select the COM port (Windows) or /dev/ttyUSB0 (Linux). |
| Step 5 |
Open File → Examples → 01.Basics → Blink. Click Upload (arrow button). |
| Step 6 |
The onboard LED on pin 13 should blink once per second. Setup is confirmed. |
Adding ESP32 Board Support
| Step |
Action |
| Step 1 |
Go to File → Preferences (or Arduino → Settings on Mac). |
| Step 2 |
In ‘Additional boards manager URLs’, add: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json |
| Step 3 |
Go to Tools → Board → Boards Manager. Search ‘esp32’. Install ‘esp32 by Espressif Systems’. |
| Step 4 |
Connect ESP32 via USB. Go to Tools → Board → ESP32 Arduino → ESP32 Dev Module. |
| Step 5 |
Set Tools → Upload Speed → 115200. Set Tools → Port to your ESP32’s COM/tty port. |
| Step 6 |
Hold the BOOT button on the ESP32 during upload if it fails to connect automatically. |
| Step 7 |
Open File → Examples → WiFi → WiFiScan. Upload and open Serial Monitor (115200 baud). |
Digital Output — Core Functions
| Function |
Description |
| pinMode(pin, mode) |
Set a pin as OUTPUT, INPUT, or INPUT_PULLUP. Must call in setup(). |
| digitalWrite(pin, HIGH) |
Set digital output pin to HIGH (+5 V on Uno, +3.3 V on ESP32). |
| digitalWrite(pin, LOW) |
Set digital output pin to LOW (0 V / GND). |
| delay(ms) |
Pause execution for specified milliseconds. Blocks loop() — use with care. |
| millis() |
Returns milliseconds since board powered on. Use for non-blocking timing. |
| analogWrite(pin, value) |
Arduino Uno: outputs PWM signal 0–255 on PWM-capable pins (~). |
| ledcWrite(ch, duty) |
ESP32: outputs PWM. Must first configure with ledcSetup() and ledcAttachPin(). |
Traffic Light Circuit — Arduino Uno
| Pin |
Circuit Connection |
Purpose |
| Arduino Pin 4 |
220 Ω resistor → Red LED anode → LED cathode → GND |
Simulate RED phase |
| Arduino Pin 5 |
220 Ω resistor → Yellow LED anode → LED cathode → GND |
Simulate YELLOW phase |
| Arduino Pin 6 |
220 Ω resistor → Green LED anode → LED cathode → GND |
Simulate GREEN phase |
Arduino C++ — Traffic Light Simulation
// Unit 2 — Traffic Light Simulation
const int RED_PIN = 4;
const int YELLOW_PIN = 5;
const int GREEN_PIN = 6;
void setup() {
pinMode(RED_PIN, OUTPUT);
pinMode(YELLOW_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
}
void loop() {
// RED phase — 3 seconds
digitalWrite(RED_PIN, HIGH);
digitalWrite(YELLOW_PIN, LOW);
digitalWrite(GREEN_PIN, LOW);
delay(3000);
// YELLOW phase — 1 second
digitalWrite(RED_PIN, LOW);
digitalWrite(YELLOW_PIN, HIGH);
digitalWrite(GREEN_PIN, LOW);
delay(1000);
// GREEN phase — 3 seconds
digitalWrite(RED_PIN, LOW);
digitalWrite(YELLOW_PIN, LOW);
digitalWrite(GREEN_PIN, HIGH);
delay(3000);
}
TRY
Modify the code to add a pedestrian button on pin 7. When the button is pressed (INPUT_PULLUP, reads LOW), shorten the GREEN phase and trigger the pedestrian walk phase.
Digital Input — Button Reading with Debounce
Arduino C++ — Button Input with Software Debounce
const int BUTTON_PIN = 7;
const int LED_PIN = 13;
int ledState = LOW;
int lastButtonState = HIGH; // HIGH because INPUT_PULLUP
long lastDebounceTime = 0;
const long DEBOUNCE_DELAY = 50; // 50 ms debounce
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(LED_PIN, OUTPUT);
Serial.begin(9600);
}
void loop() {
int reading = digitalRead(BUTTON_PIN);
if (reading != lastButtonState) {
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > DEBOUNCE_DELAY) {
if (reading == LOW) { // Button pressed (pulled to GND)
ledState = !ledState;
digitalWrite(LED_PIN, ledState);
Serial.println("Button pressed!");
}
}
lastButtonState = reading;
}
KEY
Mechanical buttons ‘bounce’ — they rapidly open and close 10–100 times in the few milliseconds after being pressed. Without debounce logic, one press registers as many presses. Always debounce buttons in IoT code.
PWM — Analog-Like Output
| PWM Setting |
Effect (Arduino Uno, 5 V) |
| Duty cycle 0% (value 0) |
Pin always LOW → 0 V → LED off, motor stopped |
| Duty cycle 25% (value 64) |
~1.25 V effective → LED dim |
| Duty cycle 50% (value 128) |
~2.5 V effective → LED medium |
| Duty cycle 75% (value 192) |
~3.75 V effective → LED bright |
| Duty cycle 100% (value 255) |
5 V effective → LED full brightness |
Arduino C++ — PWM LED Fade
const int LED_PIN = 9; // Must be a PWM pin (~)
void setup() { pinMode(LED_PIN, OUTPUT); }
void loop() {
// Fade in
for (int brightness = 0; brightness <= 255; brightness++) {
analogWrite(LED_PIN, brightness);
delay(10);
}
// Fade out
for (int brightness = 255; brightness >= 0; brightness--) {
analogWrite(LED_PIN, brightness);
delay(10);
}
}
NOTE
ESP32 does NOT use analogWrite(). Instead use: ledcSetup(channel, freq, resolution), ledcAttachPin(pin, channel), then ledcWrite(channel, duty). The ESP32 has 16 independent PWM channels at configurable frequencies.
ESP32 Wi-Fi — Hello IoT World
Arduino C++ — ESP32 Wi-Fi Connection
#include <WiFi.h>
const char* ssid = "YourNetworkName";
const char* password = "YourPassword";
void setup() {
Serial.begin(115200);
Serial.print("Connecting to Wi-Fi");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nConnected!");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
}
void loop() {
// Cloud operations go here in later units
}
TRY
Run this code and open the Serial Monitor at 115200 baud. Note the IP address assigned to your ESP32. In Unit 6 you will use this address to send sensor data to a cloud dashboard.
Check Your Understanding — Lesson 2.2
?
1. What is the maximum safe current per GPIO pin on the Arduino Uno? What component is always needed between a GPIO pin and an LED to stay within this limit?
?
2. Why is analogWrite() not used on the ESP32? Write the three lines of ESP32 code needed to configure PWM on GPIO 18 at 5000 Hz with 8-bit resolution.
?
3. A student connects a 5 V Arduino output directly to an ESP32 GPIO input pin. What is the risk? How should the connection be made safely?