2018-08-19 01:03:17 HeGuang68207 阅读数 1846
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3414 人正在学习 去看看 朱有鹏

SD卡(Secure Digital Memory Card):

又叫安全数码卡,是一种基于半导体闪存工艺的存储卡,被广泛应用于便携式电子设备。
SD卡已成为目前消费数码设备中应用最广泛的一种存储卡,具有大容量、高性能、安全等多种特点。

今天小楊就来试验一下通过单片机读写SD卡。
实验材料
1、普通PC一台;
2、SD/TF卡至少一张(推荐2GB以内);
3、禾灮Young_SD读卡模块一块,配原理图;
4、普通读卡器一个;
5、禾灮Young_AVR智能机器人控制板一块(兼容Arduino代码)(附Atmel官方MCU说明书一份)。
5、杜邦线若干。

读卡模块原理图

当然了,发烟测试第一步,通过最简单的代码实现功能:

Arduino代码:

/*
***此例子展示记录串口输入数据到SD卡
* SD卡与控制板使用SPI总线连接
** MOSI - pin 11
** MISO - pin 12
** CLK  - pin 13
** CS   - pin 4
*/

#include <SD.h>

const int chipSelect = 4;  //设定CS引脚为D4,这里也沿用官方默认设置

void setup(){
    Serial.begin(9600);  //设置串口通信波特率为9600
    Serial.print("Initializing SD card...");  //串口输出数据Initializing SD card...
    if (!SD.begin(chipSelect)) {  //如果从CS口与SD卡通信失败,串口输出信息Card failed, or not present
        Serial.println("Card failed, or not present");
        return;
    }
    Serial.println("card initialized.");  //与SD卡通信成功,串口输出信息card initialized.
}

void loop(){
    String dataString = Serial..readStringUntil("\n");

    // 打开文件,注意在同一时间只能有一个文件被打开
    // 如果你要打开另一个文件,就需要先关闭前一个
    File dataFile = SD.open("datalog.txt", FILE_WRITE);  

    // 打开datalog.txt文件,读写状态,位置在文件末尾。
    if (dataFile) {
        dataFile.println(dataString);
        dataFile.close();
        // 数组dataString输出到串口
        // Serial.println(dataString);
    }else {  // 如果无法打开文件,串口输出错误信息error opening datalog.txt
        Serial.println("error opening datalog.txt");
    } 
}

关闭开发板电源后把SD卡取出并接入电脑。可以看到SD卡中有一个datalog.txt文件,打开后有可以看到,此文件中的信息就是记录下的串口输入数据。

/*
***这个例子展示从SD卡中读取一个文件,并且把数据通过串口发送
*/

#include <SD.h>

const int chipSelect = 4;  //设定CS接口

void setup(){
  Serial.begin(9600);  //设置串口通信波特率为9600
  Serial.print("Initializing SD card...");  //串口输出数据Initializing SD card...

  if (!SD.begin(chipSelect)) {  //如果从CS口与SD卡通信失败,串口输出信息Card failed, or not present
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");  //与SD卡通信成功,串口输出信息card initialized.

  File dataFile = SD.open("datalog.txt");  //打开datalog.txt文件

  if (dataFile) {
    while (dataFile.available()) {  //检查是否dataFile是否有数据
      Serial.write(dataFile.read());  //如果有数据则把数据发送到串口
    }
    dataFile.close();  //关闭dataFile
  }else {
    Serial.println("error opening datalog.txt");  //如果文件无法打开串口发送信息error opening datalog.txt
  } 
}

void loop(){
}

可以看到,datalog.txt文件中的数据都通过串口发送回了电脑。

/*
***此例子展示如何在SD卡中创建于删除文件
*/
#include <SD.h>
File myFile;
void setup(){
  Serial.begin(9600);  //设置串口通信波特率为9600
  Serial.print("Initializing SD card...");  //串口输出数据Initializing SD card...

  if (!SD.begin(4)) {  //如果从CS口与SD卡通信失败,串口输出信息initialization failed!
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");  //CS口与SD卡通信成功,串口输出信息initialization done.

  if (SD.exists("example.txt")) {  //检查example.txt文件是否存在
    Serial.println("example.txt exists.");  //如果存在输出信息example.txt exists.至串口
  }else {
    Serial.println("example.txt doesn't exist.");  //不存在输出信息example.txt doesn't exist.至串口
  }
  Serial.println("Creating example.txt...");
  myFile = SD.open("example.txt", FILE_WRITE);  //打开example.txt,如果没有自动创建,写入状态
  myFile.close();  //关闭文件
  if (SD.exists("example.txt")) {
    Serial.println("example.txt exists.");
  }else {
    Serial.println("example.txt doesn't exist.");  
  }
  Serial.println("Removing example.txt...");
  SD.remove("example.txt");  //删除文件example.txt
  if (SD.exists("example.txt")){ 
    Serial.println("example.txt exists.");
  }else {
    Serial.println("example.txt doesn't exist.");  
  }
}

void loop(){
}
串口监视器显示文件创建于删除的过程。
#include <SD.h>

File myFile;

void setup(){
  Serial.begin(9600);
  Serial.print("Initializing SD card...");

  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
  myFile = SD.open("test.txt", FILE_WRITE);

  if (myFile) {
    Serial.print("Writing to test.txt...");
    myFile.println("testing 1, 2, 3.");
    myFile.close();
    Serial.println("done.");
  } else {
    Serial.println("error opening test.txt");
  }

  myFile = SD.open("test.txt");
  if (myFile) {
    Serial.println("test.txt:");    
    while (myFile.available()) {
            Serial.write(myFile.read());
    }
    myFile.close();
  } else {
    Serial.println("error opening test.txt");
  }
}

void loop(){
}

感谢一直关注着禾灮成长进步的朋友们。你们的信任、支持和鼓励,鞭策着我们一路走到了今天。

感谢所有的合作伙伴,我们相互促进,共同见证了彼此的成长。

感谢所有曾经在禾灮彼此倚靠、相互鼓励、携手同心、砥砺同行的兄弟姐妹。这里承载了我们的青春与热血。

            禾灮,感谢有你。

未来,我们将一如既往,砥砺前行。

                                    禾灮·小楊
                                   2018.08.16
2014-09-27 17:15:23 sparkstrike 阅读数 4683
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3414 人正在学习 去看看 朱有鹏

单片机:STC12C5A60S2 晶振:24MHZ

51单片机读sd卡资料:http://download.csdn.net/detail/sparkstrike/7982195

sd卡引脚



一.IO接口

sbit CLK = P3^4;//同步时钟
sbit DI = P3^5;//Cmd/DataIn
sbit DO = P3^6;//DataOut
sbit CS = P3^7;//片选



二.模拟SPI

注:spi相关见http://blog.csdn.net/sparkstrike/article/details/39609235

//***********模拟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(){
	unsigned char Data,i;
	DO = 1;//设置DO接口为输入状态
	for(i = 0; i<8; i++){
		Data <<= 1;
		CLK = 0;
		CLK = 1;
		Data |= DO;
	};
	return Data;
}

三.等待SD卡的回应(在写入一些命令后,sd卡会回应一些东西)

//**************读sd卡回应
unsigned char SD_Response(){
	unsigned char i,Response;
	for(i = 0; i<10; i++){
		Response = SPI_R();
		if(Response == 0x00)
			break;
		if(Response == 0x01)
			break;
	};
	return Response;
}


四.向sd卡写入命令

Cmd为命令,命令有复位命令、读命令、写命令等,4位的Arguement为地址,CRC为校验码

//***************向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卡

SD卡有两种读写模式:SD模式和SPI模式,默认的读写模式为SD模式,单片机用SPI模式比较方便,要使用SPI模式需要在SD卡上电是对它写入CMD0命令和CMD1命令

/*************SD卡初始化,设置SPI模式
unsigned char SD_Init(){
	unsigned int delay = 0;
	unsigned char i;
	unsigned char Response = 0xff;
	
	CS = 1;
	for(i = 0; i<10; i++){
		SPI_W(0xff);//上电后给74个以上的时间脉冲
	};

	CS = 0;
	SD_Cmd(0x00, 0, 0x95);//命令CMD0,复位SD卡

	//等待复位成功
	i = 0;
	while(SD_Response() != 0x01){//等待SD卡回应信号
		i++;
		if(i > 100){
			return 0;//失败返回0
		};
	};

	CS = 1;
	SPI_W(0xff);//关片选后写8个空脉冲,SD卡复位完毕

	//设置SPI
	i = 0;
	CS = 0;
	while(Response != 0x00){//循环等待成功回应,若成功,回应信号为0x00
		SD_Cmd(0x01, 0, 0xff);//CMD1,将SD卡设置为SPI模式,无需CRC校验,填入0xff
		Response = SD_Response();
		if(i > 100){
			return 0;//尝试100次,失败返回0
		};
	};
	CS = 1;

	SPI_W(0xff);//给8个空脉冲
	return 1;
}


六.SD卡读写数据

因为sd卡的读写都是以扇区为单位的,所以这里定义一个全局变量,512表示一个扇区

unsigned int const len = 512;//扇区大小


1.写入数据:

adress为开始写的地址,一定要为512的整数倍,block为一个512字节的数组

//***************SD卡写入数据块
unsigned char SD_Block_W(unsigned char* block, unsigned long address){
	unsigned int i;
	unsigned char Response_Write;
	CS =0;
	SD_Cmd(0x18, address, 0xff);//CMD18,块写入命令
	while(SD_Response() != 0x00);//循环等待命令回应0x00
	for(i = 0; i<10; i++){
		SPI_W(0xff);//写入一定量空脉冲
	};

	SPI_W(0xfe);//0xfe为块头部,后面跟512b字节,+2bCRC(0xff,0xff)

	for(i=0; i<len; i++){
		SPI_W(block[i]);//写入512b字节
	};

	SPI_W(0xff);
	SPI_W(0xff);

	Response_Write = SPI_R()&0x0f;//写入CRC码后SD卡会回应一个xxx0,1001
	while(SPI_R() == 0);//等待SD卡回应

	CS = 1;
	SPI_W(0xff);//写入8个空脉冲

	if(Response_Write == 0x05){
		return 1;
	}else{
		return 0;
	};
}

2.读数据:

adress为开始读的地址,一定要为512的整数倍,block为一个512字节的数组

//****************从sd卡读数据块
void SD_Block_R(unsigned char* block, unsigned long address){
	unsigned int i;

	CS = 0;
	SD_Cmd(0x11, address, 0xff);//CMD11,数据块读写命令,

	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();//两个字节的CRC。舍弃

	CS =1;
	SPI_R();//8个空脉冲
}

附:测试程序(程序从SD卡512000处写入512字节的数据,并读出)

/*********************************************************************************************/


#include <STC12C5A60S2.H> //单片机头文件

sbit CLK = P3^4;//同步时钟
sbit DI = P3^5;//Cmd/DataIn
sbit DO = P3^6;//DataOut
sbit CS = P3^7;//片选

unsigned int const len = 512;//扇区大小

void DELAY_MS (unsigned int a){
	unsigned int i;
	while( --a != 0){
		for(i = 0; i < 600; i++);
	}
}



//***********模拟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(){
	unsigned char Data,i;
	DO = 1;//设置DO接口为输入状态
	for(i = 0; i<8; i++){
		Data <<= 1;
		CLK = 0;
		CLK = 1;
		Data |= DO;
	};
	return Data;
}


