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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 4496|回復(fù): 1
收起左側(cè)

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

  [復(fù)制鏈接]
ID:535176 發(fā)表于 2020-2-14 14:49 | 顯示全部樓層 |閱讀模式
SD卡
SD 卡(Seecure Digital Memory Cardl)是一種基于 Flash 的新一代存儲器,具有體積小、容量大、數(shù)據(jù)傳輸快、移動靈活、安全性能好等優(yōu)點,是許多便攜式電子儀器理想的外部存儲介質(zhì)
圖片1.png
圖片2.png
SD 卡支持兩種總線方式:SD 方式與 SPI 方式。其中 SD 方式采用 6 線制,使用 CLK、 CMD、DAT0~DAT3 進行數(shù)據(jù)通信。而 SPI 方式采用 4 線制,使用 CS、CLK、DataIn、DataOut 進行數(shù)據(jù)通信。SD 方式時的數(shù)據(jù)傳輸速度與 SPI 方式要快,采用單片機對 SD 卡進行讀寫時一般都采用 SPI 模式。采用不同的初始化方式可以使 SD 卡工作于 SD 方式或 SPI 方式。

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

向SD卡寫入一個CMD或者ACMD指令的過程是這樣的:
1.首先使CS為低電平,SD卡使能;其次在SD卡的Din寫入指令;寫入指令后還要附加8個填充時鐘,是SD卡完成內(nèi)部操作;之后在SD卡的Dout上接受回應(yīng);回應(yīng)接受完畢使CS為低電平,再附加8個填充時鐘。
2.在SD卡的Din沒有數(shù)據(jù)寫入時,應(yīng)使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屬于附加命令,發(fā)送起來要麻煩一些,必須提前通知SD卡下一條要發(fā)送的命令為ACMD,這個通知就是CMD55,它的4字節(jié)參數(shù)都為0即可
SD卡的命令格式:
每一個命令的長度都是固定的6個字節(jié),前1個字節(jié)的值=命令號+0x40;中間4個字節(jié)為參數(shù),不同的命令參數(shù)格式都不相同,但參數(shù)最多為4個字節(jié);最后1個字節(jié)是CRC校驗碼和1位固定結(jié)束位‘1’。這里需要說明一下0x40的意思,任何命令都有一個固定的起始格式,即先0后1,這是固定的命令起始標志,前兩個字節(jié)的二進制碼就是:01xx xxxx 
SD 卡所有的命令都是由 48 個數(shù)據(jù)位組成的,其結(jié)構(gòu)如表 2 所示。
圖片3.png
圖片4.png
需要特殊說明的是CRC的問題,這是一種檢驗錯誤的方法,具體問題度娘說的還算明白,在SPI模式中,CRC校驗?zāi)J是關(guān)閉的,也就是說這7位必須要發(fā),但是SD卡會在讀到CRC以后自動忽略它,所以全部發(fā)1就可以。例外的是,CMD0,CMD8這兩個命令發(fā)送的時候SD卡還沒有進入SPI模式,也就是說CRC校驗在這個時候還是啟用狀態(tài),因此這兩個命令的CRC效驗碼必須要寫正確,SD卡才會執(zhí)行命令,否在在返回值R1中就會有相應(yīng)的錯誤標志位提示開發(fā)人員CRC校驗碼錯誤。     
圖片5.png
圖片6.png
圖片7.png
圖片8.png
圖片9.png

SD卡的命令代碼:
1)復(fù)位
圖片10.png

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

  2. * @函數(shù)名:SD_SPI_Rest

  3. * @描  述:SD卡復(fù)位

  4. * @參  數(shù):無

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

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

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

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

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

  12. SD_CS=1;  //關(guān)閉片選

  13. for(i=0;i<0x0f;i++) //復(fù)位時,首先要發(fā)送最少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);//連續(xù)寫入CMD0

  22.      time++;

  23.   if(time==TRY_TIME)

  24.   {

  25.   SD_CS=1; //關(guān)閉片選

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

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

  28.   }

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

  30. SD_CS=1; //關(guān)閉片選

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

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

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

  2. * @函數(shù)名:SD_SPI_Version

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

  4. * @參  數(shù):無

  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; //關(guān)閉片選

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

  20.    return(0x01);

  21.   }

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

  23.   SD_CS=1; //關(guān)閉片選

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

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

  26. }
