您尚未登录。

楼主 # 2024-06-25 09:08:18

Gentlepig
会员
注册时间: 2018-10-24
已发帖子: 1,280
积分: 1229.5

请教,单片机一般如何保存定时采集的数据,要求长期保存,方便查寻历史记录。

目前用d133定时采集can总线上的数据,然后在rgb屏幕上的lvgl界面上显示出来。

但是想保存采集到的数据,方便其他设备查询历史记录,或者在lvgl界面上查询历史记录。
请教,有什么好的办法?

问了几个群里,有推荐sqlite3和flashdb的。想知道,使用数据库有什么好处?

还有就是目前使用的spi nor flash,如果用fatfs,好想说并不适合频繁擦写。

目前有两种需求:
1, 采集can总线上定时发送过来的数据,每次保存,或几次采集后保存一次,可能保存频率很高;
2, 采集can总线上不定时发送过来的,一般是系统出现问题时才发送过来,保存频率较低。

最近编辑记录 Gentlepig (2024-06-25 09:23:01)

离线

#1 2024-06-25 09:28:03

晕哥
管理员
注册时间: 2017-09-06
已发帖子: 9,281
积分: 9197

Re: 请教,单片机一般如何保存定时采集的数据,要求长期保存,方便查寻历史记录。

建议用日志型(ext4,jffs2...)的文件系统,按时间段分文件存储。

如果没有后备电池和断电检测,做好最后一个文件阵亡的心理准备。





离线

楼主 #2 2024-06-25 09:32:40

Gentlepig
会员
注册时间: 2018-10-24
已发帖子: 1,280
积分: 1229.5

Re: 请教,单片机一般如何保存定时采集的数据,要求长期保存,方便查寻历史记录。

晕哥 说:

建议用日志型(ext4,jffs2...)的文件系统,按时间段分文件存储。

如果没有后备电池和断电检测,做好最后一个文件阵亡的心理准备。

我这不是linux系统啊,是rtt,目前看sdk里默认打开了fatfs和littlefs。

离线

#3 2024-06-25 09:57:25

晕哥
管理员
注册时间: 2017-09-06
已发帖子: 9,281
积分: 9197

Re: 请教,单片机一般如何保存定时采集的数据,要求长期保存,方便查寻历史记录。

Gentlepig 说:
晕哥 说:

建议用日志型(ext4,jffs2...)的文件系统,按时间段分文件存储。

如果没有后备电池和断电检测,做好最后一个文件阵亡的心理准备。

我这不是linux系统啊,是rtt,目前看sdk里默认打开了fatfs和littlefs。

那建议优先使用Littlefs文件系统,按时间段分文件存储。

LittleFS 是一种日志结构化的文件系统。它结合了日志结构(log-structured)文件系统和Copy-on-Write (COW)文件系统的特点。在日志结构的文件系统中,新的数据总是被写入到空闲或新分配的空间中,而不是直接覆盖旧的数据,这有助于减少对闪存介质的磨损并提供更好的掉电恢复能力。





离线

楼主 #4 2024-06-25 17:37:37

Gentlepig
会员
注册时间: 2018-10-24
已发帖子: 1,280
积分: 1229.5

Re: 请教,单片机一般如何保存定时采集的数据,要求长期保存,方便查寻历史记录。

手头的板子没焊接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数据库文件生成。

离线

#5 2024-06-25 17:53:34

wupaul2001
会员
注册时间: 2019-09-30
已发帖子: 264
积分: 242

Re: 请教,单片机一般如何保存定时采集的数据,要求长期保存,方便查寻历史记录。

@Gentlepig
长期保存建议512M的SLC

离线

#6 2024-06-25 20:33:12

海石生风
会员
所在地: 深圳
注册时间: 2019-07-02
已发帖子: 557
积分: 681
个人网站

Re: 请教,单片机一般如何保存定时采集的数据,要求长期保存,方便查寻历史记录。

@Gentlepig
写一大串没用的,难道你就没有怀疑是你输入的命令有问题?写了一大串也没有把重要细节show出来!

离线

#7 2024-06-26 01:42:54

Quotation
会员
注册时间: 2018-10-04
已发帖子: 293
积分: 261.5

Re: 请教,单片机一般如何保存定时采集的数据,要求长期保存,方便查寻历史记录。

不用FS,自己管理写入位置,能做到最少的Flash磨损。
Flash擦除后,分多次写入,一直往后写,不改前面的,写完一个块应该只算写了一次。(记得是这样)
如果断电,重新上电后扫描一遍Flash。要求写入的数据每个块一定不全为0xFF,这样就知道上次写到哪个位置了。

离线

#8 2024-06-26 08:46:45

