第25章串行FLASH文件系统FatFs野火firege

即使读者可能不了解文件系统,读者也一定对“文件”这个概念十分熟悉。数据在PC上是以文件的形式储存在磁盘中的,这些数据的形式一般为ASCII码或二进制形式。在上一章我们已经写好了QSPIFlash芯片的驱动函数,我们可以非常方便的在QSPIFlash芯片上读写数据。如需要记录本书的书名“零死角玩转STM32-F7系列”,可以把这些文字转化成ASCII码,存储在数组中,然后调用QSPI_FLASH_BufferWrite函数,把数组内容写入到QSPIFlash芯片的指定地址上,在需要的时候从该地址把数据读取出来,再对读出来的数据以ASCII码的格式进行解读。

但是,这样直接存储数据会带来极大的不便,如难以记录有效数据的位置,难以确定存储介质的剩余空间,以及应以何种格式来解读数据。就如同一个巨大的图书馆无人管理,杂乱无章地存放着各种书籍,难以查找所需的文档。想象一下图书馆的采购人员购书后,把书籍往馆内一扔,拍拍屁股走人,当有人来借阅某本书的时候,就不得不一本本地查找。这样直接存储数据的方式对于小容量的存储介质如EEPROM还可以接受,但对于QSPIFlash芯片或者SD卡之类的大容量设备,我们需要一种高效的方式来管理它的存储内容。

这些管理方式即为文件系统,它是为了存储和管理数据,而在存储介质建立的一种组织结构,这些结构包括操作系统引导区、目录和文件。常见的windows下的文件系统格式包括FAT32、NTFS、exFAT。在使用文件系统前,要先对存储介质进行格式化。格式化先擦除原来内容,在存储介质上新建一个文件分配表和目录。这样,文件系统就可以记录数据存放的物理地址,剩余空间。

使用文件系统时,数据都以文件的形式存储。写入新文件时,先在目录中创建一个文件索引,它指示了文件存放的物理地址,再把数据存储到该地址中。当需要读取数据时,可以从目录中找到该文件的索引,进而在相应的地址中读取出数据。具体还涉及到逻辑地址、簇大小、不连续存储等一系列辅助结构或处理过程。

文件系统的存在使我们在存取数据时,不再是简单地向某物理地址直接读写,而是要遵循它的读写格式。如经过逻辑转换,一个完整的文件可能被分开成多段存储到不连续的物理地址,使用目录或链表的方式来获知下一段的位置。

上一章的SPIFlash芯片驱动只完成了向物理地址写入数据的工作,而根据文件系统格式的逻辑转换部分则需要额外的代码来完成。实质上,这个逻辑转换部分可以理解为当我们需要写入一段数据时,由它来求解向什么物理地址写入数据、以什么格式写入及写入一些原始数据以外的信息(如目录)。这个逻辑转换部分代码我们也习惯称之为文件系统。

上面提到的逻辑转换部分代码(文件系统)即为本章的要点,文件系统庞大而复杂,它需要根据应用的文件系统格式而编写,而且一般与驱动层分离开来,很方便移植,所以工程应用中一般是移植现成的文件系统源码。

FatFs是面向小型嵌入式系统的一种通用的FAT文件系统。它完全是由AISIC语言编写并且完全独立于底层的I/O介质。因此它可以很容易地不加修改地移植到其他的处理器当中,如8051、PIC、AVR、SH、Z80、H8、ARM等。FatFs支持FAT12、FAT16、FAT32等格式,所以我们利用前面写好的QSPIFlash芯片驱动,把FatFs文件系统代码移植到工程之中,就可以利用文件系统的各种函数,对QSPIFlash芯片以“文件”格式进行读写操作了。

FatFs文件系统的源码可以从fatfs官网下载:

在移植FatFs文件系统到开发板之前,我们先要到FatFs的官网获取源码,最新版本为R0.11a,官网有对FatFs做详细的介绍,有兴趣可以了解。解压之后可看到里面有doc和src这两个文件夹,见图25-1。doc文件夹里面是一些使用帮助文档;src才是FatFs文件系统的源码。

图25-1FatFs文件目录

打开doc文件夹,可看到如图25-2的文件目录:

图25-2doc文件夹的文件目录

其中en和ja这两个文件夹里面是编译好的html文档,讲的是FATFS里面各个函数的使用方法,这些函数都是封装得非常好的函数,利用这些函数我们就可以操作SPIFlash芯片。有关具体的函数我们在用到的时候再讲解。这两个文件夹的唯一区别就是en文件夹下的文档是英文的,ja文件夹下的是日文的。img文件夹包含en和ja文件夹下文件需要用到的图片,还有四个名为app.c文件,内容都是FatFs具体应用例程。00index_e.html和00index_j.html是一些关于FATFS的简介,至于另外两个文件可以不看。

打开src文件夹,可看到如图25-3的文件目录:

图25-3src文件夹的文件目录

option文件夹下是一些可选的外部c文件,包含了多语言支持需要用到的文件和转换函数。

00history.txt介绍了FatFs的版本更新情况。

00readme.txt说明了当前目录下diskio.c、diskio.h、ff.c、ff.h、integer.h的功能。

src文件夹下的源码文件功能简介如下:

qinteger.h:文件中包含了一些数值类型定义。

qdiskio.c:包含底层存储介质的操作函数,这些函数需要用户自己实现,主要添加底层驱动函数。

qff.c:FatFs核心文件,文件管理的实现方法。该文件独立于底层介质操作文件的函数,利用这些函数实现文件的读写。

qcc936.c:本文件在option目录下,是简体中文支持所需要添加的文件,包含了简体中文的GBK和Unicode相互转换功能函数。

qffconf.h:这个头文件包含了对FatFs功能配置的宏定义,通过修改这些宏定义就可以裁剪FatFs的功能。如需要支持简体中文,需要把ffconf.h中的_CODE_PAGE的宏改成936并把上面的cc936.c文件加入到工程之中。

建议阅读这些源码的顺序为:integer.h-->diskio.c-->ff.c。

阅读文件系统源码ff.c文件需要一定的功底,建议读者先阅读FAT32的文件格式,再去分析ff.c文件。若仅为使用文件系统,则只需要理解integer.h及diskio.c文件并会调用ff.c文件中的函数就可以了。本章主要讲解如何把FATFS文件系统移植到开发板上,并编写一个简单读写操作范例。

移植FatFs之前我们先通过FatFs的程序结构图了解FatFs在程序中的关系网络,见图25-4。

图25-4FatFs程序结构图

