🎯 empfohlene Sammlungen
Balanced sample collections from various categories for you to explore
Arduino Entwicklungsbeispiele
Umfassende Arduino Entwicklungsbeispiele inklusive Mikrocontroller-Programmierung, Sensor- und Aktuatorsteuerung, Robotik-Projekte und Echtzeitsystementwurf
💻 Multi-Sensor-Überwachungs-Dashboard cpp
🟡 intermediate
⭐⭐⭐⭐
Komplettes Sensor-Überwachungssystem mit LCD-Anzeige, SD-Karten-Logging, Web-Interface und Echtzeit-Datenvisualisierung
⏱️ 45 min
🏷️ arduino, sensors, monitoring, embedded, iot
Prerequisites:
Arduino programming, C++, Electronics basics, I2C, SPI protocols
// Arduino Multi-Sensor Monitoring Dashboard
// Complete sensor monitoring with LCD, SD card logging, and web interface
// Compatible with Arduino Uno/Mega and ESP32
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SD.h>
#include <SPI.h>
#include <DHT.h>
#include <BH1750.h>
#include <ArduinoJson.h>
// Pin configurations for Arduino Uno
#define DHT_PIN 2
#define DHT_TYPE DHT22
#define LIGHT_SENSOR_PIN A0
#define SOUND_SENSOR_PIN A1
#define PIR_PIN 3
#define BUZZER_PIN 4
#define LED_PIN 13
#define SD_CS_PIN 10
// I2C addresses
#define LCD_ADDRESS 0x27
#define BH1750_ADDRESS 0x23
// Timing constants
#define SENSOR_UPDATE_INTERVAL 2000 // 2 seconds
#define LOGGING_INTERVAL 10000 // 10 seconds
#define DISPLAY_UPDATE_INTERVAL 1000 // 1 second
#define WEB_UPDATE_INTERVAL 5000 // 5 seconds
// Sensor thresholds
#define TEMP_HIGH_THRESHOLD 30.0
#define TEMP_LOW_THRESHOLD 10.0
#define HUMIDITY_HIGH_THRESHOLD 70.0
#define LIGHT_HIGH_THRESHOLD 800
#define SOUND_HIGH_THRESHOLD 600
// Global objects
LiquidCrystal_I2C lcd(0x27, 20, 4);
DHT dht(DHT_PIN, DHT_TYPE);
BH1750 lightMeter;
File dataFile;
// Sensor data structure
struct SensorData {
float temperature;
float humidity;
float lightLevel;
int soundLevel;
bool motionDetected;
unsigned long timestamp;
String dateTime;
int freeMemory;
};
// System state
SensorData currentData;
SensorData historicalData[100];
int dataIndex = 0;
bool sdCardAvailable = false;
bool alertActive = false;
unsigned long lastSensorUpdate = 0;
unsigned long lastLoggingUpdate = 0;
unsigned long lastDisplayUpdate = 0;
unsigned long lastWebUpdate = 0;
// Alert counters
int tempAlertCount = 0;
int humidityAlertCount = 0;
int lightAlertCount = 0;
int soundAlertCount = 0;
void setup() {
Serial.begin(115200);
delay(2000);
Serial.println("\n=== Arduino Multi-Sensor Dashboard ===");
Serial.println("Initializing system...");
// Initialize pins
pinMode(LED_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(PIR_PIN, INPUT);
digitalWrite(LED_PIN, LOW);
digitalWrite(BUZZER_PIN, LOW);
// Initialize LCD
initializeLCD();
// Initialize sensors
initializeSensors();
// Initialize SD card
initializeSDCard();
// Initialize motion detection interrupt
attachInterrupt(digitalPinToInterrupt(PIR_PIN), motionDetected, RISING);
// Display welcome message
displayWelcomeMessage();
// Initialize web server (for ESP32)
#ifdef ESP32
initializeWebServer();
#endif
Serial.println("System initialized successfully!");
}
void loop() {
unsigned long currentTime = millis();
// Update sensor data
if (currentTime - lastSensorUpdate >= SENSOR_UPDATE_INTERVAL) {
updateSensorData();
lastSensorUpdate = currentTime;
// Store historical data
storeHistoricalData();
// Check for alerts
checkAlerts();
}
// Update LCD display
if (currentTime - lastDisplayUpdate >= DISPLAY_UPDATE_INTERVAL) {
updateDisplay();
lastDisplayUpdate = currentTime;
}
// Log data to SD card
if (sdCardAvailable && (currentTime - lastLoggingUpdate >= LOGGING_INTERVAL)) {
logDataToSDCard();
lastLoggingUpdate = currentTime;
}
// Update web interface (ESP32 only)
#ifdef ESP32
if (currentTime - lastWebUpdate >= WEB_UPDATE_INTERVAL) {
updateWebInterface();
lastWebUpdate = currentTime;
}
#endif
// Handle alerts
handleAlerts();
delay(100);
}
void initializeLCD() {
Serial.println("Initializing LCD...");
lcd.init(20, 4);
lcd.backlight();
// Test LCD
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Sensor Dashboard");
lcd.setCursor(0, 1);
lcd.print("Initializing...");
delay(2000);
Serial.println("LCD initialized");
}
void initializeSensors() {
Serial.println("Initializing sensors...");
// Initialize DHT22 temperature/humidity sensor
dht.begin();
// Initialize BH1750 light sensor
if (lightMeter.begin(BH1750_ADDRESS, CONTINUOUS_HIGH_RES_MODE)) {
Serial.println("BH1750 light sensor initialized");
} else {
Serial.println("Error initializing BH1750 light sensor");
}
// Test sensors
float testTemp = dht.readTemperature();
float testHum = dht.readHumidity();
if (isnan(testTemp) || isnan(testHum)) {
Serial.println("Warning: DHT22 sensor not responding");
}
Serial.println("Sensors initialized");
}
void initializeSDCard() {
Serial.println("Initializing SD card...");
if (SD.begin(SD_CS_PIN)) {
sdCardAvailable = true;
Serial.println("SD card initialized successfully");
// Test file creation
if (SD.exists("sensor_data.csv")) {
Serial.println("Existing data file found");
} else {
createDataFile();
}
} else {
sdCardAvailable = false;
Serial.println("Error initializing SD card");
}
}
void createDataFile() {
dataFile = SD.open("sensor_data.csv", FILE_WRITE);
if (dataFile) {
// Write CSV header
dataFile.println("Timestamp,Temperature,Humidity,Light,Sound,Motion,FreeMemory");
dataFile.close();
Serial.println("Created new data file");
} else {
Serial.println("Error creating data file");
}
}
void displayWelcomeMessage() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Arduino Sensor");
lcd.setCursor(0, 1);
lcd.print("Monitoring System");
lcd.setCursor(0, 2);
lcd.print("Ready!");
lcd.setCursor(0, 3);
lcd.print("Initializing...");
delay(3000);
lcd.clear();
}
void updateSensorData() {
// Read temperature and humidity from DHT22
currentData.temperature = dht.readTemperature();
currentData.humidity = dht.readHumidity();
// Handle DHT22 reading errors
if (isnan(currentData.temperature) || isnan(currentData.humidity)) {
Serial.println("Error reading DHT22 sensor");
// Use last valid values or defaults
if (dataIndex > 0) {
currentData.temperature = historicalData[dataIndex - 1].temperature;
currentData.humidity = historicalData[dataIndex - 1].humidity;
} else {
currentData.temperature = 20.0;
currentData.humidity = 50.0;
}
}
// Read light level from BH1750
currentData.lightLevel = lightMeter.readLightLevel();
if (currentData.lightLevel < 0) {
currentData.lightLevel = analogRead(LIGHT_SENSOR_PIN);
currentData.lightLevel = map(currentData.lightLevel, 0, 1023, 0, 1000);
}
// Read sound level from analog sensor
currentData.soundLevel = analogRead(SOUND_SENSOR_PIN);
// Motion is handled by interrupt
// currentData.motionDetected is set in motionDetected() function
// Get current timestamp
currentData.timestamp = millis();
currentData.dateTime = getCurrentDateTime();
// Get free memory
currentData.freeMemory = getFreeMemory();
// Serial output for debugging
Serial.printf("Temp: %.1f°C, Humidity: %.1f%%, Light: %.1f lux, Sound: %d, Motion: %s\n",
currentData.temperature, currentData.humidity, currentData.lightLevel,
currentData.soundLevel, currentData.motionDetected ? "Yes" : "No");
}
void storeHistoricalData() {
historicalData[dataIndex] = currentData;
dataIndex = (dataIndex + 1) % 100; // Circular buffer of 100 entries
}
String getCurrentDateTime() {
char dateTimeStr[20];
unsigned long seconds = currentData.timestamp / 1000;
unsigned long minutes = seconds / 60;
unsigned long hours = minutes / 60;
unsigned long days = hours / 24;
sprintf(dateTimeStr, "%02ld:%02ld:%02ld:%02ld",
days, hours % 24, minutes % 60, seconds % 60);
return String(dateTimeStr);
}
int getFreeMemory() {
#ifdef ESP32
return ESP.getFreeHeap();
#else
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
#endif
}
void updateDisplay() {
lcd.clear();
// Line 1: Temperature and Humidity
lcd.setCursor(0, 0);
lcd.printf("T:%.1f°C H:%.0f%%", currentData.temperature, currentData.humidity);
// Line 2: Light and Sound
lcd.setCursor(0, 1);
lcd.printf("L:%.0f S:%4d", currentData.lightLevel, currentData.soundLevel);
// Line 3: Motion and Memory
lcd.setCursor(0, 2);
lcd.printf("M:%s Mem:%dB", currentData.motionDetected ? "Yes" : "No ", currentData.freeMemory / 100);
// Line 4: Status and alerts
lcd.setCursor(0, 3);
if (alertActive) {
lcd.printf("ALERT! %s", getActiveAlert().c_str());
} else {
lcd.printf("Status: OK");
}
}
void checkAlerts() {
alertActive = false;
// Temperature alerts
if (currentData.temperature > TEMP_HIGH_THRESHOLD) {
triggerAlert("TEMP_HIGH", "Temperature too high");
tempAlertCount++;
} else if (currentData.temperature < TEMP_LOW_THRESHOLD) {
triggerAlert("TEMP_LOW", "Temperature too low");
tempAlertCount++;
} else {
tempAlertCount = 0;
}
// Humidity alerts
if (currentData.humidity > HUMIDITY_HIGH_THRESHOLD) {
triggerAlert("HUMID_HIGH", "Humidity too high");
humidityAlertCount++;
} else {
humidityAlertCount = 0;
}
// Light alerts
if (currentData.lightLevel > LIGHT_HIGH_THRESHOLD) {
triggerAlert("LIGHT_HIGH", "Light level too high");
lightAlertCount++;
} else {
lightAlertCount = 0;
}
// Sound alerts
if (currentData.soundLevel > SOUND_HIGH_THRESHOLD) {
triggerAlert("SOUND_HIGH", "Noise level too high");
soundAlertCount++;
} else {
soundAlertCount = 0;
}
// Motion alert (only trigger if motion is detected)
if (currentData.motionDetected) {
triggerAlert("MOTION", "Motion detected");
}
}
void triggerAlert(String alertType, String message) {
alertActive = true;
Serial.printf("ALERT [%s]: %s\n", alertType.c_str(), message.c_str());
}
String getActiveAlert() {
if (tempAlertCount > 0) return "TEMP";
if (humidityAlertCount > 0) return "HUMID";
if (lightAlertCount > 0) return "LIGHT";
if (soundAlertCount > 0) return "SOUND";
if (currentData.motionDetected) return "MOTION";
return "";
}
void handleAlerts() {
static unsigned long lastAlertTime = 0;
static bool lastAlertState = false;
static bool buzzerState = false;
if (alertActive) {
// Blink LED
digitalWrite(LED_PIN, (millis() / 500) % 2);
// Sound buzzer (if enabled and not too frequent)
if (millis() - lastAlertTime > 1000) {
buzzerState = !buzzerState;
digitalWrite(BUZZER_PIN, buzzerState ? HIGH : LOW);
lastAlertTime = millis();
}
} else {
// Turn off alert indicators
if (lastAlertState) {
digitalWrite(LED_PIN, LOW);
digitalWrite(BUZZER_PIN, LOW);
lastAlertState = false;
}
}
}
void logDataToSDCard() {
if (!sdCardAvailable) return;
dataFile = SD.open("sensor_data.csv", FILE_WRITE);
if (dataFile) {
// Append new data
dataFile.printf("%lu,%.2f,%.2f,%.2f,%d,%s,%d\n",
currentData.timestamp,
currentData.temperature,
currentData.humidity,
currentData.lightLevel,
currentData.soundLevel,
currentData.motionDetected ? "1" : "0",
currentData.freeMemory);
dataFile.close();
Serial.println("Data logged to SD card");
} else {
Serial.println("Error writing to SD card");
}
}
void motionDetected() {
currentData.motionDetected = true;
Serial.println("Motion detected!");
}
#ifdef ESP32
// ESP32 Web Server Implementation
#include <WiFi.h>
#include <WebServer.h>
#include <WiFiClient.h>
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
WebServer server(80);
void initializeWebServer() {
// WiFi setup for ESP32
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// Web server routes
server.on("/", handleRoot);
server.on("/data.json", handleData);
server.on("/history.json", handleHistory);
server.on("/stats", handleStats);
server.begin();
Serial.println("Web server started");
}
void handleRoot() {
String html = generateWebPage();
server.send(200, "text/html", html);
}
void handleData() {
String json = generateCurrentDataJSON();
server.send(200, "application/json", json);
}
void handleHistory() {
String json = generateHistoryJSON();
server.send(200, "application/json", json);
}
void handleStats() {
String json = generateStatsJSON();
server.send(200, "application/json", json);
}
void updateWebInterface() {
// Web interface updates are handled by HTTP requests
}
String generateWebPage() {
String html = R"(
<!DOCTYPE html>
<html>
<head>
<title>Arduino Sensor Dashboard</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.dashboard { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; }
.card { background: #f9f9f9; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
.card h3 { margin-top: 0; color: #333; }
.metric { font-size: 2em; font-weight: bold; color: #007bff; }
.unit { font-size: 0.6em; color: #666; }
.alert { background: #f8d7da; border: 1px solid #f5c6cb; color: #721c24; }
.ok { background: #d4edda; border: 1px solid #c3e6cb; color: #155724; }
button { background: #007bff; color: white; border: none; padding: 10px 20px; border-radius: 4px; cursor: pointer; }
button:hover { background: #0056b3; }
</style>
</head>
<body>
<h1>🌡️ Arduino Sensor Dashboard</h1>
<div class="dashboard">
<div class="card">
<h3>Temperature</h3>
<div class="metric"><span id="temperature">--</span><span class="unit">°C</span></div>
</div>
<div class="card">
<h3>Humidity</h3>
<div class="metric"><span id="humidity">--</span><span class="unit">%</span></div>
</div>
<div class="card">
<h3>Light Level</h3>
<div class="metric"><span id="light">--</span><span class="unit"> lux</span></div>
</div>
<div class="card">
<h3>Sound Level</h3>
<div class="metric"><span id="sound">--</span><span class="unit"> dB</span></div>
</div>
<div class="card">
<h3>Status</h3>
<div id="status" class="ok">System OK</div>
</div>
<div class="card">
<h3>Controls</h3>
<button onclick="location.reload()">🔄 Refresh</button>
<button onclick="downloadData()">📊 Download Data</button>
</div>
</div>
<script>
async function updateData() {
try {
const response = await fetch('/data.json');
const data = await response.json();
document.getElementById('temperature').textContent = data.temperature.toFixed(1);
document.getElementById('humidity').textContent = data.humidity.toFixed(1);
document.getElementById('light').textContent = data.lightLevel.toFixed(0);
document.getElementById('sound').textContent = data.soundLevel;
const statusEl = document.getElementById('status');
if (data.alertActive) {
statusEl.textContent = '⚠️ ' + data.activeAlert;
statusEl.className = 'alert';
} else {
statusEl.textContent = '✅ System OK';
statusEl.className = 'ok';
}
} catch (error) {
console.error('Error updating data:', error);
}
}
function downloadData() {
window.open('/history.json', '_blank');
}
// Update data every 2 seconds
setInterval(updateData, 2000);
updateData(); // Initial update
</script>
</body>
</html>)";
return html;
}
String generateCurrentDataJSON() {
DynamicJsonDocument doc(512);
doc["temperature"] = currentData.temperature;
doc["humidity"] = currentData.humidity;
doc["lightLevel"] = currentData.lightLevel;
doc["soundLevel"] = currentData.soundLevel;
doc["motionDetected"] = currentData.motionDetected;
doc["timestamp"] = currentData.timestamp;
doc["alertActive"] = alertActive;
doc["activeAlert"] = getActiveAlert();
doc["freeMemory"] = currentData.freeMemory;
String jsonString;
serializeJson(doc, jsonString);
return jsonString;
}
String generateHistoryJSON() {
DynamicJsonDocument doc(4096);
JsonArray array = doc.to<JsonArray>();
for (int i = 0; i < 20; i++) {
int index = (dataIndex - 1 - i + 100) % 100;
JsonObject obj = array.createNestedObject();
obj["temperature"] = historicalData[index].temperature;
obj["humidity"] = historicalData[index].humidity;
obj["lightLevel"] = historicalData[index].lightLevel;
obj["timestamp"] = historicalData[index].timestamp;
}
String jsonString;
serializeJson(doc, jsonString);
return jsonString;
}
String generateStatsJSON() {
DynamicJsonDocument doc(512);
doc["totalReadings"] = dataIndex;
doc["tempAlerts"] = tempAlertCount;
doc["humidityAlerts"] = humidityAlertCount;
doc["lightAlerts"] = lightAlertCount;
doc["soundAlerts"] = soundAlertCount;
doc["uptime"] = millis();
doc["freeMemory"] = currentData.freeMemory;
doc["sdCardAvailable"] = sdCardAvailable;
String jsonString;
serializeJson(doc, jsonString);
return jsonString;
}
#else
// Arduino Uno/Leo compatibility functions
void initializeWebServer() {
// Not implemented for Arduino Uno (no WiFi)
Serial.println("Web server not available on this platform");
}
void updateWebInterface() {
// Not implemented for Arduino Uno
}
void handleRoot() {}
void handleData() {}
void handleHistory() {}
void handleStats() {}
String generateWebPage() { return ""; }
String generateCurrentDataJSON() { return ""; }
String generateHistoryJSON() { return ""; }
String generateStatsJSON() { return ""; }
#endif
// Utility functions
void printSystemInfo() {
Serial.println("\n=== System Information ===");
Serial.printf("Uptime: %lu ms\n", millis());
Serial.printf("Free Memory: %d bytes\n", getFreeMemory());
Serial.printf("SD Card: %s\n", sdCardAvailable ? "Available" : "Not Available");
Serial.printf("Total Readings: %d\n", dataIndex);
Serial.printf("Temperature Alerts: %d\n", tempAlertCount);
Serial.printf("Humidity Alerts: %d\n", humidityAlertCount);
Serial.printf("Light Alerts: %d\n", lightAlertCount);
Serial.printf("Sound Alerts: %d\n", soundAlertCount);
}
void formatSerialOutput() {
// Clean up serial output formatting
Serial.println();
Serial.println("========================================");
Serial.println();
}
// Emergency functions
void emergencyShutdown() {
Serial.println("Emergency shutdown initiated!");
// Save current data before shutdown
logDataToSDCard();
// Turn off all outputs
digitalWrite(LED_PIN, LOW);
digitalWrite(BUZZER_PIN, LOW);
// Display shutdown message
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("SYSTEM SHUTDOWN");
lcd.setCursor(0, 1);
lcd.print("Data Saved");
delay(5000);
// Enter low power mode (if supported)
#ifdef ESP32
esp_deep_sleep_start();
#endif
}
💻 Arduino Roboter-Controller cpp
🔴 complex
⭐⭐⭐⭐⭐
Vollständiges autonomes Robot-Steuerungssystem mit Motortreibern, Ultraschall-Navigation, Linienverfolgung und Hindernisvermeidung
⏱️ 60 min
🏷️ arduino, robotics, autonomous, navigation, embedded
Prerequisites:
Advanced Arduino, Motor control, Sensor integration, PID control theory
// Arduino Robot Controller
// Complete autonomous robot with motor control, navigation, and sensors
// Compatible with Arduino Mega and motor driver L298N or similar
#include <Arduino.h>
#include <Servo.h>
#include <NewPing.h>
// Motor driver pins (L298N)
#define ENA 5
#define IN1 6
#define IN2 7
#define ENB 10
#define IN3 8
#define IN4 9
// Ultrasonic sensor pins
#define TRIG_PIN 12
#define ECHO_PIN 13
// Line sensor pins (analog)
#define LINE_LEFT_PIN A0
#define LINE_CENTER_PIN A1
#define LINE_RIGHT_PIN A2
// Servo pin for ultrasonic sensor
#define SERVO_PIN 11
// LED and buzzer pins
#define STATUS_LED 2
#define BUZZER_PIN 3
// Navigation constants
#define MAX_DISTANCE 200 // Maximum detection distance in cm
#define SAFE_DISTANCE 30 // Safe distance from obstacles
#define WARNING_DISTANCE 60 // Warning distance for obstacles
#define BASE_SPEED 150 // Base motor speed
#define TURN_SPEED 100 // Speed during turns
#define LINE_THRESHOLD 512 // Threshold for line detection
// Robot states
enum RobotState {
IDLE,
MOVING_FORWARD,
TURNING_LEFT,
TURNING_RIGHT,
OBSTACLE_AVOIDANCE,
LINE_FOLLOWING,
STOPPED,
EMERGENCY
};
// Global variables
Servo ultrasonicServo;
NewPing sonar(TRIG_PIN, ECHO_PIN, MAX_DISTANCE);
RobotState currentState = IDLE;
RobotState previousState = IDLE;
// Navigation variables
int currentSpeed = BASE_SPEED;
int turnAngle = 90; // Center position for ultrasonic servo
unsigned long lastObstacleCheck = 0;
unsigned long lastLineCheck = 0;
bool lineDetected = false;
int linePosition = 0; // -1: left, 0: center, 1: right
// Motor control variables
bool motorsEnabled = true;
unsigned long lastMotorUpdate = 0;
// Statistics
unsigned long totalDistance = 0;
unsigned int obstaclesAvoided = 0;
unsigned int turnsMade = 0;
unsigned long operationTime = 0;
// PID controller for line following
struct PIDController {
float kp, ki, kd;
float integral, previous_error;
PIDController(float p = 1.0, float i = 0.0, float d = 0.0) {
kp = p;
ki = i;
kd = d;
integral = 0;
previous_error = 0;
}
float calculate(float error) {
integral += error;
float derivative = error - previous_error;
previous_error = error;
return kp * error + ki * integral + kd * derivative;
}
void reset() {
integral = 0;
previous_error = 0;
}
};
PIDController linePID(2.0, 0.1, 0.5);
void setup() {
Serial.begin(115200);
delay(2000);
Serial.println("=== Arduino Robot Controller ===");
Serial.println("Initializing robot systems...");
// Initialize motor pins
initializeMotors();
// Initialize sensors
initializeSensors();
// Initialize servos
initializeServos();
// Initialize control pins
pinMode(STATUS_LED, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
// Perform system checks
performSystemCheck();
// Ready signal
signalReady();
operationTime = millis();
Serial.println("Robot ready! Starting navigation...");
// Start in line following mode
currentState = LINE_FOLLOWING;
}
void loop() {
// Update sensors
updateSensors();
// State machine
switch (currentState) {
case IDLE:
handleIdleState();
break;
case MOVING_FORWARD:
handleForwardMovement();
break;
case TURNING_LEFT:
handleLeftTurn();
break;
case TURNING_RIGHT:
handleRightTurn();
break;
case OBSTACLE_AVOIDANCE:
handleObstacleAvoidance();
break;
case LINE_FOLLOWING:
handleLineFollowing();
break;
case STOPPED:
handleStoppedState();
break;
case EMERGENCY:
handleEmergencyState();
break;
}
// Update status
updateRobotStatus();
// Check for manual overrides or commands
checkManualCommands();
delay(50); // Main loop delay
}
void initializeMotors() {
Serial.println("Initializing motors...");
// Set motor pins as outputs
pinMode(ENA, OUTPUT);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(ENB, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(IN4, OUTPUT);
// Initialize motor states
stopMotors();
// Enable motors
digitalWrite(ENA, HIGH);
digitalWrite(ENB, HIGH);
Serial.println("Motors initialized");
}
void initializeSensors() {
Serial.println("Initializing sensors...");
// Initialize ultrasonic servo
ultrasonicServo.attach(SERVO_PIN);
ultrasonicServo.write(turnAngle);
// Initialize line sensor pins
pinMode(LINE_LEFT_PIN, INPUT);
pinMode(LINE_CENTER_PIN, INPUT);
pinMode(LINE_RIGHT_PIN, INPUT);
Serial.println("Sensors initialized");
}
void initializeServos() {
Serial.println("Initializing servos...");
// Center the ultrasonic servo
ultrasonicServo.write(90);
delay(500);
Serial.println("Servos initialized");
}
void performSystemCheck() {
Serial.println("Performing system check...");
// Test motors
Serial.println("Testing motors...");
testMotors();
// Test sensors
Serial.println("Testing sensors...");
testSensors();
// Test servos
Serial.println("Testing servos...");
testServos();
Serial.println("System check completed");
}
void testMotors() {
// Test forward movement
moveForward(BASE_SPEED);
delay(1000);
stopMotors();
// Test turning
turnLeft(90);
delay(1000);
turnRight(90);
delay(1000);
stopMotors();
Serial.println("Motor test completed");
}
void testSensors() {
// Test ultrasonic sensor
int distance = readUltrasonic();
Serial.printf("Ultrasonic reading: %d cm\n", distance);
// Test line sensors
int leftLine = analogRead(LINE_LEFT_PIN);
int centerLine = analogRead(LINE_CENTER_PIN);
int rightLine = analogRead(LINE_RIGHT_PIN);
Serial.printf("Line sensors - Left: %d, Center: %d, Right: %d\n",
leftLine, centerLine, rightLine);
}
void testServos() {
// Test servo movement
for (int angle = 60; angle <= 120; angle += 10) {
ultrasonicServo.write(angle);
delay(100);
}
ultrasonicServo.write(90);
Serial.println("Servo test completed");
}
void signalReady() {
// Flash LED and beep buzzer to signal readiness
for (int i = 0; i < 3; i++) {
digitalWrite(STATUS_LED, HIGH);
tone(BUZZER_PIN, 1000, 100);
delay(200);
digitalWrite(STATUS_LED, LOW);
delay(200);
}
}
// Motor control functions
void moveForward(int speed) {
if (!motorsEnabled) return;
// Left motor forward
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
analogWrite(ENA, speed);
// Right motor forward
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
analogWrite(ENB, speed);
Serial.printf("Moving forward at speed %d\n", speed);
}
void moveBackward(int speed) {
if (!motorsEnabled) return;
// Left motor backward
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
analogWrite(ENA, speed);
// Right motor backward
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
analogWrite(ENB, speed);
Serial.printf("Moving backward at speed %d\n", speed);
}
void turnLeft(int degrees) {
if (!motorsEnabled) return;
// Calculate turn duration based on degrees
int turnDuration = map(degrees, 0, 360, 0, 2000);
// Turn motors in opposite directions
// Left motor backward
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
analogWrite(ENA, TURN_SPEED);
// Right motor forward
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
analogWrite(ENB, TURN_SPEED);
delay(turnDuration);
stopMotors();
turnsMade++;
Serial.printf("Turned left %d degrees\n", degrees);
}
void turnRight(int degrees) {
if (!motorsEnabled) return;
// Calculate turn duration based on degrees
int turnDuration = map(degrees, 0, 360, 0, 2000);
// Turn motors in opposite directions
// Left motor forward
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
analogWrite(ENA, TURN_SPEED);
// Right motor backward
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
analogWrite(ENB, TURN_SPEED);
delay(turnDuration);
stopMotors();
turnsMade++;
Serial.printf("Turned right %d degrees\n", degrees);
}
void stopMotors() {
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW);
digitalWrite(IN4, LOW);
analogWrite(ENA, 0);
analogWrite(ENB, 0);
}
void setMotorSpeeds(int leftSpeed, int rightSpeed) {
if (!motorsEnabled) return;
// Left motor
if (leftSpeed >= 0) {
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
analogWrite(ENA, leftSpeed);
} else {
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
analogWrite(ENA, -leftSpeed);
}
// Right motor
if (rightSpeed >= 0) {
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
analogWrite(ENB, rightSpeed);
} else {
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
analogWrite(ENB, -rightSpeed);
}
}
// Sensor functions
int readUltrasonic() {
int distance = sonar.ping_cm();
return distance;
}
void scanWithUltrasonic() {
// Scan environment by moving servo
int distances[9];
for (int i = 0; i < 9; i++) {
int angle = 60 + i * 15; // 60° to 180°
ultrasonicServo.write(angle);
delay(50); // Wait for servo to reach position
distances[i] = readUltrasonic();
delay(50); // Wait for ultrasonic reading
}
// Return servo to center position
ultrasonicServo.write(90);
// Find the direction with the most open path
int maxDistance = 0;
int bestDirection = 90;
for (int i = 0; i < 9; i++) {
if (distances[i] > maxDistance) {
maxDistance = distances[i];
bestDirection = 60 + i * 15;
}
}
Serial.printf("Best direction: %d°, Distance: %d cm\n", bestDirection, maxDistance);
turnAngle = bestDirection;
}
void updateLineSensors() {
int leftValue = analogRead(LINE_LEFT_PIN);
int centerValue = analogRead(LINE_CENTER_PIN);
int rightValue = analogRead(LINE_RIGHT_PIN);
// Determine line position
bool leftDetected = leftValue > LINE_THRESHOLD;
bool centerDetected = centerValue > LINE_THRESHOLD;
bool rightDetected = rightValue > LINE_THRESHOLD;
if (leftDetected && rightDetected && !centerDetected) {
linePosition = 0; // Centered on wide line
} else if (leftDetected) {
linePosition = -1; // Line is to the left
} else if (rightDetected) {
linePosition = 1; // Line is to the right
} else if (centerDetected) {
linePosition = 0; // Centered
} else {
linePosition = 2; // No line detected
}
lineDetected = (linePosition < 2);
// Debug output
static unsigned long lastDebug = 0;
if (millis() - lastDebug > 1000) {
Serial.printf("Line sensors - L:%d C:%d R:%d Position:%d\n",
leftValue, centerValue, rightValue, linePosition);
lastDebug = millis();
}
}
void updateSensors() {
// Update ultrasonic reading
if (millis() - lastObstacleCheck > 100) { // Check every 100ms
readUltrasonic();
lastObstacleCheck = millis();
}
// Update line sensors
if (millis() - lastLineCheck > 50) { // Check every 50ms
updateLineSensors();
lastLineCheck = millis();
}
}
// State handling functions
void handleIdleState() {
stopMotors();
digitalWrite(STATUS_LED, LOW);
// Wait for 3 seconds, then start line following
static unsigned long idleStartTime = 0;
if (idleStartTime == 0) {
idleStartTime = millis();
}
if (millis() - idleStartTime > 3000) {
currentState = LINE_FOLLOWING;
idleStartTime = 0;
}
}
void handleForwardMovement() {
moveForward(currentSpeed);
// Check for obstacles
int distance = readUltrasonic();
if (distance < SAFE_DISTANCE) {
currentState = OBSTACLE_AVOIDANCE;
}
// Check for line
updateLineSensors();
if (lineDetected && linePosition != 2) {
currentState = LINE_FOLLOWING;
}
}
void handleLeftTurn() {
// Turn left logic is handled in turnLeft() function
// After turn is complete, return to previous state
if (previousState == OBSTACLE_AVOIDANCE) {
currentState = MOVING_FORWARD;
} else {
currentState = LINE_FOLLOWING;
}
}
void handleRightTurn() {
// Turn right logic is handled in turnRight() function
// After turn is complete, return to previous state
if (previousState == OBSTACLE_AVOIDANCE) {
currentState = MOVING_FORWARD;
} else {
currentState = LINE_FOLLOWING;
}
}
void handleObstacleAvoidance() {
static unsigned long avoidanceStartTime = 0;
static bool scanning = false;
if (!scanning) {
Serial.println("Scanning for clear path...");
scanWithUltrasonic();
scanning = true;
avoidanceStartTime = millis();
}
// Wait for scan to complete
if (millis() - avoidanceStartTime > 1500) {
scanning = false;
// Turn in the best direction
if (turnAngle < 90) {
turnLeft(90 - turnAngle);
} else if (turnAngle > 90) {
turnRight(turnAngle - 90);
} else {
// Best direction is straight, but we have an obstacle
// Turn around
turnRight(180);
}
obstaclesAvoided++;
previousState = OBSTACLE_AVOIDANCE;
currentState = MOVING_FORWARD;
}
}
void handleLineFollowing() {
if (!lineDetected || linePosition == 2) {
// No line detected, move forward and search
moveForward(BASE_SPEED);
// Scan for line
static unsigned long lastLineScan = 0;
if (millis() - lastLineScan > 1000) { // Scan every second
scanWithUltrasonic();
lastLineScan = millis();
}
return;
}
// Line following logic using PID controller
float error = 0;
switch (linePosition) {
case -1: // Line is to the left
error = -1.0;
break;
case 0: // Centered
error = 0;
break;
case 1: // Line is to the right
error = 1.0;
break;
}
// Calculate PID correction
float correction = linePID.calculate(error);
// Apply correction to motor speeds
int leftSpeed = BASE_SPEED - (int)correction;
int rightSpeed = BASE_SPEED + (int)correction;
// Limit speeds
leftSpeed = constrain(leftSpeed, 50, 250);
rightSpeed = constrain(rightSpeed, 50, 250);
setMotorSpeeds(leftSpeed, rightSpeed);
// Check for obstacles while following line
int distance = readUltrasonic();
if (distance < SAFE_DISTANCE) {
stopMotors();
linePID.reset();
currentState = OBSTACLE_AVOIDANCE;
}
}
void handleStoppedState() {
stopMotors();
digitalWrite(STATUS_LED, HIGH);
// Emergency stop activated, require manual reset
// In a real implementation, you would need a way to resume
}
void handleEmergencyState() {
stopMotors();
// Flash LED and sound alarm
digitalWrite(STATUS_LED, millis() % 500 < 250);
if (millis() % 1000 < 500) {
tone(BUZZER_PIN, 2000, 100);
}
// Emergency stop - require manual intervention
Serial.println("EMERGENCY! Robot stopped!");
}
void updateRobotStatus() {
static unsigned long lastStatusUpdate = 0;
if (millis() - lastStatusUpdate > 5000) { // Update every 5 seconds
Serial.printf("State: %d, Speed: %d, Obstacles: %d, Turns: %d\n",
currentState, currentSpeed, obstaclesAvoided, turnsMade);
lastStatusUpdate = millis();
}
}
void checkManualCommands() {
// Check for serial commands
if (Serial.available()) {
String command = Serial.readStringUntil('\n');
command.trim();
if (command == "STOP") {
currentState = STOPPED;
Serial.println("Manual stop command received");
} else if (command == "START") {
if (currentState == STOPPED) {
currentState = LINE_FOLLOWING;
Serial.println("Manual start command received");
}
} else if (command == "FORWARD") {
currentState = MOVING_FORWARD;
Serial.println("Manual forward command received");
} else if (command == "LEFT") {
turnLeft(90);
Serial.println("Manual left turn command received");
} else if (command == "RIGHT") {
turnRight(90);
Serial.println("Manual right turn command received");
} else if (command == "SCAN") {
scanWithUltrasonic();
Serial.println("Manual scan command received");
} else if (command == "STATUS") {
printRobotStatus();
} else if (command == "HELP") {
printHelp();
}
}
}
void printRobotStatus() {
Serial.println("\n=== Robot Status ===");
Serial.printf("Current State: %d\n", currentState);
Serial.printf("Current Speed: %d\n", currentSpeed);
Serial.printf("Motors Enabled: %s\n", motorsEnabled ? "Yes" : "No");
Serial.printf("Ultrasonic Distance: %d cm\n", readUltrasonic());
Serial.printf("Line Detected: %s\n", lineDetected ? "Yes" : "No");
Serial.printf("Line Position: %d\n", linePosition);
Serial.printf("Total Obstacles Avoided: %d\n", obstaclesAvoided);
Serial.printf("Total Turns Made: %d\n", turnsMade);
Serial.printf("Operation Time: %lu ms\n", millis());
Serial.printf("Free Memory: %d bytes\n", getFreeMemory());
Serial.println("========================");
}
void printHelp() {
Serial.println("\n=== Robot Commands ===");
Serial.println("STOP - Emergency stop");
Serial.println("START - Resume operation");
Serial.println("FORWARD - Move forward");
Serial.println("LEFT - Turn left 90°");
Serial.println("RIGHT - Turn right 90°");
Serial.println("SCAN - Scan surroundings");
Serial.println("STATUS - Show robot status");
Serial.println("HELP - Show this help");
Serial.println("==================");
}
int getFreeMemory() {
#ifdef ARDUINO_ARCH_ESP32
return ESP.getFreeHeap();
#else
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
#endif
}
// Utility functions
void beep(int frequency, int duration) {
tone(BUZZER_PIN, frequency, duration);
}
void blinkLED(int count, int duration) {
for (int i = 0; i < count; i++) {
digitalWrite(STATUS_LED, HIGH);
delay(duration);
digitalWrite(STATUS_LED, LOW);
delay(duration);
}
}
// Emergency and recovery functions
void emergencyStop() {
currentState = EMERGENCY;
Serial.println("Emergency stop activated!");
}
void resetRobot() {
Serial.println("Resetting robot systems...");
// Reset variables
currentSpeed = BASE_SPEED;
linePID.reset();
obstaclesAvoided = 0;
turnsMade = 0;
lineDetected = false;
linePosition = 2;
// Reset servos
ultrasonicServo.write(90);
// Reset motors
stopMotors();
delay(1000);
// Start in safe state
currentState = IDLE;
Serial.println("Robot reset completed");
}
💻 Echtzeitsystem-Entwurf mit Arduino cpp
🔴 complex
⭐⭐⭐⭐⭐
Implementierung deterministischer Echtzeitsysteme mit Arduino inklusive Aufgabenplanung, Interrupt-Management und Zeitrestriktionen
⏱️ 90 min
🏷️ arduino, real-time, rtos, embedded
Prerequisites:
Advanced C/C++, RTOS concepts, Arduino architecture, Interrupt handling
// Arduino Real-Time System Framework
// Complete RTOS-like implementation for Arduino with task scheduling and interrupt management
// Compatible with Arduino Mega/Uno (with limitations)
#include <Arduino.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <util/atomic.h>
// Real-time system configuration
#define MAX_TASKS 8
#define MAX_INTERRUPTS 16
#define SYSTEM_TICK_INTERVAL_MS 1
#define TICK_COUNT_TO_MS(tick) ((tick) * SYSTEM_TICK_INTERVAL_MS)
#define MS_TO_TICK_COUNT(ms) ((ms) / SYSTEM_TICK_INTERVAL_MS)
// Task priorities
#define PRIORITY_IDLE 0
#define PRIORITY_LOW 1
#define PRIORITY_NORMAL 2
#define PRIORITY_HIGH 3
#define PRIORITY_CRITICAL 4
// Task states
enum TaskState {
TASK_READY,
TASK_RUNNING,
TASK_WAITING,
TASK_SUSPENDED,
TASK_TERMINATED
};
// Task control block structure
struct TaskControlBlock {
void (*taskFunction)(void);
char name[16];
TaskState state;
uint8_t priority;
uint32_t delayTicks;
uint32_t deadlineTicks;
uint32_t executionCount;
uint32_t maxExecutionTime;
uint32_t totalExecutionTime;
uint32_t lastStartTime;
uint32_t lastDeadlineMiss;
bool periodic;
uint32_t periodTicks;
uint32_t stackPointer; // Simulated stack pointer for Arduino Uno
};
// Interrupt handler structure
struct InterruptHandler {
void (*handler)(void);
char name[16];
uint8_t priority;
uint32_t count;
bool enabled;
};
// Global system variables
TaskControlBlock tasks[MAX_TASKS];
InterruptHandler interrupts[MAX_INTERRUPTS];
volatile uint32_t systemTickCount = 0;
volatile bool contextSwitchRequested = false;
uint8_t currentTaskIndex = 0;
uint8_t taskCount = 0;
// Performance monitoring
struct SystemStats {
uint32_t totalTicks;
uint32_t idleTicks;
uint32_t contextSwitches;
uint32_t missedDeadlines;
float cpuUtilization;
uint32_t maxInterruptLatency;
uint32_t totalInterruptTime;
};
SystemStats stats;
// Task scheduling
volatile bool schedulerRunning = false;
// Initialize the real-time system
void initializeRTS() {
Serial.begin(115200);
delay(2000);
Serial.println("=== Arduino Real-Time System ===");
Serial.println("Initializing RTOS framework...");
// Initialize system
memset(&tasks, 0, sizeof(tasks));
memset(&interrupts, 0, sizeof(interrupts));
memset(&stats, 0, sizeof(stats));
// Configure timer interrupt for system tick
setupSystemTimer();
// Enable global interrupts
sei();
// Create system monitor task
createTask("SystemMonitor", PRIORITY_LOW, systemMonitorTask, 1000, false, 0);
schedulerRunning = true;
Serial.println("RTOS framework initialized");
Serial.printf("System tick interval: %d ms\n", SYSTEM_TICK_INTERVAL_MS);
Serial.printf("Maximum tasks: %d\n", MAX_TASKS);
}
void setupSystemTimer() {
// Configure Timer1 for system tick (Arduino Uno/Mega)
noInterrupts();
TCCR1A = 0; // Normal mode
TCCR1B = 0;
TCCR1C = 0;
// Set CTC mode
TCCR1B |= (1 << WGM12);
// Set prescaler to 64
TCCR1B |= (1 << CS11) | (1 << CS10);
// Set compare value for 1ms tick (16MHz / 64 / 1000 = 250)
OCR1A = 250;
// Enable compare match interrupt
TIMSK1 |= (1 << OCIE1A);
interrupts();
}
// System timer interrupt service routine
ISR(TIMER1_COMPA_vect) {
systemTickCount++;
// Check for task delays and deadlines
checkTaskDeadlines();
// Request context switch if needed
contextSwitchRequested = true;
}
// Task management functions
int createTask(const char* name, uint8_t priority, void (*taskFunction)(void),
uint32_t period, bool periodic, uint32_t initialDelay) {
if (taskCount >= MAX_TASKS) {
return -1; // No free task slots
}
// Find free task slot
for (int i = 0; i < MAX_TASKS; i++) {
if (tasks[i].taskFunction == NULL) {
// Initialize task control block
strncpy(tasks[i].name, name, sizeof(tasks[i].name) - 1);
tasks[i].name[sizeof(tasks[i].name) - 1] = '\0';
tasks[i].taskFunction = taskFunction;
tasks[i].state = TASK_READY;
tasks[i].priority = priority;
tasks[i].delayTicks = MS_TO_TICK_COUNT(initialDelay);
tasks[i].deadlineTicks = 0;
tasks[i].executionCount = 0;
tasks[i].maxExecutionTime = 0;
tasks[i].totalExecutionTime = 0;
tasks[i].lastStartTime = 0;
tasks[i].lastDeadlineMiss = 0;
tasks[i].periodic = periodic;
tasks[i].periodTicks = MS_TO_TICK_COUNT(period);
tasks[i].stackPointer = 0; // Simplified for Arduino
taskCount++;
Serial.printf("Task created: %s (Priority: %d)\n", name, priority);
return i;
}
}
return -1; // No free slots
}
void terminateTask(int taskIndex) {
if (taskIndex >= 0 && taskIndex < MAX_TASKS && tasks[taskIndex].taskFunction != NULL) {
tasks[taskIndex].state = TASK_TERMINATED;
tasks[taskIndex].taskFunction = NULL;
taskCount--;
Serial.printf("Task terminated: %s\n", tasks[taskIndex].name);
}
}
void suspendTask(int taskIndex) {
if (taskIndex >= 0 && taskIndex < MAX_TASKS) {
tasks[taskIndex].state = TASK_SUSPENDED;
Serial.printf("Task suspended: %s\n", tasks[taskIndex].name);
}
}
void resumeTask(int taskIndex) {
if (taskIndex >= 0 && taskIndex < MAX_TASKS) {
if (tasks[taskIndex].state == TASK_SUSPENDED) {
tasks[taskIndex].state = TASK_READY;
Serial.printf("Task resumed: %s\n", tasks[taskIndex].name);
}
}
}
void setTaskPriority(int taskIndex, uint8_t priority) {
if (taskIndex >= 0 && taskIndex < MAX_TASKS) {
tasks[taskIndex].priority = priority;
Serial.printf("Task priority updated: %s -> %d\n",
tasks[taskIndex].name, priority);
}
}
// Task delay functions
void taskDelay(uint32_t milliseconds) {
int currentTask = currentTaskIndex;
if (currentTask >= 0 && currentTask < MAX_TASKS) {
tasks[currentTask].state = TASK_WAITING;
tasks[currentTask].delayTicks = MS_TO_TICK_COUNT(milliseconds);
}
}
void taskDelayUntil(uint32_t milliseconds) {
int currentTask = currentTaskIndex;
if (currentTask >= 0 && currentTask < MAX_TASKS) {
tasks[currentTask].delayTicks = MS_TO_TICK_COUNT(milliseconds) - systemTickCount;
tasks[currentTask].state = TASK_WAITING;
}
}
// Scheduling functions
void schedule() {
if (!schedulerRunning) return;
int highestPriorityTask = -1;
uint8_t highestPriority = 0;
// Find highest priority ready task
for (int i = 0; i < MAX_TASKS; i++) {
if (tasks[i].state == TASK_READY && tasks[i].priority > highestPriority) {
highestPriority = tasks[i].priority;
highestPriorityTask = i;
}
}
// Context switch if needed
if (highestPriorityTask != -1 && highestPriorityTask != currentTaskIndex) {
performContextSwitch(highestPriorityTask);
}
// Check for idle state
if (highestPriorityTask == -1) {
stats.idleTicks++;
handleIdleState();
}
}
void performContextSwitch(int newTaskIndex) {
// Save current task state
if (currentTaskIndex >= 0 && currentTaskIndex < MAX_TASKS) {
tasks[currentTaskIndex].state = TASK_READY;
}
// Switch to new task
currentTaskIndex = newTaskIndex;
if (currentTaskIndex >= 0 && currentTaskIndex < MAX_TASKS) {
tasks[currentTaskIndex].state = TASK_RUNNING;
tasks[currentTaskIndex].lastStartTime = systemTickCount;
}
stats.contextSwitches++;
}
void checkTaskDeadlines() {
for (int i = 0; i < MAX_TASKS; i++) {
if (tasks[i].state == TASK_TERMINATED || tasks[i].taskFunction == NULL) {
continue;
}
// Update delays
if (tasks[i].state == TASK_WAITING) {
if (tasks[i].delayTicks > 0) {
tasks[i].delayTicks--;
} else {
tasks[i].state = TASK_READY;
}
}
// Check deadlines for running tasks
if (tasks[i].state == TASK_RUNNING && tasks[i].deadlineTicks > 0) {
if (systemTickCount >= tasks[i].deadlineTicks) {
tasks[i].lastDeadlineMiss = systemTickCount;
stats.missedDeadlines++;
Serial.printf("DEADLINE MISSED: %s\n", tasks[i].name);
}
}
// Handle periodic tasks
if (tasks[i].periodic && tasks[i].state == TASK_READY) {
if (tasks[i].deadlineTicks <= systemTickCount) {
tasks[i].deadlineTicks = systemTickCount + tasks[i].periodTicks;
}
}
}
}
void handleIdleState() {
// Enter low power mode when idle
// This is a simplified implementation
set_sleep_mode(SLEEP_MODE_IDLE);
sleep_mode();
}
// Interrupt management
int registerInterrupt(const char* name, uint8_t priority, void (*handler)(void)) {
for (int i = 0; i < MAX_INTERRUPTS; i++) {
if (interrupts[i].handler == NULL) {
strncpy(interrupts[i].name, name, sizeof(interrupts[i].name) - 1);
interrupts[i].name[sizeof(interrupts[i].name) - 1] = '\0';
interrupts[i].handler = handler;
interrupts[i].priority = priority;
interrupts[i].count = 0;
interrupts[i].enabled = true;
Serial.printf("Interrupt registered: %s (Priority: %d)\n", name, priority);
return i;
}
}
return -1;
}
void enableInterrupt(int interruptIndex) {
if (interruptIndex >= 0 && interruptIndex < MAX_INTERRUPTS) {
interrupts[interruptIndex].enabled = true;
Serial.printf("Interrupt enabled: %s\n", interrupts[interruptIndex].name);
}
}
void disableInterrupt(int interruptIndex) {
if (interruptIndex >= 0 && interruptIndex < MAX_INTERRUPTS) {
interrupts[interruptIndex].enabled = false;
Serial.printf("Interrupt disabled: %s\n", interrupts[interruptIndex].name);
}
}
// Sample tasks
void systemMonitorTask() {
while (true) {
// Calculate CPU utilization
float utilization = ((float)(stats.totalTicks - stats.idleTicks) / stats.totalTicks) * 100.0;
stats.cpuUtilization = utilization;
// Print system statistics
static unsigned long lastPrint = 0;
if (systemTickCount - lastPrint >= TICK_COUNT_TO_MS(5000)) { // Print every 5 seconds
printSystemStats();
lastPrint = systemTickCount;
}
taskDelay(1000); // Monitor every second
}
}
void blinkLEDTask() {
const int ledPin = 13;
pinMode(ledPin, OUTPUT);
while (true) {
digitalWrite(ledPin, HIGH);
taskDelay(500);
digitalWrite(ledPin, LOW);
taskDelay(500);
}
}
void readSensorTask() {
while (true) {
int sensorValue = analogRead(A0);
float voltage = (sensorValue / 1023.0) * 5.0;
Serial.printf("Sensor reading: %d (%.2fV)\n", sensorValue, voltage);
taskDelay(2000); // Read every 2 seconds
}
}
void highPriorityTask() {
uint32_t count = 0;
while (true) {
count++;
Serial.printf("High priority task count: %lu\n", count);
// This task should complete quickly
taskDelay(100);
}
}
void deadlineTask() {
while (true) {
uint32_t startTime = systemTickCount;
// Simulate variable workload
int workload = random(50, 200);
delayMicroseconds(workload * 1000);
uint32_t executionTime = systemTickCount - startTime;
Serial.printf("Deadline task executed in %lu ms\n", TICK_COUNT_TO_MS(executionTime));
// Wait until next period
taskDelayUntil(1000); // Execute every second with deadline
}
}
// Performance monitoring functions
void printSystemStats() {
Serial.println("\n=== System Statistics ===");
Serial.printf("System Ticks: %lu\n", systemTickCount);
Serial.printf("Total Ticks: %lu\n", stats.totalTicks);
Serial.printf("Idle Ticks: %lu\n", stats.idleTicks);
Serial.printf("CPU Utilization: %.2f%%\n", stats.cpuUtilization);
Serial.printf("Context Switches: %lu\n", stats.contextSwitches);
Serial.printf("Missed Deadlines: %lu\n", stats.missedDeadlines);
Serial.printf("Active Tasks: %d\n", taskCount);
Serial.printf("Free Memory: %d bytes\n", getFreeMemory());
// Print task statistics
Serial.println("\n--- Task Statistics ---");
for (int i = 0; i < MAX_TASKS; i++) {
if (tasks[i].taskFunction != NULL) {
Serial.printf("%s: State=%d, Priority=%d, Count=%lu\n",
tasks[i].name, tasks[i].state, tasks[i].priority, tasks[i].executionCount);
}
}
Serial.println("========================");
}
int getFreeMemory() {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
// Main application
void setup() {
initializeRTS();
// Create example tasks
createTask("BlinkLED", PRIORITY_NORMAL, blinkLEDTask, 0, false, 1000);
createTask("ReadSensor", PRIORITY_NORMAL, readSensorTask, 0, false, 2000);
createTask("HighPriority", PRIORITY_HIGH, highPriorityTask, 0, false, 100);
createTask("DeadlineTask", PRIORITY_CRITICAL, deadlineTask, 1000, true, 500);
// Create interrupts
registerInterrupt("Timer2", PRIORITY_HIGH, timer2Handler);
Serial.println("System ready, starting scheduler...");
}
void loop() {
if (schedulerRunning) {
stats.totalTicks++;
schedule();
// This loop provides the basic scheduling infrastructure
// Real work is done in the scheduler and interrupt handlers
delayMicroseconds(100); // Small delay to prevent busy-waiting
}
}
// Example interrupt handler
void timer2Handler() {
// This would be triggered by Timer2 overflow or compare match
// For demonstration purposes, we'll just increment a counter
static uint32_t counter = 0;
counter++;
// Toggle pin to show interrupt is working
static uint8_t pinState = 0;
pinState = !pinState;
digitalWrite(3, pinState);
}
// Utility functions for timing constraints
bool hasTimeRemaining(uint32_t startTime, uint32_t budget) {
uint32_t elapsedTime = systemTickCount - startTime;
return (elapsedTime < MS_TO_TICK_COUNT(budget));
}
uint32_t getRemainingTime(uint32_t startTime, uint32_t budget) {
uint32_t elapsedTime = systemTickCount - startTime;
uint32_t budgetTicks = MS_TO_TICK_COUNT(budget);
if (elapsedTime >= budgetTicks) {
return 0;
}
return TICK_COUNT_TO_MS(budgetTicks - elapsedTime);
}
// Time constraint checking macros
#define TIME_CONSTRAINT_START(budget) uint32_t __startTime = systemTickCount; uint32_t __budget = (budget)
#define CHECK_TIME_CONSTRAINT() if (!hasTimeRemaining(__startTime, __budget)) { Serial.println("TIME CONSTRAINT VIOLATED"); return; }
#define GET_REMAINING_TIME() getRemainingTime(__startTime, __budget)
// Example usage of time constraints
void timeConstrainedTask() {
TIME_CONSTRAINT_START(10); // 10ms budget
// Some time-critical work
CHECK_TIME_CONSTRAINT();
// More work
CHECK_TIME_CONSTRAINT();
// Final work
uint32_t remaining = GET_REMAINING_TIME();
Serial.printf("Time remaining: %lu ms\n", remaining);
}
// Real-time message passing system
struct Message {
uint8_t type;
uint8_t source;
uint8_t destination;
uint8_t data[16];
uint32_t timestamp;
};
#define MESSAGE_QUEUE_SIZE 10
Message messageQueue[MESSAGE_QUEUE_SIZE];
volatile int messageQueueHead = 0;
volatile int messageQueueTail = 0;
bool sendMessage(uint8_t type, uint8_t dest, uint8_t* data, uint8_t dataSize) {
int nextTail = (messageQueueTail + 1) % MESSAGE_QUEUE_SIZE;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE);
if (nextTail == messageQueueHead) {
ATOMIC_BLOCK(ATOMIC_RESTORESTATE);
return false; // Queue full
}
Message& msg = messageQueue[messageQueueTail];
msg.type = type;
msg.source = currentTaskIndex;
msg.destination = dest;
msg.timestamp = systemTickCount;
if (dataSize > 16) dataSize = 16;
memcpy(msg.data, data, dataSize);
messageQueueTail = nextTail;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE);
return true;
}
bool receiveMessage(uint8_t type, Message* msg) {
ATOMIC_BLOCK(ATOMIC_RESTORESTATE);
if (messageQueueHead == messageQueueTail) {
ATOMIC_BLOCK(ATOMIC_RESTORESTATE);
return false; // Queue empty
}
if (messageQueue[messageQueueHead].type != type) {
ATOMIC_BLOCK(ATOMIC_RESTORESTATE);
return false; // Wrong message type
}
*msg = messageQueue[messageQueueHead];
messageQueueHead = (messageQueueHead + 1) % MESSAGE_QUEUE_SIZE;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE);
return true;
}
// Example message passing tasks
void producerTask() {
uint8_t counter = 0;
while (true) {
uint8_t data[] = {counter};
sendMessage(1, 2, data, sizeof(data));
counter++;
taskDelay(1000);
}
}
void consumerTask() {
Message msg;
while (true) {
if (receiveMessage(1, &msg)) {
Serial.printf("Received message from task %d: %d\n",
msg.source, msg.data[0]);
}
taskDelay(100);
}
}
// Watchdog timer implementation
volatile uint32_t watchdogCounter = 0;
volatile bool watchdogReset = false;
void initializeWatchdog() {
registerInterrupt("Watchdog", PRIORITY_CRITICAL, watchdogHandler);
}
void resetWatchdog() {
watchdogCounter = 0;
}
void watchdogHandler() {
if (!watchdogReset) {
watchdogCounter++;
// Trigger reset if watchdog not reset within timeout
if (watchdogCounter > 1000) { // 1 second timeout
Serial.println("Watchdog timeout! Resetting...");
asm volatile ("jmp 0");
}
}
}
// Use the watchdog in critical tasks
void criticalTask() {
resetWatchdog();
while (true) {
// Critical work here
resetWatchdog();
taskDelay(100);
}
}