51单片机读写SD卡

合集下载
相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Maplead MCU Development Board
21. SD 卡的 SPI 方式读写
SD 卡及其总线结构
SD 卡是日常生活中常见的一种电可擦除移动存储设备,因其存储量大、价 格低廉而被广泛应用于数码相机、手机等数码产品中。

SD 卡支持两种总线方式:SD 方式与 SPI 方式。

其中 SD 方式采用 6 线制, 使用 CLK、CMD、DAT0、DAT1、DAT2、DAT3 进行数据通信,其特点是数据 位数宽(4 位) 、速度快。

SPI 方式采用 4 线制,使用 CS、CLK、DataIn、DataOut 这 4 个端口进行数据通信,其特点是速度要比 SD 方式慢,但总线简单、不需要 进行 CRC 校验,因而比较适合单片机采用这种方式对 SD 卡进行读写操作。


图 21-1 SD 卡及其接口 表 21-1 SD 卡接口定义
端口 1. DAT3/CS 2. CMD/DataIn 3. VSS1 4. VDD 5. CLK/SCK 6. VSS2 7. DAT0/DataOut 8.DAT1 9.DAT2 DAT3 口。

命令/回应。

电源地。

电源。

同步时钟。

电源地。

DAT0 口。

DAT1 口。

DAT2 口。

说明 SD 模式 SPI 模式 片选,低电平有效。

数据输入端。

电源地。

电源。

同步时钟。

电源地。

数据输出端。

NC。

NC。


SD 卡命令格式
SD 卡的命令字由 6 个字节组成,其组成结构见图 21-2。


146



Maplead MCU Development Board
命令字的第 1 个字节为命令号(CMD0、CMD1 等) ,命令号的最高位始终 为 0,次高位(位 7)为 1,表示命令是由主机向 SD 卡发送的命令。

命令字的第 2、3、4、5 字节为命令参数表,传送随命令附带的参数,如地 址信息等。

命令字的最后一个字节为 CRC 校验字节,其中该字节的高 7 位为 CRC 码, 最后一位为结束位,始终为 1。


Byte1* Byte2 Byte3 Byte4 Byte5 Byte6 7 位 CRC
0
1
x
x
x
x
x
x
参数
参数
参数
参数
1
* X 表示该位可以为“0”或者“1”。

图 21-2 SD 卡命令字结构 当主机向 SD 卡发送一个命令后,SD 卡会首先向主机发送一个相应码,如 果指令没有错误 SD 卡接下来便会执行主机发来的命令。


SD 卡复位至 SPI 方式
SD 卡默认的读写方式为 SD 模式, 要使用 SPI 模式对 SD 卡进行读写, 需要 在 SD 卡上电后对 SD 卡写入 CMD0 和 CMD1 命令。

在两条命令写入 SD 卡后, 如果一切正常,SD 卡会进入 SPI 模式,从而可以方便地采用单片机对 SD 卡进 行 SPI 方式的读写操作。


图 21-3 对 SD 卡的复位操作时序 当 SD 卡完成上电后,先对 SD 卡发送 74 个以上的同步时钟。

然后向 SD 卡发送 CMD0 命令(因命令号的最高位始终为 0,次高位为 1, 因此发送给 SD 卡的命令是 0 与 0x40 进行或运算的结果) 。

命令字的第 2、3、4、5 字节皆为 0x00。


147



Maplead MCU Development Board
命令字的第 6 字节为 CRC 校验字节,固定为 0x95。

命令字发送完成后,发送若干个 8 位的同步时钟,直至 SD 卡发出响应字节 0x01。

接收完 SD 卡的响应字节后,CS 线拉高,再发送 8 个空时钟。


图 21-4 将 SD 卡初始化为 SPI 方式时序 当 SD 卡执行完复位过程后,接着向 SD 卡发送初始化指令 SMD1,以激活 SD 卡 SPI 方式。

首先发送指令号 CMD1(0x01|0x40=0x41) ,然后发送 4 个 0x00 字节,最 后发送 CRC 校验码,此处为 0xFF,原因是此时 SD 卡已经工作在 SPI 模式,在 SPI 模式下,SD 卡默认为不进行 CRC 校验,因此我们可以随意写入一个 0xFF 字节以填充满整个命令字的结构。

当向 SD 卡发送完 CMD1 指令后,发送若干个 8 位的同步时钟,直至 SD 卡 发出响应字节 0x00。

