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

📄 sd_card.c

📁 常用的sd卡的单片机程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/************************************************************************************/
/* sd_card.c: 27/10/2006                                                            */
/*                                                                                  */
/* 外部程序会使用到的函数:sd_init, user_new_file, sd_write_file, spi_init           */
/*                        bcd_to_ascii, ascii_to_bcd, chars_to_int, ints_to_long    */
/*                        delay                                                     */
/*                                                                                  */
/************************************************************************************/

#include "sd_card.h"
#include "pcf8563.h"
//#include <msp430x16x.h>
#include  "msp430x14x.h"

/*               SD卡信息                  */
//static unsigned long sd_address; //SD卡中的物理地址
static unsigned long sd_fat1_addr;  //FAT1的开始地址
static unsigned long sd_fat2_addr;  //FAT2的开始地址
static unsigned long sd_fdt_addr;   //FDT的开始地址
static unsigned long sd_data_addr;  //DATA(用户数据区)的开始地址

static unsigned int sd_rs;        //relative sectors       相对扇区数
static unsigned int sd_rsc;       //reserved sectors       保留扇区数
static unsigned int sd_sf;        //sectors per FAT        每个FAT表扇区数
static unsigned char sd_fnum;     //FAT numbers            FAT表个数

static unsigned int sd_mcn;       //the max cluster number 最大簇号
static unsigned char sd_sc;       //sectors per cluster    每簇扇区数 
static unsigned long sd_ts;       //total sectors          总扇区数

/*              工作目录信息                 */
static unsigned int dir_firstc;   //工作目录的首簇簇号
static unsigned int dir_lastc;    //工作目录的末簇簇号(最后一个登记项)
static unsigned char dir_sector;  //工作目录的末扇区号(最后一个登记项)0~SC-1
static unsigned int dir_byte;     //工作目录的扇区内字节偏移
                                  //(最后一个登记项的首字节) 0~480(32的倍数)

/*               文件信息                */                                 
static unsigned int c_file;  //簇号(待写入文件的首字节位置)
static char s_file;          //扇区号,0~SC-1(待写入文件的首字节位置)
static unsigned int b_file;  //扇区内字节偏移,0~511(待写入文件的首字节位置)
static unsigned int c_attr;  //文件属性(登记项)所在的簇号
static char s_attr;          //文件属性(登记项)所在的扇区号 0~SC-1
static unsigned int b_attr;  //文件属性(登记项)所在的扇区内字节偏移,0~480(32的倍数)
static unsigned int c_read;  //上次读的簇号
static char s_read;          //上次读的扇区号
static unsigned int c_first; //文件首簇的簇号

/*               其它信息                */
//FAT表目前扇区号,目的避免从第一扇区查找空簇花费大量的时间                                  
static unsigned int fat_offset;

//工作目录名:USERDATA,扩展名为空格,说明其为文件夹
static char dir_name[11] = {'U','S','E','R','D','A','T','A',' ',' ',' '};
//文件名,由实时时钟的时间命名: DDhhmmss.LOG
static char file_name[11] = {0,0,0,0,0,0,0,0,'L','O','G'};

char sd_buffer[BUFFER_LENGTH] = {0};    //数据缓存区
unsigned int indicator;  //待写入SD卡的字节数,指示待写入数据末字节的位置
//注意:
//sd_buffer[0]~sd_buffer[indicator-1]为待写入SD卡的数据
//若indicator不是512的整数倍,调用sd_write_file时会把sd_buffer[indicator-1]之后
//至512整数倍的字节写入SD卡,然后把该扇区的内容读出,储存在sd_buffer[0]~sd_buffer[511]
//中以供下次调用函数时重新写入.(这是因为读写SD卡时只能以扇区为单位进行)
//同时更新indicator=b_file,下次储存数据时从sd_buffer[indicator]开始!!!!
//注意sd_buffer[]的长度要满足实际使用要求! 
                        
/*               外部变量                */
extern char pcf_bday,pcf_bhour,pcf_bminute,pcf_bsecond;
extern char pcf_b10ms;
extern unsigned int pcf_wdate,pcf_wtime;

/****************************************************************************/
/*  延时函数                                                                */
/*  Function : delay                                                        */
/*  Input    : unsinged long t --延时时间(毫秒)                             */
/*  Output   : Nothing                                                      */
/*  Description :                                                           */
/*  利用指令运行的时间延时,一次循环需要7个时钟周期,假定时钟频率使用         */
/*  8MHz,则延时t毫秒需要的循环次数为:t*8000/7                              */
/****************************************************************************/           
void delay(unsigned long t)
{
  unsigned long i;                   
  i = t*8000/7;                      
  while(--i);
}
//在430中,当t*8000超过65535时,t和i都必须是长整型运算才正确.

