FATFS深入理解

FATFS深入理解
FATFS深入理解

一、通过格式化命令-看磁盘文件系统的建立过程

1、添加format命令,单步调试

所有的底层驱动函数都已经准备好。添加格式化命令format后,编译下载。

Format命令的执行主要是调用f_mkfs()函数,下面进行单步调试。

以下主要列出函数的主要执行步骤:

res=f_mkfs( 0, 1, 4096 ); //1表示不需要引导扇区。4096是8个扇区。

进入f_mkfs()函数,这里只列出主要执行步骤:

if (disk_ioctl(drv, GET_SECTOR_COUNT, &n_part) != RES_OK || n_part < MIN_SECTOR)

return FR_MKFS_ABORTED;这个函数调用后,n_part=0x000F,3400 = 996 352,这是SD的总块数。allocsize /= SS(fs); 等于8/*Number of sectors per cluster */

n_clst = n_part / allocsize; //等于0x1E680 = 124 544 簇。

if (n_clst >= 0xFFF5) fmt = FS_FAT32; 所以文件系统确定为FAT32类型。

n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs); 等于0x3CE = 974,表示FAT要占据974个扇区。

n_rsv = 33 - partition; 保留扇区32个。

n_dir = 0;

b_fat = b_part + n_rsv; /* FATs start sector 32扇区*/

b_dir = b_fat + n_fat * N_FATS; /* Directory start sector 0x3EE =1006,由于FAT表个数设为1个,所以目录区=FAT起始+FAT占用扇区数*/

b_data = b_dir + n_dir; /* Data start sector */

以上三项确定FAT区域、根目录区、数据区的起始扇区。

disk_ioctl(drv, GET_BLOCK_SIZE, &n) != RES_OK,这个函数调用没有正确返回可擦出扇区的总数。接下来程序会出错,因此退出,修改disk_ioctl()函数后,再次分析。把这个函数返回值直接改为32。并且把FAT表的个数定义为2.

N_FATS改为2后,根目录区、数据区的起始扇区的起始扇区变为0x7BC=1980扇区。继续往下执行。

n = (b_data + n - 1) & ~(n - 1);

n_fat += (n - b_data) / N_FATS;这两句话对fat所占扇区数进行了修正,保证擦除时,以32个扇区为一个单位。

n_clst = (n_part - n_rsv - n_fat * N_FATS - n_dir) / allocsize; =0x1E588。

tbl = fs->win; /* Clear buffer */

mem_set(tbl, 0, SS(fs)); 清零文件系统缓冲区。

mem_set(tbl, 0, SS(fs));

ST_DWORD(tbl+BS_jmpBoot, 0x90FEEB); /* Boot code (jmp $, nop) */

ST_WORD(tbl+BPB_BytsPerSec, SS(fs)); /* Sector size */

tbl[BPB_SecPerClus] = (BYTE)allocsize; /* Sectors per cluster */

ST_WORD(tbl+BPB_RsvdSecCnt, n_rsv); /* Reserved sectors */

上面的工作主要是填充引导扇区缓冲区,也就是常说的DBR扇区缓冲,等所有的参数写好,就可以写回磁盘。

ST_WORD(tbl+BS_55AA, 0xAA55); /* Signature */

if (disk_write(drv, tbl, b_part+0, 1) != RES_OK)

return FR_DISK_ERR; //这就是在写有效引导标志sec[510]=0x55, sec[511]=0xAA。

if (fmt == FS_FAT32)

disk_write(drv, tbl, b_part+6, 1); //FAT32在第六扇区有个备份引导扇区。

