硬汉嵌入式论坛

 找回密码
 立即注册
查看: 226|回复: 2
收起左侧

[USB] 测试STM32H7的USB挂载64GB容量闪迪卡,浏览二级文件夹目录问题

[复制链接]

1万

主题

7万

回帖

12万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
122743
QQ
发表于 2026-5-17 15:59:41 | 显示全部楼层 |阅读模式


问题

客户反馈在原始例子基础上,自己增加了个二级目录的访问问题,即Dir下创建的子目录无法访问

测试
1、使用例子

V7-026_FatFS文件系统例子(外挂U盘)

2、使用JD上买的闪迪卡

12.png

3、测试

2.png

4、将命令1修改为如下浏览函数

[C] 纯文本查看 复制代码
/*
*********************************************************************************************************
*
*        模块名称 : SD卡Fat文件系统演示模块。
*        文件名称 : demo_sd_fatusbfs.c
*        版    本 : V1.0
*        说    明 : 该例程移植FatFS文件系统(版本 R0.12c),演示如何创建文件、读取文件、创建目录和删除文件
*                           并测试了文件读写速度.支持以下6个功能,用户通过电脑端串口软件发送数字给开发板即可:
*              1 - 显示根目录下的文件列表
*              2 - 创建一个新文件armfly.txt
*              3 - 读armfly.txt文件的内容
*              4 - 创建目录
*              5 - 删除文件和目录
*              6 - 读写文件速度测试
*
*        修改记录 :
*                版本号   日期         作者        说明
*                V1.0    2018-12-12   Eric2013    正式发布
*
*        Copyright (C), 2018-2030, 安富莱电子 [url=http://www.armfly.com]www.armfly.com[/url]
*
*********************************************************************************************************
*/
#include "bsp.h"
#include "ff.h"                                /* FatFS文件系统模块*/
#include "ff_gen_drv.h"
#include "usbh_usr.h"


/* 用于测试读写速度 */
#define TEST_FILE_LEN                        (2*1024*1024)        /* 用于测试的文件长度 */
#define BUF_SIZE                                (4*1024)                /* 每次读写SD卡的最大数据长度 */

/* 仅允许本文件内调用的函数声明 */
static void DispMenu(void);
static void ViewRootDir(void);
static void CreateNewFile(void);
static void ReadFileData(void);
static void CreateDir(void);
static void DeleteDirFile(void);
static void WriteFileTest(void);

/*
    1、V7开发板的SD卡接口是用的SDMMC1,而这个接口仅支持AXI SRAM区访问,其它SRAM和TCP均不支持。
    2、AXI SRAM的主频是200MHz,需要Cache配合提速,所以此例子主RAM直接使用性能最高的DTCM。仅DMA
       操作SDIO的地方使用AXI SRAM,下面这几个变量是都需要使用AXI SRAM空间的。
    3、详情在此贴进行了说明:[url=http://forum.armfly.com/forum.php?mod=viewthread&tid=91531]http://forum.armfly.com/forum.php?mod=viewthread&tid=91531[/url]
*/
FIL file;
char FsReadBuf[1024];
char FsWriteBuf[1024] = {"FatFS Write Demo \r\n [url=http://www.armfly.com]www.armfly.com[/url] \r\n"};
uint8_t g_TestBuf[BUF_SIZE];
DIR DirInf;
FILINFO FileInf;

extern FATFS usbfs;
extern char USBDISKPath[4];  /* USB逻辑驱动路径,比盘符0,就是"0:/" */

/* FatFs API的返回值 */
static const char * FR_Table[]= 
{
        "FR_OK:成功",                                                             /* (0) Succeeded */
        "FR_DISK_ERR:底层硬件错误",                                         /* (1) A hard error occurred in the low level disk I/O layer */
        "FR_INT_ERR:断言失败",                                                     /* (2) Assertion failed */
        "FR_NOT_READY:物理驱动没有工作",                                     /* (3) The physical drive cannot work */
        "FR_NO_FILE:文件不存在",                                                 /* (4) Could not find the file */
        "FR_NO_PATH:路径不存在",                                                 /* (5) Could not find the path */
        "FR_INVALID_NAME:无效文件名",                                     /* (6) The path name format is invalid */
        "FR_DENIED:由于禁止访问或者目录已满访问被拒绝",         /* (7) Access denied due to prohibited access or directory full */
        "FR_EXIST:文件已经存在",                                             /* (8) Access denied due to prohibited access */
        "FR_INVALID_OBJECT:文件或者目录对象无效",                         /* (9) The file/directory object is invalid */
        "FR_WRITE_PROTECTED:物理驱动被写保护",                             /* (10) The physical drive is write protected */
        "FR_INVALID_DRIVE:逻辑驱动号无效",                                 /* (11) The logical drive number is invalid */
        "FR_NOT_ENABLED:卷中无工作区",                                         /* (12) The volume has no work area */
        "FR_NO_FILESYSTEM:没有有效的FAT卷",                             /* (13) There is no valid FAT volume */
        "FR_MKFS_ABORTED:由于参数错误f_mkusbfs()被终止",                 /* (14) The f_mkusbfs() aborted due to any parameter error */
        "FR_TIMEOUT:在规定的时间内无法获得访问卷的许可",                 /* (15) Could not get a grant to access the volume within defined period */
        "FR_LOCKED:由于文件共享策略操作被拒绝",                                 /* (16) The operation is rejected according to the file sharing policy */
        "FR_NOT_ENOUGH_CORE:无法分配长文件名工作区",                     /* (17) LFN working buffer could not be allocated */
        "FR_TOO_MANY_OPEN_FILES:当前打开的文件数大于_FS_SHARE", /* (18) Number of open files > _FS_SHARE */
        "FR_INVALID_PARAMETER:参数无效"                             /* (19) Given parameter is invalid */
};

/*
*********************************************************************************************************
*        函 数 名: DemoFatFS
*        功能说明: FatFS文件系统演示主程序
*        形    参: 无
*        返 回 值: 无
*********************************************************************************************************
*/
void DemoFatFS(void)
{
        uint8_t cmd;
        
        DispMenu();        /* 打印命令列表,用户可以通过串口操作指令 */
        
        usbh_OpenMassStorage();        /* 打开USB HOST, 支持U盘 */

        bsp_StartAutoTimer(0, 500);        /* 启动1个500ms的自动重装的定时器 */
        
        while (1)
        {
                usbh_Poll();                /* 支持U盘 */
                
                /* 判断定时器超时时间 */
                if (bsp_CheckTimer(0))        
                {            
                        /* 每隔500ms 进来一次 */  
                        bsp_LedToggle(2);
                }

                if (comGetChar(COM1, &cmd))        /* 从串口读入一个字符(非阻塞方式) */
                {
                        printf("\r\n");
                        switch (cmd)
                        {
                                case '1':
                                        printf("【1 - ViewRootDir】\r\n");
                                        ViewRootDir();                /* 显示SD卡根目录下的文件名 */
                                        break;

                                case '2':
                                        printf("【2 - CreateNewFile】\r\n");
                                        CreateNewFile();        /* 创建一个新文件,写入一个字符串 */
                                        break;

                                case '3':
                                        printf("【3 - ReadFileData】\r\n");
                                        ReadFileData();                /* 读取根目录下armfly.txt的内容 */
                                        break;

                                case '4':
                                        printf("【4 - CreateDir】\r\n");
                                        CreateDir();                /* 创建目录 */
                                        break;

                                case '5':
                                        printf("【5 - DeleteDirFile】\r\n");
                                        DeleteDirFile();        /* 删除目录和文件 */
                                        break;

                                case '6':
                                        printf("【6 - TestSpeed】\r\n");
                                        WriteFileTest();        /* 速度测试 */
                                        break;
                                
                                default:
                                        DispMenu();
                                        break;
                        }
                }
        }
}

