Einheit 3 / 9

Eingebettete Systeme und Mikrocontroller-Codegenerierung

Gewinne:

  • Möglichkeit, eingebetteten Code mit gegebenem Register- und Hardwarekontext für Arduino/STM32/ESP32 mit KI zu generieren
  • Fähigkeit, eingebettete Muster wie Interrupts, Timer und nicht blockierende Schleifen in der KI-Ausgabe zu erkennen und zu korrigieren
  • Möglichkeit, den generierten Code hinsichtlich Speicher, Echtzeit und Sicherheit zu überprüfen, bevor er auf die Hardware hochgeladen wird

In der Mechatronik ist der Mikrocontroller der Ort, an dem Ideen auf die physische Welt treffen. Karten wie Arduino, STM32, ESP32; Es liest Sensoren, steuert Aktoren, kommuniziert und tut dies alles unter begrenztem Speicher, begrenzter Verarbeitungsleistung und strengen Timing-Anforderungen. Künstliche Intelligenz ist in diesem Bereich sehr nützlich: Sie kann Registereinstellungen basierend auf dem Datenblatt eines Sensors extrahieren, ein Kommunikationsprotokoll codieren und einen Timer-Interrupt festlegen. Aber eingebettete Systeme gehören zu den Bereichen, in denen KI die „überzeugendsten Unwahrheiten“ produziert; denn Registeradressen, Bitmasken und Timing-Verhalten sind kartenspezifisch und ein Bitfehler stört das gesamte Verhalten. In dieser Einheit erfahren Sie, wie Sie eingebetteten Code mit KI generieren lassen und wie Sie ihn überprüfen, bevor Sie ihn in die Hardware laden.

Unterschied zwischen eingebettetem Code und reiner Software

Ein Desktop-Programm verfügt über ausreichend Speicher, Betriebssystem und einfaches Debuggen. Im eingebetteten Code fehlen die meisten davon:

Größe

Desktop

eingebettetes System

Erinnerung

GB-Ebene

KB-Ebene (z. B. 2 KB RAM)

Timing

Generell flexibel

Eng, in Echtzeit

Debuggen

Einfach (Debugger, Protokoll)

Hart (JTAG, seriell, LED)

Fehlerergebnis

Das Programm stürzt ab

Aktuator/Hardware könnten beschädigt sein

Ressourcenzugriff

Zusammenfassungen zum Betriebssystem

Direkter Zugriff auf das Register

Diese Unterschiede bestimmen Ihre Kriterien für die Bewertung der KI-Ausgabe: Speichernutzung, Echtzeit (nicht blockierend) und Hardware-Registergenauigkeit stehen immer ganz oben auf Ihrer Checkliste.

Blocker vs. nicht blockierender Code

Der häufigste Fehler, den Anfänger machen (und der häufig von KI gemacht wird), ist die Verwendung von delay(). Verzögerung(1000) sperrt den Prozessor für 1 Sekunde; In diesem Zeitraum können keine anderen Sensoren ausgelesen, keine Tasten angesteuert werden. Das ist in der Mechatronik nicht akzeptabel. Stattdessen wird ein auf millis() basierendes, nicht blockierendes Muster verwendet.

// SCHLECHT: Blocker – Prozessor kann 1 Sekunde lang keine andere Arbeit erledigen void loop() { digitalWrite(LED, HIGH); Verzögerung (1000); // alles stoppt digitalWrite(LED, LOW); Verzögerung (1000); // Ein Notfallknopf kann derzeit nicht gelesen werden!}// GUT: nicht blockierend – die Schleife wird nicht blockiert, andere Aufgaben werden ausgeführt if (nowMs - previousMs >= Interval) { previousMs = nowMs; ledStatus = !ledStatus; digitalWrite(LED, ledStatus); } buttonCheck(); // kann in jedem Zyklus ausgeführt werden sensorRead(); //kann in jeder Schleife ausgeführt werden}

Das nicht blockierende Muster ist die Grundlage der eingebetteten Mechatronik: Der Regelkreis fließt kontinuierlich, keine Aufgabe sperrt eine andere. Wenn Sie der KI sagen, dass sie beim Schreiben von Code „keine Verzögerung verwenden und Millis-basiertes Nichtblockieren schreiben“ soll, wird die Qualität der Ausgabe direkt verbessert.

