跳转至

键值对存储(nvm)

一、简介

nvm:非易失性存储器(英语:non-volatile memory,缩写为 NVM)是指当电流关掉后,所存储的数据不会消失的电脑存储器,利用文件系统实现的一种非易失性参数存储管理模块。

典型的应用场景为:小数据量的简单键值对参数。不适合大容量数据的存储管理,如果数据量超过 10K,建议直接使用 io 接口操作文件来管理。

二、演示功能概述

本教程教你如何用 Air724 开发板,用 nvm API 对小数据量的简单键值对参数读写,并通过日志观察实验结果。

三、准备硬件环境

3.1 开发板准备

使用 EVB_Air724 开发板,如下图所示:

淘宝购买链接:Air724UG-NFM 开发板淘宝购买链接

此开发板的详细使用说明参考:Air724UG 产品手册 中的《 EVB_Air724UG_AXX 开发板使用说明》,写这篇文章时最新版本的使用说明为:《EVB_Air724UG_A14 开发板使用说明》;开发板使用过程中遇到任何问题,可以直接参考这份使用说明文档。

api:https://doc.openluat.com/wiki/21?wiki_page_id=2068

3.2 数据通信线

USB 数据线一根(micro USB)。

3.3 PC 电脑

WIN7 以及以上版本的 WINDOWS 系统。

3.4 SIM 卡

中国大陆环境下,可以上网的 SIM 卡。一般来说,使用移动,电信,联通的物联网卡或者手机卡都行。

3.5 组装硬件环境

usb 数据线插入 USB 口,另一端与电脑相连,拨码开关全部拨到 ON,串口切换开关选择 UART1,USB 供电的 4V 对应开关拨至 ON 档,SIM 卡放到 SIM 卡槽中锁紧,如下图所示。

四、准备软件环境

4.1 下载调试工具

使用说明参考:Luatools 下载和详细使用

4.2 源码及固件

1.底层 core 下载

下载底层固件,并解压

链接:https://docs.openluat.com/air724ug/luatos/firmware/

如下图所示,红框的是我们要使用到的。

2.本教程使用的 demo:

https://gitee.com/openLuat/LuatOS-Air724UG/tree/master/script_LuaTask/demo/nvm

4.3 下载固件和脚本到开发板中

打开 Luatools,开发板上电开机,如开机成功 Luatools 会打印如下信息。

点击项目管理测试选项。

进入管理界面,如下图所示。

  • 点击选择文件,选择底层固件,我的文件放在 D:\luatOS\Air724 路径中

  • 点击增加脚本或资源文件,选择 之前下载的程序源码,如下图所示。

  • 点击下载底层和脚本,下载完成如下图所示。

五、代码示例介绍

5.1 API 说明

5.1.1 nvm.init(defaultCfgFile, burnSave)

初始化参数存储管理模块

  • 参数
名称
传入值类型
释义
defaultCfgFile
string
默认参数文件名
burnSave
bool
本地烧录时是否保留已有参数,true 为保留,false 或者 nil 为清除注意:在同一个项目,不同版本中,此参数必须保持前后版本一致
- 返回值

nil

  • 例子
_-- 初始化参数存储管理模块,默认参数文件名为config.lua,本地烧录时清除已有的参数:_
nvm.init("config.lua")
_-- 初始化参数存储管理模块,默认参数文件名为config.lua,本地烧录时保留已有的参数:_
nvm.init("config.lua",true)

5.1.2 nvm.set(k, v, r, s)

设置某个参数的值

  • 参数
名称
传入值类型
释义
k
string
参数名
v
param
参数的新值,仅支持 number、string、boolean、table 类型
r
param
设置原因,如果传入了非 nil 的有效参数,并且 v 值和旧值相比发生了改变,会产生一个 PARA_CHANGED_IND 内部消息,携带 k,v,r 3 个参数
s
param
是否立即写入到文件系统中,false 不写入,其余的都写入
  • 返回值

bool 或者 nil,成功返回 true,失败返回 nil

  • 例子
