news 2026/10/28 1:08:13

嵌入式AI协同开发实战:用Codex类工具提效重复编码

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
嵌入式AI协同开发实战:用Codex类工具提效重复编码

1. 从“能跑就行”到“AI协同”:这个项目到底在解决什么问题

嵌入式软件工程师大概都有过这种体验:一个项目里最耗时的往往不是写核心算法,而是那些“边角料”代码——GPIO初始化、串口收发、定时器配置、状态机框架、通信协议解析。这些东西技术含量不算高,但架不住量大、重复、容易出错,而且一旦硬件平台换了,又得从头来一遍。我做了十多年嵌入式,前前后后换过五六家芯片平台,每次最烦的就是这些底层驱动的重复劳动。

这个项目标题叫“第一个AI协同开发项目-3”,从编号来看应该是一个系列实践的第三篇。前两篇大概率是在讲怎么把AI编程工具引入到嵌入式开发流程里,以及第一次尝试协同开发时踩了哪些坑。到了这第三篇,重点应该落在“协同”两个字上——不是让AI替你写代码,而是你和AI之间形成一种分工协作的关系,你负责架构设计、硬件对接、关键逻辑,AI负责那些模式化、重复性高的代码生成和重构。

说白了,这个项目要解决的核心问题是:嵌入式开发中大量重复性编码工作如何通过AI协同来提效,同时保证生成代码的可靠性和可维护性。它适合那些已经有一定嵌入式基础、想尝试用AI工具提升效率的工程师,也适合刚入行不久、想看看AI到底能在嵌入式领域做到什么程度的新人。你不需要是AI专家,但至少得能看懂C语言、了解基本的单片机开发流程,否则AI给你的代码你也没法判断对错。

我自己的感受是,嵌入式领域用AI编程和纯软件领域有本质区别。纯软件项目跑在通用操作系统上,AI生成的代码只要逻辑对,基本就能跑;但嵌入式代码直接跟硬件打交道,寄存器配置错一位、时序差一个周期,轻则功能异常,重则烧板子。所以“协同”的前提是你得有能力审核AI的输出,而不是闭着眼睛复制粘贴。

2. 项目整体设计与思路拆解

2.1 为什么选“协同”而不是“全自动”

市面上不少AI编程工具宣传的是“一句话生成整个项目”,但在嵌入式场景下,这种全自动模式基本不现实。原因很简单:嵌入式项目的硬件差异太大,同一款MCU不同封装、不同晶振频率、不同外设连接方式,代码都不一样。AI没有你的原理图,不知道你的LED接在哪个引脚,不知道你的串口波特率是多少,它只能根据常见惯例去猜,猜错了你还得花更多时间去排查。

所以这个项目的设计思路很明确:人负责“定义问题”,AI负责“生成方案”,人再负责“验证和调整”。具体来说,你先把硬件接口、功能需求、约束条件用自然语言描述清楚,AI生成一版代码框架,你拿去编译、烧录、测试,发现问题后把错误信息反馈给AI,让它修正。这个循环跑几轮之后,代码基本就能用了。

这种协同模式的优势在于:你始终掌握控制权,AI只是加速了“从想法到代码”的过程。而且随着你反馈的信息越来越具体,AI生成的代码质量会越来越高,到后面甚至能预测你的编码习惯和项目风格。

2.2 工具选型:为什么是Codex类工具而不是通用聊天AI

热词里提到了“codex付费ai编程软件”,这其实指向了一类专门针对代码生成优化的AI工具。和通用聊天AI相比,这类工具在嵌入式场景下有几点优势:

  • 上下文理解更强:它们通常支持更大的代码上下文窗口,能把你的整个工程文件作为参考,生成的代码风格更统一。
  • 代码补全更精准:在写寄存器操作、位运算、中断服务函数时,补全建议更符合嵌入式惯例。
  • 支持多轮迭代:你可以把编译错误、逻辑问题直接贴回去,它能基于之前的对话历史做修正,而不是每次从零开始。

当然,通用聊天AI也不是不能用,但你需要把需求描述得更详细,而且每次都要重新提供上下文,效率会低一些。我自己的做法是:复杂逻辑用专用工具,简单函数用通用AI快速生成,两者结合。

2.3 项目分层设计:把AI用在刀刃上

嵌入式项目通常可以分成几层:硬件抽象层(HAL)、驱动层、中间件层、应用层。不同层对AI的依赖程度不一样。

