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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

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

51單片機+SD卡可讀可寫串口顯示源程序與詳解

  [復制鏈接]
跳轉到指定樓層
樓主
SD卡
SD 卡(Seecure Digital Memory Cardl)是一種基于 Flash 的新一代存儲器,具有體積小、容量大、數據傳輸快、移動靈活、安全性能好等優點,是許多便攜式電子儀器理想的外部存儲介質

SD 卡支持兩種總線方式:SD 方式與 SPI 方式。其中 SD 方式采用 6 線制,使用 CLK、 CMD、DAT0~DAT3 進行數據通信。而 SPI 方式采用 4 線制,使用 CS、CLK、DataIn、DataOut 進行數據通信。SD 方式時的數據傳輸速度與 SPI 方式要快,采用單片機對 SD 卡進行讀寫時一般都采用 SPI 模式。采用不同的初始化方式可以使 SD 卡工作于 SD 方式或 SPI 方式。

這里只對其 SPI 方式進行介紹。
SPI 方式驅動 SD 卡的方法
SD 卡的 SPI 通信接口使其可以通過 SPI 通道進行數據讀寫。從應用的角度來看,采用 SPI 接口的好處在于,很多單片機內部自帶 SPI 控制器,不光給開發上帶來方便,同時也見降低了開發成本。然而,它也有不好的地方,如失去了 SD 卡的性能優勢,要解決這一問題,就要用 SD 方式,因為它提供更大的總線數據帶寬。SPI 接口的選用是在上電初始時向其寫入第一個命令時進行的。以下介紹 SD 卡的驅動方法,只實現簡單的扇區讀寫。
為了使SD卡初始化進入SPI模式,我們需要使用的命令有3個CMD0,CMD55,ACMD41(使用ACMD類的指令前應先發CMD55,CMD55起到一個切換到ACMD類命令的作用)。
   為什么在使用CMD0以后不使用CMD1?CMD1是MMC卡使用的指令。我們上電或者發送CMD0后,應該首先發送CMD55+ACMD41確認是否有回應,如果有回應則為SD卡,如果等回應超時,則可能是MMC卡,再發CMD1確認。
SD卡調試步驟:
1. 上電時要延時足夠長的時間給SD卡一個準備的過程,SD卡初始化第一步發送CMD命令之前,在片選有效的情況下首先要發送至少74個時鐘,否則可能會出現SD卡不能初始化的問題。那么為什么要74個CLK呢?因為在上電初期,電壓的上升過程據SD卡組織的計算約合64個CLK周期才能到達SD卡的正常工作電壓他們管這個叫做Supply ramp up time,其后的10個CLK是為了與SD卡同步,之后開始CMD0的操作,嚴格按照此項操作,一定沒有問題。
2. SD卡發送CMD0命令,返回狀態為0x01,則復位成功。
3. SD卡發送復位命令CMD0后,要發送版本查詢命令CMD8,返回狀態一般分為兩種,若返回0x01,表示此SD卡接收CMD8,也就是說SD卡支持版本2;若返回0x05則表示SD卡支持版本1.
4. 理論上要求發送CMD58獲得SD卡電壓參數,但實際上都實現知道SD卡的工作電壓是3.3v,所以可以省略這一步。
5. 發送CMD55命令,返回0x01,起到轉換的作用。
6. 再發送ACMD41,等待返回0x00,則表示完成初始化。這里要說的是如果最后的回應內容還是0x01的話,可以循環發送CMD55+ACMD41,直到回應的內容0x00。
SD卡操作命令作步驟:
1.讀步驟:
發送CMD17(單塊)或CMD18(多塊)讀命令,返回0x00
接收數據開始令牌0xfe(或0xfc)+正式數據512B+CRC校驗2B
2.寫步驟:
發送CMD24(單塊)或CMD25(多塊)寫命令,返回0x00.
發送數據開始令牌0xfe(或0xfc)+正式數據512B+CRC校驗2B
3.擦除步驟:
發送CMD32,跟一個參數來指定首個要擦除的起始地址
發送CMD33,指定最后的地址
發送CMD38,擦除指定區間的內容。

