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

📄 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 = 0x5e; //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,UINT8 u8SDResponse) 
{
    UINT8 u8Counter;
    volatile UINT8 u8Temp=0;

    /* Send Start byte */
    SPI_SendByte(u8SDCommand);

    
    /* Send Argument */
    for(u8Counter=0;u8Counter<4;u8Counter++) 
        SPI_SendByte(gu8SD_Argument.bytes[u8Counter]);
  
   
    /* Send CRC */
    SPI_SendByte(0x95); //这个校验位仅仅适用于2G以下!HOW TO SOLVE?
  
    /* Response RHandler */
    u8Counter=SD_WAIT_CYCLES;
    do
    {
        u8Temp=SPI_RecByte(0xff);
        u8Counter--;
    }while((u8Temp != u8SDResponse) && u8Counter > 0);
    
    if(u8Counter)   return(0);//正确返回0,错误返回1
    else            return(1);
}


/***************************************************************
*sd的初始化  非常关键!
* 
****************************************************************/
UINT8 SD_Init(void) 
{
    UINT8 i;
    SPI_Init();             // SPI Initialization


    SD_deSel();
    for(i=0;i<12;i++)
    SPI_RecByte(0xff);           // Send 12*8=96 clocks 
   
    SD_Sel();
    gu8SD_Argument.lword=0;
    SPI_RecByte(0xff);
    SPI_RecByte(0xff);
    
    /* IDLE Command */
    
    SD_Sel();
    if(SD_SendCommand(CMD0|0x40,SD_IDLE))  //发送CMD0
    {
       SD_deSel();
        return(1);      // Command IDLE fail
    }
    SD_deSel();
    
    SPI_RecByte(0xff);  // Dummy SPI cycle
    
    /*  Initialize SD Command */
     SD_Sel();
    while(SD_SendCommand(1|0x40,SD_OK));  //发送CMD1
    SD_deSel();
    
   SPI_RecByte(0xff); // Dummy SPI cycle

    /*  Block Length */
    SD_Sel();
      
    gu8SD_Argument.lword=SD_BLOCK_SIZE;
    if(SD_SendCommand(CMD16|0x40,SD_OK))    //发送CMD0
    {
       SD_deSel();
        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|0x40,SD_OK))
    {
         SD_deSel();
        return(4);      // Command IDLE fail
    }
    
    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=496;  //存储设置在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 + -