第 4 周个人作业:使用 AI 为 XIAO MG24 Sense 开发板编写应用程序
在完成基于 XIAO MG24 Sense 的嵌入式开发实践后,我们熟悉了基本的 Arduino 编程环境,以及如何在 Arduino IDE 中添加开发板、库,如何上传程序到开发版。有了这些基础,现在可以通过自然语言向 AI 描述需求,来获得所需的程序。
我们之前有 2 个示例,一个 Blink,一个 IMU 测试。比如我想将这 2 个示例程序结合起来,让程序通过计算 IMU 加速度计的平均加速度,来控制 LED 的亮度,当我疯狂摇晃 XIAO MG24 越剧烈,LED 就越亮。
这个项目我起名为:XIAO MG24 的 LED 的疯狂亮度计
如何编写编程类提示词
在向 AI 描述编程需求时,一个好的提示词应包含以下要素:
- 目标描述
- 清晰说明想要实现什么功能
- 用简单的语言描述期望的行为
- 已有资源
- 说明使用什么硬件/开发板
- 列出可用的传感器/组件
- 提到已有的相关代码示例
- 具体要求
- 指出关键的技术参数
- 说明特定的实现方式
- 提出性能或其他约束
- 输出期望
- 想要得到完整代码还是框架
- 是否需要注释说明
- 是否需要调试建议
疯狂亮度计的提示词示例
基于上述原则,我们可以这样描述疯狂亮度计的需求:
我想开发一个程序,让 XIAO MG24 Sense 的 LED 亮度随着晃动强度变化。具体要求:
- 硬件:
- 使用 XIAO MG24 Sense 开发板
- 使用板载 LSM6DS3TR-C 六轴传感器的加速度计功能
- 控制板载用户 LED
- 功能需求:
- 读取三轴加速度数据
- 计算三轴加速度的平均值作为晃动强度
- 将晃动强度映射为 LED 亮度
- LED 亮度范围: 0-255
- 采样频率建议 100ms
- 参考代码:
- 可参考 Blink 示例的 LED 控制部分
- 可参考 IMU 测试程序的传感器初始化和数据读取部分 请提供完整的代码,并添加关键部分的注释说明。
各种 AI 大语言模型正在快速的迭代更新,可以选择自己常用的 AI 来完成这个练习,下面我用 Claude 来测试 AI 的编程输出是否能达到期望。
本来开始计划使用 DeepSeek,但这个 AI 在我写这个文档的时候还不太稳定,和它展开几次聊天后,就不断提示:服务器繁忙,请稍后再试。所以我用了比较稳定的 Claude 来完成这个练习。
使用 Claude 编程
我在 Claude 聊天窗口选择了 Claude 3.5 Sonnet 模型,然后复制了刚才写好的提示词,以及 IMU test 程序和 Blink 程序,如下图所示。注意, Claude 不支持上传 Arduino 的.ino
程序上传,所以在这里我把示例程序直接粘贴到了聊天窗口。
在 Claude 聊天窗口输入需求和示例程序
很快,Claude 就输出了所需的程序,并添加了注释和说明。
Claude 按照需求输出了程序和说明
下面是 Claude 首次输出的程序
#include "LSM6DS3.h"
#include "Wire.h"
// 创建 IMU 对象,使用 I2C 通信模式
LSM6DS3 myIMU(I2C_MODE, 0x6A);
// 定义 LED 控制相关常量
const int LED_PIN = LED_BUILTIN; // 使用板载 LED
const int PWM_MAX = 255; // PWM 最大值
const int SAMPLE_INTERVAL = 100; // 采样间隔(ms)
// 定义加速度阈值
const float MIN_ACC = 0.0; // 最小加速度值
const float MAX_ACC = 3.0; // 最大加速度值(可根据实际情况调整)
void setup() {
// 初始化串口通信,用于调试
Serial.begin(115200);
Wire.begin();
delay(1000);
// 初始化 LED 引脚为输出模式
pinMode(LED_PIN, OUTPUT);
// 初始化 IMU 传感器
if (myIMU.begin() != 0) {
Serial.println("IMU 初始化失败!");
while (1); // 如果初始化失败,程序停止运行
}
Serial.println("IMU 初始化成功!");
}
void loop() {
// 读取三轴加速度数据
float accX = abs(myIMU.readFloatAccelX());
float accY = abs(myIMU.readFloatAccelY());
float accZ = abs(myIMU.readFloatAccelZ());
// 计算晃动强度(三轴加速度的平均值)
float shakeIntensity = (accX + accY + accZ) / 3.0;
// 将晃动强度映射为 LED 亮度(0-255)
int brightness = map(
constrain(shakeIntensity * 100, MIN_ACC * 100, MAX_ACC * 100),
MIN_ACC * 100,
MAX_ACC * 100,
0,
PWM_MAX
);
// 输出调试信息
Serial.print("加速度: X=");
Serial.print(accX);
Serial.print(" Y=");
Serial.print(accY);
Serial.print(" Z=");
Serial.print(accZ);
Serial.print(" 晃动强度=");
Serial.print(shakeIntensity);
Serial.print(" LED亮度=");
Serial.println(brightness);
// 设置 LED 亮度
analogWrite(LED_PIN, brightness);
// 等待下一次采样
delay(SAMPLE_INTERVAL);
}
把程序复制到 Arduino IDE,然后上传。没有出现任何错误,打开串口监视器,可以看到不断输出的加速度数值和期望的 LED 亮度值。
XIAO MG24 在成功上传程序后 LED 常亮,我如果拼命晃动 XIAO 才会熄灭,这和我们期望的不符。
通过向 AI 反馈结果修正程序
我大概知道是怎么回事,但对于不太懂编程原理的初学者,可以直接把现象告诉 Claude,让它改进程序。
我继续在聊天窗口向 Claude 描述了现象,Claude 再次给出了修改后的程序,如下图所示。
现在 LED 亮了,不过我静止 XIAO 的时候 LED 亮灯,晃动时熄灭,看串口监视器的输出是正确的,晃动厉害的时候,LED 亮度会变成255
进一步向 Claude 描述现象后,AI 再次给出了修改后的程序
修改后程序如下所示:
#include "LSM6DS3.h"
#include "Wire.h"
// 创建 IMU 对象,使用 I2C 通信模式
LSM6DS3 myIMU(I2C_MODE, 0x6A);
// 定义 LED 控制相关常量
const int LED_PIN = LED_BUILTIN; // 使用板载 LED
const int PWM_MAX = 255; // PWM 最大值
const int SAMPLE_INTERVAL = 100; // 采样间隔(ms)
// 定义加速度阈值
const float MIN_ACC = 0.0; // 最小加速度值
const float MAX_ACC = 3.0; // 最大加速度值(可根据实际情况调整)
void setup() {
// 初始化串口通信,用于调试
Serial.begin(115200);
Wire.begin();
delay(1000);
// 初始化 LED 引脚为输出模式
pinMode(LED_PIN, OUTPUT);
// 初始化 IMU 传感器
if (myIMU.begin() != 0) {
Serial.println("IMU 初始化失败!");
while (1); // 如果初始化失败,程序停止运行
}
Serial.println("IMU 初始化成功!");
}
void loop() {
// 读取三轴加速度数据
float accX = abs(myIMU.readFloatAccelX());
float accY = abs(myIMU.readFloatAccelY());
float accZ = abs(myIMU.readFloatAccelZ());
// 计算晃动强度(三轴加速度的平均值)
float shakeIntensity = (accX + accY + accZ) / 3.0;
// 将晃动强度映射为 LED 亮度(0-255)
int brightness = map(
constrain(shakeIntensity * 100, MIN_ACC * 100, MAX_ACC * 100),
MIN_ACC * 100,
MAX_ACC * 100,
0,
PWM_MAX
);
// 反转 PWM 值,因为 LED 是低电平点亮
brightness = PWM_MAX - brightness;
// 输出调试信息
Serial.print("加速度: X=");
Serial.print(accX);
Serial.print(" Y=");
Serial.print(accY);
Serial.print(" Z=");
Serial.print(accZ);
Serial.print(" 晃动强度=");
Serial.print(shakeIntensity);
Serial.print(" LED亮度=");
Serial.println(brightness);
// 设置 LED 亮度
analogWrite(LED_PIN, brightness);
// 等待下一次采样
delay(SAMPLE_INTERVAL);
}
我再次复制程序到 Arduino IDE,这次 XIAO MG24 的 LED 灯变成了常亮,无论怎么晃动,都无法熄灭。我再次提交了反馈。
现在 LED 变成始终常亮,无论怎么晃动
Claude 第 3 次输出了程序,如下图所示。
Claude 第 3 次输出了程序
输出的程序如下所示:
#include "LSM6DS3.h"
#include "Wire.h"
// 创建 IMU 对象,使用 I2C 通信模式
LSM6DS3 myIMU(I2C_MODE, 0x6A);
// 定义 LED 控制相关常量
const int LED_PIN = LED_BUILTIN; // 使用板载 LED
const int PWM_MAX = 255; // PWM 最大值
const int SAMPLE_INTERVAL = 100; // 采样间隔(ms)
// 定义加速度相关参数
const float GRAVITY = 1.0; // 重力加速度基准值
const float MIN_ACC = 0.0; // 最小加速度变化值
const float MAX_ACC = 2.0; // 最大加速度变化值
// 用于存储上一次的加速度值
float lastAccX = 0;
float lastAccY = 0;
float lastAccZ = 0;
void setup() {
// 初始化串口通信,用于调试
Serial.begin(115200);
Wire.begin();
delay(1000);
// 初始化 LED 引脚为输出模式
pinMode(LED_PIN, OUTPUT);
// 初始化 IMU 传感器
if (myIMU.begin() != 0) {
Serial.println("IMU 初始化失败!");
while (1); // 如果初始化失败,程序停止运行
}
Serial.println("IMU 初始化成功!");
// 读取初始加速度值
lastAccX = myIMU.readFloatAccelX();
lastAccY = myIMU.readFloatAccelY();
lastAccZ = myIMU.readFloatAccelZ();
}
void loop() {
// 读取当前加速度数据
float accX = myIMU.readFloatAccelX();
float accY = myIMU.readFloatAccelY();
float accZ = myIMU.readFloatAccelZ();
// 计算加速度变化量(去除重力影响)
float deltaX = abs(accX - lastAccX);
float deltaY = abs(accY - lastAccY);
float deltaZ = abs(accZ - lastAccZ);
// 更新上一次的加速度值
lastAccX = accX;
lastAccY = accY;
lastAccZ = accZ;
// 计算总体晃动强度(三轴加速度变化的平均值)
float shakeIntensity = (deltaX + deltaY + deltaZ) / 3.0;
// 将晃动强度映射为 LED 亮度(0-255)
int brightness = map(
constrain(shakeIntensity * 100, MIN_ACC * 100, MAX_ACC * 100),
MIN_ACC * 100,
MAX_ACC * 100,
PWM_MAX, // 注意:这里反转了范围,静止时 PWM_MAX(LED 暗)
0 // 晃动时接近 0(LED 亮)
);
// 输出调试信息
Serial.print("加速度变化: X=");
Serial.print(deltaX);
Serial.print(" Y=");
Serial.print(deltaY);
Serial.print(" Z=");
Serial.print(deltaZ);
Serial.print(" 晃动强度=");
Serial.print(shakeIntensity);
Serial.print(" LED亮度=");
Serial.println(brightness);
// 设置 LED 亮度
analogWrite(LED_PIN, brightness);
// 等待下一次采样
delay(SAMPLE_INTERVAL);
}
这一次,程序的效果达到了预期,如果我静置 XIAO,LED 不亮,晃动后 LED 会变亮,且亮度会随晃动程度变化。如下图所示。
现在晃动 XIAO MG24,板载 LED 会变亮
有了这个体验,你可以尝试一些更复杂的应用。我的建议是在提问时,尽量给 AI 提供充分的背景资料(文档,示例程序等)。