akaxiang
驱动牛犊
驱动牛犊
  • 注册日期2010-06-13
  • 最后登录2011-07-27
  • 粉丝0
  • 关注0
  • 积分29分
  • 威望251点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:2280回复:0

小弟在玩单片机读写SD的一些心得

楼主#
更多 发布于:2010-11-11 19:58
        我用的是51单片机模拟spi总线来读写SD卡的,呵呵,其实51速度很是落后啦,即使是增强型的速度也就那吧,不说这个,谁让他用的多呢(连68013都是增强型51核的)。 在用51读写SD卡的实验过程中,我通过不断地优化代码也使读写速度有所提高。
        其实速度的提高关键在于SD读写字节的代码优化,下面是我写的几个代码:
函数名:char SD_Byte_read(void);

功能:模拟spi读SD卡的一个字节。

涉及定义:SD_IN(SD卡的数据写入引脚),SD_OUT(SD卡的数据输出引脚),SD_CLK都是IO口的一个位定义,
如在8051中,可定义sbit SD_IN=P0^0:其它的类似。

代码1(C语言版):
char SD_Byte_read(void)

{

uchar i,out_data;

SD_IN=1;

out_data=0;

for(i=0;i<8;i++)
{
SD_CLK=0;
out_data<<=1; //循环移位
SD_CLK=1;
If(SD_OUT)
out_data|=0x01;//置位最低位
}
return out_data;
}

代码2(C语言版):
uchar bdata out_data; //定义即可位寻址又可字节寻址的变量
sbit out_data0=out_data^0; //定义out_data个bit位
sbit out_data1=out_data^1;
sbit out_data2=out_data^2;
sbit out_data3=out_data^3;
sbit out_data4=out_data^4;
sbit out_data5=out_data^5;
sbit out_data6=out_data^6;
sbit out_data7=out_data^7;

char SD_Byte_read(void)
{
SD_IN=1;
SD_CLK=0;
SD_CLK=1;
sbit out_data7=out_data^7;
SD_CLK=0;
SD_CLK=1;
sbit out_data6=out_data^6;
SD_CLK=0;
SD_CLK=1;
sbit out_data5=out_data^5;
SD_CLK=0;
SD_CLK=1;
sbit out_data4=out_data^4;
SD_CLK=0;
SD_CLK=1;
sbit out_data3=out_data^3;
SD_CLK=0;
SD_CLK=1;
sbit out_data2=out_data^2;
SD_CLK=0;
SD_CLK=1;
sbit out_data1=out_data^1;
SD_CLK=0;
SD_CLK=1;
sbit out_data0=out_data^0;

return out_data;
}

代码3(C语言中嵌套汇编):
char SD_Byte_read(void)
{
#pragma asm

SETB SD_IN

CLR SD_CLK
SETB SD_CLK
MOV C,SD_OUT
RRC A

CLR SD_CLK
SETB SD_CLK
MOV C,SD_OUT
RRC A

CLR SD_CLK
SETB SD_CLK
MOV C,SD_OUT
RRC A

CLR SD_CLK
SETB SD_CLK
MOV C,SD_OUT
RRC A

CLR SD_CLK
SETB SD_CLK
MOV C,SD_OUT
RRC A

CLR SD_CLK
SETB SD_CLK
MOV C,SD_OUT
RRC A

CLR SD_CLK
SETB SD_CLK
MOV C,SD_OUT
RRC A

CLR SD_CLK
SETB SD_CLK
MOV C,SD_OUT
RRC A

#pragma endasm


return A;

}

以上三段代码完成同一功能,但代码却各不相同。

从代码的简洁性来说,第一段代码是最简洁的,代码功能清楚明了,占用内存小,但是他是最优代码吗?
从代码占用内存量上来说,第一个是最好的(当然,如果把上述代码用汇编的循环语句形式写出将是最省空间的,但汇编的不好掌握以及灵活性差,移植性差等缺点是很多人选C的直接原因,我也是有这个思想的,但最近写程序让我打消了对汇编的轻视,这也是我写这篇文章的原因)。

但是,我们常常需要提高代码的功能执行速度(尤其是在时钟频率相对较低的微处理器,如8051中),而不看重代码的内存占用。可以看出,要是论代码执行速度,第一段代码却是最差的(尤其是在反汇编后看的更明白,大家可在Keil C中看看反汇编后的代码),占用指令周期是最多的,也就是代码冗余度是最大的。下面从代码占用指令周期数来考虑这些代码,我们看:

首先,第二,第三段代码都省去循环语句,以节约时间。
其次,第二段代码表面上看上去和第三段占用时间应该一样,但其实不然。
先看看第二点代码的反汇编(大致是这样的,用的是Keil C51编译器):
SETB SD_IN

CLR SD_CLK
SETB SD_CLK
MOV C,SD_OUT
MOV C,out_data0
..........
..........
..........
CLR SD_CLK
SETB SD_CLK
MOV C,SD_OUT
MOV C,out_data7
..........
..........
..........

可看出和自己编的代码的不同之处是

MOV C,out_data0 ;反汇编

RRC A ;自己编的

学习过单片机(8051核的)指令的就看出这其中的不同了,

MOV C,out_data0 ;占用两个指令周期

RRC A ;占用一个指令周期

至此,我们看出了汇编的强悍之处,进一步把这段代码(我就是用这段代码来读写SD卡的,几个代码段我都试验了)执行512次(对SD卡一次常读写512字节)或更长,就会感到明显的时间差距(这对低速微处理器提高SD卡读写速度是很有意义的)。

综上,

1.C语言用起来很方便,这点是大家公认的(甚至有些人鄙视汇编,说它过时了)

2.但是汇编是效率最高的(一般情况下,别抬杠呀)。

3.C与汇编结合是最好的,二者优势相结合,很牛。

4.想提高读或写的速度,那读写代码要分开写。

最后,小弟还想说的是在单片机上使用SD卡时并不一定要懂FAT16或FAT32,他们只是一种协议,让PC机能读SD卡的协议,去掉协议单片机照样可以存储数据到SD中,只不过这时电脑就不认SD卡了而已(用WinHex好像还可以读)。
还有,你若有空,完全可以自己定义一个自己的文件系统,然后接上USB接口,如68013,然后再写一个上位机然见照样可以读写你自己的文件系统里的文件。呵呵,一切都是协议,对上就行。



快乐就好
游客

返回顶部