《AI 赋能嵌入式开发:从 0 到全栈工程师》模块1|第3课时

嵌入式专用 Prompt 工程与模板库

第 2 章我们复盘了当前别人在用什么 AI 工具链。但很多读者会遇到同一个困惑:为什么我问的 AI 答不好? 不是 AI 不行,而是提问方式不对。给 AI 的指令就像给工程师的需求书:需求写得含糊,交付必然含糊。

本章你将学会一套可复用的提问框架,拿到 4 类嵌入式专用 Prompt 模板,并通过 4 个完整的实战演示把每个模板用熟。学完本章,你问 AI 的效率会明显拉开和只会随便问问的人的距离。

这里有一点非常重要的一点是,跟随本教程,随着嵌入式开发的深入,从裸机到free_RTOS再到linux。从驱动开发到算法应用。你将不断的积累你的模板库,以后做项目工程的时候,你只需要复刻你的模板库,就能高效的完成各种复杂功能的开发,我想这也是这个教程最具价值的地方,你的库就是你所有的经验,不存在忘记了,有需要重头理一遍。

另一点需要说明的是,AI虽然非常强大,可以回答您任何问题,但是如果你不懂,你就根本没办法判别他的好与坏。

因此,AI可以回答很多问题,但是好的回答就显得尤为重要!!!

3.1 学习目标

  1. 掌握 Prompt 工程的核心原则;

  2. 熟练使用 4 类嵌入式专用 Prompt 模板;

  3. 能根据实际需求自定义属于自己的 Prompt,并建立个人 Prompt 库。

3.2 核心内容

3.2.1 Prompt 工程基础:为什么你问的 AI 答不好

好 Prompt 的四要素框架(RTFC)

本专栏把高质量 Prompt 归纳为四要素,简称 RTFC:

要素 英文 含义 反例
角色 Role 告诉 AI 你是谁、以什么身份回答 帮我看看代码
任务 Task 清晰说明要做什么、做到什么程度 帮我优化一下
上下文 Context 给出芯片型号、内核版本、硬件连接、代码片段等背景 为什么串口乱码
格式 Format 指定输出的结构:表格/步骤/分级清单 分析一下

这四要素符合主流大模型厂商官方推荐的做法。

OpenAI 官方 Prompt Engineering 指南建议用指令→上下文→示例→输出要求组织消息;Anthropic 官方最佳实践提出黄金法则------提示词:要能让一个不了解任务的同事直接看懂;Google Gemini 官方文档同样推荐输入、约束、响应格式三段式结构。四要素正是把这三家官方建议浓缩成嵌入式场景可用的骨架。

嵌入式场景的特殊要求

通用 Prompt 基础上,嵌入式开发还有四个必须:

  1. **必须指定芯片型号与内核架构:**STM32F407 是 Cortex-M4,和 STM32F103(Cortex-M3)的寄存器、时钟树都不一样。只说STM32会让 AI 猜,猜就可能给错代码;
  2. **必须指定软件栈:**寄存器操作、HAL 库 、标准库是三套完全不同的写法;裸机 、FreeRTOS 、Linux 也是不同世界。不指定,AI 默认给你最流行的;
  3. **必须描述硬件连接:**引脚号、电平逻辑、外设接线(如:LED 接 PF9,高电平点亮,USART1 用 PA9/PA10)------这是 AI 无法凭空知道的,也是最容易出错的地方;
  4. **必须让 AI 区分"确定"与"推测":**要求它对拿不准的硬件细节明确标注需要人工核对数据手册,而不是自信地编一个。

研究显示:首个嵌入式综合基准 EmbedBench(ICSE 2026,arXiv 2506.11003)显示,最强代码模型在嵌入式任务上 pass@1 仅 55.6%,ESP-IDF 移植类任务最佳仅 29.4%;配合 RAG 检索 + 编译器反馈闭环后可提升至 65.1%。这说明:靠AI 自己猜硬件行不通,必须把硬件上下文喂进去。

三组反面案例 vs 正面案例

案例一:看代码

  • 反面:帮我看看这个代码有什么问题?

  • 正面:

    角色:你是一位严格的嵌入式代码审查专家,擅长 STM32(Cortex-M4)开发。任务:审查以下 GPIO 初始化代码,检查寄存器配置是否正确、是否有遗漏。上下文:芯片 STM32F407,LED 接 PF9(高电平点亮),使用寄存器方式操作。格式:按严重程度分级(致命/警告/建议),每条给出位置、问题、修复方案。[粘贴代码]

案例二:串口乱码

  • 反面:为什么我的串口乱码"

  • 正面:

    角色:你是一位嵌入式调试工程师。任务:分析串口乱码的可能原因,并给出排查顺序。上下文:- 芯片:STM32F407,主频 168MHz,USART1 挂 APB2(84MHz)- 配置:波特率 115200,8 数据位,无校验,1 停止位- 现象:发送英文和数字正常,中文和部分字符乱码- 串口工具:MobaXterm,波特率已核对格式:按可能性从高到低排序,每条给出原因 + 验证方法 + 修复方案。

案例三:生成初始化代码

  • 反面:帮我写个串口初始化

  • 正面:

    角色:你是一位 STM32 HAL 库专家。任务:生成 USART1 的初始化函数。上下文:芯片 STM32F407,APB2=84MHz,波特率 115200,引脚 TX=PA9/RX=PA10(AF7)。约束:使用 HAL 库,开启全局中断,不使用 DMA。格式:先给设计思路(1 段),再给可编译的 .c 代码,最后标注需要人工核对的部分。

3.2.2 模板一:Datasheet 解读模板

适用场景:拿到新芯片/新外设,快速了解关键信息(寄存器、时序、电气特性、坑与 errata)。

模板结构:

复制代码
角色:你是一位资深嵌入式工程师,精通 [芯片架构]。任务:请解读以下 datasheet 片段,重点关注:1. 关键寄存器及位域定义2. 初始化步骤与时序要求3. 常见坑与 errata4. 与 [其他芯片] 的差异上下文:我使用的是 [开发板型号],[具体硬件连接]。格式:用表格列出寄存器,用步骤列出初始化流程。[粘贴 datasheet 片段、或者上传PDF文档]

实战演示:解读一款 SPI 传感器的 datasheet

以常见 SPI 热电偶传感器 MAX6675 为例:

复制代码
角色:你是一位传感器驱动专家,精通 MAX6675(SPI K 型热电偶接口)。任务:解读附件的 MAX6675 datasheet 手册,输出:1. SPI 通信时序要点(时钟极性 CPOL/相位 CPHA、最大时钟频率)2. 12 位温度数据的位定义与换算公式(含符号位处理)3. 热电偶开路检测位的用法与误判风险4. 初始化/读取流程步骤格式:寄存器/位定义用表格,流程用编号步骤,无法从片段确认的内容标注"需查官方 datasheet 对应章节"。[粘贴 MAX6675 datasheet 手册]
复制代码
以下解读基于你提供的 MAX6675 datasheet 片段。片段未给出的参数我会明确标注 **“需查官方 datasheet 对应章节”**。
复制代码
## 1. SPI 通信时序要点
复制代码
| 项目 | 结论/要点 |
复制代码
|---|---|
复制代码
| 接口类型 | SPI 兼容、只读,SO 输出数据 |
复制代码
| 片选 CS | `CS` 低使能串口并输出第一位;`CS` 低会立即停止转换;`CS` 高启动新的转换 |
复制代码
| 读取长度 | 一次完整读取需要 **16 个 SCK 时钟周期** |
复制代码
| 数据顺序 | D15 先输出,随后 D14…D0 |
复制代码
| 采样边沿 | datasheet 明确:在时钟 **下降沿** 读取 16 位输出位 |
复制代码
| CPOL/CPHA | 片段未直接给出参数。根据图 1b 中 SCK 空闲为高、且“下降沿读取”,通常可推断为 **CPOL=1, CPHA=0,即 SPI Mode 2**。但请以官方 Serial Interface Timing 章节为准。**需查官方 datasheet 对应章节** |
复制代码
| 最大 SCK 频率 | 片段电气特性表中未列出最大 SCK 频率。常见 MAX6675 官方规格约 **4.3 MHz**,但必须以官方 Electrical Characteristics / Serial Interface Timing 为准。**需查官方 datasheet 对应章节** |
复制代码
| 时序参数 | 图 1b 出现 `tCSS、tCH、tCL、tDV、tDO、tTR`,但片段未给出具体数值。**需查官方 datasheet 对应章节** |
复制代码
| 转换时间 | 典型 0.17 s,最大 0.22 s(Note 2)。连续读取时必须等待转换完成,否则可能读到旧数据 |
复制代码
| 电源与旁路 | VCC 3.0 V ~ 5.5 V;VCC 与 GND 间靠近引脚放 0.1 µF 陶瓷旁路电容 |
复制代码
| 转换控制 | 上电后 `CS` 置高启动转换;读取时拉低 `CS`,读取完再拉高启动下一次转换 |
复制代码
## 2. 16 位 SO 输出位定义与温度换算
复制代码
SO 每次输出 16 位,位定义如下:
复制代码
| 位 | 名称 | 含义 | 处理方式 |
复制代码
|---|---|---|---|
复制代码
| D15 | Dummy sign bit | 虚拟符号位,datasheet 说明始终为 0 | 忽略;若读到 1,通常说明时序/接线异常 |
复制代码
| D14:D3 | 12-bit temperature reading | 12 位温度转换结果,D14 为 MSB,D3 为 LSB | 提取为 `code = (raw >> 3) & 0x0FFF` |
复制代码
| D2 | Thermocouple input / open detect | 正常为低;热电偶输入开路时变高 | `open = (raw >> 2) & 0x01`,为 1 时报开路故障 |
复制代码
| D1 | Device ID | MAX6675 器件 ID,datasheet 说明为低,即 0 | 可检查 `(raw >> 1) & 0x01` 是否为 0 |
复制代码
| D0 | Three-state | 三态 | 忽略 |
复制代码
### 温度换算公式
复制代码
```text
复制代码
raw16 = 读取到的 16 位数据
复制代码
code  = (raw16 >> 3) & 0x0FFF
复制代码
T_hot = code × 0.25 °C
复制代码
```
复制代码
也可写为:
复制代码
```text
复制代码
T_hot = code / 4
复制代码
```
复制代码
范围与示例:
复制代码
| code | 温度 |
复制代码
|---|---|
复制代码
| 0x000 | 0 °C |
复制代码
| 0xFFF = 4095 | 4095 × 0.25 = +1023.75 °C |
复制代码
### 符号位处理
复制代码
- D15 是 **dummy sign bit**,始终为 0,不是二进制补码符号位。
复制代码
- D14:D3 这 12 位温度数据按 **无符号数** 处理。
复制代码
- MAX6675 热端可读范围是 **0 °C 到 +1023.75 °C**,不支持负热端温度。
复制代码
- 冷端补偿范围 `-20 °C ~ +85 °C` 指的是 MAX6675 环境温度,不是输出负温度。
复制代码
- 若把 D15 当作符号位,或把 12 位数据当补码,会得到错误结果。
复制代码
## 3. 热电偶开路检测位 D2 的用法与误判风险
复制代码
### 用法
复制代码
- D2 正常为低。
复制代码
- D2 为高表示热电偶输入开路。
复制代码
- 每次读取 16 位后应检查 D2;若 D2=1,温度数据应视为无效,应报“热电偶开路/传感器故障”。
复制代码
- 为使开路检测正常工作,`T-` 必须外部接地,并且接地连接尽量靠近 MAX6675 的 GND 引脚。
复制代码
### 误判风险
复制代码
- `T-` 未接地或接地不良时,开路检测器不能正常工作,可能误报开路。
复制代码
- 电源噪声、地噪声、长导线拾取噪声可能导致 D2 误置位。
复制代码
- 热电偶或接线瞬断、接触不良可能被捕获为开路。
复制代码
- 未等待转换完成就读取,可能读到无效或旧数据。
复制代码
- CS/SCK 时序错误、SO 在 D0 三态期间浮空,可能导致整帧数据错误,从而误判 D2。
复制代码
- 片段未给出 D2 的检测阈值、滤波和故障判定细节。**需查官方 datasheet 对应章节**。
复制代码
## 4. 初始化/读取流程步骤
复制代码
1. **硬件连接与上电**
复制代码
   - VCC 接 3.0 V ~ 5.5 V,GND 接地。
复制代码
   - VCC 与 GND 间靠近器件放置 0.1 µF 旁路电容。
复制代码
   - K 型热电偶:`T+` 接 Chromel,`T-` 接 Alumel。
复制代码
   - `T-` 必须外部接地,接地尽量靠近 MAX6675 的 GND。
复制代码
   - `SO` 接 MCU 的 MISO,`SCK` 接 SPI 时钟,`CS` 接片选。
复制代码
2. **上电复位**
复制代码
   - 确保 VCC 上升超过上电复位阈值,典型 2.25 V。
复制代码
   - 上电后先将 `CS` 置高,启动一次新的温度转换。
复制代码
3. **等待转换完成**
复制代码
   - 等待典型 0.17 s,最大 0.22 s;建议等待大于 0.22 s,或按实际官方 Note 2 条件等待。
复制代码
   - 转换期间不要一直保持 `CS` 低,因为 `CS` 低会停止转换。
复制代码
4. **启动串行读取**
复制代码
   - 拉低 `CS`,使能串口并输出第一位 D15。
复制代码
   - 产生 16 个 SCK 时钟周期。
复制代码
   - 在 SCK 下降沿读取 SO 数据。
复制代码
   - 读取顺序为 D15、D14、…、D0。
复制代码
   - 若使用硬件 SPI,通常按推断配置为 SPI Mode 2;但 CPOL/CPHA 需以官方时序为准。
复制代码
5. **解析 16 位数据**
复制代码
   ```text
复制代码
   raw16 = 读取的 16 位
复制代码
   open  = (raw16 >> 2) & 0x01
复制代码
   id    = (raw16 >> 1) & 0x01
复制代码
   code  = (raw16 >> 3) & 0x0FFF
复制代码
   T_hot = code * 0.25
复制代码
   ```
复制代码
   - 若 `open == 1`,报热电偶开路,温度无效。
复制代码
   - 若 `id != 0`,可视为通信异常。
复制代码
   - D15 应为 0,D0 忽略。
复制代码
6. **结束读取并启动下一次转换**
复制代码
   - 拉高 `CS`,结束本次读取并启动新的转换。
复制代码
   - 若连续采样,重复“等待转换 → 拉低 CS 读取 16 位 → 拉高 CS 启动下一次转换”。
复制代码
7. **误差与噪声处理**
复制代码
   - 使用 0.1 µF 旁路电容,远离噪声源。
复制代码
   - 长热电偶线建议使用双绞线。
复制代码
   - 避免热源靠近 MAX6675,冷端与 MAX6675 尽量同温。
复制代码
   - 使用大接地平面改善热性能。
复制代码
### 需查官方 datasheet 的内容汇总
复制代码
- CPOL/CPHA 的官方明确模式:**需查官方 datasheet 对应章节**。
复制代码
- 最大 SCK 频率:**需查官方 datasheet 对应章节**。
复制代码
- `tCSS、tCH、tCL、tDV、tDO、tTR` 具体数值:**需查官方 datasheet 对应章节**。
复制代码
- Conversion Time 的 Note 2 条件:**需查官方 datasheet 对应章节**。
- D2 开路检测的阈值、滤波和详细误判条件:**需查官方 datasheet 对应章节**。