Tipp: Achten Sie auf Verzögerungen im eingebetteten Code der KI. Wenn Sie eine Verzögerung im Hauptregelkreis feststellen, ist dieser Code meist nicht für ein Echtzeitsystem geeignet und sollte neu geschrieben werden.

Interrupts und Timer

Wir erfassen zeitkritische Ereignisse (Encoderimpuls, Taste, periodische Abtastung) mit Interrupts, anstatt in der Hauptschleife zu warten. Die Interrupt-Routine (ISR) sollte kurz und sorgfältig geschrieben sein: keine Verzögerungen, Serial.print oder lange Berechnungen darin; Gemeinsam genutzte Variablen sind als flüchtig gekennzeichnet.

volatiler langer EncoderCounter = 0; // ISR und Schleife werden gemeinsam genutzt -> flüchtige Bedingung void enkoderISR() { // Kurzes ISR: nur zählen, keine andere Arbeit ausführen if (digitalRead(ENC_B)) enkoderCounter++; else encoderCounter--;}void setup() { pinMode(ENC_A, INPUT_PULLUP); pinMode(ENC_B, INPUT_PULLUP); attachmentInterrupt(digitalPinToInterrupt(ENC_A), enkoderISR, RISING);}void loop() { long counter; noInterrupts(); //kurze Interrupts für atomares Lesen counter = EncoderCounter; unterbricht(); //Sichere Transaktionen mit dem Zähler durchführen...}

Drei kritische Punkte in diesem Beispiel sind, wo die KI oft übersieht: (1) der gemeinsam genutzte EncoderCounter muss „volatil“ sein, sonst werden der Compiler-Optimierung Aktualisierungen entgehen; (2) der ISR sollte kurz sein; (3) Beim Lesen einer Multibyte-Variablen in der Hauptschleife müssen Interrupts für das atomare Lesen für kurze Zeit geschlossen werden, da sonst ISR beim Lesen eingreifen und möglicherweise ein halber/beschädigter Wert gelesen wird (Race Condition). Überprüfen Sie unbedingt, ob diese drei im AI-Code vorhanden sind.

Registrieren Sie Genauigkeit und Datenblatt

KI kann die Registeradresse eines Sensors oder das Konfigurationsbit einer MCU glaubhaft falsch darstellen. Das Energieverwaltungsregister einer MPU6050-IMU ist beispielsweise 0x6B; Wenn die KI dies als 0x6A angibt, ist der Code kompiliert, er scheint zu funktionieren, aber der Sensor wacht nicht auf. Solche Fehler werden nur beim Vergleich mit dem Datenblatt erkannt.

// MPU6050 Wake-up: gemäß Datenblatt PWR_MGMT_1 = 0x6B, Wert 0x00#define MPU_ADDR 0x68#define PWR_MGMT_1 0x6B // <-- VERIFY from datasheetWire.beginTransmission(MPU_ADDR);Wire.write(PWR_MGMT_1);Wire.write(0x00); // aus dem Schlafmodus aufwachenWire.endTransmission(true);

Achtung: Überprüfen Sie jede von AI angegebene Registeradresse, Bitmaske und I2C/SPI-Adresse anhand des Datenblatts. Diese Werte sind karten- und chipspezifisch; Der Wert, den sich die KI „merkt“, stammt möglicherweise von einer anderen Chip-Revision. Eine falsche Registrierung führt stillschweigend zu falschem Verhalten.

Schwache Eingabeaufforderung / Starke Eingabeaufforderung

SCHWACH: „Temperatursensor auf ESP32 lesen.“ (Welcher Sensor? Welches Protokoll? Welcher Pin? Allgemeiner, wahrscheinlich falscher Code.)STRONG: „Lesen Sie einen DS18B20-Temperatursensor auf ESP32 (Arduino-Framework) von GPIO4 mit OneWire. Nicht blockierend schreiben, alle 1 Sekunde abtasten (mit Verzögerung, Millisekunden). Fehler-Flag im Falle eines Lesefehlers setzen (fester Wert -127 oder 85). Bitte geben Sie jede Bibliothek und Pin-Verbindung an, die Sie im verwenden erster Kommentar: Aus Speichergründen char buffer statt String verwenden.

Leistungsstarke Eingabeaufforderung; Es gibt den Chip, das Framework, den Sensor, das Protokoll, den Pin, das Abtastmuster, den Fehlerstatus und die Speicherbeschränkung an. Auf diese Weise ist die Ausgabe sowohl überprüfbar als auch realistisch.

