打印
[STM32L0]

stm32文件系统求助

[复制链接]
3026|13
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
0323w|  楼主 | 2015-12-30 14:08 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
用stm32读写sd卡信息,不知道怎么入手,建立一个文件系统将采集的信息保存修改查看等。
沙发
米尔豪斯| | 2015-12-30 18:40 | 只看该作者
着问题大了,楼主网上下资料看看

使用特权

评论回复
板凳
JY-DX-JY| | 2015-12-30 18:47 | 只看该作者
找于振南

使用特权

评论回复
地板
dongnanxibei| | 2015-12-30 21:52 | 只看该作者
这个有两种方式,一个是采用SD开的专门接口通信,速度快,还有一个采用SPI接口通信,速度慢。楼主想玩哪个?

使用特权

评论回复
5
dongnanxibei| | 2015-12-30 21:52 | 只看该作者
STM32----SPI方式读写SD卡  SD支持两种读写方式,对于单片机来说,有的并没有SDIO,所以,使用SPI更加适合使用单片机的场合,当然,现在很多型号也都有SDIO了,所以,有SDIO的,使用SDIO才是王道。

SPI使用的是查询法,还没想好如果用中断的话怎么写好,或是加入DMA,这些后面再来实现,下面来实现SD使用SPI方式读写。

程序是VS2008里面编写的,哈哈,用VS来写程序真是爽啊,可惜太庞大了点……

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

static volatile u8 sd_type;

__inline static u8 sd_ReadWriteByte( u8 _byte );
__inline static void sd_Disable_Select( void );
__inline static u8 sd_Enable_Select( void );
__inline static void sd_send_one_cmd( u8 cmd );

static void spi_SpeedLow( void );
static void spi_SpeedHigh( void );
static void sd_gpio_spi_init( void );

static u8 sd_WaitResponse( u8 response );
static u8 sd_WaitRead( void );
static u8 sd_mmc_init( void );
static u8 sd_send_cmds( u8 cmd, u32 arg, u8 crc );



static u8 sd_GetCSD( u8 *csd_buff ); // 还没实现
static u8 sd_GetCID( u8 *cid_buff ); // 还没实现

static u8 sd_ReceiveDataToBuffer( u8 *buff, u16 lenght );
static u8 sd_WriteBufferToDisk( u8 *buff, u8 cmd );

u32 SD_GetVolume( void ) // 获取容量,单位M
{
    return 0;
}


u32 SD_GetSectorCount( void ) // 获取扇区数量
{
    return 0;
}


使用特权

评论回复
6
dongnanxibei| | 2015-12-30 21:53 | 只看该作者
/******************************************************************************************************************************
* 函数名称:SD_WriteMultiSectors
* 函数功能:写数据到多个块或是扇区
* 函数说明:可以写一个或多个
* 参数说明:数据指针  扇区块位置   数量
* 返 回 值:0 成功    1 失败
* 函数调用:
* 全局变量:
* 编    写:
*  E-mail :
* 修改备注:
* 版    本:V1.0
* 日    期:2012年5月21日 星期一  17:58:42
******************************************************************************************************************************/
u8 SD_WriteMultiSectors( u8 *buff, u32 sectors, u32 num )
{
u8 sta;

    if ( sd_type != SD_TYPE_V2HC )
    {
        sectors *= 512;
    }
if ( num == 1 )
{
  sta = sd_send_cmds( SD_CMD24, sectors, 0x01 );
  if ( sta == 0 )
  {
   sta = sd_WriteBufferToDisk( buff, 0xFE );
  }
}
else {
  if ( sd_type != SD_TYPE_MMC )
  {
   sd_send_cmds( SD_CMD55, 0, 0x01 );
   sd_send_cmds( SD_CMD23, num, 0x01 );
  }
  sta = sd_send_cmds( SD_CMD25, sectors, 0x01 );
  if ( sta == 0 )
  {
   do
   {
    sta = sd_WriteBufferToDisk( buff, 0xFC );
    buff += 512;
    num--;
   } while ( (sta==0)&&(num) );
   sta = sd_WriteBufferToDisk( buff, 0xfd );
  }
}
sd_Disable_Select();
return sta;
}

使用特权