层级AI适用度原因
硬件抽象层低直接操作寄存器,依赖具体芯片手册,AI容易出错
驱动层中有固定模式,但时序要求严格,需要人工审核
中间件层高协议解析、状态机、队列管理,模式化程度高
应用层高业务逻辑清晰,AI能快速生成框架代码

这个项目里,我把AI主要用在中间件层和应用层,驱动层只让AI生成参考代码,然后自己根据手册逐行核对。硬件抽象层基本手写,因为这部分代码量不大,但出错代价最高。

3. 核心细节解析与实操要点

3.1 怎么给AI写“嵌入式风格”的提示词

热词里有个“ai编程提示词”,这确实是协同开发的关键技能。给AI写提示词和给同事写需求文档不一样,AI不会追问,你写什么它就按什么做。所以提示词要尽量具体,把隐含条件都显式表达出来。

我总结了一个嵌入式场景的提示词模板,你可以直接套用:

平台:STM32F103C8T6,主频72MHz,使用标准外设库 功能:实现一个基于状态机的按键处理模块 要求: 1. 支持短按、长按、双击三种事件 2. 消抖时间20ms,长按阈值1s,双击间隔300ms 3. 状态机用switch-case实现,不用函数指针 4. 所有变量用static修饰,避免全局污染 5. 提供初始化函数和周期调用函数,周期调用频率10ms 6. 代码风格:变量名小写加下划线,函数名驼峰 输出:完整的.c和.h文件内容

这个模板的关键在于:平台信息、功能描述、量化参数、实现约束、代码风格、输出格式,六项缺一不可。尤其是量化参数,比如消抖时间、长按阈值,你不写清楚,AI就按它自己的默认值来,后面还得改。

3.2 代码审核的四个关键检查点

AI生成的代码不能直接烧录,这是铁律。我每次拿到AI输出的代码,都会按以下顺序检查:

  1. 寄存器地址和位定义:AI有时候会凭记忆写寄存器名,但不同芯片的寄存器命名规则不一样。比如STM32的GPIO配置寄存器是CRL和CRH,但有些AI会写成GPIOx_CRL,少了下划线。这种错误编译能过,但运行必挂。

  2. 中断优先级和临界区:AI生成的中断服务函数经常忘记加临界区保护,或者优先级配置不符合项目要求。嵌入式项目里中断嵌套出问题,排查起来非常痛苦。

  3. 数据类型和溢出风险:AI喜欢用int,但在8位或16位MCU上,int可能是16位的。涉及计数器、时间戳的地方,要特别注意溢出。

  4. 初始化顺序:外设初始化有先后依赖,比如时钟使能必须在配置寄存器之前。AI有时候会搞反顺序,导致外设不工作。

提示:审核AI代码时,建议打开芯片参考手册的对应章节,逐条对照。虽然费时间,但比烧录后发现问题的代价小得多。

3.3 协同开发的工作流设计

这个项目里我用的工作流是这样的:

  1. 需求拆解:把项目功能拆成独立模块,每个模块单独跟AI对话。
  2. 生成框架:让AI生成模块的.h文件,定义接口和数据结构。
  3. 人工审核接口:确认接口设计合理后,再让AI生成.c实现。
  4. 编译测试:在PC上先用gcc编译,跑单元测试,通过后再移植到目标板。
  5. 硬件验证:烧录到板子上,用逻辑分析仪或串口打印验证时序。
  6. 反馈迭代:把测试结果反馈给AI,让它修正问题。

这个流程里,第4步“PC上先编译测试”是我强烈建议的。嵌入式开发环境编译慢、调试不方便,先在PC上用gcc把纯逻辑部分跑通,能省很多时间。AI生成的代码通常不依赖具体硬件,稍微改改就能在PC上编译。

4. 实操过程与核心环节实现

4.1 环境准备:让AI能“看到”你的工程

要让AI协同开发,第一步是让它了解你的工程结构。我的做法是:在项目根目录放一个project_context.md文件,里面写清楚芯片型号、开发环境、目录结构、编码规范、常用宏定义。每次跟AI对话时,把这个文件内容贴在提示词前面。

这个文件不需要很长,但关键信息要有。比如:

# 项目上下文 - 芯片:STM32F103C8T6 - 开发环境:Keil MDK 5.38 - 库:标准外设库 v3.5.0 - 目录结构: - /Drivers:外设驱动 - /Middlewares:中间件 - /App:应用逻辑 - 编码规范: - 缩进4空格 - 函数名:模块名_功能名 - 变量名:小写加下划线 - 常用宏: - DEBUG_PRINT(fmt, ...) 串口打印 - ASSERT(expr) 断言