/*
*********************************************************************************************************
*        函 数 名: DispMenu
*        功能说明: 显示操作提示菜单
*        形    参:无
*        返 回 值: 无
*********************************************************************************************************
*/
static void DispMenu(void)
{
        printf("\r\n------------------------------------------------\r\n");
        printf("请选择操作命令:\r\n");
        printf("1 - 显示根目录下的文件列表\r\n");
        printf("2 - 创建一个新文件armfly.txt\r\n");
        printf("3 - 读armfly.txt文件的内容\r\n");
        printf("4 - 创建目录\r\n");
        printf("5 - 删除文件和目录\r\n");
        printf("6 - 读写文件速度测试\r\n");
}

/*
*********************************************************************************************************
*        函 数 名: ViewRootDir
*        功能说明: 显示SD卡根目录下的文件名
*        形    参:无
*        返 回 值: 无
*********************************************************************************************************
*/
static void ViewRootDir(void)
{
    FRESULT result;
    uint32_t cnt = 0;
    FILINFO fno;
    DIR sub_dir;              /* 子目录句柄 */
    FILINFO sub_fno;          /* 子目录内容 */
    
    /* 挂载文件系统 */
    result = f_mount(&usbfs, USBDISKPath, 0);
    if (result != FR_OK)
    {
        printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);
        return;                /* 漏了 return */
    }

    /* 打开根文件夹 */
    result = f_opendir(&DirInf, USBDISKPath);
    if (result != FR_OK)
    {
        printf("打开根目录失败  (%s)\r\n", FR_Table[result]);
        return;
    }

    printf("属性        |  文件大小 | 短文件名 | 长文件名\r\n");
    for (cnt = 0; ;cnt++)
    {
        result = f_readdir(&DirInf, &FileInf);
        if (result != FR_OK || FileInf.fname[0] == 0)
        {
            break;
        }

        if (FileInf.fname[0] == '.')
        {
            continue;
        }

        /* ====== 打印根目录当前项 ====== */
        if (FileInf.fattrib & AM_DIR)
        {
            printf("(0x%02d)目录  ", FileInf.fattrib);
        }
        else
        {
            printf("(0x%02d)文件  ", FileInf.fattrib);
        }

        f_stat(FileInf.fname, &fno);
        printf(" %10d", (int)fno.fsize);
        printf("  %s\r\n", (char *)FileInf.fname);

        /* ====== 如果是目录,打印它下面第一级内容 ====== */
        if (FileInf.fattrib & AM_DIR)
        {
            result = f_opendir(&sub_dir, FileInf.fname);
            if (result == FR_OK)
            {
                printf("  └─ %s 下的内容:\r\n", FileInf.fname);
                
                while (1)
                {
                    result = f_readdir(&sub_dir, &sub_fno);
                    if (result != FR_OK || sub_fno.fname[0] == 0)
                    {
                        break;
                    }
                    if (sub_fno.fname[0] == '.')
                    {
                        continue;
                    }

                    if (sub_fno.fattrib & AM_DIR)
                    {
                        printf("       [子目录] %s\r\n", sub_fno.fname);
                    }
                    else
                    {
                        f_stat(sub_fno.fname, &fno);
                        printf("        文件 %10d  %s\r\n", (int)fno.fsize, sub_fno.fname);
                    }
                }
                
                f_closedir(&sub_dir);
                printf("\r\n");
            }
        }
    }

    /* 卸载文件系统 */
    f_mount(NULL, USBDISKPath, 0);
}


