首先是定义BPB的结构体,存储FAT32文件系统的相干信息。
+ 查看代码
#pragma pack(1)
typedef struct
{
__IO uint16_t byte_per_sector; //0B
__IO uint8_t sector_per_cluster; //0D
__IO uint16_t reserved_sector; //0E
__IO uint8_t number_fat; //10
__IO uint16_t no_use_1; //11
__IO uint16_t no_use_2; //13
__IO uint8_t media_descriptor; //15
__IO uint16_t no_use_3; //16
__IO uint16_t sector_per_trark; //18
__IO uint16_t number_head; //1A
__IO uint32_t hidden_sector; //1C
__IO uint32_t all_sector; //20
__IO uint32_t sector_fat_use; //24
__IO uint32_t no_use_4; //28
__IO uint32_t root_start_cluster; //2C
}fat_32;
#pragma pack()
这里要注意,要使用#pragma pack(1) ,使结构体以一个字节对齐。关于对齐,可以自行百度。这里如果不以一个字节对齐的话,结果是 不对的。
主体代码;
+ 查看代码
fat_32 *fat_file;
uint8_t response;
uint16_t i=0;
periph_init();
printf("hello world!!!!\n");
while(1)
{
response = SD_reset();
if(response == RESET_SUCCESS)
break;
i++;
if(i==20)
{
printf("初始化失败\n");
i = 0;
}
delay_ms(5);
}
printf("初始化成功\n");
delay_ms(200);
response = SD_read_sector_data(0,SD_data,1);
for(i=0; i<512; i++)
{
if(i%16 == 0 && i != 0)
printf("\n");
if(i%8 == 0 && i != 0 && i%16 !=0)
printf(" ");
printf("%2x ",SD_data[i]);
}
printf("\n");
fat_file = (fat_32 *)(&SD_data[0x0b]);
printf("扇区字节数:%d ",fat_file->byte_per_sector);
printf("每簇扇区数:%d\n",fat_file->sector_per_cluster);
printf("保留扇区数:%d ",fat_file->reserved_sector);
printf("FAT表份数:%d ",fat_file->number_fat);
printf("介质类型:%x\n",fat_file->media_descriptor);
printf("磁盘总扇区数:%d ",fat_file->all_sector);
printf("FAT表占用扇区数:%d\n",fat_file->sector_fat_use);
printf("根目录入口簇号:%d\n",fat_file->root_start_cluster);
首先是定义了一个fat32的结构体指针。然后读取扇区0的数据。然后将读取的512字节数据填入到结构体中。这里因为数据是依次的填入到结构体中,所以这里使用一个指针的技巧。
fat_file = (fat_32 *)(&SD_data[0x0b]);
这样,就将连续的数据填入到结构体中了。然后将一些重要的数据显示出来。

可以看出0扇区就是DBR,从11数据开始就是BPB数据。对BPB的数据进行处理,就可以得到FAT32的相关信息了。
然后是测试写数据。首先,我在SD卡中,放了一个txt文件,里面的内容是沁园春·雪。通过winhex软件,查看,得知,这个文件的内容在30304扇区,因为数据比较小,只占着一个扇区。所以我就将这个扇区的数据给读取出来,然后在写到其他扇区去(这里写入的扇区为9198825和9198826),然后在读取这两个扇区,看看数据是否正确。
主体代码:
+ 查看代码
response = SD_read_sector_data(30304,SD_data,1);
for(i=0; i<512; i++)
SD_data[512+i] = SD_data[i];
printf("测试连续写扇区,写两个\n");
response = SD_write_sector_data(9198825,SD_data,2);
if(response == WRITE_SECTOR_SUCCESS)
{
printf("写入数据成功,写入扇区为9198825,共两个\r\n");
for(i=0; i<1024; i++)
SD_data[i] = 5;
response = SD_read_sector_data(9198825,SD_data,2);
printf("读取扇区9198825和9198826的数据\n");
if(response == READ_SECTOR_SUCCESS)
{
for(i=0; i<1024; i++)
{
printf("%c",SD_data[i]);
if(i==512)
printf("\n");
}
printf("\n");
printf("读取数据成功\n");
}
}
从串口读取的数据

写数据也是成功的。
最后就测试一下擦除了。
主体代码:
+ 查看代码
response = SD_erase_sector(9198825, 9198826);
if(response == ERASE_SECTOR_SUCCESS)
{
printf("擦除数据成功");
for(i=0; i<1024; i++)
SD_data[i] = 1;
SD_read_sector_data(9198825,SD_data,2);
for(i=0; i<1024; i++)
{
if(i%16 == 0 && i != 0)
printf("\n");
if(i%8 == 0 && i != 0 && i%16 !=0)
printf(" ");
printf("%2x ",SD_data[i]);
}
printf("\n");
}
else
printf("擦除数据不成功");
首先是执行擦除函数,然后将数组给清1.然后去读取擦除扇区的值。

可以看出,数据都是0,表明数据擦除成功。
通过这样的测试,说明,我们写的SDHC卡驱动,是可以使用的。其实还有些其他操作,比如读取SD卡的内部的一些寄存器的值,这些都没有介绍,不过道理也是一样的,发送命令,读取数据即可
SD卡驱动,重要的要掌握SD卡的初始化,SD卡数据读取和数据写入,数据擦除。有了这些,就可以操作我们的SD卡。