⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sd_spi.#3

📁 本源码是c8051f330使用spi口在spi模式下读写SD卡
💻 #3
字号:
//SD卡命令发送程序接口


#include "inc.h"
#include "define.h"

#define MAX SD_BLOCKSIZE

extern xdata uint8 statuslen = 4;
extern xdata uint8 cidlen = 16;		  		 //len取值0~MAX
//extern xdata uint8 csdlen = 16;
extern xdata uint8 sendbuf[16] ={0,1,2,3,4,5,6,7,8,9,0};
extern xdata uint8 recbuf[1] ={0};
extern xdata uint8 resp[5] = {0};

uint8 sd_send_cmd(uint8 cmd,uint8 *param,uint8 resptype,uint8 *resp)			//发送命令
{

	char i,rlen;
	uint8 tmp;
	spi_cs_clr();
//	command = 0;

	spi_sendbyte(((cmd & 0x3f) | 0x40));	   //发送命令头和命令字
	
	for(i=3;i>=0;i--)
	{
		spi_sendbyte(param[i]);			   //发送 send parameters
	}

	if(cmd == 0)
		spi_sendbyte(0x95);					   //CRC校验,用于第一个命令
	else
		spi_sendbyte(0xFF);

	
	switch(resptype)
	{
	
		case R1:   rlen = 0;		break;
		case R1B:  rlen = 1;		break;
		case R2:   rlen = 2;		break;
		case R3:   rlen = 5;		break;
		

	}

	i = 0;
	do
	{
		tmp = spi_recbyte();
		i++;	

	}
	while(((tmp &0x80 )!= 0) && (i<SD_CMD_TIMEOUT));

	if(rlen == 0)
		resp[0] = tmp;

	for(i =rlen-1;i>=0;i--)
	{
		resp[i] = tmp;
		tmp = spi_recbyte();
	}

	spi_sendbyte(0xFF);
	
//	if((cmd != 9) && (cmd != 10) && (cmd != 13))
//	{
//		spi_cs_set();

//	}	

//	return ret;
	return tmp;

}


void sd_pack_param(uint8 *parameter,uint32 value)						   	//将32位数据转化为4个字节
{

	parameter[3] = (uint8)(value>>24);
	parameter[2] = (uint8)(value>>16);
	parameter[1] = (uint8)(value>>8);
	parameter[0] = (uint8)(value);


}


uint8 sd_block_cmd(uint8 cmd,uint8 restype,uint32 parameter)			   //块命令
{
	uint8 param[4],resp,ret;
	
	sd_pack_param(param,parameter);

	ret = sd_send_cmd(cmd,param,restype,&resp);
	
					 
	return ret;
}





uint8 sd_set_blocklen(uint32 length)							   //设置块长度
{
	uint8 param[4],resp,ret;

	sd_pack_param(param,length);

	ret = sd_send_cmd(CMD16,param,CMD16_R,&resp);
	
				
	return ret; 	

}


uint8 sd_crc(uint8 enable)
{
	uint8 param[4],resp,ret;

	if( enable == 1 )
		param[0] = 1;											//使能CRC
	else													//禁止CRC
		param[1] = 0;
	
	ret = sd_send_cmd(CMD59,param,CMD59_R,&resp);
	
if(ret != SD_NO_ERR)
		return ret;	


	return SD_NO_ERR;

}

uint8 sd_read_single_block(uint32 blockaddr)				   //读单块命令
{
	sd_block_cmd(CMD17,CMD17_R,blockaddr);

	sd_read(SD_BLOCKSIZE,recbuf);

	spi_cs_set();

	return SD_NO_ERR;

}

uint8 sd_read_multiple_block(uint32 blockaddr)				   //读多块命令,直到收到停止命令
{
	sd_block_cmd(CMD18,CMD18_R,blockaddr);

	spi_cs_set();	
	
	return SD_NO_ERR;			
}

uint8 sd_stop_transmission(void)						  	   //停止发送
{
	uint8 param[4] = {0,0,0,0,},resp;
	
	return(sd_send_cmd(CMD12,param,CMD12_R,&resp));

}

uint8 sd_write_single_block(uint32 blockaddr)					//写单块命令
{
	
	sd_block_cmd(CMD24,CMD24_R,blockaddr);
	
	sd_write(0,SD_BLOCKSIZE,sendbuf);

	return SD_NO_ERR;
}

uint8 sd_write_multiple_block_cmd(uint8 blockaddr)				//写多块命令
{
	sd_block_cmd(CMD25,CMD25_R,blockaddr);

	sd_write(1,SD_BLOCKSIZE,sendbuf);

	spi_cs_set();	
	
	return SD_NO_ERR;
}


uint8 erase_startblock(uint32 startblock)						//设置块擦除起始地址
{
	
	return(sd_block_cmd(CMD32,CMD32_R,startblock));

}

uint8 erase_endblock(uint32 endblock)							 //设置块擦除结尾地址
{																 

	return(sd_block_cmd(CMD33,CMD33_R,endblock));
}



uint8 erase_selectedblock(void)									 //擦除选中的块
{
	uint8 param[4],tmp,resp;
	
	sd_pack_param(param,0);

	tmp = sd_send_cmd(CMD38,param,CMD38_R,&resp);
	
	spi_cs_set();
	
	return SD_NO_ERR;

}

uint8 sd_check_protect(void)
{
	uint8 param[4],tmp,resp;

	sd_pack_param(param,0);

	tmp = sd_send_cmd(CMD30,param,CMD29_R,&resp);

	spi_cs_set();

	return tmp;

}


uint8 sd_clear_protect(void)
{
	uint8 param[4],tmp,resp;

	sd_pack_param(param,0);

	tmp = sd_send_cmd(CMD29,param,CMD29_R,&resp);

	spi_cs_set();

	return tmp;

}

uint8 sd_set_protect(void)
{
	uint8 param[4],tmp,resp;

	sd_pack_param(param,0);

	tmp = sd_send_cmd(CMD28,param,CMD28_R,&resp);

	spi_cs_set();

	return tmp; 

}


/************************************数据传输*****************************************/

uint8 sd_read(uint32 len,char* recbuf)			  //读SD卡,len为数据长度,recbuf为数据缓冲区
{
	
	uint8 tmp;
	uint16 i = 0;

	spi_cs_clr();
	
	do
	{												 //等待数据起始令牌
		tmp = spi_recbyte();
		i++;

	
	}while((tmp == 0xff) && (i<SD_READREG_TIMEOUT));

	if(i >= SD_READREG_TIMEOUT)
	{
	
		spi_cs_set();
		return SD_ERR_TIMEOUT_READ;					   //超时错误

	}


	for(i=0;i<len;i++)
	{
//		recbuf[i] = spi_recbyte();
	tmp = spi_recbyte();
	}
		
	tmp = spi_recbyte();
	tmp = spi_recbyte();

	spi_sendbyte(0xFF);									 //返回前发送8个CLK
	spi_sendbyte(0xFF);
	spi_cs_set();
	sd_delay(20);

	return(SD_NO_ERR);

		

}



uint8 sd_write(uint8 bmulti,uint32 len,char* sendbuf)		//写SD卡,len为长度,sendbuf为发送缓冲,
{															//bmulti为发送多块单块选择:1多块,0单块

	uint32 i = 0;
	uint8 tmp;

	spi_cs_clr();

//	spi_sendbyte(0xff);									  //先发送8个CLK

	if( bmulti == 1 )
		spi_sendbyte(SD_TOK_WRITE_STARTBLOCK_M);		   	//写多块开始令牌
	else													//写单块开始令牌
		spi_sendbyte(SD_TOK_WRITE_STARTBLOCK);

	for(i=0;i<len;i++)
	{
	
//		spi_sendbyte(sendbuf[i]);		
		spi_sendbyte(0x55);

	}
	
	spi_sendbyte(0xFF);						  //16位CRC
	spi_sendbyte(0xFF);
	
	do
	{
		tmp = spi_recbyte();
	

	}while(tmp == FF);

	do
	{
	tmp = spi_recbyte();	 
	 
	 }while(tmp == 0);
	
	spi_cs_set();
	sd_delay(20);

	
	return SD_NO_ERR;

}


