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

📄 sd_card.c

📁 常用的sd卡的单片机程序
💻 C
📖 第 1 页 / 共 3 页
字号:
//参见SD Card Interface for the MSP430(with C code).pdf(P11)
  CS_LOW();
  sd_delay(100);
  CS_HIGH();
  sd_delay(2);
  
  //发送CMD0命令,直到接收的响应为0x01
  CS_LOW();	
	do
	{
	  sd_send_cmd(CMD0,0);
	} while(sd_get_response() != 0x01);
	
	//发送CMD1,直到接收的响应为0x00
	do
	{
		CS_HIGH();
	  sd_delay(2);
	  //spi_send_byte(0xff);
	  CS_LOW();
	  sd_send_cmd(CMD1,0);
	} while(sd_get_response() != 0x00);
	
	CS_HIGH();
	sd_delay(2);
	//spi_send_byte(0xff);
	sd_set_blocklen(512);  //设置单块读写的长度为512字节
	sd_read_pbs();
	pcf_get_time();       //
	sd_find_dir();        
}  

/*******************************************************************************/
/*  Function : sd_write_file                                                   */
/*  Input    : none                                                            */
/*  Output   : none                                                            */
/*  Description : 将sd_buffer[0]~sd_buffer[indicator-1]中的数据写入文件        */
/*                同时更新indicator(为扇区字节偏移量)                          */
/*******************************************************************************/
void sd_write_file(void)
{
	unsigned int temp1,temp2;
	unsigned long address,address2;
	unsigned long length;
	int i,s,b;
	char *p;
	
	address = cs_to_addr(c_file,s_file); //待写入的首地址
	s = (int)(indicator/512); //完整扇区写入次数
	b = indicator - s * 512;  //扇区内的字节偏移量
	//b_file = b;
	for(i=0;i<s;i++)
	{
		p = &sd_buffer[i*512];    //单块写数据的首地址,sd_buffer[i*512]
		sd_write_block(address,p);
		s_file++;	               //扇区号加1
		if(s_file<sd_sc)	       //若扇区号小于sd_sc,不用拓展新簇
			address += 512;			
		else                     //若s_file等于sd_sc,则需要增添新簇
		{ 
			s_file = 0;            //新簇的0扇区
			temp1 = extend_cluster(c_file);
			c_file = temp1;
			address = cs_to_addr(c_file,0); //新簇的首地址
		}				
	}
	if(b > 0)          //把剩余的(不满一个扇区)字节写入SD卡
	{ 
		p = &sd_buffer[i*512];
		for(i=b;i<512;i++)
		  p[i] = 0;           //清零非用户数据    
		sd_write_block(address,p);
	}
  /*             更新文件属性                 */	
	address2 = cs_to_addr(c_attr,s_attr);
	//单块读出的数据放在sd_buffer[0]~sd_buffer[511]中
	p = sd_buffer;   
	sd_read_block(address2,p);
	
	temp1 = chars_to_int(p[b_attr+28],p[b_attr+29]);
	temp2 = chars_to_int(p[b_attr+30],p[b_attr+31]);
	length = ints_to_long(temp1,temp2);    //获得文件长度
	length += (indicator - b_file);        //更新文件长度,单位为字节
	for(i=0;i<4;i++)
	  p[b_attr+28+i]=(char)(length>>(8*i));
	p[b_attr+18] = (char)pcf_wdate;        //最后访问日期 
	p[b_attr+19] = (char)(pcf_wdate>>8);   
	p[b_attr+22] = (char)pcf_wtime;        //最后修改时间
	p[b_attr+23] = (char)(pcf_wtime>>8);
	p[b_attr+24] = (char)pcf_wdate;        //最后修改日期
	p[b_attr+25] = (char)(pcf_wdate>>8);
	sd_write_block(address2,p);
	
	b_file = b;                //更新b_file
        if(b_file>0)               //若不是刚好写满一个扇区,需要把该扇区的内容
		sd_read_block(address,p);//读出,储存在sd_buffer[0]~sd_buffer[511]中
	indicator = b_file;				 //以供下次调用函数时重新写入.	
}                            //注意储存数据时从sd_buffer[indicator]开始!!!!

