打印

51读写SD卡(带SD卡资料。更新:FAT文件系统原理手册)

[复制链接]
45879|225
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Mindor|  楼主 | 2010-1-22 18:58 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 Mindor 于 2010-2-26 18:49 编辑

这几天老师让我折腾一下SDSPI模式读写(暂时无FAT文件系统,FAT对我这个新手比较耗时),下个学期来研究下FAT文件系统,到时候有机会也跟大家交流交流~
因为51单片机无SPI总线接口,所以用软件模拟SPI总线。重点和难点主要在于SDSPI模式的初始化,读写SD卡。
哦对了,我用的是MMC卡,不过MMC卡是向上兼容的,所以SD卡手册页基本适用于MMC卡。
下面我把调试过程中遇到的一些问题以及主要代码,流程图贴出来供交流,欢迎指点。
SD卡和单片机间的电平转换我是用三极管9013做开关,不过我们需要一个5V(用于单片机)和3.3V(用于SD卡)的电源哦~到网上搜下就有了,我就不多说了。


补发几个比较主要的手册:

SD卡接口描述 .pdf

1.54 MB

SD卡使用手册.pdf

1.12 MB

SPI总线协议.pdf

1.48 MB

FAT文件系统原理.pdf

1.18 MB

相关帖子

沙发
Mindor|  楼主 | 2010-1-22 18:59 | 只看该作者
本帖最后由 Mindor 于 2010-1-22 19:04 编辑

1SDSPI模式初始化:

相关代码:
void sd_init()
{

uchar i;


Flag_init = 1;



for(i=10;i>0;i--)//
发送80个同步时钟


{


sd_wr_byte(0xff);//
SD卡上电期间需要往SD卡发送连续的高电平‘1


}



SD_CS=0;//
将片选信号线拉低,使SD卡进入SPI总线模式



sd_wr_cmd(CMD0);//
发送命令CMD0,复位SD


sd_wr_cmd(CMD1);//
发送命令CMD1,激活该卡的初始化处理



Flag_init = 0;



CMD16[3] = 0x02;//
CMD16命令设定读写数据块长度,每个数据块设定为512Byte


sd_wr_cmd(CMD16);

}

初始化.jpg (67.18 KB )

初始化.jpg

使用特权

评论回复
板凳
Mindor|  楼主 | 2010-1-22 18:59 | 只看该作者
本帖最后由 Mindor 于 2010-1-22 19:05 编辑

2SD卡写数据块:

相关代码:
void sd_wr_oneblock(uchar *dat)
{

uchar resp,i;


uint j;

         

//CMD24[4] = (K << 9);//
设定写入数据块时的地址,地址为扇区*数据块长度(512


unsigned long int addr;


//
设定写入数据地址


addr = K << 9;//
将扇区编号转化为字节地址


CMD24[1] = (addr & 0xFF000000) >> 24;


CMD24[2] = (addr & 0x00FF0000) >> 16;


CMD24[3] = (addr & 0x0000FF00) >> 8;


CMD24[4] =
addr & 0x000000FF;



sd_wr_cmd(CMD24);//
写一个数据块命令


sd_wr_byte(0xfe);//
发送起始数据标志0xFE



//
写入一个数据块,512个字节


i = 0;


do


{


i++;


for(j=0;j<512;j++)


{


sd_wr_byte(*(dat + j + (K - 1)));


}

                  

//
发送16CRC校验码


sd_wr_byte(0xff);


sd_wr_byte(0xff);

                  

resp = sd_rd_byte();//
读取写入数据块后返回的响应数据

                  

while(sd_rd_byte() != 0xff);//
等待写入数据后空闲      

                                    

}


while((resp & 0x1f) != 0x05 && i < 200);//
最多将循环发送100

}

写数据块.jpg (39.13 KB )

写数据块.jpg

使用特权

评论回复
地板
Mindor|  楼主 | 2010-1-22 19:00 | 只看该作者
本帖最后由 Mindor 于 2010-1-22 19:05 编辑

3SD卡读数据块:

相关代码:
void
sd_rd_oneblock(uchar *dat)

{

uchar i,temp;


uint j;


uchar resp;//
如果读取数据错误,将发送一个字节的错误标记

         

//CMD17[4] = (K << 9);//
设定写入数据块时的地址,地址为扇区*数据块长度(512


unsigned long int addr;


//
设定写入数据地址


addr = K << 9;//
将扇区编号转化为字节地址


CMD17[1] = (addr & 0xFF000000) >> 24;


CMD17[2] = (addr & 0x00FF0000) >> 16;


CMD17[3] = (addr & 0x0000FF00) >> 8;


CMD17[4] =
addr & 0x000000FF;



sd_wr_cmd(CMD17);//
写一个数据块命令


sd_wr_byte(0xfe);//
发送起始数据标志0xFE

         

//
读出一个数据块,512个字节


i = 0;


do


{


i++;


for(j=0;j<512;j++)


{


temp = sd_rd_byte();


dat[(K - 1) * 512 + j] = temp;


}

                  

//
接收16CRC校验码


sd_rd_byte();


sd_rd_byte();



resp = sd_rd_byte();//
如果读取数据错误,将发送一个字节的错误标记


}


while(resp != 0x00 && i < 200);//
最多将循环发送100   

}

读数据块.jpg (45.32 KB )

读数据块.jpg

使用特权

评论回复
5
Mindor|  楼主 | 2010-1-22 19:00 | 只看该作者
本帖最后由 Mindor 于 2010-1-22 19:06 编辑

一些调试总结:
1、写完代码开始硬件调试的时候,发现在keil上调试仿真的时候控制开发板上的LED等闪烁是没问题的,可是下到单片机上调试却发现很不符合逻辑,该闪的时候不闪,不该闪的时候闪个不停。后来发现原来是我定义一个缓冲区(用来接收从SD卡读取的数据)定义到data去了,改成xdata之后又行了。不过不明白为什么,有人知道吗?

2SD卡手册中提示:After power up, the host starts the clock and sends the initializing sequence on the CMD line. This sequence is a contiguous stream of logical ‘1’s. The sequence length is the maximum of 1msec, 74 clocks or the supply-ramp-uptime; the additional 10 clocks (over the 64 clocks after what the card should be ready for communication) is provided to eliminate power-up synchronization problems.
即:在SD卡上电期间需要往SD卡发送连续的高电平‘1

3、写完一个命令后延时8个时钟,以确保和SD卡时钟同步。

4、写完一个数据块时返回的数据为 0X×××00101,调试过程中发现收到的数据是0xE5,但数据依然可以写进去,搞了半天,还以为数据手册有误呢~(要有怀疑精神嘛^_^),其实0xE5也是没错的。

……

先说这几点吧!调试过程中没注意记下问题,下次会注意点哈~如果有人也在做这个有不明白的一起交流,都是新手,怕啥?哈哈~

使用特权

评论回复
6
yxwsz| | 2010-1-22 22:51 | 只看该作者
sourceforge上有个embedded file system library(efsl)开源工程,就是使用SPI口读SD的,支持FAT16, FAT32文件系统,可以直接拿来使用。

使用特权

评论回复
7
古道热肠| | 2010-1-22 23:59 | 只看该作者
呵呵,楼主的这几张流程图画得漂亮.赞一个.

使用特权

评论回复
8
Mindor|  楼主 | 2010-1-23 07:37 | 只看该作者
6# yxwsz
我之所以选择做技术,是因为做技术的过程中能满足我的好奇心,同时又有成就感~做的是我喜欢做的事,用别人的多没意思,上面的代码几乎都是我自己看资料折腾出来的~这样才能学到东西嘛~呵呵~

使用特权

评论回复
9
Mindor|  楼主 | 2010-1-23 07:38 | 只看该作者
7# 古道热肠
呵呵~多谢古道热肠~我会继续努力的~

使用特权

评论回复
10
864| | 2010-1-23 08:37 | 只看该作者
顶了

使用特权

评论回复
11
sytu_chyq| | 2010-1-23 08:47 | 只看该作者
留个记号先。。

使用特权

评论回复
12
kk2614755| | 2010-1-23 09:23 | 只看该作者
发你手上的一些资料来看看啊

使用特权

评论回复
13
Mindor|  楼主 | 2010-1-23 09:31 | 只看该作者
12# kk2614755
本来想传的,不过我在学校上的网,没多少流量了~⊙﹏⊙
那些都是网上可以找到的哦。。。不知道你要什么资料?如果文件不大的话我可以传上来哈~

使用特权

评论回复
14
Mindor|  楼主 | 2010-1-23 10:12 | 只看该作者
我把几个主要的手册补发上去咯~~~需要的下吧下吧~~

使用特权

评论回复
15
gqhonesty| | 2010-1-23 10:14 | 只看该作者
kankan

使用特权

评论回复
16
IC_99| | 2010-1-23 12:29 | 只看该作者
好东西

使用特权

评论回复
17
awmc_m| | 2010-1-23 14:26 | 只看该作者
我都是照搬照抄,只读懂未深究。lz的钻研精神值得鼓励和学习!

使用特权

评论回复
18
Mindor|  楼主 | 2010-1-23 14:51 | 只看该作者
17# awmc_m
谢谢你的肯定~呵呵~

使用特权

评论回复
19
efen| | 2010-1-23 15:18 | 只看该作者
请问LZ,SD卡的扇区的大小是512byte吗?
SD卡扇区与块地址要怎样区分了?块设置默认为512byte,那块与扇区地址重合么?
盾资料也看不懂了..

使用特权

评论回复
20
Mindor|  楼主 | 2010-1-23 16:48 | 只看该作者
19# efen
SD卡的扇区可以自己用命令设定,但是一般取512字节为一扇区。
至于第二个问题,能不能说清楚一点?不是很明白你的意思。。。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

36

主题

413

帖子

1

粉丝