【求助】SPI方式读写SD卡的问题,复位成功但初始化不成功【12.10已解决】

2019-03-24 12:01发布

12.10更新
已经解决啦,嘿嘿
是SPI读写字节的小函数出了问题,
下面的程序是没问题的哈
还是感谢各位大神帮助~~


如题~~
SD卡用的是金士顿1G大卡,SPI方式发送CMD0可以复位成功,返回0X01,
初始化时,无论发送CMD8、CMD1还是CMD55+ACMD41都返回0XFF,实在不知道是怎么回事,有人遇到过类似的问题吗?
纠结两天了,求高人指点~~

自己用的源码:

/********************************************************
/********************************************************
sd_f149.c
********************************************************/
********************************************************/

#include"sd_f149.h"
#include"usart.h"
uchar pbuf[512]={0};
//uchar is_init=0;
uchar Init_Flag=0;
/********************************************************
时钟 mclk 8M
********************************************************/
void clk_init()                         //8M时钟
{
    uchar i;
    BCSCTL1&=~XT2OFF;     //打开XT振荡器
    BCSCTL2|=SELM1+SELS;  //MCLK 8M and SMCLK 8M  
    do
    {
      IFG1 &= ~OFIFG;                 //清除振荡错误标志
      for(i = 0; i < 100; i++)
      _NOP();   //延时等待
    }
    while ((IFG1 & OFIFG) != 0); //如果标志为1继续循环等待
    IFG1&=~OFIFG;
}


/****************函数定义**********************/
void delay(unsigned int time) //延时函数
{
  while(time--);
}

//--------------------------------------------------------------------------
//初始化SD卡到SPI模式
//--------------------------------------------------------------------------
unsigned char SD_Init()
{
   unsigned int retry;
   unsigned char temp;
   unsigned char i;
   unsigned char CMD[] = {0x40,0x00,0x00,0x00,0x00,0x95};

   Init_Flag=1; //将初始化标志置1
   
   SD_CS_1;
   
   for (i=0;i<0x0f;i++)
   {
      Write_Byte_SD(0xff); //发送至少74个时钟信号
   }
   
    SD_CS_0; //片选开启
   //向SD卡发送CMD0
   retry=0;
   do
   { //为了能够成功写入CMD0,在这里写200次
     temp=Write_Command_SD(CMD);
     retry++;
     if(retry==500)
     { //超过200次
        return(INIT_CMD0_ERROR);//CMD0 Error!
     }
   }
   while(temp!=0x01); //回应01h,停止写入
   usart_send_string("Reset finish! ");


  //只到这里是完全可以的!!!串口助手上显示了"Reset finish! "说明复位成功~可是接下来的初始化部分就不行,串口助手只显示“” 说明temp读的值为0XFF
   
   //发送CMD1到SD卡
   CMD[0] = 0x41; //CMD1
   CMD[5] = 0xFF;

    retry=0;
    do
    {
       temp=Write_Command_SD(CMD);
      
       retry++;
       if(retry==1000)
       { //超过100次
          usart_send_onechar(temp+0x30);
          return(INIT_CMD1_ERROR);//CMD1 Error!  
       }
    }
    while(temp!=0x00);//回应00h停止写入
    usart_send_string("CMD1 finish! ");

//根本没到这一步,直接在上面就return了。口助手只显示“” 说明temp读的值为0XFF
   
   Init_Flag=0; //初始化完毕,初始化标志清零


   SD_CS_1; //片选无效
   return(0); //初始化成功
}



void Write_Byte_SD(unsigned char x)
{
  uchar i;
  for(i=0;i<8;i++)
  {
    P4OUT&=~BIT2; //下降沿

    if(x&0x80)
    {
      P4OUT|=BIT0;
    }
    else
    {
      P4OUT&=~BIT0;
    }

    x=x<<1;

    if(Init_Flag)         //用于初始化、复位时降速
    {
      delay_us(2);
    }

    P4OUT|=BIT2;//时钟上升沿
    if(Init_Flag)          //用于初始化、复位时降速
    {
      delay_us(2);
    }
  }
}


unsigned char Read_Byte_SD()
{
   uchar temp=0,i=0;
   P4DIR|=BIT0;//MISO切换成输出
   P4OUT|=BIT0;//电平置高
   P4DIR&=~BIT0;//再换回输入
   for(i=0;i<8;i++)
   {

     P4OUT&=~BIT2;//时钟下降沿

     if(Init_Flag)
     {
       delay_us(2);
     }
     if(P4IN&BIT1)//1
     {
       temp|=(0x80>>i);//读出数据
     }

    P4OUT|=BIT2; //上升沿 1011

     if(Init_Flag)
     {
       delay_us(2);
     }

   }
   return(temp);
}




//-----------------------------------------------------------------------------------------------
//向SD卡中写入命令,并返回回应的第二个字节
//-----------------------------------------------------------------------------------------------
unsigned char Write_Command_SD(unsigned char *CMD)
{
    unsigned char tmp;
    unsigned char retry=0;
    unsigned char i;

    //禁止SD卡片选
    SD_CS_1;
    //发送8个时钟信号
    Write_Byte_SD(0xFF);
    //使能SD卡片选
    SD_CS_0;

    //向SD卡发送6字节命令
    for (i=0;i<0x06;i++)
    {
      Write_Byte_SD(*CMD++);
    }

    //获得16位的回应
    Read_Byte_SD(); //read the first byte,ignore it.
    do
    { //读取后8位
      tmp = Read_Byte_SD();
      retry++;
    }
    while((tmp==0xff)&&(retry<100));
    return(tmp);
}


void SD_IO_Init()
{
  P4SEL=0X00;
  P4DIR=0xfd;//11111101
  P4OUT=0xff;
}


unsigned char SD_write_sector(unsigned long int addr,unsigned char *Buffer)
{
   unsigned char temp,retry;
   unsigned int i;
   unsigned char CMD[] = {0x58,0x00,0x00,0x00,0x00,0xFF}; //24号写扇区命令
   addr = addr << 9;                                           //将块地址转换成字节地址
   CMD[1] = ((addr & 0xFF000000) >>24 );
   CMD[2] = ((addr & 0x00FF0000) >>16 );
   CMD[3] = ((addr & 0x0000FF00) >>8 );        //将地址装入24号命令  
   retry=0;
   P4OUT&=~BIT3;//打开片选
   do   
   {
      temp=Write_Command_SD(CMD);  //写入24号命令
      retry++;
      if(retry==100)
      {
        return(temp); //返回sd相应值
      }
   }
   while(temp!=0);
   for (i=0;i<100;i++)
   {
      Read_Byte_SD();//插入若干个时钟信号
   }
   Write_Byte_SD(0xFE);
   for (i=0;i<512;i++)
   {
      Write_Byte_SD(*Buffer++);  //向块中写数据
   }
   Write_Byte_SD(0xFF);
   Write_Byte_SD(0xFF);  //写入两个校验码,数值不用关心
   temp=Read_Byte_SD();  //读取返回值
   if((temp & 0x1F)!=0x05)         //读回sd相应
   {
     P4OUT|=BIT3;//关闭片选
     return(WRITE_BLOCK_ERROR);
   }
   while (Read_Byte_SD()!=0xff){};//判断sd是否忙
   Write_Byte_SD(0xff);//补偿8个时钟
   P4OUT|=BIT3;//关闭片选
   return(0);
}


unsigned char SD_Read_Sector(unsigned long sector,unsigned char *buffer)
{
   unsigned char retry;
   unsigned char CMD[] = {0x51,0x00,0x00,0x00,0x00,0xFF}; //17号读扇区命令
   unsigned char temp;
   unsigned int j;
   sector = sector << 9;                          //地址转换
   CMD[1] = ((sector & 0xFF000000) >>24 );
   CMD[2] = ((sector & 0x00FF0000) >>16 );
   CMD[3] = ((sector & 0x0000FF00) >>8 );//向命令中装入地址
   retry=0;
   do
   {
      temp=Write_Command_SD(CMD);        //写入17号命令
      retry++;
      if(retry==100)
      {
        return(READ_BLOCK_ERROR);//读块数据失败
      }
   }
   while(temp!=0);   
   while (Read_Byte_SD() != 0xfe);//等待回应,当读到0xfe时,开始接收数据
   for (j=0;j<512;j++)
   {
     *buffer++ = Read_Byte_SD(); //将数据存在缓冲区
   }
    P4OUT|=BIT3;//关闭片选
    Read_Byte_SD();
    Read_Byte_SD();        //读取两位校验码,数值不用关心
    Write_Byte_SD(0xff); //按照操作时许补偿8个时钟
    return 0;      
}

[ 本帖最后由 blue_bm 于 2013-12-10 16:49 编辑 ] 此帖出自小平头技术问答
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
6条回答
651076842
2019-03-24 20:55
我这里有一个我写的51单片机的SD卡教程,你看看,能用到吗?我430这个,不是很在行。SD卡测试教程

一周热门 更多>

相关问题

    相关文章