操作系统:rt-thread
文件系统:Fat16
硬件平台:stm32f103c8

描述:利用mcu的ram虚拟一个U盘,用于存储即时小数据,通过usb以u盘的方式供上位机读取。

一:硬盘篇

1、硬盘物理结构:

盘片(platter):硬盘由很多盘片组成,每个盘片的每个面都有一个读写磁头(heads)。N个盘片,就有2N个面,对应2N个磁头,从0、1、2……开始编号;

磁道:同一个盘片不同半径的同心圆为磁道(注意,是指圆周线或圆环);

柱面(cylinders):不同盘片相同的磁道,构成柱面,由外至里编号0、1、2……

扇区(sector):每道磁道被划分成几十个扇区,通常,一个扇区容量为512B,并按照一定规则编号1、2、3……

簇:另外,由于扇区实在太多了,文件分配表没办法一一描述,所以,就把一定数量的扇区分为一个簇。所以文件系统是以一簇为最小单位的。

注意:磁头和柱面都是从0开始编号的,扇区搞毛特殊从1开始。

总扇区数量=柱面数×磁头数×每道扇区

2、磁盘引导:

下图是一个4个分区的硬盘,开头的主引导记录就是上面介绍的MBR,其中4个分区表分别指出了4个分区的位置,上位机获取MBR之后,就知道了硬盘的总体结构,包括硬盘的大小、每个分区的位置、每个分区的大小等等。

隐藏区(hidden sector):在分区之前的部分,而下面介绍的MBR就是隐藏区的第一个扇区。隐藏区不是必须的,它和系统启动有关,如果仅仅是作为存储,那么隐藏区可以没有。比如,标题说的用RAM虚拟的U盘。

注意:在我理解中,严格地说,隐藏区应该是指每个分区之内,位于保留区之前的扇区,也就是说,每个分区都有一套隐藏区+保留区。只是在唯一存储介质的第一个分区的隐藏区才是必须的,因为它需要用于系统的启动。而其他分区的隐藏区则一般被省略。如果不被省略,比如SD的开头就有一部分隐藏区,这时,引导代码部分是空的(因为不需要它来做系统启动),只有DPT分区表才有意义,用于划分SD的分区情况。

MBR(master boot record)扇区:即主引导记录,有时也叫主引导扇区,位于硬盘的0柱面0磁头1扇区,也就是所谓是第0扇区,也是整个存储介质的首个扇区。其中前446字节为引导程序,紧跟着的是64字节的硬盘分区表DPT,最后2个字节是“0x55 0xAA”,为磁盘有效结尾标志。

MBR 是不随操作系统的不同而不同的,具有公共引导特性。(在双系统中,一般先装Windows再装linux,原因是,linux会修改这段代码,让用户可以选择进去哪个系统,但Windows却是没有,如果后装Windows,那么linux的引导就会被忽略??)

(1)0x000-0x1bd:mbr引导代码(有些地方也叫MBR??),446字节,pc的bios执行完自举之后,会将cpu控制权交给此间的446个字节的loader程序;

(2)0x1be-0x1fd:DPT分区表,64字节,每16字节描述一个分区,所以硬盘的主分区+扩展分区不能大于4个,另外扩展分区数不能大于1。(现实中,不止4个,其实是扩展分区里面分出来的逻辑分区,对于逻辑分区的问题上面的链接也有提到,可以参考。)

0x1fe-0xff:0x55 0xAA。

主引导记录部分如下表:

偏移(字节) 长度(字节) 说明
0x00 3 跳转指令(跳过开头一段区域)
0x03 8 OEM名称(空格补齐)。MS-DOS检查这个区域以确定使用启动记录中的哪一部分数据 [3] 。常见值是IBM 3.3(在“IBM”和“3.3”之间有两个空格)和MSDOS5.0.
0x0b 2 每个扇区的字节数。基本输入输出系统参数块从这里开始。
0x0d 1 每簇扇区数
0x0e 2 保留扇区数(包括启动扇区)
0x10 1 文档分配表数目
0x11 2 最大根目录条目个数
0x13 2 总扇区数(如果是0,就使用偏移0x20处的4字节值)
0x15 1 介质描述