for (m = 0; m < N_FATS; m++) {

mem_set(tbl, 0, SS(fs)); /* 1st sector of the FAT */

if (fmt != FS_FAT32) {

n = (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00;

n |= partition;

ST_DWORD(tbl, n); /* Reserve cluster #0-1 (FAT12/16) */

} else {

ST_DWORD(tbl+0, 0xFFFFFFF8); /* Reserve cluster #0-1 (FAT32) */

ST_DWORD(tbl+4, 0xFFFFFFFF);

ST_DWORD(tbl+8, 0x0FFFFFFF);/* Reserve cluster #2 for root dir */ } //簇0和簇1保留,簇2分配给根目录区。

if (disk_write(drv, tbl, b_fat++, 1) != RES_OK)

return FR_DISK_ERR;

mem_set(tbl, 0, SS(fs)); /* Following FAT entries are filled by zero */ //接下来所有的扇区都清0,表示该簇未被占用。

for (n = 1; n < n_fat; n++) {

if (disk_write(drv, tbl, b_fat++, 1) != RES_OK)

return FR_DISK_ERR;

} //第一次是写从0x21扇区开始,总共0x3CF个扇区(第一个扇区已经写了)。第二次开始时是备份引导扇区,0x20+0x3D0=0x3F0。同理,第一扇区与0x21扇区相同,后面都清零。

Format命令要执行较长的时间,主要就是FAT表接近2000个扇区要清零。

m = (BYTE)((fmt == FS_FAT32) ? allocsize : n_dir); m=8,每簇8扇区。

do {

if (disk_write(drv, tbl, b_fat++, 1) != RES_OK)

return FR_DISK_ERR;

} while (--m); //以上部分是将根目录区的8个扇区清零,表示目录项未被占用。

if (fmt == FS_FAT32) {

ST_WORD(tbl+BS_55AA, 0xAA55);

ST_DWORD(tbl+FSI_LeadSig, 0x41615252);

ST_DWORD(tbl+FSI_StrucSig, 0x61417272);

ST_DWORD(tbl+FSI_Free_Count, n_clst - 1); //根目录区已经用掉了一簇。

ST_DWORD(tbl+FSI_Nxt_Free, 0xFFFFFFFF);

disk_write(drv, tbl, b_part+1, 1); //分别写入1号和7号扇区。

disk_write(drv, tbl, b_part+7, 1);

} //这是写FAT32文件系统的FSI扇区,包括空闲簇总数和上次分配的簇号。

FAT32文件系统的格式化到此完成。

2、再以Fdisk的方式格式化一次,这时候格式系统要写MBR扇区,FAT引导扇区不在0号扇区了。同时MBR要建立分区表,以找到DBR引导扇区。其过程与上述差不多,只是多执行了以下代码,详细过程就不叙述了。

if (!partition) {

DWORD n_disk = b_part + n_part;

mem_set(fs->win, 0, SS(fs));

tbl = fs->win+MBR_Table; //分区表从0x1BE开始。

ST_DWORD(tbl, 0x00010180); /*Partition start in CHS */ Table[0x1BE] =0x80,表明该分区是活动扇区。00表示开始柱面,01、01表示开始扇区、开始磁头。

if (n_disk < 63UL * 255 * 1024) { /* Partition end in CHS */

n_disk = n_disk / 63 / 255;

tbl[7] = (BYTE)n_disk; //表示结束的柱面。

tbl[6] = (BYTE)((n_disk >> 2) | 63); //结束的扇区。

} else {

ST_WORD(&tbl[6], 0xFFFF); //

}

tbl[5] = 254; //结束的磁头。

if (fmt != FS_FAT32) /* System ID */

tbl[4] = (n_part < 0x10000) ? 0x04 : 0x06;

else

tbl[4] = 0x0c; // 表示该分区类型为win95 FAT32

ST_DWORD(tbl+8, 63); /*起始扇区0x3F in LBA */

ST_DWORD(tbl+12, n_part); /*分区的大小,总扇区数减去MBR及其占据的一个柱面。*/

ST_WORD(tbl+64, 0xAA55); /* Signature */

if (disk_write(drv, fs->win, 0, 1) != RES_OK)

return FR_DISK_ERR;

partition = 0xF8; //MBR标志。

} else {

partition = 0xF0;

}

3、观察在有MBR区域的情况下,如何检查文件系统

fmt = check_fs(fs, bsect = 0); /*检查0扇区的时候,没有发现FAT文件系统扇区,但是有0x55 0xAA标志,说明这是有效磁盘,但是返回1. */

if (fmt == 1) { /* 表明可能存在分区*/

/* Check a partition listed in top of the partition table */

tbl = &fs->win[MBR_Table + LD2PT(vol) * 16]; /* Partition table */

if (tbl[4]) { 实际这里应该是0x0c,表示FAT32系统。

bsect = LD_DWORD(&tbl[8]); /* 这个是文件系统引导扇区的号码。*/

fmt = check_fs(fs, bsect); /* 再到这个扇区检查是否存在FAT文件系统标志。*/ } }

执行过后,仍然能够建立完整的文件系统信息结构体,只是里面的FAT分配起始扇区、数据区起始扇区地址相对没有MBR的时候改变了,其它都差不多。

二、将SD卡格式化成具有两个分区的磁盘。

1、目的

(1)深入理解MBR、DPT等概念。

(2)修改ff.c中的f_mkfs函数,得到一个新函数,f_format(u8 partition,u16 allocsize),前一个参数是指磁盘等分的个数,接受1、2、3、4四个参数,默认为1,最大为4。后一个参数是指每簇占用的字节数。

(3)添加命令fdisk,调用上述函数。执行完成后,用读卡器在PC上读取该SD卡,应该显示两个可移动磁盘。

2、f_format()函数的编写

首先新建一个文件fext.c,该文件就实现一个函数f_format.c,首先将f_mkfs()函数复制过来,在此基础上修改。

编译后,首先解决警告和错误:包含头文件ff.h和diskio.h。引用了ff.c中的静态函数mem_set()和mem_clr(),复制过来。定义Null为0。将FATFS * FatFs[_Drives]做外部声明。

同时发现,不同c源文件中#define 同样的宏相互之间是不影响的。说明预处理的时候是一个一个文件处理的,不检查相互之间的关联。但同一个文件中,一个宏不能两次定义。

#ifndef NULL

#define NULL 0

#endif //采取这种方式,主要是防止其他包含的头文件也对NULL进行了定义。

函数中主要修改的地方就是:

n_part = n_part /drv; //进行drv等分。每个磁盘的扇区总数就是这么多。

在DPT对应增加的分区部分,填好分区表16个字节。特别重要的是四个地方:0字节写为00或0x80,第四字节写入0xc0表示FAT32系统。(第一次调试找不到新磁盘,就是由于这个字节默认为0)。第8-11写入分区引导扇区的线性扇区地址。第12-15写入该磁盘分区的大小。

for ( i="0"; i

b_fat=b_part + n_rsv;

3、其它修改的地方

定义_DRIVE为2,定义_MULTI_PARTITION为1,表示支持多分区。同时初始化磁盘物理驱动与分区号转换结构体(每个逻辑磁盘对应一个结构体)。

主程序中也要定义两个文件系统结构体,每个对应一个磁盘。然后分别调用f_mount()函数。

4、调用执行

void UartCmdFdisk(u8 argc,void **argv)

{

FRESULT res;

res=f_format( 2, 2048 ); /2表示格式化成两个磁盘。一簇是4个扇区、2048字节。

执行完这个函数后,磁盘被分成两个分区。

实际结果是,命令界面上可以查询到两个分区。但是利用读卡器放到PC上,却只看到250M的第一分区,不知什么原因。

三、添加命令fchdrive、fmove。

1、目的

(1)fchdrive:在支持相对目录的情况下改变当前逻辑磁盘。

(2)fmove:两个参数,将文件移动到另一个位置,可以改名,也可以保留原名。

2、fchdrive 命令的实现

(1)添加命令支持

这个不再赘述。

(2)实现代码

void UartCmdFChDrive(u8 argc,void **argv){

BYTE Drive;

FRESULT res="FR"_INV ALID_DRIVE;

if ( *( (BYTE*)argv[1]+1 )==':' ){ 检查参数,是不是1:类似格式。

Drive =*( (BYTE*)argv[1]) - '0'; 取出磁盘号

res=f_chdrive( Drive ); }

if ( res!=FR_OK) { Uart_PutString( "Invalid path!\r\n");return;}

Uart_PutString( "Current disk is changed!\r\n");

}

*( (BYTE*)argv[1])这个意思是先将argv[1]转换为BYTE指针,再取出里面的数据(BYTE型,一个字节。)

以下是实现的截图:

3、fmove命令的实现

(1)这个命令带两个参数:第一个是文件的原有路径,第二个是新路径,同时可以更改文件名。(2)实现的原理

以创建新文件的方式打开新路径的文件。这样会创建一个目录项,填充一个文件信息结构体。然后打开原有路径的文件,也会得到一个文件信息结构体。将旧结构体的文件大小、起始簇号复制到新的结构体,然后更新新文件的信息。然后删除原有路径的文件。移动操作完成。

(3)代码编写

需要两次打开文件,所以需要两个文件信息结构体。

res = f_open ( &FileOld, (const char *)argv[1], FA_WRITE );

res = f_open ( &FileNew, (const char *)argv[2], FA_CREATE_NEW );

FileNew.fsize = FileOld.fsize; // 改变新文件的大小等于原文件

https://www.360docs.net/doc/0f9163845.html,_clust = https://www.360docs.net/doc/0f9163845.html,_clust; //新文件的簇等于原文件的簇。

FileNew.flag |= FA__WRITTEN; //文件属性已改变,需要更新

res=f_close ( &FileNew ); //关闭时进行更新。

res=f_unlink ( (const char *)argv[1] ); //删除原文件

编译,下载测试,功能正常。以下是实现的截图。

四、添加命令fcopy、fpath。

1、目的

(1)fcopy:复制功能,原文件保留,新位置建立文件。

(2)fpath:在支持相对路径的情况下,显示当前磁盘的当前目录。

2、fcopy命令的实现

(1)复制命令的实现思路

首先要打开两个文件,原文件以可读FA_READ的方式打开,新文件以FA_CREATE_NEW和FA_WRITE的方式打开。

然后建立一个循环,每次从原文件读出一个扇区的数据,写入新文件。然后检查原文件结束标志,已到结尾,则跳出循环。

关闭两个文件,更新文件信息。

(2)代码实现

res = f_open ( &FileOld, (const char *)argv[1], FA_READ );

res = f_open ( &FileNew, (const char *)argv[2], FA_CREATE_NEW | FA_WRITE );

for ( ; ; ){

res = f_read ( &FileOld, (void*)FileBuf, 512, &ByteRead );

res = f_write ( &FileNew, ( const void *)FileBuf, ByteRead, &ByteWrite );

if (FileOld.fptr== FileOld.fsize) )break;

}

f_close (&FileOld);

f_close (&FileNew);

编译,下载,功能正确。

3、fpath命令的实现

(1)这个命令实现起来稍微有些难度

首先要获取当前磁盘和当前磁盘的当前目录所在簇,也就是FatFs[Drive]->cdir,如果为0,表明是在磁盘根目录,显示0:或者1:。如果该簇号等于根目录所在簇号,当前目录也是在跟目录。

如果不是在根目录,那就要逐层往上搜索了。根据f_opendir (DIR,..目录)可以回溯到上层目录,DIR结构体得到了上层目录(X+1)的起始簇号,目录项指针指向第0项。用f_readdir()逐步读出目录项属性,得到FILINFO结构体。如果其簇号等于文件系统的当前搜索簇号,则其名称就是所要得到的本层目录名。如果是根目录下则为0:/X目录名。

当前搜索簇号设为(X+1)的起始簇号。再次调用f_opendir( DIR,..目录),此次得到(X+2)的起始簇号,判断是否根目录。查找当期搜索簇号在(X+2)目录层中对应的目录项,并获取X+1层的目录名。如果是在根目录,则为0:/X+1目录名/X目录名。

循环直到到达根目录跳出搜索。

目录名缓冲区的处理方法。定义总长度为100字节。Path[99]=0;初始化时先让指针指向Path【99】。

得到一个目录,向前移动名称那么长,复制名称。再往前移动1,添加’/’标志。如果是根目录添加’:’,往前移动1,在添加‘驱动号’,然后可以显示整个字符串。(2)代码实现

for ( ; ; ){

if ( CurClust == 0 || CurClust == CurFileSys->dirbase ) {

PathPtr--;

*PathPtr--=':'; /

*PathPtr = CurDrive+'0'; //如果当前簇号对应根目录。

break; }

res = f_opendir ( &DirInf, ".." ); //第一次执行时,DIR结构体的开始簇号变为X+1层目录的簇号//第二次时,变为X+2层目录的簇号。

if ( res!= FR_OK ) break;

do {

res = f_readdir ( &DirInf, &FileAttrib );

TempClust = FileAttrib.sclust;

if ( TempClust == CurClust ) break; //如果该目录项的簇号等于当前搜索簇号,它的名称就是当前需要的目录名

} while( res == FR_OK );

if ( res!= FR_OK ) break;

DirLen= Str_Length ( (const char*)FileAttrib.fname ); //这里要得到字符串的长度。

PathPtr -= DirLen; //文件指针往后退目录名长度

mem_cpy ( (void *)PathPtr, ( const void*)FileAttrib.fname, DirLen);

PathPtr--;

*PathPtr='/'; //添加文件间隔/符号。

CurClust = DirInf.sclust; //当前搜索簇号跟着上移。

}

Uart_PutString( PathPtr); //这是显示的当前目录。

Uart_PutString( "\r\n");

编译,下载,显示两层目录是正确的。但是目录一旦到第三层,就进入死循环。还要接着调试。

(3)调试

经调试发现res = f_opendir ( &DirInf, ".." )调用后,并不能每次都自动回溯到上一层目录。

所以改为:f_opendir ( &DirInf, (const char*)ddPtr),ddPtr初始化成“..”,然后每循环一次,前面加上”../”,第二次变为”../..”,第三次变为“../../.. “,这样目录不断回溯。

以下是该命令实现的截图。

五、使用文件字符串处理的功能

1、目的

验证f_printf()函数的功能,学习变参数函数的编写和使用方法。

掌握格式化字符串的一些定义和用途。

2、有关格式控制串

格式控制串总是以%开始,后跟一些参数:

%【flags】【宽度】【精度控制】type。

前面三个是可选,而type是必须的参数。

(1)flag用于控制输出的符号+(+-)、对齐方式-(左对齐)等。

(2)宽度只控制输出的宽度,03,当字符数小于3个时,左边补0.

(3)精度控制,主要针对浮点数。比如12.3456 如果%.2则只输出2位,变成12.34。

(4)类型是必须的。这里主要分析这个。

3、源代码分析

int f_printf (

FIL* fil, /* Pointer to the file object */

const char* str, /* Pointer to the format string */

... /* Optional arguments... */

){ va_list arp;

UCHAR c, f, r;

ULONG val;

char s[16];

int i, w, res, cc;

va_start(arp, str); //arp实际是一个通用类指针,指向str后的第一个参数。

for (cc = res = 0; cc != EOF; res += cc) {

c = *str++;

if (c == 0) break; /* End of string */

if (c != '%') { /* Non escape cahracter */

cc = f_putc(c, fil); //如果不是%,表示正常字符,写入文件

if (cc != EOF) cc = 1; //cc是本次写对应的字符数字。当然如果写入不成功,返回EOF,则跳出循环continue; //res是总共写入的数字。

}

w = f = 0; //从此处开始表示遇到了%后的处理

c = *str++; //取出下一个字符。

if (c == '0') { /* Flag: '0' padding */

f = 1; c = *str++; //如果是字符0,表示要控制宽度,flag第0位标志置位。取出下一字符

}

while (c >= '0' && c <= '9') { /* Precision */

w = w * 10 + (c - '0');

c = *str++; //依次取出后面的字符,如遇到034,则w=34。字符输出}

if (c == 'l') { /* Prefix: Size is long int */

f |= 2; c = *str++; //如果遇到字符'l',表示长整形,标志第1位置位。}

if (c == 's') { /* Type is string */

cc = f_puts(va_arg(arp, char*), fil); //如果遇到‘s’标志,将arp转换为char*指针,并指向下一个参数。continue; //cc是字符串的长度,本次输入文件的字符数。

}

if (c == 'c') { /* Type is character */

cc = f_putc(va_arg(arp, int), fil); //字符以int类型出现,要占四个字节。

if (cc != EOF) cc = 1;

continue;

} r = 0; //如果字符'0'和'l'后,不是s和c,则下面继续处理

if (c == 'd') r = 10; /* Type is signed decimal */

if (c == 'u') r = 10; /* Type is unsigned decimal *///十进制

if (c == 'X') r = 16; /* Type is unsigned hexdecimal */

if (r == 0) break; /* Unknown type */

if (f & 2) { /* Get the value */

val = (ULONG)va_arg(arp, long);

} else {

val = (c == 'd') ? (ULONG)(long)va_arg(arp, int) : (ULONG)va_arg(arp, unsigned int);

} //如果设置了'l',标志,则将数据转换为长整形。从参数中取出来。

/* Put numeral string */ //下面是将数字转换为字符串。

if (c == 'd') {

if (val & 0x80000000) {

val = 0 - val;

f |= 4; //标志第二位表明这是个负数。

} }

i = sizeof(s) - 1; s[i] = 0; //字符串最后一为以'\0'结束。i指向尾端,往前扩展。

do { //同时处理十进制和十六进制。

c = (UCHAR)(val % r + '0'); //十进制时,1234/10,余数4+‘0’,变成字符

if (c > '9') c += 7; //十六进制,3A表示大写A,但实际的字符A是0x41,中间差7.

s[--i] = c; //前一位存储该字符。

val /= r; //val变成123,也就是把尾端一位去掉。

} while (i && val); //最多存储15位,要不然溢出。

if (i && (f & 4)) s[--i] = '-'; //如果为负数,还要加上符号标志。

w = sizeof(s) - 1 - w; //要求的宽度计算。8位宽,则填充从第7位开始。7-14,正好8位。

while (i && i > w) s[--i] = (f & 1) ? '0' : ' ';//如果0填充置位填充0,否则填充空格。i退到0,或者i推导W都结束填充。

cc = f_puts(&s[i], fil);

} va_end(arp);

return (cc == EOF) ? cc : res;

}

把代码看了一遍,基本还是能看懂。

4、移植。

(1)添加命令fstring,该命令一个参数,是用户字符串。以附加的写入到指定的文件fstring.txt。(2)实习方法

以写文件的方式,打开文件,然后指针移动到文件末尾。调用代码f_printf(&File,”输入字符串%s/r/n”,(const char*)argv[1])来写入文件。

(3)代码实现

res=f_open( &FileStr, "0:/doc/fstring.txt",FA_WRITE ); //

res=f_lseek( &FileStr, FileStr.fsize );

f_printf (&FileStr,"用户输入:%s\r\n",(char*)argv[1] );

f_close (&FileStr );

功能比较简单,测试通过。

六、支持长文件名(一)。

1、代码页的功能

(1)在原来的程序中,我把#define _CODE_PAGE 936,代码页定义为936.

这时候可以在磁盘上新建中文名称的文件夹和文件,(通过fwrite命令实现,只要数目小于4个就行,也可以用fread命令读出来),也可以显示中文文件名。(通过命令flist来实现)。

(2)我把#define _CODE_PAGE 1,代码页定义为1后,调用flist能正常显示中文名。但是调用fread 和fwrite命令不能读取和创建中文名文件了。

进入代码分析,显示时关键在函数get_fileinfo(),它原封不动的将系统标准名转换为一般字符串,对字符串不做任何处理,送到串口以后自然可以正常显示。

但是读取文件和写入文件时,首先调用f_open()函数,进入follow_path()函数,然后调用create_name (),当它遇到大于0x80 的字符时,产生如下效果:

if (c >= 0x80) { /* Extended char */

#ifdef _EXCVT

c = cvt[c - 0x80]; /* Convert exten

d char (SBCS) */

#else

b |= 3; /* Eliminate NT flag if ext char is exist */

#if !_DF1S /* ASCII only cfg */

return FR_INV ALID_NAME;

#endif

#endif

}

返回FR_INV ALID_NAME,所以它不识别中文GB2312(OEM)代码。

如果定义了define _CODE_PAGE==936,则同时就会定义DF1S,也同时定义了IsDBCS1(c)和IsDBCS2(d)。因此可以将中文OEM代码转换为标准文件名,存储于文件系统的目录项里面。

2、如果定义长文件名_USE_LFN,而不定义UNICODE码。有什么效果呢?

根据要求,先要添加ff_convert() and ff_wtoupper()两个函数。

结果发现,光两个转换表就要150K左右,我这个128k的空间是远远不够了。只能看代码而不能测试了。不定义UNICODE码的含义是用户提供的路径名不是以UNICODE形式出现的。

以下,就只能纸上谈兵了。

3、如果0:/doc 目录下有一个文件名(这是一个very long的文件.它里面是空的.txt文档)。

如果要显示这个目录下所有的文件信息,我会在命令界面上输入:

Flist 0:/doc。

执行这个命令,程序首先调用

F_opendir(DIR dj,const void *path)函数,对输入的路径进行分析。这个函数首先调用函数chk_mounted()检查磁盘上是否有文件系统,如果已经取得了信息,则很快返回。如果没有,则初始化磁盘,并读取信息,填充文件系统信息结构体FATFS。它去掉了路径前面的0:。

F_opendir接下来调用follow_path(dj, path),这个函数根据路径填充目录信息结构体。这个函数首先设置dj->sclust,如果前面有/,会去掉这个符号。接下来一直读取目录名直到下一个/。这个工作调用create_name(dj, &path)来完成。

进入create_name(dj, &path),首先做的工作是根据路径填充dj->lfn指向的内存单元,由于我的这个目录是短文件名:doc,所以填入缓冲区的是‘d0‘,’o0‘,’c0‘,由于目录到此结束,所以NS_LAST 属性被设置,表明已经到路径末尾。同时lfn[di] = 0,di此时指向c0后面那个内存单元。注意,存储进长目录区是以unicode的形式,而path用的是ANSi码,汉字两个字节,英文字母一个字节。create_name(dj, &path)继续执行,mem_set(dj->fn, ' ', 11),先将dj结构体的标准短文件名填充空格。if (si) cf |= NS_LOSS | NS_LFN通过这句话的判断,长文件名前面没有空格和.,没有超出8.3格式。当然后面还要继续判断。执行while (di && lfn[di - 1] != '.') di—这句后,di=0,表示没有找到扩展名(doc 没有扩展名)。dj->fn[i++] = (BYTE)w,通过这个方式将doc存进了短文件名存储区。dj->fn[NS] = cf,短文件名存储区12个字节,前11个是标准短文件名,最后一个是路径属性字节:是否.目录、大小写标志,超出8.3格式,是否长文件名、是否路径结束标志等等。

所以create_name(dj, &path)的工作主要是根据路径填充dj->lfn和dj->fn,前者每个字符16Byte,以‘\0’结尾,后者12个字节,以路径的整体属性结尾。

执行路径返回follow_path(dj, path),接下来调用dir_find(dj),这个函数的作用是在当前目录(对应dj->sclust)下,搜索dj->lfn和dj->fn对应的目录项,找到以后让dj->index和dj->dir指向该目录项的数据。追踪那个进入该函数。

在函数dir_find(dj)里,首先dir_seek(dj, 0),将索引定位于0,目录第一项。ord = sum = 0xFF长目录项索引和校验和设为-1。c = dir[DIR_Name]取出目录项的第一个字符进行判断,a = dir[DIR_Attr] & AM_MASK取出属性进行判断。建立一个循环,不断移动目录缓冲(每次下移32个字节),通过dir_next(dj, FALSE)来实现。当找到”doc “目录项时,if (!(dj->fn[NS] & NS_LOSS) && !mem_cmp(dir, dj->fn, 11)) break跳出循环,此时的有效信息就是dj->sclust加上dj->index和dj->dir,它指向根目录里的“doc”目录项。

执行路径返回follow_path(dj, path),由于last = *(dj->fn+NS) & NS_LAST,标志被置位,很快跳出路径分解的循环,返回到F_opendir(DIR dj,const void *path)。通过下面这个计算:

dj->sclust = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO)真正得到了分配给doc目录的起始簇的地址。接下来就可以读取0:/doc 目录下所有的目录项,并显示它包含文件、目录的属性信息了。

回到主程序执行路径,接下来调用:

f_readdir()这个函数功能是根据DIR结构体提供的信息,填充文件属性结构体,包括文件名字符串、

文件大小、文件修改日期等。进入该函数进行追踪。这里就快要找到我的长文件名目录项《这是一个very long的文件.它里面是空的.txt文档》了,它在目录项里是怎样的存在形式呢?

它共有29个字(包括空格和.),共占据3个长目录项和一个短目录项:其格式应该如下。

f_readdir()这个函数调用dir_read()函数,读取各个目录项的信息,然后调用get_fileinfo()函数得到文件的各项信息。下面进入dir_read()进行跟踪,看它是怎样对待长目录项的。

进入dir_read()函数,首先ord, sum = 0xFF,读取属性a = dir[DIR_Attr] & AM_MASK,if (a == AM_LFN),也就是当遇到长目录索引“43”的时候,sum = dir[LDIR_Chksum];c &= 0xBF; ord = c; dj->lfn_idx = dj->index;取得校验和,取得索引(这里是3),使长目录索引指向“43”目录项的索引号。如果pick_lfn(dj->lfn, dir)返回TRUE,则索引自动ord=ord-1变为2。进入pick_lfn(dj->lfn, dir),它的作用是将当前目录项里的长文件名部分写入dj->lfn指向的名字缓冲区。先从偏移26开始存入“t文档”三个unicode字符,然后写入0,返回TRUE。也就是ord=2。

继续执行,dir_next(dj, FALSE),dj->index指向下一项,a = dir[DIR_Attr] & AM_MASK,重新取得属性。此时c = dir[DIR_Name]=02,满足(c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dj->lfn, dir))这个表达式,所以索引又被设置为ord=1。

同上,再次读取ord=1的那一项,填充长文件名缓冲区,至此unicode名称已经完全存入dj->lfn指向的缓冲区,并且ord=0,表明长目录项已经结束。

通过dir_next()再次循环,接下来dj->index指向对应的短目录项,只要sum_sfn(dir)计算出来的校验和与前面长目录项里取得的校验和相等,dir_read()函数的任务就算完成了。它获得的信息包括:dj->lfnidx(长目录项开始索引),dj->lfn(完整的unicode长文件名),dj->index和dj->dir指向短目录项。执行路径回到f_readdir()。

f_readdir()函数接下来调用get_fileinfo(dj, fno)获取目录项的详细信息。追踪该函数的执行。这个函数共获取六个信息:大小、属性、修改时间、日期、短文件名、长文件名字符串(通过读取dj->lfn指向的缓冲区,并将unicode转换为OEM代码)。有了这个文件属性结构体的数据,用户就可以在串口终端显示目录下所有目录项的信息了。

原理图元件库的设计步骤(精)

原理图元件库的设计步骤 一. 了解欲绘制的原理图元件的结构 1. 该单片机实际包含40只引脚,图中只出现了38只, 有两只引脚被隐藏,即电源VCC(Pin40和GND(Pin20。 2. 电气符号包含了引脚名和引脚编号两种基本信息。 3. 部分引脚包含引脚电气类型信息(第12脚、第13脚、第32至第39脚。 4. 除了第18脚和第19脚垂直放置,其余水平放置。由于VCC及GND隐藏,所以放置方式可以任意。 5. 一些引脚的名称带有上划线及斜线,应正确标识。

二. 新建集成元件库及电气符号库 1. 在D盘新建一个文件夹D:/student 2. 建立一个工程文件,选择File/New/Project/Integrated Library,如:Dong自制元件库.LibPkg 3. 新建一个电气符号库,选择File/New/Library/Schematic Library,如:Dong自制元件库.SchLib 4. 追加原理图元件 在左侧的SCH Library标签中,点击库元件列表框(第一个窗口下的Add(追加按钮,弹出New Component Name对话框,追加一个原理图元件,输入8051并确认,8051随即被添加到元件列表框中。 三. 绘制原理图元件 1. 绘制矩形元件体 矩形框的左上角定位在原点,则矩形框的右下脚应位于(130,-250。 注意:图纸设置中各Grids都设为10mil。 2. 放置引脚 (1P0.0~P0.7的放置及属性设置 单击实用工具面板的引脚放置工具图标,并按Tab键,系统弹出【引脚属性】对话框: 【Display Name显示名称】文本框中输入“P0.0”; 【Designator标识符】文本框中输入“39”;

Prote原理图常用元件库及常用元件

Protel DXP 2004 原理图常用元件库及学用元件 提示:搜索元件时,特殊符号用“ *”号代替,在元件名称前与后分别加“ *”,可提高搜索可靠性。 元件库常用元件

Cap C? CB? 蜂鸣器 Buzzer 电容(无极性) 穿心电容器 Cap Feed 电容(有极性) Cap Pol2 MK? 麦克风 Mic 1 可调电容 Cap Var 电路熔断器 Circuit Breaker Circuit Breaker Cap Feed lOOpF Cap Pol2 lOOpF C? Cap Var lOOpF LS? R Buzzer C? Cap lOOpF

肖特基二极管 D Schottky 变容二极管 D Varactor D? * D Schottky D? -MH D Varactor 齐纳二极管 D Zener D? D Zener 隧道二极管 D Tu nn ell D? D Tunnell 保险管Fuse 1 F? 1 1 11 11 Fuse 1 铁芯电感In ductor Iron L? Inductor lion lOniH 可调电感In ductor Adj L? Inductor Adj IO111H

扬声器Speaker LS? Speaker 增强型N沟道MOS管M0SFET-2GN Q? M0SFET-2GN 增强型P沟道MOS管MOSFET-2GP Q? M0SFET^2GP 增强型N沟道MOS管(衬底有引出线)MOSFET-N3 i Lil M0SFET-N3 耗尽型N沟道MOS管 (衬底有引出线) MOSFET-N4 Q? 增强型P沟道MOS管(衬底有引出线)MOSFET-P3 Q? M0SFET-P3 NPN型光电二极 管 Photo PNP

FAT文件系统原理详细介绍

FAT文件系统原理详细介绍 2012-03-29 23:09 434人阅读评论(0) 收藏举报 FAT文件起源于70年代末80年代初,用于微软的MS-DOS操作系统。它开始被设计成一个简单的文件系统用于小于500K的软件盘。后来被功能被大大增强用于支持越来越大的媒质。现在的文件系统有FAT12,FAT16和FAT32三种子类。 FAT12是最早的一版,主要用于软盘,它对簇的编址采用12bit宽度的数,所以称为FAT12。12bit的地址可以寻址4096个簇,事实上在FAT12中只能寻址4078个簇(在Linux 下可寻址4084个簇),有一些簇号是不能用的,在后面会给出具体的说明。磁盘的扇区是用16bit的数进行计算的,所以磁盘的容量就被局限在32M空间之内。 在FAT16中,采用了16bit宽的簇地址,32bit宽扇区地址。虽然32bit的扇区地址可以寻址2^32*512,约2个TB的容量,但于由规定每簇最大的容量不超过1024*32,所以FAT16文件系统的容量也就限制到了2^16*1024*32,大约2.1GB的空量,并且实际还达不到这个值。 FAT32文件系统使用了32bit宽的簇地址,所以称为FAT32。但在微软件的文件系统中只使用了低28位,最大容量为2^28*1024*32,约8.7TB的空量。有的人认为32bit全用,最大容量为2^32*1024*32,这种说法是不正确的。 虽然FAT32具有容纳近乎8.7TB的容量,但实际应用中通常不使用超过32GB的FAT32分区。WIN2000及之上的OS已经不直接支持对超过32GB的分区格式化成FAT32,但WIN98依然可以格式化大到127GB的FAT32分区,但不推荐这样做。 下面是一个FAT分区的构成概况 需要说明的是: 1.引导扇区和其他保留扇区一起称为保留扇区,而其他保留扇区是可选的,当没有时候,引导扇区后紧跟的就是FAT表1 2.根目录区是仅FAT12/16才有,FAT32的目录项位于数据区。由于FAT12/16的根目录区是一个固定的区域,所以它的根目录的项数是有限制的,意即不能在根录建立超过这个定数的目录项数。 (一)引导扇区与BPB BPB(BIOS Parametre Block)是FAT文件系统中第一个重要的数据结构,它位于该FAT分区的第一个扇区,同时也属于FAT文件系统基本区域的保留区, 在下面的描述中。凡名称以BPB_开头的都是BPB的一部分,凡名称与BS_开头的项

Altium Designer10原理图常用库文件

原理图常用库文件: Miscellaneous Devices.IntLib Miscellaneous Connectors.IntLib PCB元件常用库: Miscellaneous Devices PCB Miscellaneous Connector PCB.PcbLib 部分分立元件库元件名称及中英对照 AND 与门 ANTENNA 天线 BA TTERY 直流电源 BELL 铃,钟 BVC 同轴电缆接插件 BRIDEG 1 整流桥(二极管) BRIDEG 2 整流桥(集成块) BUFFER 缓冲器 BUZZER 蜂鸣器 CAP 电容 CAPACITOR 电容 CAPACITOR POL 有极性电容 CAPV AR 可调电容 CIRCUIT BREAKER 熔断丝 COAX 同轴电缆 CON 插口 CRYSTAL 晶体整荡器 DB 并行插口 DIODE 二极管 DIODE SCHOTTKY 稳压二极管 DIODE VARACTOR 变容二极管 DPY_3-SEG 3段LED DPY_7-SEG 7段LED DPY_7-SEG_DP 7段LED(带小数点) ELECTRO 电解电容 FUSE 熔断器 INDUCTOR 电感 INDUCTOR IRON 带铁芯电感INDUCTOR3 可调电感 JFET N N沟道场效应管 JFET P P沟道场效应管原理图常用库文件:Miscellaneous Devices.IntLib Miscellaneous Connectors.IntLib PCB元件常用库: Miscellaneous Devices PCB Miscellaneous Connector PCB.PcbLib

FATFS深入理解

一、通过格式化命令-看磁盘文件系统的建立过程 1、添加format命令,单步调试 所有的底层驱动函数都已经准备好。添加格式化命令format后,编译下载。 Format命令的执行主要是调用f_mkfs()函数,下面进行单步调试。 以下主要列出函数的主要执行步骤: res=f_mkfs( 0, 1, 4096 ); //1表示不需要引导扇区。4096是8个扇区。 进入f_mkfs()函数,这里只列出主要执行步骤: if (disk_ioctl(drv, GET_SECTOR_COUNT, &n_part) != RES_OK || n_part < MIN_SECTOR) return FR_MKFS_ABORTED;这个函数调用后,n_part=0x000F,3400 = 996 352,这是SD的总块数。allocsize /= SS(fs); 等于8/*Number of sectors per cluster */ n_clst = n_part / allocsize; //等于0x1E680 = 124 544 簇。 if (n_clst >= 0xFFF5) fmt = FS_FAT32; 所以文件系统确定为FAT32类型。 n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs); 等于0x3CE = 974,表示FAT要占据974个扇区。 n_rsv = 33 - partition; 保留扇区32个。 n_dir = 0; b_fat = b_part + n_rsv; /* FATs start sector 32扇区*/ b_dir = b_fat + n_fat * N_FATS; /* Directory start sector 0x3EE =1006,由于FAT表个数设为1个,所以目录区=FAT起始+FAT占用扇区数*/ b_data = b_dir + n_dir; /* Data start sector */ 以上三项确定FAT区域、根目录区、数据区的起始扇区。 disk_ioctl(drv, GET_BLOCK_SIZE, &n) != RES_OK,这个函数调用没有正确返回可擦出扇区的总数。接下来程序会出错,因此退出,修改disk_ioctl()函数后,再次分析。把这个函数返回值直接改为32。并且把FAT表的个数定义为2. N_FATS改为2后,根目录区、数据区的起始扇区的起始扇区变为0x7BC=1980扇区。继续往下执行。 n = (b_data + n - 1) & ~(n - 1); n_fat += (n - b_data) / N_FATS;这两句话对fat所占扇区数进行了修正,保证擦除时,以32个扇区为一个单位。 n_clst = (n_part - n_rsv - n_fat * N_FATS - n_dir) / allocsize; =0x1E588。 tbl = fs->win; /* Clear buffer */ mem_set(tbl, 0, SS(fs)); 清零文件系统缓冲区。 mem_set(tbl, 0, SS(fs)); ST_DWORD(tbl+BS_jmpBoot, 0x90FEEB); /* Boot code (jmp $, nop) */ ST_WORD(tbl+BPB_BytsPerSec, SS(fs)); /* Sector size */ tbl[BPB_SecPerClus] = (BYTE)allocsize; /* Sectors per cluster */ ST_WORD(tbl+BPB_RsvdSecCnt, n_rsv); /* Reserved sectors */ 上面的工作主要是填充引导扇区缓冲区,也就是常说的DBR扇区缓冲,等所有的参数写好,就可以写回磁盘。 ST_WORD(tbl+BS_55AA, 0xAA55); /* Signature */ if (disk_write(drv, tbl, b_part+0, 1) != RES_OK) return FR_DISK_ERR; //这就是在写有效引导标志sec[510]=0x55, sec[511]=0xAA。 if (fmt == FS_FAT32) disk_write(drv, tbl, b_part+6, 1); //FAT32在第六扇区有个备份引导扇区。 for (m = 0; m < N_FATS; m++) { mem_set(tbl, 0, SS(fs)); /* 1st sector of the FAT */ if (fmt != FS_FAT32) { n = (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00; n |= partition; ST_DWORD(tbl, n); /* Reserve cluster #0-1 (FAT12/16) */ } else { ST_DWORD(tbl+0, 0xFFFFFFF8); /* Reserve cluster #0-1 (FAT32) */

FATFS文件系统剖析1

FATFS文件系统剖析1: FAT16: 数据按照其不同的特点和作用大致可分为5部分:MBR区、DBR区、FAT区、DIR区和DATA区,相比fat12多了DBR区 Main boot record: MBR(0--1bdh)磁盘参数存放 DPT(1beh--1fdh)磁盘分区表 55,aa 分区结束标志 DBR(Dos Boot Record)是操作系统引导记录区的意思 FAT区(有两个,一个备份):对于fat16,每一个fat项16位,所以可寻址的簇项数为65535(2的16次方)。而其每簇大小不超过32k,所以其每个分区最大容量为2G。fat32,每一个fat项32位,可寻址簇数目为2的32次方。 DIR区(根目录区):紧接着第二FAT表(即备份的FAT表)之后,记录着根目录下每个文件(目录)的起始单元,文件的属性等。定位文件位置时,操作系统根据DIR中的起始单元,结合FAT表就可以知道文件在硬盘中的具体位置和大小了。 DATA区:实际文件内容存放区。 FAT32: 暂时放在这里,不讨论! Fatfs:嵌入式fat文件系统,支持fat16,fat32。 包含有ff.h,diskio.h,integer.h,ffconf.h 四个头文件以及ff.c 文件系统实现。当然要实现具体的应用移植,自己要根据diskio.h实现其diskio。c 底层驱动。 diskio.h : 底层驱动头文件 ff.h : 文件系统实现头文件,定义有文件系统所需的数据结构 ff.c : 文件系统的具体实现

如下开始逐个文件加以分析: integer.h :仅实现数据类型重定义,增加系统的可移植性。 ffconf.h : 文件系统配置---逐个配置,先配置实现一个最小的fat文件系统,下面来分析各配置选项: #define _FFCONF 8255 //版本号 #define _FS_TINY 0 /* 0:Normal or 1:Tiny */ //在这里与先前版本有些许变化,是通过配置头配置两种不同大小的文件系统,这里配置为0。 #define _FS_READONLY 1//定义文件系统只读,也就不能写修改,在此定义为1,这样文件系统会大大缩小,简化学习理解过程。 #define _FS_MINIMIZE 3 /* 0 to 3 */ 这个选项是用于过滤掉一些文件系统功能,为0时是全功能,3是功能实现最小 #define _USE_STRFUNC 0 /* 0:Disable or 1/2:Enable */ 是否使用字符串文件接口,为0,不使用 #define _USE_MKFS 0 /* 0:Disable or 1:Enable */ 制作文件系统,这个功能实现是还要_FS_READONLY=0 #define _USE_FORWARD 0 /* 0:Disable or 1:Enable */ f_forward function 实现还需_FS_TINY =1 #define _USE_FASTSEEK 0 /* 0:Disable or 1:Enable */ 快速查找功 能 #define _CODE_PAGE 936 // 936 - Simplified Chinese GBK (DBCS, OEM, Windows) #define _USE_LFN 0/* 0 to 3 */ 0:不使用长文件名 #define _MAX_LFN 255/* Maximum LFN length to handle (12 to 255) */ #define _LFN_UNICODE 0 /* 0:ANSI/OEM or 1:Unicode */

详细了解并学习FatFS文件系统的基本原理

详细了解并学习FatFS文件系统的基本原理 最近做的spi flash,本打算弄个文件系统,由于之前用过了JFFS、YAFFS和TrueFFS,代码量都相当的大,这次想找款代码量不那么吓人的,学习一下,听说配置会相对复杂一些。选来选去,最终选定了FatFS,代码量足够的小,最新的R0.09版本只有1个.c文件(当然,还有一个底层的要自己写,option文件夹里的无视),老点版本就更小了。而且更新很频繁,用户量也够大,就选定它了。尽管最后由于硬件和项目原因未能实际的移植它到vxWorks,但学过的还是要记录下。 在这里http://elm-chan/fsw/ff/00index_el下载源码,只有800多K,小的可怜,还可以下载示例程序,有A VR、Win32、lpc等多平台已实现的方案。打开看src文件夹,一个opTIon 文件夹、00readme.txt、diskio.h、ff.c、ff.h、ffconf.h和interger.h。移植时需要修改的文件主要包括ffconf.h和interger.h,后者是在它的定义与目标平台上的有冲突,或者用的不习惯时修改的。 在做具体修改之前,先大概阅读下FatFS的源代码,可以先读integer.h,了解所用的数据类型,然后是ff.h,了解文件系统所用的数据结构和各种函数声明,再就是diskio.h,了解与介质相关的数据结构和操作函数。ff.c这个文件相对较大,可以在最后将所实现的函数大致扫描一遍,之后根据用户应用层程序调用函数的次序仔细阅读相关代码。各个文件都可以直接用记事本打开查阅,非常方便。ff.h中的几个结构体十分重要,列举如下,首先是最基础的文件系统结构体: view plaincopy to clipboardprint? /* File system object structure (FATFS) */ typedef struct { BYTE fs_type; /* FAT子类型,一般在mount时用,置0表示未挂载*/ BYTE drv; /* 物理驱动号,一般为0*/ BYTE csize; /* 每个簇的扇区数目(1,2,4...128) */ BYTE n_fats; /* 文件分配表的数目(1,2) */

FAT文件系统原理

FAT文件系统原理 一、硬盘的物理结构: 硬盘存储数据是根据电、磁转换原理实现的。硬盘由一个或几个表面镀有磁性物质的金属或玻璃等物质盘片以及盘片两面所安装的磁头和相应的控制电路组成(图1),其中盘片和磁头密封在无尘的金属壳中。 硬盘工作时,盘片以设计转速高速旋转,设置在盘片表面的磁头则在电路控制下径向移动到指定位置然后将数据存储或读取出来。当系统向硬盘写入数据时,磁头中“写数据”电流产生磁场使盘片表面磁性物质状态发生改变,并在写电流磁场消失后仍能保持,这样数据就存储下来了;当系统从硬盘中读数据时,磁头经过盘片指定区域,盘片表面磁场使磁头产生感应电流或线圈阻抗产生变化,经相关电路处理后还原成数据。因此只要能将盘片表面处理得更平滑、磁头设计得更精密以及尽量提高盘片旋转速度,就能造出容量更大、读写数据速度更快的硬盘。这是因为盘片表面处理越平、转速越快就能越使磁头离盘片表面越近,提高读、写灵敏度和速度;磁头设计越小越精密就

能使磁头在盘片上占用空间越小,使磁头在一张盘片上建立更多的磁道以存储更多的数据。 二、硬盘的逻辑结构。 硬盘由很多盘片(platter)组成,每个盘片的每个面都有一个读写磁头。如果有N个盘片。就有2N个面,对应2N个磁头(Heads),从0、1、2开始编号。每个盘片被划分成若干个同心圆磁道(逻辑上的,是不可见的。)每个盘片的划分规则通常是一样的。这样每个盘片的半径均为固定值R的同心圆再逻辑上形成了一个以电机主轴为轴的柱面(Cylinders),从外至里编号为0、1、2……每个盘片上的每个磁道又被划分为几十个扇区(Sector),通常的容量是512byte,并按照一定规则编号为1、2、3……形成Cylinders×Heads×Sector个扇区。这三个参数即是硬盘的物理参数。我们下面的很多实践需要深刻理解这三个参数的意义。 三、磁盘引导原理。 3.1MBR(MasterBootRecord)扇区:

原理图元件库

1.在查找元件时,为了增加找到原理图元件的机会,在输入的元件名称中,最 好使用通配符 * 。 2.在字符串查找过程中,系统要寻找所有第一个字母为A的字符串的元件,应 该输入 A* 。 3.在查找元件时,可执行菜单命令工具/查找元件或点击元件库文件面 板上的【查找】按钮。 4.新建原理图元件必须在原理图库文件编辑器中进行。 5.制作一个原理图元器件首先要创建元件库。 6.在原理图库文件编辑环境下,“SCH Library”面板的功能是浏览元件库的 元件。 7.在自己建的原理图元件库文件中,要绘制一个新的元件符号,应执行 Tools/New Component(工具/新元件)菜单命令或单击“SCH Library” 面板上的 Add(追加)按钮。 8.启动元件库编辑器有两种方法,一种方法是打开已有元件库,另一种方 法是创建一个新的元件库。 9.原理图元件库编辑器工作区的中心有一个十字坐标轴,将工作区划分为4 个象限,一般在第四象限绘制原理图元件。 10.原理图元件库编辑器工作区的中心位置坐标为(0,0)。 11.通过原理图元件库编辑器的制作工具来绘制和修改一个元件图 形。 12.在原理图元件编辑环境中,“SCH Library”面板上包括“元件”区、“别 名”区、“引脚”区和“模型”区。 13.“Libraries(库文件)”面板上提供了元件库(Libraries)、查找

(Search

)和放置(Place) 三个工具按钮。 14.原理图元件库编辑管理器中除了主工具栏,还提供了绘制图形工具栏 和 IEEE 工具栏。 15.元件库编辑器里可以产生元件报表、元件库报表和元件规则检查 表。 16.在绘制直线时,可利用空格键切换直线的转角。 17.在绘制椭圆弧时第一次单击鼠标左键确定的是椭圆弧的圆心位置。 18.原理图元件由两部分组成:外形和引脚。 19.制作元器件时,为了画图形实体的外形,捕获网格的值可以按照需要 改动,但是在放置引脚之前,一定要改回 10 。 20.元件名称是为外形和引脚功能相同的元件取的一个通用名称。 21.当元器件绘制完成后,在原理图元件库编辑管理器中单击“元件”区的 “编辑”按钮可设置元件属性。 22.制作元器件符号时,要更改第一个元件名称必须选工具菜单中的重 新命名元件进行修改;要增加一个制作元件直接按【追加】按钮再修改名称。 23.在放置VCC和GND引脚时,在【电气特性】选项中应选择“Power”。 24.若放置与非门74LS00如图01所示功能单元,则在属性对话框中, Designator输入 U1 ;Part为 4 。 图01

FAT文件系统操作系统课程设计实验报告

操作系统课程设计之三 设计任务:模拟OS文件系统 在任一OS(Window或者Dos;也可以是在Linux下,但要求能将结果演示给老 师看)下,建立一个大文件,把它假象成一张盘,在其中实现一个简单的模拟OS 字 ,第 ⑤、每个目录实际能放下文件或子目录30项。 ⑸、文件系统空间分配: ①、第0个盘块(1k)存放磁盘信息(可以设定为格式说明“FAT32”、盘块大小,盘块数等 内容) ②、第1个盘块起,至125盘块,共125个盘块(125k)存放FAT内容 ③、第126、127(2个)盘块,存放位示图

④、从第128盘块至10000盘块,皆为数据(区)盘块,其逻辑编号从0开始,至 9872号数据盘块,即第0数据盘块为128号盘块,第1数据盘块为129号盘块,… ⑤、第0数据盘块(即128号盘块),存放根目录(同样只用一个盘块作根目录), 由于第0、1目录项为“.”(本目录), “..”(父目录),因此根目录下同样只能存放30个文件或目录,并且从第2个目录项开始。 ⑥、文件或子目录数据,放在第1数据盘块及以后的数据盘块中,由用户按需要使 用。 内容 ⑺、删除文件 #DelFile 文件名.扩展名,在文件所在的目录项中,将第一个字节变为0xE5,并同时修改FAT内容和位示图内容;如果文件不存在,给出出错信息 ⑻、文件拷贝 #CopyFile 老文件,新文件,为新文件创建一个目录项,并将老文件内容复制到新文件中,并同时修改FAT内容和位示图内容 ⑼、显示位示图内容

#ShowBitMP,将位示图内容(已有信息部分),显示在屏幕上(按十六进制)⑽、显示FAT内容 #ShowFAT,将FAT内容(已有信息部分),显示在屏幕上(按十六进制) 4、程序的总体流程为: ⑴、输出提示符#,等待接受命令,分析键入的命令; ⑵、对合法的命令,执行相应的处理程序,否则输出错误信息,继续等待新命令 关于对FAT表和MAP表的用法 1.当要用到数据块是,查询MAP表(因为只做比较查询即可),查询到的未用位置 置1,然后在FAT表上进行相应记录,在本程序做出的规定是,当文件夹FAT 表做-1,若是文件则按照FAT做对应的顺序记录,最后一块同样是-1结束,2.回收的时候,是按照FAT表的首项,做顺序置0,然后MAP也在相应位置置0

FATFS文件系统移植和应用

FATFS文件系统的移植 作者:LJ 时间:2010年11月12日 随着信息技术的发展,目前常用文件系统主要有微软的FAT12、FAT16、FAT32、NTES文件系统,以及Linux系统的EXT2、EXT3等。由于Windows操作系统的广泛应用,当前很多嵌入式产品中用的最多的还是FAT文件系统。所以,选择一款容易移植和使用,并且占用资源少而功能全面的文件系统就显得非常重要了。 FATFS文件系统是一个完全免费且开源的FAT文件系统模块,由小日本工程师编写,它支持FAT12、FAT16和FAT32文件系统,专门为小型的嵌入式系统而设计。模块用标准的C语言编写,可以很容易地移植到各种硬件平台。 在“驱动程序”文件夹中有一个“FatFs R0.07c”文件夹,这是官方提供的FATFS文件系统的源码和文档,版本为R0.07c。打开“doc”文件夹下的“00index_e.html”英文网页文档,里面有FATFS文件系统的全部API函数说明,相对应的应用实例和如何编写硬件接口程序的说明。如果您的英文不怎么好,建议您先装一个有道词典,使用屏幕取词功能,能帮助我们阅读和理解。“00index_j.html”则是日文版的网页,毕竟是小日本写的。“src”文件夹存放有FATFS文件系统源码,下面是该文件夹下各个文件或文件夹存放的内容说明:“ff.h”文件:FATFS文件系统的配置和API函数声明; “ff.c”文件:FATFS源码;

“diskio.h”文件:FATFS与存储设备接口函数的声明; “diskio.c”文件:FATFS与存储设备接口函数; “integer.h”文件:FATFS用到的所有变量类型的定义; “option”文件夹:存放一些外接函数,下一实例有实际的讲解; “00readme.txt”文件:FATFS版本及相关信息说明; 编译工程,没有通过,根据编译信息提示在“diskio.c”文件中在几个函数没有定义。这很正常,因为我们还没有编写文件系统与存储设备的接口函数。下面来分析“diskio.c”文件中各个函数的功能:“DSTATUS disk_initialize ( BYTE drv )”是存储媒介的初始化函数,由于我们使用的是SD卡,所以实际上是对SD卡的初始化; “DSTATUS disk_status ( BYTE drv )”状态检测函数,检测是否支持当前的存储设备,支持返回0; “DRESULT disk_read (BYTE drv, BYTE *buff, DWORD sector, BYTE count)”是读扇区函数,drv是要读扇区的存储媒介号,*buff 存储读取的数据,sector是读数据的开始扇区,count是要读的扇区数。在SD卡的驱动程序中,分别提供了读一个扇区和读多个扇区的函数。当count == 1时,用读一个扇区函数;当 count > 1时,用读多个扇区的函数,这样提高了文件系统读效率。操作成功返回0。 “DRESULT disk_write(BYTE drv, BYTE *buff, DWORD sector, BYTE count)”写扇区函数,drv是要写扇区的存储媒介号,*buff存储写入的数据,sector是写开始扇区,count是要写的扇区数。同样在SD卡的驱动程序中,分别提供了写一个扇区和写多个扇区的函数。

原理图文件中的库操作

第一单元 原理图文件中的库操作 第一单元 第1 题 [操作要求] 原理图文件中的库操作: ● 在考生文件夹中新建原理图文件,命名为X1-01A.ch 。 ● 在X1-01A.ch 文件中打开AMD Analog 、Altera Memory 和Analog Devices 三个库文件。 ● 向原理图中添加元件AM2942/B3A(28)、EPC1PC8(8)和AD8079AR (8),依次命名为IC1 、 IC2 、IC3A ,如样图1-01A 所示。 ● 保存操作结果。 E PC1PC8(8) AM2942/B3A(28) 1 2 6 7 8 IC3A AD8079AR (8) 样图1-01A 第一单元 第2 题 [操作要求] 原理图文件中的库操作: ● 在考生文件夹中新建原理图文件,命名为X1-02A.ch 。 ● 在X1-02A.ch 文件中打开AMD Analog 、Altera Memory 和Analog Devices 三个库文件。 ● 向原理图中添加元件AM2942/B3A(28)、SSm2165-2S(8) 和EPB2002ALC(28),依次命 名为IC1 、IC2 、IC3A ,如样图1-02A 所示。 ● 保存操作结果。 1 2 3 4 5 6 78IC2 SSM2165-2S (8) AM27C64-45DIB(28)

PROTE 上机习题精选 2 样图1-02A 第一单元 第3 题 [操作要求] 原理图文件中的库操作: ● 在考生文件夹中新建原理图文件,命名为X1-03A.ch 。 ● 在X1-03A.ch 文件中打开Spice 、SGS Analog 、Burr Brower Converter 三个库文件。 ● 向原理图中添加元件DIODE-ZENER 、HCC4046BF(16)和XTR110BG-BI(16),依次命名 为IC1 、IC2 、IC3A ,如样图1-03A 所示。 ● 保存操作结果。 XTR110BG-BI(16) HCC4046BF(16) 图1-03A 第一单元 第4题 [操作要求] 原理图文件中的库操作: ● 在考生文件夹中新建原理图文件,命名为X1-04A.ch 。 ● 在X1-04A.ch 文件中打开PLD 、ALtera Memory 和Dallas Micro processor 三个库文件。 ● 向原理图中添加元件C373T 、EPC1PC8(8)和DS80C310QCG(44),依次命名为IC1 、IC2 、 IC3A ,如样图1-04A 所示。 ● 保存操作结果。 样图1-04A

在STM32中移植FATFS文件系统

STM32的FATFS文件系统移植笔记 一、序言 经常在网上、群里看到很多人问关于STM32的FATFS文件系统移植的问题,刚好自己最近也在调试这个程序,为了让大家少走弯路,我把我的调试过程和方法也贡献给大家。 二、FATFS简介 FatFs Module是一种完全免费开源的FAT文件系统模块,专门为小型的嵌入式系统而设计。它完全用标准C语言编写,所以具有良好的硬件平台独立性,可以移植到8051、PIC、AVR、SH、Z80、H8、ARM等系列单片机上而只需做简单的修改。它支持FATl2、FATl6和FAT32,支持多个存储媒介;有独立的缓冲区,可以对多个文件进行读/写,并特别对8位单片机和16位单片机做了优化。 三、移植准备 1、FATFS源代码的获取,可以到官网下载:https://www.360docs.net/doc/0f9163845.html,/fsw/ff/00index_e.html最新版本是R0.09版本,我们就移植这个版本的。 2、解压文件会得到两个文件夹,一个是doc文件夹,这里是FATFS的一些使用文档和说明,以后在文件编程的时候可以查看该文档。另一个是src文件夹,里面就是我们所要的源文件。 3、建立一个STM32的工程,为方便调试,我们应重载printf()底层函数实现串口打印输出。可以参考已经建立好的printf()打印输出工程:.viewtool./bbs/foru ... d=77&extra=page%3D1 四、开始移植 1、在已经建立好的工程目录User文件夹下新建两个文件夹,FATFS_V0.09和 SPI_SD_Card,FATFS_V0.09用于存放FATFS源文件,SPI_SD_Card用于存放SPI的驱动文件。 2、如图1将ff.c添加到工程文件夹中,并新建diskio.c文件,在diskio.c文件中实现五个函数: 1.DSTATUS disk_initialize (BYTE);//SD卡的初始化 2. DSTATUS disk_status (BYTE);//获取SD卡的状态,这里可以不用管 3. DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);//从SD卡读取数据 4. DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);//将数据写入 SD卡,若该文件系统为只读文件系统则不用实现该函数 5. DRESULT disk_ioctl (BYTE, BYTE, void*);//获取SD卡文件系统相关信息 6. 复制代码

Altium Designer常用库及元件名

AD常用库及元件名2010-06-24 16:00 原理图常用库文件: Miscellaneous Devices.ddb Dallas Microprocessor.ddb Intel Databooks.ddb Protel DOS Schematic Libraries.ddb PCB元件常用库: Advpcb.ddb General IC.ddb Miscellaneous.ddb 部分分立元件库元件名称及中英对照 AND 与门 ANTENNA 天线 BATTERY 直流电源 BELL 铃,钟 BVC 同轴电缆接插件 BRIDEG 1 整流桥(二极管) BRIDEG 2 整流桥(集成块) BUFFER 缓冲器 BUZZER 蜂鸣器 CAP 电容 CAPACITOR 电容 CAPACITOR POL 有极性电容 CAPVAR 可调电容 CIRCUIT BREAKER 熔断丝 COAX 同轴电缆 CON 插口 CRYSTAL 晶体整荡器 DB 并行插口 DIODE 二极管 DIODE SCHOTTKY 稳压二极管 DIODE VARACTOR 变容二极管 DPY_3-SEG 3段LED DPY_7-SEG 7段LED DPY_7-SEG_DP 7段LED(带小数点) ELECTRO 电解电容 FUSE 熔断器 INDUCTOR 电感 INDUCTOR IRON 带铁芯电感 INDUCTOR3 可调电感 JFET N N沟道场效应管 JFET P P沟道场效应管 LAMP 灯泡

LAMP NEDN 起辉器 LED 发光二极管 METER 仪表MICROPHONE 麦克风MOSFET MOS管 MOTOR AC 交流电机MOTOR SERVO 伺服电机NAND 与非门 NOR 或非门 NOT 非门 NPN NPN三极管 NPN-PHOTO 感光三极管OPAMP 运放 OR 或门 PHOTO 感光二极管 PNP 三极管 NPN DAR NPN三极管 PNP DAR PNP三极管 POT 滑线变阻器 PELAY-DPDT 双刀双掷继电器RES1.2 电阻 RES3.4 可变电阻RESISTOR BRIDGE ? 桥式电阻RESPACK ? 电阻 SCR 晶闸管 PLUG ? 插头 PLUG AC FEMALE 三相交流插头SOCKET ? 插座 SOURCE CURRENT 电流源SOURCE VOLTAGE 电压源SPEAKER 扬声器 SW ? 开关 SW-DPDY ? 双刀双掷开关 SW-SPST ? 单刀单掷开关 SW-PB 按钮THERMISTOR 电热调节器TRANS1 变压器 TRANS2 可调变压器 TRIAC ? 三端双向可控硅TRIODE ? 三极真空管VARISTOR 变阻器 ZENER ? 齐纳二极管 DPY_7-SEG_DP 数码管 SW-PB 开关

stm32-SD卡FatFS文件系统

STM32平台SD卡的FatFS文件系统开发 系统平台: STM32系列的STM32F103ZE SPI方式与SD卡通信 SD上移植FatFS系统 1 FatFS文件系统 1.1 FatFS简介 FatFS是一个为小型嵌入式系统设计的通用FAT(File Allocation Table)文件系统模块。FatFs 的编写遵循ANSI C,并且完全与磁盘I/O层分开。因此,它独立(不依赖)于硬件架构,可以被嵌入到低成本的微控制器中,如A VR, 8051, PIC, ARM, Z80, 68K 等等,而不需要做任何修改。 特点: ?Windows兼容的FAT文件系统 ?不依赖于平台,易于移植 ?代码和工作区占用空间非常小 ?多种配置选项 ?多卷(物理驱动器和分区) ?多ANSI/OEM代码页,包括DBCS ?在ANSI/OEM或Unicode中长文件名的支持 ?RTOS的支持 ?多扇区大小的支持 ?只读,最少API,I/O缓冲区等等

1.2 FatFS文件系统移植 FatFS文件系统移植需要的几个关键文件如下。 ●ff.c(不动)文件系统的实现代码,里面主要是FatFS文件系统源码,移植的时候 不需要修改; ●diskio.h(不动)声明diskio.c文件中需要的一些接口函数和命令格式; ●diskio.c(自写)这个文件是文件系统底层和SD驱动的中间接口的实现代码,移 植的时候需要改写在diskio.h中声明的那几个函数,代码在ff.c中被调用; ●integer.h(微改)这是FatFS用到的数据类型定义,按移植的平台修改; ●ff.h(不动)是FatFS的文件系统的函数(在ff.c中)声明,以及一些选项的配 置,具体选项及详细说明在文件中都有; ●ffconf.h(按需要)这个是在FatFS的0.08a版本中有看到,0.06版本中还没有,是 关于FatFS系统模块的一些配置; 综上,需要修改的就是diskio.c文件,主要是6个函数,描述如下。 DSTATUS disk_initialize (BYTE pdrv /* Physical drive nmuber (0..) */) 初始化函数,调用编写的SD卡初始化函数,成功返回0,失败返回其它。 DSTATUS disk_status (BYTE pdrv /* Physical drive nmuber (0..) */) 设备状态函数,只支持一个设备,若pdrv大于0,则返回错误;否则返回SD的状态,若初始化成功,返回0,否则其它。 DRESULT disk_read ( BYTE pdrv, /* Physical drive nmuber (0..) */ BYTE *buff, /* Data buffer to store read data */ DWORD sector, /* Sector address (LBA) */ BYTE count /* Number of sectors to read (1..128) */ ) 读函数,传入的参数是设备名称,用于保存读到的数据的缓存,扇区地址,扇区个数。 分为一个扇区和多个扇区,两者需要给SD卡发送不同的命令。 DRESULT disk_write ( BYTE pdrv, /* Physical drive nmuber (0..) */ const BYTE *buff, /* Data to be written */ DWORD sector, /* Sector address (LBA) */ BYTE count /* Number of sectors to write (1..128) */ ) 写函数,传入的参数是设备名称,要写的数据地址,扇区地址,扇区个数。 同样分为一个扇区和多个扇区,两者给SD卡发送的命令也不一样。 DWORD get_fattime (void) 用于获取系统当前的unix时间。 DRESULT disk_ioctl ( BYTE pdrv, /* Physical drive nmuber (0..) */ BYTE cmd, /* Control code */ void *buff /* Buffer to send/receive control data */ )

原理图库文件对照表

原理图常用库文件:Miscellaneous Devices.ddb Dallas Microprocessor.ddb Intel Databooks.ddb Protel DOS Schematic Libraries.ddb PCB元件常用库: Advpcb.ddb General IC.ddb Miscellaneous.ddb 部分分立元件库元件名称及中英对照AND 与门 ANTENNA 天线 BA TTERY 直流电源 BELL 铃,钟 BVC 同轴电缆接插件 BRIDEG 1 整流桥(二极管) BRIDEG 2 整流桥(集成块) BUFFER 缓冲器 BUZZER 蜂鸣器 CAP 电容 CAPACITOR 电容 CAPACITOR POL 有极性电容CAPV AR 可调电容 CIRCUIT BREAKER 熔断丝 COAX 同轴电缆 CON 插口 CRYSTAL 晶体整荡器 DB 并行插口 DIODE 二极管 DIODE SCHOTTKY 稳压二极管DIODE VARACTOR 变容二极管DPY_3-SEG 3段LED DPY_7-SEG 7段LED DPY_7-SEG_DP 7段LED(带小数点) ELECTRO 电解电容 FUSE 熔断器 INDUCTOR 电感 INDUCTOR IRON 带铁芯电感INDUCTOR3 可调电感 JFET N N沟道场效应管 JFET P P沟道场效应管 LAMP 灯泡 LAMP NEDN 起辉器

LED 发光二极管 METER 仪表 MICROPHONE 麦克风MOSFET MOS管 MOTOR AC 交流电机 MOTOR SERVO 伺服电机NAND 与非门 NOR 或非门 NOT 非门 NPN NPN三极管 NPN-PHOTO 感光三极管OPAMP 运放 OR 或门 PHOTO 感光二极管 PNP 三极管 NPN DAR NPN三极管 PNP DAR PNP三极管 POT 滑线变阻器 PELAY-DPDT 双刀双掷继电器RES1.2 电阻 RES3.4 可变电阻 RESISTOR BRIDGE ? 桥式电阻RESPACK ? 电阻 SCR 晶闸管 PLUG ? 插头 PLUG AC FEMALE 三相交流插头SOCKET ? 插座 SOURCE CURRENT 电流源SOURCE VOLTAGE 电压源SPEAKER 扬声器 SW ? 开关 SW-DPDY ? 双刀双掷开关 SW-SPST ? 单刀单掷开关 SW-PB 按钮 THERMISTOR 电热调节器TRANS1 变压器 TRANS2 可调变压器 TRIAC ? 三端双向可控硅TRIODE ? 三极真空管 V ARISTOR 变阻器 ZENER ? 齐纳二极管 DPY_7-SEG_DP 数码管 SW-PB 开关

相关文档
最新文档