评论回复
7
dongnanxibei| | 2015-12-30 21:53 | 只看该作者
/******************************************************************************************************************************
* 函数名称:SD_WriteSingleSectors
* 函数功能:把数据缓冲的数据写入卡里
* 函数说明:一次只写个扇区或块
* 参数说明:缓冲区数据指针   扇区或块的位置
* 返 回 值:0  成功   1 失败
* 函数调用:
* 全局变量:
* 编    写:
*  E-mail :
* 修改备注:
* 版    本:v1.0
* 日    期:2012年5月21日 星期一  17:57:43
******************************************************************************************************************************/
u8 SD_WriteSingleSectors( u8 *buff, u32 sectors )
{
u8 sta;

if ( sd_type != SD_TYPE_V2HC )
{
  sectors *= 512;
}
sta = sd_send_cmds( SD_CMD24, sectors, 0x01 );
if ( sta == 0 )
{
  sta = sd_WriteBufferToDisk( buff, 0xFE );
}
sd_Disable_Select();
#if SD_DEBUG_EN>0
printf( "数据写入返回值为 %x \n\n\n", sta );
#endif
return sta;
}


/******************************************************************************************************************************
* 函数名称:SD_ReadMultiSectors
* 函数功能:读取多个扇区或是块的数据
* 函数说明:可以读取一个或是多个
* 参数说明:缓冲区数据指针   扇区/块位置    扇区/块的数量
* 返 回 值:0  成功正确   1  失败异常
* 函数调用:
* 全局变量:
* 编    写:
*  E-mail :
* 修改备注:
* 版    本:V1.0
* 日    期:2012年5月21日 星期一  17:56:02
******************************************************************************************************************************/
u8 SD_ReadMultiSectors( u8 *buff, u32 sectors, u32 num )
{
u8 sta;

if ( sd_type != SD_TYPE_V2HC )
{ // 如果不是2.0HC高速卡,则转换为字节地址
  sectors <<= 9;
  #if SD_DEBUG_EN>0
   printf( "使用的不是高速卡哦!" );
  #endif
}

if ( num == 1 )
{
  sta = sd_send_cmds( SD_CMD17, sectors, 0x01 );
  if ( sta == 0 )
  {
   sta = sd_ReceiveDataToBuffer( buff, 512 );
  }
}
else {
  sta = sd_send_cmds( SD_CMD18, sectors, 0x01 );
  do
  {
   sta = sd_ReceiveDataToBuffer( buff, 512 );
   buff += 512;
   num--;
  } while ( (sta==0)&&num );
  sd_send_cmds( SD_CMD12, 0, 0x01 );
}
sd_Disable_Select();
return sta;
}

/******************************************************************************************************************************
* 函数名称:SD_ReadSingleSectors
* 函数功能:读取一个扇区的数据到缓冲区
* 函数说明:读取的单位是扇区
* 参数说明:缓冲区指针    扇区位置/偏置
* 返 回 值:
* 函数调用:
* 全局变量:
* 编    写:
*  E-mail :
* 修改备注:
* 版    本:V1.0
* 日    期:2012年5月21日 星期一  17:16:59
******************************************************************************************************************************/
u8 SD_ReadSingleSectors( u8 *buff, u32 sectors )
{
u8 sta;
    #if SD_DEBUG_EN>0
    printf( "\n要读取的扇区是%d\n\n", sectors );
    #endif
if ( sd_type != SD_TYPE_V2HC )
{ // 如果不是2.0HC高速卡,则转换为字节地址
  sectors <<= 9;
}

sta = sd_send_cmds( SD_CMD17, sectors, 0x01 );
if ( sta == 0 )
{
  sta = sd_ReceiveDataToBuffer( buff, 512 );
}
sd_Disable_Select();
return sta;
}