Überprüfen Sie die Checkliste für eingebetteten Code

Führen Sie die KI-Ausgabe vor dem Laden durch diese Liste:

  1. Blockierung: Gibt es eine Verzögerung oder eine lange Blockierung in der Hauptschleife?
  2. volatile: Werden Variablen mit ISR volatile geteilt?
  3. Atomarer Zugriff: Ist eine gemeinsam genutzte Mehrbyte-Variable sicher lesbar?
  4. Registrieren: Sind die Adressen und Bitmasken mit dem Datenblatt kompatibel?
  5. Speicher: String, große Arrays, führt die Rekursion zu einem Überlauf auf KB-Ebene?
  6. Fehlerbehandlung: Werden Sensorlesefehler und Kommunikations-Timeouts behandelt?
  7. Sicherer Start: Werden die Aktorausgänge beim Start in einen sicheren (passiven) Zustand versetzt?

Mini-Koffer

Baran, Ingenieur für eingebettete Systeme, lässt die KI den Code schreiben, der die IMU für eine Drohne liest. Der Code wird kompiliert und scheint zu funktionieren, aber die Winkelwerte sind bedeutungslos. Baran wendet die Checkliste an: vergleicht die Registeradressen mit dem Datenblatt und stellt fest, dass die KI das Gyroskop-Konfigurationsregister falsch ausgibt (0x1A statt 0x1B), sodass die Empfindlichkeitsskala falsch ist. Nach der Korrektur stabilisieren sich die Werte. Dann werden Verzögerungen (10) in der Hauptschleife angezeigt. Dies in eine Millis-basierte Struktur umwandeln, da eine Blockierung des Flugregelkreises inakzeptabel ist. Schließlich stellt es fest, dass die gemeinsam genutzte Zählervariable nicht flüchtig ist, und fügt sie hinzu. Die KI gab das Skelett schnell; In der Überprüfungsliste wurden jedoch drei verschiedene Fehler festgestellt: Register, Blocking und Volatile, und die Hardware war überhaupt nicht gefährdet.

Häufige Fehler

  • Beenden der Echtzeitreaktion durch Verwendung von „delay()“ im Hauptregelkreis.
  • Vermeiden Sie es, die mit ISR gemeinsam genutzte Variable flüchtig zu machen und eine unbemerkte Datenbeschädigung zu verursachen.
  • Eine Mehrbyte-Variable nicht atomar lesen und eine Race-Bedingung generieren.
  • Die von AI angegebenen Register-/Bitmasken werden nicht mit dem Datenblatt überprüft.
  • Erstellen eines Speicherüberlaufs durch die Verwendung von Strings und großen Arrays in begrenztem RAM.
  • Vergessen, die Aktorausgänge zunächst zu sichern.

Zusammenfassend

  • Eingebetteter Code; Es arbeitet mit begrenztem Speicher, engem Timing und direktem Registerzugriff.
  • In der Hauptschleife wird anstelle der Verzögerung ein nicht blockierendes Muster auf Millis-Basis verwendet.
  • ISR wird kurz gehalten; Gemeinsam genutzte Variablen müssen flüchtig sein und einen atomaren Zugriff ermöglichen.
  • Registeradressen und Bitmasken werden immer anhand des Datenblatts überprüft. KI kann falsch liegen.
  • Speicher, Fehlerbehandlung und sicherer Startstatus werden immer überprüft.
  • Leistungsstarke Eingabeaufforderung; Es umfasst den Chip, das Framework, den Sensor, das Protokoll, den Pin und Einschränkungen.

Anwendungsaufgabe

Wählen Sie einen Sensor (z. B. DS18B20, MPU6050 oder HC-SR04) und einen Mikrocontroller (Arduino/ESP32/STM32). Lassen Sie die KI mit der leistungsstarken Eingabeaufforderungsvorlage in dieser Einheit einen nicht blockierenden Lesecode generieren. Befolgen Sie dann nacheinander die sieben Punkte der Überprüfungscheckliste: Vergleichen Sie mindestens einen Register-/Pin-Wert mit dem Datenblatt, prüfen Sie, ob Schleifenverzögerungen vorliegen, prüfen Sie den flüchtigen Status gemeinsam genutzter Variablen. Wie viele Punkte haben beim ersten Versuch „bestanden“ und wie viele mussten korrigiert werden? Notieren Sie sich jedes gefundene Problem und dessen Lösung.