_-- 参数name赋值为Luat,立即写入文件系统:_
nvm.set("name","Luat")
_-- 参数age赋值为12,立即写入文件系统:-- 如果旧值不是12,会产生一个PARA_CHANGED_IND消息,携带 "age",12,"SVR" 3个参数:_
nvm.set("age",12,"SVR")
_-- 参数class赋值为Class2,不写入文件系统:_
nvm.set("class","Class2",nil,false)
_-- 参数score赋值为{chinese=100,math=99,english=98},立即写入文件系统:_
nvm.set("score",{chinese=100,math=99,english=98})
_-- 连续写入4个参数,前3个不保存到文件系统中,写第4个时,一次性全部保存到文件系统中:_
nvm.set("para1",1,nil,false)
nvm.set("para2",2,nil,false)
nvm.set("para3",3,nil,false)
nvm.set("para4",4)

5.1.3 nvm.sett(k, kk, v, r, s)

设置某个 table 类型参数的某一个索引的值

  • 参数
名称
传入值类型
释义
k
string
table 类型的参数名
kk
param
table 类型参数的某一个索引名
v
param
table 类型参数的某一个索引的新值
r
param
设置原因,如果传入了非 nil 的有效参数,并且 v 值和旧值相比发生了改变,会产生一个 TPARA_CHANGED_IND 消息,携带 k,kk,v,r4 个参数
s
param
是否立即写入到文件系统中,false 不写入,其余的都写入
  • 返回值

bool 或者 nil,成功返回 true,失败返回 nil

  • 例子
nvm.sett("score","chinese",100),参数score["chinese"]赋值为100,立即写入文件系统
nvm.sett("score","chinese",100,"SVR"),参数score["chinese"]赋值为100,立即写入文件系统,
_-- 如果旧值不是100,会产生一个TPARA_CHANGED_IND消息,携带 "score","chinese",100,"SVR" 4个参数_
nvm.sett("score","chinese",100,nil,false),参数class赋值为Class2,不写入文件系统

5.1.4 nvm.flush()

所有参数立即写入文件系统

  • 参数

  • 返回值

nil

  • 例子
nvm.flush()

5.1.5 nvm.get(k)

读取某个参数的值

  • 参数
名称
传入值类型
释义
k
string
参数名
  • 返回值

参数值

  • 例子
_-- 读取参数名为name的参数值:_
nameValue = nvm.get("name")

5.1.6 nvm.gett(k, kk)

读取某个 table 类型参数的键名对应的值

  • 参数
名称
传入值类型
释义
k
string
table 类型的参数名
kk
param
table 类型参数的键名
  • 返回值

参数值

  • 例子
_-- 有一个table参数为score,数据如下:_
score = {chinese=100, math=100, english=95}
_-- 读取score中chinese对应的值:_
log.info("score"nvm.gett("score","chinese"))

5.1.7 nvm.restore()

参数恢复出厂设置

  • 参数

  • 返回值

nil

  • 例子
nvm.restore()

5.1.8 nvm.remove()

请求删除参数文件.

此接口一般用在远程升级时,需要用新的 config.lua 覆盖原来的参数文件的场景,在此场景下,远程升级包下载成功后,在确定要重启前调用此接口

下次开机执行 nvm.init(“config.lua”)时,会用新的 config.lua 文件自动覆盖参数文件;以后再开机就不会自动覆盖了

也就是说"nvm.remove()-> 重启->nvm.init(“config.lua”)"是一个仅执行一次的完整操作

  • 参数

  • 返回值

nil

  • 例子
nvm.remove()

5.2 testNvm.lua 代码

系统启动后等待一定时间,确保异步操作有足够的时间完成。

nvm.sett() 用于将数据存储到非易失性存储器中,数据即使系统重启也能保存。

nvm.gett() 用于从非易失性存储器中读取数据。输出日志。

--- 模块功能:参数存储功能测试.
-- @author openLuat
-- @module nvm.testNvm
-- @license MIT
-- @copyright openLuat
-- @release 2018.03.27

module(...,package.seeall)

require"config"
require"nvm"

nvm.init("config.lua")

nvm.set("strPara","str2")
nvm.set("numPara",2)
nvm.set("boolPara",false)
nvm.set("tablePara",{"item2-1","item2-2","item2-3"})

log.info("testNvm.strPara",nvm.get("strPara"))
log.info("testNvm.numPara",nvm.get("numPara"))
log.info("testNvm.boolPara",nvm.get("boolPara"))
local tableValue = nvm.get("tablePara")
log.info("testNvm.tablePara",tableValue[1],tableValue[2],tableValue[3])