接收完 SD 卡的响应字节后,CS 线拉高,再发送 8 个空时钟。

至此,我们完成了 SD 卡的复位及进入到 SPI 方式的所有步骤。


SD 卡的 SPI 方式读写
SD 卡读写一次的数据量必须为 512 字节的整数倍,亦即,对 SD 卡读写操 作的最少数据量为 512 字节。

我们也可以通过向 SD 卡写修改扇区大小的指令 CMD16 以使每次读写的数据量变为(n×512)字节(n≥1) ,本文中我们使用 SD 卡默认的一次操作 512 字节的模式对 SD 卡进行读写操作。


148



Maplead MCU Development Board
对 SD 卡的单数据块读操作:
图 21-5 对 SD 卡进行单数据块读操作时序 如图 21-4 所示,对 SD 卡读操作的时序为: (1) 写入读单数据块命令 CMD17(0x11|0x40=0x51) 。

(2) 写 4 个地址参数,4 个字节凑成一个 32 位的地址值,第一个字节是 32 位地址值的最高 8 位数据,第 4 个字节是 32 位地址值的最低 8 位 数据。

(3) 写 CRC 校验位 0xFF。

(4) 写若干个 0xFF 的空操作。

(5) SD 卡发送 0x00 响应。

(6) 写若干个 0xFF 的空操作。

(7) SD 卡发送 0x FE 数据头。

(8) SD 卡发送指令指定地址的 512 字节数据块。

(9) SD 卡发送两字节的 CRC 校验码,由于 SPI 模式默认不需要 CRC 校 验,因此这两个字节的数据可丢弃不用。

(10)拉高 CS,发送 8 个空时钟。

至此,我们完成了对 SD 卡指定地址数据块的读操作。


149



Maplead MCU Development Board
对 SD 卡的单数据块写操作:
图 21-6 对 SD 卡进行单数据块写操作时序 如图 21-4 所示,对 SD 卡读操作的时序为: (1) 写入读单数据块命令 CMD24(0x18|0x40=0x58) 。

(2) 写 4 个地址参数,4 个字节凑成一个 32 位的地址值,第一个字节是 32 位地址值的最低 8 位数据,第 4 个字节是 32 位地址值的最高 8 位 数据。

(3) 写 CRC 校验位 0xFF。

(4) 写若干个 0xFF 的空操作。

(5) SD 卡发送 0x00 响应。

(6) 写若干个 0xFF 的空操作。

(7) 写 0x FE 数据头,表示接下来要发送 512 字节的数据块。

(8) 写 512 字节数据块。

(9) 写两字节的 0xFF 作为 CRC 校验码的填充字节。

(10)SD 卡发送 xxx00101B 响应码。

(11)在 SD 卡将 512 字节数据向指定地址写完之前,其数据输出断时钟被 拉低。

(12)SD 卡释放数据输出线 DataOut。


150



Maplead MCU Development Board
(13)拉高 CS,发送 8 个空时钟。

至此,我们完成了对 SD 卡指定地址数据块的写操作。


图 21-7
SD 卡电路连接原理图
SD 卡电路连接实物图
图 21-8
SD 卡电路连接实物图
用杜邦线将 P3.4 口连接至 SD 模块的 CLK 端口; 用杜邦线将 P3.5 口连接至 SD 模块的 DI 端口;
151



Maplead MCU Development Board
用杜邦线将 P3.6 口连接至 SD 模块的 DO 端口; 用杜邦线将 P3.7 口连接至 SD 模块的 CS 端口; 将一张 2G 容量以下(2G 以上没有测试过)的 SD 卡插入 SD 卡槽就可以进 行该实验了。


