快讯
HOME
快讯
正文内容
卡在nand write 存储卡选购,看这一篇就够咯
发布时间 : 2025-04-05
作者 : 小编
访问数量 : 23
扫码分享至微信

存储卡选购,看这一篇就够咯

本文由什么值得买用户原创:

王二狗

前言:

数码产品越来越多的融入到我们的生活,各类存储卡能看到的频次越来越高。普通用户面对规格和品种众多的存储卡,如何进行选择适合自己需求的产品确实是一件困难的事情。二狗今天就通过这篇文章来详细聊聊存储卡的选购,希望对你选卡有所助益

常见存储卡介绍:

存储卡市场发展多年,目前市面上常见存储卡主要包括SD卡(Secure Digital Memory Card)和MicroSD卡(原名TF,Trans-flash Card )两类。

前者规格为24mmx32mmx2.1mm,后者规格为15mmx 11mmx 1mm。由于两种卡在大小上存在明显差别,一边习惯上将SD卡称为大卡,将TF卡称为小卡。小卡通过专用适配器可以转换成大卡进行使用。

除了常见的大卡、小卡外,市面上还能见到CF卡、QDA卡等存储卡。这些存储卡使用范围较小,这里就不做介绍。

存储卡基础知识:

存储卡除了按照种类划分为大小卡外,一般还可以容量和速度进行划分。

1)存储卡按容量分类:

SD:早期版本现在已经基本停用,最大容量2GB。

SDHC:目前使用较多,容量为4GB-32GB。

SDXC:发展前景最好的版本,容量为64GB-2TB。

2)存储卡按速度分类:

Class等级标准:

早期存储卡速度等级使用Class等级来标识。Class等级越高传输速度越快,现在比较常见的都是速度最快的Class 10级别,简称C10。速度更低的C6、C4、C2的存储卡早已退出市场。

UHS 等级标准:

UHS(Ultra High Speed)超高速等级为全新的总线模式。目前有UHS-I、UHS-II、UHS-III三种版本。实现UHS标准传输速度需要设备支持,高版本向下兼容低版本,不支持该标准可以兼容降速为普通存储卡使用。日常使用U1(最低写入速度10M/S)和U3(最低写入速度30M/S)的等级标识最低写入速度。UHS-I卡的最大读取速度为104M/S,而UHS-II卡的最大读取速度为312M/S。UHS-III卡的最大读取达到了624M/S。

VSC等级标准:

VSC(Video Speed Class)视频速度等级。4K视频的拍摄需求增大后,SD协会针对视频拍摄应用制定的视频速度等级,以识别字母V加上最低写入速度值的数字构成标识。比如拍摄4K视频的存储卡必须要达到V30,要求稍高的4K视频必须达到V60。

PS:存储卡包装一般标明的都是读取速度,等级标准都是最低写入速度。读取速度一般都是快于写入速度的,大家注意区分。

有了上面的知识储备,我们就可以轻松读懂存储卡上的参数内容。以上图存储卡为例:

品牌与系列:SANDISK(闪迪) Extreme PRO系列

读取速度:170M/S

容量分类:SDXC存储卡

视频速度等级:V30,即最低写入速度30M/S

UHS模式:支持UHS-I模式

Class等级:C10,最低写入速度10M/S

超高速等级:U3, 支持UHS模式时,最低写入速度30M/S

简单来说,上面这张卡是一张256G的SD卡,普通模式下最低写入速度10M/S。UHS模式下最低写入速度30M/S,最高读取速度170M/S。

此外在不少TF卡上我们经常可以看到卡片表示有A1/A2,这个又是什么意思啦?

大文件连续读写时很容易掉速,应用等级表现就是规定在各种因素造成的掉速情况下能够保持的最低速度。目前只有A1和A2两个等级,他们的最低写入速度都是10M/S,不过在随机读取最低速度和随机写入最低速度的要求有所不同。

存储卡选购指南:

刚才已经介绍了存储卡的基础知识,那么我们选购的时候应该从那几个维度来进行挑选啦?高售价的产品肯定能满足需求,但是作为普通用户往往需要性价比,选购存储卡需要从容量、品牌、性能和保修四个维度进行考量。

