ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Vibe Coding与嵌入式开发:AI辅助的真相与实践指南

Vibe Coding与嵌入式开发:AI辅助的真相与实践指南 别急着让AI接管你的单片机先聊聊Vibe Coding和嵌入式开发的真相最近圈子里“Vibe Coding”这个词热度高得吓人。特斯拉前AI负责人Andrej Karpathy提了一嘴“找个舒服的环境听点音乐像萨满跳大神一样跟LLM对话让AI把代码写出来但你自己完全不知道代码咋写的”立刻引爆了社区。Web开发圈、脚本圈的朋友们玩得不亦乐乎三个小时从零到一搭出一个小工具这种体验确实很爽。但作为干了十几年的嵌入式工程师我看到这种“跟着感觉走、全权交给AI”的写代码方式第一反应是这玩意敢用在电机控制里吗敢用在医疗设备里吗敢用在微波成像板卡里吗芯片寄存器写错一位板子可能直接冒烟这不是删库跑路能比的。嵌入式开发和Vibe Coding之间存在一个天然的“八字不合”。但这个“不合”不意味着我们要拒绝AI辅助而是要用完全不同的姿势去对待它。这篇文章想聊聊我在实际项目中怎么用AI辅助嵌入式开发的哪些环节真的能“Vibe”哪些环节一点都不能“Vibe”以及踩过的一堆坑。不管你是刚入行的嵌入式新手还是被老板逼着“用AI提效”的资深开发这篇文章应该都能给你一点参考。1. 拆解Vibe Coding它到底是“神谕”还是“高级自动补全”1.1 Vibe Coding的核心逻辑和适用边界Vibe Coding说白了就是你把需求用自然语言描述给大模型让它直接产出代码。你负责“意图”它负责“实现”。典型的交互长这样用户帮我写一个Python脚本解析这个CSV文件输出每列的平均值。 AI好的这里给你一个完整的脚本包含错误处理和注释。这种模式在最理想的情况下确实让编程变成了“跟产品经理聊需求”——你只管说清楚要什么实现细节交给别人。对于没有严格约束的领域比如数据脚本、Web页面、前端交互、简单的后端API这套玩法效率惊人。因为这类项目没有“硬件物理世界”的约束错了顶多重跑一遍编译器会帮你兜底IDE会告诉你哪里类型错了。但对于嵌入式开发事情完全不一样。1.2 为什么嵌入式开发对“不确定性”零容忍我们随手列出嵌入式开发的几个硬核特征资源受限MCU可能只有2KB RAM64KB Flash。AI生成的代码如果不考虑栈深度、堆碎片、代码段大小很可能编译能过、一运行就死机。时序敏感一个GPIO翻转要在精确的时间窗口里完成多一条指令延迟波形就偏了。AI生成的抽象代码层数太多虚拟函数、回调嵌套跑起来周期直接超限。并发与中断很多Bug只在中断打断主程序的那一刻出现。AI很难从你喂给它的分散信息中理解“此处需要关中断”“此处需要volatile修饰”。硬件耦合寄存器地址、位域定义、时钟树配置、外设工作模式稍有偏差芯片就罢工。AI记忆中的芯片型号资料通常是过时或不完整的它非常擅长一本正经地生成错误的寄存器配置。交叉编译与调试成本高嵌入式调试不像Web端改一行刷新浏览器就有结果。你得烧录、连接调试器、抓波形、看寄存器。每一步都可能花掉好几小时。如果AI生成的代码在目标板上出了问题定位过程比对对碰糟心多了。所以Vibe Coding那种“我不知道代码怎么写的但跑起来一切都对”的状态在嵌入式领域基本是奢望。你不可能不知道代码怎么写的——因为你必须知道否则连排查问题都无从下手。但这一切不意味着我们没法用AI。只是要把它的定位从“代替你写代码”改成“帮你把已知的解决方案快速翻译成代码”。2. 嵌入式开发里哪些环节真的能“充当下手仔”我拆解了自己最近几个项目把日常工作按“适合AI辅助”和“不适合AI辅助”分了个类。工作类型适合度原因寄存器初始化代码生成高只要给出芯片手册相关页AI能生成结构清晰的Init代码通信协议解析I2C/SPI/Modbus/CAN中高协议格式清晰AI擅长按字节解析和组装CMake/Makefile编写高语法固定模式化程度高单元测试夹具与Mock代码高模式化极强且不跑在目标硬件上上位机Qt界面骨架高UI布局、信号槽连接方式很模式化中断处理函数低时序敏感行为与硬件紧密耦合低功耗状态机低每个分支出于硬件实测不能用“常识”推断内存池/无锁队列低并发Bug极其隐蔽AI无法帮你验证设备驱动核心逻辑中可以生成骨架但必须逐行审查这个表格是我多年实践下来一个粗略划分具体到你自己的项目边界可能会漂移但大方向不变凡是“文档明确、规则固定、模板化强”的内容AI都能做得不错凡是“依赖运行时行为、硬件特性、时序约束”的内容AI只能提供参考不能直接信任。2.1 举一个典型的“高适配”例子I2C传感器驱动骨架假设我们要在STM32上驱动一个温湿度传感器SHT30。标准流程是写I2C读函数发送软复位命令读取状态然后读温湿度数据最后转换为物理量。如果把这个需求直接甩给AI它大概率会给你一份看起来非常完整的代码bool sht30_read_data(float *temp, float *humi) { uint8_t cmd[2] {0x2C, 0x06}; uint8_t buff[6]; // 发送测量命令 HAL_I2C_Master_Transmit(hi2c1, SHT30_ADDR, cmd, 2, 100); HAL_Delay(20); // 读取数据 HAL_I2C_Master_Receive(hi2c1, SHT30_ADDR, buff, 6, 100); // 解析温度 *temp -45.0f 175.0f * ((buff[0] 8) | buff[1]) / 65535.0f; // 解析湿度 *humi 100.0f * ((buff[3] 8) | buff[4]) / 65535.0f; return true; }这段代码表面上没毛病。但在真实项目里我至少会追问这样几个点如果I2C总线上没有设备响应HAL_I2C_Master_Transmit返回超时怎么办AI漏掉了错误处理。在读取之前需要等待芯片的“数据就绪”状态吗SHT30在重复读取时可能返回上一次的数据AI不知道这一点。如果使用SHT40兄弟型号命令字变成了0xFD地址也变了。AI很可能把型号搞混。所以我的用法是让AI生成骨架然后我自己对照数据手册逐行检查补上错误处理、超时机制、重试逻辑和芯片特有行为。这样效率确实高但我得完全掌握这段代码的每一个字。2.2 高适配的第二好例子写CMakeLists.txt嵌入式项目现在越来越多人用CMake。我可以让AI“告诉我为一个Cortex-M4芯片想用arm-none-eabi-gcc编译链接脚本是stm32f4.ld如何写一个CMakeLists.txt”。这类问题模式极度固定AI给出的结果是直接可用的而且比我自己敲快得多。到这里你就明白了Vibe Coding在嵌入式里的台词应该是“AI帮我生成一个靠谱的草稿”而不是“AI帮我把活干了”。3. 实操过程让AI帮我写一个嵌入式Linux下I2C驱动这部分我想拿最近做的一个具体案例来聊聊——在一块ARM Linux板卡上写一个触摸屏触摸控制器比如GT911的I2C驱动。这个任务混合了“内核框架”、“设备树”、“时序”和“配置寄存器”对AI来说挑战不小但干得好能省一大半时间。先描述一下任务背景板子是某ARM Cortex-A7核心板Kernel 4.19设备树使用I2C总线2触摸控制器挂在地址0x5D。我要实现的功能是探测触摸屏读取触摸点坐标通过输入子系统上报触摸事件。工作流程如下。3.1 前半段用AI搭出驱动框架我把这段描述直接丢给大模型要求它生成一个Linux i2c client driver的C文件。它很快就生成了结构完整的内核模块#include linux/module.h #include linux/i2c.h #include linux/input.h #include linux/delay.h #define GT911_ADDR 0x5D #define GT911_POINT_REG 0x814E // ... 省略具体实现这个骨架真的省了我很多事。像struct i2c_driver、struct input_dev分配、input_set_abs_params这些模板化代码我自己敲至少要十分钟AI几秒钟就出来了。但我做了以下几件事检查了它是否包含必要的头文件。AI有时候会漏掉linux/of.h设备树API编译直接报错。确认了输入子系统的初始化顺序。AI生成的结构是先注册i2c设备再在probe里分配input_dev这没问题。但要注意如果触摸控制器在probe时没准备好需要设置异步探测AI不知道你板子的上电时序。检查了错误路径。AI经常在check_err之后漏了goto清理导致probe失败时泄漏资源。跟真实的GT911芯片手册做了对照。比如GT911的配置寄存器地址、重新映射命令0x8040/0x8041、低功耗命令0x804D等等。AI偶尔会把这些地址搞混。3.2 后半段自己动手补全细节在AI生成的代码基础上我手动补上了下面这些关键逻辑static irqreturn_t gt911_irq_handler(int irq, void *data) { struct gt911_data *ts data; uint8_t buf[8]; int ret; if (gpio_get_value(ts-int_gpio) 0) { ret i2c_master_recv(ts-client, buf, sizeof(buf)); if (ret 8) { dev_err(ts-client-dev, short read\n); return IRQ_HANDLED; } input_report_abs(ts-input, ABS_X, (buf[1] 8) | buf[2]); input_report_abs(ts-input, ABS_Y, (buf[3] 8) | buf[4]); input_sync(ts-input); } return IRQ_HANDLED; }你要问这里为什么用gpio_get_value先判断一下中断线的电平因为在边沿触发模式下中断可能会在总线回复不到位时产生虚假触发。这个细节AI不会知道数据手册里也不一定有是我在真实板子上调试时发现的问题。把中断触发方式从边沿改成电平触发或者软件先读取GPIO电平再决定是否处理是经验决定的东西。3.3 编译和实测AI在交叉编译方面给出的帮助有限其实这一步AI能帮上的忙少很多。写好了代码后要复用具体的交叉编译工具链和内核源码树。你得自己搞清楚内核源码在哪ARCHarm CROSS_COMPILEarm-linux-gnueabihf-怎么设置。该内核版本是否已经把触摸屏驱动编译成模块还是要编进内核。make menuconfig里怎么把触摸驱动设为M。即便你让AI帮你写一个构建命令它能给出的也无非是网上的标准命令。真正重要的是你那个板子的编译环境、内核版本对应的构建系统长什么样这些信息AI不一定知道。你最好自己敲过一遍搞清楚每个环节再考虑“自动化”。把驱动编译出来后我用scp传到板子上insmod加载然后用devmem直接往I2C寄存器写测试数据包来验证驱动解析逻辑是否正确。这一步妥妥要靠人工AI无法替你验证总线波形和GPIO电平。4. 实战进阶微波成像板卡项目里的“AI能写与不能写”热词列表里提到了“微波成像嵌入式”这个我碰巧参与过一个类似的项目。那是一个用于无损检测的小型微波成像装置核心是一块高速ADC采样的FPGA ARM嵌入式板需要把采集到的原始数据处理后在LinuxQt5上位机上实时显示二维图像。这个项目的复杂度集中在数据量大每帧数十MB、要实时处理、且前端采集硬件时序要求极高。4.1 Qt5上位机部分可以多让AI放手如果用温湿度驱动算“轻度信赖”那Qt5上位机的部分我比较愿意让AI大胆发挥。因为Qt的UI开发高度模式化信号槽连接方式、控件布局、样式表AI都能做得不错。我的具体操作是给AI扔一个需求“写一个Qt5程序接收串口数据每帧数据头是0xAA 0x55 两个字节长度然后数据体是16位整数的像素矩阵解析出来用QImage显示在QLabel上并支持鼠标点击选择显示坐标值。”AI能很快给我一份像模像样的代码void SerialReader::processFrame(const QByteArray frame) { QDataStream stream(frame.left(frame.size()-2)); stream.setByteOrder(QDataStream::LittleEndian); quint16 width, height; stream width height; QImage image(width, height, QImage::Format_Grayscale16); for (int y 0; y height; y) { for (int x 0; x width; x) { quint16 value; stream value; image.setPixel(x, y, (value 8) ((value 0xFF) 8)); } } ui-label-setPixmap(QPixmap::fromImage(image)); }但让我特别惊讶的是它第一次生成的代码里用了QDataStream::LittleEndian而我的设备实际输出的是大端。修改这个Bug倒不难但需要注意一旦把上位机代码交给你不熟悉的AI这类“隐式协议约定”非常容易被它忽略掉。所以对于Qt部分我的体会是让AI搭骨架、写UI、画表格都行但涉及协议解析、字节序转换、性能优化、跨线程信号槽安全必须由人亲自把关。4.2 FPGA/ADC采集部分AI完全放弃治疗到了这个层面AI基本就歇菜了。不是说生成不了代码而是FPGA的Verilog代码里充满了时钟域交叉、FIFO深度设计、时序约束、流水线延迟匹配这些物理概念。AI生成的RTL代码可能在仿真里跑得通但一旦综合到具体FPGA型号、真实ADC芯片上时序要多拉跨有多拉跨。打个比方Vibe Coding在这种场合就相当于让一个“学了很多理论知识的学生”去徒手焊接一块高密度BGA板——他可能说得头头是道但你绝对不敢让他上手焊。有些东西AI没办法替代经验。5. 常见问题与排查技巧AI辅助嵌入式开发的坑这部分是我最想写的因为网上那些“AI编程爽翻天”的帖子不会告诉你这些。我把我和朋友项目里遇到的典型问题整理一下帮你提前踩坑。5.1 AI生成的“万能”代码反而变成隐患AI有一个坏习惯非常喜欢把代码结构弄得“过度工程化”。在嵌入式里抽象层越多就越容易出错。我见过AI生成的一段读取电池电量的代码给它加了一个“Strategy Pattern”搞了一堆接口类和虚函数。在桌面上这可能很酷但在一个只有64KB Flash的小单片机里这种行为只会让代码变得臃肿、难调试。排查技巧拿到AI代码后先做一个减法。把所有不必要的抽象、动态内存分配、标准库依赖删掉用最朴素的方式重新组织。除非你真的很需要一个接口否则别用虚函数。MCU项目里简单的switch往往比一堆函数指针更可靠。5.2 错误处理经常被AI吞掉AI生成代码时默认“所有运行都是顺利的”。我让AI写一个读取SPI Flash ID的驱动生成的代码没有检查HAL_SPI_TransmitReceive的返回值也没有对超时时间做判断。如果芯片没焊好、线断了、供电不稳函数就会卡死在while循环里整板死机。排查技巧审查AI代码时把每一个API调用都圈出来问自己三个问题出错返回什么调用方收到返回了没有如果出错应该做什么缺失的部分逐一手动补上。另一个技巧是给AI提示“请在每个关键点加上错误处理”它往往会给你补得比较齐全。5.3 并发和中断的“想当然”AI特别容易忽略MCU里的重入问题。它生成的一个处理UART数据的函数里使用了全局缓冲区但函数本身不具备原子性。当UART中断来了正好也访问这个缓冲区时就会发生数据竞争。这在PC上可能只是小概率崩溃在嵌入式里会表现为偶发的“死机”“乱码”极其难排查。排查技巧凡是全局变量注明是否被中断访问。如果在中断里访问了要么加volatile要么在操作前关中断。AI生成的代码一般不会主动处理这一层你需要自己补。5.4 芯片型号、寄存器资料过时大模型的知识截止日期在那里摆着你让它写一个最新款的瑞萨RA8D1的启动代码它极有可能沿用老的RA6M3寄存器甚至把ARM Cortex-M85内核的指令集搞拧。排查技巧不要迷信AI给出的寄存器地址。任何一个芯片的外设寄存器地址都必须打开Datasheet核对一遍。我自己习惯的做法是把芯片手册的寄存器章节摘录文本直接贴到对话里让AI基于这个文本来生成代码。这样它不容易胡编。如果手册是PDF有些文本提取不是很好那你就得自己动手多敲几行核心寄存器初始化。5.5 浮点运算的陷阱带FPU的MCU越来越多但AI在生成代码时往往完全不关心是硬浮点还是软浮点。比如它在某个STM32F4项目里用了double类型做运算导致编译出的代码体积爆炸或性能下降。此时你改一下编译器配置或者把类型改成float游戏体验会好很多。排查技巧在AI生成的代码里搜索double一个一个转成float如果你的芯片FPU是单精度的话。另外如果代码用了math.h里的函数要确认目标芯片上有没有硬件实现没有的话会隐式链接软浮点库性能会差很多。5.6 过度信任导致的“撞墙”现象Vibe Coding有一种心理效应因为代码是AI生成的你会下意识地觉得“它比我懂”所以跳过代码审查。这在嵌入式里是致命的。我见过同事用AI生成的控制PWM的代码编译没有报错但他忘了设置GPIO_PIN_AF配置电机一动不动。他查了半天硬件最后发现是初始化代码里少了三行。这类问题AI没法自己发现因为它不知道你的硬件连接。排查技巧对于AI生成的代码一定要像对待同事写的代码那样做Code Review。可以拿代码去问AI“这段代码是否完整配置了PWM输出引脚”让它自己借助知识反思一下往往能发现一些问题。但最终还是要靠你在硬件上实测。6. 深度思考嵌入式工程师如何正确地“Vibe Coding”写了很多实际案例最后想聊聊更深层的想法。6.1 把AI当作“最强实习生”而不是“资深专家”实习生给你写代码你会怎么做你大概率会让他写一个具体的小模块然后你去review、提修改意见反复几次后才可能合入。面对AI就应该是这个态度。在嵌入式开发中AI的定位是一个非常聪明、但不懂业务、不懂硬件、不懂你的项目历史和上下文约束的实习生。它写出来的东西可以作为第一版草稿帮你省去从空白文件开始敲击键盘的时间和精力。但代码是否可用完全取决于你这位“资深工程师”的把握。6.2 “能手工写出关键代码”这条底线不能丢现在我有一个很深的感触当你在Vibe Coding里待久了会慢慢丧失“从零构建”的能力。嵌入式开发的特殊性在于很多知识是“默会知识”只有在手工写代码、查手册、调波形时才会获得。如果所有代码都由AI代劳你只是一个“代码搬运工”一旦AI遇到训练数据里没有的场景你就卡壳了。所以我建议每个嵌入式工程师都应该保持一个习惯每周至少手写一次“关键路径”代码。比如一个定时中断的初始化、一个DMA传输的配置、一段状态机。哪怕你知道AI能写也要自己动手写一遍然后跟AI的版本对比一下。这种刻意练习能确保你的硬件直觉一直在线。6.3 建立自己的“Vibe提示词库”如果你已经在用AI辅助开发我强烈建议花点时间整理自己的提示词库。比如我常用的几个“你是资深嵌入式Linux驱动工程师。请根据以下数据手册内容生成设备驱动初始化代码。要求使用内核常见API注意错误处理返回-errno代码风格遵循内核规范。”“忽略你已有的STM32知识。以下是我这个项目的寄存器信息请严格基于这些信息编写初始化函数...”“请把以下这段C代码转换为等价的Rust/或使用更安全的写法但不能增加运行开销。”“下面是我写的驱动probe函数请审查并发风险、资源泄露、错误路径。”这些提示词有个共同点给AI限定范围告诉它“不要幻想”严格基于你喂进去的资料去工作。这样可以显著降低它“自由发挥”的概率。6.4 坚持“验证优先”的开发流程Vibe Coding很容易让你陷入“生成代码-复制粘贴-编译报错-再生成”的循环里。这种迭代方式在嵌入式里是噩梦因为编译过不等于运行对。我现在的流程是文字描述需求和约束。让AI生成代码骨架。把代码放到编辑器里逐行审阅。补全错误处理和极简抽象。针对逻辑疑点用单元测试在PC端跑纯逻辑验证比如协议解析部分。交叉编译并部署到板卡上。用逻辑分析仪、示波器或调试器验证硬件时序。记录问题回到第2步修正。每一步都稳扎稳打虽然比“纯Vibe”慢但比“纯手写”快得多。我测算过带AI介入后我写一个新的I2C驱动大概能节省40%的时间但调试时间并没有因为AI而减少多少。所以关键是保留充足的调试余量。7. 一些补充嵌入式AI辅助开发的未来想象写到最后还是想说点轻松的。虽然现在AI在嵌入式领域还远谈不上“接管”但趋势已经很明显芯片厂商已经在推AI辅助的寄存器配置工具比如一把抓出初始化代码。调试器工具开始集成AI日志分析帮你从一串串寄存器输出中定位问题。RTOS厂商也在探索用AI生成任务划分逻辑。但这些工具再怎么演进有一点不会变嵌入式开发的本质是与物理世界打交道任何代码都必须接受真实硅片的审判。你不能让AI帮你“感觉”电机在转也不能让AI帮你“感觉”触摸屏的响应。只有示波器上的波形和电工胶布粘住的传感器能告诉你真相。所以我的态度是Vibe Coding很好但请把它用在正确的场合。在嵌入式里它是一位得力助手不是一艘自动驾驶的船。驾驶员永远是你。如果你也想试着用AI辅助你的嵌入式项目我最后再分享一个我个人的小技巧把AI的回复当成另一个工程师提交的pr而不是“标准答案”。带着挑毛病的心态去读它的代码你的项目质量反而会让你惊喜。
返回列表