有了这个文件,AI生成的代码风格会统一很多,变量命名、函数命名都符合你的习惯,后期维护成本大大降低。

4.2 第一个模块:按键状态机

我拿按键处理模块作为第一个协同开发目标,因为它足够简单,适合验证流程,又足够典型,能覆盖大部分嵌入式编码场景。

提示词:

基于以下上下文,生成一个按键处理模块: [粘贴project_context.md内容] 功能需求: - 支持4个按键,分别接在PA0、PA1、PA2、PA3 - 按键按下为低电平,外部上拉 - 支持短按、长按、双击 - 消抖20ms,长按1s,双击间隔300ms - 周期调用频率10ms 输出:key.h和key.c

AI生成的代码(节选):

// key.h #ifndef __KEY_H #define __KEY_H #include <stdint.h> typedef enum { KEY_EVENT_NONE = 0, KEY_EVENT_SHORT_PRESS, KEY_EVENT_LONG_PRESS, KEY_EVENT_DOUBLE_CLICK } key_event_t; void key_init(void); void key_scan(void); key_event_t key_get_event(uint8_t key_index); #endif
// key.c #include "key.h" #define KEY_NUM 4 #define DEBOUNCE_MS 20 #define LONG_PRESS_MS 1000 #define DOUBLE_CLICK_MS 300 #define SCAN_PERIOD_MS 10 typedef struct { uint8_t pin_state; uint8_t stable_state; uint16_t debounce_cnt; uint16_t press_cnt; uint8_t click_cnt; uint16_t click_timer; key_event_t event; } key_ctx_t; static key_ctx_t key_ctx[KEY_NUM]; void key_init(void) { // GPIO初始化代码... } void key_scan(void) { for (uint8_t i = 0; i < KEY_NUM; i++) { // 状态机逻辑... } }

我的审核记录:

  • 接口设计合理,枚举类型清晰。
  • 但key_scan里没有处理双击超时逻辑,click_timer定义了但没用上。
  • GPIO初始化部分AI写的是“// GPIO初始化代码...”,需要我手动补全。
  • 消抖计数器用uint16_t,最大65535,按10ms周期算能计655秒,够用。

反馈给AI:

key_scan函数里click_timer没有使用,双击检测逻辑不完整。 请补充:当click_cnt为1时,启动click_timer计数, 超过DOUBLE_CLICK_MS后如果没有第二次按下,则判定为单击。

AI修正后的代码就完整了。这个过程大概来回两轮,总共花了不到20分钟,如果手写的话至少一个小时。

4.3 第二个模块:环形缓冲区

环形缓冲区是嵌入式里最常用的数据结构之一,串口收发、ADC采样、日志缓存都离不开它。这个模块逻辑清晰,非常适合AI生成。

提示词:

生成一个线程安全的环形缓冲区模块,用于串口接收缓存: - 缓冲区大小256字节 - 支持单字节写入和读取 - 支持批量写入和读取 - 提供剩余空间查询和已用空间查询 - 写入和读取操作需要关中断保护 - 提供缓冲区满和空的判断函数 输出:ringbuf.h和ringbuf.c

AI生成的代码基本一次通过,我只改了一个地方:它默认用memcpy做批量操作,但在中断上下文里memcpy可能不是原子操作,我改成了逐字节拷贝。这个细节AI不会主动考虑,需要你根据实际使用场景判断。

4.4 第三个模块:Modbus RTU从机

这个模块稍微复杂一些,涉及协议解析、CRC校验、超时处理。我让AI先生成框架,然后自己填充CRC计算和超时逻辑。

提示词:

生成Modbus RTU从机协议解析模块: - 支持功能码03(读保持寄存器)和06(写单个寄存器) - 波特率9600,8N1 - 从机地址可配置 - 帧间隔超时3.5个字符时间 - CRC16校验,多项式0xA001 - 寄存器数量可配置,最大128个 输出:modbus_slave.h和modbus_slave.c

AI生成的CRC计算函数我核对了一遍,多项式是对的,但初始值它用了0xFFFF,标准Modbus RTU也是0xFFFF,没问题。超时判断它用了一个定时器计数,我改成用系统滴答定时器,更通用。

这个模块的协同开发花了大概40分钟,其中大部分时间花在核对协议细节上。但如果没有AI,光写框架和CRC就要一个多小时。

5. 常见问题与排查技巧实录

5.1 AI生成代码的典型问题速查表