选容量:

根据我们的实际需求来确定购买存储卡的大小。一般来说主要考虑视频拍摄和照片拍摄两种场景。一般选择主流的4K视频拍摄,128G的卡也能轻松拍摄近3小时,日常使用完全能满足需求。静态照片单张按照30M计算,128G的存储卡可以存储照片4267张。

考虑到主控芯片成本和颗粒价格的因素,目前主流的SD卡中64G/128G性价比较高。如果经常需要拍摄4K视频,建议购买128G的存储卡。如果主要用于照片拍摄,建议购买64G的存储卡足够。

选性能:

针对存储卡来说,最重要的规格参数就是读取速度和写入速度两大指标。

以上图为例,同是128G的索尼存储卡,读写速度的不同形成了不同的价格。

速度方面,日常拍摄对存储卡性能要求较高的就是高质量视频。抛开特殊要求不提,基本上能做到读取速度200M/S,写入速度90M/S就能满足绝大部分需求, 4K视频拍摄、高质量照片连拍都能从容应对。当然不差钱或者应对更加专业需求,建议直接上读写都能到250M/S的存储卡。

如果是用于安防等特殊场景,读写速度不是最重要的标准,存储卡的稳定性、耐热耐湿性能更加重要,可以考虑在这些方面做过优化的存储卡产品。

选品牌:

SD卡是比较成熟的产品,各家的产品区别不算太大,基于定位原因不同是品牌、颗粒、主控芯片的产品价格有所不同。大厂在品控和质保上往往有更好的控制力,选择市面上大品牌的SD卡相对来说更放心。

我自己的经验来看闪迪、索尼、东芝和三星都算比较靠谱的品牌,兼顾性价比的话也可以考虑下雷克沙、金士顿等品牌。售价相对低廉的小品牌不做推荐,价差不算大,但是存储卡损坏造成宝贵数据丢失就得不偿失咯。

选保修:

存储卡根据使用性质不同保修内容也不同。同一品牌普通内存卡10年保修,而专用的内存卡可能只有3年保修。同时代理商和厂家的保修时间也往往不同。相同条件下建议选择保修时间更长的产品。

存储卡知识Q&A:

Q:我想要的存储空间是256G,是选择一张256G的卡还是两张128G的卡?

A:一般情况推荐选择两张128G的卡。原因有两个,首先两张128G卡的价格一般会比一张256G卡的价格便宜,其实拍摄中最怕就是数据丢失,一张256G卡数据掉了就是所有内容,两张128G卡可以分摊风险,数据总会保留一部分。

Q:日常主要拍摄照片为主,使用TF卡+卡套会不会比直接插SD性能差?

A:目前卡套转换率较高,基本不会出现太大的性能损耗。使用正规厂家的转换卡套一般没有问题。

Q:行车记录仪选存储卡怎么选?

A: 行车记录仪存储卡对速度要求不高,但是对稳定性和场景条件要求较高。一般建议选择保修时间长,同时针对高温高湿环境有优化的存储卡。

Q:为什么我的UHS-1存储卡在数据拷贝中达不到标称的速度,数值差异巨大?

A:UHS-1存储卡需要配合支持UHS-1的读卡器等相应设备才能达到对应的传输速度,设别到不支持UHS-1数据传输会进行降速处理。选购读卡器时候注意查看支持的传输标准,一般只强调USB3.0就是普通的读卡器,售价便宜但是传输速度慢。

Q:部分品牌的存储卡上出现的类似633X的参数代表什么意思?

A:这是一种早期的速度标识方式,目前已较少有厂家使用。1X=150KB/S,多少X就是多少倍的意思。比如上图所示的存储卡速度为:633X=633 * 150KB/S/1000 ≈ 95M/S。

Q:如何区分UHS-1和UHS-2的存储卡?

方法一:直接看商品正面标识部分,会直接标识出存储卡类型。

