единица 3 / 9

Вградени системи и генериране на код на микроконтролер

Печалби:

  • Възможност за генериране на вграден код, даден регистър и хардуерен контекст за Arduino/STM32/ESP32 с AI
  • Възможност за разпознаване и коригиране на вградени модели като прекъсвания, таймери и неблокиращи цикли в AI изхода
  • Възможност за преглед на генерирания код по отношение на памет, реално време и сигурност, преди да го качите на хардуера

В мехатрониката микроконтролерът е мястото, където идеите се срещат с физическия свят. Карти като Arduino, STM32, ESP32; той чете сензори, задвижва задвижващи механизми, комуникира и прави всичко това при ограничена памет, ограничена процесорна мощност и строги изисквания за време. Изкуственият интелект е много полезен в тази област: той може да извлича настройките на регистъра въз основа на листа с данни на сензора, да кодира комуникационен протокол, да задава прекъсване на таймера. Но вградените системи са една от областите, в които AI произвежда най-много „убедителни лъжи“; тъй като адресите на регистъра, битовите маски и поведението на синхронизирането са специфични за платката и една битова грешка нарушава цялото поведение. В този раздел ние разглеждаме как да имате вграден код, генериран с AI и как да го прегледате, преди да го заредите в хардуера.

Разлика на вградения код от чистия софтуер

Програмата за настолен компютър има много памет, операционна система и лесно отстраняване на грешки. Във вградения код липсват повечето от тези:

Размер

работен плот

вградена система

памет

GB ниво

Ниво KB (напр. 2 KB RAM)

синхронизация

Като цяло гъвкав

Напрегнато, в реално време

отстраняване на грешки

Лесно (дебъгер, лог)

Твърд (JTAG, сериен, LED)

Резултат от грешка

Програмата се срива

Актуаторът/хардуерът може да е повреден

достъп до ресурси

Резюмета на OS

Директен достъп до регистъра

Тези разлики определят вашите критерии за оценка на AI изхода: използването на паметта, точността на регистрите в реално време (без блокиране) и хардуерните регистри винаги са в горната част на вашия контролен списък.

Блокиращ срещу неблокиращ код

Най-честата грешка, допускана от начинаещи (и често допускана от AI) е използването на delay(). delay(1000) заключва процесора за 1 секунда; През този период не могат да се четат други сензори, не могат да се управляват бутони. Това е недопустимо в мехатрониката. Вместо това се използва базиран на millis() неблокиращ модел.

// ЛОШО: блокер -- процесорът не може да върши друга работа за 1 секунда void loop() { digitalWrite(LED, HIGH); забавяне (1000); // всичко спира digitalWrite(LED, LOW); забавяне (1000); // Авариен бутон не може да бъде прочетен в момента!}// ДОБРЕ: неблокиране -- цикълът не е блокиран, други задачи се изпълняват, ако (nowMs - previousMs >= интервал) { previousMs = nowMs; ledStatus = !ledStatus; digitalWrite(LED, ledStatus); } buttonCheck(); // може да работи във всеки цикъл sensorRead(); //може да работи във всеки цикъл}

Неблокиращият модел е в основата на вградената мехатроника: управляващият контур протича непрекъснато, никоя задача не блокира друга. Казването на AI ​​да „не използва забавяне, пиши на базата на милиси без блокиране“ при писане на код директно подобрява качеството на изхода.