SD 卡 SPI 方式读写演示程序
例程 21-1 SD 卡 SPI 方式读写 /****************************************************************************** * 说明: * (1)晶振 12MHz 调试通过。

* (2)2G 以下 SD 卡 SPI 方式读写驱动程序。

* (3)对 SD 卡操作要以块为单位进行操作(地址为 512 的整数倍;数据量为 512 的整 * 数倍)。

* (4)向 SD 卡中写数据时,尽量避开卡开始部分的地址(本程序数据写入点为 51200 * 地址以后的空间), 不然可能会造成 SD 卡无法识别、 无法格式化等问题(可用 SD * 专用格式化软件解决)! * (5)请确保您的 SD 卡内没有个人资料,不然数据会丢失!!!!!!! !!!!!! * (6)建议采用价格便宜的工厂用测试卡运行本程序,对于运行本程序有可能造成的 * SD 卡损坏等情况,本程序作者及开发板生产销售商不承担任何责任!!! !!! * (7)如果单片机内部的 RAM 不够大,读入的数据块将会部分丢失,但不影响程序的 * 演示 (例如 STC89C52RC 内部的 xdata 空间容量为 256Byte, 当所取数据块超过 * 256 字节时内存溢出,数据丢失。

如果超出存储空间读数据,取出的数据都为 * 0xFF)。

* (8)测试时如果 SD 卡中途无反应,彻底关闭开发板电源,重新启动。

* (9)测试时,先用杜邦线将单片机输出端口与对应的 SD 卡 SPI 接口相连: * P3.4---->SD 卡 SPI 接口的 CLK * P3.5---->SD 卡 SPI 接口的 DI * P3.6---->SD 卡 SPI 接口的 DO * P3.7---->SD 卡 SPI 接口的 CS * 作者:Shenney John ****************************************************************************** * Copyright (C) 2010 by Shenney John, All Rights Reserved. ******************************************************************************/ #include <reg52.h> sbit CLK = P3^4; sbit DI = P3^5; sbit DO = P3^6; sbit CS = P3^7; //时钟线 //数据输入线(相对 SD 卡为输入,单片机刚好相反) //数据输出线(相对 SD 卡为输出,单片机刚好相反) //片选线
void Display(unsigned char ); void SPI_W(unsigned char); unsigned char SPI_R(void); unsigned char SD_Response(void); void SD_Cmd(unsigned char, unsigned long, unsigned char); unsigned char SD_Init(void); unsigned char SD_Block_W(unsigned char, unsigned long, unsigned int); unsigned char * SD_Block_R(unsigned long, unsigned int);
152