sys.taskInit(function()
    sys.wait(3000)
    nvm.sett("testtable","chinese",100)
    sys.wait(1000)
    log.info("testNvm.testtable",nvm.gett("testtable","chinese"))
end)

5.3 main.lua 代码

本代码为主程序脚本,系统启动后首先会对 4G 网络进行配置,等待网络连接成功,然后加载测试模块。

5.4 config.lua 代码

参数文件名为 config.lua,本地烧录时清除已有的参数。

六、开机调试

6.1 开发板开机

连接好硬件并下载固件后,启动 Luatools 软件,系统运行信息将显示在界面中。红框中为开发板连接到 PC 机后正常打印的信息,如下图所示。

6.2 功能调试

对出各种键,并且日志打印对应的数值。

七、常见问题

7.1 nvm 适用于什么场景?

nvm 每次更新参数,保存到参数文件中时,会把所有参数拼接在一起,然后执行一次全量写文件的动作;此拼接操作消耗内存较多,如果数据量很大,需要的内存就很大,在系统可用内存紧张的情况下,很容易出现内存不足,从而导致参数更新失败,严重情况下还会造成系统重启。 因此,nvm 仅适用于小数据量的简单键值对参数;不适用于大容量数据的存储管理,如果数据量超过 10KB【仅仅为经验值,实际能够存储的数据量和系统运行过程中的动态可用内存有关:可用内存越小,允许存储的数据量就越少;可用内存越大,允许存储的数据量就越多,但是也不建议超过 10KB】,建议参考 fs 的 demo 直接使用 io 接口操作文件来管理。

7.2 本地烧录时会清除原有的 para.lua 吗?

原有的 para.lua 是在 nvm.init(“config.lua”,true)时创建的,则不会清除,原有的 para.lua 是在 nvm.init(“config.lua”)时创建的,则会清除。

7.3 fota 远程升级时,会清除原有的 para.lua 吗?

默认不会 如果需要清除,根据产品的业务逻辑,在合适的时间点,调用 nvm.restore()恢复出厂设置即可。

7.4 软件版本升级时,可以在 config.lua 中增加新的参数吗?

可以,需要执行一次初始化动作才会生效,一般是直接重启执行初始化

7.5 软件版本升级时,可以在 config.lua 中删除旧的参数吗?

可以,但是操作起来比较复杂,不建议这样做 如果旧的参数没用了,可以在 config.lua 中一直保留;脚本代码不要再读写这些参数就行了。

7.6 程序运行过程中,可以使用 nvm.set 接口增加新的参数吗?

可以,新增的参数,在恢复出厂设置后会被清除,因为 config.lua 中没有此参数。

7.7 程序运行过程中,可以使用 nvm.set 接口删除已有的参数吗?

可以,将某个参数设置为 nil 就相当于删除。 删除的参数,在恢复出厂设置后会还原为 config.lua 中的默认值,因为 config.lua 中存在此参数。

7.8 读写操作过程中,掉电会丢失数据吗?

nvm 有备份机制,如果掉电时正在写参数,可能会造成正在写入的参数数据不生效,下次开机会恢复为上次正常写入的数据,不会导致数据内容出错 如果掉电时正在读参数,不会对参数数据造成任何影响;因为读取的是内存中的数据。

7.9 nvm.set 接口可以写多少次?

nvm 通过文件接口写 flash,具有擦写均衡机制 flash 可以完全擦写至少 10 万次 假设通过 rtos.get_fs_free_size()获取到的文件系统剩余空间为 512K 字节,nvm 参数文件总大小为 1K 字节,因为 nvm 参数文件还存在一个备份文件,所以写 256 次可以完全擦写一次文件系统剩余空间。允许擦写的总次数理论值就是 256*10 万次

给读者的话

本篇文章由杨超开发;

本篇文章描述的内容,如果有错误、细节缺失、细节不清晰或者其他任何问题,总之就是无法解决您遇到的问题;

请登录合宙技术交流论坛,点击文档找错赢奖金-Air724UG-LuatOS-软件指南-常用功能实现-键值对存储(nvm)

用截图标注+文字描述的方式跟帖回复,记录清楚您发现的问题;

我们会迅速核实并且修改文档;

同时也会为您累计找错积分,您还可能赢取月度找错奖金!