您的位置 首页 新品

菜鸟用C8051F020 SPI读写SD卡FAT全攻略

我从一个月前刚放暑假开始弄单片机读写SD卡,八月初完成FAT16,已经可以写入TXT文件,并可在windows上读出。由于网上资料比较散,所以一开…

我从一个月前刚放暑假开端弄单片机读写SD卡,八月初完结FAT16,现已能够写入TXT文件,并可在windows上读出。因为网上材料比较散,所以一开端走了不少弯路,现在写一篇总结,将我遇到的问题详细地列出来,期望能协助和我相同的菜鸟们少走弯路。文中提到的一些问题对高手而言仅仅常识性的,还请包容。

第一步:搭电路

我买了一小块蜂窝板和一个SD插槽,依照规范电路焊接上,因为用的是SPI形式,所以选电路图的时分要看好,SD卡上的引脚次序不要看错,912345678,最终两根挨得很紧,焊接时不要连上了,相关引脚必定要依照要求接上47K的上拉电阻。电路尽管简略,但必定要保证无误。还有一点,SD卡座品种不相同,有位学长买的是绷簧式的,焊完今后刚开端初始化都能成功,放了几天忽然不行了,查看各引脚都没问题,最终发现是卡座的问题,这样的硬件问题很难发现,还浪费时间,所以卡座仍是直接买简略的好。

第二步:设置硬件SPI

我用的是sililab的C8051F020,自带硬件SPI,假如不带能够用软件模仿,关于软件模仿SPI这块网上有许多现成的程序。这一歩首要依照020手册写了一段程序,当然是将其设为主形式,这时分CONFIG(这个软件能够视窗化操作C8051F的大多数寄存器并主动生成代码)会分配4个引脚,CLK时钟位,MISO和MOSI两个数据传输位,还有一个NSS位,这个脚用不上,不要将其当作CS片选位,CS位选一个一般IO既可。一切从单片机上输出的引脚都设为推挽输出。设置完结后最好弄个示波器看一下输出波形是否和你幻想中的相同,这样就能保证你的SPI作业没问题了,这一步也是要害,SPI是底层通讯的根底。

第三步:SD卡初始化

这一步正式进入单片机调试SD部分,了解SD卡的时序后(后边我会上传这部分材料),网上议论纷纷,还有说要看完178页英文PDF,我都晕了,这个看完估量我都是专家了。关于初始化指令有许多说法,我发的是CMD0和CMD1就能够成功初始化。

解说一下这个指令格局的意义:这是个一个字节的指令格局为01xx xxxx 后六位是CMD后边的数字的二进制值,如CMD1=0100 0001=0x41 程序中写为CMD | 0x40 CMD代表后边的数字。

需求留意初始化时SPI速率不能超过400K,我设的是100K,初始化没问题,还有发CMD0之前要向SD卡发送至少74个时钟周期,只要CMD0需求这样特别。

下面是发送CMD0的程序段:

retry=0;
CSH;

do{
for(i=0;i<10;i++) SPI_WriteByte(0xFF);//发送 至少 74个时钟周期留意片选线此刻为高
r1=mmcSendCommand(MMC_GO_IDLE_STATE, 0);//发送CMD0,留意此刻片选线才为低
retry++;
if(retry>0xfe) return -1;//测验的发送次数能够恰当多一些
} while(r1 != MMC_R1_IDLE_STATE); //正确应对为1

测验发送的次数至少为200,有人主张2000的,随意,假如不稳定,比方有时分收的到有时分收不到,就能够恰当增大发送次数

这是紧随其后发送的CMD1程序段:

retry=0;
do{
r1=mmcSendCommand(MMC_SEND_OP_COND, 0);//发送CMD1
retry++;
if(retry>100) return -1;
} while(r1!=0); //正确应对为0

初始化有这两个就能够完结了,有的程序中还会加上

mmcSendCommand(MMC_CRC_ON_OFF, 0);//关CRC校验

mmcSendCommand(MMC_SET_BLOCKLEN, 512);//设置块长度为512字节

这个无关紧要,SPI形式下默许没有CRC校验的,并且每块字节数便是512,这个块巨细就别改了,你要设置成其他巨细,后边加FAT会出费事的。

下面解说一下上面程序中的uint8_t mmcCommand(uint8_t cmd, uint32_t arg)函数

uint8_t mmcCommand(uint8_t cmd, uint32_t arg)

{
uint8_t r1,retry=0;
SPI_WriteByte(cmd|0x40);// send command
SPI_WriteByte(arg>>24);
SPI_WriteByte(arg>>16);
SPI_WriteByte(arg>>8);
SPI_WriteByte(arg);
SPI_WriteByte(0x95);// 解说符号(1)
SPI_WriteByte(0xFF);// 解说符号(2)

while((r1=SPI_WriteByte(0xFF))==0xFF)if(retry++>8)break;
return r1;
}

arg这个参数看一下SD的SPI指令格局就知道这个字段是指令的特点,一般为0

解说符号(1)

CRC位这个0x95只对CMD0有意义,发送其他指令时这个位可为恣意值,所以不必修正

解说符号(2)

这个简略疏忽,不疏忽第一个字节你就或许收不到正确的呼应,许多程序中这个叫做dummy values。特别留意看时序图,后边写指令的程序中是要发送两个字节的,不要和这个搞混了。

写指令程序段:

uint8_t mmcWrite(uint32_t sector, uint8_t* buffer){
uint8_t r1;
uint16_t i;

CSL;// assert chip select
r1 = mmcCommand(MMC_WRITE_BLOCK,sector<<9);// issue command
if(r1 != 0)return r1;
SPI_WriteByte(0xFF);// send dummy
SPI_WriteByte(MMC_STARTBLOCK_WRITE);// send data start token

for(i=0; i<512; i++){
SPI_WriteByte(*buffer++);// write data
}

SPI_WriteByte(0xFF);// write 16-bit CRC (dummy values)看清楚!两个字节哦!
SPI_WriteByte(0xFF);

r1 = SPI_WriteByte(0xFF);// read data response token
if((r1&MMC_DR_MASK)!=MMC_DR_ACCEPT)return r1;//解说符号(1)
while(!SPI_WriteByte(0xFF));// wait until card not busy
CSH;// release chip select
return 0;
}

解说符号(1)

这个很重要!!!我在这浪费了一个星期!!!

许多程序包括网上的大多材料都说这个回应为0x05,可是我每次都收不到这个回应,收到的是0xE5,原本我认为是程序有问题,其实否则,我查了材料,找到了这个呼应令牌的8位的意义,发现高三位是保存位,而0xE5和0x05低五位是相同的阐明呼应是正确的,这个高三位或许因为厂家不同值不相同。

这个程序是比较完善的,呼应r1与上个MMC_DR_MASK(宏界说值为0x0001 1111)就把高三位与成0了,网上有的程序是没有这个进程的。

假如你想验证只能是否能正常读写,能够将值赋进数组写入到SD卡的一个扇区里(这儿的扇区是指物理扇区,这个概念在FAT文件中再说)在用数组读出来,在仿真器里看是否相同,这个进程或许用不了winhex这款软件,因为你写入的那个扇区或许是引导区,形成你将卡插到电脑中会提示你格局化。

下面是CMD0的波形图

本来认为这个波形图有问题,因为时序图上片选线在数据传送进程中是一向低的,还在网上问了一阵子,惋惜没人理我,其实是正确的,中心的电平跳变是因为SPI发送函数最初和末位有把片选拉低和拉高,片选线一旦拉高,数据线就会跟着变高,所以呈现了跳变,我测验着把SPI发送函数的最初末位片选去掉,发现这样也是能够的。

第四步:加FAT

假如上面测验都没问题,那么底层通讯就没有问题了,到目前为止咱们一向是把SD当成一个大的FLASH来操作的,可是要想在电脑上把用单片机写的程序读出来就要依照必定规矩往里边写,这个规矩便是FAT。我用的是2G的金士顿SD卡,正好能够用FAT16,FAT16最大支撑2G。