向SD卡寫入一個CMD或者ACMD指令的過程是這樣的:
1.首先使CS為低電平,SD卡使能;其次在SD卡的Din寫入指令;寫入指令后還要附加8個填充時鐘,是SD卡完成內部操作;之后在SD卡的Dout上接受回應;回應接受完畢使CS為低電平,再附加8個填充時鐘。
2.在SD卡的Din沒有數據寫入時,應使Din保持高電平。
一些常用的指令格式:
CMD0:0x40,0x00,0x00,0x00,0x00,0x95 
CMD8:0x48,0x00,0x00,0x01,0xaa,0x87 
CMD55:0x77,0x00,0x00,0x00,0x00,0xff   0x77=0x40+0x37(55的16進制表示) ACMD41:0x69,0x40,0x00,0x00,0x00,0xff
CMD58:0x7a,0x00,0x00,0x00,0x00,0xff
ACMD41屬于附加命令,發送起來要麻煩一些,必須提前通知SD卡下一條要發送的命令為ACMD,這個通知就是CMD55,它的4字節參數都為0即可
SD卡的命令格式:
每一個命令的長度都是固定的6個字節,前1個字節的值=命令號+0x40;中間4個字節為參數,不同的命令參數格式都不相同,但參數最多為4個字節;最后1個字節是CRC校驗碼和1位固定結束位‘1’。這里需要說明一下0x40的意思,任何命令都有一個固定的起始格式,即先0后1,這是固定的命令起始標志,前兩個字節的二進制碼就是:01xx xxxx 
SD 卡所有的命令都是由 48 個數據位組成的,其結構如表 2 所示。
需要特殊說明的是CRC的問題,這是一種檢驗錯誤的方法,具體問題度娘說的還算明白,在SPI模式中,CRC校驗默認是關閉的,也就是說這7位必須要發,但是SD卡會在讀到CRC以后自動忽略它,所以全部發1就可以。例外的是,CMD0,CMD8這兩個命令發送的時候SD卡還沒有進入SPI模式,也就是說CRC校驗在這個時候還是啟用狀態,因此這兩個命令的CRC效驗碼必須要寫正確,SD卡才會執行命令,否在在返回值R1中就會有相應的錯誤標志位提示開發人員CRC校驗碼錯誤。     





SD卡的命令代碼:
1)復位


單片機源程序如下:
  1. /*********************************

  2. * @函數名:SD_SPI_Rest

  3. * @描  述:SD卡復位

  4. * @參  數:無

  5. * @返回值:成功 0  失敗 0x01

  6. *********************************/

  7. uchar SD_SPI_Rest()//SD卡復位,進入SPI模式,使用CMD0(命令0)
  8. {
  9. uchar time,temp,i;

  10. uchar pcmd[] = {0x40,0x00,0x00,0x00,0x00,0x95}; //命令0的字節序列

  11. SPI_Speed_Slow=1; //將SPI_Speed_Slow置為1

  12. SD_CS=1;  //關閉片選

  13. for(i=0;i<0x0f;i++) //復位時,首先要發送最少74個時鐘信號,這是必須的!!!

  14. {

  15.   SD_SPI_Write_Byte(0xff); //120個時鐘   0x0f=15*8=120個時鐘信號

  16. }

  17. SD_CS=0; //打開片選

  18. time=0;

  19. do

  20. {

  21.      temp=SD_SPI_Write_CMD(pcmd);//連續寫入CMD0

  22.      time++;

  23.   if(time==TRY_TIME)

  24.   {

  25.   SD_CS=1; //關閉片選

  26.   Send_String("初始化失敗"); //提示初始化失敗

  27.      return(0x01);//CMD0寫入失敗

  28.   }

  29. }while(temp!=0x01);  //返回0x01是復位成功

  30. SD_CS=1; //關閉片選

  31. SD_SPI_Write_Byte(0xff); //按照SD卡的操作時序在這里補8個時鐘

  32. return 0;//返回0,說明復位操作成功

  33. }
復制代碼
2)查版本號
  1. /*********************************

  2. * @函數名:SD_SPI_Version

  3. * @描  述:讀SD卡版本號

  4. * @參  數:無

  5. * @返回值:成功 0  失敗 0x01

  6. *********************************/

  7. uchar SD_SPI_Version()

  8. {

  9.     uchar time,temp;

  10. uchar pcmd[] = {0x48,0x00,0x00,0x01,0xaa,0x87}; // //CMD8

  11. SD_CS=0; //打開片選

  12.   time=0;

  13. do

  14.     temp=SD_SPI_Write_CMD(pcmd);

  15.     time++;

  16.   if(time==TRY_TIME)

  17.   {

  18.   SD_CS=1; //關閉片選

  19.   Send_String("獲取版本號失敗");//獲取版本號失敗

  20.    return(0x01);

  21.   }

  22. }while(temp!=0x01);  //返回0x01是2.0版本

  23.   SD_CS=1; //關閉片選

  24.   SD_SPI_Write_Byte(0xff); //按照SD卡的操作時序在這里補8個時鐘

  25. return 0;//返回0,說明復位操作成功

  26. }
