Arduino IDE 附带的 SD 库很方便,但缺少 exFAT、LFN(长文件名)和非英文字符支持等功能。本文介绍了一种替代 SD 卡驱动程序(基于 RT-Thread)来解决这些问题。
RT-Thread是一个免费的开源(Apache 许可证 2.0)RTOS,并以 Arduino 库的形式提供。还有另一篇文章 ( Multitasking on Arduino ) 可用于了解 RT-Thread 的基本概念。
让我们从通过 Arduino IDE 的库管理器安装库开始。(本文基于 RT-Thread 库版本 0.4.4 。)
(如果您对实现不感兴趣,只想知道如何使用它,请跳过本节。)
RT-Thread 库中的 SD 卡支持采用DFS(设备文件系统)的形式,它是 RT-Thread 架构的一部分。FAT 是 RT-Thread 支持的文件系统之一。(在 RT-Thread 库的 0.4.4 版本中,FAT 是唯一支持的文件系统。)
FAT DFS 本身就是基于ChaN 的 FatFs 项目的优秀作品。
标准的 RT-Thread DFS 提供以下文件系统和文件接口:
/* File system operations */
struct dfs_filesystem_ops
{
const char *name;
uint32_t flags; /* flags for file system operations */
/* operations for file */
const struct dfs_file_ops *fops;
/* mount and unmount file system */
int (*mount) (struct dfs_filesystem *fs, unsigned long rwflag, const void *data);
int (*unmount) (struct dfs_filesystem *fs);
/* make a file system */
int (*mkfs) (rt_device_t devid);
int (*statfs) (struct dfs_filesystem *fs, struct statfs *buf);
int (*unlink) (struct dfs_filesystem *fs, const char *pathname);
int (*stat) (struct dfs_filesystem *fs, const char *filename, struct stat *buf);
int (*rename) (struct dfs_filesystem *fs, const char *oldpath, const char *newpath);
};
/* File operations */
struct dfs_file_ops
{
int (*open) (struct dfs_fd *fd);
int (*close) (struct dfs_fd *fd);
int (*ioctl) (struct dfs_fd *fd, int cmd, void *args);
int (*read) (struct dfs_fd *fd, void *buf, size_t count);
int (*write) (struct dfs_fd *fd, const void *buf, size_t count);
int (*flush) (struct dfs_fd *fd);
int (*lseek) (struct dfs_fd *fd, off_t offset);
int (*getdents) (struct dfs_fd *fd, struct dirent *dirp, uint32_t count);
int (*poll) (struct dfs_fd *fd, struct rt_pollreq *req);
}
一个特定的 DFS 可能会实现它们的全部或部分。当挂载DFS时,例如dfs_mount("SD", "/", "elm", 0, 0)
,特定的DFS会绑定到一个设备上。在这种情况下,DFS "elm" (FatFs) 绑定到设备 "SD"。
标准的 RT-Thread 设备提供以下接口:
/* operations set for device object */
struct rt_device_ops
{
/* common device interface */
rt_err_t (*init) (rt_device_t dev);
rt_err_t (*open) (rt_device_t dev, rt_uint16_t oflag);
rt_err_t (*close) (rt_device_t dev);
rt_size_t (*read) (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
rt_size_t (*write) (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
rt_err_t (*control)(rt_device_t dev, int cmd, void *args);
};
一个特定的设备可以实现它们的全部或全部(将函数指针设置为 NULL)。
在库中,名为“SD”的设备实现了与SD卡访问相关的功能,在MKRZERO板的情况下,它涉及到一个名为“SPI1”的低级设备。而 SPI 设备最终涉及到了 Arduino SPI 库。
Arduino SD 库提供了一个名为“Datalogger”的示例。RT-Thread 库中也提供了相同的示例,如下面的代码部分所列。
不同之处在于,在下面的示例代码中,采样间隔为 1 秒,并且只执行 10 次。
您可能已经注意到上面的注释open()
功能。要打开现有文件并删除其所有内容,只需O_APPEND
用O_TRUNC
标志替换即可。
当使用 MKRZERO 板运行以下示例时,您可能会观察到串行监视器的以下输出:
\ | /
- RT - Thread Operating System
/ | \ 4.0.1 build Apr 17 2019
2006 - 2019 Copyright by rt-thread team
+ Mount SD to "/"
416,347,312
finsh />436,369,335
442,375,340
449,376,338
449,375,346
429,374,341
447,369,342
449,363,338
426,363,334
419,353,327
使用 RT-Thread 库的真正优势在于它使您能够使用 (FinSH) shell 命令来操作文件。
在串行监视器或其他串行终端工具中,输入ls()
命令将显示当前目录(在本例中为“/”)中的文件列表,如下所示。
ls()
Directory /:
DATALOG.TXT 240
HI_UTF8.TXT 35
A_REAL~1.TXT 22
0, 0x00000000
文件名后面的数字是以字节为单位的文件大小。在上面的屏幕截图中,“datalog.txt”的大小为 240 字节,因为我运行了该示例两次。
输入cat("datalog.txt")
命令会显示“datalog.txt”的内容,确认有20条记录。
finsh />cat("datalog.txt")
464,358,333
464,368,336
480,381,354
447,364,346
443,363,340
441,365,343
463,371,345
467,374,313
447,364,345
465,369,346
416,347,312
436,369,335
442,375,340
449,376,338
449,375,346
429,374,341
447,369,342
449,363,338
426,363,334
419,353,327
0, 0x00000000
还有copy()
和rm()
命令。
finsh />copy("datalog.txt", "copy.txt")
0, 0x00000000
finsh />ls()
Directory /:
COPY.TXT 240
DATALOG.TXT 240
HI_UTF8.TXT 35
A_REAL~1.TXT 22
0, 0x00000000
finsh />rm("copy.txt")
0, 0x00000000
finsh />ls()
Directory /:
DATALOG.TXT 240
HI_UTF8.TXT 35
A_REAL~1.TXT 22
0, 0x00000000
要列出所有可用命令,请输入list()
。
finsh />list()
--Function List:
hello -- say hello world
version -- show RT-Thread version information
list -- list available commands
list_mem -- list memory usage information
list_thread -- list thread
list_sem -- list semaphore in system
list_mutex -- list mutex in system
list_event -- list event in system
list_mb -- list mail box in system
list_mq -- list message queue in system
list_memp -- list memory pool in system
list_timer -- list timer in system
list_dev -- list device in system
mkfs -- make a file system
df -- get disk free
mkdir -- create a directory
cd -- change current working directory
ls -- list directory contents
rm -- remove files or directories
cat -- print file content
copy -- copy file or dir
list_sd -- show SD information
--Variable List:
dummy -- dummy variable for finsh
0, 0x00000000
默认情况下不启用 ExFAT、LFN(长文件名)和非英文字符支持(以使示例更小)。在“ rtconfig.h ”(位于 RT-Thread 库目录中)中打开以下配置以启用这些功能。
#define RT_DFS_ELM_USE_EXFAT
#define RT_DFS_ELM_USE_LFN (2)
#define RT_DFS_ELM_MAX_LFN (255)
#define RT_DFS_ELM_CODE_PAGE 936
RT_DFS_ELM_MAX_LFN表示文件名的最大长度,可以在 12 到 255 的范围内。
RT_DFS_ELM_CODE_PAGE默认设置为 437 用于美国,更改为 936 将启用简体中文支持,如下所示。
finsh />ls()
Directory /:
DATALOG.TXT 240
hi_utf8.txt 35
a_really_long_file_name.txt22
0, 0x00000000
finsh />cat("hi_utf8.txt")
Hello, world!
世界,你好! 0, 0x00000000
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
全部0条评论
快来发表一下你的评论吧 !