这一块的内容能够参照http://www.sjhf.net/document/fat/#索引

里边的解说很详细,会协助你了解文件体系

需求掌握的思路是:先用电脑把SD卡格局化成FAT16的(即FAT),然后读写的规矩是:找到MBR(主引导区)读相关字节得到逻辑引导区的地址,在逻辑扇区里读出BPB数据,再对FAT表,根目录和数据区进行对应操作

这一块能够用winhex看SD卡的物理扇区和逻辑扇区,以便对照

这一块我讲几个我遇到的问题

1>>假如是VISTA操作体系,你要以办理员身份进入,否则无法看到物理扇区,即鼠标停在winhex的图标上点右键选取以办理身份运转即可(不要笑,我刚开端就不知道应该这样操作,呵呵)

2>>有些SD卡是没有主引导区即MBR的,这样更好,逻辑扇区就和物理扇区相同了,那么怎样判别有没有MBR呢?最简略的你用winhex看一下物理和逻辑扇区,假如数据相同便是没有MBR了。再有谨慎一点的办法:留意看%&&&&&%中对逻辑引导区的解说,逻辑引导区根本是以E9和EB最初的,单凭这一点就能够用函数轻松判别了。所以写文件之前先澄清你的SD卡有没有MBR,想了解更多请参照http://hi.baidu.com/bg4uvr/blog/item/b59f2fde196efd5fcdbf1aee.html

有没有MBR是能够转化的,详细请看:http://hi.baidu.com/bg4uvr/blog/item/9489a6295f7bcff998250a48.html

3>>这儿说一些关于编译的问题,参加FAT部分的程序后,工程中程序文件会比较多,这儿要留意重复包括的问题,这一块网上许多,不再重复。有时分过错并不在指针提示的那一行

比方有时分指的那一行只要int a;这样的句子,这时分留意往上面看,是不是界说函数时漏了结尾的分号,形成编译器将a也当作其形参了,这种过错有时分很荫蔽,比方int a;上面只要#include “b.h”,这时分就要去b中看看,是不是文件结尾界说的那个函数后边忘了分号

还有编译器报出”segment too large”这时分须把编译器选项中的Memory Model 中的Variable 设成XDATA这是对sililab IDE开发环境而言的,或许放入xdata数组里也行Project——>Tool Chain Intergration——>Compiler——>Custmize——>Memory Model ——>Variable——>Large:XDATA

这个IDE官方下载的会约束代码巨细,因为里边用的编译器是约束版的,这时分你假如装了正版的KEIL就能够用KEIL的编译器然后不受代码约束。详细做法:Project——>Tool Chain Intergration将Compiler和Linker中的途径修正到KEIL的相应途径即可。

还有便是有的程序是不支撑文件夹嵌套的

现在我说一个最最重要的问题,也是我遇到的最终一个问题,字节序问题,请先参阅http://blog.csdn.net/sunshine1314/archive/2008/04/20/2309655.aspx

了解了字节序,当然这儿不必管比特序,假如你用的是AVR单片机,祝贺你,和SD卡还有电脑的字序是相同的,不必转化字序的,网上大多数程序你都能用,我用的C8051F020则需求,每次和卡交流大于一个字节的数据时都需求做一次转化,因为程序中只用到了8 16 32这类数据,所以我只参加两字节转化函数和四字节转化函数,函数体如下:

uint16_t two_byte_exchange(uint16_t h)
{
if(!Big_Small_ending_Switch) //假如没有使能字节转化则回来原值
return h;

return (h >> 8) + (h << 8); }
uint32_t four_byte_exchange(uint32_t h)
{

if(!Big_Small_ending_Switch) //假如没有使能字节转化则回来原值
return h;

return (h >> 24) + ((h >> 16) << 8)+ ((h >> 8) << 16)+ (h << 24);
}

以上便是我遇到的大部分问题了,期望对我们有所协助,因为水平有限,不足之处还请长辈们指导!

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/xinpin/275737.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部