·8 min read·BASHCAT 技術團隊·embedded

Embedded Systems and IoT Development: Building a Smart Connected Future

Explore the critical role of embedded systems in the IoT ecosystem, a comprehensive guide from hardware selection to software architecture.

#Embedded Systems#IoT#ESP32#Arduino

The Perfect Fusion of Embedded Systems and IoT

In the wave of digital transformation, the combination of embedded systems and Internet of Things (IoT) technologies is redefining how we interact with the world around us. From smart homes to Industry 4.0, these technologies are creating a more intelligent, interconnected future.

Embedded Systems Fundamentals

Hardware Platform Selection

Choosing the right hardware platform is the first step toward a successful project:

ESP32 Series

ESP32 is one of our most recommended IoT development platforms:

#include "WiFi.h"
#include "PubSubClient.h"

const char* ssid = "your_wifi_ssid";
const char* password = "your_wifi_password";
const char* mqtt_server = "your_mqtt_broker";

WiFiClient espClient;
PubSubClient client(espClient);

void setup() {
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

void setup_wifi() {
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("WiFi connected");
}

Arduino Series

For entry-level projects, Arduino provides a beginner-friendly development environment:

#include <SoftwareSerial.h>
#include <ArduinoJson.h>

SoftwareSerial bluetooth(2, 3);

void setup() {
  Serial.begin(9600);
  bluetooth.begin(9600);

  // Initialize sensors
  pinMode(A0, INPUT);  // Temperature sensor
  pinMode(13, OUTPUT); // LED indicator
}

void loop() {
  int temperature = analogRead(A0);
  float celsius = (temperature * 5.0 / 1024.0 - 0.5) * 100;

  // Build JSON-formatted data
  StaticJsonDocument<200> doc;
  doc["temperature"] = celsius;
  doc["timestamp"] = millis();

  String output;
  serializeJson(doc, output);
  bluetooth.println(output);

  delay(1000);
}

Sensor Integration

Digital Sensors

The DHT22 temperature and humidity sensor is a commonly used digital sensor:

#include "DHT.h"

#define DHTPIN 2
#define DHTTYPE DHT22

DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(9600);
  dht.begin();
}

void loop() {
  float humidity = dht.readHumidity();
  float temperature = dht.readTemperature();

  if (isnan(humidity) || isnan(temperature)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }

  Serial.print("Humidity: ");
  Serial.print(humidity);
  Serial.print("%  Temperature: ");
  Serial.print(temperature);
  Serial.println("°C");

  delay(2000);
}

Analog Sensors

Example usage of a photoresistor:

const int photocellPin = A0;
const int ledPin = 9;

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  int photocellReading = analogRead(photocellPin);

  // Map sensor value to LED brightness
  int ledBrightness = map(photocellReading, 0, 1023, 255, 0);
  analogWrite(ledPin, ledBrightness);

  Serial.print("Analog reading = ");
  Serial.print(photocellReading);
  Serial.print(" - LED brightness = ");
  Serial.println(ledBrightness);

  delay(100);
}

IoT Architecture Design

Communication Protocol Selection

MQTT Protocol

MQTT is the most commonly used lightweight messaging protocol in IoT applications:

import paho.mqtt.client as mqtt
import json
import time

def on_connect(client, userdata, flags, rc):
    print(f"Connected with result code {rc}")
    client.subscribe("sensors/temperature")

def on_message(client, userdata, msg):
    try:
        data = json.loads(msg.payload.decode())
        temperature = data['temperature']
        timestamp = data['timestamp']

        print(f"Received: {temperature}°C at {timestamp}")

        # Data processing logic
        if temperature > 30:
            client.publish("alerts/high_temperature",
                          json.dumps({"alert": "High temperature detected"}))

    except Exception as e:
        print(f"Error processing message: {e}")

client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

client.connect("localhost", 1883, 60)
client.loop_forever()

HTTP REST API

For applications requiring a request-response model:

#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>

void sendSensorData(float temperature, float humidity) {
  if(WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    http.begin("http://your-api-server.com/api/sensors");
    http.addHeader("Content-Type", "application/json");

    StaticJsonDocument<200> doc;
    doc["device_id"] = "ESP32_001";
    doc["temperature"] = temperature;
    doc["humidity"] = humidity;
    doc["timestamp"] = millis();

    String jsonString;
    serializeJson(doc, jsonString);

    int httpResponseCode = http.POST(jsonString);

    if(httpResponseCode > 0) {
      String response = http.getString();
      Serial.println(response);
    }

    http.end();
  }
}

Data Processing and Analysis

Edge Computing

Performing preliminary data processing on the device side:

#include <math.h>

class SensorFilter {
private:
  float readings[10];
  int index;
  bool filled;

public:
  SensorFilter() : index(0), filled(false) {}

