FATFS 读写测试


本文章基于 NUCLEO-G0B1RE开发板;

一、实验目的

使用CubeMX配置FATFS,实现使用FATFS创建一个TXT格式的文件,存储在FLASH中。

二、实验原理

FATFS: 负责管理和存储文件信息的软件机构,在磁盘上组织文件的方法。

FATFS官网:http://elm-chan.org/fsw/ff/00index_e.html

FATFS移植文件

移植步骤:

数据类型:在integer.h 里面去定义好数据的类型。这里需要了解你用的编译器的数据类型,并根据编译器定义好数据类型 (使用 CubeMX 生成可不关心)
配置:通过ffconf.h配置FATFS的相关功能,以满足你的需要。
函数编写:打开diskio.c,进行底层驱动编写,一般需要编写6 个接口函数

配置相关宏:

_MAX_SS 扇区缓冲最大值,一般为512
_VOLUMES 支持的逻辑设备数目
_MAX_LFN 文件名的最大长度
_USE_LFN 是否支持长文件名,值不同存储的位置不同
_CODE_PAGE 设置语言936-中文GBK编码
_USE_MKFS 是否启用格式化
_USE_FASTSEEK 使能快速定位
_USE_LABEL 是否支持磁盘盘符的设置和读取

常用API函数:

f_open 打开/创建一个文件
f_close 关闭一个文件
f_read 读文件
f_write 写文件
f_lseek 移动文件读/写指针
f_sync 刷新缓存的数据
f_mount 注册/取消注册卷的工作区
f_mkfs 在逻辑驱动器上创建FAT卷

三、CubeMX 配置

配置SPI,选择PB0 作为软件CS。
引脚配置
随后配置串口,作为人机交互。
UART配置
配置FATFS,修改语言为 US
FATFS

四、程序配置

在程序中添加 FLASH的驱动库。

BSP_SPI_FLASH.h

#ifndef __BSP_SPI_FLASH_H
#define __BSP_SPI_FLASH_H



#include "stm32g0xx_hal.h"
#include <stdio.h>
#include "spi.h"


/**定义FLASH的ID*/
#define  sFLASH_ID             0x0B13   //XT25F08B
/**定义SPI CS使能*/	 
#define SPI_FLASH_CS_LOW()      HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET)
/**定义SPI CS失能*/	 
#define SPI_FLASH_CS_HIGH()     HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET) 

/**
*@name 指令表
*@{
*/
#define FLASH_WriteEnable		0x06 
#define FLASH_WriteDisable		0x04 
#define FLASH_ReadStatusReg1	0x05 
#define FLASH_ReadStatusReg2    0x35 
#define FLASH_ReadStatusReg3    0x15 
#define FLASH_WriteStatusReg1   0x01 
#define FLASH_WriteStatusReg2   0x31 
#define FLASH_WriteStatusReg3   0x11 
#define FLASH_ReadData			0x03 
#define FLASH_FastReadData	  	0x0B 
#define FLASH_FastReadDual		0x3B 
#define FLASH_PageProgram		0x02 
#define FLASH_BlockErase		0xD8 
#define FLASH_SectorErase		0x20 
#define FLASH_ChipErase			0xC7 
#define FLASH_PowerDown			0xB9 
#define FLASH_ReleasePowerDown	0xAB 
#define FLASH_DeviceID			0xAB 
#define FLASH_ManufactDeviceID	0x90 
#define FLASH_JedecDeviceID	  	0x9F 
#define FLASH_Enable4ByteAddr   0xB7
#define FLASH_Exit4ByteAddr     0xE9
/** @} */


