郑州做企业网站哪家好,wordpress能干什么,网店托管服务,做网站需要了解本专栏争取每周三更新直到更新完成#xff0c;期待大家的订阅关注#xff0c;欢迎互相学习交流。 本文需要一些SD卡的前置知识#xff0c;后续文章会介绍#xff0c;这里先介绍一下FATFS文件系统。关于FATFS的文章分为上下两篇#xff0c;上篇主要介绍什么是FAT文件系统以… 本专栏争取每周三更新直到更新完成期待大家的订阅关注欢迎互相学习交流。 本文需要一些SD卡的前置知识后续文章会介绍这里先介绍一下FATFS文件系统。关于FATFS的文章分为上下两篇上篇主要介绍什么是FAT文件系统以及FATFS的移植下篇主要介绍FATFS的一些API函数。 目录 一、FATFS文件系统简介1.1 FATFS引入1.2 FATFS特点 二、FATFS文件系统移植2.1 FATFS源码文件简介2.2 FATFS重要配置选项2.3 FATFS移植步骤2.3.1 disk_initialize函数2.3.2 disk_status函数2.3.3 disk_read函数2.3.4 disk_write函数2.3.5 disk_ioctl函数2.3.6 get_fattime函数 一、FATFS文件系统简介
1.1 FATFS引入 通常我们买来一张全新的SD卡时如果我们想把它通过读卡器插入到电脑使用我们需要先对其格式化这是因为Windows系统使用的是FAT文件系统我们格式化SD卡实际也就是在SD卡中建立一个FAT文件系统这样我们的电脑才能识别它。 FAT是一个专门为小型的嵌入式系统设计的完全用标准C语言编写完全免费开源的文件系统。FAT具有良好的硬件平台独立性可以移植到C51、PIC、ARM等单片机上而且只需要做一些简单的修改使用起来非常方便。
1.2 FATFS特点 FATFS有以下特点
Windows 兼容的 FAT 文件系统与平台无关移植简单代码量少、效率高支持多卷物理驱动器或分区最多 10 个卷多个 ANSI/OEM 代码页包括 DBCS支持长文件名、ANSI/OEM 或 Unicode支持 RTOS支持多种扇区大小只读、最小化的 API 和 I/O 缓冲区等 这里简单说明一下几个名词仅供参考大家可以自行搜索了解更多详细内容。 上面提到的卷指的是是硬盘上的存储空间一个硬盘包括好多卷一卷也可以跨越许多磁盘。卷又分为很多种比如启动卷、跨区卷、带区卷等。此外还有簇指的是磁盘文件存储管理的最小单位。 UnicodeUniversal Multiple-Octet Coded Character Set简称UCS中文意思是统一码或者叫万国码可以简单理解为他就是一个数字映射表每一个数字代表不同的字符或文字。 二、FATFS文件系统移植
2.1 FATFS源码文件简介 下面我们介绍一下如何移植FATFS。首先我们需要下载到它的源码有需要的友友可以私信获取。下载完成后打开其中的“src”文件夹其中是我们需要的源码。我们在移植FATFS模块的时候一般只需要修改ffconf.h 和 diskio.c这两个文件。 option文件夹是一些可选的外部C文件包含了多语言支持需要的文件和转换函数移植时我们通常会选择cc936.c文件用来支持简体中文它包含了简体中文GBK和Unicode互相转换的功能函数。 diskio.c文件是FATFS移植的最关键文件它为文件系统提供了最底层的接口返回问函数。diskio.h里面包含了FATFS用到的宏定义以及diskio.c文件内与底层硬件接口相关的函数声明。00history.txt介绍了当前FATFS的版本更新情况。00readme.txt介绍了文件夹中各个文件的功能。integer.h文件中是一些数据类型定义。ff.c文件时FATFS的核心里面包含了FATFS的各个模块程序时文件管理的实现方法我们在移植时通常不需要对这个文件进行修改。ffconf.h是FATFS的配置文件其中包含了对FATFS功能配置的宏定义。我们通过修改这些宏定义就可会议实现对FATFS功能的裁剪达到自己想要的效果。
2.2 FATFS重要配置选项 上面在介绍源码文件时提到FATFS模块的所有配置项都是存放在 ffconf.h 里面我们这里再介绍一些重要的配置选项。
_FS_TINY该宏定义时设置使用的是标准模式还是微小模式我们通常设置为0使用标准模式。_FS_READONLY该宏定义是选择是否使用只读模式通常我们选择可读可写设置为0。_FS_MINIMIZE该宏定义是选择是否裁剪掉一些函数通常选择不裁剪设置为0。_USE_STRFUNC该宏定义是设置是否支持字符串类操作通常选择支持设置为1。_USE_MKFS该宏定义是设置是否使用格式化我们选择使用设置为1。_USE_FASTSEEK该宏定义用来设定是否是能快速定位通常选择使用设置为1。_USE_LABEL该宏定义用来设置是否支持磁盘盘符读取与设置通常选择支持设置为1。使能后我们就可以通过相关函数来读取或者设置磁盘的名字。_CODE_PAGE该宏定义用来设置语言类型通常我们选择简体中文设置为936也就是c936.c文件。_USE_LFN该宏定义用来设置是否支持长文件名取值范围是0到3。0表示不支持长文件名1~3表示支持长文件名但是存储的地方不一样。通常设置为3可以通过ff_memalloc函数来动态分配长文件名的存储区域。_MAX_LFN该宏定义用来设置允许的最大文件名长度我们设置为最大值255。_LFN_UNICODE该宏定义用来设置是否使用FATFS的字符编码通常设置为不使用设置为0。_VOLUMES该宏定义用来设置FATFS支持的逻辑涉笔数量。_MAX_SS该宏定义用来设置山区缓冲的最大值一般设置为512。
2.3 FATFS移植步骤 想要将FATFS移植到STM32实际并不复杂主要分为三步
下载FATFS源码将源码添加到Keil工程编写一些底层的接口函数 通常最后一步我们需要编写六个底层的接口函数下面我们来详细地介绍一下它们。
2.3.1 disk_initialize函数
函数功能初始化磁盘。函数原型DSTATUS disk_initialize(BYTE pdrv);输入参数prdrv是要初始化的逻辑驱动器号也就是盘符取值范围是0~9。返回值返回一个盘符状态作为结果。注意事项应用程序不应该在FATFS活动时调用此函数否则卷上的FAT结构可能会损坏。
//初始化磁盘
DSTATUS disk_initialize (BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{u8 res0; switch(pdrv){case SD_CARD://SD卡resSD_Init();//SD卡初始化 break;case EX_FLASH://外部flashW25QXX_Init();FLASH_SECTOR_COUNT2048*12;//W25Q1218,前12M字节给FATFS占用 break;default:res1; } if(res)return STA_NOINIT;else return 0; //初始化成功
} 2.3.2 disk_status函数
函数功能返回当前磁盘驱动器的状态。函数原型DSTATUS disk_status (BYTE pdrv);输入参数pdrv是要确认的逻辑驱动器号也就是盘符取值范围是0~9。返回值有如下几个返回值
#define STA_NOINIT 0x01 /* Drive not initialized */
#define STA_NODISK 0x02 /* No medium in the drive */
#define STA_PROTECT 0x04 /* Write protected */FATFS只使用前两个返回值。
//获得磁盘状态
DSTATUS disk_status (BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{ return RES_OK;
} 2.3.3 disk_read函数
函数功能从磁盘上读取扇区。函数原型DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);输入参数pdrv驱动器逻辑号 buff指向存储读取数据字节数组的指针 sector指定起始扇区的逻辑块上的地址 count指定要读取的扇区数返回值返回值结构体如下
/* Results of Disk Functions */
typedef enum {RES_OK 0, /* 0: Successful */RES_ERROR, /* 1: R/W Error */RES_WRPRT, /* 2: Write Protected */RES_NOTRDY, /* 3: Not Ready */RES_PARERR /* 4: Invalid Parameter */
} DRESULT;//读扇区
//pdrv:磁盘编号0~9
//*buff:数据接收缓冲首地址
//sector:扇区地址
//count:需要读取的扇区数
DRESULT disk_read (BYTE pdrv, /* Physical drive nmuber to identify the drive */BYTE *buff, /* Data buffer to store read data */DWORD sector, /* Sector address in LBA */UINT count /* Number of sectors to read */
)
{u8 res0; if (!count)return RES_PARERR;//count不能等于0否则返回参数错误 switch(pdrv){case SD_CARD://SD卡resSD_ReadDisk(buff,sector,count); while(res)//读出错{SD_Init(); //重新初始化SD卡resSD_ReadDisk(buff,sector,count); //printf(sd rd error:%d\r\n,res);}break;case EX_FLASH://外部flashfor(;count0;count--){W25QXX_Read(buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE);sector;buffFLASH_SECTOR_SIZE;}res0;break;default:res1; }//处理返回值将SPI_SD_driver.c的返回值转成ff.c的返回值if(res0x00)return RES_OK; else return RES_ERROR;
}2.3.4 disk_write函数
函数功能向磁盘写入一个或多个扇区。函数原型DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);输入参数pdrv要操作的逻辑驱动器号 buff指向要写入的数组的指针 sector指定起始扇区逻辑块上的地址 count指定要写入的扇区数取值范围是1~128返回值与上面的读函数为同一个结构体。
//写扇区
//pdrv:磁盘编号0~9
//*buff:发送数据首地址
//sector:扇区地址
//count:需要写入的扇区数
#if _USE_WRITE
DRESULT disk_write (BYTE pdrv, /* Physical drive nmuber to identify the drive */const BYTE *buff, /* Data to be written */DWORD sector, /* Sector address in LBA */UINT count /* Number of sectors to write */
)
{u8 res0; if (!count)return RES_PARERR;//count不能等于0否则返回参数错误 switch(pdrv){case SD_CARD://SD卡resSD_WriteDisk((u8*)buff,sector,count);while(res)//写出错{SD_Init(); //重新初始化SD卡resSD_WriteDisk((u8*)buff,sector,count); //printf(sd wr error:%d\r\n,res);}break;case EX_FLASH://外部flashfor(;count0;count--){ W25QXX_Write((u8*)buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE);sector;buffFLASH_SECTOR_SIZE;}res0;break;default:res1; }//处理返回值将SPI_SD_driver.c的返回值转成ff.c的返回值if(res 0x00)return RES_OK; else return RES_ERROR;
}
#endif2.3.5 disk_ioctl函数
函数功能控制设备指定特性和一些除了读写外的杂项功能。函数原型DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);输入参数pdrv要操作的逻辑驱动器号 cmd命令代码 buff指向参数缓冲区的指针取决于命令代码不使用时指向一个NULL指针返回值与上面的读/写函数为同一个结构体。注意事项 这里贴一下一些命令的宏定义
/* Command code for disk_ioctrl fucntion *//* Generic command (Used by FatFs) */
#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY 0) */
#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS 1) */
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS ! _MIN_SS) */
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS 1) */
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM 1) *//* Generic command (Not used by FatFs) */
#define CTRL_POWER 5 /* Get/Set power status */
#define CTRL_LOCK 6 /* Lock/Unlock media removal */
#define CTRL_EJECT 7 /* Eject media */
#define CTRL_FORMAT 8 /* Create physical format on the media *//* MMC/SDC specific ioctl command */
#define MMC_GET_TYPE 10 /* Get card type */
#define MMC_GET_CSD 11 /* Get CSD */
#define MMC_GET_CID 12 /* Get CID */
#define MMC_GET_OCR 13 /* Get OCR */
#define MMC_GET_SDSTAT 14 /* Get SD status *//* ATA/CF specific ioctl command */
#define ATA_GET_REV 20 /* Get F/W revision */
#define ATA_GET_MODEL 21 /* Get model name */
#define ATA_GET_SN 22 /* Get serial number *///其他表参数的获得
//pdrv:磁盘编号0~9
//ctrl:控制代码
//*buff:发送/接收缓冲区指针
#if _USE_IOCTL
DRESULT disk_ioctl (BYTE pdrv, /* Physical drive nmuber (0..) */BYTE cmd, /* Control code */void *buff /* Buffer to send/receive control data */
)
{
DRESULT res; if(pdrvSD_CARD)//SD卡{switch(cmd){case CTRL_SYNC:res RES_OK; break; case GET_SECTOR_SIZE:*(DWORD*)buff 512; res RES_OK;break; case GET_BLOCK_SIZE:*(WORD*)buff SDCardInfo.CardBlockSize;res RES_OK;break; case GET_SECTOR_COUNT:*(DWORD*)buff SDCardInfo.CardCapacity/512;res RES_OK;break;default:res RES_PARERR;break;}}else if(pdrvEX_FLASH) //外部FLASH {switch(cmd){case CTRL_SYNC:res RES_OK; break; case GET_SECTOR_SIZE:*(WORD*)buff FLASH_SECTOR_SIZE;res RES_OK;break; case GET_BLOCK_SIZE:*(WORD*)buff FLASH_BLOCK_SIZE;res RES_OK;break; case GET_SECTOR_COUNT:*(DWORD*)buff FLASH_SECTOR_COUNT;res RES_OK;break;default:res RES_PARERR;break;}}else resRES_ERROR;//其他的不支持return res;
}
#endif2.3.6 get_fattime函数
函数功能获取当前时间。返回值返回以双字封装的当前时间具体格式这里不再详细描述了。注意事项get_fattime函数必须返回一个合法的时间如果系统不支持实时时钟可以返回0。 通过上述步骤我们就完成了对于FATFS的移植FATFS 提供了很多 API 函数这些函数 FATFS 的自带介绍文件里面都有详细的介绍。这里需要注意的是在使用FATFS的时候必须先通过f_mount函数注册一个工作区才能开始后续 API 的使用。