Enhet 3 / 9

Inbyggda system och generering av mikrokontrollerkoder

Vinster:

  • Möjlighet att generera inbäddad kod givet register och hårdvarukontext för Arduino/STM32/ESP32 med AI
  • Möjlighet att känna igen och korrigera inbäddade mönster som avbrott, timers och icke-blockerande loopar i AI-utgång
  • Möjlighet att granska den genererade koden vad gäller minne, realtid och säkerhet innan den laddas upp till hårdvaran

Inom mekatronik är mikrokontrollern där idéer möter den fysiska världen. Kort som Arduino, STM32, ESP32; den läser sensorer, driver ställdon, kommunicerar och gör allt detta under begränsat minne, begränsad processorkraft och strikta tidskrav. Artificiell intelligens är mycket användbar inom detta område: den kan extrahera registerinställningar baserat på en sensors datablad, koda ett kommunikationsprotokoll, ställa in ett timeravbrott. Men inbyggda system är ett av de områden där AI producerar de mest "övertygande falskheterna"; eftersom registeradresser, bitmasker och timingbeteende är specifika för kortet och ett bitfel stör hela beteendet. I den här enheten tar vi upp hur man får inbäddad kod genererad med AI och hur man granskar den innan den laddas in i hårdvaran.

Skillnaden mellan inbäddad kod från Pure Software

Ett skrivbordsprogram har gott om minne, operativsystem och enkel felsökning. Inbäddad kod saknar de flesta av dessa:

Storlek

skrivbordet

inbyggt system

minne

GB nivå

KB-nivå (t.ex. 2 KB RAM)

timing

Generellt flexibel

Tight, realtid

felsökning

Enkelt (debugger, logg)

Hård (JTAG, seriell, LED)

Felresultat

Programmet kraschar

Ställdon/hårdvara kan vara skadad

tillgång till resurser

OS-sammandrag

Direkt tillgång till registret

Dessa skillnader avgör dina kriterier för att utvärdera AI-utdata: minnesanvändning, realtid (icke-blockerande) och hårdvaruregistrets noggrannhet är alltid högst upp på din checklista.

Blockerare vs icke-blockerande kod

Det vanligaste misstaget som görs av nybörjare (och ofta görs av AI) är användningen av delay(). delay(1000) låser processorn i 1 sekund; Under denna period kan inga andra sensorer avläsas, inga knappar kan styras. Detta är oacceptabelt inom mekatronik. Istället används ett millis()-baserat icke-blockerande mönster.

// BAD: blocker - processorn kan inte göra något annat arbete under 1 sekund void loop() { digitalWrite(LED, HIGH); fördröjning(1000); // allt stannar digitalWrite(LED, LÅG); fördröjning(1000); // En nödknapp kan inte läsas just nu!}// BRA: icke-blockerande -- slingan är inte blockerad, andra uppgifter körs if (nowMs - previousMs >= interval) { previousMs = nowMs; ledStatus = !ledStatus; digitalWrite(LED, ledStatus); } buttonCheck(); // kan köras i varje cykel sensorRead(); //kan köras i valfri slinga}

Det icke-blockerande mönstret är grunden för inbyggd mekatronik: styrslingan flödar kontinuerligt, ingen uppgift låser ut en annan. Att säga till AI:n att "inte använda fördröjning, skriv millis-baserad icke-blockering" när du skriver kod förbättrar kvaliteten på utdata direkt.