方法二:查看商品的金手指,如果只有一排金手指即使UHS-1存储卡,有两排为UHS-2以上的存储卡。

Q:读取速度与写入速度到底谁更重要?

A:一般厂家会在卡面标识速度,R(read)代表读取速度,W(write)代表写入速度。如果只有一个速度那就读取速度,一般来说读取速度会比写入速度快。

一般来说,连续拍摄照片或者高质量视频拍摄的时候,对存储卡写入速度要求较高。使用Switch等游戏机的时候往往对存储卡读取速度要求较高。根据自己需求,合理选择存储卡十分必要。

存储卡选购TIPS:

下面对选购存储卡做个小总结,没看内容的可以直接看结论咯。

1)优先选择实力较强的大品牌,比如闪迪、索尼、东芝、三星等,其次高性价比的雷克沙、金士顿也可以考虑,小品牌不建议购买;

2)日常拍摄以静态照片为主,同时对大卡小卡都有需求场景,可以考虑购买小卡+卡套的组合;

3)有4K视频拍摄需求,至少要选择V30标准的存储卡,有条件的话选择V60或者V90的存储卡;

4)预算相对充分的情况下,建议选择读取速度200M/S,写入速度90M/S的存储卡,能够满足4K视频拍摄、静态照片连拍等多种需求;

5)有视频拍摄需求建议选择128G或以上容量存储卡,非视频拍摄建议选择64G或以上容量存储卡;

6)注意区分存储卡的读取速度和写入速度,厂商一般会标识读取速度,不过很多存储卡写入速度不够理想,厂商往往不会在产品上进行明显标识。

【STM32】SD卡读写(四)-STM32利用SPI读写SD卡的程序详解

SD卡的读写驱动程序是运用FATFS的基础,学了FATFS就可以在SD卡上创建文件夹及文件了。

我们先从main文件了解一下程序的执行流程

int main(void){ u16 i; USART1_Config(); for(i=0;i<1536;i++) send_data[i]='D'; switch(SD_Init()) { case 0: USART1_Puts("\r\nSD Card Init Success!\r\n");break; case 1: USART1_Puts("Time Out!\n"); break; case 99: USART1_Puts("No Card!\n"); break; default: USART1_Puts("unknown err\n"); break; } SD_WriteSingleBlock(30,send_data); SD_ReadSingleBlock(30,receive_data); if(Buffercmp(send_data,receive_data,512)) { USART1_Puts("\r\n single read and write success \r\n"); //USART1_Puts(receive_data); } SD_WriteMultiBlock(50,send_data,3); SD_ReadMultiBlock(50,receive_data,3); if(Buffercmp(send_data,receive_data,1536)) {USART1_Puts("\r\nmulti read and write success \r\n");//USART1_Puts(receive_data); } while(1);}

这里程序流程比较简单:

1)配置串口,用作程序的调试输出

2)填充将要给SD卡写入数据的数组send_data。

3)初始化SD卡,根据返回SD_Init()返回值确定SD卡初始化是否完成。

4)单块读写实验,并比对读写出的数据是否相同。

5)多块读写实验,并比对读写出的数据是否相同。

下面我们开始对main函数中涉及到的用户函数的层层调用详细说明

SD初始化函数SD_Init()

为使程序更简洁,故只对SD卡进行检测,放弃对MMC卡的支持(此种卡市面上已几乎不再使用,本人手上也没有这种卡,所以写出驱动程序,也没有硬件进行检测是否可用)。

下面程序是部分对SD2.0卡检测的代码,完整代码中还有对1.0版本SD卡的初始化,可下载完整代码查看。