void BSP_SPI_FLASH_Init(void);
uint16_t  BSP_SPI_FLASH_ReadID(void);  	    		//读取FLASH ID
uint8_t BSP_SPI_FLASH_ReadSR(uint8_t regno);             //读取状态寄存器 
void BSP_SPI_FLASH_4ByteAddr_Enable(void);     //使能4字节地址模式
void BSP_SPI_FLASH_Write_SR(uint8_t regno,uint8_t sr);   //写状态寄存器
void BSP_SPI_FLASH_Write_Enable(void);  		//写使能 
void BSP_SPI_FLASH_Write_Disable(void);		//写保护
void BSP_SPI_FLASH_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);
void BSP_SPI_FLASH_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead);   //读取flash
void BSP_SPI_FLASH_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);//写入flash
void BSP_SPI_FLASH_Erase_Chip(void);    	  	//整片擦除
void BSP_SPI_FLASH_Erase_Sector(uint32_t Dst_Addr);	//扇区擦除
void BSP_SPI_FLASH_Wait_Busy(void);           	//等待空闲
void BSP_SPI_FLASH_PowerDown(void);        	//进入掉电模式
void BSP_SPI_FLASH_WAKEUP(void);				//唤醒

#endif

BSP_SPI_FLASH.c

#include "BSP_SPI_FLASH.h"

/** 定义定义BSP_SPI_FLASH芯片型号*/
uint16_t BSP_SPI_FLASH_TYPE;

  /**
  * @Brief     FLASH读写1byte函数      
  * @Param     byte 需要写入的数据
  * @Return    ucReadData 接收到的数据
  * @Note      None
  */
uint8_t SPI_FLASH_SendByte(uint8_t byte)
{
    uint8_t ucReadData;

    HAL_SPI_TransmitReceive(&hspi1, &byte, &ucReadData, 1, 1000);      
   
   return ucReadData;/*返回收到的数据*/	
}

  /**
  * @Brief     FLASH初始化函数      
  * @Param     None
  * @Return    None
  * @Note      获取FLASH的ID,判断是否成功通讯
  */
void BSP_SPI_FLASH_Init(void)
{

    BSP_SPI_FLASH_TYPE=BSP_SPI_FLASH_ReadID();	        //读取FLASH ID.
    if(BSP_SPI_FLASH_TYPE == sFLASH_ID)                //SPI FLASH为XT25F08B
    {

    }
}
  /**
  * @Brief     FLASH读取状态寄存器函数      
  * @Param     regno 状态寄存器号
  * @Return    byte 状态寄存器值
  * @Note      None
  */
uint8_t BSP_SPI_FLASH_ReadSR(uint8_t regno)
{
    uint8_t byte=0,command=0;
    switch(regno)
    {
    case 1:
        command=FLASH_ReadStatusReg1;    //读状态寄存器1指令
        break;
    case 2:
        command=FLASH_ReadStatusReg2;    //读状态寄存器2指令
        break;
    case 3:
        command=FLASH_ReadStatusReg3;    //读状态寄存器3指令
        break;
    default:
        command=FLASH_ReadStatusReg1;
        break;
    }
    SPI_FLASH_CS_LOW();                            //使能器件
    SPI_FLASH_SendByte(command);            //发送读取状态寄存器命令
    byte=SPI_FLASH_SendByte(0Xff);          //读取一个字节
    SPI_FLASH_CS_HIGH();                            //取消片选
    return byte;
}
  /**
  * @Brief     FLASH写状态寄存器函数      
  * @Param     regno 状态寄存器号
  * @Param     sr    写入的状态寄存器值
  * @Return    None
  * @Note      None
  */
void BSP_SPI_FLASH_Write_SR(uint8_t regno,uint8_t sr)
{
    uint8_t command=0;
    switch(regno)
    {
    case 1:
        command=FLASH_WriteStatusReg1;    //写状态寄存器1指令
        break;
    case 2:
        command=FLASH_WriteStatusReg2;    //写状态寄存器2指令
        break;
    case 3:
        command=FLASH_WriteStatusReg3;    //写状态寄存器3指令
        break;
    default:
        command=FLASH_WriteStatusReg1;
        break;
    }
    SPI_FLASH_CS_LOW();                            //使能器件
    SPI_FLASH_SendByte(command);            //发送写取状态寄存器命令
    SPI_FLASH_SendByte(sr);                 //写入一个字节
    SPI_FLASH_CS_HIGH();                            //取消片选
}
  /**
  * @Brief     FLASH写使能函数      
  * @Param     None
  * @Return    None
  * @Note      None
  */
