//Return: 返回MMC/SD卡对命令响应的第2字节,作为命令成功判断
unsigned char Write_Command_SD(unsigned char cmd,unsigned long address) //**************************************************************************** {
unsigned char tmp; unsigned char retry=\
SD_Disable();
SPI_TransferByte(0xFF);
SD_Enable();
SPI_TransferByte(cmd); //将32位地址进行移位作为地址字节 SPI_TransferByte(address>>24); SPI_TransferByte(address>>16); SPI_TransferByte(address>>8); SPI_TransferByte(address); SPI_TransferByte(0xFF);
SPI_TransferByte(0xFF); do{
tmp = SPI_TransferByte(0xFF); //发送8个时钟接受最后一个字节 retry++;
}while((tmp==0xff)&&(retry<8)); return(tmp); }
//**************************************************************************** // 写一个扇区(512Byte) to MMC/SD-Card //如果写完成返回TRUE
unsigned char SD_write_sector(unsigned long addr,unsigned char *Buffer) //****************************************************************************
{
unsigned char temp; unsigned int i;
SPI_TransferByte(0xFF); //延迟8个时钟 SD_Enable(); //开片选
temp = Write_Command_MMC(MMC_WRITE_BLOCK,addr<<9); //发送写扇区命令 if(temp != 0x00) {
SD_Disable(); return(temp); }
SPI_TransferByte(0xFF); SPI_TransferByte(0xFF); SPI_TransferByte(0xFE);
for (i=0;i<512;i++) {
SPI_TransferByte(*Buffer++); //发送512字节数据 }
//CRC-Byte
SPI_TransferByte(0xFF); //Dummy CRC SPI_TransferByte(0xFF); //CRC Code
temp = SPI_TransferByte(0xFF); //读SD卡运行响应
if((temp & 0x1F)!=0x05) //如果最后4位为0101,为操作成功。否则为操作失败。 {
SD_Disable();
return(WRITE_BLOCK_ERROR); //返回错误 }
while (SPI_TransferByte(0xFF) != 0xFF);
SD_Disable();
return(TRUE); //返回成功 }
//**************************************************************************** // 读512字节 from MMC/SD-Card //如果成功返回TRUE
unsigned char SD_read_sector(unsigned long addr,unsigned char *Buffer) //**************************************************************************** {
unsigned char temp; unsigned int i; unsigned char data;
SPI_TransferByte(0xff);
MMC_Enable();
temp = Write_Command_SD(SD_READ_BLOCK,addr<<9);//发送读扇区命令
if(temp != 0x00) {
SD_Disable();
return(READ_BLOCK_ERROR); //返回错误号 }
while(SPI_TransferByte(0xff) != 0xfe);
for(i=0;i<512;i++) {
data = SPI_TransferByte(0xff); //存数据
*Buffer++=data;
}
SPI_TransferByte(0xff); //读CRC码 SPI_TransferByte(0xff); //读CRC码
SD_Disable();
return(TRUE); //返回成功 }
//************************************************************************** // 查找数据开始标志(预设DATASTART)根据实际需要删改 //************************************************************************** unsigned long SD_find(void) {
unsigned long tmp=%unsigned char data[512]; do {
SD_read_sector(tmp,data); //从0扇区开始查找 tmp++; //查找DATASTART
}while(!((data[0]=='D')&&(data[1]=='A')&&(data[2]=='T')&&(data[3]=='A')&&(data[4]=='S')&&(data[5]=='T')&&(data[6]=='A')&&(data[7]=='R')&&(data[8]=='T'))); return tmp; //返回开始标志的下一个扇区 }
//************************************************************************** // 发送一个字节
//************************************************************************** unsigned char SPI_TransferByte(unsigned char byte) {
SPDR = byte;
while (!(SPSR & 0x80)); //检测线路是否空闲 return SPDR; }
//************************************************************************** // 主程序例子
//************************************************************************** void main(void) {
unsigned long temp; unsigned char data[512];
unsigned char data2[512]={'sssssssssssssssssssssssss'}; unsigned char comm1[]={'\\r\\nhello world\\r\\n'}; unsigned char comm2[]={'\\r\\nSD_INIT OK\\r\\n'}; uart0_init();
SD_Port_Init(); //端口初始化 if(SD_Init()== 0x01)
{ //SD卡初始化,并读取返回值 putstr(comm2); }
temp=\//查找DATASTART数据开始标志,返回下一扇区地址 SD_read_sector(1001,data); //读取temp地址的512字节数据,512字节数据存入data数组
putstr(data);
SD_write_sector(temp,data2); //将data2数组512字节数据写入temp扇区 }
测试程序很简单,仅仅是做了一下读写SD卡的测试。
关于SD卡的几点注意事项。
1、无论我们愿意不愿意,SD卡每次读写数据的最小单位是1个扇区,即512个字节。 2、SD卡与单片机连接的 SPI总线不能太长,要尽量短。这样的好处是速度可以更快,也不容易出错。
3、虽然我们并不关心FAT文件表,但是我们仍然要关心SD卡的存储结构,如果我们不想使用PC机来读取保存在SD卡上的数据那我们就不用关心SD存储结构了。但,作为一个大容量的可移动存储设备,不能用PC机来读取是个很大的遗憾,我解决这个遗憾的方法如下: 3-1、因为我不了解FAT复杂的结构,所以我做的程序没法去按照FAT表的各项功能来进行创建文件、删除文件、创建目录等等操作。
3-2、虽然我们的单片机不能创建文件,但是PC机是可以创建文件的啊!所以我使用PC机将SD卡格式化,之后在SD卡上创建一个大文件,比如我的128M的SD卡上我建立了一个100M的文件。这里需要注意一下,一般使用windows创建文件的功能时是没有办法指定创建文件的
大小的,空文件就是0个字节的长度,而我们是需要一个固定长度的文件的,所以我用VC编写了一个小软件,这个软件可以为我创建一个100M长度的空文件,记住,这点很重要:一个固定长度的空文件
3-3、虽然我们建立了个文件在SD卡上,可是我们因为不去了解FAT表,所以我们一样不知道这个文件到底位于SD卡的什么地方,不要以为它会在0字节的地方开始,为了找到这个文件的开始位置,我们可以在建立的那个空文件的开头写上几个字符,比如我程序里面写的
“DATASTART”,接下来我们要做的就是一个扇区一个扇区的去找这个几个特殊的字符,这是个笨方法,但却是最简单直观的方法。这个方法有两个缺点:a、如果文件建立在整个SD卡的后面,那找到这个文件需要漫长的等待。b、如果碰巧某个文件里面也有我们定义的那个特殊字符串的话,那就乱套了!不过好在我们使用的SD卡一般都是专用的,并不能拿去做其他应用,比如从公司copy点文件回家之类的,那就能保证这个SD卡上文件的简单性,即只有我们需要的那个文件,其他文件并不存在,而且这个文件肯定会从SD卡开始的那些扇区中的某一个开始。这样说来的话找到这个字符串也不是那么慢嘛!^_^。不过这里要建议一下,在使用SD卡之前最好用windows将它完全格式话一下。
3-4、一旦我们找到了我们要写入文件的起始位置(它一般表示为一个扇区号),那我们就可以在这个起始扇区的下一个扇区写入数据了。
4、OK,看起来很简单!有了这种存储方式我们还需要IIC接口的 EEPROM干吗呢?