0xF8 单面、每面80磁道、每磁道9扇区
0xF9 双面、每面80磁道、每磁道9扇区
0xFA 单面、每面80磁道、每磁道8扇区
0xFB 双面、每面80磁道、每磁道8扇区
0xFC 单面、每面40磁道、每磁道9扇区
0xFD 双面、每面40磁道、每磁道9扇区
0xFE 单面、每面40磁道、每磁道8扇区
0xFF 双面、每面40磁道、每磁道8扇区

同样的介质描述必须在重复复制到每份FAT的第一个字节。有些操作系统(MSX-DOS 1.0版)全部忽略启动扇区参数,而仅仅使用FAT的第一个字节的介质描述确定文件系统参数。

0x16 2 每个文档分配表的扇区(FAT16)
0x18 2 每磁道的扇区
0x1a 2 磁头数
0x1c 4 隐藏扇区
0x20 4 总扇区数(如果超过65535,参见偏移0x13)
0x24 4 每个文档分配表的扇区(FAT32)。扩展基本输入输出系统参数块从这里开始。
0x24 1 物理驱动器个数(FAT16)
0x25 1 当前磁头(FAT16)
0x26 1 签名(FAT16)
0x27 4 ID(FAT16)
0x28 2 Flags(FAT32)
0x2a 2 版本号(FAT32)
0x2c 4 根目录启始簇(FAT32)
0x2b 11 卷标(非FAT32)
0x30 2 FSInfo扇区(FAT32)
0x32 2 启动扇区备份(FAT32)
0x34 12 保留未使用(FAT32)
0x36 8 FAT文件系统类型(如FAT、FAT12、FAT16)
0x3e 2 操作系统自引导代码
0x40 1 BIOS设备代号(FAT32)
0x41 1 未使用(FAT32)
0x42 1 标记(FAT32)
0x43 4 卷序号(FAT32)
0x47 11 卷标(FAT32)
0x52 8 FAT文件系统类型(FAT32)
0x1FE 2 扇区结束符(0x55 0xAA)

DPT分区表:

表1  图2分区表第一字段
字节位移 字段长度 字段名和定义
0x01BE BYTE 0x80    引导指示符(Boot Indicator)   指明该分区是否是活动分区。
0x01BF BYTE 0x01 开始磁头(Starting Head)
0x01C0 6位 0x01 开始扇区(Starting Sector) 只用了0~5位。后面的两位(第6位和第7位)被开始柱面字段所使用
0x01C1 10位 0x00 开始柱面(Starting Cylinder)   除了开始扇区字段的最后两位外,还使用了1位来组成该柱面值。开始柱面是一个10位数,最大值为1023
0x01C2 BYTE 0x07 系统ID(System ID) 定义了分区的类型,详细定义,请参阅图4
0x01C3 BYTE 0xFE 结束磁头(Ending Head)
0x01C4 6位 0xFF 结束扇区(Ending Sector)     只使用了0~5位。最后两位(第6、7位)被结束柱面字段所使用
0x01C5 10位 0x7B 结束柱面(Ending Cylinder) 除了结束扇区字段最后的两位外,还使用了1位,以组成该柱面值。结束柱面是一个10位的数,最大值为1023
0x01C6 DWORD 0x0000003F 相对扇区数(Relative Sectors) 从该磁盘的开始到该分区的开始的位移量,以扇区来计算
0x01CA DWORD 0x00DAA83D 总扇区数(Total Sectors) 该分区中的扇区总数

3、FAT分区原理:

下面终于开始说FAT。

对于一个存储介质,隐藏区之后,才是文件系统的起始部分,以保留区开头。

FAT文件系统的结构是按照这个方式排列的:保留区、FAT区、副FAT区、根目录区、数据区。

(1)、保留区(Reserved Region)