u8 SD_Init(void){ u16 i; u8 r1; u16 retry; u8 buff[6]; SPI_ControlLine(); //SD卡初始化时时钟不能超过400KHz SPI_SetSpeed(SPI_SPEED_LOW); //CS为低电平,片选置低,选中SD卡 SD_CS_ENABLE(); //纯延时,等待SD卡上电稳定 for(i=0;i<0xf00;i++); //先产生至少74个脉冲,让SD卡初始化完成 for(i=0;i<10;i++) { //参数可随便写,经过10次循环,产生80个脉冲 SPI_ReadWriteByte(0xff); }//-----------------SD卡复位到idle状态----------------//循环发送CMD0,直到SD卡返回0x01,进入idle状态//超时则直接退出 retry=0; do { //发送CMD0,CRC为0x95 r1=SD_SendCommand(CMD0,0,0x95); retry++; } while((r1!=0x01)&&(retry<200)); //跳出循环后,检查跳出原因, if(retry==200)//说明已超时 { return 1; } //如果未超时,说明SD卡复位到idle结束 //发送CMD8命令,获取SD卡的版本信息 r1=SD_SendCommand(CMD8,0x1aa,0x87); //下面是SD2.0卡的初始化 if(r1==0x01) { // V2.0的卡,CMD8命令后会传回4字节的数据,要跳过再结束本命令 buff[0] = SPI_ReadWriteByte(0xFF); buff[1] = SPI_ReadWriteByte(0xFF); buff[2] = SPI_ReadWriteByte(0xFF); buff[3] = SPI_ReadWriteByte(0xFF); SD_CS_DISABLE(); //多发8个时钟 SPI_ReadWriteByte(0xFF); retry = 0; //发卡初始化指令CMD55+ACMD41 do { r1 = SD_SendCommand(CMD55, 0, 0); //应返回0x01 if(r1!=0x01) return r1; r1 = SD_SendCommand(ACMD41, 0x40000000, 1); retry++; if(retry>200) return r1; } while(r1!=0); //初始化指令发送完成,接下来获取OCR信息 //----------鉴别SD2.0卡版本开始----------- //读OCR指令 r1 = SD_SendCommand_NoDeassert(CMD58, 0, 0); //如果命令没有返回正确应答,直接退出,返回应答 if(r1!=0x00) return r1; //应答正确后,会回传4字节OCR信息 buff[0] = SPI_ReadWriteByte(0xFF); buff[1] = SPI_ReadWriteByte(0xFF); buff[2] = SPI_ReadWriteByte(0xFF); buff[3] = SPI_ReadWriteByte(0xFF); //OCR接收完成,片选置高 SD_CS_DISABLE(); SPI_ReadWriteByte(0xFF); //检查接收到的OCR中的bit30位(CSS),确定其为SD2.0还是SDHC //CCS=1:SDHC CCS=0:SD2.0 if(buff[0]&0x40) { SD_Type = SD_TYPE_V2HC; } else { SD_Type = SD_TYPE_V2; } //-----------鉴别SD2.0卡版本结束----------- SPI_SetSpeed(1); //设置SPI为高速模式 }}

以上函数是根据SD卡的发送和响应时序进行编写的。

1)程序中配置好SPI模式和引脚后,需要先将SPI的速度设为低速,SD卡初始化时SCK时钟信号不能大于400KHz,初始化结束后再设为高速模式,这里对SPI的模式配置不在赘述,可参考SPI读写FLASH文章的相关内容。

2)将片选信号拉低,选中SD卡,上电后,需要等待至少74个时钟,使SD卡上电稳定。

3)向SD卡发送CMD0指令,SD卡如果返回0x01,说明SD卡已复位到idle状态。

4)向SD卡发送CMD8指令,SD卡如果返回0x01,说明SD卡是2.0或SDHC卡。

SPI读写一字节数据

在这里,先介绍一个相对底层的函数。

SPI操作SD卡时,发送和接收是同步的,所以发送和接收数据使用同一个函数。

在发送数据时,并不关心函数的返回值;

在接收数据时,可以发送并无实际意义的字节(如0xFF)作为函数的参数。

u8 SPI_ReadWriteByte(u8 TxData){ while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)==RESET); SPI_I2S_SendData(SPI1,TxData); while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)==RESET); return SPI_I2S_ReceiveData(SPI1);}

这个函数在所有主机与SD卡通信的函数中都会被调用到。

从SD卡中读回指定长度的数据

在SD卡读写试验中,我们会遇到很多需要读取SD卡各个寄存器数据的情况。

