单片机:STC12C5A60S2 晶振:24MHZ
51单片机读sd卡资料:
http://download.csdn.net/detail/sparkstrike/7982195
sd卡引脚
一.IO接口
sbit CLK = P3^4;//同步时钟
sbit DI = P3^5;//Cmd/DataIn
sbit DO = P3^6;//DataOut
sbit CS = P3^7;//片选
二.模拟SPI
注:spi相关见
http://blog.csdn.net/sparkstrike/article/details/39609235
//***********模拟spi写函数
void SPI_W(unsigned char Data){
unsigned char i;
for(i = 0; i<8; i++){
Data <<= 1;
CLK = 0;
DI = CY;
CLK = 1;
};
DI = 1;
}
//***********模拟spi读函数
unsigned char SPI_R(){
unsigned char Data,i;
DO = 1;//设置DO接口为输入状态
for(i = 0; i<8; i++){
Data <<= 1;
CLK = 0;
CLK = 1;
Data |= DO;
};
return Data;
}
三.等待SD卡的回应(在写入一些命令后,sd卡会回应一些东西)
//**************读sd卡回应
unsigned char SD_Response(){
unsigned char i,Response;
for(i = 0; i<10; i++){
Response = SPI_R();
if(Response == 0x00)
break;
if(Response == 0x01)
break;
};
return Response;
}
四.向sd卡写入命令
Cmd为命令,命令有复位命令、读命令、写命令等,4位的Arguement为地址,CRC为校验码
//***************向SD发命令
void SD_Cmd(unsigned char Cmd, unsigned long Argument, unsigned char CRC){
unsigned char arg[4];
arg[0] = (unsigned char)Argument;
arg[1] = (unsigned char)(Argument >> 8);
arg[2] = (unsigned char)(Argument >> 16);
arg[3] = (unsigned char)(Argument >> 24);
SPI_W(Cmd | 0x40);
SPI_W(arg[3]);
SPI_W(arg[2]);
SPI_W(arg[1]);
SPI_W(arg[0]);
SPI_W(CRC);
}
五.初始化SD卡
SD卡有两种读写模式:SD模式和SPI模式,默认的读写模式为SD模式,单片机用SPI模式比较方便,要使用SPI模式需要在SD卡上电是对它写入CMD0命令和CMD1命令
/*************SD卡初始化,设置SPI模式
unsigned char SD_Init(){
unsigned int delay = 0;
unsigned char i;
unsigned char Response = 0xff;
CS = 1;
for(i = 0; i<10; i++){
SPI_W(0xff);//上电后给74个以上的时间脉冲
};
CS = 0;
SD_Cmd(0x00, 0, 0x95);//命令CMD0,复位SD卡
//等待复位成功
i = 0;
while(SD_Response() != 0x01){//等待SD卡回应信号
i++;
if(i > 100){
return 0;//失败返回0
};
};
CS = 1;
SPI_W(0xff);//关片选后写8个空脉冲,SD卡复位完毕
//设置SPI
i = 0;
CS = 0;
while(Response != 0x00){//循环等待成功回应,若成功,回应信号为0x00
SD_Cmd(0x01, 0, 0xff);//CMD1,将SD卡设置为SPI模式,无需CRC校验,填入0xff
Response = SD_Response();
if(i > 100){
return 0;//尝试100次,失败返回0
};
};
CS = 1;
SPI_W(0xff);//给8个空脉冲
return 1;
}
六.SD卡读写数据
因为sd卡的读写都是以扇区为单位的,所以这里定义一个全局变量,512表示一个扇区
unsigned int const len = 512;//扇区大小
1.写入数据:
adress为开始写的地址,一定要为512的整数倍,block为一个512字节的数组
//***************SD卡写入数据块
unsigned char SD_Block_W(unsigned char* block, unsigned long address){
unsigned int i;
unsigned char Response_Write;
CS =0;
SD_Cmd(0x18, address, 0xff);//CMD18,块写入命令
while(SD_Response() != 0x00);//循环等待命令回应0x00
for(i = 0; i<10; i++){
SPI_W(0xff);//写入一定量空脉冲
};
SPI_W(0xfe);//0xfe为块头部,后面跟512b字节,+2bCRC(0xff,0xff)
for(i=0; i
2.读数据:
adress为开始读的地址,一定要为512的整数倍,block为一个512字节的数组
//****************从sd卡读数据块
void SD_Block_R(unsigned char* block, unsigned long address){
unsigned int i;
CS = 0;
SD_Cmd(0x11, address, 0xff);//CMD11,数据块读写命令,
while(SD_Response()!=0x00);//循环等待命令回应0x00
while(SPI_R() != 0xfe); //0xfe为块读出的头, 后面紧跟512字节的数据块+2字节的CRC
for(i=0; i
附:测试程序(程序从SD卡512000处写入512字节的数据,并读出)
/*********************************************************************************************/
#include //单片机头文件
sbit CLK = P3^4;//同步时钟
sbit DI = P3^5;//Cmd/DataIn
sbit DO = P3^6;//DataOut
sbit CS = P3^7;//片选
unsigned int const len = 512;//扇区大小
void DELAY_MS (unsigned int a){
unsigned int i;
while( --a != 0){
for(i = 0; i < 600; i++);
}
}
//***********模拟spi写函数
void SPI_W(unsigned char Data){
unsigned char i;
for(i = 0; i<8; i++){
Data <<= 1;
CLK = 0;
DI = CY;
CLK = 1;
};
DI = 1;
}
//***********模拟spi读函数
unsigned char SPI_R(){
unsigned char Data,i;
DO = 1;//设置DO接口为输入状态
for(i = 0; i<8; i++){
Data <<= 1;
CLK = 0;
CLK = 1;
Data |= DO;
};
return Data;
}
//**************读sd卡回应
unsigned char SD_Response(){
unsigned char i,Response;
for(i = 0; i<10; i++){
Response = SPI_R();
if(Response == 0x00)
break;
if(Response == 0x01)
break;
};
return Response;
}
//***************向SD发命令
void SD_Cmd(unsigned char Cmd, unsigned long Argument, unsigned char CRC){
unsigned char arg[4];
arg[0] = (unsigned char)Argument;
arg[1] = (unsigned char)(Argument >> 8);
arg[2] = (unsigned char)(Argument >> 16);
arg[3] = (unsigned char)(Argument >> 24);
SPI_W(Cmd | 0x40);
SPI_W(arg[3]);
SPI_W(arg[2]);
SPI_W(arg[1]);
SPI_W(arg[0]);
SPI_W(CRC);
}
//*************SD卡初始化
unsigned char SD_Init(){
unsigned int delay = 0;
unsigned char i;
unsigned char Response = 0xff;
CS = 1;
for(i = 0; i<10; i++){
SPI_W(0xff);//上电后给74个以上的时间脉冲
};
CS = 0;
SD_Cmd(0x00, 0, 0x95);//命令CMD0,复位SD卡
//等待复位成功
i = 0;
while(SD_Response() != 0x01){//等待SD卡回应信号
i++;
if(i > 100){
return 0;//失败返回0
};
};
CS = 1;
SPI_W(0xff);//关片选后写8个空脉冲,SD卡复位完毕
//设置SPI
i = 0;
CS = 0;
while(Response != 0x00){//循环等待成功回应,若成功,回应信号为0x00
SD_Cmd(0x01, 0, 0xff);//CMD1,将SD卡设置为SPI模式,无需CRC校验,填入0xff
Response = SD_Response();
if(i > 100){
return 0;//尝试100次,失败返回0
};
};
CS = 1;
SPI_W(0xff);//给8个空脉冲
return 1;
}
//***************SD卡写入数据块
unsigned char SD_Block_W(unsigned char* block, unsigned long address){
unsigned int i;
unsigned char Response_Write;
CS =0;
SD_Cmd(0x18, address, 0xff);//CMD18,块写入命令
while(SD_Response() != 0x00);//循环等待命令回应0x00
for(i = 0; i<10; i++){
SPI_W(0xff);//写入一定量空脉冲
};
SPI_W(0xfe);//0xfe为块头部,后面跟512b字节,+2bCRC(0xff,0xff)
for(i=0; i