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

📄 mmc.c

📁 C8051FTest.rar 是C8051F系列处理器的基本测试程序
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <string.h>
#include <stdio.h>
#include "uart.h"
#include "menu.h"
#include "Lcd.h"
#include "system.h"
#include "mmc.h"
#include "usbtest.h"

char FILENO=0;
unsigned long WCnt=0;
unsigned long RCnt=0;
char Found;									//在目录中找到的文件或目录个数
unsigned long DCounter;						//查找目录时字节计数器
FILESTRUCT  File[13];						//保存查找到的文件或目录信息
FILESTRUCT CurF;							//存放当前目录
unsigned char MMCDataBuf[513];				//存放MMC一个块的数据
unsigned char MMCUSBBuf[513];				//用作与PC通过USB交换数据
char PATH[40];
char DEPTH;

unsigned long SecPClu=0;					//每簇所含块数
unsigned long BytePClu=0;					//每簇所含字节数
unsigned long DIR_ORI=0;					//根目录起始点	(根目录共占32个Sector,16kB)
unsigned long DIR_END=0;					//根目录结束点	(紧随其后是第二簇,没有第零,一簇)
unsigned long DIR_LEN=0;					//根目长度
unsigned long CLU_ORI=0;					//用户区起始地址,假设存在的第零簇的位置
unsigned long FAT1_ORI=0;					//FAT表1起始地址
unsigned long FAT2_ORI=0;					//FAT表2起始地址


unsigned char code FileIcon[]={"砬"};
unsigned char code FoldIcon[]={"苈"};

void SYS_INIT()
{	
	SFRPAGE=0x0f;		//c8051f120系列中要访问P4-P7必须设置SFRPAGE=0x0F

	XBR2|=0x40;			//交叉开关使能
	XBR0|=0x06;			//SPI,UART0使能(在C8051F0XX系列中时SMbBus使能,即0x03)*/
	P0MDOUT|=0x14;		//p0.2:SPI-SCK为PUSH-PULL,p0.4:SPI-MOSI 设为PUSH-PULL fpage
	P7MDOUT|=0x60;	    //P7.5:CS设置为PUSH-PULL,P7.6:PWR设为PUSH-PULL,f page

	// SPI 0 PAGE
	SFRPAGE=0x00;
	SPIEN=0;			//turn off SPIEN before setting phase and polarity
	SPI0CFG |= 0x70;		//设置时钟相位和极性,SPI设置为主模式
	SPI0CN |= 0x01;        //SSPI使能!transmit buffer empty!由于使三线所以设置NSSnMD为00
	SPI0CKR = 0x00;       //SPI时钟速率

	//skip p1.1 pin because spi set to 3 lines mode
//	XBR0 |= 0x40;
//	P1MDIN &= 0xFD;


	SFRPAGE=0x0f;
	MMC_power=0;		//打开电源
}

//////////////////////////////////////////////////////////////////////////////////////////////////
//								SPI底层单字节数据收发											//
//////////////////////////////////////////////////////////////////////////////////////////////////
unsigned char SPI_SEND(unsigned char Bdata)			//与MMC卡交换数据函数
{	
	SFRPAGE=0x00;
	SPI0DAT=Bdata;
	while(!SPIF);					//当SPI中断为到,即数据为传输完时则循环等待.				
	SPIF=0;							//由于硬件中断后没有清零,所以需要手动清零
	return SPI0DAT;
}

//////////////////////////////////////////////////////////////////////////////////////////////////
//							MMC卡SPI模式命令层													//
//////////////////////////////////////////////////////////////////////////////////////////////////
unsigned char MMC_SEND_CMD(unsigned char index,argument1,argument2,argument3,argument4)
{

/*
  每一个MMC命令均为48bits,所以发送6个字节的数据
  而默认的情况下:MMC的命令格式如下:

  位	47		46		[45:40]		[39:8]		[7:1]		0
  值	0		1			X		  X			  X			1 
  宽度  1       1           6         32 		  7			1
  功能  起始位 传输位    命令值       参数       CRC7      中止位

   SPI模式下CRC校验默认为关闭,相应的位可为任意值.		
*/
	signed char temp;
	//以下的6个语句用来reset MMC to SPI mode
	SPI_SEND(index|0x40);		//01xx xxxx 
	SPI_SEND(argument1);
	SPI_SEND(argument2);
	SPI_SEND(argument3);
	SPI_SEND(argument4);		//32bit参数zz
	SPI_SEND(0x95);				//crc校验位,进入spi模式后默认关闭,值可以任意

	SPI_SEND(0xff);				
	temp=SPI_SEND(0xff);
	if ((temp-0x80)>=0)
	{		//0b1xxxxxxx=err	
		temp=0xff;
		while (SPI_SEND(0xff)==0); 
	}
	else 
	if (index&0xbf==13)
	{									//如果是读状态命令
		temp=SPI_SEND(0xff); 			//read STATUS
		while (SPI_SEND(0xff)==0); 
	}                                                                                                                                                                                                      
	else
	{ 								//是其他命令
		while (SPI_SEND(0xff)==0); 
	}
	return temp; 
}