void BSP_SPI_FLASH_Write_Enable(void)
{
    SPI_FLASH_CS_LOW();                            //使能器件
    SPI_FLASH_SendByte(FLASH_WriteEnable);   //发送写使能
    SPI_FLASH_CS_HIGH();                            //取消片选
}
  /**
  * @Brief     FLASH写禁止函数      
  * @Param     None
  * @Return    None
  * @Note      None
  */
void BSP_SPI_FLASH_Write_Disable(void)
{
    SPI_FLASH_CS_LOW();                            //使能器件
    SPI_FLASH_SendByte(FLASH_WriteDisable);  //发送写禁止指令
    SPI_FLASH_CS_HIGH();                            //取消片选
}

  /**
  * @Brief     FLASH读芯片ID函数      
  * @Param     None
  * @Return    芯片的ID
  * @Note      测试芯片是XT25F08B,ID为0x0B13
  */
uint16_t BSP_SPI_FLASH_ReadID(void)
{
    uint16_t Temp = 0;
    SPI_FLASH_CS_LOW();
    SPI_FLASH_SendByte(0x90);//发送读取ID命令
    SPI_FLASH_SendByte(0x00);
    SPI_FLASH_SendByte(0x00);
    SPI_FLASH_SendByte(0x00);
    Temp|=SPI_FLASH_SendByte(0xFF)<<8;
    Temp|=SPI_FLASH_SendByte(0xFF);
    SPI_FLASH_CS_HIGH();
    return Temp;
}
  /**
  * @Brief     FLASH读函数      
  * @Param     pBuffer  数据存储区
  * @Param     ReadAddr 开始读取的地址(24bit)
  * @Param     NumByteToRead  要读取的字节数(最大65535)
  * @Return    None
  * @Note      在指定地址开始读取指定长度的数据
  */
void BSP_SPI_FLASH_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)
{
    uint16_t i;
    SPI_FLASH_CS_LOW();                            //使能器件
    SPI_FLASH_SendByte(FLASH_ReadData);      //发送读取命令

    SPI_FLASH_SendByte((uint8_t)((ReadAddr)>>16));   //发送24bit地址
    SPI_FLASH_SendByte((uint8_t)((ReadAddr)>>8));
    SPI_FLASH_SendByte((uint8_t)ReadAddr);
    for(i=0; i<NumByteToRead; i++)
    {
        pBuffer[i]=SPI_FLASH_SendByte(0XFF);    //循环读数
    }
    SPI_FLASH_CS_HIGH();
}
  /**
  * @Brief     FLASH页写函数      
  * @Param     pBuffer  数据存储区
  * @Param     WriteAddr 开始写入的地址(24bit)
  * @Param     NumByteToWrite  要写入的字节数(最大256),该数不应该超过该页的剩余字节数
  * @Return    None
  * @Note      在一页(0~65535)内写入少于256个字节的数据
  */
void BSP_SPI_FLASH_Write_Page(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
    uint16_t i;
    BSP_SPI_FLASH_Write_Enable();                  //SET WEL
    SPI_FLASH_CS_LOW();                            //使能器件
    SPI_FLASH_SendByte(FLASH_PageProgram);   //发送写页命令

    SPI_FLASH_SendByte((uint8_t)((WriteAddr)>>16)); //发送24bit地址
    SPI_FLASH_SendByte((uint8_t)((WriteAddr)>>8));
    SPI_FLASH_SendByte((uint8_t)WriteAddr);
    for(i=0; i<NumByteToWrite; i++)SPI_FLASH_SendByte(pBuffer[i]); //循环写数
    SPI_FLASH_CS_HIGH();                            //取消片选
    BSP_SPI_FLASH_Wait_Busy();					   //等待写入结束
}
  /**
  * @Brief     FLASH页无检验写函数      
  * @Param     pBuffer  数据存储区
  * @Param     WriteAddr 开始写入的地址(24bit)
  * @Param     NumByteToWrite  要写入的字节数(最大65535)
  * @Return    None
  * @Note      必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败
  *            具有自动换页功能
  *            在指定地址开始写入指定长度的数据,但是要确保地址不越界
  */