问题类型典型表现排查方法解决技巧
寄存器名错误编译通过但运行异常对照芯片手册逐条核对让AI只写逻辑,寄存器操作自己补
中断优先级错误中断嵌套死锁检查NVIC配置明确告诉AI优先级分组和具体数值
数据类型溢出计数器归零异常检查变量位宽显式指定uint32_t等类型
初始化顺序错误外设不工作对照参考手册初始化流程在提示词里写明初始化顺序
缺少临界区保护偶发数据错误检查共享变量访问让AI在读写共享变量时关中断
死循环无退出程序卡死检查while循环条件添加超时机制

5.2 我踩过的三个坑

第一个坑:AI生成的延时函数不准确。早期我让AI生成一个delay_ms函数,它用空循环实现,但循环次数是按PC上的经验估的,在72MHz的STM32上跑出来差了十几倍。后来我改成用系统滴答定时器做精确延时,AI生成的空循环只用来做微秒级短延时。

第二个坑:AI对“ volatile”的理解不到位。在中断和主循环之间共享的变量,必须加volatile,否则编译器优化后可能读不到最新值。AI生成的代码经常漏掉这个关键字,我后来在提示词里明确要求“所有中断中修改的全局变量必须加volatile”。

第三个坑:AI生成的代码风格不统一。同一个项目里,有的模块用驼峰命名,有的用下划线,看起来像两个人写的。后来我每次对话都带上project_context.md,风格问题基本解决了。

5.3 什么情况下不要用AI

不是所有代码都适合AI生成。以下几种情况我建议手写:

  • 芯片特有的寄存器操作:AI容易记混不同芯片的寄存器定义。
  • 严格的时序控制:比如软件模拟I2C、SPI,时序要求精确到微秒,AI生成的代码很难保证。
  • 安全关键代码:涉及人身安全、设备安全的逻辑,必须人工编写和审核。
  • 高度优化的算法:AI生成的代码通常可读性优先,性能不是最优。

注意:AI是加速器,不是替代品。嵌入式工程师的核心竞争力在于对硬件的理解和系统设计能力,这些AI暂时还替代不了。

6. 协同开发的效率账与个人体会

6.1 效率对比:手写 vs AI协同

我拿这个项目里的三个模块做了个粗略统计:

模块纯手写耗时AI协同耗时节省比例
按键状态机60分钟20分钟67%
环形缓冲区40分钟15分钟62%
Modbus从机120分钟40分钟67%

节省的时间主要来自两个方面:一是AI快速生成框架代码,省去了敲键盘的时间;二是AI能提供一些我没想到的实现思路,比如环形缓冲区的批量操作优化。但审核和调试的时间并没有减少太多,因为AI生成的代码总有一些细节需要修正。

6.2 对“AI是否能实现把设计稿编程分层图”的看法

热词里有个“ai是否能实现把设计稿编程分层图”,这个问题在嵌入式领域其实不太成立。嵌入式开发很少有“设计稿”这个概念,更多是原理图、时序图、状态图。AI目前能根据状态图生成状态机代码,根据时序图生成通信协议框架,但前提是这些图得用文字描述清楚。直接丢一张图片给AI,它识别出来的信息往往不完整,生成的代码偏差很大。

我的做法是:把状态图用文字描述成状态转移表,把时序图用文字描述成步骤序列,再让AI生成代码。这样准确率高很多。

6.3 后续可以扩展的方向

这个项目跑通之后,我打算把协同开发流程扩展到更多模块:PID控制、滤波算法、通信协议栈、文件系统。每个模块都建立对应的提示词模板和审核清单,形成一套可复用的工作流。另外,我还在尝试让AI根据单元测试用例反向生成代码,这样能保证生成的代码天然通过测试,减少后期调试工作量。

嵌入式软件AI编程这件事,我的体会是:它不会让你失业,但会让你那些只会写重复代码的同事失业。工具在变,核心能力没变——对硬件的理解、对系统的设计、对质量的把控,这些才是嵌入式工程师的护城河。AI只是帮你把护城河挖得更深更快。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/28 1:07:52

万能芯片真相:FPGA如何实现可重构计算与异构集成

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/28 1:05:48

高分辨率远程摄像头如何越做越小?GMSL串行链路设计实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/28 1:05:48

VNC 4.0简体汉化版兼容性避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/28 1:05:37

RV1103边缘NPU实战:图像分类模型部署与性能对比

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/28 1:04:58

AHB与APB总线深度解析:从MCU内部通信到驱动开发实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/28 1:04:48

STM32F1实战:手写DHT11温湿度驱动与单总线时序解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华