復制代碼
3)初始化
  1. /*********************************

  2. * @函數名:SD_SPI_Init

  3. * @描  述:SD卡初始化

  4. * @參  數:無

  5. * @返回值:成功 0  失敗 0x01

  6. *********************************/

  7. uchar SD_SPI_Init()        //初始化,使用ACMD41

  8. {  

  9. uchar time,temp;

  10. uchar pcmd[] = {0x69,0x40,0x00,0x00,0x00,0xff}; //ACMD41的字節序列

  11. uchar pcmd1[]={0x77,0x00,0x00,0x00,0x00,0xff};//CMD55

  12. /*調用這兩個函數*/

  13. SD_SPI_Rest();                         //復位SD卡

  14. SD_SPI_Version();//版本號

  15. SD_CS=0; //打開片選

  16. time=0;

  17. do

  18. {

  19. SD_SPI_Read_Byte(); //這4個讀函數,必須有,沒有將不會初始化成功

  20. SD_SPI_Read_Byte();

  21. SD_SPI_Read_Byte();

  22. SD_SPI_Read_Byte();

  23. temp=SD_SPI_Write_CMD(pcmd1); // 發送CMD55

  24. if(temp!=0x01)//上一次的返回值,這次沒有返回值

  25. {

  26.   Send_String("CMD55錯誤");

  27. return 0xfb;

  28. }

  29.   temp=SD_SPI_Write_CMD(pcmd);//發送ACMD41

  30.   time++;

  31.   if(time==TRY_TIME)

  32.   {

  33. SD_CS=1; //關閉片選

  34.    Send_String("初始化失敗");

  35. return(0x01);//ACMD41寫入失敗

  36.   }

  37. }while(temp!=0x00);  //當返回數據時0x00的時候,說明初始化成功

  38. SPI_Speed_Slow=0; //初始化完畢,將SPI_Speed_Slow設置為0,為了提高以后的數據傳輸速度

  39. SD_CS=1;  //關閉片選

  40. SD_SPI_Write_Byte(0xff); //按照SD卡的操作時序在這里補8個時鐘

  41. return(0); //返回0,說明初始化操作成功

  42. }
復制代碼
(4)寫一個扇區
  1. /*********************************

  2. * @函數名:SD_SPI_Write_Sector

  3. * @描  述:寫一扇區的數據

  4. * @參  數:addr:扇區地址 *buffer:指向數據緩沖區的指針

  5. * @返回值:成功 0x00  失敗 0x01

  6. *********************************/

  7. uchar SD_SPI_Write_Sector(uchar *buffer,ulong addr)        //向SD卡中的指定地址的扇區寫入512個字節,使用CMD24(命令24)

  8. {  

  9. uchar temp,time;

  10. uint i;

  11. uchar pcmd[] = {0x58,0x00,0x00,0x00,0x00,0xff}; //向SD卡中單個塊(512字節,一個扇區)寫入數據,用CMD24

  12. addr<<=9; //addr = addr * 512        將塊地址(扇區地址)轉為字節地址 [這里就限制了SD卡的最大容量為4G]

  13. pcmd[1]=((addr&0xff000000)>>24); //將字節地址寫入到CMD24字節序列中

  14. pcmd[2]=((addr&0x00ff0000)>>16);

  15. pcmd[3]=((addr&0x0000ff00)>>8);

  16. SD_CS=0;//打開SD卡片選

  17.     time=0;

  18. do

  19. {  

  20.   temp=SD_SPI_Write_CMD(pcmd);//發送ACMD41

  21.   time++;

  22.   if(time==TRY_TIME)

  23.   {

  24.     SD_CS=1; //關閉片選

  25.    return temp ; //命令寫入失敗

  26.   }

  27. }while(temp!=0);  //寫入地址,返回值是0x00正確

  28. for(i=0;i<100;i++) //這里要插入若干時鐘信號

  29. {

  30.   SD_SPI_Write_Byte(0xff);

  31. }
  32. SD_SPI_Write_Byte(0xfe);//寫入開始字節 0xfe,后面就是要寫入的512個字節的數據

  33. for(i=0;i<512;i++) //將緩沖區中要寫入的512個字節寫入SD卡

  34. {

  35.   SD_SPI_Write_Byte(buffer[i]); //寫入512個字節的數據

  36. }

  37. SD_SPI_Write_Byte(0xff);

  38. SD_SPI_Write_Byte(0xff); //兩個字節的CRC校驗碼,不用關心

  39. temp=SD_SPI_Read_Byte();   //讀取返回值

  40. if((temp&0x1F)!=0x05) //如果返回值是 XXX00101說明數據已經被SD卡接受了

  41. {

  42.   SD_CS=1;

  43.   return(0x01); //寫塊數據失敗

  44. }
  45. while(SD_SPI_Read_Byte()!=0xff);//等到SD卡不忙(數據被接受以后,

  46. //  SD卡要將這些數據寫入到自身的FLASH中,需要一個時間)

  47. //忙時,讀回來的值為0x00,不忙時,為0xff

  48. SD_CS=1; //關閉片選

  49. SD_SPI_Write_Byte(0xff);//按照SD卡的操作時序在這里補8個時鐘

  50. return(0);         //返回0,說明寫扇區操作成功

  51. }
