呵呵!今天晚上真是走運啊,我12月8日開始的做SD讀實驗,到今天晚上11:00才做出來啊,其中寫片115次,變過四次程序,連著三晚上沒睡好覺,兩天偷偷的沒去上班在宿舍做實驗,終于搞定讀邏輯0扇區了!我算是受夠了,但是這幾天每天晚上都在找資料,請老師,可是真是那句話,靠誰也不如靠自己,別人是不了解你的實際情況的,在這里我真的很感謝網絡,有了它,我在千千萬萬的資料中找到了最有用的幾分,然我得意找到鑰匙。
接下來說下SD卡(microsd)讀DBR:
SD卡作為一種存儲設備早在應用了,但是關于SD卡我還是在做完12864顯示以后才發現,光顯示圖片有啥意思?不如來點動畫,呵呵殊不知存儲空間收到限制了,一幅BMP圖片要1KB的存儲空間,我的存儲容量是8K,呵呵,很顯然是不行的,有沒有一種大容量小體積便攜,便于PC操作的存儲設備那?指向了SD卡,一代的可以最大存儲4GB,這是相當海量的,也是很理想的,決定后看了關于FAT32的文件系統,感覺真是很難,不過,也大抵能找到根目錄,FAT表和數據區,接下來是做實驗搭模塊,開始看了關于SD卡的資料,網上資料很多,我看了大多泛泛而談,沒做過的,即使看了還是無處下手,我經驗如下:1.首先要了解SPI通信,因為他是基礎,要靠他來完成數據交換,其實SPI也沒什么,個人感覺比異步簡單老鼻子了,關鍵是SD卡中數據發送時上升沿,數據接收是下降沿,記好了,期間一定要保證數據的穩定,且在寫時MISO線要保持高電平,讀時MOSI要保持高電平,2,寫命令是公六字節,最先發送的是指令代碼(高位先發)然后是參數,對于參數是地址的則按地址字節最高字節在前,以此類推,例如:ADD=0x01020304,那么先要發送01,在發02,在發03在發04;最后發CRC效驗,當然這里默認為FF,不用管它;3,先調復位SD卡,然后再調初始化,在調讀,這里注意,當你初始化復位時,時鐘一定要慢,當要讀扇區是一定要提高時鐘頻率,要不非得操蛋不可,當調好復位初始化后,先做個試驗,讀取0扇區的值,當然這里指的是讀物理扇區,如果讀到扇區的最后兩個字節是55AA,那恭喜你,你的程序沒問題了,但是FAT文件系統要的是邏輯0扇區的BPB(系統引導記錄),所以你要用軟件打開磁盤找到PHYSICALL SECTOR NO:和LOGICAL SECTOR NO:即物理扇區和邏輯扇區,例如我的是253 0:表示什么呢?表示邏輯扇區0在物理253扇區,所以找到253扇區就找到邏輯0扇區了,那怎樣找?又要注意了,SD卡的讀操作的尋址是按字節一扇區來的,所以要吧扇區轉換成字節,一扇區是512字節,那么邏輯0扇區的物理地址為253*512=129536;吧這個值寫入SD卡然后讀出來就是邏輯0扇區的值;一個也不搭茬;找到了邏輯0扇區就找到了進入FAT32文件系統的第一步,也是一把非常重要的鑰匙,但是離最終的文件尋址還差的遠,要是沒這一步,文件尋址是不可能的!還證明了,WINheBUbub不能顯示物理0扇區,只能顯示邏輯0扇區,嘻嘻!
下面是源碼、、、我用的是手機內存卡1GB
- #include <reg52.h>
- #define uchar unsigned char
- #define uint unsigned int
- sbit p1_7=P1^7;
- sbit CS=P2^0; //片選信號(低電平有效)
- sbit DATEIN =P2^1;//主-從數據輸入
- sbit SCLK=P2^2;//時鐘信號
- sbit DATEOUT=P2^3;//從-主數據輸出
- uint btime;
- uchar c;
- sbit led4=P1^0;
- sbit led3=P1^1; //2010年12月14日與天津開發區
- sbit led2=P1^2;
- sbit led1=P1^3;
- uchar g=0,s=0,bw=0,q=0; //顯示單元 個位、十位、百位、千位
- uchar code tab1[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};//不帶小數點顯示0~9
- unsigned char bdata dat;
- sbit dat_0=dat^0;
- sbit dat_1=dat^1;
- sbit dat_2=dat^2;
- sbit dat_3=dat^3;
- sbit dat_4=dat^4;
- sbit dat_5=dat^5;
- sbit dat_6=dat^6;
- sbit dat_7=dat^7;
- bit is_init;//決定是否延時;
- uchar lpp;
- unsigned char fhz;//返回值
- uchar fhz_buff; //讀返回值中間量
- unsigned char xdata tab[512];
- void delay(uint time)
- { while(time)
- time--;
- }
- //**********************************************
- /*讀sd卡子程序,無返回值,有參函數,參數為要寫入DATEIN數據線的字節*/
- void write(unsigned char wr_)// 寫入一個字節SD卡
- {
- dat=wr_;
- DATEIN=dat_7;
-
- SCLK=0;
- if(is_init)delay(200);
- if(!is_init)delay(2);
- SCLK=1;
- if(is_init) delay(200);
- if(!is_init)delay(2);
-
- DATEIN=dat_6;
-
- SCLK=0;
- if(!is_init)delay(2);
- if(is_init)delay(200);
- SCLK=1;
- if(is_init) delay(200);
- if(!is_init)delay(2);
- DATEIN=dat_5;
-
- SCLK=0;
- if(is_init)delay(200);
- if(!is_init)delay(2);
- SCLK=1;
- if(is_init) delay(200);
- if(!is_init)delay(2);
- DATEIN=dat_4;
-
- SCLK=0;
- if(is_init)delay(200);
- if(!is_init)delay(2);
- SCLK=1;
- if(is_init) delay(200);
- if(!is_init)delay(2);
- DATEIN=dat_3;
-
- SCLK=0;
- if(is_init)delay(200);
- if(!is_init)delay(2);
- SCLK=1;
- if(is_init) delay(200);
- if(!is_init)delay(2);
- DATEIN=dat_2;
-
- SCLK=0;
- if(is_init)delay(200);
- if(!is_init)delay(2);
- SCLK=1;
- if(is_init) delay(200);
- if(!is_init)delay(2);
- DATEIN=dat_1;
-
- SCLK=0;
- if(is_init)delay(200);
- if(!is_init)delay(2);
- SCLK=1;
- if(is_init) delay(200);
- if(!is_init)delay(2);
- DATEIN=dat_0;
-
- SCLK=0;
- if(is_init)delay(200);
- if(!is_init)delay(2);
- SCLK=1;
- if(is_init) delay(200);
- if(!is_init)delay(2);
- }
- unsigned char read()// 讀取一個字節SD卡
- {
- DATEOUT=1;
- SCLK=1;
- if(is_init)delay(200);
- if(!is_init)delay(2);
- SCLK=0;
- if(is_init)delay(200);
- if(!is_init)delay(2);
- dat_7=DATEOUT;
- SCLK=1;
- if(is_init)delay(200);
- if(!is_init)delay(2);
- SCLK=0;
- if(is_init)delay(200);
- if(!is_init)delay(2);
- dat_6=DATEOUT;
- SCLK=1;
- if(is_init)delay(200);
- if(!is_init)delay(2);
- SCLK=0;
- if(is_init)delay(200);
- if(!is_init)delay(2);
- dat_5=DATEOUT;
- SCLK=1;
- if(is_init)delay(200);
- if(!is_init)delay(2);
- SCLK=0;
- if(is_init)delay(200);
- if(!is_init)delay(2);
- dat_4=DATEOUT;
- SCLK=1;
- if(is_init)delay(200);
- if(!is_init)delay(2);
- SCLK=0;
- if(is_init)delay(200);
- if(!is_init)delay(2);
- dat_3=DATEOUT;
- SCLK=1;
- if(is_init)delay(200);
- if(!is_init)delay(2);
- SCLK=0;
- if(is_init)delay(200);
- if(!is_init)delay(2);
- dat_2=DATEOUT;
- SCLK=1;
- if(is_init)delay(200);
- if(!is_init)delay(2);
- SCLK=0;
- if(is_init)delay(200);
- if(!is_init)delay(2);
- dat_1=DATEOUT;
- SCLK=1;
- if(is_init)delay(200);
- if(!is_init)delay(2);
- SCLK=0;
- if(is_init)delay(200);
- if(!is_init)delay(2);
- dat_0=DATEOUT;
- return (dat);
- }
- void restsd()//復位SD卡
- { uchar i;
- uchar pcmd[6]={0x40,0x00,0x00,0x00,0x00,0x95};
- is_init=1;
-
- CS=1;
- for(i=0;i<15;i++)
- {
- //120時鐘
- write(0xff);
- }
-
-
- CS=1;
- write(0xff);//據說是提高兼容性
- CS=0;//片選開
- write( pcmd[0]);
- write( pcmd[1]);
- write( pcmd[2]);
- write( pcmd[3]);
- write( pcmd[4]);
- write( pcmd[5]);
- fhz=read();
- for(;;)
- {
- fhz=read();
- if(fhz==0x01)break;
-
-
- }
-
- CS=1;
- write(0xff);
- }
-
- void initsd()//初始化
- {
- //
- uchar pcmd[6]={0x41,0x00,0x00,0x00,0x00,0xff};//
- //
-
- CS=1;
- write(0xff);//據說是提高兼容性
- CS=0;//片選開
- write( pcmd[0]);
- write( pcmd[1]);
- write( pcmd[2]);
- write( pcmd[3]);
- write( pcmd[4]);
- write( pcmd[5]);
-
-
- fhz=read();
- for(;;)
- {
- fhz=read();
- if(fhz==0x00)break;
-
-
- }
-
- CS=1;
- write(0xff);
-
-
-
- }
- void readsd()//讀SD卡物理扇區
- {
- uchar pcmd[6]={0x51,0x00,0x01,0xfa,0x00,0xff};//原來這里是高地址字節在前地地址在后啊201012月14日
- uint j,n;
-
- CS=1;
- write(0xff);//據說是提高兼容性
- CS=0;//片選開
- write( pcmd[0]);
- write( pcmd[1]);
- write( pcmd[2]);
- write( pcmd[3]);
- write( pcmd[4]);
- write( pcmd[5]);
- DATEOUT=1;
-
- for(;;)
- {
- fhz=read();
- if(fhz==0x00)break;
-
-
- }
- DATEOUT=1;
- for(;;)
- {
- fhz=read();
- if(fhz==0xfe)break;
-
-
- }
- DATEOUT=1;
- n=0;
- for(j=512;j;j--)
- {
- tab[n]=read();
- n++;
-
- }
- fhz=read();
- fhz=read();
- CS=1;
- write(0xff);
-
-
-
- }
- /*void writesd()
- {
- uchar pcmd[6]={0x58,0x00,0x00,0x00,0x00,0xff};
- uint j,k;
-
- CS=1;
- write(0xff);//據說是提高兼容性
- CS=0;//片選開
- write( pcmd[0]);
- write( pcmd[1]);
- write( pcmd[2]);
- write( pcmd[3]);
- write( pcmd[4]);
- write( pcmd[5]);
-
- DATEOUT=1;
- for(;;)
- {
- fhz=read();
- if(fhz==0x00)break;
-
-
- }
- DATEOUT=1;
- for(j=20;j;j--)
- {
- write(0xff);
-
-
- }
- write(0xfe);
- for(j=512;j;j--)
- { k=tab[j];
- write(k);
-
-
- }
- write(0xff);
- write(0xff);
- DATEOUT=1;
- for(;;)
- {
- fhz=read();
- if((fhz&0x0f)==0x05)break;
- }
-
-
- if(!DATEOUT);
- {
- write(0xff);
- }
- CS=1;
- write(0xff);
-
-
-
- }
- */
- void delay1(uint z) //延時程序
- {
- uint x,a,b;
- for (x=0;x<z;x++)
-
- {
- for(b=120;b>0;b--)
- {
- for(a=3;a>0;a--);
-
- }
- }
- }
- void display(uchar sd) //顯示程序
- {
- c=sd;
- g=(sd&0x0f);
-
- c=(c>>4);
- s=(c&0x0f);
- led1=0;
- P0=tab1[g]; //個
- delay1(2);
- led1=1;
- led2=0;
- P0=tab1[s];//十
- delay1(2);
- led2=1;
- led3=0;
- P0=tab1[0]; //百
- delay1(2);
- led3=1;
- led4=0;
- P0=tab1[0]; //千
- delay1(2);
- led4=1;
- }
- void delay2(void) //誤差 -0.00000000025us
- {
- unsigned char a,b,c,n;
- for(c=217;c>0;c--)
- for(b=225;b>0;b--)
- for(a=225;a>0;a--);
- for(n=10;n>0;n--);
- }
- void main()
- { uint ad;
- uchar v;
- is_init=1;
- restsd();
- initsd();
- is_init=0;//提高始終頻率
- p1_7=0;
- //writesd();
- readsd();//讀物理扇區
- p1_7=1;
- btime=65536;
- while(1)
- { btime=300;
- delay2();
-
- for(;;)
- {
- v=tab[ad];
- display(v);
- btime--;
- if(btime==0)break;
- }
- ad++;
- if(ad==512)ad=0;
- }
-
-
- }
復制代碼 以上程序僅在本人試驗模塊中通過,不知兼容咋樣!用LED顯示512字節的碼形!
2015年12月14日-12月8日歷時一星期終于讀出BPB,加油啊,離文件系統還差的遠啊!
|