/*
*********************************************************************************************************
*        函 数 名: CreateNewFile
*        功能说明: 在SD卡创建一个新文件,文件内容填写“[url=http://www.armfly.com]www.armfly.com[/url]”
*        形    参:无
*        返 回 值: 无
*********************************************************************************************************
*/
static void CreateNewFile(void)
{
        FRESULT result;
        uint32_t bw;
        char path[32];


         /* 挂载文件系统 */
        result = f_mount(&usbfs, USBDISKPath, 0);                        /* Mount a logical drive */
        if (result != FR_OK)
        {
                printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);
        }

        /* 打开文件 */
        sprintf(path, "%sarmfly.txt", USBDISKPath);
        result = f_open(&file, path, FA_CREATE_ALWAYS | FA_WRITE);
        if (result == FR_OK)
        {
                printf("armfly.txt 文件打开成功\r\n");
        }
        else
        {
                printf("armfly.txt 文件打开失败  (%s)\r\n", FR_Table[result]);
        }

        /* 写一串数据 */
        result = f_write(&file, FsWriteBuf, strlen(FsWriteBuf), &bw);
        if (result == FR_OK)
        {
                printf("armfly.txt 文件写入成功\r\n");
        }
        else
        {
                printf("armfly.txt 文件写入失败  (%s)\r\n", FR_Table[result]);
        }

        /* 关闭文件*/
        f_close(&file);

        /* 卸载文件系统 */
        f_mount(NULL, USBDISKPath, 0);
}

/*
*********************************************************************************************************
*        函 数 名: ReadFileData
*        功能说明: 读取文件armfly.txt前128个字符,并打印到串口
*        形    参:无
*        返 回 值: 无
*********************************************************************************************************
*/
static void ReadFileData(void)
{
        FRESULT result;
        uint32_t bw;
        char path[64];

        
         /* 挂载文件系统 */
        result = f_mount(&usbfs, USBDISKPath, 0);                        /* Mount a logical drive */
        if (result != FR_OK)
        {
                printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);
        }

        /* 打开文件 */
        sprintf(path, "%sarmfly.txt", USBDISKPath);
        result = f_open(&file, path, FA_OPEN_EXISTING | FA_READ);
        if (result !=  FR_OK)
        {
                printf("Don't Find File : armfly.txt\r\n");
                return;
        }

        /* 读取文件 */
        result = f_read(&file, FsReadBuf, sizeof(FsReadBuf), &bw);
        if (bw > 0)
        {
                FsReadBuf[bw] = 0;
                printf("\r\narmfly.txt 文件内容 : \r\n%s\r\n", FsReadBuf);
        }
        else
        {
                printf("\r\narmfly.txt 文件内容 : \r\n");
        }

        /* 关闭文件*/
        f_close(&file);

        /* 卸载文件系统 */
        f_mount(NULL, USBDISKPath, 0);
}

/*
*********************************************************************************************************
*        函 数 名: CreateDir
*        功能说明: 在SD卡根目录创建Dir1和Dir2目录,在Dir1目录下创建子目录Dir1_1
*        形    参:无
*        返 回 值: 无
*********************************************************************************************************
*/
static void CreateDir(void)
{
        FRESULT result;
        char path[64]; 

        
         /* 挂载文件系统 */
        result = f_mount(&usbfs, USBDISKPath, 0);                        /* Mount a logical drive */
        if (result != FR_OK)
        {
                printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);
        }

        /* 创建目录/Dir1 */
        sprintf(path, "%sDir1", USBDISKPath);
        result = f_mkdir(path);
        if (result == FR_OK)
        {
                printf("f_mkdir Dir1 Ok\r\n");
        }
        else if (result == FR_EXIST)
        {
                printf("Dir1 目录已经存在(%d)\r\n", result);
        }
        else
        {
                printf("f_mkdir Dir1 失败 (%s)\r\n", FR_Table[result]);
                return;
        }

        /* 创建目录/Dir2 */
        sprintf(path, "%sDir2", USBDISKPath);
        result = f_mkdir(path);
        if (result == FR_OK)
        {
                printf("f_mkdir Dir2 Ok\r\n");
        }
        else if (result == FR_EXIST)
        {
                printf("Dir2 目录已经存在(%d)\r\n", result);
        }
        else
        {
                printf("f_mkdir Dir2 失败 (%s)\r\n", FR_Table[result]);
                return;
        }

        /* 创建子目录 /Dir1/Dir1_1           注意:创建子目录Dir1_1时,必须先创建好Dir1 */
        sprintf(path, "%sDir1/Dir1_1", USBDISKPath);
        result = f_mkdir(path); /* */
        if (result == FR_OK)
        {
                printf("f_mkdir Dir1_1 成功\r\n");
        }
        else if (result == FR_EXIST)
        {
                printf("Dir1_1 目录已经存在 (%d)\r\n", result);
        }
        else
        {
                printf("f_mkdir Dir1_1 失败 (%s)\r\n", FR_Table[result]);
                return;
        }

        /* 卸载文件系统 */
        f_mount(NULL, USBDISKPath, 0);
}