用户应用程序需要由用户编写,想实现什么功能就编写什么的程序,一般我们只用到f_mount()、f_open()、f_write()、f_read()就可以实现文件的读写操作。

FatFs组件是FatFs的主体,文件都在源码src文件夹中,其中ff.c、ff.h、integer.h以及diskio.h四个文件我们不需要改动,只需要修改ffconf.h和diskio.c两个文件。

底层设备输入输出要求实现存储设备的读写操作函数、存储设备信息获取函数等等。我们使用QSPIFlash芯片作为物理设备,在上一章节已经编写好了QSPIFlash芯片的驱动程序,这里我们就直接使用。

FatFs属于软件组件,不需要附带其他硬件电路。我们使用QSPIFlash芯片作为物理存储设备,其硬件电路在上一章已经做了分析,这里就直接使用。

上一章我们已经实现了QSPIFlash芯片驱动程序,并实现了读写测试,为移植FatFs方便,我们直接拷贝一份工程,我们在工程基础上添加FatFs组件,并修改main函数的用户程序即可。

1)先拷贝一份QSPIFlash芯片测试的工程文件(整个文件夹),并修改文件夹名为“QSPI—FatFs文件系统”。将FatFs源码中的src文件夹整个文件夹拷贝一份至“QSPI—FatFs文件系统\USER\”文件夹下并修改名为“FATFS”,见图25-5。

图25-5拷贝FatFs源码到工程

2)使用KEIL软件打开工程文件(..\QSPI—FatFs文件系统\Project\RVMDK(uv5)\BH-F767.uvprojx),并将FatFs组件文件添加到工程中,需要添加有ff.c、diskio.c和cc936.c三个文件,见图25-6。

图25-6添加FatFS文件到工程

3)添加FATFS文件夹到工程的include选项中。打开工程选项对话框,选择“C/C++”选项下的“IncludePaths”项目,在弹出路径设置对话框中选择添加“FATFS”文件夹,见图25-7。

图25-7添加FATFS路径到工程选项

4)如果现在编译工程,可以发现有两个错误,一个是来自diskio.c文件,提示有一些头文件没找,diskio.c文件内容是与底层设备输入输出接口函数文件,不同硬件设计驱动就不同,需要的文件也不同;另外一个错误来自cc936.c文件,提示该文件不是工程所必需的,这是因为FatFs默认使用日语,我们想要支持简体中文需要修改FatFs的配置,即修改ffconf.h文件。至此,将FatFs添加到工程的框架已经操作完成,接下来要做的就是修改diskio.c文件和ffconf.h文件。

FatFs文件系统与底层介质的驱动分离开来,对底层介质的操作都要交给用户去实现,它仅仅是提供了一个函数接口而已。表251为FatFs移植时用户必须支持的函数。通过表251我们可以清晰知道很多函数是在一定条件下才需要添加的,只有前三个函数是必须添加的。我们完全可以根据实际需求选择实现用到的函数。

前三个函数是实现读文件最基本需求。接下来三个函数是实现创建文件、修改文件需要的。为实现格式化功能,需要在disk_ioctl添加两个获取物理设备信息选项。我们一般只有实现前面六个函数就可以了,已经足够满足大部分功能。

为支持简体中文长文件名称需要添加ff_convert和ff_wtoupper函数,实际这两个已经在cc936.c文件中实现了,我们只要直接把cc936.c文件添加到工程中就可以了。

后面六个函数一般都不用。如真有需要可以参考syscall.c文件(src\option文件夹内)。

表25-1FatFs移植需要用户支持函数

函数

条件(ffconf.h)

备注

disk_statusdisk_initializedisk_read

总是需要

底层设备驱动函数

disk_writeget_fattimedisk_ioctl(CTRL_SYNC)

_FS_READONLY==0

disk_ioctl(GET_SECTOR_COUNT)disk_ioctl(GET_BLOCK_SIZE)

_USE_MKFS==1

disk_ioctl(GET_SECTOR_SIZE)

_MAX_SS!=_MIN_SS

disk_ioctl(CTRL_TRIM)

_USE_TRIM==1

ff_convertff_wtoupper

_USE_LFN!=0

Unicode支持,为支持简体中文,添加cc936.c到工程即可

ff_cre_syncobjff_del_syncobjff_req_grantff_rel_grant

_FS_REENTRANT==1

FatFs可重入配置,需要多任务系统支持(一般不需要)

ff_mem_allocff_mem_free

_USE_LFN==3

长文件名支持,缓冲区设置在堆空间(一般设置_USE_LFN=2)

底层设备驱动函数是存放在diskio.c文件,我们的目的就是把diskio.c中的函数接口与QSPIFlash芯片驱动连接起来。总共有五个函数,分别为设备状态获取(disk_status)、设备初始化(disk_initialize)、扇区读取(disk_read)、扇区写入(disk_write)、其他控制(disk_ioctl)。

接下来,我们对每个函数结合QSPIFlash芯片驱动做详细讲解。

代码清单25-1设备状态获取

1DSTATUSTM_FATFS_FLASH_SPI_disk_status(BYTElun)

2{

3FLASH_DEBUG_FUNC();

4if(sFLASH_ID==QSPI_FLASH_ReadID()){/*检测FLASH是否正常工作*/

5returnTM_FATFS_FLASH_SPI_Stat&=~STA_NOINIT;/*ClearSTA_NOINITflag*/

6}else{

7returnTM_FATFS_FLASH_SPI_Stat|=STA_NOINIT;

8}

9}

TM_FATFS_FLASH_SPI_disk_status函数只有一个参数lun,没有使用。对于QSPIFlash芯片,我们直接调用在QSPI_FLASH_ReadID()获取设备ID,然后判断是否正确,如果正确,函数返回正常标准;如果错误,函数返回异常标志。

代码清单25-2设备初始化

1DSTATUSTM_FATFS_FLASH_SPI_disk_initialize(BYTElun)

3GPIO_InitTypeDefGPIO_InitStruct;

4

5/*使能QSPI及GPIO时钟*/

6QSPI_FLASH_CLK_ENABLE();

7QSPI_FLASH_CLK_GPIO_ENABLE();

8QSPI_FLASH_BK1_IO0_CLK_ENABLE();

9QSPI_FLASH_BK1_IO1_CLK_ENABLE();

10QSPI_FLASH_BK1_IO2_CLK_ENABLE();

11QSPI_FLASH_BK1_IO3_CLK_ENABLE();

12QSPI_FLASH_CS_GPIO_CLK_ENABLE();

13

14//设置引脚

15/*!<配置QSPI_FLASH引脚:CLK*/