unsigned char MMC_SPI_INIT(void)
{
	unsigned char counter,temp;
	temp=0xff;
	SFRPAGE=0x0F;
	MMC_CS=0;			
	//延时
	for(counter=0;counter<10;counter++)
	SPI_SEND(0xff);
	delay(500);

	temp=MMC_SEND_CMD(MMC_GO_IDLE_STATE,0,0,0,0);	//进入SPI模式
	for(counter=0;counter<=80;counter++)			//延时80周期
	{
		temp=MMC_SEND_CMD(MMC_SEND_OP_COND,0,0,0,0);	
		if(temp==0)	break;
	}
	if(counter==81)	return KO;
	return OK;
	MMC_CS=1;
}


unsigned char MMC_block_read(unsigned char *buf,unsigned long Addr32)	//读取Addr32所在的SECTOR到Buf
{
	int counter=0;
	unsigned char temp;
	unsigned char P[3];
	P[2]=(unsigned char)(Addr32>>8)&0xFE;
	P[1]=(unsigned char)(Addr32>>16);
	P[0]=(unsigned char)(Addr32>>32);
	MMC_CS=0;
	temp=MMC_SEND_CMD(MMC_READ_SINGLE_BLOCK,P[0],P[1],P[2],0);	//发送单块读命令
	while(temp!=0xfe && counter<255)					//等待返回0xFE起始字节
	{
		temp=SPI_SEND(0xff);
		counter++;
	}
	if(counter==255)
	{
		return KO;
	}
	for(counter=0;counter<512;counter++)
	{
		buf[counter]=SPI_SEND(0xff);
	}
	SPI_SEND(0xff);
	SPI_SEND(0xff);
	MMC_CS=1;
	return OK;
}

unsigned char MMC_block_write(unsigned char *buf,unsigned long Addr32)//将512B的Buf写入到Addr32所在的SECTOR
{
	int counter;
	unsigned char temp;
	unsigned char P[3];
	P[2]=(unsigned char)(Addr32>>8)&0xFE;
	P[1]=(unsigned char)(Addr32>>16);
	P[0]=(unsigned char)(Addr32>>32);
	MMC_CS=0;

	SPI_SEND(0xff);
	temp=MMC_SEND_CMD(MMC_WRITE_BLOCK,P[0],P[1],P[2],0);
	for(counter=0;counter<255;counter++)
	SPI_SEND(0xff);
	
	SPI_SEND(0xfe);							//发送起始字节
	
	for(counter=0;counter<512;counter++)	//发送数据
	{
		SPI_SEND(buf[counter]);
	}

	temp=SPI_SEND(0xff);					//CRC码
	temp=SPI_SEND(0xff);

	counter=0;
	do
	{
		temp=SPI_SEND(0xff);
		counter++;
	}
	while( (temp&0x0f)!=5 && counter<255);	//等待返回写入成功字节xxx00101

	if(counter==255)	return KO;
		
	temp=0;
	while((temp==0)&&counter<512)
	{
		temp=SPI_SEND(0xff);
		counter++;
		delay(10);
	}
	MMC_CS=1;
	if(counter==512)
	return KO;
	return OK;
}

void CheckCard()
{
	unsigned long ReservedSector=0;
	unsigned long RootEntries=0;
	unsigned long SectorsperFAT=0;
	MMC_block_read(MMCDataBuf,0);	//读入DBR,分析BPB

	SecPClu=MMCDataBuf[0x0d];
 	BytePClu=SecPClu*512;

   	ReservedSector=MMCDataBuf[0x0e]+MMCDataBuf[0x0f]*256;
   	RootEntries=MMCDataBuf[0x11]+MMCDataBuf[0x12]*256;
   	SectorsperFAT=MMCDataBuf[0x16]+MMCDataBuf[0x17]*256;

	FAT1_ORI=ReservedSector*512;
	FAT2_ORI=FAT1_ORI+SectorsperFAT*512;
	DIR_ORI=FAT2_ORI+SectorsperFAT*512;
	DIR_LEN=RootEntries*32;
	CLU_ORI=DIR_ORI+DIR_LEN-2*BytePClu;

	return ;
}