Съвет: Потърсете delay( във вградения код от AI. Ако видите забавяне в главния контролен цикъл, най-често този код не е подходящ за система в реално време и трябва да бъде пренаписан.

Прекъсвания и таймери

Ние улавяме критични за времето събития (импулс на енкодер, бутон, периодично вземане на проби) с прекъсвания, вместо да чакаме в главния цикъл. Процедурата за прекъсване (ISR) трябва да бъде написана кратко и внимателно: без закъснения, Serial.print или дълги изчисления в нея; Споделените променливи са маркирани като непостоянни.

volatile long encoderCounter = 0; // ISR и цикълът се споделят -> променливо състояние void enkoderISR() { // Кратко ISR: просто преброяване, не правете друга работа 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() {дълъг брояч; noInterrupts(); //кратки прекъсвания за атомно четене counter = encoderCounter; прекъсва(); // извършвайте безопасна транзакция с брояча...}

Три критични точки в този пример са местата, където AI често пропуска: (1) споделеният encoderCounter трябва да е „нестабилен“ или оптимизацията на компилатора ще пропусне актуализации; (2) ISR трябва да е кратък; (3) При четене на многобайтова променлива в главния цикъл, прекъсванията за атомарно четене трябва да бъдат затворени за кратко време, в противен случай ISR може да се намеси по време на четене и може да се прочете половин/повредена стойност (състезание). Не забравяйте да проверите дали тези три присъстват в AI кода.

Регистрирайте точност и лист с данни

AI може достоверно да представи погрешно адреса на регистъра на сензор или конфигурационния бит на MCU. Например регистърът за управление на мощността на MPU6050 IMU е 0x6B; Ако AI ​​даде това като 0x6A, кодът се компилира, изглежда работи, но сензорът не се събужда. Такива грешки се откриват само при сравнение с листа с данни.

// MPU6050 събуждане: според листа с данни PWR_MGMT_1 = 0x6B, стойност 0x00#define MPU_ADDR 0x68#define PWR_MGMT_1 0x6B // <-- ПРОВЕРКА от datasheetWire.beginTransmission(MPU_ADDR);Wire.write(PWR_MGMT_1);Wire.write(0x00); // събуждане от спящ режимWire.endTransmission(true);

Внимание: Проверете всеки адрес на регистъра, битова маска и I2C/SPI адрес, дадени от AI от листа с данни. Тези стойности са специфични за картата и чипа; Стойността, която AI "помни" може да е от друга ревизия на чип. Неправилният регистър тихо води до неправилно поведение.

Слаба подкана / Силна подкана

СЛАБ: „Прочетете температурен сензор на ESP32.“ (Кой сензор? Кой протокол? Кой щифт? Общ, вероятно грешен код.) СИЛЕН: „Прочетете температурен сензор DS18B20 на ESP32 (Arduino framework) от GPIO4 с OneWire. Пишете без блокиране, извадка на всяка 1 секунда (използвайки забавяне, базирано на милисекунди). Задайте флаг за грешка в случай на грешка при четене (фиксирана стойност -127 или 85). Моля, посочете всяка библиотека и пин връзка, която използвате в първия коментар, използвайте char буфер вместо String."

Мощна подсказка; Той дава чипа, рамката, сензора, протокола, щифта, шаблона за вземане на проби, състоянието на грешката и ограничението на паметта. По този начин резултатът е едновременно проверим и реалистичен.

Прегледайте контролния списък за вграден код

Преди да заредите AI изхода, прекарайте го през този списък:

  1. Блокиране: Има ли забавяне или дълго блокиране в главния цикъл?
  2. volatile: Променливите, споделени с ISR, летливи ли са?
  3. Атомен достъп: Безопасна ли е за четене многобайтова споделена променлива?
  4. Регистрирайте се: адресите и битовите маски съвместими ли са с листа с данни?
  5. Памет: Низ, големи масиви, рекурсията създава ли препълване на KB ниво?
  6. Обработване на грешки: Обработват ли се грешки при четене на сензора, прекъсване на комуникацията?
  7. Безопасен старт: Изходите на задвижващия механизъм поставени ли са в безопасно (пасивно) състояние при стартиране?

Мини калъф

Инженерът по вградени системи Баран кара AI да напише кода, който чете IMU за дрон. Кодът се компилира и изглежда работи, но стойностите на ъглите са безсмислени. Баран прилага контролния списък: сравнява адресите на регистъра с листа с данни и открива, че AI неправилно извежда регистъра за конфигурация на жироскопа (0x1A вместо 0x1B), така че скалата на чувствителността е грешна. Веднъж коригирани, стойностите се установяват. След това delay(10) забелязва в главния цикъл; преобразувайки това в милис-базирана структура, тъй като блокирането на веригата за управление на полета е неприемливо. Накрая вижда, че споделената променлива на брояча не е непостоянна и я добавя. AI даде скелета бързо; Но списъкът за преглед улови три отделни грешки: регистър, блокиране и летливи, а хардуерът изобщо не беше изложен на риск.

Често срещани грешки

  • Убиване на отговора в реално време чрез използване на delay() в главния контролен цикъл.
  • Избягвайте да правите променливата, споделена с ISR, непостоянна и да изпитвате безшумна повреда на данните.
  • Четене на многобайтова споделена променлива неатомично и генериране на условие за състезание.
  • Не се проверяват регистрите/битовите маски, дадени от AI с листа с данни.
  • Създаване на препълване на паметта чрез използване на низове и големи масиви в ограничена RAM.
  • Забравяне на първоначалното осигуряване на изходите на задвижването.

В обобщение

  • Вграден код; Работи с ограничена памет, ограничено време и директен достъп до регистъра.
  • В главния цикъл се използва базиран на милиси неблокиращ модел вместо забавяне.
  • ISR се поддържа кратък; споделените променливи трябва да са непостоянни и с атомарен достъп.
  • Адресите на регистъра и битовите маски винаги се проверяват спрямо листа с данни; AI може да греши.
  • Винаги се проверяват паметта, обработката на грешки и състоянието на безопасно стартиране.
  • Мощна подсказка; Той включва чип, рамка, сензор, протокол, щифт и ограничения.

Задача за приложение

Изберете сензор (напр. DS18B20, MPU6050 или HC-SR04) и микроконтролер (Arduino/ESP32/STM32). Накарайте AI да генерира неблокиращ код за четене с мощния шаблон за подкана в това устройство. След това следвайте седемте елемента от контролния списък за преглед един по един: сравнете поне една стойност на регистър/пин с листа с данни, проверете за забавяния на цикъла, проверете променливото състояние на споделените променливи. Колко елемента са "преминали" при първия опит и колко изискват корекция? Отбележете всеки открит проблем и неговото отстраняване.