16GPIO_InitStruct.Pin=QSPI_FLASH_CLK_PIN;

17GPIO_InitStruct.Mode=GPIO_MODE_AF_PP;

18GPIO_InitStruct.Pull=GPIO_NOPULL;

19GPIO_InitStruct.Speed=GPIO_SPEED_HIGH;

20GPIO_InitStruct.Alternate=QSPI_FLASH_CLK_GPIO_AF;

21

22HAL_GPIO_Init(QSPI_FLASH_CLK_GPIO_PORT,&GPIO_InitStruct);

23

24/*!<配置QSPI_FLASH引脚:IO0*/

25GPIO_InitStruct.Pin=QSPI_FLASH_BK1_IO0_PIN;

26GPIO_InitStruct.Alternate=QSPI_FLASH_BK1_IO0_AF;

27HAL_GPIO_Init(QSPI_FLASH_BK1_IO0_PORT,&GPIO_InitStruct);

28

29/*!<配置QSPI_FLASH引脚:IO1*/

30GPIO_InitStruct.Pin=QSPI_FLASH_BK1_IO1_PIN;

31GPIO_InitStruct.Alternate=QSPI_FLASH_BK1_IO1_AF;

32HAL_GPIO_Init(QSPI_FLASH_BK1_IO1_PORT,&GPIO_InitStruct);

33

34/*!<配置QSPI_FLASH引脚:IO2*/

35GPIO_InitStruct.Pin=QSPI_FLASH_BK1_IO2_PIN;

36GPIO_InitStruct.Alternate=QSPI_FLASH_BK1_IO2_AF;

37HAL_GPIO_Init(QSPI_FLASH_BK1_IO2_PORT,&GPIO_InitStruct);

38

39/*!<配置QSPI_FLASH引脚:IO3*/

40GPIO_InitStruct.Pin=QSPI_FLASH_BK1_IO3_PIN;

41GPIO_InitStruct.Alternate=QSPI_FLASH_BK1_IO3_AF;

42HAL_GPIO_Init(QSPI_FLASH_BK1_IO3_PORT,&GPIO_InitStruct);

43

44/*!<配置SPI_FLASH_SPI引脚:NCS*/

45GPIO_InitStruct.Pin=QSPI_FLASH_CS_PIN;

46GPIO_InitStruct.Alternate=QSPI_FLASH_CS_GPIO_AF;

47HAL_GPIO_Init(QSPI_FLASH_CS_GPIO_PORT,&GPIO_InitStruct);

48

49/*QSPI_FLASH模式配置*/

50

51hqspi.Instance=QUADSPI;

52hqspi.Init.ClockPrescaler=1;

53hqspi.Init.FifoThreshold=4;

54hqspi.Init.SampleShifting=QSPI_SAMPLE_SHIFTING_HALFCYCLE;

55hqspi.Init.FlashSize=23;

56hqspi.Init.ChipSelectHighTime=QSPI_CS_HIGH_TIME_2_CYCLE;

57hqspi.Init.ClockMode=QSPI_CLOCK_MODE_0;

58HAL_QSPI_Init(&hqspi);

59

60BSP_QSPI_Init();

61

62returnTM_FATFS_FLASH_SPI_disk_status(NULL);

63

64}

TM_FATFS_FLASH_SPI_disk_initialize函数也是有一个参数lun,没有使用。对于QSPIFlash芯片我们调用HAL_QSPI_Init函数实现对SPIFlash芯片引脚GPIO初始化配置,调用BSP_QSPI_Init()函数对通信参数配置。

最后调用TM_FATFS_FLASH_SPI_disk_status函数获取QSPIFlash芯片状态,并返回状态值。

代码清单25-3扇区读取

1DRESULTTM_FATFS_FLASH_SPI_disk_read(

2BYTElun,//物理扇区,多个设备时用到(0...)

3BYTE*buff,//数据缓存区

4DWORDsector,//扇区首地址

5UINTcount)//扇区个数(1..128)

6{

7FLASH_DEBUG_FUNC();

8if((TM_FATFS_FLASH_SPI_Stat&STA_NOINIT)){

9returnRES_NOTRDY;

10}

11sector+=1536;//扇区偏移,外部Flash文件系统空间放在外部Flash后面6M空间

12BSP_QSPI_Read(buff,sector<<12,count<<12);

13returnRES_OK;

14}

TM_FATFS_FLASH_SPI_disk_read函数有四个形参。lun为设备物理编号。buff是一个BYTE类型指针变量,buff指向用来存放读取到数据的存储区首地址。sector是一个DWORD类型变量,指定要读取数据的扇区首地址。count是一个UINT类型变量,指定扇区数量。

BYTE类型实际是unsignedchar类型,DWORD类型实际是unsignedlong类型,UINT类型实际是unsignedint类型,类型定义在integer.h文件中。

开发板使用的QSPIFlash芯片型号为W25Q128FV,每个扇区大小为4096个字节(4KB),总共有16M字节空间,为兼容后面实验程序,我们只将后部分10MB空间分配给FatFs使用,前部分6MB空间用于其他实验需要,即FatFs是从6MB空间开始,为实现这个效果需要将所有的读写地址都偏移1536个扇区空间。

代码清单25-4扇区输入

1DRESULTTM_FATFS_FLASH_SPI_disk_write(

3constBYTE*buff,//数据缓存区

7uint32_twrite_addr;

8FLASH_DEBUG_FUNC();

9sector+=1536;//扇区偏移,外部Flash文件系统空间放在外部Flash后面4M空间

10write_addr=sector<<12;

11BSP_QSPI_Erase_Block(write_addr);

12BSP_QSPI_Write((uint8_t*)buff,write_addr,4096);

TM_FATFS_FLASH_SPI_disk_write函数有四个形参,lun为设备物理编号。buff指向待写入扇区数据的首地址。sector,指定要读取数据的扇区首地址。count指定扇区数量。对于QSPIFlash芯片,在写入数据之前需要先擦除,所以用到扇区擦除函数(BSP_QSPI_Erase_Block)。然后就是在调用数据写入函数(BSP_QSPI_Write)把数据写入到指定位置内。

代码清单25-5其他控制

1DRESULTTM_FATFS_FLASH_SPI_disk_ioctl(BYTElun,BYTEcmd,void*buff)

3

4FLASH_DEBUG_FUNC();

5switch(cmd){

6caseGET_SECTOR_COUNT:

7*(DWORD*)buff=2560;/*扇区数量:2560*4096/1024/1024=10(MB)*/

8break;

9caseGET_SECTOR_SIZE:/*获取扇区读写的大小(字)*/

10

11*(WORD*)buff=4096;/*flash最小写单元为页,256字节,此处取2页为一个读写单位*/

12break;

13caseGET_BLOCK_SIZE:/*同时擦除扇区个数(双字)*/

14*(DWORD*)buff=1;/*flash以1个sector为最小擦除单位*/

15break;

16caseCTRL_TRIM:

17break;

18caseCTRL_SYNC:

19break;

20}

21returnRES_OK;

22}