/******************************************************************************************************************************
* 函数名称:SD_Init
* 函数功能:检测卡是否存在并检测卡的类型,初始化SD卡
* 函数说明:目前可以适用的卡有V1.0,V2.0,V2.0HC,MMC
* 参数说明:
* 返 回 值:0 初始化成功与正常  1 初始化失败或是卡异常
* 函数调用:
* 全局变量:
* 编    写:
*  E-mail :
* 修改备注:
* 版    本:V1.0
* 日    期:2012年5月21日 星期一  17:27:07
******************************************************************************************************************************/
u8 SD_Init( void )
{
u16 i;
u16 cnt;
u8  sta;
u8  buf[4];

sd_type = 0x00;
sd_gpio_spi_init();
sd_Disable_Select();// 取消片选
delay_ms( 5 );  // 小延时,让SD稳定下来

// 发送至少74个时钟,让SD卡完成上电后的工作
for ( cnt = 0; cnt < 11; cnt++ )
{
  sd_ReadWriteByte( 0xff ); // 不使能片选信号,发送时钟
}

// 接下来发送命令0,让SD卡复位进入空状态
cnt = 200;
do
{ // 循环读取发送命令0的返回状态,直到出现0x01或是超出200次
  sta = sd_send_cmds( SD_CMD0, 0, 0x95 );
  cnt--;
} while ( ( sta != 0x01 ) && ( cnt ) );

if ( cnt == 0) // 判断上面循环退出的原因,读取到0x01???? 超时????
{
  // 如果超时了,取消片选后,直接退出
  sd_Disable_Select();

  #if SD_DEBUG_EN>0 // 如果使能了调试,则通过串口打印出调试信息
   printf( "SD卡复位失败.......\n\n" );
  #endif

  return 1; // 返回1,初始化失败
}

#if SD_DEBUG_EN>0
  printf( "SD卡复位成功........\n\n" );
#endif

// 读取命令8的返回值
sta = sd_send_cmds( SD_CMD8, 0x1AA, 0x87 );
#if SD_DEBUG_EN>0 // 使能调试时,通过串口打印出该命令的返回值
  printf( "命令SD_CMD8  返回  %d........\n\n", sta );
#endif

if ( sta == 0x01 ) // 如果是0x01, 则是2.0版本,2.0版本中还是2.0HC版本
{
  // 读取命令8后卡发送来的四字节数据,只有2.0版本有
  for ( i = 0; i < 4; i++ )
  {
   buf[ i ] = sd_ReadWriteByte( 0xff );
  }
  #if SD_DEBUG_EN>0 // 使能调试时
   printf( "检测到卡为2.0卡..." );
   printf( "接收到手四字节数据是:%d  %d  %d  %d\n\n", buf[0], buf[1], buf[2], buf[3] );
  #endif
  
  // 根据读取回来的四字节数据,判断该卡是否支持2.7---3.6的电压
  if ( ( buf[ 2 ] == 0x01 )&&( buf[ 3 ] == 0xAA ) ) //
  {
   #if SD_DEBUG_EN>0
    printf( "SD卡可以支持电压范围2.7---3.6....\n\n" );
   #endif
   // 只有支持2.7---3.6电压了才继续操作
   cnt = 0xffff;
   do
   {
    sd_send_cmds( SD_CMD55, 0, 0x01 );
    sta = sd_send_cmds( SD_CMD41, 0x40000000, 0x01 );
    cnt--;
   } while ( sta && cnt );

   sta = sd_send_cmds( SD_CMD58, 0, 0 );

   if ( sta != 0x00 ) // 如果没有得到正确的回应
   {
    sd_Disable_Select();
    #if SD_DEBUG_EN>0
     printf( "命令SD_CMD58错误返回 %d....\n\n", sta );
    #endif
    return 1;
   }

   // 如果有得到正确的回应,则读取卡发回来的OCR信息
   for ( i = 0; i < 4; i++ ) // 读取四字节的信息
   {
    buf[ i ] = sd_ReadWriteByte( 0xff );
   }
   sd_Disable_Select();
   #if SD_DEBUG_EN>0
    printf( "从卡读取回来的OCR信息是 %x %x %x %x....\n\n", buf[0],buf[1],buf[2],buf[3] );
   #endif
   // 读取完成,鉴别卡是2.0还是2.0HC
   if ( buf[0] & 0x40 )
   {
    #if SD_DEBUG_EN>0
     printf( "检测到卡的类型是V2.0HC高速卡,可以正常使用.....\n\n" );
    #endif
    sd_type = SD_TYPE_V2HC;
   }
   else {
    #if SD_DEBUG_EN>0
     printf( "检测到卡的类型是V2.0普通卡,可以正常使用.....\n\n" );
    #endif
    sd_type = SD_TYPE_V2;
   }
   
   spi_SpeedHigh(); // 让SPI进入高速模式
  }
  else { // 如果不支持2.7---3.6电压的处理
   sd_Disable_Select();
   return 1;
  }
}
else { // 认为是1.0版本或是MMC卡,如果是MMC,需要设置扇区的大小
  // 无四字节数据的输出
  sd_type = SD_TYPE_V1; // 暂时认为是V1.0的卡
  sd_send_cmds( SD_CMD55, 0, 0x01 );
  sta = sd_send_cmds( SD_CMD41, 0, 0x01 );
  
  if ( sta <= 1 )
  { // V1.0卡
   sd_type = SD_TYPE_V1;
   cnt = 0xffff;
   do
   {
    sd_send_cmds( SD_CMD55, 0, 0x01 );
    sta = sd_send_cmds( SD_CMD41, 0, 0x01 );
    cnt--;
   } while ( sta && cnt );
   #if SD_DEBUG_EN>0
    printf( "检测到卡的类型是V1.0普通卡," );
   #endif
  }
  else { // MMC卡
   sd_type = SD_TYPE_MMC;
   cnt = 0xffff;
   do
   {
    sta = sd_send_cmds( SD_CMD1, 0, 0x01 );
    cnt--;
   } while ( sta && cnt );
   #if SD_DEBUG_EN>0
    printf( "检测到卡的类型是MMC卡," );
   #endif
  }
  if ( (cnt==0)||(sd_send_cmds(SD_CMD16,512,0x01)!=0) )
  {
   sd_type = SD_TYPE_ERR;
   sd_Disable_Select();
   #if SD_DEBUG_EN>0
    printf( "无法设置卡的扇区大小,请检查卡!\n\n" );
   #endif
   return 1;
  }
  #if SD_DEBUG_EN>0
  else {
   printf( "可以正常使用了.....\n\n" );
  }
  #endif
}

sd_Disable_Select();
return 0; // 返回0 , 初始化成功
}

