原创 STC单片机驱动大容量SDHC程序

2011-9-22 19:14 4269 4 5 分类: MCU/ 嵌入式

 

    昨晚忙了一个晚上,在振南老师驱动的基础上,参阅网上几位网友的驱动,终于可以对SDHC进行读写。以下为其C51代码,有谁弄这个,也可以参考一下。

 

/******************************************************************
 - 功能描述:向SD卡写命令
 - 隶属模块:SD卡模块
 - 函数属性:内部
 - 参数说明:SD卡的命令是6个字节,pcmd是指向命令字节序列的指针
 - 返回说明:命令写入后,SD卡的回应值,调用不成功,将返回0xff
 ******************************************************************/

unsigned char SD_Write_Cmd(unsigned char *pcmd) //向SD卡写命令,pcmd是命令字节序列的首地址
{
 unsigned char temp,time=0;

 SD_CS=1;
 SD_spi_write(0xff); //提高兼容性,如果没有这里,有些SD卡可能不支持  
 SD_CS=0;

 SD_spi_write(pcmd[0]);
 SD_spi_write(pcmd[1]);
 SD_spi_write(pcmd[2]);
 SD_spi_write(pcmd[3]);
 SD_spi_write(pcmd[4]);
 SD_spi_write(pcmd[5]);

 do
 { 
  temp = ****************************************
 - 功能描述:复位SD卡,用到CMD0,使用SD卡切换到SPI模式
 - 隶属模块:SD卡模块
 - 函数属性:外部,供用户调用
 - 参数说明:无
 - 返回说明:调用成功,返回0x00,否则返回INIT_CMD0_ERROR (sd.h中有定义)
 ******************************************************************/

unsigned char SD_Reset()//SD卡复位,进入SPI模式,使用CMD0(命令0)
{
 unsigned char time,temp,i;
 unsigned char pcmd[] = {0x40,0x00,0x00,0x00,0x00,0x95}; //命令0的字节序列

 is_init=1; //将is_init置为1

 SD_CS=1;  //关闭片选
 for(i=0;i<0x0f;i++) //复位时,首先要发送最少74个时钟信号,这是必须的!!!
 {
  SD_spi_write(0xff); //120个时钟
 }

 SD_CS=0; //打开片选

 time=0;
 do
 {
  temp=SD_Write_Cmd(pcmd);//写入CMD0
  time++;
  if(time==TRY_TIME)
  {
   SD_CS=1; //关闭片选
   return(INIT_CMD0_ERROR);//CMD0写入失败
  }
 }while(temp!=0x01);

 SD_CS=1; //关闭片选

 SD_spi_write(0xff); //按照SD卡的操作时序在这里补8个时钟
 return 0;//返回0,说明复位操作成功
}

/******************************************************************
 - 功能描述:初始化SD卡,使用CMD1
 - 隶属模块:SD卡模块
 - 函数属性:外部,供用户调用
 - 参数说明:无
 - 返回说明:调用成功,返回0x00,否则返回INIT_CMD1_ERROR (sd.h中有定义)
 ******************************************************************/

unsigned char SD_Init() //初始化,使用CMD1(命令1)

 unsigned char time,temp;
 unsigned char pcmd0[] = {0x40,0x00,0x00,0x00,0x00,0x95}; //命令0的字节序列
 unsigned char pcmd8[] = {0x48,0x00,0x00,0x01,0xaa,0x87}; //命令8的字节序列
 unsigned char pcmd41[] = {0x69,0x40,0x00,0x00,0x00,0xff};//命令41的字节序列
 unsigned char pcmd55[] = {0x77,0x00,0x00,0x00,0x00,0xff};//命令55的字节序列

 P2=0xff;

 for(time=0;time<0x1f;time++)
 {
   SD_spi_write(0xff);
 }

 SD_CS=0; //打开片选

 time=0;
 do
 {
  temp=SD_Write_Cmd(pcmd0);
  time++;
  if(time>=TRY_TIME)
  {
   SD_CS=1; //关闭片选
   LED1=0;
   return(INIT_CMD1_ERROR);//CMD1写入失败
  }
 }while(temp!=0x01);
 time=0;
 do
 {
   temp=SD_Write_Cmd(pcmd8);
   time++;
   //P2=temp;
   if(time>=TRY_TIME)
   {
     SD_CS=1;
  //P2=~P2;
  LED2=0;
  return(INIT_CMD1_ERROR);
   }
 }while(temp!=0x01);
 time=0;
 do
 {
   temp=SD_Write_Cmd(pcmd55);
   time++;
   if(time>=TRY_TIME)
   {
     SD_CS=1;
  LED3=0;
  return(INIT_CMD1_ERROR);
   }
 }while(SD_Write_Cmd(pcmd41)!=0x00);

     
 is_init=0; //初始化完毕,将is_init设置为0,为了提高以后的数据传输速度
  
 SD_CS=1;  //关闭片选

 SD_spi_write(0xff); //按照SD卡的操作时序在这里补8个时钟
 return(0); //返回0,说明初始化操作成功
}

/****************************************************************************
 - 功能描述:将buffer指向的512个字节的数据写入到SD卡的addr扇区中
 - 隶属模块:SD卡模块
 - 函数属性:外部,供用户调用
 - 参数说明:addr:扇区地址
             buffer:指向数据缓冲区的指针
 - 返回说明:调用成功,返回0x00,否则返回WRITE_BLOCK_ERROR (sd.h中有定义)
 - 注:SD卡初始化成功后,读写扇区时,尽量将SPI速度提上来,提高效率
 ****************************************************************************/

unsigned char SD_Write_Sector(unsigned long addr,unsigned char *buffer) //向SD卡中的指定地址的扇区写入512个字节,使用CMD24(命令24)

 unsigned char temp,time;
 unsigned int i;
 unsigned char pcmd[] = {0x58,0x00,0x00,0x00,0x00,0xff}; //向SD卡中单个块(512字节,一个扇区)写入数据,用CMD24

 //addr<<=9; //addr = addr * 512 将块地址(扇区地址)转为字节地址 [这里就限制了SD卡的最大容量为4G]
 
 pcmd[1]=((addr&0xff000000)>>24); //将字节地址写入到CMD24字节序列中
 pcmd[2]=((addr&0x00ff0000)>>16);
 pcmd[3]=((addr&0x0000ff00)>>8);
 pcmd[4]=(addr&0x000000ff);

 SD_CS=0;//打开SD卡片选

 time=0;
 do
 { 
  temp=SD_Write_Cmd(pcmd);
  time++;
  if(time==TRY_TIME)
  {
   SD_CS=1; //关闭片选
   return(temp); //命令写入失败
  }
 }while(temp!=0);

 for(i=0;i<100;i++) //这里要插入若干时钟信号
 {
  SD_spi_write(0xff);
 }
 
 SD_spi_write(0xfe);//写入开始字节 0xfe,后面就是要写入的512个字节的数据 
 
 for(i=0;i<512;i++) //将缓冲区中要写入的512个字节写入SD卡
 {
  SD_spi_write(buffer);
 }
 
 SD_spi_write(0xff);
 SD_spi_write(0xff); //两个字节的CRC校验码,不用关心
  
   
 temp=SD_spi_read();   //读取返回值
 if((temp&0x1F)!=0x05) //如果返回值是 XXX00101说明数据已经被SD卡接受了
 {
  SD_CS=1;
  return(WRITE_BLOCK_ERROR); //写块数据失败
 }
 
 while(SD_spi_read()!=0xff);//等到SD卡不忙(数据被接受以后,SD卡要将这些数据写入到自身的FLASH中,需要一个时间)
           //忙时,读回来的值为0x00,不忙时,为0xff

 SD_CS=1; //关闭片选

 SD_spi_write(0xff);//按照SD卡的操作时序在这里补8个时钟
 return(0);   //返回0,说明写扇区操作成功
}

/****************************************************************************
 - 功能描述:读取addr扇区的512个字节到buffer指向的数据缓冲区
 - 隶属模块:SD卡模块
 - 函数属性:外部,供用户调用
 - 参数说明:addr:扇区地址
             buffer:指向数据缓冲区的指针
 - 返回说明:调用成功,返回0x00,否则返回READ_BLOCK_ERROR (sd.h中有定义)
 - 注:SD卡初始化成功后,读写扇区时,尽量将SPI速度提上来,提高效率
 ****************************************************************************/

unsigned char SD_Read_Sector(unsigned long addr,unsigned char *buffer)//从SD卡的指定扇区中读出512个字节,使用CMD17(17号命令)
{
 unsigned int j;
 unsigned char time,temp;
 unsigned char pcmd[]={0x51,0x00,0x00,0x00,0x00,0xff}; //CMD17的字节序列
  
 //addr<<=9; //addr=addr*512    将块地址(扇区地址)转为字节地址

 pcmd[1]=((addr&0xff000000)>>24);//将字节地址写入到CMD17字节序列中
 pcmd[2]=((addr&0x00FF0000)>>16);
 pcmd[3]=((addr&0x0000FF00)>>8);
 pcmd[4]=(addr&0x000000ff);

 SD_CS=0;//打开片选

 time=0;
 do
 { 
  temp=SD_Write_Cmd(pcmd); //写入CMD17
  time++;
  if(time==TRY_TIME)
  {
   return(READ_BLOCK_ERROR); //读块失败
  }
 }while(temp!=0);
      
 while (SD_spi_read()!= 0xfe); //一直读,当读到0xfe时,说明后面的是512字节的数据了

 for(j=0;j<512;j++)  //将数据写入到数据缓冲区中
 { 
  buffer[j]=SD_spi_read();
 }

 SD_spi_read();
 SD_spi_read();//读取两个字节的CRC校验码,不用关心它们

 SD_CS=1;  //SD卡关闭片选

 SD_spi_write(0xff);//按照SD卡的操作时序在这里补8个时钟

 return 0;
}

PARTNER CONTENT

文章评论1条评论)

登录后参与讨论

用户377235 2015-5-9 22:35

ACMD41之后是不是不需要再发送CMD58读OCR寄存器里的上电完成标志位?
相关推荐阅读
用户1629785 2011-10-26 02:31
要搞好与老板的关系
干得好,还要与老板关系搞得好   第2章   干得好,  还要与老板关系搞得好  老板需要的人不一定  最有能力  俗话说得好,三个臭皮匠顶一个诸葛亮。诸葛亮聪明,是个非常有能力的人,但臭皮匠呢,明...
用户1629785 2011-10-24 00:55
MOS 场效应管的工作原理及特点
MOS 场效应管的工作原理及特点   场效应管是只有一种载流子参与导电,用输入电压控制输出电流的半导体器件。有N沟道器件和P沟道器件。有结型场效应三极管JFET(Junction Field...
用户1629785 2011-10-19 15:38
宏晶STC单片机EEPROM读写
#include<reg51.h>//#include<intrins.h> #define uchar unsigned char#define uint  unsigned...
用户1629785 2011-10-16 20:29
RIFF文件格式
1. 简介 RIFF全称为资源互换文件格式(ResourcesInterchange FileFormat),RIFF文件是windows环境下大部分多媒体文件遵循的一种文件结构,RIFF文件所包含的...
用户1629785 2011-10-16 01:38
文件名匹配测试程序
/*********************************************************************** - 功能描述:文件名匹配(支持带*?通配符的文件名的匹...
用户1629785 2011-10-15 00:47
读znFAT笔记
FAT文件系统整体概述        MBR:0扇区,分区记录,不一定每个磁盘都有MBR.   DBR:可能位于0扇区,若不在0扇区则由MBR计算得到他的位置,以0XEB开始,记录该分区重要参...
EE直播间
更多
我要评论
1
4
关闭 站长推荐上一条 /3 下一条