/****************************************************************************/
/*  初始化SPI                                                               */
/*  Function : spi_init                                                     */
/*  Input    : none                                                         */
/*  Output   : none                                                         */
/*  Description :                                                           */
/*   P5.4 as SD select,P5.1-5.3 SPI option select,P5.0 as SD dectecting     */
/****************************************************************************/  
void spi_init(void)
{  
	
  UCTL1 = CHAR + SYNC + MM + SWRST;      // 8-bit, SPI, Master
  UTCTL1 =  CKPH + SSEL1 + SSEL0 + STC;	// SMCLK, 3-pin mode, clock idle low, data valid on rising edge, UCLK delayed
  UBR01 = 0x02;			                    // 0x02: SMCLK/2 for baud rate (4M)
  UBR11 = 0x00;			                    // 
  UMCTL1 = 0x00;		                    // no modulation 
  P5SEL |= 0x0E;		                   // P5.1-3 SPI option select
  P5DIR |= 0x1A;		                   // P5.4,P5.3,P5.1 output direction
  ME2 |= USPIE1;		                   // Enable USART1 SPI mode
  UCTL1 &= ~SWRST;                     // SPI enable
}

/****************************************************************************/
/*  SPI通讯子函数                                                           */
/*  Function : spi_send_byte                                                */
/*  Input    : const unsigned char data -- the byte to transfer             */
/*  Output   : unsigned char            -- the byte received                */
/*  Description :                                                           */
/*                                                                          */
/****************************************************************************/  
unsigned char spi_send_byte(const unsigned char data)
{
 while ((IFG2&UTXIFG1) ==0);	// wait while not ready for TX
 TXBUF1 = data;			          // write
 while ((IFG2 & URXIFG1)==0);	// wait for RX buffer 
 return (RXBUF1);
}

/**************************************************************************/
/*  Function : sd_send_cmd                                                */
/*  Input    : const char cmd     -- 命令编号                             */
/*           : unsigned long data -- 命令参数                             */
/*           :                                                            */
/*  Output   : none                                                       */
/*  Description : 发送一个命令                                            */
/**************************************************************************/
void sd_send_cmd(const char cmd, unsigned long data)
{
  char frame[6];
  char temp;
  int i;

  frame[0]=(cmd|0x40);  
//把data从高字节到低字节依次取出放入frame[1]~frame[4]中
  for(i=3;i>=0;i--)
  {
    temp=(char)(data>>(8*i));
    frame[4-i]=(temp);
  }
//CMD0的CRC校验码为0x95,其它命令在SPI模式下的校验码被忽略,故都用0x95
  frame[5]=0x95;   
  for(i=0;i<6;i++)
    spi_send_byte(frame[i]);
}

/****************************************************************************/
/*  接收SD Card的响应 (包括R1响应和单块读时的开始字节0xfe)                  */
/*  Function : sd_get_response                                              */
/*  Input    : none                                                         */
/*  Output   : char response -- 接收到的响应                                */
/*  Description :                                                           */
/****************************************************************************/ 
char sd_get_response(void)
{
  //Response comes 1-8bytes after command
  int i=0;
  char response;

  while(i<=64)
  {
   response=spi_send_byte(0xff);
   if(response!=0xff) break;
   //if(response==0x00)break;
   //if(response==0x01)break;
   i++;
  }
  return response;
}

/*******************************************************************************/
/*  Function : sd_check_busy                                                   */
/*  Input    : none                                                            */
/*  Output   : char                                                            */
/*  Description :                                                              */
/*  接收数据响应 xxx0<status>1 : status 010: Data accected, status 101: Data   */
/*  rejected due to a crc error, status 110: Data rejected due to a Write error*/
/*  然后等待清除busy信号                                                       */
/*******************************************************************************/ 
char sd_check_busy(void)
{
  
  int i=0;
  char response;
  char rvalue;
  while(i<=64)
  {
   response=spi_send_byte(0xff);
   response &= 0x1f;
   switch(response)
    {
     case 0x05: rvalue=SD_SUCCESS; break;
     case 0x0b: return(SD_CRC_ERROR);
     case 0x0d: return(SD_WRITE_ERROR);
     default:
	      rvalue = SD_OTHER_ERROR;
	      break;
    }
   if(rvalue == SD_SUCCESS) break;
    i++;
  }
  i=0;
  do
  {
   response=spi_send_byte(0xff);
   i++;
  }while(response == 0);
  return rvalue;
}