使用特权

评论回复
8
dongnanxibei| | 2015-12-30 21:54 | 只看该作者
/******************************************************************************************************************************
* 函数名称:sd_WriteBufferToDisk
* 函数功能:写缓冲的区数据到卡
* 函数说明:
* 参数说明:
* 返 回 值:
* 函数调用:
* 全局变量:
* 编    写:
*  E-mail :
* 修改备注:
* 版    本:V1.0
* 日    期:2012年5月21日 星期一  17:42:59
******************************************************************************************************************************/
static u8 sd_WriteBufferToDisk( u8 *buff, u8 cmd )
{
u16 cnt;
u8 sta;
if ( sd_WaitRead() )
{
#if SD_DEBUG_EN>0
printf( "数据写入等待失败....\n\n\n" );
#endif
  return 1;
}
sd_ReadWriteByte( cmd );
if ( cmd != 0xFD )
{
  for ( cnt = 0; cnt < 512; cnt++ )
  {
   sd_ReadWriteByte( *buff );
   buff++;
  }
  for ( cnt = 0; cnt < 2; cnt++ )
  {
   sd_ReadWriteByte( 0xff );
  }
  sta = sd_ReadWriteByte( 0xff );
  if ( ( sta & 0x1F ) != 0x05 )
  {
   #if SD_DEBUG_EN>0
    printf( "数据完成,但发生错误,错误码是 %x  \n\n\n", sta );
   #endif
   return 2;
  }
}

return 0;
}

/******************************************************************************************************************************
* 函数名称:sd_ReceiveDataToBuffer
* 函数功能:接收长度为lenght的数据到缓冲区buff
* 函数说明:最长65536
* 参数说明:缓冲区指针与接收长度
* 返 回 值:接收状态 0  正常     1 错误
* 函数调用:
* 全局变量:
* 编    写:
*  E-mail :
* 修改备注:
* 版    本:V1.0
* 日    期:2012年5月21日 星期一  15:09:54
******************************************************************************************************************************/
static u8 sd_ReceiveDataToBuffer( u8 *buff, u16 lenght )
{
u8 cnt;
// 等待令牌 0xfe 回应
if ( sd_WaitResponse( 0xfe ) )
{
#if SD_DEBUG_EN>0
  printf( "读取数据时等待令牌 0xFE 失败....\n\n" );
#endif
  return 1;
}
while ( lenght-- )
{
  *buff = sd_ReadWriteByte( 0xff );
  buff++;
}
// 不进行CRC校验,发送假的CRC
for ( cnt = 0; cnt < 2; cnt++ )
{
  sd_ReadWriteByte( 0xff );
}

return 0;
}