復(fù)制代碼
3)初始化
圖片11.png
  1. /*********************************

  2. * @函數(shù)名:SD_SPI_Init

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

  4. * @參  數(shù):無

  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的字節(jié)序列

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

  12. /*調(diào)用這兩個函數(shù)*/

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

  14. SD_SPI_Version();//版本號

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

  16. time=0;

  17. do

  18. {

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

  20. SD_SPI_Read_Byte();

  21. SD_SPI_Read_Byte();

  22. SD_SPI_Read_Byte();

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

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

  25. {

  26.   Send_String("CMD55錯誤");

  27. return 0xfb;

  28. }

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

  30.   time++;

  31.   if(time==TRY_TIME)

  32.   {

  33. SD_CS=1; //關(guān)閉片選

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

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

  36.   }

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

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

  39. SD_CS=1;  //關(guān)閉片選

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

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

  42. }
復(fù)制代碼
(4)寫一個扇區(qū)
圖片12.png
  1. /*********************************

  2. * @函數(shù)名:SD_SPI_Write_Sector

  3. * @描  述:寫一扇區(qū)的數(shù)據(jù)

  4. * @參  數(shù):addr:扇區(qū)地址 *buffer:指向數(shù)據(jù)緩沖區(qū)的指針

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

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

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

  8. {  

  9. uchar temp,time;

  10. uint i;

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

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

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

  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);//發(fā)送ACMD41

  21.   time++;

  22.   if(time==TRY_TIME)

  23.   {

  24.     SD_CS=1; //關(guān)閉片選

  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);//寫入開始字節(jié) 0xfe,后面就是要寫入的512個字節(jié)的數(shù)據(jù)

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

  34. {

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

  36. }

  37. SD_SPI_Write_Byte(0xff);

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

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

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

  41. {

  42.   SD_CS=1;

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

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

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

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

  48. SD_CS=1; //關(guān)閉片選

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

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

  51. }
復(fù)制代碼
5)讀一個扇區(qū)
圖片13.png
  1. /*********************************

  2. * @函數(shù)名:SD_SPI_Read_Sector

  3. * @描  述:讀一扇區(qū)的數(shù)據(jù)

  4. * @參  數(shù):addr:扇區(qū)地址 *buffer:指向數(shù)據(jù)緩沖區(qū)的指針

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

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

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

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

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

  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.   {
復(fù)制代碼
注意:
1.2GB以內(nèi)的SD卡(標準卡)和2GB以上的SD卡(大容量卡在地址訪問形式上不一樣。
2.對某一塊要進行寫操作時最好先執(zhí)行擦除命令,這樣寫入的速度就能大大的提高。
3.對標準卡進行字節(jié)操作時,起始和終止必須在一個物理扇區(qū)內(nèi)。不管是標準卡還是大容量卡一個讀寫讀寫命令只能對一個快進行操作,不允許跨物理層地址操作。

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

評分

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

查看全部評分

回復(fù)

使用道具 舉報

ID:79094 發(fā)表于 2024-7-5 00:24 來自觸屏版 | 顯示全部樓層
厲害高手  幫了大忙了
回復(fù)

使用道具 舉報

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

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

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

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 亚洲一区二区久久 | 国产一区精品视频 | 亚洲日本一区二区 | 色天天综合 | 欧美久久久久久久久 | 黄色网址免费看 | 成人爽a毛片一区二区免费 亚洲午夜在线观看 | 国产精品福利在线观看 | av网在线观看| 日本黄a三级三级三级 | 成人三级视频在线观看 | 成人做爰www看视频软件 | 欧美一区二区三区在线观看 | 黄色三级视频 | 日本不卡视频 | av网站免费看| 国产一区视频在线 | 日韩欧美在线观看视频 | 中文字幕一区二区在线播放 | 91在线网站 | 亚洲天堂男人 | 成人9ⅰ免费影视网站 | 日韩三级一区 | 日韩精品中文字幕在线观看 | 精品久久久久久久久久久久久久久久 | 91精品久久久久久久久 | 黄色网在线 | 亚洲理论片 | 一区二区三区久久久 | 精品一区二区三区三区 | 日本免费一级片 | 国产成人在线视频 | 亚洲精品成人 | 一区二区三区免费在线观看 | 香蕉视频在线播放 | 亚洲最大黄色 | 九九精品国产 | 国产色视频一区二区三区qq号 | 午夜成人免费视频 | 一区二区三区视频在线 | 日韩av免费在线播放 |