/*******************************************************************************/
/*  Function : user_new_file                                                   */
/*  Input    : none                                                            */
/*  Output   : none                                                            */
/*  Description : 在工作目录中新用户数据文件,调用了sd_new()                    */
/*******************************************************************************/
void user_new_file(void)
{
	unsigned int temp;
	char *p;
	p = sd_buffer;  //指向数据缓存区的首地址
	char test[] = "SD Card new file";  //测试字符串
	
	temp = bcd_to_ascii(pcf_bday);   
	file_name[0] = (char)temp;
	file_name[1] = (char)(temp>>8);
	temp = bcd_to_ascii(pcf_bhour);  
	file_name[2] = (char)temp;
	file_name[3] = (char)(temp>>8);	
	temp = bcd_to_ascii(pcf_bminute);  
	file_name[4] = (char)temp;
	file_name[5] = (char)(temp>>8);
	temp = bcd_to_ascii(pcf_bsecond);  
	file_name[6] = (char)temp;
	file_name[7] = (char)(temp>>8);
	
	sd_new();         //调用sd_new(),新建数据文件
	
	for(indicator=0;indicator<16;indicator++)
	p[indicator] = test[indicator];
	sd_write_file();
}

/*******************************************************************************/
/*  Function : sd_new                                                          */
/*  Input    : none                                                            */
/*  Output   : none                                                            */
/*  Description : 在工作目录中新建文件,并储存文件信息                          */
/*******************************************************************************/
void sd_new(void)
{
	unsigned int temp;
	unsigned long address;
	int i;
	char *p = sd_buffer;  //单块数据放在sd_buffer[0]~sd_buffer[511]中
	
	dir_byte += 32;         //工作目录扇区内字节偏移+32
	if(dir_byte == 512)
	{
		dir_byte = 0;         //若扇区满,dir_byte变为0
		dir_sector++;         //工作目录的末扇区号+1
		if(dir_sector == sd_sc)
		{
			dir_sector = 0;     //若末扇区号为sd_sc,说明该簇已满
			temp = extend_cluster(dir_lastc);//为工作目录拓展一个新簇
			clear_cluster(temp);             //同时清空该簇
			dir_lastc = temp;                //并改写工作目录的末簇簇号
		}
	}
	c_first = find_newc();  //为文件占用一个新簇,储存文件的首簇簇号
	c_file = c_first;       //储存文件的待写入首字节位置的簇号
	s_file = 0;             //储存文件的待写入首字节位置的扇区号 
	b_file = 0; 		        //储存文件的待写入首字节位置的扇区内字节偏移
	c_attr = dir_lastc;     
	s_attr = dir_sector;    //将更新后的工作目录的末登记项的位置
	b_attr = dir_byte;      //(簇号,扇区,扇区内字节偏移)赋予文件属性
	
	/*     写文件的目录登记项       */
	address = cs_to_addr(dir_lastc,dir_sector);
	sd_read_block(address,p);    //读文件属性(登记项)所在的扇区	
	
	for(i=0;i<11;i++)
	p[b_attr+i] = file_name[i];  //文件名
	p[b_attr+11] = 0x20;         //文件属性-存档
	p[b_attr+12] = 0x00; 
	p[b_attr+13] = pcf_b10ms;             
	p[b_attr+14] = (char)pcf_wtime;       
	p[b_attr+15] = (char)(pcf_wtime>>8);  
	p[b_attr+16] = (char)pcf_wdate;
	p[b_attr+17] = (char)(pcf_wdate>>8);
	p[b_attr+18] = p[b_attr+16];
	p[b_attr+19] = p[b_attr+17];
	p[b_attr+20] = p[b_attr+21] = 0x00;
	p[b_attr+22] = (char)pcf_wtime;
	p[b_attr+23] = (char)(pcf_wtime>>8);
	p[b_attr+24] = (char)pcf_wdate;
	p[b_attr+25] = (char)(pcf_wdate>>8);
	p[b_attr+26] = (char)c_file;
	p[b_attr+27] = (char)(c_file>>8);
	p[b_attr+28] = p[b_attr+29] = 0x00;
	p[b_attr+30] = p[b_attr+31] = 0x00;	
	
	sd_write_block(address,p);    //写文件属性所在的扇区
	indicator = 0;                //
}
	
/*******************************************************************************/
/*  Function : sd_read_pbs                                                     */
/*  Input    : none                                                            */
/*  Output   : none                                                            */
/*  Description : 读分区引导扇区(PBS)内的相关信息                              */
/*******************************************************************************/
void sd_read_pbs(void)
{		
	unsigned long sd_address;
	unsigned int low_word;
	unsigned int high_word;
	char *p;
	
	//单块读出的数据放在sd_buffer[0]~sd_buffer[511]中
	p = sd_buffer; 	
	//读主引导记录(MBR),位于SD卡的第一扇区,起始地址为0
	sd_read_block(0,p);
	//读取相对扇区数,即分区1前扇区总数,位于MBR的454字节
	sd_rs = chars_to_int(*(p+454),*(p+455));
	
/*       读分区1的第一扇区,即分区引导扇区(PBS)        */	
	sd_address = (unsigned long)sd_rs * 512;  //分区1的起始地址	
	sd_read_block(sd_address,p);                //读分区引导扇区(PBS)
	
	sd_sc = *(p+13);                         //save sectors per cluster
	
	sd_rsc = chars_to_int(*(p+14),*(p+15));  //save reserved sectors
	
	sd_fnum = *(p+16);                       //save FAT numbers
	
	sd_sf = chars_to_int(*(p+22),*(p+23));   //save sector per FAT
  
  low_word = chars_to_int(*(p+32),*(p+33)); 
  high_word = chars_to_int(*(p+34),*(p+35));
  sd_ts = ints_to_long(low_word,high_word); //save the total sectors
  
  sd_fat1_addr = ((unsigned long)sd_rs+(unsigned long)sd_rsc)*512;//save FAT1 address
  
  sd_fat2_addr = sd_fat1_addr+(unsigned long)sd_sf*512;    //save FAT2 address
  
  sd_fdt_addr = sd_fat2_addr+(unsigned long)sd_sf*512;  //save FDT address
  
  sd_data_addr = sd_fdt_addr + 32 * 512;              //save DATA address
  
  sd_mcn = (unsigned int)((sd_ts-sd_rsc-sd_sf-sd_sf-32)/sd_sc)+1; //save max cluster number
}