  float addReading(float value) {
    readings[index] = value;
    index = (index + 1) % 10;
    if (index == 0) filled = true;

    return getAverage();
  }

  float getAverage() {
    float sum = 0;
    int count = filled ? 10 : index;

    for (int i = 0; i < count; i++) {
      sum += readings[i];
    }

    return sum / count;
  }

  bool isAnomalous(float value) {
    float avg = getAverage();
    float variance = 0;
    int count = filled ? 10 : index;

    for (int i = 0; i < count; i++) {
      variance += pow(readings[i] - avg, 2);
    }

    float stdDev = sqrt(variance / count);
    return abs(value - avg) > (2 * stdDev);
  }
};

SensorFilter tempFilter;

void loop() {
  float rawTemp = readTemperature();
  float filteredTemp = tempFilter.addReading(rawTemp);

  if (tempFilter.isAnomalous(rawTemp)) {
    Serial.println("Anomalous reading detected!");
    // Trigger alert or additional processing
  }

  // Only send filtered data
  sendSensorData(filteredTemp);
  delay(1000);
}

Power Management

Low-Power Design

For battery-powered IoT devices, power consumption control is critical:

#include "esp_sleep.h"

#define uS_TO_S_FACTOR 1000000  // Microseconds to seconds conversion factor
#define TIME_TO_SLEEP  30       // Sleep duration (seconds)

void setup() {
  Serial.begin(115200);

  // Read sensor data
  float temperature = readTemperature();
  float humidity = readHumidity();

  // Send data
  sendDataToServer(temperature, humidity);

  // Configure wake-up source
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);

  Serial.println("Going to sleep now");
  Serial.flush();

  // Enter deep sleep
  esp_deep_sleep_start();
}

void loop() {
  // This will never execute, as the device enters sleep after setup
}

Battery Monitoring

#define BATTERY_PIN A0
#define VOLTAGE_DIVIDER_RATIO 2.0

float getBatteryVoltage() {
  int rawValue = analogRead(BATTERY_PIN);
  float voltage = (rawValue / 1024.0) * 3.3 * VOLTAGE_DIVIDER_RATIO;
  return voltage;
}

int getBatteryPercentage() {
  float voltage = getBatteryVoltage();

  // Assuming lithium battery voltage range: 3.0V - 4.2V
  if (voltage >= 4.2) return 100;
  if (voltage <= 3.0) return 0;

  return (int)((voltage - 3.0) / 1.2 * 100);
}

void checkBatteryStatus() {
  int batteryLevel = getBatteryPercentage();

  if (batteryLevel < 20) {
    // Send low battery warning
    sendLowBatteryAlert();

    // Enable power saving mode
    enablePowerSaveMode();
  }
}

Security Considerations

Data Encryption

#include "mbedtls/aes.h"

void encryptData(uint8_t* input, uint8_t* output, uint8_t* key) {
  mbedtls_aes_context aes;
  mbedtls_aes_init(&aes);
  mbedtls_aes_setkey_enc(&aes, key, 256);
  mbedtls_aes_crypt_ecb(&aes, MBEDTLS_AES_ENCRYPT, input, output);
  mbedtls_aes_free(&aes);
}

void secureDataTransmission(String data) {
  uint8_t key[32] = {/* your encryption key */};
  uint8_t input[16];
  uint8_t encrypted[16];

  // Prepare data for encryption
  data.getBytes(input, 16);

  // Encrypt data
  encryptData(input, encrypted, key);

  // Send encrypted data
  sendEncryptedData(encrypted, 16);
}

Device Authentication

#include <WiFiClientSecure.h>

WiFiClientSecure client;

void setupSecureConnection() {
  // Load CA certificate
  client.setCACert(ca_cert);

  // Load client certificate and private key
  client.setCertificate(client_cert);
  client.setPrivateKey(client_key);
}

bool authenticateDevice() {
  if (client.connect("secure.server.com", 443)) {
    String authRequest = "GET /api/authenticate HTTP/1.1\r\n";
    authRequest += "Host: secure.server.com\r\n";
    authRequest += "Device-ID: " + String(ESP.getEfuseMac()) + "\r\n";
    authRequest += "Connection: close\r\n\r\n";

    client.print(authRequest);

    // Read response
    String response = client.readString();
    return response.indexOf("200 OK") != -1;
  }

  return false;
}

Real-World Project Example

Smart Agriculture Monitoring System

#include <WiFi.h>
#include <PubSubClient.h>
#include "DHT.h"

#define SOIL_MOISTURE_PIN A0
#define DHT_PIN 2
#define PUMP_PIN 8

DHT dht(DHT_PIN, DHT22);
WiFiClient espClient;
PubSubClient mqtt(espClient);