staunchheart
会员
注册时间: 2019-12-17
已发帖子: 222
积分: 179

Re: 请教,单片机一般如何保存定时采集的数据,要求长期保存,方便查寻历史记录。

FLASH的写入次数有限制,而且像NorFlash写入速度极慢。
D133有网络,数据通过网络保存到服务器上是比较好的方案。
如果对数据的完整性要求高,设备端要加上铁电存储,未上传到服务器上的数据先保存到铁电里。
直接写FLASH可以考虑加个掉电保护,比如外部是12V供电,到单片机端变压成5V,单片机供电端加个较大的电容。
用一个比较电路,外部断电时电压低于内部,触发中断,依靠电容中的电将未保存的数据存到FLASH。

离线

楼主 #9 2024-06-26 09:26:13

Gentlepig
会员
注册时间: 2018-10-24
已发帖子: 1,280
积分: 1229.5

Re: 请教,单片机一般如何保存定时采集的数据,要求长期保存,方便查寻历史记录。

海石生风 说:

@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

离线

楼主 #10 2024-06-26 14:46:12

Gentlepig
会员
注册时间: 2018-10-24
已发帖子: 1,280
积分: 1229.5

Re: 请教,单片机一般如何保存定时采集的数据,要求长期保存,方便查寻历史记录。

还是得看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)

离线

#11 2024-06-26 15:34:39

Leotian
会员
所在地: 河南
注册时间: 2020-03-27
已发帖子: 39
积分: 136

Re: 请教,单片机一般如何保存定时采集的数据,要求长期保存,方便查寻历史记录。

个人比较推荐2个方向:
1.上传数据至本地内存卡,可以以TXT形式by天/周保存成单个txt;之前做过类似功能,效果还不错;
2.借助物联网平台或者自己搭物联网平台,可以增加一个5块钱的ESP8266模块,将你的数据推上阿里云,优点是可远程查询数据。

离线

#12 2024-06-26 15:41:10

Leotian
会员
所在地: 河南
注册时间: 2020-03-27
已发帖子: 39
积分: 136

Re: 请教,单片机一般如何保存定时采集的数据,要求长期保存,方便查寻历史记录。

@Gentlepig
目前大企业都是自己搭云平台实现,小公司用公共云平台,更建议你数据上云。

离线

楼主 #13 2024-06-26 16:08:05

Gentlepig
会员
注册时间: 2018-10-24
已发帖子: 1,280
积分: 1229.5

Re: 请教,单片机一般如何保存定时采集的数据,要求长期保存,方便查寻历史记录。

感谢各位,板子是有网口的,目前是通过tcp将数据发送给局域网pc。

本机存储是想以后可能会用到,某些不定时的,数量较少的数据,希望存储到板子上。

离线

#14 2024-06-26 17:14:53

kin
会员
注册时间: 2020-04-06
已发帖子: 29
积分: 73.5

Re: 请教,单片机一般如何保存定时采集的数据,要求长期保存,方便查寻历史记录。

正如7楼所说的,不用FS,直接写FLASH,写满了再擦,这种方法对FLASH寿命保护最好。

离线

#15 2024-06-26 18:10:19

lcfmax
会员
注册时间: 2018-04-13
已发帖子: 321
积分: 274.5

Re: 请教,单片机一般如何保存定时采集的数据,要求长期保存,方便查寻历史记录。

kin 说:

正如7楼所说的,不用FS,直接写FLASH,写满了再擦,这种方法对FLASH寿命保护最好。

赞同这种做法。

离线

楼主 #16 2024-06-27 16:55:44

Gentlepig
会员
注册时间: 2018-10-24
已发帖子: 1,280
积分: 1229.5

Re: 请教,单片机一般如何保存定时采集的数据,要求长期保存,方便查寻历史记录。

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)

离线

#17 2024-06-27 21:20:27

LinjieGuo
Moderator
注册时间: 2019-07-24
已发帖子: 575
积分: 580
个人网站

Re: 请教,单片机一般如何保存定时采集的数据,要求长期保存,方便查寻历史记录。

rtt有个现成的循环工具,ulog,
ulog+littlefs。
能满足你。

离线

楼主 #18 2024-06-28 10:27:57

Gentlepig
会员
注册时间: 2018-10-24
已发帖子: 1,280
积分: 1229.5

Re: 请教,单片机一般如何保存定时采集的数据,要求长期保存,方便查寻历史记录。

莫名奇妙的例程能正常运行了。

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)

离线

楼主 #19 2024-06-29 11:47:11

Gentlepig
会员
注册时间: 2018-10-24
已发帖子: 1,280
积分: 1229.5

Re: 请教,单片机一般如何保存定时采集的数据,要求长期保存,方便查寻历史记录。

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)

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn