51单片机驱动SD卡

2019-04-15 16:27发布

单片机: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