【分享】51单片机读写SD/TF卡测试程序
本帖最后由 分立元件 于 2020-11-14 15:35 编辑测试2G和2G以下的TF卡可以使用,4G和8G的卡不能使用,不容易找了几天:L
#include<reg52.h>
//替换关键字
typedef unsigned long u32;
typedef unsigned char u8;
typedef unsigned int u16;
//接口定义
sbit SD_CS = P1^0;
sbit SPI_MOSI = P1^2;
sbit SPI_MISO = P1^3;
sbit SPI_CLK = P1^1;
//测试平台:STC89C516和STC12C5A60S2
//内存卡大小:128MB和2GB
//晶振:均为12MHz
//定义512字节数据缓冲区
u8 xdata BUFFER_DATA={0};
//使用位操作加快SPI读写速度
u8 bdata Byte_data;
sbit Byte_data7=Byte_data^7;
sbit Byte_data6=Byte_data^6;
sbit Byte_data5=Byte_data^5;
sbit Byte_data4=Byte_data^4;
sbit Byte_data3=Byte_data^3;
sbit Byte_data2=Byte_data^2;
sbit Byte_data1=Byte_data^1;
sbit Byte_data0=Byte_data^0;
//SPI写入一个字节(字节数据)
void SPI_write_Byte(u8 Byte)
{
SPI_MOSI=1;
Byte_data=Byte;
SPI_CLK=0;SPI_MOSI=Byte_data7;SPI_CLK=1;
SPI_CLK=0;SPI_MOSI=Byte_data6;SPI_CLK=1;
SPI_CLK=0;SPI_MOSI=Byte_data5;SPI_CLK=1;
SPI_CLK=0;SPI_MOSI=Byte_data4;SPI_CLK=1;
SPI_CLK=0;SPI_MOSI=Byte_data3;SPI_CLK=1;
SPI_CLK=0;SPI_MOSI=Byte_data2;SPI_CLK=1;
SPI_CLK=0;SPI_MOSI=Byte_data1;SPI_CLK=1;
SPI_CLK=0;SPI_MOSI=Byte_data0;SPI_CLK=1;
SPI_MOSI=1;
}
//SPI读取一个字节(返回值为数据)
u8 SPI_read_Byte()
{
SPI_MISO=1;
SPI_CLK=0;Byte_data7=SPI_MISO;SPI_CLK=1;
SPI_CLK=0;Byte_data6=SPI_MISO;SPI_CLK=1;
SPI_CLK=0;Byte_data5=SPI_MISO;SPI_CLK=1;
SPI_CLK=0;Byte_data4=SPI_MISO;SPI_CLK=1;
SPI_CLK=0;Byte_data3=SPI_MISO;SPI_CLK=1;
SPI_CLK=0;Byte_data2=SPI_MISO;SPI_CLK=1;
SPI_CLK=0;Byte_data1=SPI_MISO;SPI_CLK=1;
SPI_CLK=0;Byte_data0=SPI_MISO;SPI_CLK=1;
SPI_MISO=1;
return Byte_data;
}
//检测SD卡的响应
u8 SD_response()
{
u8 i;
u8 response;
for(i=0;i<9;++i)
{
response=SPI_read_Byte();
if((response==0x00)||(response==0x01)) break;
}
return response;
}
//MCU向SD卡写入命令
void MCU_write_SD_command(u8 command,u32 argument,u8 CRC)
{
SPI_write_Byte(command|0x40);
SPI_write_Byte(((u8 *)&argument));
SPI_write_Byte(((u8 *)&argument));
SPI_write_Byte(((u8 *)&argument));
SPI_write_Byte(((u8 *)&argument));
SPI_write_Byte(CRC);
}
//SD卡初始化
u8 SD_init()
{
u8 i;
u8 response=0x01;
SD_CS=1;
for(i=0;i<10;++i) SPI_write_Byte(0xFF);
SD_CS=0;
MCU_write_SD_command(0x00,0x00000000,0x95);//发送命令0将MMC置于SPI模式
response=SD_response();
if(response!=0x01) return 0;
while(response)
{
SD_CS=1;
SPI_write_Byte(0xFF);
SD_CS=0;
MCU_write_SD_command(0x01,0x00FFC000,0xFF);
response=SD_response();
}
SD_CS=1;
SPI_write_Byte(0xFF);
return 1;
}
//MCU向SD卡写入数据,一次最多512字节(扇区,数据长度(最大为512,建议填512))
u8 MCU_write_SD_512Byte(u32 block,u16 data_length)
{
u16 i;
u8 *block_data_pointer;//扇区数据指针
u8 dataResp;
block_data_pointer=BUFFER_DATA;//指针指向缓冲数据
SD_CS=0;
MCU_write_SD_command(0x18,512*block,0xFF);//发送写入命令
if(!SD_response())
{
SPI_write_Byte(0xFF);
SPI_write_Byte(0xFF);
SPI_write_Byte(0xFF);
//命令成功-现在MCU向SD卡写入数据
SPI_write_Byte(0xFE);//数据将在发送0xFE后开始写入
//现在MCU向SD卡写入数据
for(i=0;i<data_length;++i)
{
SPI_write_Byte(*block_data_pointer);
++block_data_pointer;
}
for(;i<512;++i) SPI_write_Byte(0x00);
//数据块发送-现在发送校验和
SPI_write_Byte(0xFF);//两字节CRC校验,为0XFFFF,不考虑CRC
SPI_write_Byte(0xFF);
dataResp=SPI_read_Byte();//现在读取数据响应
//在数据响应之后是一个繁忙的字节数,一个零字节表示MMC忙
while(!SPI_read_Byte());
dataResp=dataResp&0x0F; //屏蔽数据响应令牌的高字节
SD_CS=1;
SPI_write_Byte(0xFF);
if(dataResp==0x0B) return 0;//数据不被CARD接受
if(dataResp==0x05) return 1;//无效的数据响应
return 0;
}
//写入命令0x18没有被MMC接收
return 0;
}
//MCU向SD卡读取数据,一次最多512字节(扇区,数据长度(最大为512,建议填512))
u8 MCU_read_SD_512Byte(u32 block,u16 data_length)
{
u16 i;
u8 *block_data_pointer;//扇区数据指针
block_data_pointer=BUFFER_DATA;//指针指向缓冲数据
SD_CS=0;
MCU_write_SD_command(0x11,512*block,0xFF);//然后发送写命令
if(!SD_response())
{
while(SPI_read_Byte()!=0xFE);//发送命令成功,现在发送数据,数据在接收0xFE之后
for(i=0;i<data_length;++i)
{
*block_data_pointer=SPI_read_Byte();
++block_data_pointer;
}
for(;i<512;++i) SPI_read_Byte();
//数据块发送-现在发送校验和
SPI_read_Byte();
SPI_read_Byte();
//现在读入数据响应
SD_CS=1;
SPI_read_Byte();
return 1;
}
//读命令0x11没有被MMC的接收
return 0;
}
void main()
{
unsigned int i;
SD_init();//SD卡初始化
for(i=0;i<512;++i)
BUFFER_DATA=0x7F;
MCU_write_SD_512Byte(960,512);//MCU向SD卡写入数据,一次最多512字节(扇区,数据长度(最大为512,建议填512))
for(i=0;i<512;++i) //清零数组,准备接收SD卡数据
BUFFER_DATA=0;
MCU_read_SD_512Byte(960,512);//MCU向SD卡读取数据,一次最多512字节(扇区,数据长度(最大为512,建议填512))
P0=BUFFER_DATA;
while(1);
}
/*
unsigned int i;
SD_init();//SD卡初始化
{
在使用SD卡模块前,先初始化SD卡
}
for(i=0;i<512;++i) BUFFER_DATA=0x7F;
MCU_write_SD_512Byte(960,512);//MCU向SD卡写入数据,一次最多512字节(扇区,数据长度(最大为512,建议填512))
{
将数据写入到SD卡:
先将数据写入到数据缓冲数组BUFFER_DATA中(这里的数据我全部都写0x7F),
然后运行MCU_write_SD_512Byte(960,512);
960为SD卡的扇区,表示将数据写入到SD卡的960扇区,512为一次性写入的数据大小,为512字节,建议填512字节,
因为1个扇区的大小为512字节
}
MCU_read_SD_512Byte(960,512);//MCU向SD卡读取数据,一次最多512字节(扇区,数据长度(最大为512,建议填512))
P0=BUFFER_DATA;
{
从SD卡读取数据:
先运行MCU_read_SD_512Byte(960,512);
这里的960为你要读的SD扇区,512位一次性读取的数据大小,为512字节,建议填512字节,因为1个扇区的大小为512字节
完成后数据存放在数据缓冲数组BUFFER_DATA中
因为没有现象的话不好判断SD卡读写是否成功,所以把P0BUFFER_DATA赋给P0,P0接LED灯,就可以看见现象了
}
{
注意:将程序下载到开发板后可能会出现P0口显示的数据和SD卡写入数据不一致的情况
这时,
要将开发板和SD卡模块断电
要将开发板和SD卡模块断电
要将开发板和SD卡模块断电
不是复位
不是复位
不是复位
将开发板断电后再上电,就可以看见现象了
如果还不成功,
检查连线是否正确
检查连线是否正确
检查连线是否正确
或尝试插拔SD卡
SD卡读写成功后,可以修改扇区和SD的写入数据多实验几次,确保万无一失
}
*/
本帖最后由 iffi123 于 2020-11-14 20:29 编辑
网上很多程序,针对1.x版本的tf/sd卡, 通过CMD0进入空闲状态,然后发送CMD1进行初始化
而2.0(大于4G容量)需改成CMD8初始化,我是用16G卡做试验 iffi123 发表于 2020-11-14 20:28
网上很多程序,针对1.x版本的tf/sd卡, 通过CMD0进入空闲状态,然后发送CMD1进行初始化
而2.0(大于4G容量 ...
这样额,我试试看!谢谢啦 iffi123 发表于 2020-11-14 20:28
网上很多程序,针对1.x版本的tf/sd卡, 通过CMD0进入空闲状态,然后发送CMD1进行初始化
而2.0(大于4G容量 ...
刚才试了一下原来的4G和8G内存卡,把CDM1改CDM8(0X48,0X000001AA,0X78),也不能正常工作,用我新买的4G内存卡居然可以在CDM1下正常工作,好奇怪?
本帖最后由 t3486784401 于 2020-11-15 01:22 编辑
我看了 Arduino 的 SD 库(4G/8G 都支持),的确提到了通过 CMD8 来区分 SD1 和 SD2 类型的卡。
但是 CMD8 的数据 CRC 校验是 0x87,与 LZ 在 4L 提到的不符,望确认。
Arduino 库里 CMD8 发送的是: 0x48, 0x1AA, 0x87
附上源码截图:
------------------------------------------------------------------------------------------------------
Arduino 的库直接在 FAT 层面搞的,底层平时都没咋看过 本帖最后由 iffi123 于 2020-11-15 08:09 编辑
分立元件 发表于 2020-11-15 00:39
刚才试了一下原来的4G和8G内存卡,把CDM1改CDM8(0X48,0X000001AA,0X78),也不能正常工作,用我新买的4G内 ...
SD规范对初始化的流程, 图看起来比较杂
昨天我回复时疏忽了,CMD8是识别卡是否支持2.0的,
如果支持,后续真正初始化是ACMD41, 执行成功后,卡就进入ready状态,可以正常读写操作, 此时若再发送CMD58,可进一步识别是否是大容量卡;
不支持CMD8的话,就是1.x卡,改用CMD1初始化(手上没有小于4G卡,自己未试过CMD1)
t3486784401 发表于 2020-11-15 01:21
我看了 Arduino 的 SD 库(4G/8G 都支持),的确提到了通过 CMD8 来区分 SD1 和 SD2 类型的卡。
但是 CMD8 ...
不好意思是我打错数字了,87写成78了!
页:
[1]