进阶技巧:分段喂入长 datasheet

datasheet 动辄几百页,一次性粘贴会超出上下文窗口。正确做法, Anthropic 官方建议长文档放顶部、查询放末尾:

  1. 第一轮:贴器件概述 + 引脚定义段落,问这个芯片有哪些功能模块、引脚如何分类;

  2. 第二轮:贴寄存器描述段落,问关键寄存器位定义汇总表;

  3. 第三轮:贴电气特性 + 时序图段落,问"初始化步骤与最小时序要求;

  4. 最后:让 AI 把三份摘要串联成一份快速上手笔记。

防幻觉要点:datasheet 提取后必须与厂商头文件、参考手册二次核对,AI 最容易忽略脚注footnote与 errata 勘误------这是社区多方验证的共识。

3.2.3 模板二:代码生成模板

适用场景:需要快速生成驱动框架、初始化代码、应用逻辑。

模板结构:

复制代码
角色:你是一位嵌入式软件开发工程师,有 [X] 年经验。任务:请为 [芯片型号] 编写 [功能模块] 代码。要求:1. 使用 [寄存器/HAL/标准库] 方式2. 代码风格:[注释量/命名规范]3. 需要包含:初始化函数、读写函数、中断处理(如适用)4. 硬件连接:[具体引脚]上下文:这是一个 [项目类型] 项目,已有 [已有代码说明]。格式:先给出设计思路,再给出完整代码,最后标注需要人工确认的部分。

实战演示:用 AI 生成 STM32 的 UART 初始化 + DMA 接收代码

复制代码
角色:你是一位 STM32 嵌入式专家,精通 HAL 库与 DMA。任务:生成 USART1 初始化 + DMA 接收的完整代码。上下文:- 芯片:STM32F407VGT6,APB2=84MHz- 引脚:TX=PA9、RX=PA10(复用功能 AF7)- 波特率 115200,8-N-1- DMA:USART1_RX 使用 DMA2 Stream2,Channel4(以工程实际分配为准)约束:1. 使用 HAL 库(禁止寄存器风格)2. DMA 配置使用 HAL_DMA 与 __HAL_LINKDMA 方式3. 接收使用空闲中断 + DMA 不定长接收思路(若实现复杂,给出可行简化方案)4. 所有外设基地址与宏定义以 STM32F407xx.h 为准,禁止凭记忆写格式:先给设计思路(2-3 段),再给可编译的 main.c/中断回调,最后列出"需要人工核对"的清单。
objectivec 复制代码
/* ============================================================
 * main.c --- USART1 DMA 空闲中断不定长接收
 * 芯片: STM32F407VGT6 | APB2 = 84MHz
 * TX=PA9  RX=PA10  AF7
 * DMA: USART1_RX -> DMA2_Stream2, Channel 4
 * 参考: stm32f407xx.h (USART1_BASE, DMA2_Stream2_BASE 等宏)
 * ============================================================ */
#include "stm32f4xx_hal.h"
#include <string.h>
/* ---------- 全局句柄 ---------- */
UART_HandleTypeDef  huart1;
DMA_HandleTypeDef   hdma_usart1_rx;
/* ---------- 接收缓冲区 ---------- */
#define RX_BUFFER_SIZE  256U
uint8_t  g_rx_buffer[RX_BUFFER_SIZE];
volatile uint16_t g_rx_len = 0;          /* 上一帧实际接收长度 */
volatile uint8_t  g_rx_ready = 0;        /* 帧就绪标志,供主循环轮询 */
/* ---------- 前向声明 ---------- */
static void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_USART1_UART_Init(void);
/* ============================================================
 * main
 * ============================================================ */
