4、参数配置文件:配置文件格式(INI/JSON/XML)、参数分类、加载与保存操作

说到AF调试的参数配置,我见过不少新手工程师直接把参数写死在代码里。嗯,这种做法在原型验证阶段还能凑合,一旦进入量产标定阶段,你就会发现——改一个参数就得重新编译固件,效率低得让人抓狂。

配置文件,说白了就是把参数和代码解耦。你想想看,调试工程师不需要动代码,改改配置文件就能调整对焦策略,这才是正经的工程化做法。这一章我们就来聊聊配置文件的那些事。

4.1 三种主流配置文件格式

我个人在实际项目中接触最多的就是这三种:INI、JSON、XML。它们各有各的脾气,选对了能省不少事。

格式 可读性 解析速度 层级支持 典型场景
INI ★★★★★ ★★★★★ ★☆☆☆☆ 嵌入式设备、简单参数
JSON ★★★★☆ ★★★★☆ ★★★★★ PC端工具、复杂结构
XML ★★★☆☆ ★★★☆☆ ★★★★★ 跨平台交换、带Schema校验

4.1.1 INI格式——轻量级选手

INI格式是我最早接触的配置文件格式。结构简单,就是「节(Section) + 键值对(Key=Value)」。在资源受限的嵌入式平台上,INI的解析器可以做到非常轻量。

; AF调试参数配置文件 (INI格式)
[LENS]
; 镜头型号与物理参数
model=GC5035
focal_length=3.58
f_number=2.2

[AF_CALIB]
; 对焦校准参数
infinity_code=120
macro_code=950
search_range=30

[AF_TUNING]
; 对调优参数
step_delay_ms=5
overshoot_compensation=2
hysteresis_threshold=3
我的习惯:INI格式最适合存放「扁平化」的参数。如果你的参数结构只有一两层,用INI就够了。我曾经在一个低端摄像头项目里用INI做标定参数存储,解析代码只写了不到100行C代码,跑在Cortex-M0上毫无压力。

4.1.2 JSON格式——结构化首选

JSON现在基本是PC端调试工具的标配。为什么?因为它天然支持嵌套结构,而且几乎所有编程语言都有现成的解析库。

{
    "lens": {
        "model": "GC5035",
        "focal_length": 3.58,
        "f_number": 2.2
    },
    "af_calib": {
        "infinity_code": 120,
        "macro_code": 950,
        "search_range": 30
    },
    "af_tuning": {
        "step_delay_ms": 5,
        "overshoot_compensation": 2,
        "hysteresis_threshold": 3,
        "velocity_curve": [10, 25, 50, 80, 100]
    }
}

你看,JSON里可以用数组来表示曲线数据,这在INI里就很难优雅地表达。我个人在写调试工具时,90%的情况都用JSON。它比XML简洁,比INI灵活,刚好卡在中间。

避坑提醒:JSON文件里不能有注释!这是很多人刚接触时踩的坑。我曾经在量产配置里写了注释,结果解析器直接报错,排查了半天才发现是注释的问题。如果需要注释,可以考虑用JSON5格式,或者单独维护一份带注释的文档。

4.1.3 XML格式——工业级选择

XML现在用得少了,但在某些特定场景下它依然不可替代。比如需要做Schema校验的场景,或者需要和第三方系统做数据交换时。

<?xml version="1.0" encoding="UTF-8"?>
<af_configuration>
    <lens>
        <model>GC5035</model>
        <focal_length unit="mm">3.58</focal_length>
        <f_number>2.2</f_number>
    </lens>
    <af_calib>
        <infinity_code>120</infinity_code>
        <macro_code>950</macro_code>
        <search_range>30</search_range>
    </af_calib>
</af_configuration>

XML最大的优势是可以用属性(attribute)来附加元信息,比如上面的unit="mm"。但代价就是文件体积大,解析慢。说实话,除非客户强制要求,我一般不会主动选XML。

4.2 参数分类——别把所有参数塞在一起

这是很多新手容易犯的错:把所有参数堆在一个文件里,不分层级,不分类型。结果就是——改一个参数要翻半天,还容易改错。