SD卡返回的数据长度并不都相同,所以需要一个函数来实现这个功能。

函数中多次调用了读写一字节数据的函数SPI_ReadWriteByte。

这个功能由函数 u8 SD_ReceiveData()来实现。

u8 SD_ReceiveData(u8 *data, u16 len, u8 release){ u16 retry; u8 r1; //启动一次传输 SD_CS_ENABLE(); retry = 0; do { r1 = SPI_ReadWriteByte(0xFF); retry++; if(retry>4000) //4000次等待后没有应答,退出报错(可多试几次) { SD_CS_DISABLE(); return 1; }} //等待SD卡发回数据起始令牌0xFE while(r1 != 0xFE); //跳出循环后,开始接收数据 while(len--) { *data = SPI_ReadWriteByte(0xFF); data++; } //发送2个伪CRC SPI_ReadWriteByte(0xFF); SPI_ReadWriteByte(0xFF); //按需释放总线 if(release == RELEASE) { SD_CS_DISABLE(); SPI_ReadWriteByte(0xFF); } return 0;}

此函数有3个输入参数:

u8 * data为保存读回数据的变量

len为需要保存的的数据个数

release 为当程序结束后是否释放总线的标志。

给SD卡发送命令

在初始化函数中,我们需要做的最多的就是给SD卡发送各种命令以及接收各种响应,从而判断卡片的类型,操作条件等相关信息。

一个命令包括6个段:

给SD卡发送命令的程序有2个。

区别为一个发送完命令后失能片选,一个为发送完命令不失能片选(后续还有数据传回)。

u8 SD_SendCommand(u8 cmd,u32 arg,u8 crc){ unsigned char r1; unsigned int Retry = 0; SD_CS_DISABLE(); //发送8个时钟,提高兼容性 SPI_ReadWriteByte(0xff); //选中SD卡 SD_CS_ENABLE(); /*按照SD卡的命令序列开始发送命令 */ //cmd参数的第二位为传输位,数值为1,所以或0x40 SPI_ReadWriteByte(cmd | 0x40); //参数段第24-31位数据[31..24] SPI_ReadWriteByte((u8)(arg >> 24)); //参数段第16-23位数据[23..16] SPI_ReadWriteByte((u8)(arg >> 16)); //参数段第8-15位数据[15..8] SPI_ReadWriteByte((u8)(arg >> 8)); //参数段第0-7位数据[7..0] SPI_ReadWriteByte((u8)arg); SPI_ReadWriteByte(crc); //等待响应或超时退出 while((r1 = SPI_ReadWriteByte(0xFF))==0xFF) { Retry++; if(Retry > 800)break; //超时次数 } //关闭片选 SD_CS_DISABLE(); //在总线上额外发送8个时钟,让SD卡完成剩下的工作 SPI_ReadWriteByte(0xFF); //返回状态值 return r1;}u8 SD_SendCommand_NoDeassert(u8 cmd, u32 arg,u8 crc){ unsigned char r1; unsigned int Retry = 0; SD_CS_DISABLE(); //发送8个时钟,提高兼容性 SPI_ReadWriteByte(0xff); //选中SD卡 SD_CS_ENABLE(); /* 按照SD卡的命令序列开始发送命令 */ SPI_ReadWriteByte(cmd | 0x40); SPI_ReadWriteByte((u8)(arg >> 24)); SPI_ReadWriteByte((u8)(arg >> 16)); SPI_ReadWriteByte((u8)(arg >> 8)); SPI_ReadWriteByte((u8)arg); SPI_ReadWriteByte(crc); //等待响应或超时退出 while((r1 = SPI_ReadWriteByte(0xFF))==0xFF) { Retry++; if(Retry > 800)break; } return r1;}

以上两个函数就是根据SD卡在SPI模式下发送指令的时序编写的

取CID寄存器数据

u8 SD_GetCID(u8 *cid_data){ u8 r1; //发CMD10命令,读取CID信息 r1 = SD_SendCommand(CMD10, 0, 0xFF); if(r1 != 0x00) return r1; //响应错误,退出 //接收16个字节的数据 SD_ReceiveData(cid_data, 16, RELEASE); return 0;}

以上程序源码相对比较简单,发送了CMD10读取CID寄存器命令后,如果相应正确,即开始进入接收数据环节,这里SD_ReceiveData函数中第二个参数输入16,即表示回传128位的CID数据。

获取SD卡容量信息

SD卡容量的信息主要是通过查询CSD寄存器的一些相关数据,并根据数据手册进行计算得出的。

该函数虽然较为复杂,但可先精读SPI操作SD卡的理论知识篇,看懂程序的算法为何是这样实现的,也就容易理解程序的编写原理了。

u32 SD_GetCapacity(void){ u8 csd[16]; u32 Capacity; u8 r1; u16 i; u16 temp; //取CSD信息,如果出错,返回0 if(SD_GetCSD(csd)!=0) return 0; //如果是CSD寄存器是2.0版本,按下面方式计算 if((csd[0]&0xC0)==0x40) { Capacity=((u32)csd[8])<<8; Capacity+=(u32)csd[9]+1; Capacity = (Capacity)*1024;//得到扇区数 Capacity*=512;//得到字节数 } else//CSD寄存器是1.0版本 { i = csd[6]&0x03; i<<=8; i += csd[7]; i<<=2; i += ((csd[8]&0xc0)>>6); r1 = csd[9]&0x03; r1<<=1; r1 += ((csd[10]&0x80)>>7); r1+=2; temp = 1; while(r1) { temp*=2; r1--; } Capacity = ((u32)(i+1))*((u32)temp); i = csd[5]&0x0f; temp = 1; while(i) { temp*=2; i--; } //最终结果 Capacity *= (u32)temp; //字节为单位 } return (u32)Capacity;}

此函数计算出来的容量是Kbyte,结果除以1024就是Mbyte,再除以1024就是GByte。

2G的卡,结果可能是1.8G,8G的卡结果可能是7.6G,代表用户可用容量。

读单块block和读多块block

SD卡读单块和多块的命令分别为CMD17和CMD18,他们的参数即要读的区域的开始地址。

因为考虑到一般SD卡的读写要求地址对齐,所以一般我们都将地址转为块,并以扇区(块)(512Byte)为单位进行读写,比如读扇区0参数就为0,读扇区1参数就为1<<9(即地址512),读扇区2参数就为2<<9(即地址1024),依此类推。

读单块:

u8 SD_ReadSingleBlock(u32 sector, u8 *buffer){ u8 r1; //高速模式 SPI_SetSpeed(SPI_SPEED_HIGH); if(SD_Type!=SD_TYPE_V2HC)//如果不是SDHC卡 { sector = sector<<9;//512*sector即物理扇区的边界对其地址 } r1 = SD_SendCommand(CMD17, sector, 1);//发送CMD17 读命令 if(r1 != 0x00)return r1; r1 = SD_ReceiveData(buffer, 512, RELEASE);//一个扇区为512字节 if(r1 != 0) return r1; //读数据出错 else return 0; //读取正确,返回0}

读多块:

u8 SD_ReadMultiBlock(u32 sector, u8 *buffer, u8 count){ u8 r1; SPI_SetSpeed(SPI_SPEED_HIGH); if(SD_Type != SD_TYPE_V2HC) { sector = sector<<9; } r1 = SD_SendCommand(CMD18, sector, 1);//读多块命令 if(r1 != 0x00)return r1; do//开始接收数据 { if(SD_ReceiveData(buffer, 512, NO_RELEASE) != 0x00) { break; } buffer += 512; } while(--count); SD_SendCommand(CMD12, 0, 1);//全部传输完成,发送停止命令 SD_CS_DISABLE();//释放总线 SPI_ReadWriteByte(0xFF); if(count != 0) return count; //如果没有传完,返回剩余个数 else return 0;}

写单块和写多块

SD卡用CMD24和CMD25来写单块和多块,参数的定义和读操作是一样的。

忙检测 :SD卡写入数据并自编程时,数据线上读到0x00表示SD卡正忙,当读到0xff表示写操作完成。

u8 SD_WaitReady(void){ u8 r1; u16 retry=0; do { r1 = SPI_ReadWriteByte(0xFF); retry++; if(retry==0xfffe) return 1; }while(r1!=0xFF); return 0;}

写单块流程:

1.发送CMD24,收到0x00表示成功

2.发送若干时钟

3.发送写单块开始字节0xFE

4.发送512个字节数据

5.发送2字节CRC(可以均为0xff)

6.连续读直到读到XXX00101表示数据写入成功

7.继续读进行忙检测(读到0x00表示SD卡正忙),当读到0xff表示写操作完成

u8 SD_WriteSingleBlock(u32 sector, const u8 *data){ u8 r1; u16 i; 16 retry; //高速模式 SPI_SetSpeed(SPI_SPEED_HIGH);//如果不是SDHC卡,将sector地址转为byte地址 if(SD_Type!=SD_TYPE_V2HC) { sector = sector<<9; }//写扇区指令 r1 = SD_SendCommand(CMD24, sector, 0x00); if(r1 != 0x00) {//应答错误,直接返回 return r1; }//开始准备数据传输 SD_CS_ENABLE(); //先发3个空数据,等待SD卡准备好 SPI_ReadWriteByte(0xff); SPI_ReadWriteByte(0xff); SPI_ReadWriteByte(0xff); //放起始令牌0xFE SPI_ReadWriteByte(0xFE); //发一个sector数据 for(i=0;i<512;i++) { SPI_ReadWriteByte(*data++); } //发送2个伪CRC校验 SPI_ReadWriteByte(0xff); SPI_ReadWriteByte(0xff); //等待SD卡应答 r1 = SPI_ReadWriteByte(0xff);//如果为0x05说明数据写入成功 if((r1&0x1F)!=0x05) { SD_CS_DISABLE(); return r1; } //等待操作完成 retry = 0; //卡自编程时,数据线被拉低 while(!SPI_ReadWriteByte(0xff)) { retry++; if(retry>65534) //如果长时间没有写入完成,退出报错 { SD_CS_DISABLE(); return 1; //写入超时,返回1 } } //写入完成,片选置1 SD_CS_DISABLE(); SPI_ReadWriteByte(0xff); return 0;}

写多块流程:

1.发送CMD25,收到0x00表示成功

2.发送若干时钟

3.发送写多块开始字节0xFC

4.发送512字节数据

5.发送两个CRC(可以均为0xff)

6.连续读直到读到XXX00101表示数据写入成功

7.继续读进行忙检测,直到读到0xFF表示写操作完成

8.如果想读下一扇区重复2-7步骤

9.发送写多块停止字节0xFD来停止写操作

10.进行忙检测直到读到0xFF

u8 SD_WriteMultiBlock(u32 sector, const u8 *data, u8 count){ u8 r1; u16 i; SPI_SetSpeed(SPI_SPEED_HIGH); if(SD_Type != SD_TYPE_V2HC) { sector = sector<<9; } if(SD_Type != SD_TYPE_MMC) { //启用ACMD23指令使能预擦除 r1 = SD_SendCommand(ACMD23, count, 0x01); } //写多块指令CMD25 r1 = SD_SendCommand(CMD25, sector, 0x01); //应答不正确,直接返回 if(r1 != 0x00)return r1;//开始准备数据传输 SD_CS_ENABLE();//放3个空数据让SD卡准备好SPI_ReadWriteByte(0xff); SPI_ReadWriteByte(0xff); SPI_ReadWriteByte(0xff); //下面是N个sector循环写入的部分 do { //放起始令牌0xFC,表明是多块写入 SPI_ReadWriteByte(0xFC); //发1个sector的数据 for(i=0;i<512;i++) { SPI_ReadWriteByte(*data++); } //发2个伪CRC SPI_ReadWriteByte(0xff); SPI_ReadWriteByte(0xff); //等待SD卡回应 r1 = SPI_ReadWriteByte(0xff); //0x05表示数据写入成功 if((r1&0x1F)!=0x05) { SD_CS_DISABLE(); return r1; } //检测SD卡忙信号 if(SD_WaitReady()==1) { SD_CS_DISABLE(); //长时间写入未完成,退出 return 1; } } while(--count); //发送传输结束令牌0xFD SPI_ReadWriteByte(0xFD); //等待准备好 if(SD_WaitReady()) { SD_CS_DISABLE(); return 1; } //写入完成,片选置1 SD_CS_DISABLE(); SPI_ReadWriteByte(0xff); //返回count值,如果写完,则count=0,否则count=未写完的sector数 return count; }

SD卡的基本读写程序就是这些,编写的思路就是由最底层的SPI 读写一字节数据的程序作为基本程序,然后根据SD卡不同时序进行相应的组合。

掌握了这个例程的读写SD卡的函数原理,就可以着手运用到FATFS文件系统了。

相关问答

三星i9100g刷机 卡在nand write start!!怎么处理-ZOL问答

先让手机进入线刷模式,手机链接电脑,在电脑上下载完美刷机和对应的固件,开始刷入!我s4经常这样刷那你现在还能进入线刷那个模式么?是一点反应都没...

我的主板BIOS Write Protect没有Disabled为什么?-ZOL问答

baidu_yimeipangz主机箱后面有BIOS写保护开关,在右下角,要关机以后才能拨动.开了以后你再开机,一直按着DEL键,选到有BOOTSEQUENCE之类文字的选项,回车键进去...

写后读与写后写的区别?

"写后读"和"写后写"这两个概念在中文里并不是常见的成语或术语,但我们可以根据字面意思来推测它们的含义,并解释它们之间的区别。1.写后读(写作后的阅读):...

电信卡和移动 卡在 同一手机上,电信卡肿么没有来电提醒-ZOL问答

WIN7DWrite.dll没有在指定的Windows上运行怎么处理8108浏览7回答excel怎么提取后几名数。7233浏览3回答ZOL问答手机问题详情电脑版首页资讯查...

u盘写保护怎么回事-ZOL问答

2.找到HKEY_LOCAL_MACHINE\SYSTEM\ControlSet002\Control和HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\...

怎么将主板的BIOS设置成"禁止写入"?-ZOL问答

一般的机器都是开机按F10进入BIOS页面,有两种方法:第一种方法Boot---BIOSwritepretectionBIOS写保护,默认是disable,可以改成enable,但是如果改完就...

内存卡等级作用?

答:内存卡等级作用是用来恒来内存卡是否能够满足应用使用基本条件的协会认证。1、A1和A2标识认证全称是ApplicationPerformanceClass1和ApplicationPerf...

申请香港某所大学,遇见身份证号相同而不能申请的事,这什么情况?怎么办呢?

有可能是有人用过你的身份去申请大学。香港研究生申请的攻略其实我们的编辑团队已经写过很多版了,有心的同学应该都收藏过。不过我还是很乐意让我们平台的港校...

把手机卡格式化后会怎样?和原本新的会一样吗?我的插到电脑里...

运行regedit进入注册表编辑器,在左侧窗口展开HKEY_LOCAL_MACHINE---->SYSTEM---->CurrentControlSet---->Control---...

【英语翻译Tomgetsonthebustogototown.It'sverycrowded.Hesi...

[回答]汤姆乘车去镇上.他旁边坐着个胖女人,胖女人有很多购物袋,所以汤姆就没有很大的位置空间了.汤姆觉得心里不舒服,最终汽车倒了镇上,所有的乘客开始下...

 东山花灯路  涤纶长丝 
王经理: 180-0000-0000(微信同号)
10086@qq.com
北京海淀区西三旗街道国际大厦08A座
©2025  上海羊羽卓进出口贸易有限公司  版权所有.All Rights Reserved.  |  程序由Z-BlogPHP强力驱动
网站首页
电话咨询
微信号

QQ

在线咨询真诚为您提供专业解答服务

热线

188-0000-0000
专属服务热线

微信

二维码扫一扫微信交流
顶部