/*******************************************************************************/
/*  Function : sd_find_dir                                                     */
/*  Input    : none                                                            */
/*  Output   : none                                                            */
/*  Description : 在FDT中寻找工作目录,没有则新建                               */
/*                需事先运行pcf_get_time,获得时间信息                          */
/*******************************************************************************/
void sd_find_dir(void)
{
	unsigned long sd_address;
	int i,num;
	char findout = 0;
	char flag = 0;
	char *p;
	
	p = sd_buffer;   //单块读出的数据放在sd_buffer[0]~sd_buffer[511]中
	sd_address = sd_fdt_addr;
	
	while(1)
	{
		i = 0;
		sd_read_block(sd_address,p);  //读FDT内容	  
		while(i<512)
		{
		   if(p[i]==0){ flag=1; break; } //为0说明没有文件存在,需要新建目录
		   if(check_name(i)){ findout=1; break; } //找到工作目录
		  i += 32;
		}
		if(flag || findout) break;      		 
		else
			sd_address += 512;  //继续寻找下一扇区
	}
/*      找到了工作目录      */
	if(findout)        
	{
		//与FDT一样,工作目录内所储存的内容也是该目录下所有文件或文件夹
		//的目录登记项,其内容与FDT的内容格式相同
		//以下程序是找到工作目录中最后一个登记项的位置
		dir_firstc = chars_to_int(p[i+26],p[i+27]);//工作目录的起始簇号		
		dir_lastc = find_lastc(dir_firstc);   //根据起始簇号,找到末簇簇号
		sd_address = cs_to_addr(dir_lastc,0); //末簇0扇区的物理地址
		dir_sector = 0;                       //末扇区号赋初始值0
		flag = 1;
		while((dir_sector<sd_sc) && flag)
		{
			sd_read_block(sd_address,p);  //读工作目录内容
			i = 0;
			while((i<512) && (p[i]!=0))
			  i += 32;
			if(i<512)
				flag = 0;     //找到了空的目录登记项
			else
			{
				dir_sector++;
				sd_address += 512; //继续寻找下一扇区
			}
		}
		if(dir_sector>=sd_sc) //说明末簇已写满
		{
			dir_byte = 480;    //工作目录中最后一个文件登记项的字节偏移量
			dir_sector--;      //工作目录中最后一个文件登记项所在的扇区号
			return;            //函数返回
		}
		else
		{
			if(i == 0)
			{ dir_byte = 480;   // 512-32,上一扇区的最后一个登记项
			  dir_sector--;       
			  return; }       			
			else
			{ dir_byte = i-32;
			  return; }
		}
	}
/*      没有找到工作目录,新建工作目录      */
  else
	{
		dir_firstc = find_newc(); //占用一个新簇给工作目录
		dir_lastc = dir_firstc;
		dir_sector = 0;          
		dir_byte = 32;      //存储工作目录的簇号,扇区,扇区内字节偏移信息
    
    /* 写FDT中工作目录登记项 */
    sd_read_block(sd_address,p);  //读出FDT表中首个空的登记项所在扇区
		for(num=0;num<11;num++)
		  p[i+num] = dir_name[num];
		p[i+11] = 0x10;
		p[i+12] = 0x00;
		p[i+13] = pcf_b10ms;             
		p[i+14] = (char)pcf_wtime;      
		p[i+15] = (char)(pcf_wtime>>8);  
		p[i+16] = (char)pcf_wdate;
		p[i+17] = (char)(pcf_wdate>>8);
		p[i+18] = p[i+16];
		p[i+19] = p[i+17];
		p[i+20] = 0x00;
		p[i+21] = 0x00;
		p[i+22] = (char)pcf_wtime;
		p[i+23] = (char)(pcf_wtime>>8);
		p[i+24] = (char)pcf_wdate;
		p[i+25] = (char)(pcf_wdate>>8);
		p[i+26] = (char)dir_lastc;
		p[i+27] = (char)(dir_lastc>>8);
		p[i+28] = p[i+29] = p[i+30] = p[i+31] = 0x00;
		sd_write_block(sd_address,p);  //写入FDT中
	
		/*  写"."目录,工作目录本身    */
		sd_address = cs_to_addr(dir_lastc,0);//工作目录所在簇的首地址
		p[0] = 0x2E;           // "."
		for(i=1;i<11;i++)
		  p[i] = 0x20;         // space(空格) 
		p[11] = 0x10;
		p[12] = 0x00;
		p[13] = pcf_b10ms;             //....pcf_b10ms 位于pcf8563程序中
		p[14] = (char)pcf_wtime;       //....pcf_wtime...
		p[15] = (char)(pcf_wtime>>8);  
		p[16] = (char)pcf_wdate;
		p[17] = (char)(pcf_wdate>>8);
		p[18] = p[16];

⌨️ 快捷键说明

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