struct SensorData {
  float temperature;
  float humidity;
  int soilMoisture;
  bool pumpStatus;
  float batteryLevel;
};

void setup() {
  Serial.begin(115200);
  dht.begin();
  pinMode(PUMP_PIN, OUTPUT);

  connectWiFi();
  mqtt.setServer("mqtt.broker.com", 1883);
  mqtt.setCallback(mqttCallback);
}

void loop() {
  SensorData data = readSensors();

  // Automatic irrigation logic
  if (data.soilMoisture < 30 && !data.pumpStatus) {
    activatePump();
    data.pumpStatus = true;
  } else if (data.soilMoisture > 70 && data.pumpStatus) {
    deactivatePump();
    data.pumpStatus = false;
  }

  // Send data to cloud
  publishSensorData(data);

  // Check battery status
  if (data.batteryLevel < 20) {
    enterPowerSaveMode();
  }

  delay(30000); // 30-second interval
}

SensorData readSensors() {
  SensorData data;
  data.temperature = dht.readTemperature();
  data.humidity = dht.readHumidity();
  data.soilMoisture = map(analogRead(SOIL_MOISTURE_PIN), 0, 1023, 0, 100);
  data.pumpStatus = digitalRead(PUMP_PIN);
  data.batteryLevel = getBatteryLevel();
  return data;
}

Troubleshooting and Maintenance

Remote Diagnostics

void performDiagnostics() {
  DiagnosticReport report;

  // Check WiFi connection
  report.wifiStatus = WiFi.status() == WL_CONNECTED;
  report.signalStrength = WiFi.RSSI();

  // Check sensor status
  report.sensorStatus = testSensors();

  // Check memory usage
  report.freeHeap = ESP.getFreeHeap();
  report.heapFragmentation = ESP.getHeapFragmentation();

  // Check power status
  report.batteryVoltage = getBatteryVoltage();

  // Send diagnostic report
  sendDiagnosticReport(report);
}

Over-the-Air Updates

#include <HTTPUpdate.h>

void checkForUpdates() {
  String currentVersion = "1.0.0";
  String updateURL = "http://update.server.com/firmware.bin";

  HTTPClient http;
  http.begin(updateURL + "?version=" + currentVersion);

  int httpCode = http.GET();
  if (httpCode == 200) {
    Serial.println("Update available, starting download...");

    t_httpUpdate_return ret = httpUpdate.update(updateURL);

    switch (ret) {
      case HTTP_UPDATE_FAILED:
        Serial.printf("Update failed. Error: %s\n",
                     httpUpdate.getLastErrorString().c_str());
        break;
      case HTTP_UPDATE_NO_UPDATES:
        Serial.println("No updates available");
        break;
      case HTTP_UPDATE_OK:
        Serial.println("Update successful, rebooting...");
        ESP.restart();
        break;
    }
  }

  http.end();
}

Future Trends

Edge AI Integration

#include "tensorflow/lite/micro/all_ops_resolver.h"
#include "tensorflow/lite/micro/micro_error_reporter.h"
#include "tensorflow/lite/micro/micro_interpreter.h"

// AI model inference on edge devices
class EdgeAI {
private:
  tflite::MicroInterpreter* interpreter;

public:
  bool initModel(const unsigned char* model_data) {
    static tflite::MicroErrorReporter micro_error_reporter;
    static tflite::AllOpsResolver resolver;

    // Load the model
    model = tflite::GetModel(model_data);

    // Create the interpreter
    static uint8_t tensor_arena[10000];
    interpreter = new tflite::MicroInterpreter(
        model, resolver, tensor_arena, 10000, &micro_error_reporter);

    return interpreter->AllocateTensors() == kTfLiteOk;
  }

  float predict(float* input_data) {
    // Set input data
    TfLiteTensor* input = interpreter->input(0);
    for (int i = 0; i < input->bytes / sizeof(float); i++) {
      input->data.f[i] = input_data[i];
    }

    // Execute inference
    if (interpreter->Invoke() != kTfLiteOk) {
      return -1;
    }

    // Get prediction result
    TfLiteTensor* output = interpreter->output(0);
    return output->data.f[0];
  }
};

Conclusion

The combination of embedded systems and IoT technologies opens the door to limitless possibilities. From smart homes to industrial automation, these technologies are reshaping our world. A successful IoT project requires:

  1. Appropriate hardware platform selection
  2. Reliable communication architecture
  3. Effective power management
  4. Robust security mechanisms
  5. Intelligent data processing

At BASHCAT, we have extensive experience in embedded systems and IoT development, providing clients with complete solutions from concept to product. If you have related project needs, feel free to contact us.

$ tail -n 1 /var/log/bashcat/posts

More from the workshop.