int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_DMA_Init();
    MX_USART1_UART_Init();
    /* 启动 DMA 接收(循环模式,缓冲满自动回卷) */
    HAL_UART_Receive_DMA(&huart1, g_rx_buffer, RX_BUFFER_SIZE);
    /* 使能 USART1 空闲中断(IDLE) */
    __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
    while (1)
    {
        if (g_rx_ready)
        {
            g_rx_ready = 0;
            /* 此处处理 g_rx_buffer 中长度为 g_rx_len 的数据 */
            /* 例如:回传 */
            HAL_UART_Transmit(&huart1, g_rx_buffer, g_rx_len, 100);
            memset(g_rx_buffer, 0, g_rx_len);
            g_rx_len = 0;
        }
    }
}
/* ============================================================
 * 时钟配置:HSE 8MHz -> PLL -> SYSCLK 168MHz, APB2 = 84MHz
 * 此处保留占位,实际工程请使用 CubeMX 生成的时钟树代码
 * ============================================================ */
static void SystemClock_Config(void)
{
    /* ... 由 CubeMX / 手动配置生成,确保 APB2 Prescaler = 2 分频 */
    /* 不在此处展开,避免与用户工程冲突 */
}
/* ============================================================
 * GPIO:PA9 (TX), PA10 (RX) --- AF7, 复用推挽 / 上拉输入
 * ============================================================ */
static void MX_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /* PA9 --- USART1_TX, AF7, 推挽复用 */
    GPIO_InitStruct.Pin       = GPIO_PIN_9;
    GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull      = GPIO_NOPULL;
    GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    /* PA10 --- USART1_RX, AF7, 上拉输入(防浮空误触发 IDLE) */
    GPIO_InitStruct.Pin       = GPIO_PIN_10;
    GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;     /* AF 模式内部可配输入 */
    GPIO_InitStruct.Pull      = GPIO_PULLUP;          /* 关键:上拉抑制噪声 */
    GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
/* ============================================================
 * DMA 初始化 --- USART1_RX -> DMA2_Stream2 / Channel 4
 *
 * 映射依据:STM32F407 DMA 请求映射表中
 *   USART1_Rx -> DMA2_Stream2 或 DMA2_Stream5, 通道均为 Channel4
 * 用户指定 Stream2,此处遵循用户分配。
 * ============================================================ */
static void MX_DMA_Init(void)
{
    __HAL_RCC_DMA2_CLK_ENABLE();
    /* ---------- USART1_RX DMA 配置 ---------- */
    hdma_usart1_rx.Instance                 = DMA2_Stream2;
    hdma_usart1_rx.Init.Channel             = DMA_CHANNEL_4;
    hdma_usart1_rx.Init.Direction           = DMA_PERIPH_TO_MEMORY;
    hdma_usart1_rx.Init.PeriphInc           = DMA_PINC_DISABLE;   /* 外设地址固定 */
    hdma_usart1_rx.Init.MemInc              = DMA_MINC_ENABLE;    /* 存储器地址递增 */
    hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart1_rx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
    hdma_usart1_rx.Init.Mode                = DMA_CIRCULAR;       /* 循环模式 */
    hdma_usart1_rx.Init.Priority            = DMA_PRIORITY_HIGH;
    hdma_usart1_rx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
    HAL_DMA_Init(&hdma_usart1_rx);
    /* ---------- 将 DMA 句柄链接到 UART 句柄的 hdmarx ---------- */
    __HAL_LINKDMA(&huart1, hdmarx, hdma_usart1_rx);
    /* ---------- DMA2_Stream2 NVIC 配置 ---------- */
    /* 本方案中 DMA 本身不需要中断(循环模式 + IDLE 通知),
       但保留 NVIC 使能以兼容 HAL 错误处理路径。若不需要可注释。 */
    HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
}
/* ============================================================
 * USART1 初始化 --- 115200, 8-N-1, APB2 = 84MHz
 * ============================================================ */