我一般把AF参数分成三大类:

  1. 物理参数:镜头型号、焦距、光圈等。这些参数由硬件决定,一般不动。
  2. 校准参数:无穷远码值、微距码值、搜索范围等。这些参数每颗模组都不一样,需要逐颗标定。
  3. 调优参数:步进延时、过冲补偿、迟滞阈值等。这些参数是调试工程师反复试出来的「手感」参数。
核心原则:物理参数和校准参数要「只读」,调优参数要「可写」。调试工具里一定要区分权限,不然误改了物理参数,整批模组都得报废。

4.3 加载与保存操作——代码实现

理论说完了,咱们上点干货。下面是我在实际项目中用的一套加载/保存流程,以JSON为例。

4.3.1 加载流程

// 伪代码:加载配置文件
function loadConfig(filePath):
    // 1. 检查文件是否存在
    if not fileExists(filePath):
        return loadDefaultConfig()  // 加载默认配置
    
    // 2. 读取文件内容
    rawData = readFile(filePath)
    
    // 3. 解析JSON
    config = parseJSON(rawData)
    if config is null:
        logError("配置文件格式错误,使用默认配置")
        return loadDefaultConfig()
    
    // 4. 校验必填字段
    if not validateRequiredFields(config):
        logError("配置文件缺少必要字段")
        return loadDefaultConfig()
    
    // 5. 参数范围检查
    config = clampParameters(config)
    
    // 6. 返回有效配置
    return config
我的经验:加载配置时一定要做「容错处理」。我曾经遇到过产线工人误操作,把配置文件内容清空了。如果代码直接崩溃,整条产线就得停。所以我的习惯是——加载失败就回退到默认配置,同时打日志报警。

4.3.2 保存流程

// 伪代码:保存配置文件
function saveConfig(config, filePath):
    // 1. 参数合法性检查
    if not validateConfig(config):
        showError("参数不合法,无法保存")
        return false
    
    // 2. 序列化为JSON字符串
    jsonStr = serializeToJSON(config, prettyPrint=true)
    
    // 3. 写入临时文件(防止断电丢数据)
    tempPath = filePath + ".tmp"
    writeFile(tempPath, jsonStr)
    
    // 4. 原子替换(rename操作在大多数系统上是原子的)
    rename(tempPath, filePath)
    
    // 5. 校验写入结果
    verifyData = readFile(filePath)
    if verifyData != jsonStr:
        logError("写入校验失败")
        return false
    
    return true
我曾经踩过的坑:直接覆盖写入原文件,结果写到一半断电了,文件损坏,整批模组的标定数据全丢了。从那以后,我所有的保存操作都改成「先写临时文件,再原子替换」的模式。这个习惯救了我好几次。

4.4 知识结构总览

下面这张图把配置文件的核心逻辑串起来了,你可以对照着理解。

配置文件知识结构图 配置文件 INI格式(轻量扁平) JSON格式(结构灵活) XML格式(工业标准) 物理参数(只读) 校准参数(只读) 调优参数(可写) 加载:校验+容错 修改:参数范围检查 保存:原子写入+校验 核心原则:物理/校准参数只读,调优参数可写 加载失败回退默认配置,保存使用临时文件+原子替换

4.5 实战建议

最后,我总结几条实战中的建议:

  • 版本号一定要带:配置文件里加一个version字段。我遇到过不同版本的调试工具生成不同格式的配置,没有版本号根本没法兼容。
  • 注释用外部文档:JSON不支持注释,那就单独维护一份带注释的模板文件。产线用的配置文件里不要有任何注释,减少解析出错的可能。
  • 备份机制:每次保存前自动备份旧文件,命名成config.json.bak。这个习惯帮我挽回过好几次误操作。
  • 参数范围写在代码里:不要依赖配置文件里的注释来提示范围,要在代码里硬编码上下限。配置文件可以被篡改,但代码里的校验是最后一道防线。

嗯,配置文件这块其实不难,但细节决定成败。你想想看,一个参数写错了,可能整批模组的对焦性能都受影响。把这些基础工作做扎实了,后面的调试才能事半功倍。