TM_FATFS_FLASH_SPI_disk_ioctl函数有三个形参,lun为设备物理编号,cmd为控制指令,包括发出同步信号、获取扇区数目、获取扇区大小、获取擦除块数量等等指令,buff为指令对应的数据指针。

对于QSPIFlash芯片,为支持FatFs格式化功能,需要用到获取扇区数量(GET_SECTOR_COUNT)指令和获取擦除块数量(GET_BLOCK_SIZE)。另外,SD卡扇区大小为512字节,SPIFlash芯片一般设置扇区大小为4096字节,所以需要用到获取扇区大小(GET_SECTOR_SIZE)指令。

1__weakDWORDget_fattime(void)

4return((DWORD)(2015-1980)<<25)/*Year2015*/

5|((DWORD)1<<21)/*Month1*/

6|((DWORD)1<<16)/*Mday1*/

7|((DWORD)0<<11)/*Hour0*/

8|((DWORD)0<<5)/*Min0*/

9|((DWORD)0>>1);/*Sec0*/

qbit31:25——从1980至今是多少年,范围是(0..127);

qbit24:21——月份,范围为(1..12);

qbit20:16——该月份中的第几日,范围为(1..31);

qbit15:11——时,范围为(0..23);

qbit10:5——分,范围为(0..59);

qbit4:0——秒/2,范围为(0..29)。

ffconf.h文件是FatFs功能配置文件,我们可以对文件内容进行修改,使得FatFs更符合我们的要求。ffconf.h对每个配置选项都做了详细的使用情况说明。下面只列出修改的配置,其他配置采用默认即可。

代码清单25-7FatFs功能配置选项

1#define_USE_MKFS1

2#define_CODE_PAGE936

3#define_USE_LFN2

4#define_VOLUMES3

5#define_MIN_SS512

6#define_MAX_SS4096

1)_USE_MKFS:格式化功能选择,为使用FatFs格式化功能,需要把它设置为1。

3)_USE_LFN:长文件名支持,默认不支持长文件名,这里配置为2,支持长文件名,并指定使用栈空间为缓冲区。

4)_VOLUMES:指定物理设备数量,这里设置为3,包括预留SD卡和qSPIFlash芯片。

5)_MIN_SS、_MAX_SS:指定扇区大小的最小值和最大值。SD卡扇区大小一般都为512字节,SPIFlash芯片扇区大小一般设置为4096字节,所以需要把_MAX_SS改为4096。

移植操作到此,就已经把FatFs全部添加到我们的工程了,这时我们编译功能,顺利编译通过,没有错误。接下来,我们就可以使用编写图254中用户应用程序了。

主要的测试包括格式化测试、文件写入测试和文件读取测试三个部分,主要程序都在main.c文件中实现。

代码清单25-8变量定义

1FATFSfs;/*FatFs文件系统对象*/

2FILfnew;/*文件对象*/

3FRESULTres_flash;/*文件操作结果*/

4UINTfnum;/*文件成功读写数量*/

5BYTEbuffer[1024]={0};/*读缓冲区*/

6BYTEtextFileBuffer[]=/*写缓冲区*/

7"欢迎使用野火STM32F429开发板今天是个好日子,新建文件系统测试文件\r\n";

FATFS是在ff.h文件定义的一个结构体类型,针对的对象是物理设备,包含了物理设备的物理编号、扇区大小等等信息,一般我们都需要为每个物理设备定义一个FATFS变量。

FRESULT是也在ff.h文件定义的一个枚举类型,作为FatFs函数的返回值类型,主要管理FatFs运行中出现的错误。总共有19种错误类型,包括物理设备读写错误、找不到文件、没有挂载工作空间等等错误。这在实际编程中非常重要,当有错误出现是我们要停止文件读写,通过返回值我们可以快速定位到错误发生的可能地点。如果运行没有错误才返回FR_OK。

fnum是个32位无符号整形变量,用来记录实际读取或者写入数据的数组。

buffer和textFileBuffer分别对应读取和写入数据缓存区,都是8位无符号整形数组。

代码清单25-9主函数

1intmain(void)

3SystemClock_Config();

4/*EnableI-Cache*/

5SCB_EnableICache();

6/*EnableD-Cache*/

7SCB_EnableDCache();

8/*初始化LED*/

9LED_GPIO_Config();

10LED_BLUE;

11

12/*初始化调试串口,一般为串口1*/

13DEBUG_USART_Config();

14printf("******这是一个SPIFLASH文件系统实验******\r\n");

15//链接驱动器,创建盘符

16FATFS_LinkDriver(&QSPI_Driver,QSPIPath);

17//在外部SPIFlash挂载文件系统,文件系统挂载时会对SPI设备初始化

18res_flash=f_mount(&fs,"0:",1);

19

20/*-----------------------格式化测试---------------------------*/

21/*如果没有文件系统就格式化创建创建文件系统*/

22if(res_flash==FR_NO_FILESYSTEM){

23printf("》FLASH还没有文件系统,即将进行格式化...\r\n");

24/*格式化*/

25res_flash=f_mkfs("0:",0,0);

26

27if(res_flash==FR_OK){

28printf("》FLASH已成功格式化文件系统。\r\n");

29/*格式化后,先取消挂载*/

30res_flash=f_mount(NULL,"0:",1);

31/*重新挂载*/

32res_flash=f_mount(&fs,"0:",1);

33}else{

34LED_RED;

35printf("《《格式化失败。》》\r\n");

36while(1);

37}

38}elseif(res_flash!=FR_OK){

39printf("!!外部Flash挂载文件系统失败。(%d)\r\n",res_flash);

40printf("!!可能原因:SPIFlash初始化不成功。\r\n");

41while(1);

42}else{

43printf("》文件系统挂载成功,可以进行读写测试\r\n");

44}

45

46/*-----------------------文件系统测试:写测试-----------------------------*/

47/*打开文件,如果文件不存在则创建它*/

48printf("\r\n******即将进行文件写入测试...******\r\n");

49res_flash=f_open(&fnew,"0:FatFs读写测试文件.txt",FA_CREATE_ALWAYS|FA_WRITE);

