
有些注释看起来很多,实际一点用都没有。
比如这种:
cnt++; // 计数加一还有这种:
if (voltage < threshold) { // 如果电压小于阈值
power_off();
}它没有告诉你为什么要加一,也没有告诉你阈值从哪里来,更没有告诉你断电前有没有保存状态、有没有通知上位机、有没有可能误触发。
这种注释不是文档,是噪声。
嵌入式项目里,真正值得注释的地方,往往不是语法表面,而是代码背后的现场约束。
为什么这个 GPIO 初始化顺序不能改?
为什么 RS485 方向脚翻转后要等 20 微秒?
为什么 ADC 采样要避开 PWM 翻转边沿?
为什么这个状态机不能直接从运行态跳回空闲态?
为什么这个错误码不能删除?
这些信息通常不在代码本身里。老工程师知道,新人不知道;当年调过板子的人知道,两年后接手的人不知道;AI 更不知道。
所以我一直觉得,给嵌入式代码自动加注释这件事,不能简单理解成“让 AI 扫一遍代码,把每个函数解释一下”。
那样很容易把项目注释成一堆正确但无用的废话。
真正有价值的做法,是设计一个团队可复用的 Skill,让 AI 按统一规则给用户自己写的代码补关键注释,同时避开开源库、芯片库和自动生成文件。注释要少而准,能解释设计意图、状态机、边界条件和硬件约束。
很多项目并不是没有注释,而是注释没有打在关键点上。
我见过不少代码,函数头写得很长,真正危险的逻辑却没有一句说明。
/**
* @brief 处理电机状态
*/
void Motor_Process(void)
{
switch (motor_state) {
case MOTOR_STATE_RUN:
if (fault_flags & MOTOR_FAULT_OVERCURRENT) {
motor_state = MOTOR_STATE_STOPPING;
}
break;
}
}这个 @brief 没错,但也没什么价值。
真正需要说明的是:
嵌入式注释的价值,不是把代码翻译成中文,而是把代码看不出来的工程事实补上。
如果团队要批量使用 AI 自动注释,第一条规则就应该写清楚:
不要解释语法,要解释意图、边界和风险。
第一个翻车点,是注释范围失控。
AI 如果不加限制,很可能连 CMSIS、HAL、FreeRTOS、第三方协议栈、开源算法库都一起注释。结果仓库里多出一堆无意义改动,代码评审根本看不完。
第二个翻车点,是注释内容太虚。
比如“该函数用于处理数据”“该变量表示状态”“这里进行错误判断”。这些话看似没错,但读代码的人并不需要它。
第三个翻车点,是注释破坏工程节奏。
嵌入式项目经常对行宽、编码、编译宏、静态分析、MISRA、Doxygen 格式有要求。批量注释如果不统一,后面维护起来会很痛苦。
所以这个 Skill 不能只写一句“给代码加注释”。它至少要管住五件事。
如果这五件事没定义清楚,AI 自动注释很容易从效率工具变成仓库污染源。
嵌入式项目里有很多文件不应该被 AI 批量注释。
比如:
这些文件不是不能读,而是不要随便改。
Skill 里必须先定义排除规则。
建议在 Skill 里直接写排除目录和文件特征。
这里要注意:BSP/ 不一定都能改。有些板级文件是用户写的,可以注释;有些是工具生成的,只能跳过。Skill 不能死板,要先识别文件来源。
自动注释最难的地方,是克制。
嵌入式代码里,应该优先注释这些地方:
不建议注释这些地方:
注释应该增加信息密度,而不是增加文字密度。
自动注释要能批量用,格式必须统一。
我比较推荐嵌入式 C 项目使用接近 Doxygen 的函数头,同时保持局部注释克制。
函数注释模板可以这样定:
/**
* @brief 处理 RS485 接收事件并推进协议解析状态机。
*
* @param port 通信端口索引,取值范围为 0 到 COMM_PORT_MAX - 1。
* @param event 接收事件,必须来自串口空闲中断或 DMA 完成回调投递。
*
* @return 0 表示处理成功;负数表示端口无效、缓冲区异常或协议状态机错误。
*
* @note 本函数运行在通信任务上下文,不能在中断中直接调用。
* @note 只消费环形缓冲区中的完整帧,不负责清空 DMA 原始缓冲区。
*/
int Comm_ProcessRxEvent(uint8_t port, const CommRxEvent_t *event);变量注释可以这样定:
/* DMA 写入位置,由串口空闲中断更新;通信任务只读取快照,避免直接改写。 */
static volatile uint16_t s_uart3_dma_write_pos;
/* 电机保护状态机当前状态,只允许 Motor_Task 在任务上下文推进。 */
static MotorProtectState_t s_protect_state;局部逻辑注释可以这样定:
/* RS485 方向脚释放后需要等待收发器进入接收态,V2.1 板卡实测最小稳定时间约 15us。 */
Delay_Us(20);
/* 零长度接收通常来自空闲中断重复进入,不能推进写指针,否则会破坏环形缓冲区边界。 */
if (rx_len == 0U) {
s_uart3_zero_len_cnt++;
return;
}状态机注释可以这样定:
switch (s_motor_state) {
case MOTOR_STATE_STOPPING:
/*
* 先等待 PWM 输出降为 0,再关闭驱动使能。
* 直接跳到 IDLE 会绕过制动释放流程,可能导致功率桥残余电流未泄放。
*/
Motor_UpdateStopRamp();
break;
}这样的注释有几个特点:
下面是一个完整的中文 Skill 示例,可以作为团队内部版本的雏形。
---
name: embedded-code-commenter
description: 当用户要求为嵌入式 C 或 C++ 项目自动补充代码注释、统一注释格式、批量生成函数说明、变量说明、状态机说明、参数返回值说明,并且需要排除开源库、芯片库、自动生成文件和第三方代码时,使用本技能。
---
# 嵌入式代码自动注释
## 目标
为用户自研的嵌入式代码补充少量、准确、统一、可维护的注释。注释重点是设计意图、硬件约束、状态机规则、并发关系、参数单位、返回值含义和边界条件。不要把代码逐行翻译成中文。
## 处理范围
优先处理:
- `App/`
- `User/`
- `BSP/` 中用户手写部分
- `Src/` 中非自动生成部分
- `Inc/` 中用户定义的接口头文件
- 项目中特别标记为业务代码、板级代码、驱动适配代码的文件
必须跳过:
- 芯片厂商库
- RTOS 内核
- 开源组件
- 第三方 SDK
- 自动生成文件
- 已经明确禁止修改的协议文件
- 用户没有授权修改的目录
## 排除规则
遇到以下路径或特征时,不修改文件:
- `CMSIS`
- `HAL_Driver`
- `FreeRTOS`
- `rt-thread`
- `lwip`
- `fatfs`
- `mbedtls`
- `tinyusb`
- `third_party`
- `external`
- `vendor`
- 文件中包含 `DO NOT EDIT`
- 文件中包含 `Generated by`
如果文件来源不确定,先只读分析,不直接修改。
## 注释原则
1. 只给关键代码加注释。
2. 不解释一眼能看懂的语句。
3. 不写空泛评价,例如“提高稳定性”“保证安全运行”,除非说明具体机制。
4. 不改变代码逻辑。
5. 不改变量名、函数名、宏名和文件结构。
6. 不引入新的头文件。
7. 不扩大编译产物。
8. 保持原有编码、缩进和行宽风格。
9. 注释必须能被代码或工程事实支撑。
10. 如果无法判断设计意图,写成待确认注释或不写。
## 必须优先注释的对象
- 对外接口函数。
- 带有硬件时序要求的函数。
- 中断服务函数和回调函数。
- DMA、环形缓冲区、双缓冲相关逻辑。
- 状态机状态和关键迁移条件。
- 安全保护、降额、故障恢复逻辑。
- 协议兼容分支。
- 全局变量、静态变量、跨中断和任务共享的变量。
- 带单位的参数和返回值。
- 魔法数、阈值、延时值、重试次数。
## 函数注释格式
使用以下格式:
```txt/**
volatile。这个 Skill 的关键,不是写得长,而是把自由度控制住。
它告诉 AI:哪些能动,哪些不能动;哪些必须注释,哪些不要注释;注释应该写什么,不能写什么;最后还要检查什么。
这才像一个团队能批量使用的工具。
我不建议第一次就让 AI 扫完整个仓库。
正确做法是先选一个模块试跑,比如 App/Protocol/ 或 App/Motor/。
建议第一轮只处理 5 到 10 个文件。
评审时重点看:
通过之后,再扩大到整个用户自研目录。
好注释不是给编译器看的,也不是给领导看的。
它是给半年后的自己、刚接手项目的同事、半夜处理现场问题的人看的。
嵌入式代码里,很多真正重要的信息都藏在代码外面:板卡版本、现场波形、硬件余量、客户兼容、故障复现条件、当年踩过的坑。
AI 可以帮我们把这些信息补到代码边上,但前提是我们要给它规则。
这才是 AI Coding 在嵌入式团队里该做的事。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。