復制代碼
5)讀一個扇區
  1. /*********************************

  2. * @函數名:SD_SPI_Read_Sector

  3. * @描  述:讀一扇區的數據

  4. * @參  數:addr:扇區地址 *buffer:指向數據緩沖區的指針

  5. * @返回值:成功 0x00  失敗 0x01

  6. *********************************/

  7. uchar SD_SPI_Read_Sector(uchar *buffer,ulong addr)//從SD卡的指定扇區中讀出512個字節,使用CMD17(17號命令)
  8. {
  9. uint j;
  10. uchar time,temp;

  11. uchar pcmd[]={0x51,0x00,0x00,0x00,0x00,0xff}; //CMD17的字節序列
  12. addr<<=9; //addr=addr*512           將塊地址(扇區地址)轉為字節地址

  13. pcmd[1]=((addr&0xff000000)>>24);//將字節地址寫入到CMD17字節序列中

  14. pcmd[2]=((addr&0x00FF0000)>>16);

  15. pcmd[3]=((addr&0x0000FF00)>>8);

  16. SD_CS=0;//打開片選

  17. time=0;

  18. do

  19. {  

  20.     temp=SD_SPI_Write_CMD(pcmd); //寫入CMD17

  21.     time++;

  22.   if(time==TRY_TIME)
  23.   {
復制代碼
注意:
1.2GB以內的SD卡(標準卡)和2GB以上的SD卡(大容量卡在地址訪問形式上不一樣。
2.對某一塊要進行寫操作時最好先執行擦除命令,這樣寫入的速度就能大大的提高。
3.對標準卡進行字節操作時,起始和終止必須在一個物理扇區內。不管是標準卡還是大容量卡一個讀寫讀寫命令只能對一個快進行操作,不允許跨物理層地址操作。

全部資料51hei下載地址:
SD卡.zip (1.86 MB, 下載次數: 91)

評分

參與人數 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎勵!

查看全部評分

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

使用道具 舉報

沙發
ID:79094 發表于 2024-7-5 00:24 來自手機 | 只看該作者
厲害高手  幫了大忙了
回復

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 日日夜夜操天天干 | 黄色一级大片在线免费看产 | 国产精品成人在线 | 国产精品久久久久久福利一牛影视 | 五月天综合网 | 午夜精品久久久久久久久久久久 | 日韩一级电影免费观看 | www.五月天婷婷.com | 欧美激情精品久久久久久变态 | 国产乱码精品一区二区三区忘忧草 | 亚洲精品99999 | 国产精品一区二区av | 毛片的网址 | 毛片区| 亚洲在线免费观看 | 一区在线视频 | 久久亚洲视频网 | 这里只有精品999 | 一区二区三区成人 | 一区二区中文字幕 | 日韩在线不卡 | 精品国产视频 | 国产农村妇女毛片精品久久麻豆 | av福利网| 欧美激情精品久久久久 | 国产精品视频久久久久 | 国产精品福利在线观看 | 精品国产精品国产偷麻豆 | 国产又爽又黄的视频 | 日本精品网站 | 久久精品99国产精品日本 | 中文字幕日韩一区二区 | 色就干| 久久99网 | 九色 在线| 真人女人一级毛片免费播放 | 成年免费在线观看 | 成人二区三区 | 天天色天天 | 一色桃子av一区二区 | 欧美男人天堂 |