保留区就是分区的开始扇区到FAT表之前的扇区,注意,保留区是位于分区之内,每个分区的开头都会有一个保留区。而保留区的第一个扇区必须是BPB。如果隐藏区为0,那么BPB将位于第0扇区。

DBR(Dos Boot Record):即操作系统引导记录,通常位于分区的第0个扇区,共512个字节(特殊情况也要占用其它保留扇区)。在这512个字节中,其实又是由跳转指令,厂商标志和操作系统版本号,BPB(BIOS Parameter Block),扩展BPB,os引导程序,结束标志几部分组成。 以用的最多的FAT32为例说明分区DBR各字节的含义。见图:

对应解释见下表:

    表3   FAT32分区上DBR中各部分的位置划分   
字节位移 字段长度 字段名 对应图8颜色
0x00 3个字节 跳转指令  
0x03 8个字节 厂商标志和os版本号  
0x0B 53个字节 BPB  
0x40 26个字节 扩展BPB  
0x5A 420个字节 引导程序代码  
0x01FE 2个字节 有效结束标志  

其实,图中,除了黑色部分,其他部分同MBR是一样的,可以直接查看上面对MBR内容的分析表格。

需要注意的是:

1)跳转指令:EB xx 90,也就说第0和第2为分别是EB和90,至于具体意义,没有暂时没有深究;

2)对应MBR,最大的区别是,DBR没有分区表DPT!

(2)、FAT区

即文件分配表,有两份,第二份是第一份的备份。文件分配表每项代表一个簇,由于fat16使用两字节即16位来描述一个簇,所以最多只能管理65536个簇,又由于每簇最大只有32kB,所以使用fat16的时候,每个分区最大容量是2G。分区表的大小可以在DBR里设置。

(3)、根目录区:

第二个FAT表(即备份FAT)后面紧接着的下一个扇区,就是根目录区的开始。存放目录项,每个目录下为32个字节,记录一个文件或目录的信息(长文件名例外)。目录项所占的扇区与可以容纳的目录项有关,一般为512项,将占“512(目录项数)×32/512(扇区大小)”个扇区。但是目录项×32一定是扇区大小512的整数倍。

32字节目录项内容如下表:

字节偏移 长度 描述
0x00 8 DOS文件名(附加空格)

第一个字节可以是下面的特殊数值:

0x00 这个条目有用并且后面没有被占用条目
0x05 最初字符确实是0xE5
0x2E '点'条目;'.'或者'..'
0xE5 这个条目曾经被删除不再有用。取消删除文档工具作为取消删除的一步必须使用一个正常的字符取代它。
0x08 3 DOS文件扩展名(空格补齐)
0x0b 1 文档属性

第一个字节可以是下面一些特殊值:

掩码 描述
0 0x01 只读
1 0x02 隐藏
2 0x04 系统
3 0x08 卷标
4 0x10 子目录
5 0x20 档案
6 0x40 设备(内部使用,磁盘上看不到)
7 0x80 没有使用

属性值0x0F用来表示长文件名条目。

0x0c 1 保留,NT使用(参见后面)
0x0d 1 创建时间,最小时间分辨率:10ms单位,数值从0到199。
0x0e 2 创建时间。小时、分钟和秒根据后面的图示描述进行编码:

描述
15-11 小时(0-23)
10-5 分钟(0-59)
4-0 秒/2(0-29)

注意只保存了2秒的分辨率。更细分辨率的文档创建时间在偏移0x0d处。

0x10 2 创建日期。年、月和日根据后面的图示编码:

描述
15-9 年(0 = 1980, 127 = 2107)
8-5 月(1 = 1月,12 = 12月)
4-0 日(1 - 31)
0x12 2 最近访问时间;参见偏移0x0e处的描述。
0x14 2 FAT12和FAT16中的EA-Index(OS/2和NT使用),FAT32中第一个簇的两个高字节
0x16 2 最后更改时间;参见偏移0x0e处的描述。
0x18 2 最后更改日期; 参见偏移0x10处的描述。
0x1a 2 FAT12和FAT16中的第一个簇。FAT32中第一个簇的两个低字节。
0x1c 4 文档大小

