Skip to content

第 7 章:NVS 参数持久化

7.1 知识要点

  • NVS(Non-Volatile Storage)的分区结构与命名空间
  • 基本类型(u8/i32/float)和 blob 的读写 API
  • 参数初始化标志位的设计模式
  • USB CDC 串口命令解析与参数热更新

7.2 课程内容

机器人控制系统中,PID 参数等调试数据需要在断电后保留。ESP32-S3 的 NVS 提供了一个键值存储系统,基于 Flash 的磨损均衡分区,支持字符串、整数、浮点数和任意二进制数据(blob)的持久化存储。本章演示将 PID 参数以 blob 形式存入 NVS,并通过 USB CDC 串口命令实时修改。

7.3 基础学习

NVS 结构

NVS 使用命名空间(namespace)隔离不同模块的数据,每个命名空间下可以存储多个键值对:

NVS Flash
└── namespace: "pid_params"
    ├── key: "init"   → u8(是否已初始化)
    └── key: "params" → blob(pid_params_t 结构体)

初始化标志模式

首次上电时 NVS 为空,需要写入默认值。通过一个 init 标志位判断是否已初始化,避免每次重启都覆盖用户修改的参数:

c
uint8_t inited = 0;
nvs_get_u8(h, "init", &inited);
if (!inited) {
    // 使用默认值,不从 NVS 读取
}

Blob 读写

Blob 可以存储任意结构体,读取时需要传入缓冲区大小:

c
// 写入
nvs_set_blob(h, "params", &g_params, sizeof(pid_params_t));
nvs_commit(h);  // 必须 commit 才会真正写入 Flash

// 读取
size_t sz = sizeof(pid_params_t);
nvs_get_blob(h, "params", &g_params, &sz);

7.4 程序学习

加载参数(带默认值回退):

c
static void params_load(void)
{
    nvs_handle_t h;
    if (nvs_open("pid_params", NVS_READONLY, &h) != ESP_OK) goto defaults;

    uint8_t inited = 0;
    nvs_get_u8(h, "init", &inited);
    if (!inited) { nvs_close(h); goto defaults; }

    size_t sz = sizeof(pid_params_t);
    if (nvs_get_blob(h, "params", &g_params, &sz) == ESP_OK) {
        nvs_close(h);
        return;
    }
defaults:
    g_params.kp = 447.0f;
    g_params.ki = 4.7f;
    g_params.kd = 47.0f;
}

保存参数:

c
static void params_save(void)
{
    nvs_handle_t h;
    ESP_ERROR_CHECK(nvs_open("pid_params", NVS_READWRITE, &h));
    nvs_set_blob(h, "params", &g_params, sizeof(pid_params_t));
    nvs_set_u8(h, "init", 1);
    nvs_commit(h);
    nvs_close(h);
}

串口命令解析:

c
char line[64];
if (fgets(line, sizeof(line), stdin)) {
    float val;
    if (sscanf(line, "kp %f", &val) == 1) {
        g_params.kp = val;
        params_save();
    } else if (strcmp(line, "show") == 0) {
        printf("kp=%.2f ki=%.2f kd=%.2f\n",
               g_params.kp, g_params.ki, g_params.kd);
    }
}

7.5 课程总结

本章掌握了 NVS 的命名空间、blob 读写和 commit 机制,实现了 PID 参数的断电保持和串口热更新。这一模式适用于所有需要持久化的配置参数,是嵌入式系统调试的重要工具。


Built for OSRCORE robot development board.