/*******************************************************************************/
/*  Function : sd_set_blocklen                                                 */
/*  Input    : const unsigned long blocklen -- block length (2^n)              */
/*  Output   : char response -- R1响应                                         */
/*  Description : 设置块的长度,默认块的长度定义在CSD中,一般为512字节           */
/*******************************************************************************/
char sd_set_blocklen (const unsigned long blocklen)
{
  char response;
  
  CS_LOW();
  sd_send_cmd(CMD16, blocklen);
  // get response from SD - make sure that it's 0x00 (R1 ok response format)
  //if(sd_get_response()!=0x00);
  response = sd_get_response();
  CS_HIGH();
  // Send 8 Clock pulses of delay.
  spi_send_byte(0xff);
  return response;
}			

/*******************************************************************************/
/*  Function : sd_delay                                                        */
/*  Input    : char number  -- 待发送的字节数                                  */
/*  Output   : none                                                            */
/*  Description : 发送空字节(0xff)                                             */
/*******************************************************************************/
void sd_delay(char number)
{
	char i;
	for(i=0;i<number;i++)
	spi_send_byte(0xff);  //clock out an idle byte(0xff)
}

/*******************************************************************************/
/*  Function : sd_detection                                                    */
/*  Input    : none                                                            */
/*  Output   : none                                                            */
/*  Description : 检查SD卡是否就位,卡没就位时红绿灯交替闪烁                    */
/*                SD_CD脚为0表示卡已就位,退出循环                              */
/*******************************************************************************/
void sd_detection(void)
{
	while(P5IN&SD_CD)
	{
		LED_RED_ON();
		delay(500);      // delay 500 milliseconds
		LED_RED_OFF();
		LED_GREEN_ON();
		delay(500);      // delay 500 milliseconds
	        LED_GREEN_OFF();
	}
}

/*******************************************************************************/
/*  Function : sd_read_block                                                   */
/*  Input    : const unsigned long address -- SD卡中的物理地址                 */
/*             char *index  --  接收数据的数组的首地址                         */
/*  Output   : char         -- 读取成功与否的状态码                            */
/*  Description : 写入成功后返回SD_SUCCESS (0x00)                              */
/*******************************************************************************/
char sd_read_block(const unsigned long address,char *index)
{
	unsigned int i;
	char rvalue = SD_RESPONSE_ERROR;
	char *p;
	p = index;
	
	CS_LOW();
	sd_send_cmd(CMD17,address);
	if(sd_get_response() == 0)
		{
			if(sd_get_response() == 0xfe)
				{
					for(i = 0;i < 512;i++)
					*(p+i) = spi_send_byte(0xff);
					// get CRC bytes (not really needed by us, but required by SD card)
					spi_send_byte(0xff);
					spi_send_byte(0xff);
					rvalue = SD_SUCCESS;
				}
			else
				rvalue = SD_DATA_TOKEN_ERROR;		
		}
	
		CS_HIGH();
		spi_send_byte(0xff);
		return rvalue;
}
					
/*******************************************************************************/
/*  Function : sd_write_block                                                  */
/*  Input    : const unsigned long address -- SD卡的物理地址                   */
/*             char *index  -- 待发送数组的首地址                              */
/*  Output   : char         -- 读取成功与否的状态码                            */
/*  Description : 写入成功后返回SD_SUCCESS (0x00)                              */
/*******************************************************************************/
char sd_write_block(const unsigned long address, char *index)
{
	unsigned int i;
	char rvalue = SD_RESPONSE_ERROR;
	char *p;
	p = index;
	
	CS_LOW();
	sd_send_cmd(CMD24,address);
	if(sd_get_response() == 0)
		{
			//need 8 clock cycles before the data block is started
			spi_send_byte(0xff);
			//send the data token to signify the start of the data
			spi_send_byte(0xfe);
			//clock the actual data transfer and transmit the bytes
			for(i=0;i<512;i++)
			spi_send_byte(*(p+i));
			//put CRC bytes (not really needed by us, but required by SD card)
			spi_send_byte(0xff);
			spi_send_byte(0xff);
			
			rvalue = sd_check_busy();
		}
		
	CS_HIGH();
	spi_send_byte(0xff);
	return rvalue;
}
						
/*******************************************************************************/
/*  Function : sd_init                                                         */
/*  Input    : none                                                            */
/*  Output   : none                                                            */
/*  Description : 初始化SD卡并进入SPI模式,读取卡信息,打开或新建工作目录        */
/*******************************************************************************/
void sd_init(void)
{
	//unsigned int i;
			
	sd_detection();   //检查SD卡是否插好     
	spi_init();       //初始化SPI
	fat_offset = 0;   //FAT表目前扇区号为0
// Delay for at least 74 clock cycles. This means to actually
//clock out at least 74 clock cycles with no data present on
// the clock. In SPI mode, send at least 10 idle bytes (0xFF).

⌨️ 快捷键说明

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