Maplead MCU Development Board
unsigned char code LED_Seg[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07, 0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};//数码管段码 unsigned char code LED_Bit[]={0x00, 0x01}; //数码管位码 unsigned char xdata *DATA; //指向数据块的指针
unsigned char code Test_1[]={ //测试数据块 1 0X00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0X0B,0X0C,0X0D,0X0E,0X0F, 0X10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0X1B,0X1C,0X1D,0X1E,0X1F, 0X20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0X2B,0X2C,0X2D,0X2E,0X2F, 0X30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0X3B,0X3C,0X3D,0X3E,0X3F, 0X40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0X4B,0X4C,0X4D,0X4E,0X4F, 0X50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0X5B,0X5C,0X5D,0X5E,0X5F, 0X60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0X6B,0X6C,0X6D,0X6E,0X6F, 0X70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0X7B,0X7C,0X7D,0X7E,0X7F, 0X80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0X8B,0X8C,0X8D,0X8E,0X8F, 0X90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0X9B,0X9C,0X9D,0X9E,0X9F,
0XA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0XAB,0XAC,0XAD,0XAE,0XAF, 0XB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0XBB,0XBC,0XBD,0XBE,0XBF, 0XC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0XCB,0XCC,0XCD,0XCE,0XCF, 0XD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0XDB,0XDC,0XDD,0XDE,0XDF, 0XE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0XEB,0XEC,0XED,0XEE,0XEF,
0XF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0XFB,0XFC,0XFD,0XFE,0XFF, 0X00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0X0B,0X0C,0X0D,0X0E,0X0F, 0X10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0X1B,0X1C,0X1D,0X1E,0X1F, 0X20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0X2B,0X2C,0X2D,0X2E,0X2F, 0X30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0X3B,0X3C,0X3D,0X3E,0X3F, 0X40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0X4B,0X4C,0X4D,0X4E,0X4F, 0X50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0X5B,0X5C,0X5D,0X5E,0X5F, 0X60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0X6B,0X6C,0X6D,0X6E,0X6F, 0X70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0X7B,0X7C,0X7D,0X7E,0X7F, 0X80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0X8B,0X8C,0X8D,0X8E,0X8F, 0X90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0X9B,0X9C,0X9D,0X9E,0X9F,
0XA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0XAB,0XAC,0XAD,0XAE,0XAF, 0XB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0XBB,0XBC,0XBD,0XBE,0XBF, 0XC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0XCB,0XCC,0XCD,0XCE,0XCF, 0XD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0XDB,0XDC,0XDD,0XDE,0XDF, 0XE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0XEB,0XEC,0XED,0XEE,0XEF,
0XF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0XFB,0XFC,0XFD,0XFE,0XFF, }; unsigned char code Test_2[]={ //测试数据块 2 0X00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0X0B,0X0C,0X0D,0X0E,0X0F, 0X10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0X1B,0X1C,0X1D,0X1E,0X1F, 0X20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0X2B,0X2C,0X2D,0X2E,0X2F, 0X30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0X3B,0X3C,0X3D,0X3E,0X3F, 0X40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0X4B,0X4C,0X4D,0X4E,0X4F, 0X50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0X5B,0X5C,0X5D,0X5E,0X5F, 0X60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0X6B,0X6C,0X6D,0X6E,0X6F, 0X70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0X7B,0X7C,0X7D,0X7E,0X7F, 0X80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0X8B,0X8C,0X8D,0X8E,0X8F, 0X90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0X9B,0X9C,0X9D,0X9E,0X9F,
0XA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0XAB,0XAC,0XAD,0XAE,0XAF, 0XB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0XBB,0XBC,0XBD,0XBE,0XBF, 0XC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0XCB,0XCC,0XCD,0XCE,0XCF, 0XD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0XDB,0XDC,0XDD,0XDE,0XDF, 0XE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0XEB,0XEC,0XED,0XEE,0XEF,
153



Maplead MCU Development Board
0XF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0XFB,0XFC,0XFD,0XFE,0XFF, 0X00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0X0B,0X0C,0X0D,0X0E,0X0F, 0X10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0X1B,0X1C,0X1D,0X1E,0X1F, 0X20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0X2B,0X2C,0X2D,0X2E,0X2F, 0X30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0X3B,0X3C,0X3D,0X3E,0X3F, 0X40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0X4B,0X4C,0X4D,0X4E,0X4F, 0X50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0X5B,0X5C,0X5D,0X5E,0X5F, 0X60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0X6B,0X6C,0X6D,0X6E,0X6F, 0X70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0X7B,0X7C,0X7D,0X7E,0X7F, 0X80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0X8B,0X8C,0X8D,0X8E,0X8F, 0X90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0X9B,0X9C,0X9D,0X9E,0X9F,
0XA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0XAB,0XAC,0XAD,0XAE,0XAF, 0XB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0XBB,0XBC,0XBD,0XBE,0XBF, 0XC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0XCB,0XCC,0XCD,0XCE,0XCF, 0XD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0XDB,0XDC,0XDD,0XDE,0XDF, 0XE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0XEB,0XEC,0XED,0XEE,0XEF,
0XF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0XFB,0XFC,0XFD,0XFE,0XFF, }; void main(void) { unsigned int i=0,j; unsigned long const Lenth=512; SD_Init(); SD_Block_W( Test_1, Lenth*100 , Lenth ); SD_Block_W( Test_2, Lenth*100+512, Lenth );
//数据块长度 //SD 卡初始化 //往地址 51200 处写测试数组 1 //往地址(51200+512)处写测试数组 2
DATA=SD_Block_R( Lenth*100, Lenth ); //从地址 51200 处读测试数组 1,存于 DATA 中 // DATA=SD_Block_R( Lenth*100+512, Lenth ); //从地址(51200+512)处读测试数组 2,存于 DATA 中 while(1) { for(i=0;i<512;i++)//STC89C52RC 单片机 256 个以后的数据都为 0xFF(内存溢出, 数 { //字重影表明单片机正在试图用 P0,P2 口输出地址并读外部 RAM 数据 for(j=0;j<150;j++) Display(DATA[i]); //循环显示数组中的元素 } } } /**************************************** * 显示函数 *****************************************/ void Display(unsigned char Num) { unsigned char First_Bit, Second_Bit, i; First_Bit =Num%16; Second_Bit=Num/16; P0=0x00; P2=LED_Bit[0]; //取出 16 进制低位 //取出 16 进制高位 //清数码管显示
154



Maplead MCU Development Board
P0=LED_Seg[First_Bit]; for(i=0;i<200;i++); P0=0x00; P2=LED_Bit[1]; P0=LED_Seg[Second_Bit]; for(i=0;i<200;i++); P0=0x00; } //显示 16 进制低位
//显示 16 进制高位
/********************************* * SPI 写函数 **********************************/ void SPI_W(unsigned char Data) { unsigned char i; for(i=0;i<8;i++) { Data<<=1; CLK =0; DI =CY; CLK =1; } DI=1; } /********************************* * SPI 读函数 *********************************/ unsigned char SPI_R(void) { unsigned char Data,i; DO=1; for(i=0;i<8;i++) { Data <<=1; CLK =0; CLK =1; Data|=DO; } return Data; } /********************************* * 读 SD 卡回应 *********************************/ unsigned char SD_Response() {
155
//最高位移入 CY 位中
//将 DO 口设置为输入状态(对单片机而言是输入口)



Maplead MCU Development Board
unsigned char i,Response; for(i=0;i<10;i++) { Response = SPI_R(); if(Response==0x00) break; if(Response==0x01) break; } return Response; } /********************************* * 向 SD 卡写命令 *********************************/ void SD_Cmd(unsigned char Cmd, unsigned long Argument, unsigned char CRC) { unsigned char arg[4]; arg[0]=( unsigned char) Argument; arg[1]=( unsigned char)(Argument>>8); arg[2]=( unsigned char)(Argument>>16); arg[3]=( unsigned char)(Argument>>24); SPI_W(Cmd|0x40); SPI_W(arg[3]); SPI_W(arg[2]); SPI_W(arg[1]); SPI_W(arg[0]); SPI_W(CRC); } /********************************* * SD 卡初始化 *********************************/ unsigned char SD_Init(void) { unsigned int delay=0, trials=0; unsigned char i; unsigned char Response=0xFF; CS=1; for(i=0;i<10;i++) SPI_W(0xFF); CS=0; SD_Cmd(0x00,0,0x95); i=0; while(SD_Response()!=0x01) { i++; if(i>=100) return 0; } //SD 命令为:(命令号|0x40)
//上电后给 74 个以上的时钟脉冲 //CMD0:复位 SD 卡,CRC 码固定为 0x95 //等待卡回应信号 0x01
//失败返回 0
156



Maplead MCU Development Board
CS=1; SPI_W(0xff); //关片选后写 8 个空脉冲,SD 卡复位完毕 i=0; CS=0; while(Response!=0x00) //循环等待初始化成功回应,若成功回应信号为 0x00 { SD_Cmd(0x01,0,0xff); //CMD1:将 SD 卡置为 SPI 模式,无需 CRC 校验,填入 0xFF Response=SD_Response(); i++; if(i>100) //尝试 100 次 return 0; //失败返回 0 } CS=1; SPI_W(0xff); return 1; } /********************************* * SD 卡数据块写入 *********************************/ unsigned char SD_Block_W(unsigned char *Block, unsigned long address, unsigned int len) { unsigned int i; unsigned char Response_Write; P1=0xff; CS=0; SD_Cmd(0x18,address,0xFF); //CMD18:块写入命令;address 为要写入块的地址(512 整数倍) while(SD_Response()!=0x00); for(i=0;i<10;i++) SPI_W(0xFF); //循环等待命令回应 0x00 //写入一定量的空脉冲 //给 8 个空脉冲 //成功返回 1
SPI_W(0xFE); //0xFE 为块写入的头,后面紧跟 512 字节的块数据+2 字节的 CRC 码(0xFF,0xFF) for(i=0;i<len;i++) //写入 512Byte 数据 SPI_W(Block[i]); SPI_W(0xFF); //两字节 CRC 校验 SPI_W(0xFF); Response_Write=SPI_R()&0x0f; //写入 CRC 码后,SD 卡会回应一个(xxx0 0101) while(SPI_R()==0); //等待卡数据写入回应 CS=1; SPI_W(0xFF); if(Response_Write==0x05) return 1; else return 0; }
157
//写入 8 个空脉冲



Maplead MCU Development Board
/********************************* * 从 SD 卡读数据块 *********************************/ unsigned char * SD_Block_R(unsigned long address, unsigned int len) { unsigned int i; unsigned char xdata Block[512]; CS=0; SD_Cmd(0x11,address,0xff); //CMD11:数据块读命令;address 为要读块的地址(512 整数倍) while(SD_Response()!=0x00); //循环等待命令回应 0x00 while(SPI_R()!=0xfe); //0xFE 为块读出的头,后面紧跟 512 字节的块数据+2 字节的 CRC 码 for(i=0;i<len;i++) Block[i]=SPI_R(); SPI_R(); SPI_R(); CS=1; SPI_R(); return Block; } //读出 512Byte 数据 //两个 CRC 校验字节,丢弃
//8 个空脉冲 //返回数据块
158
















相关文档
最新文档