Embedded Systems and IoT - Complete Mastery
Introduction: Computing Beyond Computers
Embedded systems are specialized computing devices dedicated to performing specific tasks. Unlike general-purpose computers, they are purpose-built with constraints:
- Limited Resources: Low power, small memory, restricted processing
- Real-Time Requirements: Must respond within time constraints
- Reliability: Often work unsupervised for years
- Cost-Sensitive: Mass production demands efficiency
Common Applications:
- Smart home devices (Alexa, Google Home)
- Automotive systems (engine control, infotainment)
- Medical devices (pacemakers, monitors)
- Industrial IoT (sensors, controllers)
- Consumer electronics (smartwatches, fitness trackers)
- Mobile devices (phones, tablets)
This guide covers microcontroller fundamentals and IoT development.
1. Microcontroller Basics
Arduino Platform
Arduino: Beginner-friendly microcontroller platform
- Open-source hardware and software
- Easy programming (simplified C/C++)
- Large community and libraries
- Affordable boards ($20-50)
Popular Boards:
Arduino Uno: Most common, 16KB RAM, 32KB Flash
Arduino MKR WiFi 1010: WiFi connectivity, 32KB RAM
Arduino Due: High performance, 96KB RAM
Arduino Nano: Compact, embedded useHardware Components
Essential Parts:
1. Microcontroller (MCU): Brain of the system
- Processor: CPU core
- Memory: RAM, Flash, EEPROM
- I/O Pins: Digital, Analog
2. Power Supply: Battery or external
3. Crystal Oscillator: Clock signal for timing
4. Reset Circuit: Boot microcontroller
5. I/O Interfaces:
- Digital pins (HIGH/LOW)
- Analog pins (0-1023 values)
- Serial pins (communication)
6. Sensors: Collect data
- Light (LDR)
- Temperature (DHT22)
- Motion (PIR)
- Distance (HC-SR04 ultrasonic)
- Accelerometer (MPU6050)
7. Actuators: Perform actions
- LED: Visual output
- Motor: Movement
- Relay: Switch high voltage
- Buzzer: Sound outputArduino Development Environment
// Arduino sketch structure
// setup(): Runs once at startup
void setup() {
Serial.begin(9600); // Serial communication
pinMode(LED_PIN, OUTPUT); // Set pin mode
pinMode(BUTTON_PIN, INPUT);
}
// loop(): Runs repeatedly
void loop() {
int buttonState = digitalRead(BUTTON_PIN);
if (buttonState == HIGH) {
digitalWrite(LED_PIN, HIGH); // Turn LED on
Serial.println("LED ON");
} else {
digitalWrite(LED_PIN, LOW); // Turn LED off
Serial.println("LED OFF");
}
delay(100); // Wait 100ms
}
// Pin modes:
// INPUT: Read from pin
// OUTPUT: Write to pin
// INPUT_PULLUP: Read with internal pullup resistor
// Digital I/O:
// digitalWrite(pin, HIGH/LOW) - Set digital output
// digitalRead(pin) - Read digital input
// Analog I/O (0-1023):
// analogWrite(pin, value) - PWM output (0-255)
// analogRead(pin) - Read analog input2. Sensors and Sensor Integration
Analog Sensors
// Temperature Sensor (LM35)
// 10mV per degree Celsius
const int TEMP_PIN = A0;
void setup() {
Serial.begin(9600);
}
void loop() {
int rawValue = analogRead(TEMP_PIN);
// Convert to voltage (0-5V)
float voltage = (rawValue / 1023.0) * 5.0;
// Convert to temperature
// LM35: 10mV/°C, so 0.01V = 1°C
float temperature = voltage * 100.0;
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.println("°C");
delay(1000); // Read every second
}Digital Sensors
// Ultrasonic Sensor (HC-SR04)
// Measure distance by measuring echo time
const int TRIG_PIN = 9;
const int ECHO_PIN = 10;
void setup() {
Serial.begin(9600);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
}
void loop() {
// Send ultrasonic pulse
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
// Measure echo time
long duration = pulseIn(ECHO_PIN, HIGH);
// Calculate distance
// Speed of sound = 343 m/s = 0.0343 cm/µs
// Distance = speed × time / 2 (round trip)
float distance = (duration * 0.0343) / 2;
Serial.print("Distance: ");
Serial.print(distance);
Serial.println("cm");
delay(100);
}I2C Communication
// I2C: Two-wire protocol (SDA, SCL)
// Multiple devices on same bus
// Addresses identify devices
#include <Wire.h>
const int MPU6050_ADDR = 0x68; // I2C address
void setup() {
Serial.begin(9600);
Wire.begin(); // Join I2C bus
}
void loop() {
// Read from accelerometer (axes: X, Y, Z)
Wire.beginTransmission(MPU6050_ADDR);
Wire.write(0x3B); // Accelerometer data register
Wire.endTransmission(false);
// Request 6 bytes (2 per axis)
Wire.requestFrom(MPU6050_ADDR, 6, true);
if (Wire.available() >= 6) {
int16_t accelX = Wire.read() << 8 | Wire.read();
int16_t accelY = Wire.read() << 8 | Wire.read();
int16_t accelZ = Wire.read() << 8 | Wire.read();
Serial.print("X: "); Serial.print(accelX);
Serial.print(" Y: "); Serial.print(accelY);
Serial.print(" Z: "); Serial.println(accelZ);
}
delay(500);
}SPI Communication
// SPI: Serial Peripheral Interface
// Faster than I2C, separate chip selects
// Master-slave architecture
#include <SPI.h>
const int CS_PIN = 10;
const int MOSI = 11; // Master Out, Slave In
const int MISO = 12; // Master In, Slave Out
const int CLK = 13; // Clock
void setup() {
Serial.begin(9600);
pinMode(CS_PIN, OUTPUT);
digitalWrite(CS_PIN, HIGH); // Chip select inactive
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV16);
}
void loop() {
// Communicate with SPI slave
digitalWrite(CS_PIN, LOW); // Select slave
byte response = SPI.transfer(0xA5); // Send byte, receive byte
digitalWrite(CS_PIN, HIGH); // Deselect slave
Serial.println(response, HEX);
delay(1000);
}3. Communication Protocols
UART (Serial Communication)
// Send/receive text over serial port
// Baud rate: 9600, 115200, etc.
void setup() {
Serial.begin(9600); // Initialize serial
}
void loop() {
// Send data
Serial.print("Hello ");
Serial.println("World"); // println adds newline
// Receive data
if (Serial.available() > 0) {
char received = Serial.read();
Serial.print("Received: ");
Serial.println(received);
}
delay(1000);
}
// Serial Monitor: View output in Arduino IDE
// Tools → Serial Monitor → 9600 baudWiFi Connectivity
// Arduino MKR WiFi 1010 with WiFi
#include <WiFi.h>
char ssid[] = "NetworkName";
char pass[] = "Password";
void setup() {
Serial.begin(9600);
// Connect to WiFi
Serial.println("Connecting to WiFi...");
while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
Serial.print(".");
delay(1000);
}
Serial.println("\nWiFi connected!");
Serial.print("IP: ");
Serial.println(WiFi.localIP());
}
void loop() {
// Use WiFi for IoT
}MQTT (IoT Communication)
// Lightweight publish-subscribe protocol
// Perfect for IoT devices
#include <WiFi.h>
#include <ArduinoMqttClient.h>
WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);
const char broker[] = "mqtt.example.com";
int port = 1883;
const char topic[] = "home/temperature";
void setup() {
Serial.begin(9600);
WiFi.begin(ssid, pass); // Connect as before
// Connect to MQTT broker
while (!mqttClient.connect(broker, port)) {
Serial.print("MQTT connection failed: ");
Serial.println(mqttClient.connectError());
delay(1000);
}
Serial.println("MQTT connected!");
}
void loop() {
// Read temperature sensor
int temperature = readTemperature();
// Publish to MQTT topic
String payload = String(temperature);
mqttClient.publish(topic, payload);
Serial.print("Published: ");
Serial.println(payload);
delay(5000); // Publish every 5 seconds
}4. Real-Time Operating Systems (RTOS)
FreeRTOS Basics
// Real-time OS for embedded systems
// Enables multitasking on single-core MCU
#include <Arduino.h>
#include <FreeRTOS.h>
#include <task.h>
// Task 1: Read sensor
void sensorTask(void *pvParameters) {
while (1) {
int reading = analogRead(A0);
Serial.print("Sensor: ");
Serial.println(reading);
vTaskDelay(pdMS_TO_TICKS(1000)); // Delay 1 second
}
}
// Task 2: Control output
void controlTask(void *pvParameters) {
while (1) {
digitalWrite(LED_PIN, HIGH);
vTaskDelay(pdMS_TO_TICKS(500));
digitalWrite(LED_PIN, LOW);
vTaskDelay(pdMS_TO_TICKS(500));
}
}
void setup() {
Serial.begin(9600);
pinMode(LED_PIN, OUTPUT);
// Create tasks
xTaskCreate(
sensorTask, // Function to execute
"SensorTask", // Task name
128, // Stack size (bytes)
NULL, // Parameters
1, // Priority (0=low, 4=high)
NULL // Task handle
);
xTaskCreate(
controlTask,
"ControlTask",
128,
NULL,
1,
NULL
);
}
void loop() {
// FreeRTOS scheduler runs tasks
// loop() not needed with FreeRTOS
}
// Benefits:
// - Tasks run "concurrently"
// - Scheduler switches between tasks
// - No need for complex state machines
// - Responsive real-time behaviorTask Synchronization
#include <FreeRTOS.h>
#include <task.h>
#include <queue.h>
// Queue for communication between tasks
QueueHandle_t dataQueue;
void producerTask(void *pvParameters) {
while (1) {
int sensorValue = analogRead(A0);
// Send to queue
xQueueSend(dataQueue, &sensorValue, portMAX_DELAY);
vTaskDelay(pdMS_TO_TICKS(500));
}
}
void consumerTask(void *pvParameters) {
int receivedValue;
while (1) {
// Receive from queue
if (xQueueReceive(dataQueue, &receivedValue, portMAX_DELAY)) {
Serial.print("Received: ");
Serial.println(receivedValue);
}
}
}
void setup() {
Serial.begin(9600);
// Create queue (10 items, size of int)
dataQueue = xQueueCreate(10, sizeof(int));
xTaskCreate(producerTask, "Producer", 128, NULL, 1, NULL);
xTaskCreate(consumerTask, "Consumer", 128, NULL, 1, NULL);
}
void loop() {}5. IoT Architecture
Edge Device (Arduino)
┌─ Sensors ─┐
│ • Temperature
│ • Humidity
│ • Motion
└───────────┘
↓
┌─ Edge Device ─────┐
│ Arduino/ESP32 │
│ • Process data │
│ • Local decision │
│ • Filter noise │
└──────┬─────────────┘
↓
WiFi/4G/LoRaWAN
↓
┌─ Cloud Server ────┐
│ • Store history │
│ • Analytics │
│ • Machine Learning │
└────────────────────┘IoT Communication Protocols Comparison
Protocol Range Power Bandwidth Latency Use Case
Bluetooth 10m Medium 1Mbps Low Wearables
WiFi 100m High 54Mbps Low Home automation
LoRaWAN 10km Very Low 50kbps Medium Long-range sensors
NB-IoT 10km Very Low 250kbps Medium Cellular IoT
Zigbee 100m Very Low 250kbps Medium Smart home
6LoWPAN 100m Very Low 250kbps Medium Smart gridCloud Integration Example
// Arduino sending data to cloud
// Using HTTPClient library
#include <WiFi.h>
#include <HTTPClient.h>
void setup() {
Serial.begin(9600);
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
Serial.println("Connected to WiFi");
}
void loop() {
// Read sensor
float temperature = readTemperature();
float humidity = readHumidity();
// Create JSON payload
String jsonData = "{";
jsonData += "\"temperature\":" + String(temperature) + ",";
jsonData += "\"humidity\":" + String(humidity);
jsonData += "}";
// Send to cloud
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
http.begin("http://api.example.com/data");
http.addHeader("Content-Type", "application/json");
int httpCode = http.POST(jsonData);
if (httpCode == 200) {
Serial.println("Data sent successfully");
} else {
Serial.print("Error: ");
Serial.println(httpCode);
}
http.end();
}
delay(10000); // Send every 10 seconds
}6. Power Management
Battery Life Optimization
// Sleep modes save power when device inactive
void setup() {
Serial.begin(9600);
pinMode(BUTTON_PIN, INPUT);
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), wakeUp, RISING);
}
volatile boolean woken = false;
void wakeUp() {
woken = true;
}
void loop() {
// Do work
int reading = analogRead(A0);
Serial.println(reading);
// Enter sleep mode (power down, timer off)
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_mode();
sleep_disable();
// Woke up from interrupt or timer
if (woken) {
Serial.println("Button pressed!");
woken = false;
}
}
// Power consumption:
// Wake: 50mA
// Sleep: 0.1mA (500x reduction)
// Battery life: 500x longer!Power Budget Calculation
Battery capacity: 2000 mAh
Device current (awake): 50 mA
Device current (sleep): 0.1 mA
Scenario 1: Always awake
Battery life = 2000 mAh / 50 mA = 40 hours
Scenario 2: 90% sleep, 10% awake
Average current = 0.9 × 0.1 + 0.1 × 50 = 5.09 mA
Battery life = 2000 / 5.09 = 393 hours (16 days!)7. Real-World IoT Project: Smart Temperature Monitor
// Complete project: Temperature monitoring with cloud storage
#include <WiFi.h>
#include <HTTPClient.h>
#include <DHT.h>
#define DHTTYPE DHT22
#define DHTPIN 4
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(9600);
// WiFi
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) delay(500);
// Sensor
dht.begin();
// Pin modes
pinMode(LED_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
}
void loop() {
// Read temperature and humidity
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
if (isnan(temperature) || isnan(humidity)) {
Serial.println("Sensor error");
return;
}
// Check thresholds
if (temperature > 30) {
digitalWrite(LED_PIN, HIGH);
digitalWrite(BUZZER_PIN, HIGH);
delay(100);
digitalWrite(BUZZER_PIN, LOW);
} else {
digitalWrite(LED_PIN, LOW);
}
// Send to cloud
String payload = "{\"temp\":" + String(temperature) +
",\"humid\":" + String(humidity) + "}";
HTTPClient http;
http.begin("http://api.example.com/readings");
http.addHeader("Content-Type", "application/json");
http.POST(payload);
http.end();
// Display on serial
Serial.print("Temp: ");
Serial.print(temperature);
Serial.print("°C, Humidity: ");
Serial.print(humidity);
Serial.println("%");
delay(5000); // Read every 5 seconds
}Key Takeaways
- Arduino = Entry Point - Best for learning embedded systems
- Sensors first - Understand analog/digital I/O thoroughly
- Communication critical - I2C, SPI, UART, WiFi, MQTT
- Power matters - Sleep modes crucial for battery life
- Real-time = RTOS - Multitasking essential for complex systems
- Cloud integration - IoT = device + cloud
- Interrupts powerful - Handle time-critical events
- Reliability essential - Embedded systems must run unattended
- Test extensively - Hardware bugs are expensive
- Community resources - Libraries available, use them!