//////////////////////////////////////////////////////////////////////////////////////////////////
//								文件层数据读取													//
//////////////////////////////////////////////////////////////////////////////////////////////////
unsigned int SearchEmptyCluster()							//在FAT表中搜寻未被占用的簇号
{															//成功返回簇号,失败返回0
	unsigned long Addr32=FAT1_ORI;
	unsigned int counter=0;
	int i;
	while(Addr32<FAT2_ORI)									//搜索FAT1表
	{
		MMC_block_read(MMCDataBuf,Addr32);					//读入一块
		for(i=0;i<512;i+=2)
		{
			if(MMCDataBuf[i]==0 && MMCDataBuf[i+1]==0)		//判断是否为空白块
			{
				MMCDataBuf[i]=0xFF;
			 	MMCDataBuf[i+1]=0xFF;

				if(MMC_block_write(MMCDataBuf,Addr32)==OK)	//将其占用
				return	counter*256+i/2;
				else
				return	0;
			}
		}
		counter++;
		Addr32+=512;
	}
	return 0;
}

unsigned int Find_NextN_Cluster(unsigned int First_Cluster,unsigned int n)	//计算给定簇的下N个簇序号
{																			//超过文件界限返回0
	int i;
	unsigned int temp=First_Cluster;
	if(n==0)
	return First_Cluster;
	for(i=0;i<n;i++)
	{
		MMC_block_read(MMCDataBuf,FAT1_ORI+temp*2);				
		temp=MMCDataBuf[(temp%256)*2]+MMCDataBuf[(temp%256)*2+1]*0x100;
		if(temp==0xFFFF)	
		break;
	}
	if(i>=n-1)
		return temp;
	else
		return 0;
}

int ReadFile(FILESTRUCT *fp,unsigned long offset)		//读取文件fp偏移offset所在块到buf,
{														//返回offset在buf中的偏移,失败返回-1
	unsigned long sector_sn=offset/512;
	unsigned int cluster_sn=sector_sn/SecPClu;
	int sector_offset=offset%512;
	char cluster_0ffset=sector_sn%SecPClu;
	unsigned long temp=Find_NextN_Cluster(fp->firstcluster,cluster_sn);
	if(fp->firstcluster==0)		
	{
		if(fp->attribute==0)		//读根目录文件
		{
			if(offset>=DIR_LEN)
			return -1;
			MMC_block_read(MMCDataBuf,DIR_ORI+offset);
		}
		else						//读的是空文件
		{
			return -1;		
		}
	}
	else							//普通文件
	{
		if	(temp==0xFFFF)
		return	-1;
		MMC_block_read(MMCDataBuf,CLU_ORI+temp*BytePClu+cluster_0ffset*0x200);
	}
	SFRPAGE=0x0f;
	return	sector_offset;
}