50if(res_flash==FR_OK){

51printf("》打开/创建FatFs读写测试文件.txt文件成功,向文件写入数据。\r\n");

52/*将指定存储区内容写入到文件内*/

53res_flash=f_write(&fnew,WriteBuffer,sizeof(WriteBuffer),&fnum);

54if(res_flash==FR_OK){

55printf("》文件写入成功,写入字节数据:%d\n",fnum);

56printf("》向文件写入的数据为:\r\n%s\r\n",WriteBuffer);

57}else{

58printf("!!文件写入失败:(%d)\n",res_flash);

59}

60/*不再读写,关闭文件*/

61f_close(&fnew);

62}else{

63LED_RED;

64printf("!!打开/创建文件失败。\r\n");

65}

66

67/*-------------------文件系统测试:读测试------------------------------------*/

68printf("******即将进行文件读取测试...******\r\n");

69res_flash=f_open(&fnew,"0:FatFs读写测试文件.txt",FA_OPEN_EXISTING|FA_READ);

70if(res_flash==FR_OK){

71LED_GREEN;

72printf("》打开文件成功。\r\n");

73res_flash=f_read(&fnew,ReadBuffer,sizeof(ReadBuffer),&fnum);

74if(res_flash==FR_OK){

75printf("》文件读取成功,读到字节数据:%d\r\n",fnum);

76printf("》读取得的文件数据为:\r\n%s\r\n",ReadBuffer);

77}else{

78printf("!!文件读取失败:(%d)\n",res_flash);

79}

80}else{

81LED_RED;

82printf("!!打开文件失败。\r\n");

83}

84/*不再读写,关闭文件*/

85f_close(&fnew);

86

87/*不再使用文件系统,取消挂载文件系统*/

88f_mount(NULL,"0:",1);

89

90/*操作完成,停机*/

91while(1){

92}

93}

首先,初始化系统时钟,RGB彩灯和调试串口,用来指示程序进程。

FatFs的第一步工作就是链接驱动器,创建盘符然后使用f_mount函数挂载工作区。f_mount函数有三个形参,第一个参数是指向FATFS变量指针,如果赋值为NULL可以取消物理设备挂载。第二个参数为逻辑设备编号,使用设备根路径表示,与物理设备编号挂钩,这里使用“0:”。第三个参数可选0或1,1表示立即挂载,0表示不立即挂载,延迟挂载。f_mount函数会返回一个FRESULT类型值,指示运行情况。

如果f_mount函数返回值为FR_NO_FILESYSTEM,说明没有FAT文件系统,比如新出厂的SPIFlash芯片就没有FAT文件系统。我们就必须对物理设备进行格式化处理。使用f_mkfs函数可以实现格式化操作。f_mkfs函数有三个形参,第一个参数为逻辑设备编号;第二参数可选0或者1,0表示设备为一般硬盘,1表示设备为软盘。第三个参数指定扇区大小,如果为0,表示通过代码清单255中TM_FATFS_FLASH_SPI_disk_ioctl函数获取。格式化成功后需要先取消挂载原来设备,再重新挂载设备。

在设备正常挂载后,就可以进行文件读写操作了。使用文件之前,必须使用f_open函数打开文件,不再使用文件必须使用f_close函数关闭文件,这个跟电脑端操作文件步骤类似。f_open函数有三个形参,第一个参数为文件对象指针。第二参数为目标文件,包含绝对路径的文件名称和后缀名。第三个参数为访问文件模式选择,可以是打开已经存在的文件模式、读模式、写模式、新建模式、总是新建模式等的或运行结果。比如对于写测试,使用FA_CREATE_ALWAYS和FA_WRITE组合模式,就是总是新建文件并进行写模式。

f_close函数用于不再对文件进行读写操作关闭文件,f_close函数只要一个形参,为文件对象指针。f_close函数运行可以确保缓冲区完全写入到文件内。

成功打开文件之后就可以使用f_write函数和f_read函数对文件进行写操作和读操作。这两个函数用到的参数是一致的,只不过一个是数据写入,一个是数据读取。f_write函数第一个形参为文件对象指针,使用与f_open函数一致即可。第二个参数为待写入数据的首地址,对于f_read函数就是用来存放读出数据的首地址。第三个参数为写入数据的字节数,对于f_read函数就是欲读取数据的字节数。第四个参数为32位无符号整形指针,这里使用fnum变量地址赋值给它,在运行读写操作函数后,fnum变量指示成功读取或者写入的字节个数。

最后,不再使用文件系统时,使用f_mount函数取消挂载。

虽然我们通过RGB彩灯指示和串口调试助手信息打印方法来说明FatFs移植成功,并顺利通过测试,但心底总是很踏实,所谓眼见为实,虽然我们创建了“FatFs读写测试文件.txt”这个文件,却完全看不到实体。这个确实是个问题,因为我们这里使用SPIFlash芯片作为物理设备,并不像SD卡那么方便直接用读卡器就可以在电脑端打开验证。另外一个问题,就目前来说,在QSPIFlash芯片上挂载FatFs好像没有实际意义,无法发挥文件系统功能。

本实验主要使用FatFs软件功能,不需要其他硬件模块,使用与FatFs移植实验相同硬件配置即可。

上个实验我们已经移植好了FatFs,这个例程主要是应用,所以简单起见,直接拷贝上个实验的工程文件,保持FatFs底层驱动程序,我们只改main.c文件内容,实现应用程序。

代码清单25-10FatFs多项功能测试

1staticFRESULTmiscellaneous(void)

3DIRdir;

4FATFS*pfs;

5DWORDfre_clust,fre_sect,tot_sect;

6

7printf("\n***************设备信息获取***************\r\n");

8/*获取设备信息和空簇大小*/

9res_flash=f_getfree("0:",&fre_clust,&pfs);

11/*计算得到总的扇区个数和空扇区个数*/

12tot_sect=(pfs->n_fatent-2)*pfs->csize;

13fre_sect=fre_clust*pfs->csize;

14

15/*打印信息(4096字节/扇区)*/

16printf("》设备总空间:%10luKB。\n》可用空间:%10luKB。\n",

17tot_sect*4,fre_sect*4);

18

19printf("\n********文件定位和格式化写入功能测试********\r\n");

20res_flash=f_open(&fnew,"1:FatFs读写测试文件.txt",

21FA_OPEN_EXISTING|FA_WRITE|FA_READ);

22if(res_flash==FR_OK){

23/*文件定位*/

24res_flash=f_lseek(&fnew,f_size(&fnew)-1);

25if(res_flash==FR_OK){

26/*格式化写入,参数格式类似printf函数*/

27f_printf(&fnew,"\n在原来文件新添加一行内容\n");

28f_printf(&fnew,"》设备总空间:%10luKB。\n》可用空间:%10luKB。\n",

29tot_sect*4,fre_sect*4);

30/*文件定位到文件起始位置*/

31res_flash=f_lseek(&fnew,0);

32/*读取文件所有内容到缓存区*/

33res_flash=f_read(&fnew,readbuffer,f_size(&fnew),&fnum);

34if(res_flash==FR_OK){

35printf("》文件内容:\n%s\n",readbuffer);

36}

38f_close(&fnew);

39

40printf("\n**********目录创建和重命名功能测试**********\r\n");

41/*尝试打开目录*/

42res_flash=f_opendir(&dir,"0:TestDir");

43if(res_flash!=FR_OK){

44/*打开目录失败,就创建目录*/

45res_flash=f_mkdir("0:TestDir");

46}else{

47/*如果目录已经存在,关闭它*/

48res_flash=f_closedir(&dir);

49/*删除文件*/

50f_unlink("0:TestDir/testdir.txt");

51}

52if(res_flash==FR_OK){

53/*重命名并移动文件*/

54res_flash=f_rename("0:FatFs读写测试文件.txt",

55"0:TestDir/testdir.txt");

56}

58printf("!!打开文件失败:%d\n",res_flash);

59printf("!!或许需要再次运行“FatFs移植与读写测试”工程\n");

60}

61returnres_flash;

62}

首先是设备存储信息获取,目的是获取设备总容量和剩余可用空间。f_getfree函数是设备空闲簇信息获取函数,有三个形参,第一个参数为逻辑设备编号;第二个参数为返回空闲簇数量;第三个参数为返回指向文件系统对象的指针。通过计算可得到设备总的扇区个数以及空闲扇区个数,对于QSPIFlash芯片我们设置每个扇区为4096字节大小。这样很容易就算出设备存储信息。

接下来是文件读写指针定位和格式化输入功能测试。文件定位在一些场合非常有用,比如我们需要记录多项数据,但每项数据长度不确定,但有个最长长度,使用我们就可以使用文件定位lseek函数功能把数据存放在规定好的地址空间上。当我们需要读取文件内容时就使用文件定位函数定位到对应地址读取。

使用文件读写操作之前都必须使用f_open函数打开文件,开始文件是读写指针是在文件起始位置的,马上写入数据的话会覆盖原来文件内容的。这里,我们使用f_lseek函数定位到文件末尾位置,再写入内容。f_lseek函数有两个形参,第一个参数为文件对象指针,第二个参数为需要定位的字节数,这个字节数是相对文件起始位置的,比如设置为0,则将文件读写指针定位到文件起始位置了。

f_printf函数是格式化写入函数,需要把ffconf.h文件中的_USE_STRFUNC配置为1才支持。f_printf函数用法类似C库函数printf函数,只是它将数据直接写入到文件中。

最后是目录创建和文件移动和重命名功能。使用f_opendir函数可以打开路径(这里不区分目录和路径概念,下同),如果路径不存在则返回错误,使用f_closedir函数关闭已经打开的路径。新版的FatFs支持相对路径功能,使路径操作更加灵活。f_opendir函数有两个形参,第一个参数为指向路径对象的指针,第二个参数为路径。f_closedir函数只需要指向路径对象的指针一个形参。

f_mkdir函数用于创建路径,如果指定的路径不存在就创建它,创建的路径存在形式就是文件夹。f_mkdir函数只要一个形参,就是指定路径。

f_rename函数是带有移动功能的重命名函数,它有两个形参,第一个参数为源文件名称,第二个参数为目标名称。目标名称可附带路径,如果路径与源文件路径不同见移动文件到目标路径下。

代码清单25-11文件信息获取

1staticFRESULTfile_check(void)

3FILINFOfno;

5/*获取文件信息*/

6res_flash=f_stat("0:TestDir/testdir.txt",&fno);

7if(res_flash==FR_OK){

8printf("“testdir.txt”文件信息:\n");

9printf("》文件大小:%ld(字节)\n",fno.fsize);

11(fno.fdate>>9)+1980,fno.fdate>>5&15,fno.fdate&31,

12fno.ftime>>11,fno.ftime>>5&63);

13printf("》属性:%c%c%c%c%c\n\n",

14(fno.fattrib&AM_DIR)'D':'-',//是一个目录

15(fno.fattrib&AM_RDO)'R':'-',//只读文件

16(fno.fattrib&AM_HID)'H':'-',//隐藏文件

17(fno.fattrib&AM_SYS)'S':'-',//系统文件

18(fno.fattrib&AM_ARC)'A':'-');//档案文件

19}

20returnres_flash;

21}

代码清单25-12路径扫描

1staticFRESULTscan_files(char*path)

3FRESULTres;//部分在递归过程被修改的变量,不用全局变量

4FILINFOfno;

5DIRdir;

6inti;

7char*fn;//文件名

8

9#if_USE_LFN

10/*长文件名支持*/

11/*简体中文需要2个字节保存一个“字”*/

12staticcharlfn[_MAX_LFN*2+1];

13fno.lfname=lfn;

14fno.lfsize=sizeof(lfn);

15#endif

16//打开目录

17res=f_opendir(&dir,path);

18if(res==FR_OK){

19i=strlen(path);

20for(;;){

21//读取目录下的内容,再读会自动读下一个文件

22res=f_readdir(&dir,&fno);

23//为空时表示所有项目读取完毕,跳出

24if(res!=FR_OK||fno.fname[0]==0)break;

25#if_USE_LFN

26fn=*fno.lfnamefno.lfname:fno.fname;

27#else

28fn=fno.fname;

29#endif

30//点表示当前目录,跳过

31if(*fn=='.')continue;

32//目录,递归读取

33if(fno.fattrib&AM_DIR){

34//合成完整目录名

35sprintf(&path[i],"/%s",fn);

36//递归遍历

37res=scan_files(path);

38path[i]=0;

39//打开失败,跳出循环

40if(res!=FR_OK)

41break;

43printf("%s/%s\r\n",path,fn);//输出文件名

44/*可以在这里提取特定格式的文件路径*/

45}//else

46}//for

47}

48returnres;

49}

scan_files函数用来扫描指定路径下的文件。比如我们设计一个mp3播放器,我们需要提取mp3格式文件,诸如*.txt、*.c文件我们统统不可要的,这时我们就必须扫描路径下所有文件并把*.mp3或*.MP3格式文件提取出来。这里我们提取特定格式文件,而是把所有文件名称都通过串口打印出来。

