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

📄 sd.c

📁 FATFS(10.4).rar
💻 C
字号:
#include"config.h"


/*******************************  SPI模式设置  ***********************************/

void SPI_Low(void)		
{//SPI低速模式
	SPCR = 0;
	SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0) | (1 << SPR1);
	//使能SPI,主机方式,MSB在前,模式0,128分频
}

void SPI_High(void)
{//SPI高速模式
	SPCR = 0;
	SPCR = (1 << SPE) | (1 << MSTR);
	SPSR |= (1 << SPI2X);
	//使能SPI,主机方式,MSB在前,模式0,4分频,2倍频
}

void SPI_Init(void)
{//SPI初始化
	SPI_PORT = (1 << SPI_SS) | (1 << SPI_MISO);		//将SS置位输出拉高,MISO输入带上拉
	SPI_DDR = (1 << SPI_SS) | (1 << SPI_MOSI) | (1 << SPI_SCK);
	//将SS SCK MOSI置为输出	
}

uint8_t SPI_RW(uint8_t dat)
{//SPI读写1Byte(欲想读之必先与之)
	SPDR = dat;
	while(!(SPSR & (1 << SPIF)))
		;
	return (SPDR);
}

/*******************************  SPI模式设置  ***********************************/


/**********************************************************************************
 - 功能描述:向SD卡写命令
 - 隶属模块:SD卡模块
 - 函数属性:内部
 - 参数说明:SD卡的命令是6个字节,pcmd是指向命令字节序列的指针
 - 返回说明:命令写入后,SD卡的回应值,调用不成功,将返回0xff
 **********************************************************************************/

uint8_t SD_Write_Cmd(uint8_t *pcmd) //向SD卡写命令,pcmd是命令字节序列的首地址
{
	uint8_t i,temp,retry;

	SET_SD_CS;					//关片选
 	SPI_RW(0XFF); 				//提高兼容性,如果没有这里,有些SD卡可能不支持   
	CLR_SD_CS;					//开片选(后面的读写扇区可以省去开片选)
	asm("nop");
	
	for(i=0;i<6;i++)
	{
		SPI_RW(*pcmd);
		pcmd++;
	}

	SPI_RW(0XFF);				//写入指令后附加8个时钟脉冲(如有问题可不加)	

	retry = 0;
	do							//不断地读
	{
		temp = SPI_RW(0XFF);
		retry++;		
	}while((temp == 0XFF) && (retry < 254));
	
	return (temp);
}

/**********************************************************************************
 - 功能描述:复位SD卡,用到CMD0,使用SD卡切换到SPI模式
 - 隶属模块:SD卡模块
 - 函数属性:内部
 - 参数说明:无
 - 返回说明:调用成功,返回0x00,否则返回INIT_CMD0_ERROR (sd.h中有定义)
 **********************************************************************************/

uint8_t SD_Reset()//SD卡复位,进入SPI模式,使用CMD0(0号命令)
{
	uint8_t retry,temp,i;
	uint8_t pcmd[] = {0x40,0x00,0x00,0x00,0x00,0x95}; 	

	SPI_Init();						//SPI初始化
	SPI_Low();						//SPI低速模式

	retry = 0;
	do
	{ 
		SET_SD_CS;
		for(i=0;i<0x0f;i++) //初始时,首先要发送最少74个时钟信号,这是必须的!!!
		{
			SPI_RW(0XFF);
		}

		temp = SD_Write_Cmd(pcmd);				//写入CMD0
		retry++;
		if(retry > 254) 
		{ 
			SET_SD_CS;							//关闭片选
			return(INIT_CMD0_ERROR);			//CMD0写入失败
		}
	}while(temp != 0x01);

	SET_SD_CS;
	SPI_RW(0XFF); 								//按照SD卡的操作时序在这里补8个时钟	
	return 0;									//返回0,说明复位操作成功
}

/**********************************************************************************
 - 功能描述:初始化SD卡,使用CMD1
 - 隶属模块:SD卡模块
 - 函数属性:内部
 - 参数说明:无
 - 返回说明:调用成功,返回0x00,否则返回INIT_CMD1_ERROR (sd.h中有定义)
 - 注:SD卡初始化成功后,读写扇区时,尽量将SPI速度提上来,提高效率
 **********************************************************************************/

uint8_t SD_Init()								//初始化,使用CMD1(1号命令)
{  
	unsigned char retry,temp;
	unsigned char pcmd[] = {0x41,0x00,0x00,0x00,0x00,0xff};	

	retry = 0;
	do
	{ 
		temp = SD_Write_Cmd(pcmd);
		retry++;
		if(retry > 254) 
		{ 
			SET_SD_CS;							//关闭片选
			return(INIT_CMD1_ERROR);			//CMD1写入失败
		}
	}while(temp != 0);

	 

	SET_SD_CS;  								//关闭SD卡的片选 
	SPI_RW(0XFF); 								//按照SD卡的操作时序在这里补8个时钟
	SPI_High();									//SPI高速模式
	return(0); 									//返回0,说明初始化操作成功
} 

