Skip to content

Latest commit

 

History

History
146 lines (110 loc) · 5.97 KB

dx_framework_code_style.md

File metadata and controls

146 lines (110 loc) · 5.97 KB

你们学长要求做到的嵌入式系统代码规范

1. 文件组织规范

  • 采用模块化组织方式,分为bsp(板级支持包)、module(功能模块)、task(任务)等目录
  • 每个模块包含:
    • .h头文件(接口声明)
    • .c源文件(实现)
    • .md文档(模块说明)
  • 头文件必须包含保护宏,格式为#ifndef MODULE_NAME_H/#define MODULE_NAME_H

2. 命名规范

  • 宏定义:全大写加下划线,如DBUS_BUFF_SIZE
  • 类型定义:使用_t后缀,如rc_info_t
  • 函数命名:小写加下划线,如pid_calc_add()
  • 变量命名:小驼峰式,如lastCount
  • 结构体成员:小写加下划线,如mouse_x

3. 注释规范

  • 文件头注释:说明文件用途和作者
  • 函数注释:使用Doxygen风格
/**
 * @brief 函数功能说明
 * @param param1 参数1说明
 * @return 返回值说明
 */
  • 关键代码块:添加中英文注释说明
  • 复杂算法:添加实现原理和公式说明

4. 代码风格

  • 缩进:4个空格
  • 大括号:K&R风格
  • 运算符前后加空格
  • 指针符号靠近类型名:int* ptr
  • 每行不超过120字符

5. 最佳实践

高内聚低耦合实现方法

高内聚低耦合实现方法

模块设计

  • 模块功能单一明确:每个模块专注于一个核心功能,避免功能交叉或过于复杂。例如:

    • 数据接收模块:仅负责接收数据。
    • 弹道解算模块:仅负责弹道计算。
    • 状态发送模块:仅负责状态的发送。
  • 明确模块层次结构:在系统设计时,明确模块的层次结构,将功能相近的模块划分到同一层次,并确保模块间的调用关系是上下层的,而非同层的。

    例如:

      数据接收模块 → 弹道解算模块 → 状态发送模块。
    

    反例:

  chassis_power_control(pid_type_def *pid_3508_speed_chassis[4],can_motor_t *chassis_Rx1[4],power *power_control);
  //同层调用了`can_motor_t`(位于电机通讯模块)`power`(功率控制模块,现已修改)
  • 通过接口进行交互:即使模块处于同一层次,也应通过定义好的接口进行交互,而非直接调用彼此的实现代码,降低模块间的耦合度。实际上,本框架决定只允许在task层进行模块间通信,其他层通过事件驱动或消息传递机制进行通信。

  • 使用事件驱动或消息传递机制:在某些情况下,可通过事件驱动或消息传递机制实现模块间的通信,而非直接调用。例如,模块 A 发送一个事件或消息,模块 B 监听并处理该事件或消息,从而实现松耦合通信。

  • 模块间通过清晰定义的接口交互:模块之间的交互应通过明确、简洁且稳定的接口进行,避免直接访问其他模块的内部实现。例如,数据接收模块通过定义好的接口将接收到的数据传递给弹道解算模块。

  • 使用配置宏控制功能开关:通过配置宏(如 radar_MOD)灵活地启用或禁用某些功能,提高系统的可配置性和可维护性。

接口设计

  • 参数和返回值使用结构体封装:将接口的参数和返回值封装在结构体中,提升接口的可读性和可维护性,同时减少参数传递错误的可能性。例如,定义一个结构体包含弹道解算所需的输入参数和输出结果。

  • 避免使用全局变量:尽量通过参数传递数据,而非使用全局变量,以降低模块间的耦合度,增强系统的可维护性和扩展性。

  • 提供工具函数库减少重复代码:创建通用工具函数库(如 map 函数用于数据映射,limit 函数用于数据限幅),在多个模块中复用这些函数,减少重复代码,提升代码一致性。

数据管理

  • 相关数据封装在结构体中:将相关的数据封装在结构体中,提升数据的组织性和可访问性。例如,将雷达数据的目标位置、速度、方向等信息封装在一个结构体中。

  • 使用访问宏统一数据访问方式:通过定义访问宏(如 get_vision_id)统一数据访问方式,确保数据访问的一致性和安全性。

  • 重要数据添加保护措施:对重要数据添加保护措施(如输出限幅、数据校验、备份等),防止数据超出合理范围或出现异常行为,提升数据可靠性。

文档规范

  • 模块接口必须有详细注释:每个模块的接口都应包含详细注释,说明接口的功能、输入参数、输出结果及返回值,便于其他开发者快速理解接口的使用方法。

  • 复杂算法提供实现原理说明:对于复杂的算法,应提供详细的实现原理说明(包括数学模型、假设条件、实现步骤等),帮助其他开发者理解算法逻辑和原理。

  • 数据结构有字段说明:对于数据结构中的每个字段,应提供详细的说明(包括字段含义、取值范围、单位等),确保其他开发者能够正确理解和使用这些数据。

其他最佳实践

  • 防御性编程,检查参数有效性
  • 重要操作添加安全限制
  • 复杂算法提供文档说明
  • 代码复用通过函数库而非复制粘贴

6. 示例

头文件示例

#ifndef MODULE_NAME_H
#define MODULE_NAME_H

#include "dependency.h"

#define MODULE_MAX_SIZE 128

typedef struct {
    int member1;
    float member2;
} module_t;

void module_init(module_t* mod);
int module_process(module_t* mod, int input);

#endif // MODULE_NAME_H

源文件示例

#include "module_name.h"

/**
 * @brief 模块初始化函数
 * @param mod 模块结构体指针
 */
void module_init(module_t* mod) 
{
    memset(mod, 0, sizeof(module_t));
    // 初始化代码...
}

/**
 * @brief 模块处理函数
 * @param mod 模块结构体指针
 * @param input 输入参数
 * @return 处理结果
 */
int module_process(module_t* mod, int input)
{
    if (input > MODULE_MAX_SIZE) {
        return -1; // 错误处理
    }
    // 处理逻辑...
    return 0;
}