单位 3 / 9

嵌入式系统和微控制器代码生成

收益:

  • 能够使用 AI 为 Arduino/STM32/ESP32 生成给定寄存器和硬件上下文的嵌入式代码
  • 能够识别和纠正 AI 输出中的嵌入式模式,例如中断、计时器和非阻塞循环
  • 在将生成的代码上传到硬件之前,能够从内存、实时性和安全性方面对其进行审查

在机电一体化领域,微控制器是思想与物理世界相遇的地方。 Arduino、STM32、ESP32等卡;它读取传感器、驱动执行器、通信,并在有限的内存、有限的处理能力和严格的时序要求下完成所有这些工作。人工智能在这个领域非常有用:它可以根据传感器的数据表提取寄存器设置,编写通信协议,设置定时器中断。但嵌入式系统是人工智能产生最“令人信服的谎言”的领域之一;因为寄存器地址、位掩码和时序行为是特定于电路板的,一位错误会破坏整个行为。在本单元中,我们将介绍如何使用人工智能生成嵌入式代码以及如何在将其加载到硬件之前对其进行检查。

嵌入式代码与纯软件的区别

桌面程序具有充足的内存、操作系统并且易于调试。嵌入式代码缺少其中大部分:

尺寸

桌面

嵌入式系统

记忆

国标级

KB 级(例如 2 KB RAM)

时机

一般都很灵活

严格、实时

调试

简单(调试器、日志)

硬(JTAG、串行、LED)

错误结果

程序崩溃

执行器/硬件可能损坏

资源访问

操作系统摘要

直接访问寄存器

这些差异决定了您评估 AI 输出的标准:内存使用情况、实时性(非阻塞)和硬件寄存器精度始终位于您的检查表的首位。

阻塞代码与非阻塞代码

初学者最常犯的错误(人工智能经常犯的错误)是使用delay()。延迟(1000)锁定处理器1秒;在此期间,无法读取其他传感器,也无法控制任何按钮。这在机电一体化中是不可接受的。相反,使用基于 millis() 的非阻塞模式。

// 不好:阻塞 - 处理器在 1 秒内无法执行任何其他工作 void Loop() { digitalWrite(LED, HIGH); 延迟(1000); // 一切都停止 digitalWrite(LED, LOW); 延迟(1000); // 此时无法读取紧急按钮!} // 好:非阻塞——循环不会阻塞,其他任务运行 if (nowMs - previousMs >= Interval) { previousMs = nowMs; ledStatus = !ledStatus; digitalWrite(LED, ledStatus); } 按钮检查(); // 可以在每个周期运行sensorRead(); //可以在任何循环中运行}

非阻塞模式是嵌入式机电一体化的基础:控制循环连续流动,没有任务会锁定另一个任务。告诉AI在编写代码时“不要使用延迟,编写基于毫秒的非阻塞”,直接提高了输出的质量。

提示:在 AI 的嵌入式代码中查找延迟(。如果您在主控制循环中看到延迟,则大多数情况下该代码不适合实时系统,应该重写。

中断和定时器

我们通过中断捕获时间关键事件(编码器脉冲、按钮、定期采样),而不是在主循环中等待。中断例程(ISR)应该写得简短而仔细:其中没有延迟、Serial.print 或长计算;共享变量被标记为易失性的。

易失性长编码器计数器 = 0; // ISR 和循环是共享的 -> 易失性条件 void enkoderISR() { // 短 ISR:只计数,不做其他工作 if (digitalRead(ENC_B)) enkoderCounter++; 否则encoderCounter--;}void setup() { pinMode(ENC_A, INPUT_PULLUP); pinMode(ENC_B, INPUT_PULLUP); AttachInterrupt(digitalPinToInterrupt(ENC_A), enkoderISR, RISING);}void Loop() { 长计数器; 没有中断(); //原子读取的短中断计数器=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 // <-- VERIFY from datasheetWire.beginTransmission(MPU_ADDR);Wire.write(PWR_MGMT_1);Wire.write(0x00); // 从睡眠模式唤醒Wire.endTransmission(true);

注意:验证 AI 从数据表中给出的每个寄存器地址、位掩码和 I2C/SPI 地址。这些值是卡和芯片特定的; AI“记住”的值可能来自另一个芯片版本。不正确的注册会默默地导致不正确的行为。

弱提示/强提示

弱:“读取 ESP32 上的温度传感器。”(哪个传感器?哪个协议?哪个引脚?通用,可能是错误的代码。)强:“使用 OneWire 从 GPIO4 读取 ESP32(Arduino 框架)上的 DS18B20 温度传感器。非阻塞写入,每 1 秒采样一次(使用延迟,基于毫秒)。设置错误标志以防读取错误(固定值 -127 或 85)。请指定您使用的每个库和引脚连接在第一条注释中,出于内存原因,请使用字符缓冲区而不是字符串。”

强大的提示功能;它给出了芯片、框架、传感器、协议、引脚、采样模式、错误状态和内存约束。这样,输出既可验证又现实。

嵌入式代码审查清单

在加载 AI 输出之前,将其传递到此列表:

  1. 阻塞:主循环中是否存在延迟或长时间阻塞?
  2. 易失性:与 ISR 共享的变量是否易失性?
  3. 原子访问:多字节共享变量读取安全吗?
  4. 寄存器:地址和位掩码与数据表兼容吗?
  5. 内存:字符串、大数组、递归是否会造成KB级溢出?
  6. 错误处理:传感器读取错误、通信超时是否得到处理?
  7. 安全启动:启动时执行器输出是否处于安全(被动)状态?

迷你包

嵌入式系统工程师 Baran 让 AI 编写读取无人机 IMU 的代码。代码编译并看起来可以工作,但角度值没有意义。 Baran应用检查表:将寄存器地址与数据表进行比较,发现AI错误地输出了陀螺仪配置寄存器(0x1A而不是0x1B),因此灵敏度标度是错误的。一旦修正,数值就稳定下来。然后delay(10)在主循环中通知;将其转换为基于毫秒的结构,因为阻塞飞行控制回路是不可接受的。最后,它发现共享计数器变量不是易失性的,并将其添加。 AI快速给出骨架;但审查列表发现了三个独立的错误:注册、阻塞和易失性,并且硬件根本没有面临风险。

常见错误

  • 通过在主控制循环中使用delay()来终止实时响应。
  • 避免使与 ISR 共享的变量易失并经历静默数据损坏。
  • 以非原子方式读取多字节共享变量并生成竞争条件。
  • 未使用数据表验证 AI 给出的寄存器/位掩码。
  • 在有限的 RAM 中使用字符串和大型数组会造成内存溢出。
  • 忘记最初保护执行器输出。

综上所述

  • 嵌入代码;它以有限的内存、严格的时序和直接寄存器访问的方式运行。
  • 在主循环中,使用基于毫秒的非阻塞模式而不是延迟。
  • ISR 保持简短;共享变量必须是易失性的并且是原子访问的。
  • 寄存器地址和位掩码始终根据数据表进行验证;人工智能可能是错误的。
  • 始终检查内存、错误处理和安全启动状态。
  • 强大的提示功能;它包括芯片、框架、传感器、协议、引脚和约束。

应用任务

选择传感器(例如 DS18B20、MPU6050 或 HC-SR04)和微控制器(Arduino/ESP32/STM32)。让AI用本单元强大的提示模板生成非阻塞读取代码。然后一一遵循检查清单的七个项目:将至少一个寄存器/引脚值与数据表进行比较,检查循环延迟,检查共享变量的易失性状态。有多少项在第一次尝试中“通过”了,有多少项需要纠正?记下您发现的每个问题及其解决方法。