我们在ffconf.h文件中定义了长文件名称支持(_USE_LFN=2),一般有用到简体中文文件名称的都要长文件名支持。短文件名称是8.3格式,即名称是8个字节,后缀名是3个字节,对于使用英文名称还可以,使用中文名称就很容易长度不够了。使能了长文件名支持后,使用之前需要指定文件名的存储区还有存储区的大小。

接下来就是使用f_opendir函数打开指定的路径。如果路径存在就使用f_readdir函数读取路径下内容,f_readdir函数可以读取路径下的文件或者文件夹,并保存信息到文件信息对象变量内。f_readdir函数有两个形参,第一个参数为指向路径对象变量的指针,第二个参数为指向文件信息对象的指针。f_readdir函数另外一个特性是自动读取下一个文件对象,即循序运行该函数可以读取该路径下的所有文件。所以,在程序中,我们使用for循环让f_readdir函数读取所有文件,并在读取所有文件之后退出循环。

在f_readdir函数成功读取到一个对象时,我们还不清楚它是一个文件还是一个文件夹,此时我们就可以使用文件信息对象变量的文件属性来判断了,如果判断得出是个文件那我们就直接通过串口打印出来就好了。如果是个文件夹,我们就要进入该文件夹扫描,这时就重新调用扫描函数scan_files就可以了,形成一个递归调用结构,只是我们这次用的参数与最开始时候是不同的,现在是使用子文件夹名称。

代码清单25-13主函数

3/*初始化调试串口,一般为串口1*/

4Debug_USART_Config();

5printf("********这是一个QSPIFLASH文件系统实验*******\r\n");

6FATFS_LinkDriver(&QSPI_Driver,QSPIPath);

7//在外部SPIFlash挂载文件系统,文件系统挂载时会对SPI设备初始化

8res_flash=f_mount(&fs,"0:",1);

9if(res_flash!=FR_OK){

10printf("!!外部Flash挂载文件系统失败。(%d)\r\n",res_flash);

11printf("!!可能原因:QSPIFlash初始化不成功。\r\n");

12while(1);

13}else{

14printf("》文件系统挂载成功,可以进行测试\r\n");

15}

16

17/*FatFs多项功能测试*/

18res_flash=miscellaneous();

20

21printf("\n***************文件信息获取测试**************\r\n");

22res_flash=file_check();

24

25printf("*****************文件扫描测试****************\r\n");

26strcpy(fpath,"0:");

27scan_files(fpath);

29

30/*不再使用文件系统,取消挂载文件系统*/

31f_mount(NULL,"0:",1);

32

33/*操作完成,停机*/

34while(1){

35}

串口在程序调试中经常使用,可以把变量值直观打印到串口调试助手,这个信息非常重要,同样在使用之前需要调用Debug_USART_Config函数完成调试串口初始化。

使用FatFs进行文件操作之前都使用f_mount函数挂载物理设备,这里我们使用SPIFlash芯片上的FAT文件系统。

接下来我们直接调用miscellaneous函数进行FatFs设备信息获取、文件定位和格式化写入功能以及目录创建和重命名功能测试。调用file_check函数进行文件信息获取测试。

scan_files函数用来扫描路径下的所有文件,fpath是我们定义的一个包含100个元素的字符型数组,并将其赋值为SPIFlash芯片物理编号对于的根目录。这样允许scan_files函数见打印SPIFlash芯片内FatFs所有文件到串口调试助手。注意,这里的定义fpaht数组是必不可少的,因为scan_files函数本身是个递归函数,要求实际参数有较大空间的缓存区。

