⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.c

📁 SD读写程序
💻 C
字号:
#include <hidef.h>      /* common defines and macros */
#include "derivative.h"      /* derivative-specific definitions */
/***************************************************************
*这个程序可以实现读取SD卡中的数据

*存在的问题:只能2G以下,以上就不能支持了! 
****************************************************************/  

/***************************************************************
*变量的初始化及宏定义
* 
****************************************************************/  
typedef unsigned char     UINT8;  		/*unsigned 8 bit definition */
typedef unsigned short    UINT16; 		/*unsigned 16 bit definition*/
typedef unsigned long     UINT32; 		/*unsigned 32 bit definition*/
typedef signed char       INT8;   		/*signed 8 bit definition */
typedef short      		  INT16;  		/*signed 16 bit definition*/
typedef long int    	  INT32;  		/*signed 32 bit definition*/
typedef union
{
	UINT8  bytes[4];
	UINT32 lword;		
}T32_8;

#define BYTE unsigned char 
#define UL  unsigned long
#define UINT unsigned int

#define SD_Sel()   PTM_PTM3=0        //低电平
#define SD_deSel() PTM_PTM3=1        //高电平

#define SD_BLOCK_SIZE   (0x00000200)
#define SD_BLOCK_SHIFT  (9)
#define BLOCK_SIZE      512
//命令指令!
#define CMD0    0       //卡复位
#define CMD8   	8  			/* SEND_IF_COND */
#define CMD9    9       //命令9 ,读CSD数据
#define CMD10   10      //命令10,读CID数据
#define CMD12   12      //命令12,停止数据传输
#define CMD16   16      //命令16,设置SectorSize 应返回0x00
#define CMD17   17      //命令17,读sector
#define CMD18   18      //命令18,读Multi sector
#define ACMD23  23      //命令23,设置多sector写入前预先擦除N个block
#define CMD24   24      //命令24,写sector
#define CMD25   25      //命令25,写Multi sector
#define ACMD41  0x80+41      //命令41,应返回0x00
#define CMD55   55      //命令55,应返回0x01
#define CMD58   58      //命令58,读OCR信息
#define CMD59   59      //命令59,使能/禁止CRC,应返回0x00

#define SD_WAIT_CYCLES 200

/***************************************************************
*变量的声明定义
* 
****************************************************************/
T32_8 gu8SD_Argument;
UINT8 gu8SD_CID[16];//联合体

volatile BYTE  data_buff[512];

enum
{
    SD_OK,
    SD_IDLE
};





//所有的子函数
/***************************************************************
*spi的初始化
* 
****************************************************************/
void SPI_Init(void) 
{
   MODRR =0;
   MODRR_MODRR4=1; //使用PM口
   DDRM|=0x38;   //SCK0=1,MOSI=1,SS0=1
   SPI0CR1 = 0x52; //CPOL=0,CPHA=0;//CPOL=1,CPHA=1; 
   SPI0CR2 = 0x10;
   SPI0BR  = 0x37;  // 80M / 256 = 312.5k         
}




/***************************************************************
*spi的high设置
* 
****************************************************************/
void SPI_High()
{
   

 // SPI0BR = 0x00; //BR=busclk/((SPPR + 1)· 2^(SPR + 1))=// 60M / 16 = 3.75M
  
  SPI0BR = 0x05; //BR=busclk/((SPPR + 1)· 2^(SPR + 1))=// 60M / 64 = 0.9M
}




/***************************************************************
*SPI读取一个字节
* 
****************************************************************/
byte SPI_RecByte(byte val)     //SPI读一个字节
{ 	
  while(!SPI0SR_SPTEF);
  SPI0DRL=0xFF;
  
	while(!SPI0SR_SPIF);
	return(SPI0DRL);
}



/***************************************************************
*SPI发送一个字节
* 
****************************************************************/
void SPI_SendByte(byte data)   //SPI写一个字节,其中is_init为1时,写的速度放慢
{
  	while(!SPI0SR_SPTEF);
	(void)SPI0SR; //清除标志位的一种特殊写法!
	SPI0DRL=data;
	while(!SPI0SR_SPIF);
	(void)SPI0DR;
}
 