int WriteFile(unsigned char *buf,FILESTRUCT *fp,unsigned long offset)	//将512字节buf内容写入fp文件offset偏移处所在块
{																
	unsigned long sector_sn=offset/512;
	unsigned int cluster_sn=sector_sn/SecPClu;
	int sector_offset=offset%512;
	char cluster_0ffset=sector_sn%SecPClu;
	unsigned int Temp1,Temp2;

	if(fp->firstcluster==0)
	{
		if(offset>DIR_LEN)	
		return -1;
		MMC_block_write(buf,DIR_ORI+offset);
		return 1;
	}

	Temp1=Find_NextN_Cluster(fp->firstcluster,cluster_sn);
	if(Temp1==0)						//偏移越界,写文件失败,返回
	return -1;
	if(Temp1==0xFFFF)					//需要分配新簇
	{
		Temp1=SearchEmptyCluster();
		//将新簇链接到FAT1表中	
		Temp2=Find_NextN_Cluster(fp->firstcluster,cluster_sn-1)*2;
		MMC_block_read(MMCDataBuf,FAT1_ORI+Temp2);
		MMCDataBuf[Temp2%512]=Temp1;
		MMCDataBuf[Temp2%512+1]=Temp1>>8;	
		MMC_block_write(MMCDataBuf,FAT1_ORI+Temp2);
	}
	MMC_block_write(buf,CLU_ORI+Temp1*BytePClu+cluster_0ffset*0x200);
	return 1;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
//							应用层显示目录与浏览文本文件										//
//////////////////////////////////////////////////////////////////////////////////////////////////
void Get_File_List(unsigned long addr32,int From)			//获取DataBuf中从From开始的目录信息,直到Found=13或查找完毕
{
	int i,j;
	for(i=From;i<512;i+=32)
	{
		DCounter+=32;
		//空目录项,跳过(下面不再会有有效记录??)
		if(MMCDataBuf[i]==0)	continue;

		//曾经被占用过的目录项,下一个
		if(MMCDataBuf[i]==0xE5)	continue;

		if(MMCDataBuf[i+0x0b]==0x0F)	continue;			//该项为长文件名项,目前程序不支持长文件名,不必理会
															//紧随其后会有其短文件名			
		//该条目录有效,解释出相关信息,保存到File结构中

		//保存该条目录地址
		File[Found].Addr=addr32+DCounter-32;

		//文件名
		File[Found].filename[8]=0;
		File[Found].filename[9]=0;
		for(j=0;j<8;j++)
		{
			if(MMCDataBuf[i+j]==0x20)
			{
				File[Found].filename[j]=0;
				break;
			}
			File[Found].filename[j]=MMCDataBuf[i+j];
		}
		if(MMCDataBuf[i]=='.')
		{
			if(MMCDataBuf[i+1]=='.')			//。。表示上级目录
			{
				memcpy(File[Found].filename,"上级目录",8);
				File[Found].filename[9]=1;
			}
			if(MMCDataBuf[i+1]==0x20)			//。表示当前目录,保存到CurrentFile中
			{
				CurF.firstcluster=MMCDataBuf[i+0x1a]+MMCDataBuf[i+0x1b]*0x100;	
				continue;
			}
		}
		
		//扩展名
		File[Found].extension[3]=0;	
		for(j=0;j<3;j++)	
		{
			if(MMCDataBuf[i+0x08+j]==0x20)
			{
				File[Found].extension[j]=0;	
				break;
			}
			File[Found].extension[j]=MMCDataBuf[i+0x08+j];
		}
		
		//权限(识别文件还是目录)
		if((MMCDataBuf[i+0x0b]&0x10)!=0)		//注意:!=运算优先级高于 & 
		File[Found].attribute=0;
		else
		File[Found].attribute=1;

		//时分
		{
			unsigned int temp=MMCDataBuf[i+0x16]+MMCDataBuf[i+0x17]*0x100;
			File[Found].minute=(temp&0x07E0)>>5;
			File[Found].hour=temp>>11;
		}

		//年月日
		{
			unsigned int temp=MMCDataBuf[i+0x18]+MMCDataBuf[i+0x19]*0x100;
			File[Found].year=(temp>>9)-20;
			File[Found].month=(temp&0x01E0)>>5;
			File[Found].day=(temp&0x001F);
		}	
		//首簇号
		File[Found].firstcluster=MMCDataBuf[i+0x1a]+MMCDataBuf[i+0x1b]*0x100;

		//文件大小
		File[Found].size=0;		
		for(j=0x1f;j>=0x1c;j--)
		File[Found].size=MMCDataBuf[i+j]+File[Found].size*0x100;

		Found++;
		if(Found==13)
		return ;
	}
}

void Show_Dir_List()
{
	char n;
	SFRPAGE=0x0F;
	Clear(0,208);
	for(n=0;n<Found;n++)
	{
		dprintf(4,16*n,File[n].filename);
		if(File[n].attribute==1)			//如果是文件,显示文件图标,扩展名,文件大小
		{
			dprintf(2,16*n,FileIcon);		
			if (strlen(File[n].extension) != 0)
			{
				dprintf(4+strlen(File[n].filename),16*n,".");
				dprintf(5+strlen(File[n].filename),16*n,File[n].extension);
			}
			putufig(16,16*n, File[n].size,8,0,' ');
		}
		else								//如果是目录,显示文件夹图标
		{
			dprintf(2,16*n,FoldIcon);		
		}	
		dprintf(28,16*n, "/  /     :");
		putufig(26,16*n, File[n].year,2,0,'0');
		putufig(29,16*n, File[n].month,2,0,'0');
		putufig(32,16*n, File[n].day,2,0,'0');
		putufig(35,16*n, File[n].hour,2,0,'0');
		putufig(38,16*n, File[n].minute,2,0,'0');
	}
}

⌨️ 快捷键说明

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