嵌入式中常用的参数存储方案

一、有哪些参数需要管理?

在智能硬件产品中,一般有三类数据需要存储并管理:

1. 系统设置数据

系统设置数据是指产品自身正常工作所依赖的一些参数

这类数据的特点:只能在生产过程中修改,出厂后用户无权限修改

比如:产品 SN、产品密钥/token/license、传感器校准值。

2. 用户设置数据

用户设置数据是指在用户使用过程中,由用户根据自身喜好所设置的一些参数

这类数据的特点:出厂时恢复默认,出厂后由用户动态修改。

比如:检测类产品的告警阈值、模块化功能是否打开。

3. 用户使用数据

用户使用数据是指在用户使用过程中,产品工作产生的一系列用户数据

这类数据的特点:数据量较大,且用户需要查看历史数据

比如:过去一小时的语音数据、过去一天的监测数据、过去一周的视频数据等等。

二、参数的硬件存储方案

一些常见的参数存储方案如下,每种存储方案在不同的智能硬件产品中都有其独特的应用场景,选择合适的存储方案需要根据具体的需求、成本和技术限制来决定

1. EEPROM

EEPROM 是一种容量较小的存储器,在产品中需要外挂一片 EEPROM,适用于存储少量的数据。

优点:

  • 可以进行字节级别的擦写操作

  • 寿命较长,擦写次数通常在 10 万次左右

  • 价格低

缺点:

  • 容量较小,一般为几 KB 到几百 KB

比如:智能家居产品中用户设定的温度阈值设定可以存储在 EEPROM 中

2. Flash

Flash 是一种容量较大的存储器,比如 Spi Flash/Nand Flash/Emmc,适用于存储大量参数数据。

优点:

  • 容量较大,从几 MB 到几 GB 不等。

  • 擦写寿命较长,通常可达数十万次。

缺点:

  • 擦写操作需要按块(通常是几 KB 到几 MB)进行

  • 擦写时间较长

比如:智能手表中的用户使用数据(如步数、心率记录)可以存储在 Flash 中

3. FRAM(Ferroelectric RAM)

FRAM 是一种结合了 RAM 速度和 EEPROM 数据保存能力的存储器,适用于需要高频读写和数据保持的应用场景。

优点:

  • 擦写速度快,接近于 RAM。

  • 擦写寿命极长,通常在 10 亿次以上。

  • 非易失性,断电数据不丢失。

缺点:

  • 容量相对较小,通常为几 KB 到几 MB。

比如:医疗产品中的病人数据记录器,可以使用 FRAM 来存储重要的参数和数据

4. SD 卡或硬盘

SD 卡和硬盘适用于需要大容量存储的应用场景。

优点:

  • 容量大,从几 GB 到几 TB 不等。

  • 便于更换和升级。

缺点:

  • 可靠性相对较低,易受物理损坏。

  • 速度较慢,特别是与内部存储器相比。

比如:智能监控摄像头会使用 SD 卡来存储视频录制文件

5. 云存储

云存储是一种通过互联网将数据存储在远程服务器上的方法,适用于需要大容量和易于共享的场景。

优点:

  • 理论上容量无限

  • 易于访问和共享

  • 数据安全和备份有保障

缺点:

  • 依赖网络连接。

  • 存在隐私和安全风险。

比如:智能家居系统中将过去一天的监测数据上传到云端进行存储和分析

三、参数的软件管理方案

参数能通过硬件进行存储后,还需要进行软件的管理,比如参数读取、参数写入、参数备份、参数重置、参数更新等软件功能。

一些常见的软件管理方案如下,这些方案都有其适用的场景,根据存储介质的特点和具体应用场景进行权衡,在使用过程中需要灵活使用,甚至可以配合使用。

一般来说:

  • 简单的参数存储:选 KV 存储或配置文件

  • 大量复杂数据或历史记录:嵌入式数据库

  • 远程访问和备份数据:云存储

1. 文件系统

适用场景: 大容量存储,如 Flash 或 SD 卡。

方法:

  • 使用嵌入式文件系统,如 FATFS、LittleFS 或 SPIFFS,将参数存储为文件,可以方便地进行读取和修改。

  • 文件内容格式可以是 ini、json、xml 等。

示例代码(使用 SPIFFS):

#include <SPIFFS.h>