void BSP_SPI_FLASH_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
    uint16_t pageremain;
    pageremain=256-WriteAddr%256; //单页剩余的字节数
    if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节
    while(1)
    {
        BSP_SPI_FLASH_Write_Page(pBuffer,WriteAddr,pageremain);
        if(NumByteToWrite==pageremain)break;//写入结束了
        else //NumByteToWrite>pageremain
        {
            pBuffer+=pageremain;
            WriteAddr+=pageremain;

            NumByteToWrite-=pageremain;			  //减去已经写入了的字节数
            if(NumByteToWrite>256)pageremain=256; //一次可以写入256个字节
            else pageremain=NumByteToWrite; 	  //不够256个字节了
        }
    };
}
/** FLASH 缓存数组*/
uint8_t BSP_SPI_FLASH_BUFFER[4096];
  /**
  * @Brief     FLASH写函数      
  * @Param     pBuffer  数据存储区
  * @Param     WriteAddr 开始写入的地址(24bit)
  * @Param     NumByteToWrite  要写入的字节数(最大65535)
  * @Return    None
  * @Note      在指定地址开始写入指定长度的数据
  *            该函数带擦除操作!
  */
void BSP_SPI_FLASH_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
    uint32_t secpos;
    uint16_t secoff;
    uint16_t secremain;
    uint16_t i;
    uint8_t * BSP_SPI_FLASH_BUF;
    BSP_SPI_FLASH_BUF=BSP_SPI_FLASH_BUFFER;
    secpos=WriteAddr/4096;//扇区地址
    secoff=WriteAddr%4096;//在扇区内的偏移
    secremain=4096-secoff;//扇区剩余空间大小
    //printf("ad:%X,nb:%X\r\n",WriteAddr,NumByteToWrite);//测试用
    if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大于4096个字节
    while(1)
    {
        BSP_SPI_FLASH_Read(BSP_SPI_FLASH_BUF,secpos*4096,4096);//读出整个扇区的内容
        for(i=0; i<secremain; i++) //校验数据
        {
            if(BSP_SPI_FLASH_BUF[secoff+i]!=0XFF)break;//需要擦除
        }
        if(i<secremain)//需要擦除
        {
            BSP_SPI_FLASH_Erase_Sector(secpos);//擦除这个扇区
            for(i=0; i<secremain; i++)	 //复制
            {
                BSP_SPI_FLASH_BUF[i+secoff]=pBuffer[i];
            }
            BSP_SPI_FLASH_Write_NoCheck(BSP_SPI_FLASH_BUF,secpos*4096,4096);//写入整个扇区

        }
        else BSP_SPI_FLASH_Write_NoCheck(pBuffer,WriteAddr,secremain); //写已经擦除了的,直接写入扇区剩余区间.
        if(NumByteToWrite==secremain)break;//写入结束了
        else//写入未结束
        {
            secpos++;//扇区地址增1
            secoff=0;//偏移位置为0

            pBuffer+=secremain;  //指针偏移
            WriteAddr+=secremain;//写地址偏移
            NumByteToWrite-=secremain;				//字节数递减
            if(NumByteToWrite>4096)secremain=4096;	//下一个扇区还是写不完
            else secremain=NumByteToWrite;			//下一个扇区可以写完了
        }
    };
}
  /**
  * @Brief     FLASH擦除整个芯片函数      
  * @Param     None
  * @Return    None
  * @Note      需要等待很长时间
  */
void BSP_SPI_FLASH_Erase_Chip(void)
{
    BSP_SPI_FLASH_Write_Enable();                  //SET WEL
    BSP_SPI_FLASH_Wait_Busy();
    SPI_FLASH_CS_LOW();                            //使能器件
    SPI_FLASH_SendByte(FLASH_ChipErase);        //发送片擦除命令
    SPI_FLASH_CS_HIGH();                            //取消片选
    BSP_SPI_FLASH_Wait_Busy();   				   //等待芯片擦除结束
}
  /**
  * @Brief     FLASH擦除一个扇区函数      
  * @Param     Dst_Addr  扇区地址 根据实际容量设置
  * @Return    None
  * @Note      擦除一个扇区的最少时间:150ms
  */
void BSP_SPI_FLASH_Erase_Sector(uint32_t Dst_Addr)
{
    //监视falsh擦除情况,测试用
    //printf("fe:%x\r\n",Dst_Addr);
    Dst_Addr*=4096;
    BSP_SPI_FLASH_Write_Enable();                  //SET WEL
    BSP_SPI_FLASH_Wait_Busy();
    SPI_FLASH_CS_LOW();                            //使能器件
    SPI_FLASH_SendByte(FLASH_SectorErase);   //发送扇区擦除指令

    SPI_FLASH_SendByte((uint8_t)((Dst_Addr)>>16));  //发送24bit地址
    SPI_FLASH_SendByte((uint8_t)((Dst_Addr)>>8));
    SPI_FLASH_SendByte((uint8_t)Dst_Addr);
    SPI_FLASH_CS_HIGH();                            //取消片选
    BSP_SPI_FLASH_Wait_Busy();   				    //等待擦除完成
}
  /**
  * @Brief     FLASH等待空闲函数      
  * @Param     None
  * @Return    None
  * @Note      None
  */
void BSP_SPI_FLASH_Wait_Busy(void)
{
    while((BSP_SPI_FLASH_ReadSR(1)&0x01)==0x01);   // 等待BUSY位清空
}
  /**
  * @Brief     FLASH进入掉电模式函数      
  * @Param     None
  * @Return    None
  * @Note      None
  */
void BSP_SPI_FLASH_PowerDown(void)
{
    SPI_FLASH_CS_LOW();                            //使能器件
    SPI_FLASH_SendByte(FLASH_PowerDown);     //发送掉电命令
    SPI_FLASH_CS_HIGH();                            //取消片选
    HAL_Delay(2);                            //等待TPD
}
  /**
  * @Brief     FLASH唤醒函数      
  * @Param     None
  * @Return    None
  * @Note      None
  */
void BSP_SPI_FLASH_WAKEUP(void)
{
    SPI_FLASH_CS_LOW();                                //使能器件
    SPI_FLASH_SendByte(FLASH_ReleasePowerDown);  //  send FLASH_PowerDown command 0xAB
    SPI_FLASH_CS_HIGH();                                //取消片选
    HAL_Delay(2);                                //等待TRES1
}

路径
在 usart.c 中,重定向 printf 函数,需要添加头文件 #include “stdio.h”

#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
	HAL_UART_Transmit(&huart2 , (uint8_t *)&ch, 1 , 0xffff);
	return ch;

打开 user_diskio.c 函数,准备修改读写的底层驱动。
配置
定义外部FLASH的驱动器号和容量,为了方便,设定为1个块,2048 个扇区,每个扇区512字节。

/** 定义外部FLASH物理驱动器号为0*/
#define EX_FLASH		0	/* Example: Map Ramdisk to physical drive 0 */

/**
*@name 定义FLASH的大小
*@{
*/
/** 定义FLAH 一个扇区的大小*/
#define FLASH_SECTOR_SIZE 	512	
/** 定义FLASH 扇区的数量*/
#define FLASH_SECTOR_COUNT 	8*256
/** 定义FLASH 块的数量*/
#define FLASH_BLOCK_SIZE   	1    
/** @} */

代码图
在 USER_initialize 函数中添加初始化。

		MX_SPI1_Init();
		if(BSP_SPI_FLASH_ReadID() == 0X0B13 )
		{
			Stat = RES_OK;
		}
		else
		{
			Stat = STA_NOINIT;
		}   
    	return Stat;

代码
在 USER_status 添加状态获取。

		if(BSP_SPI_FLASH_ReadID() == 0X0B13 )
		{
			Stat = RES_OK;
		}
		else
		{
			Stat = STA_NOINIT;
		}   
    	return Stat;

代码
在 USER_read 中添加 读函数

	switch(pdrv)
	{
			case EX_FLASH :
			BSP_SPI_FLASH_Read(buff,sector*FLASH_SECTOR_SIZE,count*FLASH_SECTOR_SIZE);
			return RES_OK;
	}
   return RES_PARERR;

代码
在USER_write 函数中添加写函数

	uint8_t res=0;  
  	if (!count)return RES_PARERR;	 	 
	switch(pdrv)
	{

		case EX_FLASH:							    
			BSP_SPI_FLASH_Write((uint8_t*)buff,sector*FLASH_SECTOR_SIZE,count*FLASH_SECTOR_SIZE);		
			res=0;
			break;
		default:
			res=1; 
	}
    if(res == 0x00)return RES_OK;	 
    else return RES_ERROR;

代码
在 USER_ioctl 中添加 FLASH 的大小。

		DRESULT res = RES_ERROR;
	  	if(pdrv==EX_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 res=RES_ERROR;//其他的不支持
   
	return res;

代码
在main.c 中 或者新添加 fatfs_demo.c ,去添加测试程序。
先定义存储的变量。

/** 定义空文件系统存储变量*/
FATFS flash_fs;

/** 定义空文件存储变量*/
FIL testfp;

/** 定义格式化的工作缓冲区*/
BYTE work[_MIN_SS];

/** 定义每次写入的数据长度*/
UINT bw;
/** 定于整体写入的数据长度*/
uint32_t FATFS_Addr=0;

/** 定义输出的数据值*/
char Data_Buff[20]="123456";
/** 定义读出的数据值*/
char Read_Buff[20]="";
/** 返回函数状态*/
FRESULT myret;

添加测试初始化函数。
在第一次进行初始化时,一定要全部擦除FLASH ,然后强制使用 f_mkfs 函数进行格式化。

/**
  * @Brief    文件系统初始化函数       
  * @Param     None
  * @RetVal    None
  * @Note      判断是否需要进行格式化
  */
void fatfs_init(void)
{   
  FRESULT res_flash;
    
  printf( "\r\n文件系统测试\r\n" );
  res_flash =f_mount(&flash_fs,"0:",0);
  if(res_flash == FR_NO_FILESYSTEM)
  {
		printf( "\r\n 即将进行格式化... \r\n");
    
		res_flash = f_mkfs("0:",FM_ANY,0,work,sizeof(work));
    if(res_flash == FR_OK)
    {
        printf( "\r\n 已成功格式化r\n");
        
        res_flash=f_mount(NULL,"0:",0);
        res_flash=f_mount(&flash_fs,"0:",0);
    }
    else
    {
        printf( "\r\n 格式化失败r\n");
        while(1);
    }
  }
  else if(res_flash != FR_OK )
  {
      printf( "\r\n 文件系统挂载失败r\n");
      while(1);
  }
  else
  {
      printf("》文件系统挂载成功,可以进行读写测试\r\n");
  }
}

添加测试demo,进行读写测试。

/**
  * @Brief     文件系统测试函数       
  * @Param     None
  * @RetVal    None
  * @Note      创建TXT格式文件
  */
void fatfs_test(void)
{
	myret = f_open(&testfp,"0:/test.txt",FA_OPEN_ALWAYS|FA_WRITE|FA_READ);
    if(myret== FR_OK)
    {
				printf("创建文件成功\r\n");

				f_lseek(&testfp,FATFS_Addr);
			
        myret = f_write(&testfp, (const void*)Data_Buff, sizeof(Data_Buff)-1, &bw);    
				if(myret== FR_OK)
				{
					printf("写入成功\r\n");	
				}					
        f_close(&testfp);
    }
		myret = f_open(&testfp,"0:/test.txt",FA_READ);
		if(myret== FR_OK)
    {
				printf("打开文件成功\r\n");

				f_lseek(&testfp,FATFS_Addr);
			
        		myret = f_read(&testfp, (void*)Read_Buff, sizeof(Read_Buff)-1, &bw);    
				if(myret== FR_OK)
				{
					printf("文件读取成功,读到的字节数据:%d\r\n",bw);
					printf("读取的文件数据为:%s\r\n",Read_Buff);
				}
				else
				{
					printf("读取失败:%d\r\n",myret); 
				}					
        f_close(&testfp);
    }
}

五、实验结果

串口有数据显示,也可以通过KEIL 仿真查看。
结果

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jeni成长小栈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值