THE END
1.图书馆管理系统架构图图书管理系统 功能结构图~~~ 图书馆管理系统通常由前端、后端和数据库三个部分组成,其架构图如下: 前端:通常包括用户界面和业务逻辑处理,用户可以通过前端界面进行查询、借阅、归还、续借等操作。前端可以使用常见的Web开发技术实现,如HTML、CSS、JavaScript等。 后端:通常包括业务逻辑处理和数据交互,处理用户请求并与数https://wenku.csdn.net/answer/2099sinkfm
2.图书管理系统系统总体架构图mob64ca13f587aa的技术博客自友图书馆管理系统解决方案适用于中小学、大中专院校以及企事业单位中小型图书馆的自动化管理需求,其功能覆盖了图书馆自动化集成管理业务流程所包括的所有环节。《图书馆管理系统》首先应该按照我国图书馆行业通用CNMARC格式及《中图法第四版》行业标准开发而成,支持CNMARC导入导出,支持Z39.50检索协议,能实现不同图书馆https://blog.51cto.com/u_16213572/12515031
3.图书管理系统需求分析报告范文(精选10篇)随着社会一步步向前发展,报告对我们来说并不陌生,报告包含标题、正文、结尾等。其实写报告并没有想象中那么难,以下是小编整理的图书管理系统需求分析报告范文(精选10篇),仅供参考,欢迎大家阅读。 图书管理系统需求分析报告 篇1 一、引言 1.背景分析 一直以来人们使用传统的人工方式管理图书馆的日常工作,对于图书馆的https://www.ruiwen.com/baogao/6437442.html
4.图书馆管理系统结构图.docx该【图书馆管理系统结构图 】是由【花双韵芝】上传分享,文档一共【11】页,该文档可以免费在线阅读,需要了解更多关于【图书馆管理系统结构图 】的内容,可以使用淘豆网的站内搜索功能,选择自己适合的文档,以下文字是截取该文章内的部分文字,如需要获得完整电子版,请下载此文档到您的设备,方便您编辑和打印。图书馆管理https://www.taodocs.com/p-841517108.html
5.计算机专业毕业论文开题报告范本该管理系统与MIS系统相联系,在图书馆内部建成可靠,方便,并且功能齐全的MIS系统。从而在图书馆对新旧书的反应;对书籍借阅的管理能力;对读者和图书馆工作人员的管理能力;对图书馆管理人员软件操作的适应时间和操作感觉这些方面都将大大的提高。当然对该软件的态度是渴望获得显著的社会效益。https://biyelunwen.yjbys.com/kaitibaogao/636937.html
6.图书管理系统功能结构图网上图书商城系统功能结构.pdf 上传者:qq_35291562时间:2021-11-26 图书管理系统(流程图 功能图 ER 全套设计论文) 图书管理系统:以管理员身份登录到图书管理系统中,查询、修改、图书的书名、ISBN、库存量等信息和添加新书和删除旧书等。这些信息都会被记录到相应的数据库中。 1. 图书基本信息包括书名,作者,出版日https://www.iteye.com/resource/wannastay-2272221
7.图书馆指纹门禁系统的设计与实现图书馆门禁系统结构功能框图如图 1 所示。 系统硬件主要包括 :电源模块、CMOS 光学传感指纹采集模块、指纹数据存储模块(SRAM 和SDRAM)、指纹程序及指纹模板存储模块(FLASH)、UART 模块、USB 2.0 模块、指纹图像算法处理模块、IC 卡、以太网MAC 模块及LCD 显示模块等。 https://www.21ic.com/article/894991.html
8.图书管理系统系统设计(精选6篇)2.2 系统流程图及其功能的划分模块图 图1为图书管理流程图,图2为图书管理模块图。 3 系统数据库设计 3.1 数据库概念结构设计 所谓数据库是指长期存储在计算机内的,有组织的,课共享的数据集合。数据库是以某种文件结构存储的一系列信息表,这种文件结构使您能够访问这些表、选择表中的列、对表进行排序以及根据各种标https://www.360wenmi.com/f/fileu9ihjn2g.html
9.图书馆书目检索系统Word 之光:颠覆认知的Word必修课 图书 基本信息 元数据(MARC) 出版发行项:北京:电子工业出版社,2019 ISBN及定价:978-7-121-36087-9 CNY79.90 载体形态项:286页:彩图;24cm 其它题名:颠覆认知的Word必修课: 个人责任者:冯注龙 著李海潇 著 学科主题:文字处理系统 中图法分类号:TP391.12 提要文摘附注:本书从https://libsys.sdufe.edu.cn/space/searchDetailLocal/mf272bf2b90ee5f6960abda12ffbbf2c3
10.校园能源管理系统建设方案今日头条电力监控系统可以对整个配电系统范围内的设备进行远程遥控操作。例如配电系统维护人员可以通过监控系统的主界面点击相应的断路器遥信点调出遥控操作界面,可以及时执行调度系统或站内相应的操作命令。 ■网络拓扑图 电力监控系统支持实时监视接入系统的各设备的通讯状态,能够完整的显示整个系统网络结构;可在线诊断设备通讯状态https://www.elecfans.com/news/1829405.html
11.图书管理系统层次结构图流程图模板图书管理系统层次结构图主要包括用户界面层、业务逻辑层和数据访问层。用户界面层负责与用户进行交互,接收用户的输入和展示系统的输出。业务逻辑层处理用户请求,实现系统的核心功能,如图书的增删改查、借阅还书等。数据访问层负责与数据库进行通信,实现数据的存储和检索。这三层之间通过接口进行通信,保证了系统的模块化https://www.processon.com/view/5a45f627e4b0849f8ffad393
12.图书馆管理系统结构图.doc文档全文免费预览WORD 格式 整理 PAGE 学习 参考 资料 分享 图书馆管理系统结构图确定取消管理认证离开挂起系统 主界面管理人员系统修改密码系统离开挂起系统库存盘点系统关于本系统退出系统图书借阅系统图书归还系统图书统计系统图书续借系统图书查询系统统计超期图书新书登记系统图书修改系统统计遗失图书读者信息系统读者登记系统读者删除系统管理https://max.book118.com/html/2019/0201/8106041135002004.shtm
13.2018级降管理专业人才培养方案在教学过程中,理论教学由基础到专业、技能培养由易到难逐步提升,素质教育贯穿始终,实现理论、实践教学的系统化设计。 (一)课程体系结构图 (二)实践教学体系 实践教学以学校仿真环境和真实环境为依托,以职业能力培养为主线构建实践教学体系,遵循职业岗位能力培养的基本规律,开展课程教学、仿真实训和临床实习。技能训练由https://jwc.wfhlxy.com/info/1023/1356.htm
14.教室布置方案15篇一、系统结构图 图略 二、系统组成 1)视频、数字展示台。 它可以进行实物、照片、书本资料的投影,是一种非常实用的设备。它不单独使用,只能输出视频、数字信号,由多媒体投影机来投影。 2)多媒体投影机。 多媒体投影机是整个多媒体演示教室中最重要的也是最昂贵的设备,它连接着计算机系统、所有视频输出系统及数字https://www.unjs.com/fanwenku/354707.html
15.图书管理系统流程图书管理系统的开发过程包括:调研和计划;需求分析;软件计划;编码和模块测试;总体测试;确认和评审;交付使用。接下来,小编为您分享了图书管理系统流程,仅供参考! 图书管理系统流程 篇1 系统功能结构设计 综合考虑系统的逻辑模型和设计系统目标的要求绘制的系统功能结构 https://www.jy135.com/guanli/162184.html
16.图书馆管理系统结构图1、15 图书馆管理系统结构图15 #15 #VVVV1管修离库关退图图图理改开存于出书书书人密挂盘本系借归续员码起占八、系统阅还借系统系统系统系统统系统系统系统主界面r1TVVV1TVV1T图图统新图统读读读书书计书书计者者者统查超登修遗信登删计询期记改失息记除系系图系系图系系系统统书统统书统统统15 https://www.renrendoc.com/paper/219505736.html
17.软件工程腾讯云开发者社区A.逻辑架构B.物理架构C.组成结构D.体系结构 19、角色可以有四种类型:系统的使用者,硬件设备,外部系统和()。 A.数据库B.接口C.对象D.时间 20、功能模型用于表达系统的需求,为软件的进一步分析和设计打下基础。在面向对象方法中,由()实现。 A.场景描述 B.活动图和场景描述 C. 用例图和场景描述 D.交互图和https://cloud.tencent.com/developer/news/373361
18.新大纲2024军队文职图书专业第二部分(第二篇)图书馆信息化的概念和特征;图书馆信息化建设的原则;图书馆信息化建设的发展阶段;图书馆信息化建设的主要内容。 二、图书馆自动化 图书馆自动化的概念;图书馆自动化研究的内容;图书馆自动化系统的特点、图书馆自动化系统的功能结构;图书馆自动化各子系统功能及主要流程。 https://www.zjjks.com/bmzd/81651.html
19.第119页80树状结构通常用来呈现概述、或是系统组织的高层结构图。 巢状”结构的等级关系,是把子元素包含在母元素里,如同文氏圆”(Venn Diagram)一样。巢状结构最适用于简单的等级关系。一旦不同等级之间的关系变得太紧密或复杂,让人无法清楚地辨认,巢状结构就会失效了。巢状结构通常用来集合信息与功能,呈现简单的逻辑关系。 https://book.douban.com/annotation/79392843/