/******************************************************************************************************************************
* 函数名称:sd_send_cmds
* 函数功能:发送一个命令+参数+CRC校验码给SD
* 函数说明:SD的命令一般由六个字节组合而成
* 参数说明:函数会先取消卡的片选信号 ,再便能该信号
* 返 回 值:
* 函数调用:sd_ReadWriteByte
* 全局变量:
* 编    写:
*  E-mail :
* 修改备注:
* 版    本:V1.0
* 日    期:2012年5月20日 星期日  19:37:24
******************************************************************************************************************************/
static u8 sd_send_cmds( u8 cmd, u32 arg, u8 crc )
{
u32 cnt=512;
u8  sta;

sd_Disable_Select();  // 先取消片选
if ( sd_Enable_Select() ) // 再使能片选
{
  return 0xff;   // 如果片选失败,退出返回255
}

sd_ReadWriteByte( cmd | 0x40 );  // 发送命令组合
sd_ReadWriteByte( (u8)(arg>>24) ); // 参数1
sd_ReadWriteByte( (u8)(arg>>16) ); // 参数2
sd_ReadWriteByte( (u8)(arg>>8) ); // 参数3
sd_ReadWriteByte( (u8)(arg) );  // 参数4
sd_ReadWriteByte( crc );   // CRC校验码

do
{
  sta = sd_ReadWriteByte( 0xff ); // 读取发送状态
  cnt--;
} while ( (cnt)&&(sta==0xff) );

return sta; // 返回发送状态   
}


/******************************************************************************************************************************
* 函数名称:sd_send_one_cmd
* 函数功能:发送一个命令给SD/MMC卡
* 函数说明:内联
* 参数说明:待发送的命令,发送前需要先使能片选
* 返 回 值:
* 函数调用:sd_ReadWriteByte
* 全局变量:
* 编    写:
*  E-mail :
* 修改备注:
* 版    本:V1.0
* 日    期:2012年5月20日 星期日  19:36:17
******************************************************************************************************************************/
__inline static void sd_send_one_cmd( u8 cmd )
{
sd_ReadWriteByte( cmd ); // 发送一字节的命令
}


/******************************************************************************************************************************
* 函数名称:sd_WaitResponse
* 函数功能:读取SD/MMC/指定的应答状态
* 函数说明:
* 参数说明:指定的应答状态,应答码
* 返 回 值:应答是否符合 0 符合     1 不符合
* 函数调用:sd_ReadWriteByte
* 全局变量:
* 编    写:
*  E-mail :
* 修改备注:
* 版    本:V1.0
* 日    期:2012年5月20日 星期日  19:34:46
******************************************************************************************************************************/
static u8 sd_WaitResponse( u8 response )
{
u16 cnt = 4096;

do
{
  if ( sd_ReadWriteByte( 0xff ) == response ) // 判断指定的应答是否出现
  {
   return MSD_RESPONSE_NO_ERROR;
  }
  cnt--;
} while ( cnt );
#if SD_DEBUG_EN>0
printf( "等待 0x%x 信号失败....\n\n", response );
#endif
return MSD_RESPONSE_FAILURE;
}


/******************************************************************************************************************************
* 函数名称:sd_WaitRead
* 函数功能:等SD/MMC卡读就绪
* 函数说明:只有就绪的时候才可以进行读取操作
* 参数说明:
* 返 回 值:等待状态  0 就绪    1 没就绪,错误
* 函数调用:sd_ReadWriteByte
* 全局变量:
* 编    写:
*  E-mail :
* 修改备注:
* 版    本:V1.0
* 日    期:2012年5月20日 星期日  19:33:29
******************************************************************************************************************************/
static u8  sd_WaitRead( void )
{
u32 cnt = 0x00ffffff;
u8  sta;
do
{
  sta = sd_ReadWriteByte( 0xff );
  if ( sta == 0xff ) // 判断等待读取是否就绪
  {
   return 0;
  }
  cnt--;
} while ( cnt );
#if SD_DEBUG_EN>0
printf( "等待超时....\n\n" );
#endif
return 1;
}