void setup() {
  if (!SPIFFS.begin(true)) {
    Serial.println("SPIFFS Mount Failed");
    return;
  }

  File file = SPIFFS.open("/config.txt", FILE_WRITE);
  if (!file) {
    Serial.println("Failed to open file for writing");
    return;
  }
  file.println("parameter1=value1");
  file.println("parameter2=value2");
  file.close();
}

void loop() {
  // 读取和处理参数
  File file = SPIFFS.open("/config.txt");
  if (!file) {
    Serial.println("Failed to open file for reading");
    return;
  }
  while (file.available()) {
    Serial.println(file.readStringUntil('\n'));
  }
  file.close();
}

2. 数据库

适用场景: 需要管理大量复杂参数或历史记录。

方法:

  • 使用嵌入式数据库,如 SQLite,数据库可以提供强大的查询和管理功能。

示例代码(使用 SQLite):

#include <sqlite3.h>

void setup() {
  sqlite3 *db;
  char *zErrMsg = 0;
  int rc;

  rc = sqlite3_open("/mydb.db", &db);
  if (rc) {
    Serial.printf("Can't open database: %s\n", sqlite3_errmsg(db));
    return;
  }

  const char* sql = "CREATE TABLE IF NOT EXISTS CONFIG ("
                    "ID INTEGER PRIMARY KEY AUTOINCREMENT,"
                    "KEY TEXT NOT NULL,"
                    "VALUE TEXT NOT NULL);";
  rc = sqlite3_exec(db, sql, 0, 0, &zErrMsg);
  if (rc != SQLITE_OK) {
    Serial.printf("SQL error: %s\n", zErrMsg);
    sqlite3_free(zErrMsg);
  }

  sqlite3_close(db);
}

void loop() {
  // 数据库操作示例
}

3. 键值存储(KV-存储)

适用场景: 少量配置参数,频繁读写,如 EEPROM、FRAM。

方法:

  • 使用键值对存储结构,常见库如 FlashDB、EEPROM 库、Preferences 库。

示例代码(使用 FlashDB):

#include <flashdb.h>

#ifdef FDB_USING_KVDB

#define FDB_LOG_TAG "[sample][kvdb][basic]"

void kvdb_basic_sample(fdb_kvdb_t kvdb)
{
    struct fdb_blob blob;
    int boot_count = 0;

    FDB_INFO("==================== kvdb_basic_sample ====================\n");

    { /* GET the KV value */
        /* get the "boot_count" KV value */
        fdb_kv_get_blob(kvdb, "boot_count", fdb_blob_make(&blob, &boot_count, sizeof(boot_count)));
        /* the blob.saved.len is more than 0 when get the value successful */
        if (blob.saved.len > 0) {
            FDB_INFO("get the 'boot_count' value is %d\n", boot_count);
        } else {
            FDB_INFO("get the 'boot_count' failed\n");
        }
    }

    { /* CHANGE the KV value */
        /* increase the boot count */
        boot_count ++;
        /* change the "boot_count" KV's value */
        fdb_kv_set_blob(kvdb, "boot_count", fdb_blob_make(&blob, &boot_count, sizeof(boot_count)));
        FDB_INFO("set the 'boot_count' value to %d\n", boot_count);
    }

    FDB_INFO("===========================================================\n");
}

#endif /* FDB_USING_KVDB */

4. 云存储

适用场景: 需要远程访问和备份,数据量大。

方法:

  • 使用云存储服务,如各个大厂的物联网平台,或者自建物联网平台。

  • 通过网络接口(如 HTTP、MQTT)进行数据传输和管理。

示例代码(使用 HTTP POST 到云服务器):

#include <WiFi.h>
#include <HTTPClient.h>

const char* ssid = "your-SSID";
const char* password = "your-PASSWORD";
const char* serverName = "http://your-server.com/upload";

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }

  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    http.begin(serverName);
    http.addHeader("Content-Type", "application/json");

    String postData = "{\"param1\": 42, \"param2\": 3.14}";
    int httpResponseCode = http.POST(postData);

    if (httpResponseCode > 0) {
      String response = http.getString();
      Serial.println(httpResponseCode);
      Serial.println(response);
    } else {
      Serial.print("Error on sending POST: ");
      Serial.println(httpResponseCode);
    }

    http.end();
  }
}

void loop() {
  // 云端管理和处理参数
}

如果还有未被整理到的方案,欢迎留言区讨论补充!

  • 25
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值