/*
*********************************************************************************************************
*        函 数 名: DeleteDirFile
*        功能说明: 删除SD卡根目录下的 armfly.txt 文件和 Dir1,Dir2 目录
*        形    参:无
*        返 回 值: 无
*********************************************************************************************************
*/
static void DeleteDirFile(void)
{
        FRESULT result;
        uint8_t i;
        char path[64]; 
        
         /* 挂载文件系统 */
        result = f_mount(&usbfs, USBDISKPath, 0);                        /* Mount a logical drive */
        if (result != FR_OK)
        {
                printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);
        }
        
        /* 删除目录/Dir1 【因为还存在目录非空(存在子目录),所以这次删除会失败】*/
        sprintf(path, "%sDir1", USBDISKPath);
        result = f_unlink(path);
        if (result == FR_OK)
        {
                printf("删除目录Dir1成功\r\n");
        }
        else if (result == FR_NO_FILE)
        {
                printf("没有发现文件或目录 :%s\r\n", "/Dir1");
        }
        else
        {
                printf("删除Dir1失败(错误代码 = %d) 文件只读或目录非空\r\n", result);
        }

        /* 先删除目录/Dir1/Dir1_1 */
        sprintf(path, "%sDir1/Dir1_1", USBDISKPath);
        result = f_unlink(path);
        if (result == FR_OK)
        {
                printf("删除子目录/Dir1/Dir1_1成功\r\n");
        }
        else if ((result == FR_NO_FILE) || (result == FR_NO_PATH))
        {
                printf("没有发现文件或目录 :%s\r\n", "/Dir1/Dir1_1");
        }
        else
        {
                printf("删除子目录/Dir1/Dir1_1失败(错误代码 = %d) 文件只读或目录非空\r\n", result);
        }

        /* 先删除目录/Dir1 */
        sprintf(path, "%sDir1", USBDISKPath);
        result = f_unlink(path);
        if (result == FR_OK)
        {
                printf("删除目录Dir1成功\r\n");
        }
        else if (result == FR_NO_FILE)
        {
                printf("没有发现文件或目录 :%s\r\n", "/Dir1");
        }
        else
        {
                printf("删除Dir1失败(错误代码 = %d) 文件只读或目录非空\r\n", result);
        }

        /* 删除目录/Dir2 */
        sprintf(path, "%sDir2", USBDISKPath);
        result = f_unlink(path);
        if (result == FR_OK)
        {
                printf("删除目录 Dir2 成功\r\n");
        }
        else if (result == FR_NO_FILE)
        {
                printf("没有发现文件或目录 :%s\r\n", "/Dir2");
        }
        else
        {
                printf("删除Dir2 失败(错误代码 = %d) 文件只读或目录非空\r\n", result);
        }

        /* 删除文件 armfly.txt */
        sprintf(path, "%sarmfly.txt", USBDISKPath);
        result = f_unlink(path);
        if (result == FR_OK)
        {
                printf("删除文件 armfly.txt 成功\r\n");
        }
        else if (result == FR_NO_FILE)
        {
                printf("没有发现文件或目录 :%s\r\n", "armfly.txt");
        }
        else
        {
                printf("删除armfly.txt失败(错误代码 = %d) 文件只读或目录非空\r\n", result);
        }

        /* 删除文件 speed1.txt */
        for (i = 0; i < 20; i++)
        {
                sprintf(path, "%sSpeed%02d.txt", USBDISKPath, i);/* 每写1次,序号递增 */        
                result = f_unlink(path);
                if (result == FR_OK)
                {
                        printf("删除文件%s成功\r\n", path);
                }
                else if (result == FR_NO_FILE)
                {
                        printf("没有发现文件:%s\r\n", path);
                }
                else
                {
                        printf("删除%s文件失败(错误代码 = %d) 文件只读或目录非空\r\n", path, result);
                }
        }

        /* 卸载文件系统 */
        f_mount(NULL, USBDISKPath, 0);
}