static void MX_USART1_UART_Init(void)
{
    __HAL_RCC_USART1_CLK_ENABLE();
    huart1.Instance          = USART1;
    huart1.Init.BaudRate     = 115200;
    huart1.Init.WordLength   = UART_WORDLENGTH_8B;
    huart1.Init.StopBits     = UART_STOPBITS_1;
    huart1.Init.Parity       = UART_PARITY_NONE;
    huart1.Init.Mode         = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl    = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    HAL_UART_Init(&huart1);
    /* ---------- USART1 NVIC:用于 IDLE 中断 ---------- */
    HAL_NVIC_SetPriority(USART1_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
}

后面我们安装完工具后让他跑起来,看起来是没什么问题的。

关键技巧:

  1. 明确指定标注需要人工确认的部分------要求 AI 主动暴露不确定性,而不是事后你去猜哪些可能是错的;
  2. 给出 APB 时钟值------波特率分频是 AI 最常算错的地方,把APB2=84MHz写进上下文能显著降错;
  3. 要求用宏不用魔法数------Anthropic 官方提示模板明确反对 hard-code 数值,对嵌入式可维护性尤其重要;
  4. 让 AI 最后自查寄存器------把你写到的每个寄存器地址与官方头文件核对一遍,无法确认就标注。

3.2.4 模板三:日志/报错分析模板

适用场景:编译报错、运行崩溃、内核 oops、硬件异常。

模板结构:

复制代码
角色:你是一位嵌入式调试专家,擅长 [MCU/Linux 驱动] 问题排查。任务:分析以下报错信息,给出可能的原因和排查步骤。报错信息:[粘贴完整报错日志]上下文:- 硬件平台:[开发板]- 软件环境:[内核版本/编译器版本]- 操作步骤:[复现步骤]- 已尝试:[已做的排查]格式:按可能性排序,每条给出原因 + 验证方法 + 修复建议。

示例:分析 STM32 HardFault 报错

复制代码
角色:你是一位 ARM Cortex-M4 故障分析专家。任务:根据以下崩溃信息定位 HardFault 根因并给出修复方案。崩溃现场(真实值,来自调试器):- CFSR (0xE000ED28) = 0x00008200(请逐位拆解说明触发的 fault 类型)- HFSR (0xE000ED2C) = 0x40000000- 触发位置:PC=0x08001234,LR=0x08004567- 代码上下文:崩溃发生在 USART1 中断回调中补充信息:- 已排查:电源稳定(3.3V)、MPU 配置- 尚未排查:栈溢出、野指针、中断优先级格式:先给出最可能的根因排序(概率从高到低),每条给验证步骤和修复方案。禁止编造寄存器值;所有数值以上面提供的为准。

3.2.5 模板四:代码审查模板

适用场景:AI 生成代码后自查、他人代码 Review。

模板结构:

复制代码
角色:你是一位严格的嵌入式代码审查专家,关注硬件安全性和实时性。
任务:审查以下代码,重点检查:
1. 硬件相关:寄存器配置是否正确、时序是否满足
2. 内存安全:缓冲区溢出、野指针、内存泄漏
3. 并发安全:中断/多任务下的竞态条件
4. 实时性:阻塞调用、死循环、优先级问题
5. 代码风格:命名、注释、可维护性
上下文:代码运行在 [芯片],[RTOS/裸机] 环境。
格式:按严重程度分级(致命/警告/建议),每条给出位置、问题、修复方案。
[粘贴代码]

3.2.6 Prompt 进阶技巧

上下文管理:长对话如何保持上下文不丢失

  • 核心信息(芯片型号、引脚、时钟)在每轮关键提问中都重申一遍,不要指望 AI 记得上一轮(Anthropic 官方建议:长上下文放开头,具体请求放结尾);

  • 对话变长后,主动总结目前已确认、待确认清单,让 AI 基于最新状态继续;

  • 规则类信息(约束、禁止项)写进项目级规则文件(如 AGENTS.md 、.trae、rules),每次会话自动注入------这是七家主流工具(Cursor 、Claude Code 、Copilot、 JetBrains、 Cline 、Qoder CN、Trae CN)官方共同推荐的做法。

多轮迭代:第一次不满意如何追问修正

  • 第一次不满意,不要重新问一遍,而是指出具体偏差:你给的是标准库写法,我要求 HAL 库;请基于现有代码重写 USART 部分;

  • 要求 AI 先解释它理解的需求,你确认后再写代码:先要求 AI 输出计划/Spec,审查纠正后再写代码;

  • 编译报错时,把文件路径 + 行号 + 错误信息完整喂回:PhantomRun 实证这是修复率最高的模式。

角色设定:让 AI 扮演严格的导师vs乐于助人的同事的差异

  • 严格的导师:更适合代码审查、方案评审------要求逐条挑错、按严重度分级、不给面子;

  • 乐于助人的同事:更适合学习讲解、方案探讨------要求解释为什么、给替代方案;

  • 关键不在措辞,而在你随后要求它做的事。角色设定要与任务、格式配套。

避免幻觉:如何让 AI 标注不确定的部分

  • 在模板末尾追加兜底句:任何你无法从给定资料确认的硬件参数,明确列出并标注需人工核对,禁止自行补全或编造;

  • 涉及寄存器/引脚,强制要求以厂商官方头文件为准:只依赖上下文中直接提到的事实,不要使用自己的知识;

  • datasheet 类提取任务,明确:只基于我提供的文本,禁止补充未写内容,无法确定填 null。

提示词保存与管理:用 Trae 建个人 Prompt 库,后面专门演示

推荐用 Trae CN(原豆包 MarsCode)搭建个人 Prompt 库:

  1. 新建一个专门的Prompt 库仓库/项目,按场景归档;

  2. 把本章 4 类模板存为 .md 文件,每个文件头部写清楚适用场景 + 用法要点;

  3. 需要时用 Trae 的 #Rule 手动引用规则文件,或把模板粘贴进对话;

  4. 实战中改好的模板回写覆盖,让模板随项目沉淀,这样你就具备大批的数据库。

常见坑与提醒

  1. **Prompt 不是越长越好:**关键信息要精准------芯片型号、引脚、时钟、约束给足即可,无关描述会稀释重点;
  2. **不要一次问太多问题:**拆成多轮对话,一轮聚焦一个问题(尤其调试场景,一次一个假设);
  3. **AI 生成的代码必须人工审核:**尤其是寄存器配置、引脚复用、时钟分频------烧录前与官方头文件核对;
  4. **模板是起点:**要根据实际情况调整,不要生搬硬套------把你的芯片、引脚、库版本填进模板再使用。
相关推荐
周凡1231 小时前
从文档生成到可靠交付:基于 Dify 的流程化实践
人工智能
数据堂官方账号1 小时前
数据堂联合华为共筑 AI 数据价值新引擎
人工智能·华为·数据采集·具身智能·数据标注
Xuantong_901 小时前
拆解 Claude Sonnet5.5 底层设计:自适应思考、子智能体协同,Anthropic 如何重构中端大模型推理范式
人工智能·语言模型·重构
LX567771 小时前
制造业人学AI,按经验分三层
大数据·人工智能
babe小鑫1 小时前
金融工程专业秋招:金融类证书与数据分析类证书的搭配方案
大数据·数据库·人工智能
数字新视界1 小时前
2026机房动环监控选型指南:场景规模需求、市场发展占有率和竞争梯队报告解析
大数据·运维·网络·人工智能·嵌入式硬件·机房动环监控·机房环境安全
TK泰妞1 小时前
TikTok跨境电商提示词怎么找?Clipcat免费提示词资源与实用用法
大数据·人工智能
程序员_小兵1 小时前
PCIe Switch Fabric 技术解析
服务器·c语言·嵌入式硬件·php·fabric
胡家伟++1 小时前
从一段经文到 5 分半水墨动画短片:全 AI 流水线完整实录(即梦 + TTS 克隆 + ffmpeg + 思维链重构)
人工智能·ffmpeg·aigc