文章目录[toc]官方文档介绍-FatFs前提知识准备一、核心编程语言C语言优先级★★★★★二、嵌入式系统基础优先级★★★★★三、存储介质原理优先级★★★★四、文件系统基础概念优先级★★★★五、底层驱动开发能力优先级★★★★六、辅助调试与配置能力优先级★★★七、可选但加分的知识优先级★★学习路径建议一、**簇、FAT表、目录项详解****1. 簇 (Cluster) - 存储的基本单位****什么是簇****比喻仓库的储物柜****实际示例****簇的特点****2. FAT表 (File Allocation Table) - 簇的地图导航****什么是FAT表****比喻快递追踪系统****FAT表项的值****文件簇链示例****FAT表在磁盘上的位置****3. 目录项 (Directory Entry) - 文件的身份证****什么是目录项****比喻图书馆的图书卡片****目录项的详细结构32字节****属性字节 (DIR_Attr) 详解****目录项示例****三者的协同工作流程****场景读取文件DATA.BIN****场景创建新文件****FatFs中对应的操作****实际调试示例****常见问题****Q: 为什么我的4KB文件显示占用8KB****Q: 删除文件后数据还在吗****Q: 如何查看文件的真实簇链**二、**FAT32 磁盘布局****关键结构详解****1. 引导扇区 (DBR - DOS Boot Record)****2. FAT 表 (File Allocation Table)****3. 目录项结构 (32字节)****4. 长文件名支持 (LFN)****5. 簇的寻址****6. 文件簇链示例****与 FatFs 的关联****FatFs 内部结构****常用 FatFs 函数与 FAT32 的关系****FAT32 限制****学习建议**三、实际应用 FatFs核心设计模块化与可移植性️ 如何使用FatFs核心工作流程 FatFs与其他嵌入式文件系统对比 关键概念与使用要点 学习与移植建议FAT12 / FAT16 / FAT32 含义一句话理解FAT12 / FAT16 / FAT32 的区别通俗类比嵌入式开发关键点举个场景官方文档介绍-FatFs前提知识准备学习FatFs文件系统是嵌入式开发中高频的技能需求FatFs是轻量级、可移植的FAT文件系统广泛用于MCU/单片机场景其前置知识需围绕嵌入式基础、存储原理、编程核心能力三大维度展开以下是分层次的必备知识清单附学习优先级和应用关联一、核心编程语言C语言优先级★★★★★FatFs源码完全由标准C编写且嵌入式场景下的移植/使用高度依赖C语言核心特性需掌握基础语法变量、数据类型尤其是uint8_t/uint16_t/uint32_t等嵌入式常用类型、分支/循环、函数定义与调用核心特性指针一级/二级指针FatFs大量使用指针操作缓冲区、文件目录项、FAT表结构体/枚举/联合体FatFs的核心对象如FIL文件结构体、DIR目录结构体、FATFS卷结构体、FRESULT错误码枚举均基于这些类型宏定义/条件编译FatFs的配置文件ffconf.h全靠宏控制功能如FF_FS_READONLY、FF_FS_MINIMIZE需理解宏的定义与展开函数指针FatFs底层驱动接口如disk_ioctl会用到函数指针实现通用适配内存操作memcpy/memset/memcmp等内存操作函数FatFs内部大量用于数据读写/校验以及嵌入式场景下的静态/动态内存分配避免堆溢出。二、嵌入式系统基础优先级★★★★★FatFs几乎只用于嵌入式场景需掌握嵌入式开发的核心底层能力MCU外设操作通信总线SPI/I2C/SDIO对接SD卡、SPI Flash、USB Host对接U盘——FatFs的存储介质依赖这些总线驱动GPIO/定时器辅助存储介质的硬件初始化如SD卡的片选引脚、Flash的复位引脚中断与并发中断处理基础文件读写时需避免中断打断关键操作如SD卡扇区读写需懂中断屏蔽/恢复RTOS基础可选但高频若在FreeRTOS/RT-Thread等系统中使用FatFs需掌握互斥锁/信号量防止多线程同时操作文件导致数据损坏内存管理嵌入式内存布局栈/堆/全局区FatFs的缓冲区如文件读写缓存需合理分配内存静态内存分配嵌入式场景通常禁用malloc/free需用静态数组替代动态内存FatFs支持静态配置缓冲区字节序大小端FAT文件系统规定数据存储为小端序MCU若为大端如部分PowerPC需掌握字节序转换FatFs提供BYTE_SWAP宏适配但需理解原理。三、存储介质原理优先级★★★★FatFs需挂载具体的存储介质必须理解介质的底层读写逻辑核心存储介质特性介质类型关键知识点SD卡/MMC卡扇区概念512字节/扇区FatFs的最小操作单位、SDIO/SPI协议、卡初始化流程、扇区读写指令SPI Flash如W25Q页/扇区/块的区别擦除单位是块读写单位是页、擦写寿命、SPI Flash的读写/擦除指令U盘USB HostUSB枚举流程、大容量存储设备MSC协议、U盘的扇区读写接口eMMC/NAND Flash坏块管理、ECC校验FatFs本身不处理坏块需底层驱动适配通用概念块设备Block DeviceFatFs仅支持块设备按固定大小扇区读写需区分“字符设备”如串口与块设备的差异读写时序存储介质的读写有严格时序要求如SD卡的CMD指令响应需理解底层驱动的“等待就绪”逻辑。四、文件系统基础概念优先级★★★★无需深入FAT协议细节但需掌握通用文件系统的核心逻辑理解FatFs的设计目标FAT文件系统核心术语卷Volume一个存储介质如一张SD卡对应一个FatFs卷FATFS结构体簇ClusterFAT文件系统的最小分配单位由多个扇区组成FatFs通过簇管理文件空间文件分配表FAT表记录簇的使用状态空闲/已分配/坏簇是FatFs读写文件的核心依据目录项Directory Entry存储文件/目录的元信息名称、大小、起始簇、时间戳FAT格式差异FAT12/FAT16/FAT32的区别FatFs支持全系列需知道ffconf.h中FF_FS_FAT32的配置逻辑文件操作通用流程打开→读写→关闭FatFs的API完全遵循这一逻辑如f_open/f_read/f_write/f_close。五、底层驱动开发能力优先级★★★★FatFs的核心是“可移植”其与硬件的解耦依赖底层驱动接口需掌握FatFs底层接口diskio.c需实现5个核心函数FatFs的“硬件抽象层”必须理解每个函数的作用disk_initialize存储介质初始化如SD卡初始化disk_status获取介质状态就绪/未就绪disk_read从扇区读取数据FatFs读文件的底层依赖disk_write向扇区写入数据FatFs写文件的底层依赖disk_ioctl控制指令如获取扇区数、擦除扇区、同步缓存驱动调试能力能通过串口打印调试底层读写是否正常如读取SD卡的MBR主引导记录、FAT表定位“介质未就绪”“读写失败”等问题。六、辅助调试与配置能力优先级★★★FatFs配置文件ffconf.h理解核心配置项的含义按需裁剪功能减少ROM/RAM占用FF_FS_READONLY是否只读仅读场景可开启节省代码FF_FS_MINIMIZE功能裁剪级别0-3级别越高功能越少FF_USE_STRFUNC是否启用字符串操作如f_puts/f_getsFF_VOLUMES支持的卷数量如同时挂载SD卡SPI Flash需设为2错误码解析FatFs的返回值FRESULT枚举如FR_DISK_ERR、FR_NOT_READY、FR_NO_FILE是调试的核心需熟记常见错误码的含义编译与链接嵌入式编译器Keil/STM32CubeIDE/GCC的基本使用能将FatFs源码加入工程解决链接时的“未定义函数”通常是底层驱动未实现。七、可选但加分的知识优先级★★FAT协议细节如MBR分区表结构、FAT表的映射规则、长文件名LFN的存储方式FatFs支持长文件名需理解其编码逻辑低功耗/异常处理文件读写中断后的恢复逻辑如掉电前同步文件缓存跨平台移植经验理解FatFs的“硬件无关层”与“硬件相关层”分离设计能快速适配不同MCU如STM32、ESP32、51单片机。学习路径建议先巩固C语言指针/结构体 嵌入式外设驱动如SD卡SPI驱动理解FAT文件系统的核心概念扇区/簇/FAT表从ffconf.h最简配置入手只读、单卷、禁用长文件名先实现“读取SD卡中某文件”的基础功能逐步开启写功能、长文件名、多卷结合RTOS实现多线程安全的文件操作。核心逻辑FatFs的学习本质是“C语言嵌入式驱动文件系统概念”的融合重点不是背API而是理解“FatFs如何通过通用接口适配不同存储介质如何基于FAT协议管理文件”。一、簇、FAT表、目录项详解1. 簇 (Cluster) - 存储的基本单位什么是簇定义簇是文件系统中存储分配的最小单位组成一个簇 N个连续的扇区通常N1,2,4,8,…大小格式化时决定常见的有4KB8个512字节扇区比喻仓库的储物柜仓库硬盘 → 储物柜区簇区 每个储物柜簇有固定大小如4KB 即使只存1字节文件也要占用整个储物柜实际示例// 假设簇大小 4KB8个扇区文件log.txt大小1.2KB 但实际占用空间4KB一个整簇 文件photo.jpg大小15KB 实际占用空间16KB4个簇15/4向上取整簇的特点编号从2开始簇0和簇1有特殊用途物理位置簇号 → 物理扇区需要转换计算浪费问题小文件会产生内部碎片2. FAT表 (File Allocation Table) - 簇的地图导航什么是FAT表定义一个簇号映射表记录每个簇的状态和链接关系作用跟踪文件占用了哪些簇以及这些簇的顺序比喻快递追踪系统文件 一批要配送的货物 每个簇 一个配送站点 FAT表 配送路线图告诉你 当前站点的下一站是哪里 货物是否已送达FAT表项的值0x00000000空闲簇可以分配0x00000002有效簇号指向下一簇0x0FFFFFF7坏簇不可用0x0FFFFFF8-0x0FFFFFFF文件结束标记文件簇链示例文件report.doc占用簇5 → 8 → 12 → EOF FAT表内容 索引 | 值 | 含义 -----|----------|---------------- 5 | 0x00000008 → 去簇8 8 | 0x0000000C → 去簇12 12 | 0x0FFFFFFF → 文件结束 其他 | 0x00000000 → 空闲FAT表在磁盘上的位置扇区0-31: 引导区 扇区32-543: FAT1主表 扇区544-1055: FAT2备份表 扇区1056: 数据区簇从这里开始3. 目录项 (Directory Entry) - 文件的身份证什么是目录项定义32字节的记录存储文件的元数据信息位置位于目录文件的内容中目录也是一种特殊文件比喻图书馆的图书卡片目录项 图书索引卡片 包含书名文件名、位置簇号、大小、借阅时间等目录项的详细结构32字节// 实际内存布局小端序字节0-10:DIR_Name[11]// FILENAMEEXT8.3格式字节11:DIR_Attr// 属性字节字节12-21:保留/时间信息 字节22-23:DIR_FstClusHI// 起始簇高16位字节24-25:DIR_WrtTime// 最后写入时间字节26-27:DIR_WrtDate// 最后写入日期字节28-29:DIR_FstClusLO// 起始簇低16位字节30-33:DIR_FileSize// 文件大小字节属性字节 (DIR_Attr) 详解位0 (0x01): 只读 → 不能修改 位1 (0x02): 隐藏 → dir命令不显示 位2 (0x04): 系统文件 → 操作系统使用 位3 (0x08): 卷标 → 磁盘标签 位4 (0x10): 子目录 → 这是一个目录 位5 (0x20): 存档 → 已备份/可修改 位6-7: 保留 长文件名条目属性0x0F特殊标记目录项示例文件: README.TXT (6KB) 属性: 存档(0x20) 起始簇: 0x0005 (簇5) 大小: 6144字节 十六进制表示: 52 45 41 44 4D 45 20 20 54 58 54 20 00 00 00 00 00 00 00 00 00 00 88 6D 75 54 00 00 05 00 00 00 00 00 18 00 00 00三者的协同工作流程场景读取文件DATA.BIN1. 查找目录项在目录文件中搜索 - 找到DATA.BIN的目录项 - 从中提取起始簇号5文件大小10240字节 2. 使用FAT表遍历簇链 - 读取簇5 → FAT[5]8 - 读取簇8 → FAT[8]12 - 读取簇12 → FAT[12]0x0FFFFFFF结束 3. 读取实际数据 - 簇5物理地址 数据区起始 (5-2)*每簇扇区数 - 读取簇5、8、12的内容场景创建新文件1. 在目录中找空闲目录项第一个字节0xE5或0x00 2. 在FAT表中找空闲簇FAT项0x00000000 3. 填充目录项文件名、属性、起始簇号、大小等 4. 在FAT表中标记该簇为已使用FatFs中对应的操作// 打开文件内部操作f_open(fil,test.txt,FA_READ);// 1. FatFs查找当前目录找到test.txt的目录项// 2. 读取目录项获取起始簇号和大小// 3. 初始化文件对象的当前位置信息// 读取文件f_read(fil,buffer,1024,br);// 1. 根据当前位置计算在哪个簇// 2. 读取该簇的数据// 3. 如果读到簇末尾查FAT表找下一簇// 4. 更新文件位置指针// 写入文件f_write(fil,data,512,bw);// 1. 如果当前簇已满分配新簇// 2. 更新FAT表建立簇链// 3. 更新目录项中的文件大小实际调试示例假设你想查看文件CONFIG.CFG的存储情况// 1. 找到目录项假设在根目录根目录起始簇BPB_RootClus(假设2)读取簇2搜索CONFIG CFG// 2. 解析目录项起始簇号(DIR_FstClusHI16)|DIR_FstClusLO5文件大小1500字节// 3. 跟踪FAT链FAT[5]8// 还有数据FAT[8]0x0FFFFFFF// 文件结束// 4. 结论文件占用簇5和簇8簇5:0-4095字节实际只用前1500字节 簇8:未使用因为15004096只用一个簇就够了// 这里似乎矛盾说明FAT链有问题或文件大小变了常见问题Q: 为什么我的4KB文件显示占用8KBA: 可能因为簇大小8KB或者文件系统有额外的元数据。Q: 删除文件后数据还在吗A: 还在删除只是目录项第一个字节改为0xE5标记删除FAT表中相应簇标记为空闲实际数据直到被覆盖前都保留Q: 如何查看文件的真实簇链A: 可以使用WinHex等工具或自己写代码解析FAT。二、FAT32 磁盘布局┌─────────────────────────────────────────────────────────────────┐ │ FAT32 磁盘结构 │ ├──────────────┬──────────────┬──────────────┬────────────────────┤ │ 保留区域 │ FAT1 │ FAT2 │ 数据区域 │ │ (包含MBR/DBR) │ (文件分配表)│ (备份FAT) │ (簇区域) │ ├──────────────┼──────────────┼──────────────┼────────────────────┤ │ 扇区0 │ FAT表区域 │ FAT表备份 │ 簇2, 簇3, ... │ │ (引导扇区) │ │ │ (文件/目录数据) │ └──────────────┴──────────────┴──────────────┴────────────────────┘关键结构详解1. 引导扇区 (DBR - DOS Boot Record)位于第 0 扇区包含文件系统参数typedefstruct{uint8_tBS_jmpBoot[3];// 跳转指令uint8_tBS_OEMName[8];// OEM名称uint16_tBPB_BytsPerSec;// 每扇区字节数 (通常512)uint8_tBPB_SecPerClus;// 每簇扇区数uint16_tBPB_RsvdSecCnt;// 保留扇区数 (FAT32通常为32)uint8_tBPB_NumFATs;// FAT表数量 (通常2)uint32_tBPB_FATSz32;// 每个FAT表大小(扇区数)uint32_tBPB_RootClus;// 根目录起始簇号// ... 还有其他字段}FAT32_BPB;2. FAT 表 (File Allocation Table)作用记录簇的分配状态和文件簇链FAT32表项32位实际只用28位特殊值0x00000000空闲簇0x00000002-0x0FFFFFEF下一簇号0x0FFFFFF7坏簇0x0FFFFFF8-0x0FFFFFFF文件结束3. 目录项结构 (32字节)typedefstruct{uint8_tDIR_Name[11];// 8.3文件名 (大写)uint8_tDIR_Attr;// 文件属性uint8_tDIR_NTRes;// NT保留uint8_tDIR_CrtTimeTenth;// 创建时间(10ms)uint16_tDIR_CrtTime;// 创建时间uint16_tDIR_CrtDate;// 创建日期uint16_tDIR_LstAccDate;// 最后访问日期uint16_tDIR_FstClusHI;// 起始簇号高16位uint16_tDIR_WrtTime;// 最后修改时间uint16_tDIR_WrtDate;// 最后修改日期uint16_tDIR_FstClusLO;// 起始簇号低16位uint32_tDIR_FileSize;// 文件大小(字节)}DIR_ENTRY;文件属性位 (DIR_Attr):0x01: 只读0x02: 隐藏0x04: 系统文件0x08: 卷标0x10: 子目录0x20: 存档0x0F: 长文件名条目4. 长文件名支持 (LFN)FAT32 通过特殊目录项存储长文件名属性字节 0x0F每个 LFN 条目存储 13 个 Unicode 字符通过校验和与短名关联逆序排列在短名前5. 簇的寻址簇号从 2 开始0 和 1 保留物理扇区地址计算数据区起始扇区 保留扇区数 (FAT表数 × FAT表大小) 簇的扇区地址 数据区起始扇区 (簇号 - 2) × 每簇扇区数6. 文件簇链示例假设文件占用簇 5、8、10FAT表内容 索引 值(16进制) 含义 ... 5 0x00000008 → 下一簇是8 8 0x0000000A → 下一簇是10 10 0x0FFFFFFF → 文件结束与 FatFs 的关联在 FatFs 中这些概念对应为FatFs 内部结构// FatFs 的 FAT32 结构体typedefstruct{FATFS*fs;// 文件系统对象DWORD sclust;// 起始簇号DWORD clust;// 当前簇号DWORD sect;// 当前扇区UINT index;// 扇区内偏移}FIL;常用 FatFs 函数与 FAT32 的关系f_mount()- 读取引导扇区初始化文件系统信息f_open()- 查找目录项获取起始簇号f_read()/f_write()- 通过 FAT 表遍历簇链f_lseek()- 计算簇内偏移可能触发簇链跳转f_truncate()- 修改 FAT 表释放簇FAT32 限制最大文件大小4GB - 1 字节由于 32 位文件大小字段最大分区大小理论 2TB实际通常 32GB-2TB最大文件数受限于 FAT 表大小和目录结构性能问题碎片化严重时文件访问会变慢学习建议先从 FatFs API 开始不要一开始就深入二进制格式理解关键概念簇、FAT表、目录项使用调试工具如 WinHex 查看实际磁盘结构动手实验创建小文件观察 FAT 表和目录项变化三、实际应用FatFsFile Allocation Table File System是一个专为嵌入式系统设计的、兼容FAT格式的开源文件系统模块。它不依赖操作系统能让你在W25Q128这类存储芯片上实现类似电脑U盘的文件管理。 FatFs核心设计模块化与可移植性FatFs采用清晰的分层架构便于移植到不同硬件架构层级组件名称核心职责你需要做什么应用层用户程序调用FatFs API如f_open, f_write编写业务逻辑代码中间层FatFs核心 (ff.c, ff.h)实现FAT文件系统逻辑目录、文件读写通常无需修改物理层磁盘I/O层 (diskio.c, diskio.h)提供底层存储介质的读写、控制接口重点移植部分需对接W25Q128驱动这种设计的精髓在于你只需实现底层diskio.c中的几个函数如disk_readdisk_write来驱动W25Q128上层的文件操作创建、读写文件FatFs都已为你准备好。️ 如何使用FatFs核心工作流程典型的FatFs操作遵循以下流程这是一个在SD卡或W25Q128上创建并写入文件的简化示例// 0. 初始化你的硬件SPI、GPIO等spi_init();// 1. 注册工作区挂载FATFS fs;// 文件系统对象FRESULT frf_mount(fs,0:,1);// 0:对应diskio.c中的驱动器编号// 2. 创建并打开文件FIL fil;frf_open(fil,0:/log.txt,FA_CREATE_ALWAYS|FA_WRITE);// 3. 写入数据UINT bw;chardata[]Hello, W25Q128 with FatFs!\n;frf_write(fil,data,sizeof(data)-1,bw);// 4. 关闭文件并卸载f_close(fil);f_unmount(0:); FatFs与其他嵌入式文件系统对比了解FatFs的定位有助于你做出选择特性对比FatFsLittleFSSPIFFS主要特点FAT标准兼容通用性强专为掉电安全和磨损均衡优化专为SPI NOR Flash设计极度轻量优点与PC兼容性好文档丰富功能全面防掉电损坏动态磨损均衡内存占用极小设计简洁缺点掉电保护较弱需自行处理均衡代码比FatFs稍复杂非标准格式社区支持相对少适用场景需要与PC交换数据、功能要求全面的应用频繁断电或需高可靠性的IoT设备资源极度紧张的小容量SPI Flash 关键概念与使用要点FAT卷与驱动器号FatFs通过“驱动器号”如0:1:来标识不同的物理设备。在你的diskio.c中需要将这些编号映射到具体的W25Q128芯片实例。可裁剪性FatFs通过ffconf.h配置文件提供大量选项。你可以根据需求关闭不用的功能如长文件名、多分区以节省宝贵的ROM和RAM空间。重要确保底层驱动稳定一切文件操作都建立在disk_read/disk_write稳定可靠的基础上。对于W25Q128你需要特别注意SPI时序确保在Quad SPI模式下时序正确。擦除管理NOR Flash写入前必须先擦除变为0xFF。FatFs不负责Flash的擦除特性你需要在disk_write函数中自行管理擦除操作通常是整个扇区擦除。磨损均衡W25Q128每个扇区约10万次擦写寿命。FatFs本身不提供完善的磨损均衡策略若频繁写同一区域如日志需在应用层设计策略或考虑LittleFS。 学习与移植建议官方资源访问FatFs官网阅读00readme.txt和doc目录下的文档这是最权威的信息源。移植起点以官方提供的“diskio.c模板”为起点进行修改重点关注disk_status、disk_initialize、disk_read、disk_write、disk_ioctl这五个函数。调试先确保底层W25Q128的读写擦除操作绝对可靠再挂载FatFs。使用f_mkfs创建文件系统是很好的第一步测试。总结来说FatFs是连接你的嵌入式应用与W25Q128这类存储芯片的强大桥梁。理解其分层架构和移植关键点你就能在设备上高效管理文件。FAT12 / FAT16 / FAT32 含义一句话理解FatFs 是嵌入式单片机用的开源C语言文件系统库这句话意思只要你的SD卡 / SPI Flash / U盘 格式化成 FAT12、FAT16、FAT32FatFs 就能识别、读写里面的文件和Windows电脑互相兼容。FatFs 本身不是硬件驱动它只负责文件逻辑打开、读写、创建文件、目录底层读扇区、写扇区需要你自己写底层disk驱动。FAT12 / FAT16 / FAT32 的区别名字里的数字 文件分配表FAT里簇编号占用多少bit决定能管理多大存储FAT1212bit老式软盘容量很小最大约32MB现在极少用。FAT1616bit老U盘、小存储卡分区上限约2GB单个文件最大2GB。FAT3232bit最常用普通SD卡、U盘默认格式分区最大2TB单个文件上限4GB这是FAT32经典限制。通俗类比文件系统 仓库的账本FAT表就是账本记录每一块数据簇放在哪里、是不是空闲FAT12/FAT16/FAT32是三种版本的账本格式FatFs 就是一个能看懂这三种账本的“仓库管理员”在单片机上帮你新建文件、读写数据、删除文件把SD卡插到电脑Windows格式化选FAT32插到单片机FatFs就能直接识别这个卡上的文件。嵌入式开发关键点FatFs 自动识别卡是FAT12/FAT16/FAT32你代码不用手动指定格式FatFs新版还可选开启 exFAT支持大于4GB单文件可以用FatFs的f_mkfs()函数直接在单片机里把存储介质格式化成FAT12/FAT16/FAT32不用电脑格式化代码只需要实现底层disk_read、disk_write这两个读写扇区函数上层f_open、f_write等API直接调用。举个场景STM32SD卡移植FatFsSD卡电脑格式化FAT32单片机上电FatFs挂载SD卡调用f_open(log.txt, FA_CREATE_ALWAYS | FA_WRITE)创建日志文件写采集数据写完拔卡插到电脑Windows能直接打开log.txt。
阅读完成 · 觉得有帮助?