/******************************************************************************************************************************
* 函数名称:sd_Enable_Select
* 函数功能:选择SD卡
* 函数说明:内联
* 参数说明:
* 返 回 值:0 选择成功      1 选择失败
* 函数调用:sd_WaitRead   sd_Disable_Select
* 全局变量:
* 编    写:
*  E-mail :
* 修改备注:
* 版    本:V1.0
* 日    期:2012年5月20日 星期日  19:32:20
******************************************************************************************************************************/
__inline static u8 sd_Enable_Select( void )
{
SD_CS_RESET();    // 使能片选
if ( sd_WaitRead() == 0 ) // 等待SD/MMC就绪
{
  return 0;
}
sd_Disable_Select();  // 如果没就绪,则取消片选
#if SD_DEBUG_EN>0
printf( "SD片选使能失败....\n\n" );
#endif
return 1;     // 返回1,片选失败
}


/******************************************************************************************************************************
* 函数名称:sd_Disable_Select
* 函数功能:取消片选SD/MMC卡
* 函数说明:内联
* 参数说明:
* 返 回 值:
* 函数调用:sd_ReadWriteByte
* 全局变量:
* 编    写:
*  E-mail :
* 修改备注:
* 版    本:V1.0
* 日    期:2012年5月20日 星期日  19:31:09
******************************************************************************************************************************/
__inline static void sd_Disable_Select( void )
{
SD_CS_SET();    // 取消片选
sd_ReadWriteByte( 0xff ); // 补八个时钟
}


/******************************************************************************************************************************
* 函数名称:sd_gpio_spi_init
* 函数功能:初始化SD对应的GPIO和SPI总线
* 函数说明:
* 参数说明:
* 返 回 值:
* 函数调用:GPIO_Init SPI_1_Configuration
* 全局变量:
* 编    写:
*  E-mail :
* 修改备注:
* 版    本:V1.0
* 日    期:2012年5月20日 星期日  19:29:59
******************************************************************************************************************************/
static void sd_gpio_spi_init( void )
{
GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );
GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_3 | GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
GPIO_Init( GPIOA, &GPIO_InitStructure );
GPIO_SetBits( GPIOA, GPIO_Pin_3 | GPIO_Pin_4 );
SD_CS_SET();
SPI_1_Configuration();
spi_SpeedLow();
}


/******************************************************************************************************************************
* 函数名称:spi_SpeedHigh
* 函数功能:让SPI进入高速模式
* 函数说明:
* 参数说明:
* 返 回 值:
* 函数调用:SPI_1_SpeedSeting
* 全局变量:
* 编    写:
*  E-mail :
* 修改备注:
* 版    本:V1.0
* 日    期:2012年5月20日 星期日  19:29:04
******************************************************************************************************************************/
static void spi_SpeedHigh( void )
{
SPI_1_SpeedSeting( SPI_BaudRatePrescaler_2 ); // SPI最高速
delay_us( 10 );
}


/******************************************************************************************************************************
* 函数名称:spi_SpeedLow
* 函数功能:让SPI进入低速模式
* 函数说明:
* 参数说明:
* 返 回 值:
* 函数调用:SPI_1_SpeedSeting
* 全局变量:
* 编    写:
*  E-mail :
* 修改备注:
* 版    本:V1.0
* 日    期:2012年5月20日 星期日  19:28:08
******************************************************************************************************************************/
static void spi_SpeedLow( void )
{
SPI_1_SpeedSeting( SPI_BaudRatePrescaler_256 ); // SPI最低速
delay_us( 10 );
}


/******************************************************************************************************************************
* 函数名称:sd_ReadWriteByte
* 函数功能:读取或写入一字节的数据到SD卡
* 函数说明:内联
* 参数说明:写入的数据
* 返 回 值:读取到的数据
* 函数调用:SPI_1_ReadWriteByte
* 全局变量:无
* 编    写:
*  E-mail :
* 修改备注:
* 版    本:V1.0
* 日    期:2012年5月20日 星期日  19:26:49
******************************************************************************************************************************/
__inline static u8 sd_ReadWriteByte( u8 _byte )
{
return SPI_1_ReadWriteByte( _byte ); // 读取&&写入一字节的数据
}

使用特权

评论回复
9
dongnanxibei| | 2015-12-30 21:55 | 只看该作者
编译环境使用的是Keil MDK,由于支持内联函数,所以里面有的用得比较频繁的使用了内联的写法。
以上是单独的读写,没有使用到文件系统。

使用特权

