本规范用于生成生产级嵌入式 C 代码,适用于 STM32、PowerPC、RISC-V 等平台。
核心原则: 像嵌入式软件架构师一样思考,生成可演进、可测试、可移植的代码。
生成代码时必须以 嵌入式软件架构师 的思维进行:
维度要求系统视角设计可演进的系统,考虑模块边界、接口契约、依赖关系资源意识内存精确计算缓冲区,CPU 减少中断嵌套,优化关键路径实时性ISR 应尽可能短,考虑 WCET,防范优先级反转/死锁/队列溢出可靠性看门狗策略、异常恢复、关键数据冗余存储硬件无关寄存器抽象为结构体,驱动与业务逻辑分离可测试公共接口易 mock,状态机可单步测试,边界条件覆盖
类型用途禁止uint8_t单字节、GPIOchar, signed char``uint16_t16位寄存器short, unsigned short``uint32_t32位寄存器、时间戳int, long, unsigned int``int32_t有符号值-uint64_t64位数据-bool布尔标志-
必须包含的头文件:
c
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
元素格式示例变量snake_case``sensor_value, data_count全局变量g_snake_case``g_system_ticks常量/宏SCREAMING_SNAKE``MAX_BUFFER_SIZE, SPI_CR_EN函数camelCase``initUart(), getSensorData()结构体类型snake_case_t``uart_config_t枚举类型snake_case_t``gpio_state_t枚举值PREFIXED_SNAKE``GPIO_STATE_LOW指针p_snake_case``p_rx_buffer寄存器结构体module_name_reg_t``spi_reg_t寄存器头文件module_reg.h``spi_reg.h
所有 public 函数必须:
embedded_code_status_t 枚举类型c
typedef enum {
EmbedCode_Ok = 0,
EmbedCode_ErrNullPtr = -1,
EmbedCode_ErrInvalidArg = -2,
EmbedCode_ErrTimeout = -3,
EmbedCode_ErrBusy = -4,
EmbedCode_ErrNotInit = -5
} embedded_code_status_t;
#define VALIDATE_NOT_NULL(ptr) \
do { if ((ptr) == NULL) return EmbedCode_ErrNullPtr; } while(0)
注释语言: 优先使用中文
原则说明中文优先便于团队阅读和维护解释 WHY注释应说明原因和意图,而非描述代码在做什么代码自说明如果代码本身已清楚表达含义,无需注释
Doxygen 文件头格式:
c
/**
* @file spi_reg.h
* @brief SPI 寄存器结构体定义
* @author Claude Code
* @date 2026-04-10
*/
行内注释示例:
c
config |= SPI_CR_EN_MASK; /* 启用 SPI,低电平有效 */
每个外设模块必须有独立的 reg.h 文件:
必需元素说明XXX_BASE_ADDR基地址定义,格式: XXX_BASE_ADDR``xxx_reg_t寄存器结构体,使用 volatile uint32_t``XXX_XXX_MASK/SHIFT位字段宏定义XXX_REG结构体指针访问宏
reg.h 模板:
c
/**
* @file spi_reg.h
* @brief SPI 外设寄存器定义
*/
#ifndef SPI_REG_H
#define SPI_REG_H
#include <stdint.h>
/* 基地址 */
#define SPI_BASE_ADDR (0xA0010000U)
/* 寄存器结构体 */
typedef struct {
volatile uint32_t CTRL; /* 0x00: 控制寄存器 */
volatile uint32_t STATUS; /* 0x04: 状态寄存器 */
volatile uint32_t DATA; /* 0x08: 数据寄存器 */
} spi_reg_t;
/* 位字段定义 */
#define SPI_CTRL_EN_MASK (1U << 0)
#define SPI_CTRL_MODE_MASK (3U << 2)
/* 寄存器访问 */
#define SPI_REG ((spi_reg_t *) SPI_BASE_ADDR)
#endif /* SPI_REG_H */
禁止直接赋字面值,必须使用已定义的宏:
c
// ❌ 错误
SPI_REG->CTRL = 0x47U;
SPI_REG->BAUD = 250U;
// ✅ 正确
SPI_REG->CTRL = SPI_CTRL_INIT_VAL;
SPI_REG->BAUD = SPI_BAUD_DIV;
禁止必须malloc, free, calloc, realloc固定大小缓冲区new, delete环形缓冲区用于数据流VLA (变长数组)精确计算的缓冲区大小c
#define BUFFER_SIZE 256U
uint8_t buffer[BUFFER_SIZE];
场景方式相关配置数据struct相关常量集合enum相关状态数据structc
/* 配置结构体 */
typedef struct {
uint32_t base_address;
uint16_t interrupt_priority;
bool enable_dma;
} peripheral_config_t;
/* 句柄结构体 */
typedef struct {
bool initialized;
peripheral_config_t config;
} peripheral_handle_t;
直接应用本规范生成代码,无需保留任何旧代码。
核心原则: 功能流程优先
⚠️ 用户提供的源代码代表着原有的功能实现流程。即使代码有错误,在修改前必须先完整理解其功能流程,再进行符合规范的改写。不得为符合规范而破坏原有的功能流程。
执行步骤:
步骤内容Step 1: 理解原代码梳理数据流、识别状态机/算法、标注寄存器操作Step 2: 识别重写部分确定需重构的函数/模块Step 3: 按规范重写类型/命名/结构体符合规范,功能逻辑保持一致Step 4: 回查验证验证功能流程未改变,所有规范已满足
关于原代码中的 bug:
检查现有代码是否符合嵌入式 C 规范。
执行步骤:
步骤内容Step 1: 对照检查按回查清单逐项检查Step 2: 标注问题列出不符合规范的地方Step 3: 提出建议提供具体的修改建议
text
project/
├── inc/
│ ├── module_reg.h # 寄存器结构体定义(每个外设必须有)
│ ├── module_config.h # 配置参数
│ └── module.h # 公共接口
└── src/
└── module.c # 实现
text
┌─────────────────────────────────────────────────────────┐
│ P (Plan) - 分析需求,检查完备性 │
│ • 确定模式: GENERATE / REWRITE / REVIEW │
│ • 检测领域/架构/外设关键词 │
│ • 检查关键信息是否完备(基地址等) │
│ ⚡ REWRITE模式: 优先理解原代码功能流程 │
├─────────────────────────────────────────────────────────┤
│ D (Do) - 生成/重写代码 │
│ • GENERATE: 直接应用本规范 │
│ • REWRITE: 保持原功能流程,应用本规范 │
│ • 创建或更新 reg.h 寄存器结构体定义 │
│ • 生成符合规范的代码 │
├─────────────────────────────────────────────────────────┤
│ C (Check) - 回查验证 │
│ • 对照回查清单逐项检查 │
│ • 验证寄存器结构体定义是否正确 │
│ ⚡ REWRITE模式: 验证功能流程是否保持一致 │
├─────────────────────────────────────────────────────────┤
│ A (Act) - 修正输出 │
│ • 修正所有发现的问题 │
│ • 重新回查确认 │
│ • 输出合格代码 │
└─────────────────────────────────────────────────────────┘
生成后必须逐项检查:
#检查项不合格则修正1是否有对应的 reg.h 文件?创建 reg.h2寄存器是否用 volatile uint32_t 结构体定义?重构为结构体3位字段是否有宏定义 (MASK/SHIFT)?添加位字段宏4类型是否仅用 stdint.h?替换所有非标准类型5命名是否符合规范表?修正所有命名6所有 public 函数有错误处理?添加状态返回7无任何 malloc/free/VLA?替换为固定缓冲区8注释是否使用中文?重写注释9文件头是否完整 (Doxygen)?添加 Doxygen10生成的代码是否符合规范?修正生成代码⚡ 11REWRITE 模式: 原代码的功能流程是否保持一致?确保数据流/状态机/算法逻辑不变⚡ 12寄存器赋值是否都使用宏?添加宏定义,禁止字面值赋值
c
// ❌ 错误
#define SPI_CTRL_ADDR (*(volatile uint32_t *)0xA0010000)
void spiInit(void) { SPI_CTRL_ADDR = 0x47; }
// ✅ 正确 - 独立的 reg.h,统一的命名风格
#include "spi_reg.h"
void spiInit(void) { SPI_REG->CTRL = SPI_CTRL_INIT_VAL; }
c
// ❌ 错误 - 含义不清
if (SPI_REG->STATUS & 0x04) { }
SPI_REG->CTRL |= (1U << 7);
// ✅ 正确 - 命名位字段宏
if (SPI_REG->STATUS & SPI_STATUS_TF_EMPT_MASK) { } /* TX FIFO empty */
SPI_REG->CTRL |= SPI_CTRL_SCPOL_MASK; /* 时钟极性 */
__I/ __IO 前缀#c
// ❌ 错误 - ARM CMSIS 特有,不具可移植性
typedef struct {
__I uint32_t DATA;
__IO uint32_t CTRL;
} spi_reg_t;
// ✅ 正确 - 标准 volatile
typedef struct {
volatile uint32_t DATA;
volatile uint32_t CTRL;
} spi_reg_t;
c
// ❌ 错误 - 魔法数字
SPI_REG->BAUD = 250U;
SPI_REG->CTRL = 0x08U;
// ✅ 正确 - 使用宏定义
SPI_REG->BAUD = SPI_BAUD_DIV;
SPI_REG->CTRL = SPI_CTRL_INIT_VAL;
GENERATE 模式输出每个外设模块:
text
module/
├── module_reg.h # 寄存器结构体定义
├── module.h # 公共接口
└── module.c # 实现