(4)、文件和目录数据区

目录项接着的第一个扇区就是真正存放文件数据或是目录的位置了。

二:FAT16

维基百科:http://en.wikipedia.org/wiki/Fat16

其实和上面的介绍差不多。不过这是从文件系统逻辑概念来解释,而前面更偏于物理位置。

保留区 文档
分配表#1
文档
分配表#2
根目录 其他所有数据...
剩下磁盘空间
  1. 保留扇区,位于最开始的位置。第一个保留扇区是引导区DBR(分区启动记录)。它包括一个称为基本输入输出参数块的区域(包括一些基本的文件系统信息尤其是它的类型和其它指向其它扇区的指针),通常包括操作系统的启动调用代码。保留扇区的总数记录在引导扇区中的一个参数中。引导扇区中的重要信息可以被DOS和OS/2中称为驱动器参数块的操作系统结构访问。
  2. FAT区域。它包含有两份文档分配表,这是出于系统冗余考虑,尽管它很少使用,即使是磁盘修复工具也很少使用它。它是分区信息的映射表,指示簇是如何存储的。
  3. 根目录区域。它是在根目录中存储文档和目录信息的目录表。在FAT32下它可以存在分区中的任何位置,但是在早期的版本中它永远紧随FAT区域之后。
  4. 数据区域。这是实际的文档和目录数据存储的区域,它占据了分区的绝大部分。通过简单地在FAT中添加文档链接的个数可以任意增加文档大小和子目录个数(只要有空簇存在)。然而需要注意的是每个簇只能被一个文档占有,这样的话如果在32KB大小的簇中有一个1KB大小的文档,那么31KB的空间就浪费掉了。

总结:拿SD卡来讲吧,给xp格式化之后的SD卡物理结构如下:隐藏区+保留区+FAT+副FAT+根目录区+数据区 1、隐藏区:包括MBR(主引导记录)和DPT(分区表),不过这里的MBR是空的,因为不需要它的系统启动。上位机首先读取这个512字节,根据DPT,知道分区情况,根据这些接着直接跳到第一分区的位置读取第一个分区; 2、保留区和FAT:这是上位机读取分区的第一部分内容,从而知道分区的情况,根据BDR知道根目录的位置;然后去读根目录。 3、根目录区:读取分区的根目录,可以知道分区的文件结构,然后根据对应的FAT,读到一个文件的内容。注意,在根目录里记录了文件的开始扇区,而这个逻辑开始扇区,是以2开头的,估计0和1已经被保留所用。

前面说了一大堆关于FAT16和硬盘的东西,其实是为下面做准备的。因为我觉得用RAM虚拟U盘,一要熟悉fat,二要熟悉USB协议。

前面介绍fat,下面应该就说USB了,但我对USB的了解非常肤浅,没办法从协议的角度来记录,只能简单的针对这次开发记录一下,以备后用吧。

1、要了解USB的设备、配置、接口、端点等知识点,和对应的各种描述符;

2、然后了解枚举的过程,数据线D+,D-,差分数据传输,NRZI编码,还有一些数据包;

3、一个很好用的总线监控软件,可以用它来监控USB的通信过程,对开发很有用:Bus Hound;

4、USB设备分类:显示器Monitors, 通讯设备Communication device, 音频设备Audio, 人机输入Human input, 海量存储Mass storage。而这次我们用的应该就是Mass storage;

……

本程序是从一个MSD卡程序中改过来的,准确来说应该是奋斗版的U盘程序修改过来的。

关键点:

1、建立DBR数组(操作系统引导记录):

扇区大小:512;

每簇扇区数:1;

保留扇区数:1;

根目录项:16,因为16×32,刚好一个扇区;

小扇区数:8,因为用RAM虚拟的U盘,自然很小,其实我只用到5个扇区;

每FAT扇区数:1;

隐藏扇区数:0,因为不需要MBR,主引导记录;

