本文基于优信电子售卖的stm32f407vet6最小系统开发板使用vscode进行开发

开发过程中阅读了STM32CubeMX教程28 SDIO - 使用FatFs文件系统读写SD卡_stm32cubemx fatfs-CSDN博客
这位大佬的教程,写的十分详细,但是目前来看有一些版本更新之后的区别,因此在这里简单记录一下,防止自己之后再重新走一遍
初始化过程略过
时钟树配置
初始状态如下(芯片刚点进去就是这样)

分别在主页面开启
外部时钟:system core->RCC->HSC LSE->Crystal/Ceramic Resonator.(我的板子是8Mhz,之后在时钟树还得改)
开启sdio功能:connectivity->SDIO->mode->SD4bits wide bus(然后剩下的就都不用改了,我看之前的大佬说他版本的cubemx在设置四总线之后还得在代码里改一下,但在现在版本6.15.0cubemx里就不用了)
在上述步骤结束之后的时钟树配置应该是这样的,着重关注一下画圈的三个地方,在这仨地方都配置正确之后直接点击HCLK(就是下面标着最大频率的地方)在里面直接输入168敲一下回车整个时钟树就配置好了。系统会自动配置sdio的48Mhz的。
接下来配置fatfs文件库,下面图片的三个红圈,选上了就啥也不用管了,platform报错是因为没有设置sd卡检测引脚,我这个板子上也没有这个就放那不用管,之后出来的报错继yes就完事了。(如果板子上有相应硬件的情况下,需要在右边找对应引脚设置为input,然后在platform settings里面选择该引脚即可避免报错)(没有别瞎写啊)

选上这些之后生成的文件会多出来如下内容,如果只是使用的话绝大多数不用管,只需要点开其中ff.h文件,向下拉找到主函数要用的函数声明(我选的.c.h文件分离)

绝大多数都用不上,下面简单记录其中几句的使用方式
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
FRESULT f_close (FIL* fp); /* Close an open file object */
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */
FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */
FRESULT f_truncate (FIL* fp); /* Truncate the file */
FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
FRESULT f_closedir (DIR* dp); /* Close an open directory */
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */
FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */
FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */
FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
例子
在sd卡中创建一个名为test.txt的文件,向其中写入hello sd
MX_GPIO_Init();
MX_DMA_Init();
MX_SDIO_SD_Init();
MX_USART1_UART_Init();
MX_FATFS_Init();
/* USER CODE BEGIN 2 */
UART1_Init();
////////////////////////////////////////////////////////
//主要是这段
if (f_mount(&SDFatFS, SDPath, 1) == FR_OK)
{
f_open(&SDFile, "test.txt", FA_CREATE_ALWAYS | FA_WRITE);
f_puts("hello sd\r\n", &SDFile);
f_close(&SDFile);
UART1_SendString("SD card initialized and test.txt created.\r\n");
}
/////////////////////////////////////////////////////////
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
}

&后面跟着的所有变量都被定义在app里,使用者需要的只是按照位置填进函参里,不用自己去读写,每次写完了记得写个f_close,要不然容易写不进去,或者用f_sync(&SDFile);函数
想要连续写入得用f_lseek(&f, f_size(&f));,让指针往前推
模版如下
FIL f;
UINT bw;
f_open(&f, "log.txt", FA_OPEN_ALWAYS | FA_WRITE);
f_lseek(&f, f_size(&f));
f_write(&f, "hello\r\n", 7, &bw);
f_sync(&f);
f_close(&f);
同时操作两个文件的模版如下
FIL logFile;
FIL cfgFile;
UINT br, bw;
/* 打开日志文件(写) */
f_open(&logFile, "log.txt", FA_OPEN_ALWAYS | FA_WRITE);
f_lseek(&logFile, f_size(&logFile));
/* 同时打开配置文件(读) */
f_open(&cfgFile, "config.txt", FA_READ);
/* 写日志 */
f_write(&logFile, "tick\r\n", 6, &bw);
/* 读配置 */
char buf[32];
f_read(&cfgFile, buf, sizeof(buf), &br);
f_close(&cfgFile);
f_close(&logFile);
总结:cubemx是真的好用,sd卡的读写在使用内置的sdio协议后几乎不用人为配置什么,只有当自己需要同时操作复数个文件时才需要在fatfs.c文件中定义一个文件操作体
接下来尝试写一下方便操作的api库
1188

被折叠的 条评论
为什么被折叠?