/***************************************************************
*设定总线时钟80M
* 
****************************************************************/
void SetBusCLK_80M(void)
{   
    CLKSEL=0X00;				//disengage PLL to system
    PLLCTL_PLLON=1;			//turn on PLL
    SYNR =0xc0 | 0x09;  // 已知:fOSC=16m 按照上面的设置 SYNDIV=9  REFDIV=1 则 fVCO= 2*16*10/2 = 160m	
                        // 则 VCOFRQ[7:6]= 11     即   SYNR=0xc0 | 中0xc0的由来 
                        // 这里面得问题是  80MHz <  fVCO <= 120MHz   11他到底可不可行?还是最高120m?
    
                        
    REFDV=0x80 | 0x01;   // 已知:fOSC=16m 按照上面的设置  REFDIV=1 则 fREF= 16/2 = 8m	
                        // 则 REFFRQ[7:6]= 10     即   REFDV=0x80 |中0x80的由来
    
    POSTDIV=0x00;       //pllclock=2*osc*(1+SYNR)/(1+REFDV) = 2*16*10/2 =160MHz
    _asm(nop);          //BUS CLOCK=80M
    _asm(nop);
    while(!(CRGFLG_LOCK==1));	  //when pll is steady ,then use it;
    CLKSEL_PLLSEL =1;		        //engage PLL to system; 
}




/***************************************************************
*SD卡发送协议命令
* 
****************************************************************/
UINT8 SD_SendCommand(UINT8 u8SDCommand,UINT32 ARG) 
{
    UINT8 u8Counter;
    volatile UINT8 u8Temp=0;
    
    SD_Sel();
   
  
    /* Send Start byte */
    SPI_SendByte(u8SDCommand|0x40);

    /* Send Argument */
    //for(u8Counter=0;u8Counter<4;u8Counter++) 
    //    SPI_SendByte(gu8SD_Argument.bytes[u8Counter]);
   SPI_SendByte(ARG>>24);
   SPI_SendByte(ARG>>16);
   SPI_SendByte(ARG>>8);
   SPI_SendByte(ARG);
  
    /* Send CRC */
    SPI_SendByte(0x95);
  
    /* Response RHandler */
    u8Counter=SD_WAIT_CYCLES;
    do
    {
        u8Temp=SPI_RecByte(0xff);
        u8Counter--;
    }while((u8Temp == 0xff) && u8Counter > 0);
    
    
    SD_deSel();
    SPI_RecByte(0xff);  // Dummy SPI cycle
    
    return u8Temp;
    

}

/***************************************************************
*SD卡发送协议命令(没有片选无效信号)
* 
****************************************************************/
UINT8 SD_SendCommand_Nodesert_Crc(UINT8 u8SDCommand,UINT32 ARG,UINT8 crc) 
{
    UINT8 u8Counter;
    volatile UINT8 u8Temp=0;
    
    SD_Sel();
   
  
    /* Send Start byte */
    SPI_SendByte(u8SDCommand|0x40);

    /* Send Argument */
    //for(u8Counter=0;u8Counter<4;u8Counter++) 
    //    SPI_SendByte(gu8SD_Argument.bytes[u8Counter]);
   SPI_SendByte(ARG>>24);
   SPI_SendByte(ARG>>16);
   SPI_SendByte(ARG>>8);
   SPI_SendByte(ARG);
  
    /* Send CRC */
    SPI_SendByte(crc);
  
    /* Response RHandler */
    u8Counter=SD_WAIT_CYCLES;
    do
    {
        u8Temp=SPI_RecByte(0xff);
        u8Counter--;
    }while((u8Temp == 0xff) && u8Counter > 0);
    
    return u8Temp;
    
   
}