void sd_sendmulti_stop(void)								//发送停止数据传输令牌
{

	spi_sendbyte(0xff);
	spi_sendbyte(SD_TOK_STOP_MULTI);					   
	spi_recbyte();

	spi_cs_set();

}

uint8 sd_en_acmd()
{
	uint8 param[4] = {0,0,0,0},resp,ret;

	ret = sd_send_cmd(CMD55,param,CMD55_R,&resp);

	spi_cs_set();	

	return ret;
}

uint8 sd_activates()
{
	uint8 param[4] = {0,0,0,0},resp,ret;

	ret = sd_send_cmd(ACMD41,param,ACMD41_R,&resp);

	spi_cs_set();
	
	return ret;

}

uint8 sd_read_ocr()
{
	uint8 param[4] = {0,0,0,0},resp,ret;

	ret = sd_send_cmd(CMD58,param,CMD58_R,&resp);

	spi_cs_set();

	return ret;

}

uint8 sd_readcard_status(uint8*buffer)				//读card status寄存器
{
	
	uint8 param[4] ={0,0,0,0};
	uint8 ret;

	ret = sd_send_cmd(CMD13,param,CMD13_R,buffer);

	sd_read(statuslen,recbuf);

	spi_cs_set();

	return ret;
}

uint8 sd_read_csd()
{
    uint8 param[4] = {0,0,0,0},resp,ret;
  
    ret = sd_send_cmd(CMD9, param, CMD9_R, &resp);		/* 读CSD寄存器命令 command that read CSD register */
	
	sd_read(cidlen,&recbuf);
	
	spi_cs_set();
				
	return ret;    

}


uint8 sd_read_cid()
{
    uint8 param[4] = {0,0,0,0},resp,ret;
 
    ret = sd_send_cmd(CMD10, param, CMD10_R, &resp);		/* 读CID寄存器命令 command that read CID register */
						
	sd_read(cidlen,&recbuf);	
	
	spi_cs_set();

	return ret;      
//  	return (sd_read(cidlen, recbuf));
}


void sd_delay(uint8 value)									 //延时函数
{
	
uint8 i,j;  
  for(i=0;i<value;i++)
    for(j=0;j<10;j++)
	  {
//	   _NOP_();
      }


}

uint8 sd_reset(void)									  //复位SD卡
{
	uint8 param[4] = {0,0,0,0},resp,ret;
	

	ret = sd_send_cmd(CMD0,param,CMD0_R,&resp);
	
	spi_cs_set();

	return ret;
}


uint8 sd_check(void)														 //发出CMD1,查询卡的状态
{
	
	uint8 param[4] = {0,0,0,0},ret,resp;
		
	ret = sd_send_cmd(CMD1,param,CMD1_R,&resp);
	
	spi_cs_set();

	return ret;

}


uint8 sd_init(void)												//SD卡初始化进入SPI模式
{
	uint8 tmp;	
	uint8 i = 0;

	spi_cs_set();

	for(i=0;i<13;i++)
	{
		spi_sendbyte(0xFF);
	}
	spi_cs_clr();
															
	sd_reset();												//发送CMD0复位SD卡
	sd_delay(2);
	
	do
	{
		sd_en_acmd();
		tmp = sd_activates();
		sd_delay(20);
		i++;
									//激活初始化
	}while( (tmp!= 0)&&(i<SD_CMD_TIMEOUT));
	
	if(i>=SD_CMD_TIMEOUT)
		i = 1; 			//超时
	else
		i = 0;

	sd_check();												//发送CMD1查询SD卡状态
	sd_delay(1);

//	sd_crc(0);
//	sd_delay(1);

	sd_set_blocklen(SD_BLOCKSIZE);					//设置BLOCK长度
	sd_delay(5);

	sd_clear_protect();
	sd_delay(5);

	sd_readcard_status(recbuf);				//读card status寄存器
	sd_delay(10);

	sd_read_cid();
	sd_delay(10);

	sd_read_csd();
	sd_delay(10);
		
	return SD_NO_ERR;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -