51单片机驱动SD卡

单片机:STC12C5A60S2 晶振:24MHZ

51单片机读sd卡资料:http://download.youkuaiyun.com/detail/sparkstrike/7982195

sd卡引脚



一.IO接口

[cpp]  view plain  copy
  1. sbit CLK = P3^4;//同步时钟  
  2. sbit DI = P3^5;//Cmd/DataIn  
  3. sbit DO = P3^6;//DataOut  
  4. sbit CS = P3^7;//片选  



二.模拟SPI

注:spi相关见http://blog.youkuaiyun.com/sparkstrike/article/details/39609235

[cpp]  view plain  copy
  1. //***********模拟spi写函数  
  2. void SPI_W(unsigned char Data){  
  3.     unsigned char i;  
  4.     for(i = 0; i<8; i++){  
  5.         Data <<= 1;  
  6.         CLK = 0;  
  7.         DI = CY;  
  8.         CLK = 1;  
  9.     };  
  10.     DI = 1;  
  11. }  
  12.   
  13. //***********模拟spi读函数  
  14. unsigned char SPI_R(){  
  15.     unsigned char Data,i;  
  16.     DO = 1;//设置DO接口为输入状态  
  17.     for(i = 0; i<8; i++){  
  18.         Data <<= 1;  
  19.         CLK = 0;  
  20.         CLK = 1;  
  21.         Data |= DO;  
  22.     };  
  23.     return Data;  
  24. }  

三.等待SD卡的回应(在写入一些命令后,sd卡会回应一些东西)

[cpp]  view plain  copy
  1. //**************读sd卡回应  
  2. unsigned char SD_Response(){  
  3.     unsigned char i,Response;  
  4.     for(i = 0; i<10; i++){  
  5.         Response = SPI_R();  
  6.         if(Response == 0x00)  
  7.             break;  
  8.         if(Response == 0x01)  
  9.             break;  
  10.     };  
  11.     return Response;  
  12. }  


四.向sd卡写入命令

Cmd为命令,命令有复位命令、读命令、写命令等,4位的Arguement为地址,CRC为校验码

[cpp]  view plain  copy
  1. //***************向SD发命令  
  2. void SD_Cmd(unsigned char Cmd, unsigned long Argument, unsigned char CRC){  
  3.     unsigned char arg[4];  
  4.     arg[0] = (unsigned char)Argument;  
  5.     arg[1] = (unsigned char)(Argument >> 8);  
  6.     arg[2] = (unsigned char)(Argument >> 16);  
  7.     arg[3] = (unsigned char)(Argument >> 24);  
  8.   
  9.     SPI_W(Cmd | 0x40);  
  10.     SPI_W(arg[3]);  
  11.     SPI_W(arg[2]);  
  12.     SPI_W(arg[1]);  
  13.     SPI_W(arg[0]);  
  14.     SPI_W(CRC);  
  15. }  

五.初始化SD卡

SD卡有两种读写模式:SD模式和SPI模式,默认的读写模式为SD模式,单片机用SPI模式比较方便,要使用SPI模式需要在SD卡上电是对它写入CMD0命令和CMD1命令

[cpp]  view plain  copy
  1. /*************SD卡初始化,设置SPI模式  
  2. unsigned char SD_Init(){  
  3.     unsigned int delay = 0;  
  4.     unsigned char i;  
  5.     unsigned char Response = 0xff;  
  6.       
  7.     CS = 1;  
  8.     for(i = 0; i<10; i++){  
  9.         SPI_W(0xff);//上电后给74个以上的时间脉冲  
  10.     };  
  11.   
  12.     CS = 0;  
  13.     SD_Cmd(0x00, 0, 0x95);//命令CMD0,复位SD卡  
  14.   
  15.     //等待复位成功  
  16.     i = 0;  
  17.     while(SD_Response() != 0x01){//等待SD卡回应信号  
  18.         i++;  
  19.         if(i > 100){  
  20.             return 0;//失败返回0  
  21.         };  
  22.     };  
  23.   
  24.     CS = 1;  
  25.     SPI_W(0xff);//关片选后写8个空脉冲,SD卡复位完毕  
  26.   
  27.     //设置SPI  
  28.     i = 0;  
  29.     CS = 0;  
  30.     while(Response != 0x00){//循环等待成功回应,若成功,回应信号为0x00  
  31.         SD_Cmd(0x01, 0, 0xff);//CMD1,将SD卡设置为SPI模式,无需CRC校验,填入0xff  
  32.         Response = SD_Response();  
  33.         if(i > 100){  
  34.             return 0;//尝试100次,失败返回0  
  35.         };  
  36.     };  
  37.     CS = 1;  
  38.   
  39.     SPI_W(0xff);//给8个空脉冲  
  40.     return 1;  
  41. }  


六.SD卡读写数据

因为sd卡的读写都是以扇区为单位的,所以这里定义一个全局变量,512表示一个扇区

[cpp]  view plain  copy
  1. unsigned int const len = 512;//扇区大小  


1.写入数据:

adress为开始写的地址,一定要为512的整数倍,block为一个512字节的数组

[cpp]  view plain  copy
  1. //***************SD卡写入数据块  
  2. unsigned char SD_Block_W(unsigned char* block, unsigned long address){  
  3.     unsigned int i;  
  4.     unsigned char Response_Write;  
  5.     CS =0;  
  6.     SD_Cmd(0x18, address, 0xff);//CMD18,块写入命令  
  7.     while(SD_Response() != 0x00);//循环等待命令回应0x00  
  8.     for(i = 0; i<10; i++){  
  9.         SPI_W(0xff);//写入一定量空脉冲  
  10.     };  
  11.   
  12.     SPI_W(0xfe);//0xfe为块头部,后面跟512b字节,+2bCRC(0xff,0xff)  
  13.   
  14.     for(i=0; i<len; i++){  
  15.         SPI_W(block[i]);//写入512b字节  
  16.     };  
  17.   
  18.     SPI_W(0xff);  
  19.     SPI_W(0xff);  
  20.   
  21.     Response_Write = SPI_R()&0x0f;//写入CRC码后SD卡会回应一个xxx0,1001  
  22.     while(SPI_R() == 0);//等待SD卡回应  
  23.   
  24.     CS = 1;  
  25.     SPI_W(0xff);//写入8个空脉冲  
  26.   
  27.     if(Response_Write == 0x05){  
  28.         return 1;  
  29.     }else{  
  30.         return 0;  
  31.     };  
  32. }  

2.读数据:

adress为开始读的地址,一定要为512的整数倍,block为一个512字节的数组

[cpp]  view plain  copy
  1. //****************从sd卡读数据块  
  2. void SD_Block_R(unsigned char* block, unsigned long address){  
  3.     unsigned int i;  
  4.   
  5.     CS = 0;  
  6.     SD_Cmd(0x11, address, 0xff);//CMD11,数据块读写命令,  
  7.   
  8.     while(SD_Response()!=0x00);//循环等待命令回应0x00  
  9.   
  10.     while(SPI_R() != 0xfe); //0xfe为块读出的头, 后面紧跟512字节的数据块+2字节的CRC  
  11.   
  12.     for(i=0; i<len ; i++){  
  13.         block[i] = SPI_R();//读数据  
  14.     };  
  15.   
  16.     SPI_R();  
  17.     SPI_R();//两个字节的CRC。舍弃  
  18.   
  19.     CS =1;  
  20.     SPI_R();//8个空脉冲  
  21. }  

附:测试程序(程序从SD卡512000处写入512字节的数据,并读出)

[cpp]  view plain  copy
  1. /*********************************************************************************************/  
  2.   
  3.   
  4. #include <STC12C5A60S2.H> //单片机头文件  
  5.   
  6. sbit CLK = P3^4;//同步时钟  
  7. sbit DI = P3^5;//Cmd/DataIn  
  8. sbit DO = P3^6;//DataOut  
  9. sbit CS = P3^7;//片选  
  10.   
  11. unsigned int const len = 512;//扇区大小  
  12.   
  13. void DELAY_MS (unsigned int a){  
  14.     unsigned int i;  
  15.     while( --a != 0){  
  16.         for(i = 0; i < 600; i++);  
  17.     }  
  18. }  
  19.   
  20.   
  21.   
  22. //***********模拟spi写函数  
  23. void SPI_W(unsigned char Data){  
  24.     unsigned char i;  
  25.     for(i = 0; i<8; i++){  
  26.         Data <<= 1;  
  27.         CLK = 0;  
  28.         DI = CY;  
  29.         CLK = 1;  
  30.     };  
  31.     DI = 1;  
  32. }  
  33.   
  34. //***********模拟spi读函数  
  35. unsigned char SPI_R(){  
  36.     unsigned char Data,i;  
  37.     DO = 1;//设置DO接口为输入状态  
  38.     for(i = 0; i<8; i++){  
  39.         Data <<= 1;  
  40.         CLK = 0;  
  41.         CLK = 1;  
  42.         Data |= DO;  
  43.     };  
  44.     return Data;  
  45. }  
  46.   
  47.   
  48. //**************读sd卡回应  
  49. unsigned char SD_Response(){  
  50.     unsigned char i,Response;  
  51.     for(i = 0; i<10; i++){  
  52.         Response = SPI_R();  
  53.         if(Response == 0x00)  
  54.             break;  
  55.         if(Response == 0x01)  
  56.             break;  
  57.     };  
  58.     return Response;  
  59. }  
  60.   
  61.   
  62. //***************向SD发命令  
  63. void SD_Cmd(unsigned char Cmd, unsigned long Argument, unsigned char CRC){  
  64.     unsigned char arg[4];  
  65.     arg[0] = (unsigned char)Argument;  
  66.     arg[1] = (unsigned char)(Argument >> 8);  
  67.     arg[2] = (unsigned char)(Argument >> 16);  
  68.     arg[3] = (unsigned char)(Argument >> 24);  
  69.   
  70.     SPI_W(Cmd | 0x40);  
  71.     SPI_W(arg[3]);  
  72.     SPI_W(arg[2]);  
  73.     SPI_W(arg[1]);  
  74.     SPI_W(arg[0]);  
  75.     SPI_W(CRC);  
  76. }  
  77.   
  78.   
  79.   
  80. //*************SD卡初始化  
  81. unsigned char SD_Init(){  
  82.     unsigned int delay = 0;  
  83.     unsigned char i;  
  84.     unsigned char Response = 0xff;  
  85.       
  86.     CS = 1;  
  87.     for(i = 0; i<10; i++){  
  88.         SPI_W(0xff);//上电后给74个以上的时间脉冲  
  89.     };  
  90.   
  91.     CS = 0;  
  92.     SD_Cmd(0x00, 0, 0x95);//命令CMD0,复位SD卡  
  93.   
  94.     //等待复位成功  
  95.     i = 0;  
  96.     while(SD_Response() != 0x01){//等待SD卡回应信号  
  97.         i++;  
  98.         if(i > 100){  
  99.             return 0;//失败返回0  
  100.         };  
  101.     };  
  102.   
  103.     CS = 1;  
  104.     SPI_W(0xff);//关片选后写8个空脉冲,SD卡复位完毕  
  105.   
  106.     //设置SPI  
  107.     i = 0;  
  108.     CS = 0;  
  109.     while(Response != 0x00){//循环等待成功回应,若成功,回应信号为0x00  
  110.         SD_Cmd(0x01, 0, 0xff);//CMD1,将SD卡设置为SPI模式,无需CRC校验,填入0xff  
  111.         Response = SD_Response();  
  112.         if(i > 100){  
  113.             return 0;//尝试100次,失败返回0  
  114.         };  
  115.     };  
  116.     CS = 1;  
  117.   
  118.     SPI_W(0xff);//给8个空脉冲  
  119.     return 1;  
  120. }  
  121.   
  122.   
  123. //***************SD卡写入数据块  
  124. unsigned char SD_Block_W(unsigned char* block, unsigned long address){  
  125.     unsigned int i;  
  126.     unsigned char Response_Write;  
  127.     CS =0;  
  128.     SD_Cmd(0x18, address, 0xff);//CMD18,块写入命令  
  129.     while(SD_Response() != 0x00);//循环等待命令回应0x00  
  130.     for(i = 0; i<10; i++){  
  131.         SPI_W(0xff);//写入一定量空脉冲  
  132.     };  
  133.   
  134.     SPI_W(0xfe);//0xfe为块头部,后面跟512b字节,+2bCRC(0xff,0xff)  
  135.   
  136.     for(i=0; i<len; i++){  
  137.         SPI_W(block[i]);//写入512b字节  
  138.     };  
  139.   
  140.     SPI_W(0xff);  
  141.     SPI_W(0xff);  
  142.   
  143.     Response_Write = SPI_R()&0x0f;//写入CRC码后SD卡会回应一个xxx0,1001  
  144.     while(SPI_R() == 0);//等待SD卡回应  
  145.   
  146.     CS = 1;  
  147.     SPI_W(0xff);//写入8个空脉冲  
  148.   
  149.     if(Response_Write == 0x05){  
  150.         return 1;  
  151.     }else{  
  152.         return 0;  
  153.     };  
  154. }  
  155.   
  156. //****************从sd卡读数据块  
  157. void SD_Block_R(unsigned char* block, unsigned long address){  
  158.     unsigned int i;  
  159.   
  160.     CS = 0;  
  161.     SD_Cmd(0x11, address, 0xff);//CMD11,数据块读写命令,  
  162.   
  163.     while(SD_Response()!=0x00);//循环等待命令回应0x00  
  164.   
  165.     while(SPI_R() != 0xfe); //0xfe为块读出的头, 后面紧跟512字节的数据块+2字节的CRC  
  166.   
  167.     for(i=0; i<len ; i++){  
  168.         block[i] = SPI_R();//读数据  
  169.     };  
  170.   
  171.     SPI_R();  
  172.     SPI_R();//两个字节的CRC。舍弃  
  173.   
  174.     CS =1;  
  175.     SPI_R();//8个空脉冲  
  176. }  
  177.   
  178.   
  179.   
  180. void main (void){  
  181.     unsigned char xdata block[len];  
  182.     int i;  
  183.     //初始化SD卡  
  184.     SD_Init();  
  185.     for(i=0;i<512;i++){  
  186.         block[i]=0xaa;  
  187.     };  
  188.     //从512000处写sd卡  
  189.     SD_Block_W(block, len*1000);  
  190.     //从512000处读sd卡  
  191.     SD_Block_R(block, len*1000);  
  192.       
  193. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值