📄 sd_card.c
字号:
//参见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 + -