找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4586|回复: 3
收起左侧

关于stm32spi读写sd卡cmd41一直返回0x01的解决办法

[复制链接]
ID:708086 发表于 2020-4-27 15:19 | 显示全部楼层 |阅读模式
先说一下我的情况,我的代码是原子哥的,首先执行到cmd0,返回01,进入到idle状态,这是没有问题的,然后cmd8判断是否为sdv2.0,返回01,这也是没有问题的。然后循环发送cmd41(r1=SD_SendCmd(CMD41,0x40000000,0X01))和cmd55,返回值一直为0x01,正常来说,返回指应该0x00(我的卡是sdhc)。解决办法:更换电源,我买的这个模块的是可以用5v的,之前用的3v。推测可能是电流不够。店家给的例程实在arduino上跑,我试了没问题,看到电源我才感觉有点东西,这里踩个坑,希望能帮助到大家(第一次在论坛发帖,紧张。。。。)我用的例程放到下边
51hei.png

单片机源程序如下:
  1. #include "sys.h"
  2. #include "sd-spi.h"                           
  3. #include "spi2.h"
  4. #include "usart.h"        
  5. #include<oled.h>

  6. u8  SD_Type=0;//SD卡的类型

  7. u8 SD_SPI_ReadWriteByte(u8 data)
  8. {
  9.         return SPI2_ReadWriteByte(data);
  10. }         
  11. //SD卡初始化的时候,需要低速
  12. void SD_SPI_SpeedLow(void)
  13. {
  14.          SPI2_SetSpeed(SPI_BaudRatePrescaler_256);//设置到低速模式        
  15. }
  16. //SD卡正常工作的时候,可以高速了
  17. void SD_SPI_SpeedHigh(void)
  18. {
  19.          SPI2_SetSpeed(SPI_BaudRatePrescaler_2);//设置到高速模式        
  20. }

  21. void SD_DisSelect(void)
  22. {
  23.         SD_CS=1;
  24.          SD_SPI_ReadWriteByte(0xff);//提供额外的8个时钟
  25. }
  26. //选择sd卡,并且等待卡准备OK
  27. //返回值:0,成功;1,失败;
  28. u8 SD_Select(void)
  29. {
  30.         SD_CS=0;
  31.         if(SD_WaitReady()==0)return 0;//等待成功
  32.         SD_DisSelect();
  33.         return 1;//等待失败
  34. }
  35. //等待卡准备好
  36. //返回值:0,准备好了;其他,错误代码
  37. u8 SD_WaitReady(void)
  38. {
  39.         u32 t=0;
  40.         do
  41.         {
  42.                 if(SD_SPI_ReadWriteByte(0XFF)==0XFF)return 0;//OK
  43.                 t++;                          
  44.         }while(t<0XFFFFFF);//等待
  45.         return 1;
  46. }
  47. //等待SD卡回应
  48. //Response:要得到的回应值
  49. //返回值:0,成功得到了该回应值
  50. //    其他,得到回应值失败
  51. u8 SD_GetResponse(u8 Response)
  52. {
  53.         u16 Count=0xFFFF;//等待次数                                                            
  54.         while ((SD_SPI_ReadWriteByte(0XFF)!=Response)&&Count)Count--;//等待得到准确的回应            
  55.         if (Count==0)return MSD_RESPONSE_FAILURE;//得到回应失败   
  56.         else return MSD_RESPONSE_NO_ERROR;//正确回应
  57. }
  58. //从sd卡读取一个数据包的内容
  59. //buf:数据缓存区
  60. //len:要读取的数据长度.
  61. //返回值:0,成功;其他,失败;        
  62. u8 SD_RecvData(u8*buf,u16 len)
  63. {                                    
  64.         if(SD_GetResponse(0xFE))return 1;//等待SD卡发回数据起始令牌0xFE
  65.     while(len--)//开始接收数据
  66.     {
  67.         *buf=SPI2_ReadWriteByte(0xFF);
  68.         buf++;
  69.     }
  70.     //下面是2个伪CRC(dummy CRC)
  71.     SD_SPI_ReadWriteByte(0xFF);
  72.     SD_SPI_ReadWriteByte(0xFF);                                                                                                                     
  73.     return 0;//读取成功
  74. }
  75. //向sd卡写入一个数据包的内容 512字节
  76. //buf:数据缓存区
  77. //cmd:指令
  78. //返回值:0,成功;其他,失败;        
  79. u8 SD_SendBlock(u8*buf,u8 cmd)
  80. {        
  81.         u16 t;                           
  82.         if(SD_WaitReady())return 1;//等待准备失效
  83.         SD_SPI_ReadWriteByte(cmd);
  84.         if(cmd!=0XFD)//不是结束指令
  85.         {
  86.                 for(t=0;t<512;t++)SPI2_ReadWriteByte(buf[t]);//提高速度,减少函数传参时间
  87.             SD_SPI_ReadWriteByte(0xFF);//忽略crc
  88.             SD_SPI_ReadWriteByte(0xFF);
  89.                 t=SD_SPI_ReadWriteByte(0xFF);//接收响应
  90.                 if((t&0x1F)!=0x05)return 2;//响应错误                                                                                                                     
  91.         }                                                                                                                                                                       
  92.     return 0;//写入成功
  93. }

  94. //向SD卡发送一个命令
  95. //输入: u8 cmd   命令
  96. //      u32 arg  命令参数
  97. //      u8 crc   crc校验值           
  98. //返回值:SD卡返回的响应                                                                                                                          
  99. u8 SD_SendCmd(u8 cmd, u32 arg, u8 crc)
  100. {
  101.     u8 r1;        
  102.         u8 Retry=0;
  103.         SD_DisSelect();//取消上次片选
  104.         if(SD_Select())return 0XFF;//片选失效
  105.         //发送
  106.     SD_SPI_ReadWriteByte(cmd | 0x40);//分别写入命令
  107.     SD_SPI_ReadWriteByte(arg >> 24);
  108.     SD_SPI_ReadWriteByte(arg >> 16);
  109.     SD_SPI_ReadWriteByte(arg >> 8);
  110.     SD_SPI_ReadWriteByte(arg);         
  111.     SD_SPI_ReadWriteByte(crc);
  112.         if(cmd==CMD12)SD_SPI_ReadWriteByte(0xff);//Skip a stuff byte when stop reading
  113.     //等待响应,或超时退出
  114.         Retry=0X1F;
  115.         do
  116.         {
  117.                 r1=SD_SPI_ReadWriteByte(0xFF);
  118.         }while((r1&0X80) && Retry--);         
  119.         //返回状态值
  120.     return r1;
  121. }                                                                                                                                                                              
  122. //获取SD卡的CID信息,包括制造商信息
  123. //输入: u8 *cid_data(存放CID的内存,至少16Byte)         
  124. //返回值:0:NO_ERR
  125. //                 1:错误                                                                                                                  
  126. u8 SD_GetCID(u8 *cid_data)
  127. {
  128.     u8 r1;           
  129.     //发CMD10命令,读CID
  130.     r1=SD_SendCmd(CMD10,0,0x01);
  131.     if(r1==0x00)
  132.         {
  133.                 r1=SD_RecvData(cid_data,16);//接收16个字节的数据         
  134.     }
  135.         SD_DisSelect();//取消片选
  136.         if(r1)return 1;
  137.         else return 0;
  138. }                                                                                                                                                                  
  139. //获取SD卡的CSD信息,包括容量和速度信息
  140. //输入:u8 *cid_data(存放CID的内存,至少16Byte)            
  141. //返回值:0:NO_ERR
  142. //                 1:错误                                                                                                                  
  143. u8 SD_GetCSD(u8 *csd_data)
  144. {
  145.     u8 r1;         
  146.     r1=SD_SendCmd(CMD9,0,0x01);//发CMD9命令,读CSD
  147.     if(r1==0)
  148.         {
  149.             r1=SD_RecvData(csd_data, 16);//接收16个字节的数据
  150.     }
  151.         SD_DisSelect();//取消片选
  152.         if(r1)return 1;
  153.         else return 0;
  154. }  
  155. //获取SD卡的总扇区数(扇区数)   
  156. //返回值:0: 取容量出错
  157. //       其他:SD卡的容量(扇区数/512字节)
  158. //每扇区的字节数必为512,因为如果不是512,则初始化不能通过.                                                                                                                  
  159. u32 SD_GetSectorCount(void)
  160. {
  161.     u8 csd[16];
  162.     u32 Capacity;  
  163.     u8 n;
  164.         u16 csize;                                             
  165.         //取CSD信息,如果期间出错,返回0
  166.     if(SD_GetCSD(csd)!=0) return 0;            
  167.     //如果为SDHC卡,按照下面方式计算
  168.     if((csd[0]&0xC0)==0x40)         //V2.00的卡
  169.     {        
  170.                 csize = csd[9] + ((u16)csd[8] << 8) + 1;
  171.                 Capacity = (u32)csize << 10;//得到扇区数                           
  172.     }else//V1.XX的卡
  173.     {        
  174.                 n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
  175.                 csize = (csd[8] >> 6) + ((u16)csd[7] << 2) + ((u16)(csd[6] & 3) << 10) + 1;
  176.                 Capacity= (u32)csize << (n - 9);//得到扇区数   
  177.     }
  178.     return Capacity;
  179. }
  180. //初始化SD卡
  181. u8 SD_Init(void)
  182. {
  183.     u8 r1;      // 存放SD卡的返回值
  184.     u16 retry;  // 用来进行超时计数
  185.     u8 buf[4];  
  186.         u16 i;

  187.         SPI2_Init();                //初始化IO
  188.         SD_Select();
  189.          SD_SPI_SpeedLow();        //设置到低速模式
  190.          for(i=0;i<10;i++)SD_SPI_ReadWriteByte(0XFF);//发送最少74个脉冲
  191.         retry=20;
  192.         do
  193.         {
  194.                 r1=SD_SendCmd(CMD0,0,0x95);//进入IDLE状态
  195.         }while((r1!=0X01) && retry--);
  196.          SD_Type=0;//默认无卡
  197.         if(r1==0X01)
  198.         {        
  199.                
  200.                 if(SD_SendCmd(CMD8,0x1AA,0x87)==1)//SD V2.0
  201.                 {
  202.                         for(i=0;i<4;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF);        //Get trailing return value of R7 resp
  203.                         if(buf[2]==0X01&&buf[3]==0XAA)//卡是否支持2.7~3.6V
  204.                         {
  205.                                 retry=0X0FFE;
  206.                                 do
  207.                                 {
  208.                                         SD_SendCmd(CMD55,0,0X01);        //发送CMD55
  209.                                         r1=SD_SendCmd(CMD41,0x40000000,0X01);//发送CMD41
  210.                                         OLED_DisplayHex(0,2,16,16,r1);
  211.                                 }while(r1&&retry--);
  212.                                 
  213.                                 if(retry&&SD_SendCmd(CMD58,0,0X01)==0)//鉴别SD2.0卡版本开始
  214.                                 {        
  215.                                         OLED_DisplayHex(0,0,16,16,0x22);
  216.                                         for(i=0;i<4;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF);//得到OCR值
  217.                                         if(buf[0]&0x40)SD_Type=SD_TYPE_V2HC;    //检查CCS
  218.                                         else SD_Type=SD_TYPE_V2;   
  219.                                 }
  220.                         }
  221.                 }else//SD V1.x/ MMC        V3
  222.                 {
  223.                         SD_SendCmd(CMD55,0,0X01);                //发送CMD55
  224.                         r1=SD_SendCmd(CMD41,0,0X01);        //发送CMD41
  225.                         if(r1<=1)
  226.                         {               
  227.                                 SD_Type=SD_TYPE_V1;
  228.                                 retry=0XFFFE;
  229.                                 do //等待退出IDLE模式
  230.                                 {
  231.                                         SD_SendCmd(CMD55,0,0X01);        //发送CMD55
  232.                                         r1=SD_SendCmd(CMD41,0,0X01);//发送CMD41
  233.                                 }while(r1&&retry--);
  234.                         }else//MMC卡不支持CMD55+CMD41识别
  235.                         {
  236.                                 SD_Type=SD_TYPE_MMC;//MMC V3
  237.                                 retry=0XFFFE;
  238.                                 do //等待退出IDLE模式
  239.                                 {                                                                                            
  240.                                         r1=SD_SendCmd(CMD1,0,0X01);//发送CMD1
  241.                                 }while(r1&&retry--);  
  242.                         }
  243.                         if(retry==0||SD_SendCmd(CMD16,512,0X01)!=0)SD_Type=SD_TYPE_ERR;//错误的卡
  244.                 }
  245.         }
  246.         SD_DisSelect();//取消片选
  247.         SD_SPI_SpeedHigh();//高速
  248.         if(SD_Type)return 0;
  249.         else if(r1)return r1;            
  250.         return 0xaa;//其他错误
  251. }
  252. //读SD卡
  253. //buf:数据缓存区
  254. //sector:扇区
  255. //cnt:扇区数
  256. //返回值:0,ok;其他,失败.
  257. u8 SD_ReadDisk(u8*buf,u32 sector,u8 cnt)
  258. {
  259.         u8 r1;
  260.         if(SD_Type!=SD_TYPE_V2HC)sector <<= 9;//转换为字节地址
  261.         if(cnt==1)
  262.         {
  263.                 r1=SD_SendCmd(CMD17,sector,0X01);//读命令
  264.                 if(r1==0)//指令发送成功
  265.                 {
  266.                         r1=SD_RecvData(buf,512);//接收512个字节           
  267.                 }
  268.         }else
  269.         {
  270.                 r1=SD_SendCmd(CMD18,sector,0X01);//连续读命令
  271.                 do
  272.                 {
  273.                         r1=SD_RecvData(buf,512);//接收512个字节         
  274.                         buf+=512;  
  275.                 }while(--cnt && r1==0);         
  276.                 SD_SendCmd(CMD12,0,0X01);        //发送停止命令
  277.         }   
  278.         SD_DisSelect();//取消片选
  279.         return r1;//
  280. }
  281. //写SD卡
  282. //buf:数据缓存区
  283. //sector:起始扇区
  284. //cnt:扇区数
  285. //返回值:0,ok;其他,失败.
  286. u8 SD_WriteDisk(u8*buf,u32 sector,u8 cnt)
  287. {
  288.         u8 r1;
  289.         if(SD_Type!=SD_TYPE_V2HC)sector *= 512;//转换为字节地址
  290.         if(cnt==1)
  291.         {
  292.                 r1=SD_SendCmd(CMD24,sector,0X01);//读命令
  293.                 if(r1==0)//指令发送成功
  294.                 {
  295.                         r1=SD_SendBlock(buf,0xFE);//写512个字节           
  296.                 }
  297.         }else
  298.         {
  299.                 if(SD_Type!=SD_TYPE_MMC)
  300.                 {
  301.                         SD_SendCmd(CMD55,0,0X01);        
  302.                         SD_SendCmd(CMD23,cnt,0X01);//发送指令        
  303.                 }
  304.                  r1=SD_SendCmd(CMD25,sector,0X01);//连续读命令
  305.                 if(r1==0)
  306.                 {
  307.                         do
  308.                         {
  309.                                 r1=SD_SendBlock(buf,0xFC);//接收512个字节         
  310.                                 buf+=512;  
  311.                         }while(--cnt && r1==0);
  312.                         r1=SD_SendBlock(0,0xFD);//接收512个字节
  313.                 }
  314.         }   
  315.         SD_DisSelect();//取消片选
  316.         return r1;//
  317. }        
复制代码

所有资料51hei提供下载:
Desktop.zip (5.84 KB, 下载次数: 33)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:840500 发表于 2020-11-8 11:21 | 显示全部楼层
换了电源也不行呢 ?
回复

使用道具 举报

ID:833622 发表于 2022-10-5 20:22 | 显示全部楼层
感谢,一直是0x01几天下来一直没找到原因,之前也试过电源不行,今天把开发板和SD模块同时都接上5v瞬间返回0x00
回复

使用道具 举报

ID:79094 发表于 2024-5-5 21:44 | 显示全部楼层
sd卡 不是3.3 供电吗
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表