实践案例 · 可复用模板
👉 关于作者
高可复用嵌入式AI编程模板
传感器采集 · RS485通讯 · 上位机管理
基于"五层进化"方法论的真实项目骨架,集成负日志、CLI调试助手与自动化闭环
1. 项目全景
本项目是一个开箱即用的嵌入式AI编程模板,包含:
- 嵌入式主板(STM32F407):采集温湿度、压力等传感器,通过RS485总线与上位机通讯。
- 上位机软件(Python/Qt):负责设备管理、数据存储、实时曲线显示。
- Python调试助手(核心):同时监控RS485总线流量、控制板串口日志、上位机文件日志,并在适当时机输出AI可读的诊断总结。
整个项目严格遵循文章中的五层进化架构:结构化正/负日志、统一工程目录、多模型协作契约、CLI全自动闭环、Vibe+Verify模板化生成。
2. 项目目录结构(统一上下文)
project/ ├── firmware/ # 嵌入式固件 │ ├── src/ │ │ ├── main.c │ │ ├── sensor.c # 传感器采集 │ │ ├── rs485.c # RS485驱动 │ │ ├── protocol.c # 通讯协议 │ │ └── logger.c # 正/负日志引擎 │ ├── inc/ │ │ ├── logger.h │ │ └── negative_logger.h │ └── build/ │ └── CMakeLists.txt ├── host/ # 上位机软件 │ ├── main.py # 主界面 │ ├── rs485_manager.py # 串口通讯管理 │ ├── data_store.py # 数据存储 │ └── logs/ # 运行时日志目录 ├── debug_tools/ # 调试助手(Python脚本) │ ├── debug_assistant.py # 核心调试脚本(CLI) │ └── log_parser.py # 日志解析与总结 ├── .vscode/ │ └── tasks.json # 一键自动化任务 ├── agents.md # AI行为准则与项目上下文 └── README.md
3. 嵌入式固件:正/负日志实战
固件中集成了完整的结构化日志与负日志引擎,所有关键路径都添加了日志点。以下是RS485通讯任务的核心片段:
// firmware/src/protocol.c
void rs485_communication_task(void) {
static uint8_t epoch = 0;
LOG_STATE(WAITING_FOR_POLL, epoch); // 正日志:记录状态
// 等待上位机轮询帧(50ms超时)
EXPECT_WITHIN(50, "POLL_FRAME", poll_received_flag);
if (!poll_received_flag) {
// 负日志已自动输出,此处仅记录额外上下文
LOG("WARN", "Poll timeout, epoch=%d", epoch);
return;
}
EVENT_OCCURRED("POLL_received"); // 正日志:事件发生
// 采集传感器数据并回复
float temp = read_temperature();
float pressure = read_pressure();
rs485_send_response(epoch, temp, pressure);
LOG("INFO", "Response sent: temp=%.2f, press=%.2f, epoch=%d", temp, pressure, epoch);
epoch++;
}
固件中同时使用了
EXPECT_WITHIN(负日志)和 EVENT_OCCURRED(正日志),保证了运行时状态对AI完全透明。
4. 上位机软件:通讯与管理
RS485管理器
负责串口打开/关闭、轮询帧发送、超时重试。内部同样集成了正/负日志(输出到文件)。
# host/rs485_manager.py
def poll_device(self):
self.send_frame(CMD_POLL)
t0 = time.time()
while not self.response_received:
if time.time() - t0 > 0.05:
self.logger.negative("POLL_RESPONSE",
f"Device {self.dev_id} not responding")
break
time.sleep(0.001)
if self.response_received:
self.logger.positive("POLL_RESPONSE",
f"temp={self.temp}, press={self.press}")
数据管理
存储传感器历史数据,支持CSV导出。日志记录每次操作的成功/失败状态,便于AI诊断。
5. Python调试助手:三合一监控与自动总结
这是整个模板的灵魂脚本,它实现了对三个数据源的实时监控:
- RS485总线监听(通过USB转RS485适配器,监听模式)
- 控制板串口日志(通过另一个COM口读取固件printf输出)
- 上位机文件日志(实时tail -f,监控日志文件新增行)
脚本将所有日志统一为结构化格式,并在测试结束后、检测到负日志时、或定时周期自动输出AI可读的总结报告,方便复制给AI模型诊断。
#!/usr/bin/env python3
# debug_tools/debug_assistant.py
"""
三合一调试助手:监听RS485总线、控制板串口日志、上位机日志文件,
并按正/负日志规范输出统一的结构化日志与AI诊断总结。
用法:
python debug_assistant.py --rs485 COM3 --mcu COM4 --host-log ../host/logs/app.log
选项:
--summary-interval 10 每10秒自动输出一次总结(默认检测到负日志时立即输出)
--output-summary-only 仅输出总结,不输出实时日志行
"""
import serial
import time
import re
import os
import argparse
from datetime import datetime
from collections import defaultdict
class DebugAssistant:
def __init__(self, rs485_port, mcu_port, host_log_path, summary_interval=0):
self.rs485 = serial.Serial(rs485_port, 9600, timeout=0.1) if rs485_port else None
self.mcu = serial.Serial(mcu_port, 115200, timeout=0.1) if mcu_port else None
self.host_log_path = host_log_path
self.host_log_pos = 0
self.summary_interval = summary_interval # 0表示仅负日志触发
self.negative_events = []
self.positive_events = []
self.last_summary_time = time.time()
self.running = True
def read_rs485_line(self):
if self.rs485 and self.rs485.in_waiting:
line = self.rs485.readline().decode('utf-8', errors='ignore').strip()
if line:
print(f"[RS485] {line}")
self.categorize_log(line, source='RS485')
def read_mcu_line(self):
if self.mcu and self.mcu.in_waiting:
line = self.mcu.readline().decode('utf-8', errors='ignore').strip()
if line:
print(f"[MCU] {line}")
self.categorize_log(line, source='MCU')
def read_host_log(self):
if not os.path.exists(self.host_log_path):
return
with open(self.host_log_path, 'r', encoding='utf-8') as f:
f.seek(0, 2)
size = f.tell()
if size > self.host_log_pos:
f.seek(self.host_log_pos)
new_lines = f.read().splitlines()
self.host_log_pos = size
for line in new_lines:
print(f"[HOST] {line}")
self.categorize_log(line, source='HOST')
def categorize_log(self, line, source):
"""根据日志内容分类为正/负事件"""
if 'NEGATIVE' in line or 'expected' in line.lower():
self.negative_events.append((source, line))
elif 'POSITIVE' in line or 'occurred' in line.lower():
self.positive_events.append((source, line))
def generate_summary(self):
"""生成AI可读的诊断总结"""
summary = []
summary.append("=" * 40)
summary.append(f"🕒 调试总结 [{datetime.now().strftime('%H:%M:%S')}]")
summary.append(f"📊 正事件数量: {len(self.positive_events)}")
summary.append(f"⚠️ 负事件数量: {len(self.negative_events)}")
if self.negative_events:
summary.append("--- 负事件详情 (期望但未发生) ---")
for src, evt in self.negative_events[-5:]: # 最近5条
summary.append(f" [{src}] {evt}")
if self.positive_events:
summary.append("--- 最近正事件 ---")
for src, evt in self.positive_events[-3:]:
summary.append(f" [{src}] {evt}")
summary.append("=" * 40)
return "\n".join(summary)
def run(self):
print("🚀 调试助手启动,按Ctrl+C停止...")
try:
while self.running:
self.read_rs485_line()
self.read_mcu_line()
self.read_host_log()
# 触发总结的条件:
# 1. 检测到新的负事件立即输出
# 2. 或者按间隔周期输出
now = time.time()
if self.negative_events and (self.summary_interval == 0 or now - self.last_summary_time > self.summary_interval):
print("\n" + self.generate_summary())
self.last_summary_time = now
# 仅保留最近的汇总,防止重复输出同一批
self.negative_events = self.negative_events[-1:]
time.sleep(0.05)
except KeyboardInterrupt:
print("\n🛑 停止监控,输出最终总结:")
print(self.generate_summary())
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="三合一调试助手")
parser.add_argument("--rs485", help="RS485监听串口")
parser.add_argument("--mcu", help="控制板日志串口")
parser.add_argument("--host-log", help="上位机日志文件路径")
parser.add_argument("--summary-interval", type=int, default=0, help="总结输出间隔(秒),0=仅负日志触发")
args = parser.parse_args()
assistant = DebugAssistant(args.rs485, args.mcu, args.host_log, args.summary_interval)
assistant.run()
💡 这个脚本就是CLI闭环的物理载体:AI可以通过命令
python debug_tools/debug_assistant.py --rs485 COM3 --mcu COM4 --host-log host/logs/app.log 直接启动监控,并实时获取结构化总结,无需人工解读日志。
6. agents.md:AI协作契约
放入项目根目录,任何接入的AI助手都会自动遵守项目规范。
# agents.md - RS485传感器采集项目 ## 项目概述 - 嵌入式平台:STM32F407,RS485总线9600bps - 传感器:温湿度SHT30、压力传感器(模拟量) - 上位机:Python/PyQt,通过USB-RS485适配器通信 ## 状态枚举 | 数值 | 枚举名 | 含义 | |------|--------|------| | 0 | IDLE | 空闲 | | 1 | WAITING_FOR_POLL | 等待上位机轮询 | | 2 | SENDING_RESPONSE | 正在发送数据 | ## 行为准则 1. 所有日志分析优先查找 [NEGATIVE] 和 [POSITIVE] 标签 2. 上位机日志位于 host/logs/ 下,格式为结构化键值对 3. 调试助手启动命令:`python debug_tools/debug_assistant.py --rs485 COMx --mcu COMy --host-log host/logs/app.log` 4. 建议修改固件时,使用 git diff 格式输出 5. 遇到通讯超时,优先检查RS485总线终端电阻和设备地址 ## 已知陷阱 - 轮询间隔必须 > 50ms,否则固件可能因中断过载丢帧 - RS485收发切换需延时2ms,避免总线竞争
7. VSCode Tasks:一键全自动测试
// .vscode/tasks.json
{
"version": "2.0.0",
"tasks": [
{
"label": "build-fw",
"type": "shell",
"command": "cd firmware/build && cmake --build .",
"problemMatcher": ["$gcc"]
},
{
"label": "flash",
"dependsOn": ["build-fw"],
"type": "shell",
"command": "openocd -f interface/stlink.cfg -f target/stm32f4x.cfg -c 'program firmware/build/firmware.elf verify reset exit'"
},
{
"label": "start-debug-assistant",
"dependsOn": ["flash"],
"type": "shell",
"command": "python debug_tools/debug_assistant.py --rs485 COM3 --mcu COM4 --host-log host/logs/app.log",
"isBackground": true,
"problemMatcher": []
},
{
"label": "run-host-app",
"dependsOn": ["start-debug-assistant"],
"type": "shell",
"command": "python host/main.py"
},
{
"label": "full-test",
"dependsOn": ["run-host-app"],
"group": { "kind": "test", "isDefault": true }
}
]
}
8. 五层进化在本项目中的映射
| 层级 | 文章方法 | 本项目落地 |
|---|---|---|
| 第一招 | 双向可观测性 | 固件/上位机均使用正负日志宏;调试助手自动归类并总结 |
| 第二招 | 统一上下文 | 标准目录结构 + agents.md 提供完整项目语境 |
| 第三招 | 多模型协作 | 低代码模型生成模板,高能力模型分析调试总结 |
| 第四招 | CLI闭环 | debug_assistant.py 可被AI直接调用,输出结构化总结 |
| 第五招 | 完整闭环工程 | VSCode Tasks 实现一键 full-test,案例库可积累日志样本 |
🎯 使用场景:当AI助手(如Claude、GPT)接入此项目时,只需读取 agents.md 和项目结构,即可自主运行 full-test 任务,读取调试助手输出的总结,并基于正/负日志定位问题。整个过程无需人工解释硬件细节。
这个模板可以直接克隆到任何RS485传感器采集项目中。只需修改传感器驱动和协议帧定义,其余工程化组件(日志、调试助手、agents.md、tasks.json)均可复用。真正的"一次搭建,终身受益"。