/*
*********************************************************************************************************
*        函 数 名: WriteFileTest
*        功能说明: 测试文件读写速度
*        形    参:无
*        返 回 值: 无
*********************************************************************************************************
*/
static void WriteFileTest(void)
{
        FRESULT result;
        char path[64]; 
        uint32_t bw;
        uint32_t i,k;
        uint32_t runtime1,runtime2,timelen;
        uint8_t err = 0;
        static uint8_t s_ucTestSn = 0;

        
        for (i = 0; i < sizeof(g_TestBuf); i++)
        {
                g_TestBuf[i] = (i / 512) + '0';
        }

          /* 挂载文件系统 */
        result = f_mount(&usbfs, USBDISKPath, 0);                        /* Mount a logical drive */
        if (result != FR_OK)
        {
                printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);
        }

        /* 打开文件 */
        sprintf(path, "%sSpeed%02d.txt", USBDISKPath, s_ucTestSn++); /* 每写1次,序号递增 */        
        result = f_open(&file, path, FA_CREATE_ALWAYS | FA_WRITE);

        /* 写一串数据 */
        printf("开始写文件%s %dKB ...\r\n", path, TEST_FILE_LEN / 1024);
        
        runtime1 = bsp_GetRunTime();        /* 读取系统运行时间 */
        for (i = 0; i < TEST_FILE_LEN / BUF_SIZE; i++)
        {
                result = f_write(&file, g_TestBuf, sizeof(g_TestBuf), &bw);
                if (result == FR_OK)
                {
                        if (((i + 1) % 8) == 0)
                        {
                                printf(".");
                        }
                }
                else
                {
                        err = 1;
                        printf("%s文件写失败\r\n", path);
                        break;
                }
        }
        runtime2 = bsp_GetRunTime();        /* 读取系统运行时间 */
        
        if (err == 0)
        {
                timelen = (runtime2 - runtime1);
                printf("\r\n  写耗时 : %dms   平均写速度 : %dB/S (%dKB/S)\r\n",
                        timelen,
                        (TEST_FILE_LEN * 1000) / timelen,
                        ((TEST_FILE_LEN / 1024) * 1000) / timelen);
        }

        f_close(&file);                /* 关闭文件*/


        /* 开始读文件测试 */
        result = f_open(&file, path, FA_OPEN_EXISTING | FA_READ);
        if (result !=  FR_OK)
        {
                printf("没有找到文件: %s\r\n", path);
                return;
        }

        printf("开始读文件 %dKB ...\r\n", TEST_FILE_LEN / 1024);
        
        runtime1 = bsp_GetRunTime();        /* 读取系统运行时间 */
        for (i = 0; i < TEST_FILE_LEN / BUF_SIZE; i++)
        {
                result = f_read(&file, g_TestBuf, sizeof(g_TestBuf), &bw);
                if (result == FR_OK)
                {
                        if (((i + 1) % 8) == 0)
                        {
                                printf(".");
                        }

                        /* 比较写入的数据是否正确,此语句会导致读卡速度结果降低到 3.5MBytes/S */
                        for (k = 0; k < sizeof(g_TestBuf); k++)
                        {
                                if (g_TestBuf[k] != (k / 512) + '0')
                                {
                                          err = 1;
                                        printf("Speed1.txt 文件读成功,但是数据出错\r\n");
                                        break;
                                }
                        }
                        if (err == 1)
                        {
                                break;
                        }
                }
                else
                {
                        err = 1;
                        printf("Speed1.txt 文件读失败\r\n");
                        break;
                }
        }

        runtime2 = bsp_GetRunTime();        /* 读取系统运行时间 */
        
        if (err == 0)
        {
                timelen = (runtime2 - runtime1);
                printf("\r\n  读耗时 : %dms   平均读速度 : %dB/S (%dKB/S)\r\n", timelen,
                        (TEST_FILE_LEN * 1000) / timelen, ((TEST_FILE_LEN / 1024) * 1000) / timelen);
        }

        /* 关闭文件*/
        f_close(&file);

        /* 卸载文件系统 */
        f_mount(NULL, USBDISKPath, 0);
}

/***************************** 安富莱电子 [url=http://www.armfly.com]www.armfly.com[/url] (END OF FILE) *********************************/



回复

使用道具 举报

1万

主题

7万

回帖

12万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
122743
QQ
 楼主| 发表于 2026-5-17 16:49:37 | 显示全部楼层
客户要要求再来一级

下载.png

[C] 纯文本查看 复制代码
static void PrintDirTree(const char *path, uint8_t level, uint8_t *prefix_mask)
{
    FRESULT res;
    DIR dir;
    FILINFO fno;
    char fullpath[256];
    uint32_t item_cnt = 0, item_idx = 0;

    if (level >= 4) return;

    /* 先统计目录项数量 */
    res = f_opendir(&dir, path);
    if (res != FR_OK) return;
    while (1) {
        res = f_readdir(&dir, &fno);
        if (res != FR_OK || fno.fname[0] == 0) break;
        if (fno.fname[0] == '.') continue;
        item_cnt++;
    }
    f_closedir(&dir);

    if (item_cnt == 0) return;

    /* 正式开始遍历 */
    res = f_opendir(&dir, path);
    if (res != FR_OK) return;

    while (1) {
        res = f_readdir(&dir, &fno);
        if (res != FR_OK || fno.fname[0] == 0) break;
        if (fno.fname[0] == '.') continue;

        item_idx++;
        uint8_t is_last = (item_idx == item_cnt);
        uint8_t is_dir  = (fno.fattrib & AM_DIR) ? 1 : 0;

        /* 打印缩进前缀 */
        for (uint8_t i = 0; i < level; i++) {
            printf(prefix_mask[i] ? "|   " : "    ");
        }

        /* 连接线 */
        printf(is_last ? "\\-- " : "+-- ");

        /* 打印条目 */
        if (is_dir) {
            printf("[DIR]  %s\r\n", fno.fname);
        } else {
            FILINFO st;
            f_stat(fno.fname, &st);
            if (st.fsize < 1024) {
                printf("[FILE] %s (%lu B)\r\n", fno.fname, st.fsize);
            } else if (st.fsize < 1024 * 1024) {
                printf("[FILE] %s (%.1f KB)\r\n", fno.fname, st.fsize / 1024.0);
            } else {
                printf("[FILE] %s (%.2f MB)\r\n", fno.fname, st.fsize / (1024.0 * 1024));
            }
        }

        /* 递归子目录 */
        if (is_dir) {
            prefix_mask[level] = !is_last;
            if (path[0] != '\0') {
                sprintf(fullpath, "%s/%s", path, fno.fname);
            } else {
                strcpy(fullpath, fno.fname);
            }
            PrintDirTree(fullpath, level + 1, prefix_mask);
        }
    }

    f_closedir(&dir);
}


static void ViewRootDir(void)
{
    FRESULT result;
    uint8_t prefix_mask[4] = {0};

    result = f_mount(&usbfs, USBDISKPath, 0);
    if (result != FR_OK) {
        printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);
        return;
    }

    printf("===== U盘文件目录树 (最多4层) =====\r\n");
    PrintDirTree(USBDISKPath, 0, prefix_mask);
    printf("\r\n");

    f_mount(NULL, USBDISKPath, 0);
}


234.png
回复

使用道具 举报

734

主题

3877

回帖

6104

积分

论坛元老

自定义头衔

积分
6104
发表于 12 小时前 | 显示全部楼层
eric2013 发表于 2026-5-17 16:49
客户要要求再来一级

这牛皮呀
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2026-5-25 22:47 , Processed in 0.391294 second(s), 27 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表