呵呵!今天晚上真是走运啊,我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,加油啊,离文件系统还差的远啊!
|