目前用d133定时采集can总线上的数据,然后在rgb屏幕上的lvgl界面上显示出来。
但是想保存采集到的数据,方便其他设备查询历史记录,或者在lvgl界面上查询历史记录。
请教,有什么好的办法?
问了几个群里,有推荐sqlite3和flashdb的。想知道,使用数据库有什么好处?
还有就是目前使用的spi nor flash,如果用fatfs,好想说并不适合频繁擦写。
目前有两种需求:
1, 采集can总线上定时发送过来的数据,每次保存,或几次采集后保存一次,可能保存频率很高;
2, 采集can总线上不定时发送过来的,一般是系统出现问题时才发送过来,保存频率较低。
最近编辑记录 Gentlepig (2024-06-25 09:23:01)
离线
建议用日志型(ext4,jffs2...)的文件系统,按时间段分文件存储。
如果没有后备电池和断电检测,做好最后一个文件阵亡的心理准备。
我这不是linux系统啊,是rtt,目前看sdk里默认打开了fatfs和littlefs。
离线
晕哥 说:建议用日志型(ext4,jffs2...)的文件系统,按时间段分文件存储。
如果没有后备电池和断电检测,做好最后一个文件阵亡的心理准备。
我这不是linux系统啊,是rtt,目前看sdk里默认打开了fatfs和littlefs。
那建议优先使用Littlefs文件系统,按时间段分文件存储。
LittleFS 是一种日志结构化的文件系统。它结合了日志结构(log-structured)文件系统和Copy-on-Write (COW)文件系统的特点。在日志结构的文件系统中,新的数据总是被写入到空闲或新分配的空间中,而不是直接覆盖旧的数据,这有助于减少对闪存介质的磨损并提供更好的掉电恢复能力。
在线
手头的板子没焊接sd相关,打算先用spi nor flash存储做个尝试。
rtt配置里勾选了littlefs和sqlte,sqlite里勾选了example。
/rodata配置为fatfs,分配了5M;/data配置为littlefs,分配了7M。
student_dao.c里默认数据库存在/data/stu_info.db。
编译后烧录到板子上,执行crate_student_tbl命令,按说应该在/data目录下生成stu_info.db数据库,可串口终端一直卡在这个命令这里,不过光标还是闪烁的。
等了几分钟后,仍是这个效果,就重启板子,发现/data下有stu_info.db文件,虽然大小为0。
执行stu命令,应该显示数据库所有数据,结果仍是卡住且光标正常闪烁。
以为是文件系统的问题,将student_dao.c里创建数据库的位值改为/rodata,这个是fatfs格式的。
结果执行create_student_tbl命令后,还是卡住,重启后,在/rodata目录下,并没有db数据库文件生成。
离线
@Gentlepig
长期保存建议512M的SLC
离线
不用FS,自己管理写入位置,能做到最少的Flash磨损。
Flash擦除后,分多次写入,一直往后写,不改前面的,写完一个块应该只算写了一次。(记得是这样)
如果断电,重新上电后扫描一遍Flash。要求写入的数据每个块一定不全为0xFF,这样就知道上次写到哪个位置了。
离线
FLASH的写入次数有限制,而且像NorFlash写入速度极慢。
D133有网络,数据通过网络保存到服务器上是比较好的方案。
如果对数据的完整性要求高,设备端要加上铁电存储,未上传到服务器上的数据先保存到铁电里。
直接写FLASH可以考虑加个掉电保护,比如外部是12V供电,到单片机端变压成5V,单片机供电端加个较大的电容。
用一个比较电路,外部断电时电压低于内部,触发中断,依靠电容中的电将未保存的数据存到FLASH。
离线
@Gentlepig
写一大串没用的,难道你就没有怀疑是你输入的命令有问题?写了一大串也没有把重要细节show出来!
输入命令如下:
dlk /> df /rodata
disk free: 4.8 MB [ 9968 block, 512 bytes per block ]
dlk /> df /data
disk free: 6.8 MB [ 1764 block, 4096 bytes per block ]
dlk /> create_student_tbl
/rodata/stu_info.db
对应函数如下,无参数,目的是创建数据库:
static int create_student_tbl(void)
{
int fd = 0;
db_set_name("/data/stu_info.db");
fd = open(db_get_name(), O_RDONLY);
rt_kprintf(db_get_name());
if (fd < 0)
{
/* there is not the .db file.create db and table */
const char *sql = "CREATE TABLE student(id INTEGER PRIMARY KEY AUTOINCREMENT,name varchar(32) NOT NULL,score INT NOT NULL);";
return db_create_database(sql);
}
else if (db_table_is_exist("student") > 0)
{
/* there is the table int db.close the db. */
close(fd);
LOG_I("The table has already existed!\n");
return RT_EOK;
}
else
{
/* there is not the table int db.create the table */
const char *sql = "CREATE TABLE student(id INTEGER PRIMARY KEY AUTOINCREMENT,name varchar(32) NOT NULL,score INT NOT NULL);";
return db_create_database(sql);
}
}
MSH_CMD_EXPORT(create_student_tbl, create sqlite db);
详细文件见:
https://gitee.com/artinchip/luban-lite/blob/master/packages/third-party/sqlite/student_dao.c
离线
还是得看readme.
358 ## 注意事项
1 - SQLite资源占用:RAM:250KB+,ROM:310KB+,所以需要有较充足的硬件资源。
2 - 根据应用场景创建合理的表结构,会提高操作效率。
3 - 根据应用场合理使用SQL语句,如查询条件,插入方式等。
4 - 如涉及到多表操作或联表查询,最好使用PowerDesigner等工具合理设计表。
我是在msh里执行create_student_tbl命令的,应该是需要比较大的内存,而msh默认分配了4k内存,改成40k后,可以创建数据库成功了。使用stu add xxx命令来增加数据条出错了,还在解决:
dlk />
dlk /> cd data
dlk /data> ls
Directory /data:
123 4
stu_info.db 12288
ui_font_Big.c 102408
dlk /data> stu add 1
01-01 08:31:52 E/app.dbhelper: bind failed errmsg:database disk image is malformed
01-01 08:31:52 E/app.dbhelper: db operator failed,rc=1
01-01 08:31:52 E/app.student_dao: add failed!
dlk /data>
dbhelper.c文件里,该行报错:
268 sqlite3_finalize(stmt);
1 if ((rc != SQLITE_OK) && (rc != SQLITE_DONE))
2 {
3 LOG_E("bind failed errmsg:%s", sqlite3_errmsg(db));
4 goto __db_exec_fail;
5 }
-------------------------------
msh栈空间改为400k,结果仍一样。
尝试改为1M,结果上电后,不运行了...
---------------------------------
student_dao.c里,执行stu add命令后,会调用到这个函数。
int student_add(rt_list_t *h)
{
return db_nonquery_operator("insert into student(name,score) values (?,?);", student_insert_bind, h);
}
db_nonquery_operator()执行一系列操作后,调用的是如下函数。
static int student_insert_bind(sqlite3_stmt *stmt, int index, void *arg)
{
int rc = 0;
rt_list_t *h = arg, *pos, *n;
student_t *s = RT_NULL;
rt_list_for_each_safe(pos, n, h)
{
s = rt_list_entry(pos, student_t, list);
sqlite3_reset(stmt); //reset the stmt
sqlite3_bind_text(stmt, 1, s->name, strlen(s->name), NULL); //bind the 1st data,is a string
sqlite3_bind_int(stmt, 2, s->score); //bind the 1st data,is a int
rc = sqlite3_step(stmt); //execute the stmt by step
}
if (rc != SQLITE_DONE)
return rc;
return SQLITE_OK;
}
感觉是这个函数执行后返回的值rc,根据rc值执行了报错输出。
最近编辑记录 Gentlepig (2024-06-26 17:45:54)
离线
个人比较推荐2个方向:
1.上传数据至本地内存卡,可以以TXT形式by天/周保存成单个txt;之前做过类似功能,效果还不错;
2.借助物联网平台或者自己搭物联网平台,可以增加一个5块钱的ESP8266模块,将你的数据推上阿里云,优点是可远程查询数据。
离线
@Gentlepig
目前大企业都是自己搭云平台实现,小公司用公共云平台,更建议你数据上云。
离线
感谢各位,板子是有网口的,目前是通过tcp将数据发送给局域网pc。
本机存储是想以后可能会用到,某些不定时的,数量较少的数据,希望存储到板子上。
离线
正如7楼所说的,不用FS,直接写FLASH,写满了再擦,这种方法对FLASH寿命保护最好。
离线
正如7楼所说的,不用FS,直接写FLASH,写满了再擦,这种方法对FLASH寿命保护最好。
赞同这种做法。
离线
https://club.rt-thread.org/ask/question/9faea7447d375649.html
这个sqlite在spi和sd卡上没法用,慢到无法忍受.归根结底是文件系统速度太慢.我有在uffs和yaffs文件系统上测,文件系统速度是上去了。但是数据量增加到一定量数据库就报SQL error: database disk image is malformed。不知道什么鬼。
但是在SD卡文件系统上测试就不会
在rtt论坛搜到同样报错的帖子,我还是放弃单片机上跑sqlite吧,或者等artinchip来解决。
话说,artinchip的lunban-lite sdk里带的这个sqlite,也许是给d21x这类片子运行的吧。
最近编辑记录 Gentlepig (2024-06-27 16:57:15)
离线
莫名奇妙的例程能正常运行了。
dlk /data> create_student_tbl
/data/stu_info.dbdlk /data>
dlk /data> ls
Directory /data:
stu_info.db 12288
dlk /data> stu add 10
Insert 10 record(s): 1166ms, speed: 116ms/record
dlk /data> stu
test get all students
id:1 name:Student44408 score:40
id:2 name:Student44409 score:41
id:3 name:Student44411 score:43
id:4 name:Student44414 score:46
id:5 name:Student44418 score:50
id:6 name:Student44423 score:55
id:7 name:Student44429 score:61
id:8 name:Student44436 score:68
id:9 name:Student44444 score:76
id:10 name:Student44453 score:85
record(s):10
dlk /data> stu score 40 60
-------------------------------------
创建数据库,新增数据、删除、按分数范围查找,都能执行。
执行stu score时有个坑,按说stu score 40 60,就可以查找40-60分数的数据,结果本来是4个参数,有个可选的第5个参数,程序里只判断参数大于4个的情况下,也会去读取第5个参数,结果就卡住了。加个条件即可,参数大于5时才读第5个参数。
msh线程分配了10k空间,占用率85%。
-------------------------------------
上午发现stu add命令可以成功执行后,觉得之前尝试给msh分配的空间太大了,就由512k逐渐减下去,减到10k后sqlite例程的几个命令还可以使用,以为没事了。
下午切到win下,又试着重新编译sdk里的sqlite,结果又出现了上次的问题,create_student_tbl命令可以成功创建数据库,但是stu add命令就会失败,仍报错:
bind failed errmsg:database disk image is malformed
msh线程空间也改大了,无效。怀疑是spi速度的原因影响spi nor flash里的littlefs分区的读写,降低spi速度,无效。
又切回到ubuntu下,由于下午想尝试libmodbus,重新编译过。发现ubuntu下编译烧录后,stu add命令也是报错。
最近编辑记录 Gentlepig (2024-06-28 17:13:46)
离线
https://club.rt-thread.org/ask/question/9faea7447d375649.html
看这篇文章,发现需要打开SAL选项,估计是
enable bsd socket operated by file system api.
但是我搜目前的rtt组件,没搜到这个,目前打开的是:
│ │ [*] SAL: socket abstraction layer ---> │ │
│ │ -*- Enable network interface device --->
而且,和local package里的lwip寸在冲突。
现在不用local lwip时,sqlite功能正常了。
-----------------------------------------------
一次插入8000条数据,可以成功,插入9000条,就卡住了,重启后发现目录下多了个journel.db。
删掉数据库,创新创建,多次插入8000调数据,可以成功,但发现插入一条数据的时间比插入8000调数据的时间还长。
比如,插入一条数据要16秒,插入8000调要12秒。
多次插入后,就出错了,用stu score再也无法查询出某范围的条数。复制数据到到pc,用db brower查看,也看到数据内容。
此时文件系统没有被占满,分配了7M空间,数据库才700多k。
------------------------------
删掉数据库,重新创建,然后每次只插入一条数据,发现时间大概话非1秒,有点难受啊。
用stu命令可以看到列出数据,看数据库最大条数是8564, 再新增也是这个数字。那么,数据库最大容量是8564?但实际不是,用stu score m n,可列出score值巍在m和n范围内的数据条,可以看的id有超过8664的。
最近编辑记录 Gentlepig (2024-06-29 16:24:10)
离线
我在nand flash上试了下,插入一千条数据耗时80ms、插入一万条耗时500多ms。看来跑fs + sqlite还得是nand flash好点。
stu add 1000
Insert 1000 record(s): 83ms, speed: 0ms/record
stu add 10000
Insert 10000 record(s): 562ms, speed: 0ms/record
哦,我这是D21x,cpu主频高点
最近编辑记录 海石生风 (2024-07-24 14:30:26)
离线
@海石生风
你的d21x也是运行的rtt还是linux?
按说d13x和d21x主频相比差不算太大。d13x 480M, d21x 504/600M.
剩下的,内存大小差异?8M不够用?新做了一版,打算试试16M的。
我插入9000条数据就卡死,但是连续插入8k条数据可以成功。最后放弃了sqlite这一方案。
后来尝试了flashdb。
想问下,nand flash,是不是就不用考虑擦写均衡了?
我看flashdb的几个例程,都是spi nor flash和onchip flash的。
最近编辑记录 Gentlepig (2024-07-24 14:53:59)
离线
离线
在rtos上用这个,速度不够快,库300k,重。
我有项目在用,原因是大量应用代码是linux老代码。不想改。
各位大侠,是否有兼容接口的轻量级数据库?
或者,是否能将kv db模拟成sqlite接口?
至于说裸写flash,呵呵,最后你会发现你自己写了一个简单的文件管理系统。
离线
https://sqlite.readdevdocs.com/compile.html
读一下这个配置指导。
另外,去年在网上浏览时,发现rt适配的版本有点旧。
最后我找了一个idf适配的。
你可以不用它的组件,自己移植一个试试。
离线
flash写入寿命指的是对同一个位置的擦写,你只要计算好你的数据量,用足够大的空间去弥补擦写的次数,
离线