/********************************************************************************************
 - 功能描述:将buffer指向的512个字节的数据写入到SD卡的addr扇区中
 - 隶属模块:SD卡模块
 - 函数属性:内部
 - 参数说明:addr:扇区地址
             buffer:指向数据缓冲区的指针
 - 返回说明:调用成功,返回0x00,否则返回WRITE_BLOCK_ERROR (sd.h中有定义) 
 ********************************************************************************************/

uint8_t SD_Write_Sector(uint32_t addr , const uint8_t *Buffer)	//向SD卡中的指定地址的扇区写入512个字节,使用CMD24(24号命令)
{  
	uint8_t temp,retry;
	uint16_t i;
	uint8_t pcmd[] = {0x58,0x00,0x00,0x00,0x00,0xff}; //向SD卡中单个块(512字节,一个扇区)写入数据,用CMD24

	addr <<= 9; //addr = addr * 512	将块地址(扇区地址)转为字节地址 [这里就限制了SD卡的最大容量为4G]

	pcmd[1]=((addr & 0xff000000) >> 24); //将字节地址写入到CMD24字节序列中
	pcmd[2]=((addr & 0x00ff0000) >> 16);
	pcmd[3]=((addr & 0x0000ff00) >> 8);

	retry = 0;
	do
	{  
		temp = SD_Write_Cmd(pcmd);
		retry++;
		if(retry > 254) 
		{ 
			SET_SD_CS;							//关闭片选
			return(temp); 						//命令写入失败
		}
	}while(temp != 0); 

	for(i=0;i<100;i++) 							//这里要插入若干时钟信号
	{
		SPI_RW(0XFF);
	}

	SPI_RW(0XFE);								//写入开始字节 0xfe,后面就是要写入的512个字节的数据	

	for (i=0;i<512;i++) 						//将缓冲区中要写入的512个字节写入SD卡
	{
		SPI_RW(*Buffer++);
	}

	SPI_RW(0XFF);; 
	SPI_RW(0XFF);; 								//两个字节的CRC校验码,不用关心


	temp = SPI_RW(0XFF);   						//读取返回值
	if((temp & 0x1F)!=0x05) 					//如果返回值是 XXX00DELAY_TIME1 说明数据已经被SD卡接受了
	{
		SET_SD_CS;
		return(WRITE_BLOCK_ERROR); 				//写块数据失败
	}

	while(SPI_RW(0XFF) != 0XFF);//等到SD卡不忙(数据被接受以后,SD卡要将这些数据写入到自身的FLASH中,需要一个时间)
					 //忙时,读回来的值为0x00,不忙时,为0xff

	SET_SD_CS;						 			//关闭片选
	SPI_RW(0XFF);								//按照SD卡的操作时序在这里补8个时钟
	return(0);		 							//返回0,说明写扇区操作成功
} 

/********************************************************************************************
 - 功能描述:读取addr扇区的512个字节到buffer指向的数据缓冲区
 - 隶属模块:SD卡模块
 - 函数属性:内部
 - 参数说明:addr:扇区地址
             buffer:指向数据缓冲区的指针
 - 返回说明:调用成功,返回0x00,否则返回READ_BLOCK_ERROR (sd.h中有定义)
 - 注:SD卡初始化成功后,读写扇区时,尽量将SPI速度提上来,提高效率
 ********************************************************************************************/

uint8_t SD_Read_Sector(uint32_t addr , uint8_t *buffer)//从SD卡的指定扇区中读出512个字节,使用CMD17(17号命令)
{
	uint16_t j;
	uint8_t retry,temp;
	uint8_t pcmd[]={0x51,0x00,0x00,0x00,0x00,0xFF}; //CMD17的字节序列
	addr <<= 9; //sector = sector * 512	   将块地址(扇区地址)转为字节地址
	pcmd[1]=((addr & 0xFF000000) >> 24);
	pcmd[2]=((addr & 0x00FF0000) >> 16);
	pcmd[3]=((addr & 0x0000FF00) >> 8);
	retry = 0;
	do
	{  
		temp = SD_Write_Cmd(pcmd); 				//写入CMD17
		retry++;
		if(retry > 254) 
		{
			SET_SD_CS;							//关闭片选
			return(READ_BLOCK_ERROR); 			//读块失败 READ_BLOCK_ERROR=0x04
			USART_Send_Str("SD卡读扇区失败\r\n");
		}
	}while(temp!=0); 
		
	while (SPI_RW(0XFF) != 0XFE); 				//一直读,当读到0xfe时,说明后面的是512字节的数据了

	for(j=0;j<512;j++)	 						//将数据写入到数据缓冲区中
	{	
		buffer[j] = SPI_RW(0XFF);
	}

	SPI_RW(0XFF);
	SPI_RW(0XFF);								//读取两个字节的CRC校验码,不用关心它们

	SET_SD_CS;  								//SD卡关闭片选 
	SPI_RW(0xFF);								//按照SD卡的操作时序在这里补8个时钟
	//USART_Send_Str("SD卡读扇区成功\r\n");
	return 0;
}
//---------------------------------------------------SD卡驱动--------------------------------

⌨️ 快捷键说明

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