大扇区数:0,fat16小容量没有用到;

2、FAT数组

FAT表以“F8 FF FF FF”开头,为介质描述单元。接着每2字节代表一簇,不过簇的标号是从2开始的,也就是说FAT表的4、5字节代表第2簇(顺序其实就是首簇),6、7字节代表第3簇,以此类推;

我现在fat表如下:

F8 FF FF FF  FF FF 00 00 ……

绿色就是代表第2簇,它的值代表文件的占用的下一个簇的簇号,ffff表示这是文件的最后一个簇。因为我们是一个小文件,一个文件只用一个簇,所以这个就是FFFF。0000表示此簇没有被分配。

例如,如果这里不是FFFF,而是0500(低位在前),则表示,文件的下一个簇的簇号是5,系统就会查询fat的第5簇的位置,重复上面的动作,知道遇到FFFF,表示这里是文件的最后一簇。

3、根目录数组

这里根据前一篇根目录的格式,建立一个盘符根目录(就是插入电脑的时候盘符的名字),接着是一个文件目录(因为这里只需要一个文件),起始簇为2;

4、数据数组

用于存文件的数据。

RAM虚拟的U盘结构是这样的:

DBR(1扇)-|-  FAT(1扇)-| -副FAT(1扇)-|- 根目录(1扇)-|- 数据(4扇,其实只用1扇的一点而已,小文件嘛)

pc上显示的空间大小是2k,原因是8个扇区中,数据占了4扇,而扇区的大小为512字节,所以大小是2k。

只需修改读写函数。读函数这样修改,当读的index为512×0是,发送DBR表;当为512×1时,发FAT,当为512×3时,发送根目录;当为512×4时,发送数据。其他用00 00 00 00 ……来填充。

写函数的修改:只允许写修改数据和根目录部分,其他时候直接返回失败标志。

需要注意的是,为了节省RAM,DBR、FAT、都可以用const定义,但根目录和数据数组最好用非const全局定义,原因是上位机在读取文件的时候,会修改根目录的“最近访问时间”。

另外,如果在pc机上把文件删掉,再重新建立的时候,根目录可不是简单的覆盖,而且还有清空FAT的对应标志。所以,我这里实现,可以删除文件,但再重新新建的时候,这个文件是没有被成功记录到虚拟的U盘的,估计,把FAT也改成可修改状态就可以实现,但是,这次项目不需要用到这点,所以没有去试。

这次实现存入janho程序库“Mass_Storage(用ram虚拟u盘fat16)”中,备用。

用单片机的RAM虚拟U盘(文件系统:Fat16)相关推荐

  1. RT-Thread:W25Q128虚拟U盘并搭载文件系统

    文章目录 前言 一.配置工程 二.W25Q128搭载文件系统 总结 前言 使用片外Flash W25Q128虚拟成U盘. 一.配置工程 1.打开W25Q128 2.打开USB Drever 3.开启大 ...

  2. 【STM32CubeMx你不知道的那些事】第十章:STM32CubeMx的SPI外置FLASH(W25Q128)+文件系统(FATFS)+虚拟U盘

      这一张我们主要讲解一下STM32CUBEMX新版本 片外FLASH(W25Q128)+FATFS文件系统+虚拟U盘. 一.准备工作 这里我们要想配置SPI和文件系统 并验证需要的准备工作如下: 1 ...

  3. 【单片机笔记】基于STM32F103C8的 USB 外部flash虚拟U盘

    学习stm32已经很长时间了,但是一直没有过多的学习stm32的USB部分,因为实际工作还是用的比较少.说起USB那就有的说了,因为USB的功能很强大,这里主要重点记录一下STM32的USB部分,这个 ...

  4. STM32SD卡实现USB虚拟U盘

    下载源码请关注公众号 之前的文章中介绍过STM32读写SD卡和FatFS文件系统相关的知识.今天将在这基础上介绍STM32通过USB口虚拟U盘的知识.即插入USB接口后,电脑将SD卡识别为U盘,可以直 ...

  5. STM32CbueMX之USB挂载内存虚拟U盘

    本文测试源码工程下载:USB-RAM.zip_STORAGE_LUN_NBR-其它代码类资源-CSDN下载 一.STM32CubeMX配置 Heap大小参照我们自己配置MSC_MEDIA_PACKET ...

  6. STM32Cube MX USB双设备MSC+CDC 实现虚拟U盘+虚拟串口

    前言 在上一篇文章实现USB虚拟U盘之后,项目需要用同一个USB口同时实现MSC和CDC功能,既能进行串口通信又能读取片外FLASH虚拟U盘.对于USB通用串行总线如果要真正搞明白这个协议还是比较困难 ...

  7. STM32Cube MX USB虚拟U盘+FATFS+W25Q128

    第一次写CSDN,把这两天做的一个小实验记个笔记.写的不好请见谅,有错误欢迎指正,欢迎讨论.在做之前也参考其他博主的一些文章Carry_王的博客 USB基本概念不做介绍,不懂的可以先去了解,主要说明实 ...

  8. STM32F103VET6利用片内FLASH虚拟U盘,使用文件复制方式实现IAP

    在原子论坛偶尔搜到一篇 利用STM32片内FLASH虚拟U盘,使用文件复制方式实现IAP的帖子http://www.openedv.com/forum.php?mod=viewthread&t ...

  9. 自制ST-Link V2.1教程(SWD调试+虚拟串口+虚拟U盘)

    文章目录 一. 关于ST-LINK 二. 自制ST-LINK硬件 1. 原理图 2. PCB图 3. BOM表 三. 固件烧录 四. 固件更新 五. 上电测试 六. 相关链接 一. 关于ST-LINK ...

最新文章

  1. 采用fdisk在linux进行分区操作
  2. Maven入门指南① :Maven 快速入门及简单使用
  3. Access denied for user(这个几乎让我怀疑人生的异常)
  4. Unity3D 单例模式
  5. python列表写入字典_python如何将列表中的元素添加进字典
  6. Content-Disposition 响应头,设置文件在浏览器打开还是下载
  7. JNI通过线程c回调java层的函数
  8. C++ 泛型编程(一):模板基础:函数模板、类模板、模板推演成函数的机制、模板实例化、模板匹配规则
  9. matlab读取图片的频率,获得时域图之后,也获得了频域图,但是如何查看频率呢......
  10. 白盒测试有哪些方法_软件测试中有哪些方法可以测试服务器稳定性
  11. lightbox的一个ajax效果
  12. Android环绕地球动画,手机也能带你进入360°全景立体影音世界?---杜比全景声体验全接触...
  13. 小爱同学app安卓版_小爱同学app下载-小米小爱同学下载2.9.21安卓版-西西软件下载...
  14. 2022年测试工程师高频面试题及答案【python篇】
  15. linux i5 i7差别,电脑处理器i5和i7的区别,如何选择?
  16. Zynq-Linux移植学习笔记
  17. 不会编辑图片大小?这几个软件你快码住
  18. 循环数142857问题 java_循环小数问题
  19. OA办公自动化系统源码
  20. pck.pdj评估代码

热门文章

  1. zabbix4.4 使用自动发现监测web网站健康状态(通过mysql表获取web地址)
  2. 初中三年级数学可以用计算机吗,不到3分钟,这份初中数学攻略被家长和学生疯狂转发!太实用了!...
  3. 区分各个SQL的概念
  4. 怎么还原计算机网络,怎么把网络协议还原为默认设置
  5. 【OpenCV】 - 图像分割之分水岭算法,watershed()函数的输出,对marker和image的改变
  6. 用vue3.0.1如何搭建仿京东的电商H5项目呢?本文实战教你
  7. 做跨境人人都是天秤座,三个月都没能建起一个店铺
  8. java获取首字母_【Java】获取中文首字母
  9. java倒序查询数据库_数据库 倒序查询
  10. 苹果LIVE PHOTOS实况照片转普通静态照片jpg