/***************************************************************
*sd的初始化  非常关键
*2G以下和4G以上的SD_Init()是有区别的! 
****************************************************************/
UINT8 SD_Init(void) 
{
    UINT8 i,buf[4];
    UINT8 res;
    UINT32 arg;
    SPI_Init();             // SPI Initialization


    SD_deSel();
    for(i=0;i<12;i++)
    SPI_RecByte(0xff);           // Send 12*8=96 clocks 
   
    SD_Sel();
    SPI_RecByte(0xff);
    SPI_RecByte(0xff);
    
    /* IDLE Command */
    
    arg=0;
    if(SD_SendCommand(CMD0,arg)!=0x01)
    {
      
        return(1);      // Command IDLE fail
    }
    
    arg=0x1aa;  
    
    res = SD_SendCommand_Nodesert_Crc(CMD8,arg,0x87);
    if(res ==0x01)//sdv2
    {
       buf[0]= SPI_RecByte(0xff);
        buf[1]= SPI_RecByte(0xff);
         buf[2]= SPI_RecByte(0xff);
          buf[3]= SPI_RecByte(0xff);
        
        SD_Sel();
        SPI_RecByte(0xff);
      if(buf[2]==0x01&&buf[3]==0xaa)  //accmd 41
      {
         
        for(i=0;i<200;i++) 
         {
          
         res =  SD_SendCommand(CMD55,0X00);
         arg = 0x40000000;
         res =  SD_SendCommand(41,arg);
         if(res==0x00) break;
         }
         res =  SD_SendCommand_Nodesert_Crc(58,0x00,0x95);
         if(res==0x00)
          {
           buf[0]= SPI_RecByte(0xff);
           buf[1]= SPI_RecByte(0xff);
            buf[2]= SPI_RecByte(0xff);
            buf[3]= SPI_RecByte(0xff);
            SD_Sel();
          SPI_RecByte(0xff); 
          }
      }
  }   
    else  //sdv1
    {
        /*  Initialize SD Command */
        while(SD_SendCommand(1,arg));

        /*  Block Length */
        if(SD_SendCommand(CMD16,512))
        {   
            return(1);      // Command IDLE fail
        }
    }
   
   
   
    SD_deSel();
    
    SPI_High();
    
  SPI_SendByte(0xFF);
    SPI_SendByte(0xFF);
   //  //  SPI_RecByte(0xff);   // Dummy SPI cycle
    return(0);
}





/***************************************************************
*对SD卡进行读写操作????
* 
****************************************************************/
UINT8 SD_Read_Block(UINT32 u16SD_Block,UINT8 *pu8DataPointer) 
{
    UINT8 u8Temp=0;
    UINT16 u16Counter;

     SD_Sel();
//以下两行限制了存储卡的容量!
   // gu8SD_Argument.lword=u16SD_Block;
   // gu8SD_Argument.lword=gu8SD_Argument.lword<< SD_BLOCK_SHIFT;

    if(SD_SendCommand(CMD17,u16SD_Block<<9))
    {
         SD_deSel();
        return(4);      // Command IDLE fail
    }
    
    SD_Sel();
    while(u8Temp!=0xFE)
        u8Temp= SPI_RecByte(0xff);
    
    for(u16Counter=0;u16Counter<BLOCK_SIZE;u16Counter++)
        *pu8DataPointer++=SPI_RecByte(0xff);

    SPI_RecByte(0xff);  // Dummy SPI cycle
    SPI_RecByte(0xff);  // Dummy SPI cycle

    SD_deSel();

    SPI_RecByte(0xff);  // Dummy SPI cycle
    
    return(0);
}





/***************************************************************
*主函数
* 
****************************************************************/
void main(void) {
  /* put your own code here */
  UL SECTOR=15064;  //存储设置在80扇区
  UINT8 res;
  DDRB =0XFF;
  SetBusCLK_80M();
  //Init_Dev() ;//设置总线频率以及串口连接PC的初始化

	EnableInterrupts;

 // SD_Reset();
  res= SD_Init();
   
   if(res==0) //成功的应答信号是0
   {
    PORTB = 0X00; //如果SD卡初始化成功,就会点亮所有的灯!
    SD_Read_Block(SECTOR,data_buff); //对SD卡进行读操作!
                                      //从SD卡中读取数据回S12中
   }
  /* *///
  for(;;) {
  
    _FEED_COP(); /* feeds the dog */
  } /* loop forever */
  /* please make sure that you never leave main */
}







⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -