久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 1496|回復: 0
打印 上一主題 下一主題
收起左側

分享程序:STM32通過SPI方式讀寫SD卡

[復制鏈接]
跳轉到指定樓層
樓主
ID:250869 發(fā)表于 2023-12-7 17:23 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
分享一下通過SPI方式讀寫SD卡的驅動源碼,只需要修改SPI讀寫函數(shù)以及片選口就可以投入使用,可自行搭配FATFS文件系統(tǒng)。
SD.c
  1. #include "SD.h"
  2. #include "Basic_cfg.h"

  3. u8 SD_Type = 0;
  4. /***************************/
  5. //SD讀寫函數(shù),便于替換SPI接口
  6. /***************************/
  7. u8 SD_ReadWriteByte(u8 TxData)
  8. {
  9.     SPI3_ReadWriteByte(TxData);
  10. }

  11. /***************************/
  12. //忙檢測,等待SD卡
  13. /***************************/
  14. u8 SD_WaitReady(void)
  15. {
  16.     u32 t=0;
  17.     u8 reg;
  18.     for(t=0; t<0xffff; t++)
  19.     {
  20.         reg=SD_ReadWriteByte(0XFF);//獲取返回值
  21.         if(reg==0XFF)
  22.             break;
  23.     }
  24.     if(t<0xffffff)
  25.         return 0;
  26.     else
  27.         return 1;
  28. }
  29. /***************************/
  30. //取消卡選擇
  31. /***************************/
  32. void SD_DisSelect(void)
  33. {
  34.     SD_CS=1;
  35.     SD_ReadWriteByte(0xff);//提供額外的8個時鐘
  36. }
  37. /***************************/
  38. //卡選擇,選擇SD卡
  39. /***************************/
  40. u8 SD_Select(void)
  41. {
  42.     SD_CS=0;
  43.     if(SD_WaitReady()==0)    //等待成功
  44.         return 0;
  45.     SD_DisSelect();    //等待失敗
  46.     return 1;
  47. }
  48. /***************************/
  49. //向SD卡發(fā)送一個命令
  50. //CMD:命令
  51. //arg:命令參數(shù)
  52. //crc:校驗
  53. /***************************/
  54. u8 SD_SendCmd(u8 cmd, u32 arg, u8 crc)
  55. {
  56.     u8 r1=0;
  57.     u8 Retry=0;
  58.     SD_DisSelect();    //取消上次片選

  59.     if(SD_Select())    //片選失效
  60.     {
  61.         return 0XFF;
  62.     }
  63.     //發(fā)送
  64.     //分別寫入命令
  65.     SD_ReadWriteByte(cmd | 0x40);
  66.     SD_ReadWriteByte(arg >> 24);
  67.     SD_ReadWriteByte(arg >> 16);
  68.     SD_ReadWriteByte(arg >> 8);
  69.     SD_ReadWriteByte(arg);
  70.     SD_ReadWriteByte(crc);
  71.     if(cmd==CMD12)SD_ReadWriteByte(0xff);
  72.     //等待響應,或超時退出
  73.     Retry=0X1F;
  74.     do
  75.     {
  76.         r1=SD_ReadWriteByte(0xFF);
  77.     }
  78.     while((r1&0X80) && Retry--);
  79.     //返回狀態(tài)值
  80.     return r1;
  81. }
  82. /***************************/
  83. //等待SD卡回應
  84. //Response:要得到的回應值
  85. //返回值:0,成功得到了該回應值
  86. //        其他,得到回應值失敗
  87. /***************************/
  88. u8 SD_GetResponse(u8 Response)
  89. {
  90.     //等待次數(shù)
  91.     u16 Count=0xFFFF;
  92.     //等待得到準確的回應
  93.     while ((SD_ReadWriteByte(0XFF)!=Response)&&Count)
  94.     {
  95.         Count--;
  96.     }
  97.     if (Count==0)
  98.     {
  99.         //得到回應失敗
  100.         return MSD_RESPONSE_FAILURE;
  101.     }
  102.     else
  103.     {
  104.         //正確回應
  105.         return MSD_RESPONSE_NO_ERROR;
  106.     }
  107. }
  108. //初始化SD卡
  109. u8 SD_Init(void)
  110. {
  111.     u8 r1=0;          // 存放SD卡的返回值
  112.     u16 retry;    // 用來進行超時計數(shù)
  113.     u8 buf[4];
  114.     u16 i;


  115.     SPI3_Init();    //初始化SPI3

  116.     SPI3_SetSpeed(SPI_BAUDRATEPRESCALER_256);    //配置為低速度模式
  117.     for(i=0; i<10; i++)    //發(fā)送至少74個脈沖
  118.     {
  119.         SD_ReadWriteByte(0xff);
  120.     }
  121.     retry=20;
  122.     do
  123.     {
  124.         //進入IDLE狀態(tài)
  125.         r1=SD_SendCmd(CMD0,0,0x95);
  126.     }
  127.     while((r1!=0X01) && (retry--));
  128.     //默認無卡
  129.     SD_Type=0;
  130.     //識別卡類型
  131.     if(r1==0X01)
  132.     {
  133.         //SD V2.0
  134.         if(SD_SendCmd(CMD8,0x1AA,0x87)==1)
  135.         {
  136.             //Get trailing return value of R7 resp
  137.             for(i=0; i<4; i++)
  138.                 buf[i]=SD_ReadWriteByte(0XFF);
  139.             //卡是否支持2.7~3.6V
  140.             if(buf[2]==0X01&&buf[3]==0XAA)
  141.             {
  142.                 retry=0XFFFE;
  143.                 do
  144.                 {
  145.                     //發(fā)送CMD55
  146.                     SD_SendCmd(CMD55,0,0X01);
  147.                     //發(fā)送CMD41
  148.                     r1=SD_SendCmd(CMD41,0x40000000,0X01);
  149.                 }
  150.                 while(r1&&retry--);
  151.                 //鑒別SD2.0卡版本開始
  152.                 if(retry&&SD_SendCmd(CMD58,0,0X01)==0)
  153.                 {
  154.                     //得到OCR值
  155.                     for(i=0; i<4; i++)
  156.                         buf[i]=SD_ReadWriteByte(0XFF);
  157.                     //檢查CCS
  158.                     if(buf[0]&0x40)
  159.                     {
  160.                         SD_Type=SD_TYPE_V2HC;
  161.                     }
  162.                     else
  163.                     {
  164.                         SD_Type=SD_TYPE_V2;
  165.                     }
  166.                 }
  167.             }
  168.         }
  169.     }
  170.     //SD V1.x/ MMC    V3
  171.     else
  172.     {
  173.         //發(fā)送CMD55
  174.         SD_SendCmd(CMD55,0,0X01);
  175.         //發(fā)送CMD41
  176.         r1=SD_SendCmd(CMD41,0,0X01);
  177.         if(r1<=1)
  178.         {
  179.             SD_Type=SD_TYPE_V1;
  180.             retry=0XFFFE;
  181.             //等待退出IDLE模式
  182.             do
  183.             {
  184.                 //發(fā)送CMD55
  185.                 SD_SendCmd(CMD55,0,0X01);
  186.                 //發(fā)送CMD41
  187.                 r1=SD_SendCmd(CMD41,0,0X01);
  188.             } while(r1&&retry--);
  189.         }
  190.         //MMC卡不支持CMD55+CMD41識別
  191.         else
  192.         {
  193.             //MMC V3
  194.             SD_Type=SD_TYPE_MMC;
  195.             retry=0XFFFE;
  196.             //等待退出IDLE模式
  197.             do
  198.             {
  199.                 //發(fā)送CMD1
  200.                 r1=SD_SendCmd(CMD1,0,0X01);
  201.             } while(r1&&retry--);
  202.         }
  203.         //錯誤的卡
  204.         if(retry==0||SD_SendCmd(CMD16,512,0X01)!=0)
  205.         {
  206.             SD_Type=SD_TYPE_ERR;
  207.         }
  208.     }
  209.     //取消片選
  210.     SD_DisSelect();
  211.     //配置為高速度模式
  212.     SPI3_SetSpeed(SPI_BAUDRATEPRESCALER_4);
  213.     if(SD_Type)
  214.     {
  215.         return 0;
  216.     }
  217.     else if(r1)
  218.     {
  219.         return r1;
  220.     }
  221.     //其他錯誤
  222.     return 0xaa;
  223. }
  224. /***************************/
  225. //從sd卡讀取一個數(shù)據(jù)包的內(nèi)容
  226. //buf:數(shù)據(jù)緩存區(qū)
  227. //len:要讀取的數(shù)據(jù)長度.
  228. //返回值:0,成功;其他,失敗;   
  229. /***************************/
  230. u8 SD_RecvData(u8*buf,u16 len)
  231. {                    
  232.     //等待SD卡發(fā)回數(shù)據(jù)起始令牌0xFE
  233.     if(SD_GetResponse(0xFE))
  234.     {
  235.         return 1;
  236.     }
  237.     //開始接收數(shù)據(jù)
  238.   while(len--)
  239.   {
  240.     *buf=SD_ReadWriteByte(0xFF);
  241.     buf++;
  242.   }
  243.   //下面是2個偽CRC(dummy CRC)
  244.   SD_ReadWriteByte(0xFF);
  245.   SD_ReadWriteByte(0xFF);        
  246.   //讀取成功                                                      
  247.   return 0;
  248. }
  249. /***************************/
  250. //獲取SD卡的CSD信息,包括容量和速度信息
  251. //輸入:u8 *cid_data(存放CID的內(nèi)存,至少16Byte)        
  252. //返回值:0:NO_ERR
  253. //         1:錯誤   
  254. /***************************/
  255. u8 SD_GetCSD(u8 *csd_data)
  256. {
  257.   u8 r1;     
  258.     //發(fā)CMD9命令,讀CSD
  259.   r1=SD_SendCmd(CMD9,0,0x01);
  260.   if(r1==0)
  261.     {
  262.         //接收16個字節(jié)的數(shù)據(jù)
  263.     r1=SD_RecvData(csd_data, 16);
  264.   }
  265.     //取消片選
  266.     SD_DisSelect();
  267.     if(r1)
  268.     {
  269.         return 1;
  270.     }
  271.     else
  272.     {
  273.         return 0;
  274.     }
  275. }  
  276. /***************************/
  277. //獲取SD卡的總扇區(qū)數(shù)(扇區(qū)數(shù))   
  278. //返回值:0: 取容量出錯
  279. //       其他:SD卡的容量(扇區(qū)數(shù)/512字節(jié))
  280. //每扇區(qū)的字節(jié)數(shù)必為512,因為如果不是512,則初始化不能通過.
  281. /***************************/
  282. u32 SD_GetSectorCount(void)
  283. {
  284.     u8 csd[16];
  285.     u32 Capacity;  
  286.     u8 n;
  287.         u16 csize;                          
  288.         //取CSD信息,如果期間出錯,返回0
  289.     if(SD_GetCSD(csd)!=0)
  290.         {
  291.             return 0;        
  292.         }
  293.     //如果為SDHC卡,按照下面方式計算
  294.         //V2.00的卡
  295.     if((csd[0]&0xC0)==0x40)     
  296.     {   
  297.             csize = csd[9] + ((u16)csd[8] << 8) + 1;
  298.             //得到扇區(qū)數(shù)   
  299.             Capacity = (u32)csize << 10;            
  300.     }
  301.         //V1.XX的卡
  302.         else
  303.     {   
  304.             n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
  305.             csize = (csd[8] >> 6) + ((u16)csd[7] << 2) + ((u16)(csd[6] & 3) << 10) + 1;
  306.             //得到扇區(qū)數(shù)
  307.             Capacity= (u32)csize << (n - 9);  
  308.     }
  309.     return Capacity;
  310. }

  311. u8 SD_ReadDisk(u8*buf,u32 sector,u8 cnt)
  312. {
  313.     u8 r1;
  314.     //轉換為字節(jié)地址
  315.     if(SD_Type!=SD_TYPE_V2HC)
  316.     {
  317.         sector <<= 9;
  318.     }
  319.     if(cnt==1)
  320.     {
  321.         //讀命令
  322.         r1=SD_SendCmd(CMD17,sector,0X01);
  323.         //指令發(fā)送成功
  324.         if(r1==0)
  325.         {
  326.             //接收512個字節(jié)     
  327.             r1=SD_RecvData(buf,512);  
  328.         }
  329.     }
  330.     else
  331.     {
  332.         //連續(xù)讀命令
  333.         r1=SD_SendCmd(CMD18,sector,0X01);
  334.         do
  335.         {
  336.             //接收512個字節(jié)     
  337.             r1=SD_RecvData(buf,512);
  338.             buf+=512;  
  339.         }
  340.         while(--cnt && r1==0);     
  341.         //發(fā)送停止命令
  342.         SD_SendCmd(CMD12,0,0X01);   
  343.     }   
  344.     //取消片選
  345.     SD_DisSelect();
  346.     return r1;
  347. }
  348. /***************************/
  349. //讀取SD卡的指定扇區(qū)的內(nèi)容,并通過串口1輸出
  350. //sec:扇區(qū)物理地址編號
  351. /***************************/
  352. void SD_Read_Sectorx(u32 sec)
  353. {
  354.     //存儲扇區(qū)數(shù)據(jù)
  355.     u8 buf[512];
  356.     u16 i;
  357.    
  358.     //讀取0扇區(qū)的內(nèi)容
  359.     if(SD_ReadDisk(buf,sec,1)==0)   
  360.     {   
  361.         printf("SECTOR 0 DATA:\r\n");
  362.         //打印sec扇區(qū)數(shù)據(jù)  
  363.         for(i=0;i<512;i++)
  364.             printf("%X ",buf[i]);         
  365.         printf("\r\nDATA ENDED\r\n");
  366.     }
  367. }
  368. /***************************/
  369. //獲取SD卡的CID信息,包括制造商信息
  370. //輸入: u8 *cid_data(存放CID的內(nèi)存,至少16Byte)      
  371. //返回值:0:NO_ERR
  372. //         1:錯誤   
  373. /***************************/
  374. u8 SD_GetCID(u8 *cid_data)
  375. {
  376.   u8 r1;      
  377.   //發(fā)CMD10命令,讀CID
  378.   r1=SD_SendCmd(CMD10,0,0x01);
  379.   if(r1==0x00)
  380.     {
  381.         //接收16個字節(jié)的數(shù)據(jù)     
  382.         r1=SD_RecvData(cid_data,16);
  383.   }
  384.     //取消片選
  385.     SD_DisSelect();
  386.     if(r1)
  387.         return 1;
  388.     else
  389.         return 0;
  390. }
  391. /***************************/
  392. //向sd卡寫入一個數(shù)據(jù)包的內(nèi)容 512字節(jié)
  393. //buf:數(shù)據(jù)緩存區(qū)
  394. //cmd:指令
  395. //返回值:0,成功;其他,失敗;   
  396. /***************************/
  397. u8 SD_SendBlock(u8*buf,u8 cmd)
  398. {   
  399.     u16 t;               
  400.     //等待準備失效
  401.     if(SD_WaitReady())
  402.     {
  403.         return 1;
  404.     }
  405.     SD_ReadWriteByte(cmd);
  406.     //不是結束指令
  407.     if(cmd!=0XFD)
  408.     {
  409.         //提高速度,減少函數(shù)傳參時間
  410.         for(t=0;t<512;t++)
  411.         {
  412.             SD_ReadWriteByte(buf[t]);
  413.         }
  414.         //忽略crc
  415.       SD_ReadWriteByte(0xFF);
  416.       SD_ReadWriteByte(0xFF);
  417.         //接收響應
  418.         t=SD_ReadWriteByte(0xFF);
  419.         if((t&0x1F)!=0x05)
  420.         {
  421.             //響應錯誤        
  422.             return 2;        
  423.         }            
  424.     }                                 
  425.     //寫入成功                                                      
  426.   return 0;
  427. }
  428. /***************************/
  429. //寫SD卡
  430. //buf:數(shù)據(jù)緩存區(qū)
  431. //sector:起始扇區(qū)
  432. //cnt:扇區(qū)數(shù)
  433. //返回值:0,ok;其他,失敗.
  434. /***************************/
  435. u8 SD_WriteDisk(u8*buf,u32 sector,u8 cnt)
  436. {
  437.     u8 r1;
  438.     //轉換為字節(jié)地址
  439.     if(SD_Type!=SD_TYPE_V2HC)
  440.     {
  441.         sector *= 512;
  442.     }
  443.     if(cnt==1)
  444.     {
  445.         //讀命令
  446.         r1=SD_SendCmd(CMD24,sector,0X01);
  447.         //指令發(fā)送成功
  448.         if(r1==0)
  449.         {
  450.             //寫512個字節(jié)      
  451.             r1=SD_SendBlock(buf,0xFE);
  452.         }
  453.     }
  454.     else
  455.     {
  456.         if(SD_Type!=SD_TYPE_MMC)
  457.         {
  458.             SD_SendCmd(CMD55,0,0X01);   
  459.             //發(fā)送指令   
  460.             SD_SendCmd(CMD23,cnt,0X01);
  461.         }
  462.         //連續(xù)讀命令
  463.          r1=SD_SendCmd(CMD25,sector,0X01);
  464.         if(r1==0)
  465.         {
  466.             do
  467.             {
  468.                 //接收512個字節(jié)     
  469.                 r1=SD_SendBlock(buf,0xFC);
  470.                 buf+=512;  
  471.             }
  472.             while(--cnt && r1==0);
  473.             //接收512個字節(jié)
  474.             r1=SD_SendBlock(0,0xFD);
  475.         }
  476.     }   
  477.     //取消片選
  478.     SD_DisSelect();
  479.     return r1;
  480. }   
復制代碼

sd.h
  1. #ifndef __SD_H
  2. #define __SD_H  
  3. #include "sys.h"

  4. #define SD_CS PAout(15)

  5. // SD卡類型定義  
  6. #define SD_TYPE_ERR     0X00
  7. #define SD_TYPE_MMC     0X01
  8. #define SD_TYPE_V1      0X02
  9. #define SD_TYPE_V2      0X04
  10. #define SD_TYPE_V2HC    0X06

  11. // SD卡指令表            
  12. #define CMD0    0       //卡復位
  13. #define CMD1    1
  14. #define CMD8    8       //命令8 ,SEND_IF_COND
  15. #define CMD9    9       //命令9 ,讀CSD數(shù)據(jù)
  16. #define CMD10   10      //命令10,讀CID數(shù)據(jù)
  17. #define CMD12   12      //命令12,停止數(shù)據(jù)傳輸
  18. #define CMD16   16      //命令16,設置SectorSize 應返回0x00
  19. #define CMD17   17      //命令17,讀sector
  20. #define CMD18   18      //命令18,讀Multi sector
  21. #define CMD23   23      //命令23,設置多sector寫入前預先擦除N個block
  22. #define CMD24   24      //命令24,寫sector
  23. #define CMD25   25      //命令25,寫Multi sector
  24. #define CMD41   41      //命令41,應返回0x00
  25. #define CMD55   55      //命令55,應返回0x01
  26. #define CMD58   58      //命令58,讀OCR信息
  27. #define CMD59   59      //命令59,使能/禁止CRC,應返回0x00

  28. //數(shù)據(jù)寫入回應字意義
  29. #define MSD_DATA_OK                0x05
  30. #define MSD_DATA_CRC_ERROR         0x0B
  31. #define MSD_DATA_WRITE_ERROR       0x0D
  32. #define MSD_DATA_OTHER_ERROR       0xFF

  33. //SD卡回應標記字
  34. #define MSD_RESPONSE_NO_ERROR      0x00
  35. #define MSD_IN_IDLE_STATE          0x01
  36. #define MSD_ERASE_RESET            0x02
  37. #define MSD_ILLEGAL_COMMAND        0x04
  38. #define MSD_COM_CRC_ERROR          0x08
  39. #define MSD_ERASE_SEQUENCE_ERROR   0x10
  40. #define MSD_ADDRESS_ERROR          0x20
  41. #define MSD_PARAMETER_ERROR        0x40
  42. #define MSD_RESPONSE_FAILURE       0xFF

  43. void SD_Read_Sectorx(u32 sec);
  44. u8 SD_Init(void);
  45. u8 SD_WaitReady(void);
  46. u8 SD_GetResponse(u8 Response);
  47. u32 SD_GetSectorCount(void);
  48. u8 SD_GetCID(u8 *cid_data);
  49. u8 SD_GetCSD(u8 *csd_data);
  50. u8 SD_ReadDisk(u8*buf,u32 sector,u8 cnt);
  51. u8 SD_WriteDisk(u8*buf,u32 sector,u8 cnt);

  52. #endif

復制代碼


原理圖: 無
仿真: 無



分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏4 分享淘帖 頂 踩
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 最新中文字幕在线 | 成人欧美一区二区三区黑人孕妇 | 一级片av | 欧美一二区| 精品成人免费视频 | 精品国产黄a∨片高清在线 成人区精品一区二区婷婷 日本一区二区视频 | 久久久久久久国产精品视频 | 欧美日韩成人一区二区 | 欧美最猛黑人 | 久久不卡视频 | 激情婷婷 | 香蕉视频1024 | 97国产精品视频 | 亚洲不卡在线观看 | 秋霞电影一区二区 | 欧美日韩久 | 91热在线| 久久久国产精品一区 | 国产精品激情 | 嫩草视频在线看 | 中文字幕欧美日韩一区 | 国产欧美精品一区二区三区 | 日本精品一区二区 | 欧美精品在线免费 | 蜜桃精品噜噜噜成人av | 国产精品福利在线 | 午夜小电影 | 奇米四色影视 | 羞羞视频网站免费观看 | 超碰成人av| 性一交一乱一透一a级 | 日韩欧美国产精品一区二区三区 | 日韩一级黄色片 | 91精品久久久久久久久中文字幕 | 日日日视频 | 自拍偷拍中文字幕 | 美国一级黄色片 | 毛片一级黄色 | 成人av免费 | 午夜久久久久久久久久一区二区 | 欧美日韩亚洲一区 |