Tips: Leta efter fördröjning( i den inbäddade koden från AI. Om du ser en fördröjning i huvudkontrollslingan är den koden oftast inte lämplig för ett realtidssystem och bör skrivas om.

Avbrott och timer

Vi fångar tidskritiska händelser (kodarpuls, knapp, periodisk sampling) med avbrott istället för att vänta i huvudslingan. Avbrottsrutinen (ISR) bör skrivas kort och noggrant: inga förseningar, Serial.print eller långa beräkningar i den; Delade variabler är markerade som flyktiga.

volatile long encoderCounter = 0; // ISR och loop delas -> volatile condition void enkoderISR() { // Kort ISR: bara räkna, gör inget annat arbete if (digitalRead(ENC_B)) enkoderCounter++; else encoderCounter--;}void setup() { pinMode(ENC_A, INPUT_PULLUP); pinMode(ENC_B, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(ENC_A), enkoderISR, RISING);}void loop() { long counter; noInterrupts(); //korta avbrott för atomavläsningsräknare = encoderCounter; avbryter(); //handla säkert med räknaren...}

Tre kritiska punkter i det här exemplet är där AI:n ofta missar: (1) den delade encoderCountern måste vara "flyktig" annars kommer kompilatoroptimeringen att missa uppdateringar; (2) ISR bör vara kort; (3) Vid läsning av en multi-byte-variabel i huvudslingan måste avbrott för atomavläsning stängas under en kort tid, annars kan ISR ingripa under läsning och halvt/korrupt värde kan läsas (rasvillkor). Se till att kontrollera om dessa tre finns i AI-koden.

Registrera noggrannhet och datablad

AI kan på ett trovärdigt sätt förvränga registeradressen för en sensor eller konfigurationsbiten för en MCU. Till exempel är strömhanteringsregistret för en MPU6050 IMU 0x6B; Om AI:n ger detta som 0x6A, kompileras koden, det verkar fungera, men sensorn vaknar inte. Sådana fel upptäcks endast i jämförelse med databladet.

// MPU6050 wake-up: enligt datablad PWR_MGMT_1 = 0x6B, värde 0x00#define MPU_ADDR 0x68#define PWR_MGMT_1 0x6B // <-- VERIFIERA från databladWire.beginTransmission(MPU_ADDR);Wire.write(PWR_MGMT_1);Wire.write(0x00); // vakna från vilolägeWire.endTransmission(true);

Observera: Verifiera varje registeradress, bitmask och I2C/SPI-adress som ges av AI från databladet. Dessa värden är kort- och chipspecifika; Värdet som AI:en "kommer ihåg" kan komma från en annan chiprevision. Felaktigt register leder tyst till felaktigt beteende.

Svag prompt / Stark prompt

SVAG:"Läs temperatursensor på ESP32."(Vilken sensor? Vilket protokoll? Vilket stift? Generiskt, troligtvis fel kod.)STARK:"Läs en DS18B20 temperatursensor på ESP32 (Arduino-ramverket) från GPIO4 med OneWire. Skriv icke-blockerande, prova var 1:e sekund (med fördröjning, millisfixerat värde i fallet med läs fel17 eller läs fel17). Ange varje bibliotek och pin-anslutning du använder i den första kommentaren Av minnesskäl, använd char buffer istället för String."

Kraftfull uppmaning; Det ger chip, ramverk, sensor, protokoll, stift, samplingsmönster, felstatus och minnesbegränsning. På så sätt är resultatet både verifierbart och realistiskt.

Granska checklista för inbäddad kod

Innan du laddar AI-utgången, gå igenom den här listan:

  1. Blockering: Finns det en fördröjning eller lång blockering i huvudslingan?
  2. volatile: Är variabler som delas med ISR flyktiga?
  3. Atomic access: Är multi-byte delad variabel säker att läsa?
  4. Registrera: Är adresserna och bitmaskerna kompatibla med databladet?
  5. Minne: Sträng, stora arrayer, skapar rekursion KB-nivåspill?
  6. Felhantering: Hanteras sensoravläsningsfel, kommunikationstimeout?
  7. Säker start: Är ställdonets utgångar placerade i ett säkert (passivt) tillstånd vid start?

Minifodral

Inbyggda systemingenjör Baran låter AI skriva koden som läser IMU för en drönare. Koden kompileras och verkar fungera, men vinkelvärdena är meningslösa. Baran tillämpar checklistan: jämför registeradresserna med databladet och finner att AI:n felaktigt matar ut gyroskopkonfigurationsregistret (0x1A istället för 0x1B), så känslighetsskalan är fel. När de har korrigerats löser sig värdena. Sedan delay(10) meddelanden i huvudslingan; konvertera detta till en millis-baserad struktur, eftersom blockering av flygkontrollslingan är oacceptabelt. Slutligen ser den att den delade räknarvariabeln inte är volatil och lägger till den. AI gav skelettet snabbt; Men granskningslistan fångade tre separata fel: register, blockering och flyktig, och hårdvaran var inte i fara alls.

Vanliga misstag

  • Dödar realtidssvaret genom att använda delay() i huvudkontrollslingan.
  • Undvik att göra variabeln som delas med ISR flyktig och uppleva tyst datakorruption.
  • Läsa en multi-byte delad variabel icke-atomiskt och generera ett rastillstånd.
  • Inte verifierar register-/bitmaskerna som ges av AI med databladet.
  • Skapa ett minnesspill genom att använda strängar och stora arrayer i begränsat RAM.
  • Glömde att först säkra ställdonets utgångar.

Sammanfattningsvis

  • Inbäddad kod; Den fungerar med begränsat minne, snäv timing och direkt registeråtkomst.
  • I huvudslingan används ett millis-baserat icke-blockerande mönster istället för fördröjning.
  • ISR hålls kort; delade variabler måste vara flyktiga och atomär tillgängliga.
  • Registeradresser och bitmasker verifieras alltid mot databladet; AI kan ha fel.
  • Minne, felhantering och säker startstatus kontrolleras alltid.
  • Kraftfull uppmaning; Det inkluderar chip, ramverk, sensor, protokoll, stift och begränsningar.

Applikationsuppgift

Välj en sensor (t.ex. DS18B20, MPU6050 eller HC-SR04) och en mikrokontroller (Arduino/ESP32/STM32). Låt AI:n generera en icke-blockerande läskod med den kraftfulla promptmallen i den här enheten. Följ sedan de sju punkterna i granskningschecklistan en efter en: jämför minst ett register-/stiftvärde med databladet, kontrollera om det finns loopfördröjningar, kontrollera den flyktiga statusen för delade variabler. Hur många objekt "godkändes" vid första försöket och hur många krävde korrigering? Notera varje problem du hittar och dess fix.