评论回复
10
dongnanxibei| | 2015-12-30 21:58 | 只看该作者
SD卡的读写和FatFS文件系统
学习了一下SPI操作SD卡,同时移植了一个免费开源的FAT文件系统:FatFS。感觉挺好,在单片机上实现了读写文件的操作,接下来就可以解释我的G代码咯!
  我的SD卡底层操作参考了网上几种常见的代码,但又对其结构做了一定的优化,至少看起来用起来比较方便。既可以作为文件系统的diskio使用,也可以直接使用底层函数,把SD卡作为一块flash读写。
  FatFs文件系统体积蛮小,6-7K足矣,对于128Kflash的STM32来说很合适,代价不大。同时可移植性很高,最少只需要4个函数修改既可以实现文件系统的移植。相关文件系统的介绍请看这里
  这里给一套比较完整的参考资料,包括fatfs文件系统的原版资料、几个重要的手册和网上下载的代码。
111111111111.rar (918.41 KB)
其中底层的SPI总线对SD卡的操作在SPI_SD_driver.c/h中,而FATFS的移植文件diskio.c中对磁盘的操作函数中将调用底层的操作函数。下面是一些底层操作函数:
u8 SPI_ReadWriteByte(u8 TxData);                                             //SPI总线读写一个字节
u8 SD_WaitReady(void);                                                           //等待SD卡就绪
u8 SD_SendCommand(u8 cmd, u32 arg, u8 crc);                      //SD卡发送一个命令
u8 SD_SendCommand_NoDeassert(u8 cmd, u32 arg, u8 crc);  //SD卡发送一个命令,不断线
u8 SD_Init(void);                                                                      //SD卡初始化
                                 
u8 SD_ReceiveData(u8 *data, u16 len, u8 release);                   //SD卡读数据
u8 SD_GetCID(u8 *cid_data);                                                   //读SD卡CID
u8 SD_GetCSD(u8 *csd_data);                                                 //读SD卡CSD
u32 SD_GetCapacity(void);                                                     //取SD卡容量

u8 SD_ReadSingleBlock(u32 sector, u8 *buffer);                      //读一个sector
u8 SD_WriteSingleBlock(u32 sector, const u8 *buffer);           //写一个sector
u8 SD_ReadMultiBlock(u32 sector, u8 *buffer, u8 count);       //读多个sector
u8 SD_WriteMultiBlock(u32 sector, const u8 *data, u8 count);  //写多个sector

  这是diskio.c中的一段代码,在disk初始化中,我们调用了SPI_SD_driver.c中的SD卡初始化函数。
DSTATUS disk_initialize (
    BYTE drv                /* Physical drive nmuber (0..) */
)
{
    u8 state;

    if(drv)
    {
        return STA_NOINIT;  //仅支持磁盘0的操作
    }

    state = SD_Init();
    if(state == STA_NODISK)
    {
        return STA_NODISK;
    }
    else if(state != 0)
    {
        return STA_NOINIT;  //其他错误:初始化失败
    }
    else
    {
        return 0;           //初始化成功
    }
}
  
  总之FATFS文件系统具有很高的可移植性,经测试,在STM32的18MSPI时钟下,读文件的速度在每秒300K以上,写文件也有100多K的速度,应该说基本满足了嵌入式工程应用中,对磁盘读写的速度要求。如果进一步优化SD卡读写代码,速度应该还会有一定提高,同时还要注意的是FLASH自身读写速度没有ram那么快,通过更换SD卡发现读写速度和卡本身有直接的关系,所以应该尽量选择速度较快的卡。

使用特权

评论回复
11
ticomi| | 2015-12-31 07:46 | 只看该作者
使用FATFS文件系统,查看我此前的发帖,有这方面的资料!

使用特权

评论回复
12
zhangbin_abc| | 2015-12-31 08:27 | 只看该作者
移植一个FATFS文件系统,读写很方便。

使用特权

评论回复
13
yklstudent| | 2015-12-31 09:05 | 只看该作者
文件系统多了,FatFs、EFSL、FATIO和FATSL等等都是文件系统,楼主学会一个就差不多够用了;
其中FatFs资料多点

使用特权

评论回复
14
hyl1615| | 2015-12-31 12:59 | 只看该作者
我最近也在移植文件系统,学习下

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

25

主题

31

帖子

0

粉丝