//**************读sd卡回应
unsigned char SD_Response(){
	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(){
	unsigned int delay = 0;
	unsigned char i;
	unsigned char Response = 0xff;
	
	CS = 1;
	for(i = 0; i<10; i++){
		SPI_W(0xff);//上电后给74个以上的时间脉冲
	};

	CS = 0;
	SD_Cmd(0x00, 0, 0x95);//命令CMD0,复位SD卡

	//等待复位成功
	i = 0;
	while(SD_Response() != 0x01){//等待SD卡回应信号
		i++;
		if(i > 100){
			return 0;//失败返回0
		};
	};

	CS = 1;
	SPI_W(0xff);//关片选后写8个空脉冲,SD卡复位完毕

	//设置SPI
	i = 0;
	CS = 0;
	while(Response != 0x00){//循环等待成功回应,若成功,回应信号为0x00
		SD_Cmd(0x01, 0, 0xff);//CMD1,将SD卡设置为SPI模式,无需CRC校验,填入0xff
		Response = SD_Response();
		if(i > 100){
			return 0;//尝试100次,失败返回0
		};
	};
	CS = 1;

	SPI_W(0xff);//给8个空脉冲
	return 1;
}


//***************SD卡写入数据块
unsigned char SD_Block_W(unsigned char* block, unsigned long address){
	unsigned int i;
	unsigned char Response_Write;
	CS =0;
	SD_Cmd(0x18, address, 0xff);//CMD18,块写入命令
	while(SD_Response() != 0x00);//循环等待命令回应0x00
	for(i = 0; i<10; i++){
		SPI_W(0xff);//写入一定量空脉冲
	};

	SPI_W(0xfe);//0xfe为块头部,后面跟512b字节,+2bCRC(0xff,0xff)

	for(i=0; i<len; i++){
		SPI_W(block[i]);//写入512b字节
	};

	SPI_W(0xff);
	SPI_W(0xff);

	Response_Write = SPI_R()&0x0f;//写入CRC码后SD卡会回应一个xxx0,1001
	while(SPI_R() == 0);//等待SD卡回应

	CS = 1;
	SPI_W(0xff);//写入8个空脉冲

	if(Response_Write == 0x05){
		return 1;
	}else{
		return 0;
	};
}

//****************从sd卡读数据块
void SD_Block_R(unsigned char* block, unsigned long address){
	unsigned int i;

	CS = 0;
	SD_Cmd(0x11, address, 0xff);//CMD11,数据块读写命令,

	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();//两个字节的CRC。舍弃

	CS =1;
	SPI_R();//8个空脉冲
}



void main (void){
	unsigned char xdata block[len];
	int i;
	//初始化SD卡
	SD_Init();
	for(i=0;i<512;i++){
		block[i]=0xaa;
	};
	//从512000处写sd卡
	SD_Block_W(block, len*1000);
	//从512000处读sd卡
	SD_Block_R(block, len*1000);
	
}





2017-10-22 09:32:11 sinat_33829806 阅读数 614
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3414 人正在学习 去看看 朱有鹏

Arduino 官方的SD卡库 使用起来体验很差

主要表现为:

  1. 每次使用重新进行初始化 不能保留多个文件
  2. 代码冗余

这里对此进行了优化

首先是 sdsun.h(内容不多就全写在头文件里了)

int sd_t=1;
File root;
File myFile;
String ss;
int printDirectory(File dir, int numTabs);
void setSD();
void write_SD(String ss,String s);
void setSD(){
    Serial.print("Initializing SD card...");
    if (!SD.begin(4)) {
        Serial.println("initialization failed!");
       return;
    }
    Serial.println("initialization done.");
    root = SD.open("/DATA/");
    int r=printDirectory(root, 0);
    String sd_x="/DATA/0";
    sd_x.concat(r);
    ss=sd_x+".TXT";
    Serial.println(ss);
    myFile = SD.open(ss, FILE_WRITE);
    myFile.close();
    Serial.println("done!"); 
}

void writeSD(String s){
    myFile = SD.open(ss, FILE_WRITE);
    myFile.println(s);//将输出参数写到括号里即可
    myFile.close();
  }



int printDirectory(File dir, int numTabs) {
  while (true) {
    File entry =  dir.openNextFile();
    if (! entry) {
      break;
    }
    for (uint8_t i = 0; i < numTabs; i++) {
      Serial.print('\t');
    }
    Serial.print(entry.name());
    if (entry.isDirectory()) {
      Serial.println("/");
      printDirectory(entry, numTabs + 1);
    } else {
      sd_t=sd_t+1;
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }
    entry.close();
  }
  return sd_t;
}

测试程序中 调用sdsun.h API即可,变成了这个样子:

#include <SPI.h>
#include <SD.h>
#include "sdsun.h"
void setup() {
    Serial.begin(9600);
    setSD()  ;

}
void loop() {
    writeSD("hhhhh");
}

可以说是心旷神怡,唯一需要注意的是SD卡 初始需要新建DATA文件夹 便可以一劳永逸 每次产生的新文件 以新数字命名

2009-10-19 17:38:00 jianxiang54321 阅读数 5016
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3414 人正在学习 去看看 朱有鹏

    随着电子技术的发展,SD卡作为大容量数据存储器越来越受到广大电子爱好者和客户的衷爱。但是由于SD卡FAT操作的编程复杂,很多电子爱好者望而却步,现在好了,我们推出了这块小巧玲珑的SD卡读卡模块,将复杂的FAT操作集成其内,单片机只需简单的串口操作就能将数据存到SD卡中去,而且支持FAT16和FAT32。
    单片机不限,51、avr、msp430、stc等单片机都能连接使用。
   ---------------------------------------------------------------
   稳定:工作稳定,不挑卡,不s机
   方便:串口UART操作(直接接任何带串口单片机),指令少,还可以顺序存
   ----------------------------------------------------------------


功能简介:
1. 电源输入范围宽:4~9V,支持3.3V和5V的UART接口。
2. 和单片机的接口简单 UART(串口)接口 可以直接和单片机的UART接口连接
3. 集成FAT32和FAT16格式系统
4. 文件的读写支持两种模式,一种顺序读写,用以连续的大量数据的读写.一种为给定起始地址的读写,用来随即读写的少量数据的情况,这个功能是的文件的读写非常灵活
5. 波特率可以用拨码开关选择,支持从1200~115200bps
6. 一次性发送数据贞可以长达256字节,有效字节数250
7. 支持<=8G容量的SD卡
8. 读写SD卡模块的速度快
9. 命令结构简单,方便发送
10.能动态监测SD状态有错就会提示
11.模块尺寸小,便于安装与使用。

SDV600 单片机串口读写sd卡模块资料

说明书下载地址:http://www.prog430.com/files/SDV6.pdf

测试软件下载地址:http://www.prog430.com/files/SDV6_test.rar

测试辅助模块驱动下载地址:http://www.prog430.com/files/CP2102.rar

产品购买方式:http://item.taobao.com/auction/item_detail-0db1-671f8a1a78bb55f6c79e2ab03a34bf69.htm

2018-02-08 22:59:38 Code_DZhangTeng 阅读数 3878
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3414 人正在学习 去看看 朱有鹏

    从大二开始写代码至今已经五六年了,之前做过很多嵌入式项目,参加过很多竞赛;慢慢才发现之前很多是知其然不知其所以然,很多东西都是从CSDN,论坛,各个网站学习过来的;工作以后才发现,做出一个东西并不难,重要的是方法,思路。很久以前写出了单片机读写SD卡的程序,前些日子拿出来用,发现不能直接用,自己写的程序现在不能用,很是着急。后来是静下心来,分析SD卡的反馈,修改相应的地方,很快就解决了问题。

    有人说,给SD卡发送CMD1,收到0x00表示成功。这是对的,但是如果收到0x01呢?0x04呢?0x0A呢?0x70呢?我认为这个返回值很重要,介绍给大家,希望可以帮助大家解决问题。(我先介绍这个与SD卡“交流”的方法,之后再介绍单片机读取SD卡整个过程)

    在官方英文资料《SD卡协议》中,有一项很重要的介绍,SD卡的返回值。我们给SD卡发一个信号,SD卡有没有收到?SD卡有没有响应?是否符合SD卡协议?我们都可以从SD卡的返回值中得到SD卡想要“表达”的意思。

    SD卡的一个字节返回值:

7

6

5

4

3

2

1

0

Bit0:空闲状态位—置位表示SD卡处于空闲状态,正在初始化过程中。

Bit1:擦除重置位—在执行接收到的擦除序列命令之前擦除序列被重置。

Bit2:非法命令位—接收到的命令是非法的命令代码(不符合SD卡协议命令代码)。

Bit3: CRC错误位—当前命令的CRC校验失败。

Bit4:擦除序列错误位—在擦除序列命令中发生错误。

Bit5:地址错误位—在命令中使用了一个不匹配块长度的地址。

Bit6:参数错误位—当前命令的地址或块长度超出了该SD卡的允许范围。

Bit7:预留。

    掌握了这个SD卡的返回值,可以很清楚的知道自己的程序代码哪里出了问题,解决起来就很简单。下面简单介绍一下SD卡的复位,初始化,读操作和写操作。


    复位:①拉高CS,发送至少74个时钟周期(等待同步);

      ②拉低CS,发送CMD0(六个字节命令,0x40,0x00,0x00,0x00,0x00,0x95),接收SD卡返回值,若返回值为0x01表示成功(具体含义对照上文中返回值介绍);

      ③拉高CS,发送八个时钟周期。

 

    初始化:①拉低CS,发送CMD550x77,0x00,0x00,0x00,0x00,0xFF);

         ②若返回值为0x01,继续发送CMD410x69,0x40,0x30,0x00,0x00,0xFF),返回值为0x00表示初始化成功;

    【注:SDHC卡的CMD41命令为0x69,0x40,0x30,0x00,0x00,0xFF

     而普通SD卡的CMD41命令为0x69,0x00,0x30,0x00,0x00,0xFF

         ③若返回值不是0x01,循环多次发送CMD55+CMD41;若一直不成功,则对照上文中返回值介绍查找是哪里错误。

 

     读操作:①拉低CS,发送CMD170x51,0x00,0x00,0x00,0x00,0xFF);

          ②若返回值为0x00,则读数据直至读到0xFE(有效数据开始标志位)

          ③读取512个字节的有效数据;

          ④读取两个CRC字节;

          ⑤拉高CS,发送八个时钟周期。

 

    写操作:①拉低CS,发送CMD240x58,0x00,0x00,0x00,0x00,0xFF);

         ②若返回值为0x00,则发送0xFC(写操作开始标志字节)

         ③继续发送512个字节的有效数据;

         ④发送两个CRC字节0xFF

         ⑤读取返回值直至读到***00101(二进制)表示512字节数据写入成功;

         ⑥进行查忙操作,直至返回值位0xFF

         ⑦拉高CS,发送八个时钟周期。

   完成上述操作就基本完成了SD卡的驱动程序。之后会上传自己编写的基于飞思卡尔MC9S12XEP100单片机读取8G 高速SDHC卡完整底层驱动程序(汽车级)。


二、软件部分

博文 来自: weiyidianliu

单片机spi驱动SD卡

阅读数 811

没有更多推荐了,返回首页