搜索
bottom↓
回复: 80

通过两天的调试和OURAVR朋友的帮助下,终于实现了对SD卡的读写

[复制链接]

出0入0汤圆

发表于 2009-10-17 09:26:21 | 显示全部楼层 |阅读模式
贴程序:
/*-------------------------------------
1.本程序主要为了实现以下功能:
1)通过对SPI方式对SD卡进行读与写
2)简单的FAT操作
3)对写入的数据进行打印
2.编写日期:09.10.13
3.版本号:V1.0
4.作者:andyluo

----------------------------------------*/
#include<reg52.h>         //添加头文件
#define uchar unsigned char        //宏定义数据类型
#define uint unsigned int
/*-------------------------------------
与指示灯有关的IO
--------------------------------------*/
sbit power=P0^4;
/*-------------------------------------
与SD卡通信有关的IO
---------------------------------------*/
sbit SCL=P1^5;//时钟信号
sbit CS=P1^6;//片选信号
sbit SI=P1^7;//数据输入
sbit SO=P3^3;//数据输出
//错误码定义
#define INIT_CMD0_ERROR   0X01
#define INIT_CMD1_ERROR   0X02
#define WRITE_BLOCK_ERROR 0X03
#define READ_BLOCK_ERROR  0X04

/*--------------------------------------
与通信和定时器相关的变量
---------------------------------------- */
uchar cn=0;
/*--------------------------------------
变量定义
-----------------------------------------*/
uchar is_init;//用于控制SPI的速度,通过为1与0进行选择
uchar xdata pbuf[512];//定义512个数据缓冲区

/*--------------------------------------
函数名称:delay()
函数作用:用于某些程序中的延时
函数特点:无返回值,带入口参数
-----------------------------------------*/
void delay(uint k)          
{
        uint m,n;
        for(m=0;m<5;m++)
        for(n=0;n<k;n++);       
}

/*-------------------------------
SPI写一个字节
----------------------------------*/
void spi_write(uchar x)//SPI写一个字节,其中is_init为1
{
        uchar i;
        for(i=0;i<8;i++)
        {
                SI=((x<<i)&0x80);
                SCL=0;
                if(is_init)
                {
                        delay(8);
                }
                SCL=1;
                if(is_init)
                {
                        delay(8);
                }
        }
}
/*--------------------------------
SPI读一个字节
----------------------------------*/
uchar spi_read()
{
        uchar temp=0,i;
        SO=1;
        for(i=0;i<8;i++)
        {
                SCL=0;
                if(is_init)
                {
                        delay(8);
                }
        //        if(SO)
        //        {
        //                temp+=(0x80>>i);
        //        }
                temp=(temp<<1)+(uchar)SO;
                SCL=1;
                if(is_init)//放慢速度
                {
                        delay(8);
                }
        }
        return(temp);
}
/*--------------------------------
向SD卡写命令
---------------------------------*/
uchar write_cmd(uchar *pcmd)//pcmd为命令字
{
        uchar temp,i,time=0;
        CS=1;
        spi_write(0XFF);
        CS=0;
        for(i=0;i<6;i++)  //发送6个字节的命令字节序列
        {
                spi_write(*pcmd++);       
        }
        spi_read();
        do
        {
                temp=spi_read();//一直读,直到读到的不是0XFF或者超时
                time++;
        }
        while((temp==0xff)&&(time<100));
        return temp;
}

/*------------------------------------
SD卡复位,进入SPI模式,使用CMD0命令
-------------------------------------*/
uchar SD_Reset()//SD卡复位
{
        uchar time,temp,i;
        uchar pcmd[]={0x40,0x00,0x00,0x00,0x00,0x95};//0号命令对应的6个字节
        is_init=1;//set is_init flag
        CS=1;
        for(i=0;i<0x0f;i++)//初始化时,首先要发送至少74个时钟信号,这是必须的
        {
                spi_write(0xff);//实质发了120个时钟(15*8)
        }
        CS=0;
        time=0;
        do
        {
                temp=write_cmd(pcmd);
                time++;
                if(time==200)
                {
                        return(INIT_CMD0_ERROR );//cmd0写入失败
                }
        }
        while(temp!=0x01);
        CS=1;
        spi_write(0xff);//按照SD的操作时序在这里需要补8个时钟
        return 0;//返回0,说明SD卡复位操作成功
}  


/*-------------------------------------
SD卡初始化,使用CMD1号命令
---------------------------------------*/
uchar SD_Init()//SD卡初始化,使用CMD1号命令
{
        uchar time,temp;
        uchar pcmd[]={0x41,0x00,0x00,0x00,0x00,0xff};
        CS=0;
        time=0;
        do
        {
                temp=write_cmd(pcmd);
                time++;
                if(time==100)
                {
                        return(INIT_CMD1_ERROR );
                }
        }
        while(temp!=0x00);       
        is_init=0;//初始化完成,将is_init设置为0,以提高后面数据的传输速度
        CS=1;
        spi_write(0xff);   
       
        return 0;//说明初始化成功
}
/*-----------------------------
向SD卡扇区中写数据,每一个扇区中有512个字节
---------------------------------*/
uchar SD_write_sector(unsigned long addr,uchar *Buffer)
{
        uchar temp,time;
        uint i;
        uchar pcmd[]={0x58,0x00,0x00,0x00,0x00,0xff};//向SD卡中写入24号命令
        addr=addr<<9;//addr=addr+512,将块地址(扇区地址)转化为字节地址
        pcmd[1]=((addr&0xff000000)>>24);//将字节地址写入到24号命令的时序中
        pcmd[2]=((addr&0x00ff0000)>>16);
        pcmd[3]=((addr&0x0000ff00)>>8);//SD卡最大容量4G
//        pcmd[4]=(addr&0x000000FF);//此行为增加项
        CS=0;
        time=0;
        do
        {
                temp=write_cmd(pcmd);
                time++;
                if(time==100)
                {
                        return(temp);//命令写入失败
                }
        }
        while(temp!=0);
        for(i=0;i<100;i++)//这里要插入若干个时钟信号
        {
                spi_read();
        }
        spi_write(0xfe);//写入开始字节0XFE,后面就要写入512个字节
        for(i=0;i<512;i++)//将缓冲区中要写入的512个字节写入到SD卡中
        {
                spi_write(*Buffer++);       
        }
        spi_write(0xff);
        spi_write(0xff);//两个字节CRC校验码
        temp=spi_read();//读取返回值
        if((temp&0x1f)!=0x05)//如果返回值为xxx00101,说明数据已经被接收
        {
                CS=1;
                return(WRITE_BLOCK_ERROR );//写块数据失败
        }
        while(spi_read()!=0xff);//等待SD卡不忙(数据被接收以后,SD卡要将这些数据写入自身的FLASH
                                                        // 中,需要一定时间,忙时为0x00,不忙是为0xff, )
        CS=1;
        spi_write(0xff);//补8个时钟
        return 0;
}
/*--------------------------------
读SD卡的一个扇区
---------------------------------*/
uchar SD_read_sector(unsigned long addr,uchar *Buffer)
{
        uint i;
        uchar time,temp;
        uchar pcmd[]={0x51,0x00,0x00,0x00,0x00,0xff};//CMD17号命令
        addr=addr<<9;
        pcmd[1]=((addr&0xff000000)>>24);
        pcmd[2]=((addr&0x00ff0000)>>16);
        pcmd[3]=((addr&0x0000ff00)>>8);
        CS=0;
        time=0;
        do
        {
                temp=write_cmd(pcmd);
                time++;
                if(time==100)
                {
                        return(READ_BLOCK_ERROR);//读块失败
                }
        }
        while(temp!=0);
        while(spi_read()!=0xfe);//一直读,当读到0xfe时,说明后面是512个数据字节
        for(i=0;i<512;i++)
        {
                Buffer=spi_read();
        }
        spi_read();
        spi_read();
        CS=1;
        spi_write(0xff);//补8个时钟
        return 0;
}

/*---------------------------------
串口初始化
-----------------------------------*/
void serial_init(void) //
{  
        TMOD = 0x21; //使用定时器1工作在方式2,做波率发生器,定时器0方式1
        TH0 = 0X3c;         //设置定时初值,定时20ms,1s采用20*50算法
        TL0 = 0Xb0;
        ET0 = 1;         //开定时器0中断标志
        TR0 = 1;         //启动定时器0
        TH1 = 0xfd;  //32M,9600
    TL1 = 0xfd;
        TR1 = 1;    //启动定时器1
    SCON=0X40;  //串口工作在方式1,不允许接收
        REN = 1;        //允许串口接收
        ES = 1;            //允许串口中断
        EA = 1;         //开总中断
}
/*-------------------------
函数名称:main()
函数作用:主函数
---------------------------*/
void main()
{       
        int i=0;
        SD_Reset();
        SD_Init();
        serial_init();
        for(i=0;i<512;i++)
        {
                pbuf=i;//向缓冲区中写入数据
        }
        SD_write_sector(80,pbuf);//将缓冲区中512个字节的数据写入80扇区
        for(i=0;i<512;i++)
        {
                pbuf=0;//清空数据缓冲区
        }
        SD_read_sector(80,pbuf);//从SD卡的第80个扇区中读取512个字节的数据
        for(i=0;i<512;i++)
        {
                P2=~pbuf;//将缓冲区中的数据输出在P2口,
                delay(1000);
        }
        //P2=0X00;
        while(1);
}


         
void timer0_int(void) interrupt 1          //中断程序,注意中断类型号
{
        TH0=0X3c;          //重新赋初值,并且必须要这样做,不然的话定时时间会不准确的
        TL0=0Xb0;
        cn++;          //每当进入中断程序,count++,当有关参数设置正确后,程序会自动进入中断程序
        if(cn==20)
        {
                cn=0;
                power = !power;  //本机运行指示灯闪烁
               
        }
       
}

阿莫论坛20周年了!感谢大家的支持与爱护!!

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……

出0入0汤圆

 楼主| 发表于 2009-10-17 09:38:15 | 显示全部楼层
程序还不够完善,等会改好后上完整版.

出0入0汤圆

 楼主| 发表于 2009-10-17 10:14:54 | 显示全部楼层
每进入一个函数都有相关的打印信息,这样可以有利于查程序那里有问题.
/*-------------------------------------
1.本程序主要为了实现以下功能:
1)通过对SPI方式对SD卡进行读与写
2)简单的FAT操作
3)对写入的数据进行打印
2.编写日期:09.10.13
3.版本号:V1.0
4.作者:andyluo

----------------------------------------*/
#include<reg52.h>         //添加头文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define uchar unsigned char        //宏定义数据类型
#define uint unsigned int
/*-------------------------------------
与指示灯有关的IO
--------------------------------------*/
sbit power=P0^4;
/*-------------------------------------
与SD卡通信有关的IO
---------------------------------------*/
sbit SCL=P1^5;//时钟信号
sbit CS=P1^6;//片选信号
sbit SI=P1^7;//数据输入
sbit SO=P3^3;//数据输出
//错误码定义
#define INIT_CMD0_ERROR   0X01
#define INIT_CMD1_ERROR   0X02
#define WRITE_BLOCK_ERROR 0X03
#define READ_BLOCK_ERROR  0X04

/*--------------------------------------
与通信和定时器相关的变量
---------------------------------------- */
uchar cn=0;
/*--------------------------------------
变量定义
-----------------------------------------*/
uchar is_init;//用于控制SPI的速度,通过为1与0进行选择
uchar xdata pbuf[512];//定义512个数据缓冲区

/*--------------------------------------
函数名称:delay()
函数作用:用于某些程序中的延时
函数特点:无返回值,带入口参数
-----------------------------------------*/
void delay(uint k)          
{
        uint m,n;
        for(m=0;m<5;m++)
        for(n=0;n<k;n++);       
}
/*----------------------------------------
函数名称:IO_init()
函数作用:对相关IO进行初始化
函数特点:无返回值,无入口参数
------------------------------------------*/
void IO_init()
{
        SCL=1;
        CS=1;
        SO=1;
        power=1;

}
/*----------------------------------------
函数名称:send_byte(uchar i)
函数作用:对相关数据进行打印
函数特点:无返回值,带入口参数
--------------------------------------------*/
void send_byte(uchar i)
{
        TI=0;
        SBUF=i;
        while(!TI);
        TI=0;

}
/*-------------------------------------------------------
函数名:send_s()
功能:用户函数,发送一个字符
----------------------------------------------------------*/

void send_s(char *s)
{
int len=strlen(s);
int i;
for(i=0;i<len;i++)
send_byte(s);
send_byte(0x0d);
send_byte(0x0a);
}

/*-------------------------------
SPI写一个字节
----------------------------------*/
void spi_write(uchar x)//SPI写一个字节,其中is_init为1
{
        uchar i;
        for(i=0;i<8;i++)
        {
                SI=((x<<i)&0x80);
                SCL=0;
                if(is_init)
                {
                        delay(8);
                }
                SCL=1;
                if(is_init)
                {
                        delay(8);
                }
        }
}
/*--------------------------------
SPI读一个字节
----------------------------------*/
uchar spi_read()
{
        uchar temp=0,i;
        SO=1;
        for(i=0;i<8;i++)
        {
                SCL=0;
                if(is_init)
                {
                        delay(8);
                }
        //        if(SO)
        //        {
        //                temp+=(0x80>>i);
        //        }
                temp=(temp<<1)+(uchar)SO;
                SCL=1;
                if(is_init)//放慢速度
                {
                        delay(8);
                }
        }
        return(temp);
}
/*--------------------------------
向SD卡写命令
---------------------------------*/
uchar write_cmd(uchar *pcmd)//pcmd为命令字
{
        uchar temp,i,time=0;
        CS=1;
        spi_write(0XFF);
        CS=0;
        for(i=0;i<6;i++)  //发送6个字节的命令字节序列
        {
                spi_write(*pcmd++);       
        }
        spi_read();
        do
        {
                temp=spi_read();//一直读,直到读到的不是0XFF或者超时
                time++;
        }
        while((temp==0xff)&&(time<100));
        return temp;
}

/*------------------------------------
SD卡复位,进入SPI模式,使用CMD0命令
-------------------------------------*/
uchar SD_Reset()//SD卡复位
{
        uchar time,temp,i;
       
        uchar pcmd[]={0x40,0x00,0x00,0x00,0x00,0x95};//0号命令对应的6个字节
        send_s("SD_Reset start\n");
        is_init=1;//set is_init flag
        CS=1;
        for(i=0;i<0x0f;i++)//初始化时,首先要发送至少74个时钟信号,这是必须的
        {
                spi_write(0xff);//实质发了120个时钟(15*8)
        }
        send_s("send 120 clk succeed\n");
        CS=0;
        time=0;
        do
        {
                temp=write_cmd(pcmd);
                time++;
                if(time==200)
                {
                        return(INIT_CMD0_ERROR );//cmd0写入失败
                        send_s("send CMD0 ERROR\n");
                }
        }
        while(temp!=0x01);
        CS=1;
        spi_write(0xff);//按照SD的操作时序在这里需要补8个时钟
        send_s("send CMD0 succeed\n");
        return 0;//返回0,说明SD卡复位操作成功
}  


/*-------------------------------------
SD卡初始化,使用CMD1号命令
---------------------------------------*/
uchar SD_Init()//SD卡初始化,使用CMD1号命令
{
        uchar time,temp;
        uchar pcmd[]={0x41,0x00,0x00,0x00,0x00,0xff};
        send_s("SD_Init start\n");
        CS=0;
        time=0;
        do
        {
                temp=write_cmd(pcmd);
                time++;
                if(time==100)
                {
                        return(INIT_CMD1_ERROR );
                        send_s("CMD1 ERROR\n");
                }
        }
        while(temp!=0x00);       
        is_init=0;//初始化完成,将is_init设置为0,以提高后面数据的传输速度
        send_s("send CMD1 succeed\n");
        CS=1;
        spi_write(0xff);   
        send_s("SD_Init succeed\n");
        return 0;//说明初始化成功
}
/*-----------------------------
向SD卡扇区中写数据,每一个扇区中有512个字节
---------------------------------*/
uchar SD_write_sector(unsigned long addr,uchar *Buffer)
{
        uchar temp,time;
        uint i;
        uchar pcmd[]={0x58,0x00,0x00,0x00,0x00,0xff};//向SD卡中写入24号命令
        addr=addr<<9;//addr=addr+512,将块地址(扇区地址)转化为字节地址
        pcmd[1]=((addr&0xff000000)>>24);//将字节地址写入到24号命令的时序中
        pcmd[2]=((addr&0x00ff0000)>>16);
        pcmd[3]=((addr&0x0000ff00)>>8);//SD卡最大容量4G
//        pcmd[4]=(addr&0x000000FF);//此行为增加项
        send_s("SD_write_sector start\n");
        CS=0;
        time=0;
        do
        {
                temp=write_cmd(pcmd);
                time++;
                if(time==100)
                {
                        return(temp);//命令写入失败
                }
        }
        while(temp!=0);
        for(i=0;i<100;i++)//这里要插入若干个时钟信号
        {
                spi_read();
        }
        spi_write(0xfe);//写入开始字节0XFE,后面就要写入512个字节
        for(i=0;i<512;i++)//将缓冲区中要写入的512个字节写入到SD卡中
        {
                spi_write(*Buffer++);       
        }
        spi_write(0xff);
        spi_write(0xff);//两个字节CRC校验码
        temp=spi_read();//读取返回值
        if((temp&0x1f)!=0x05)//如果返回值为xxx00101,说明数据已经被接收
        {
                CS=1;
                return(WRITE_BLOCK_ERROR );//写块数据失败
        }
        while(spi_read()!=0xff);//等待SD卡不忙(数据被接收以后,SD卡要将这些数据写入自身的FLASH
                                                        // 中,需要一定时间,忙时为0x00,不忙是为0xff, )
        send_s("SD_write_sector succeed\n");
        CS=1;
        spi_write(0xff);//补8个时钟
        return 0;
}
/*--------------------------------
读SD卡的一个扇区
---------------------------------*/
uchar SD_read_sector(unsigned long addr,uchar *Buffer)
{
        uint i;
        uchar time,temp;
        uchar pcmd[]={0x51,0x00,0x00,0x00,0x00,0xff};//CMD17号命令
        addr=addr<<9;
        pcmd[1]=((addr&0xff000000)>>24);
        pcmd[2]=((addr&0x00ff0000)>>16);
        pcmd[3]=((addr&0x0000ff00)>>8);
        send_s("SD_read_sector start\n");
        CS=0;
        time=0;
        do
        {
                temp=write_cmd(pcmd);
                time++;
                if(time==100)
                {
                        return(READ_BLOCK_ERROR);//读块失败
                }
        }
        while(temp!=0);
        while(spi_read()!=0xfe);//一直读,当读到0xfe时,说明后面是512个数据字节
        for(i=0;i<512;i++)
        {
                Buffer=spi_read();
        }
        spi_read();
        spi_read();
        CS=1;
        send_s("SD_read_sector succeed\n");
        spi_write(0xff);//补8个时钟
        return 0;
}

/*---------------------------------
串口初始化
-----------------------------------*/
void serial_init(void) //
{  
        TMOD = 0x21; //使用定时器1工作在方式2,做波率发生器,定时器0方式1
        TH0 = 0X3c;         //设置定时初值,定时20ms,1s采用20*50算法
        TL0 = 0Xb0;
        ET0 = 1;         //开定时器0中断标志
        TR0 = 1;         //启动定时器0
        TH1 = 0xfd;  //11.0592M,9600
    TL1 = 0xfd;
        TR1 = 1;    //启动定时器1
    SCON=0X40;  //串口工作在方式1,不允许接收
        REN = 1;        //允许串口接收
        ES = 1;            //允许串口中断
        EA = 1;         //开总中断
}
/*-------------------------
函数名称:main()
函数作用:主函数
---------------------------*/
void main()
{       
        int i=0;
        serial_init();
        send_s("serial_init!\n");
        IO_init();
        send_s("Port Init!\n");
        SD_Reset();
        SD_Init();

        for(i=0;i<512;i++)
        {
                pbuf=i;//向缓冲区中写入数据
        }
        SD_write_sector(80,pbuf);//将缓冲区中512个字节的数据写入80扇区
        for(i=0;i<512;i++)
        {
                pbuf=0;//清空数据缓冲区
        }
        SD_read_sector(80,pbuf);//从SD卡的第80个扇区中读取512个字节的数据
        for(i=0;i<512;i++)
        {
                P2=~pbuf;//将缓冲区中的数据输出在P2口,
                send_byte(pbuf);
                delay(1000);
        }
        //P2=0X00;
        while(1);
}


         
void timer0_int(void) interrupt 1          //中断程序,注意中断类型号
{
        TH0=0X3c;          //重新赋初值,并且必须要这样做,不然的话定时时间会不准确的
        TL0=0Xb0;
        cn++;          //每当进入中断程序,count++,当有关参数设置正确后,程序会自动进入中断程序
        if(cn==20)
        {
                cn=0;
                power = !power;  //本机运行指示灯闪烁
               
        }
       
}

出0入0汤圆

发表于 2009-10-17 11:08:13 | 显示全部楼层
标记一个

最好上工程文件  还有原理图

谢谢

出0入0汤圆

 楼主| 发表于 2009-10-17 11:27:09 | 显示全部楼层
原理图已经上了,查我前天发的帖子,工程文件你自己可以搞,你直接粘贴就可以用了.

出0入0汤圆

发表于 2009-10-17 12:04:50 | 显示全部楼层
楼主貌似重新开的主题?为什么不在原帖的基础上将问题出现的原因说出来供大家学习呢?
前提是楼主愿意和大家分享自己的成果........................

出0入0汤圆

发表于 2009-12-8 14:18:20 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-12-8 20:29:16 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-12-9 10:19:31 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-12-9 13:55:44 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-12-9 17:07:10 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-12-9 17:14:25 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-12-10 14:30:30 | 显示全部楼层
addr=addr<<9;//addr=addr+512,将块地址(扇区地址)转化为字节地址
pcmd[1]=((addr&0xff000000)>>24);//将字节地址写入到24号命令的时序中
pcmd[2]=((addr&0x00ff0000)>>16);
pcmd[3]=((addr&0x0000ff00)>>8);//SD卡最大容量4G
// pcmd[4]=(addr&0x000000FF);//此行为增加项

这段如何理解?本人初学,请楼主赐教

出0入0汤圆

发表于 2009-12-11 10:36:38 | 显示全部楼层
顶!

出0入0汤圆

发表于 2009-12-11 15:21:38 | 显示全部楼层
GOOD!

出0入0汤圆

发表于 2009-12-11 15:53:33 | 显示全部楼层
太好了!顶!

出0入0汤圆

发表于 2009-12-15 01:50:15 | 显示全部楼层
标志一下,想学习一下SD卡的驱动。

出0入0汤圆

发表于 2009-12-15 06:57:49 | 显示全部楼层
SD卡注释,马克

出0入0汤圆

发表于 2009-12-17 16:01:31 | 显示全部楼层
SD卡注释,马克

出0入46汤圆

发表于 2009-12-17 22:08:52 | 显示全部楼层
SD卡注释,马克

出0入0汤圆

发表于 2009-12-18 00:05:59 | 显示全部楼层
mark!!!!!!!!!!!

出0入0汤圆

发表于 2010-1-11 16:55:05 | 显示全部楼层
mark!

出0入0汤圆

发表于 2010-1-11 18:42:59 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-1-11 21:23:42 | 显示全部楼层
马克!什么时候才能看懂楼主写的啊赫赫

出0入0汤圆

发表于 2010-1-21 21:07:14 | 显示全部楼层
请问LZ为什么写命令要检测返回值是否Oxff?
资料上有吗?找了很久了...

/*--------------------------------
向SD卡写命令
---------------------------------*/
uchar write_cmd(uchar *pcmd)//pcmd为命令字
{
uchar temp,i,time=0;
CS=1;
spi_write(0XFF);
CS=0;
for(i=0;i<6;i++)  //发送6个字节的命令字节序列
{
spi_write(*pcmd++);
}
spi_read();
do
{
temp=spi_read();//一直读,直到读到的不是0XFF或者超时
time++;
}
while((temp==0xff)&&(time<100)); //检测返回值是否Oxff???
return temp;
}  


clock (原文件名:未命名.jpg)

出0入0汤圆

发表于 2010-1-21 22:27:27 | 显示全部楼层
mark~

出0入0汤圆

发表于 2010-1-22 16:59:37 | 显示全部楼层
谢谢了。最近也想研究SD卡呢。

出0入0汤圆

发表于 2010-1-22 19:22:34 | 显示全部楼层
请问你用的是51单片机吗,有没有用外扩ram

出0入0汤圆

发表于 2010-1-24 09:24:23 | 显示全部楼层
SD卡注释,马克

出0入0汤圆

发表于 2010-1-24 13:49:54 | 显示全部楼层
回复【24楼】efen
请问LZ为什么写命令要检测返回值是否Oxff?
资料上有吗?找了很久了...
/*--------------------------------  
向SD卡写命令  
---------------------------------*/  
uchar write_cmd(uchar *pcmd)//pcmd为命令字  
{  
uchar temp,i,time=0;  
CS=1;  
spi_write(0XFF);  
CS=0;  
for(i=0;i&lt;6;i++)  //发送6个字节的命令字节序列  
{  
spi_write(*pcmd++);  
}  
spi_read();  
do  
{  
temp=spi_read();//一直读,直到读到的不是0XFF或者超时  
time++;  
}  
while((temp==0xff)&amp;&a......
-----------------------------------------------------------------------

找到资料了,可能是 命令后的 Ncr 需要dummy clocks,0<Ncr<8

出0入0汤圆

发表于 2010-1-24 14:38:55 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-1-24 18:10:23 | 显示全部楼层
标记

出0入0汤圆

发表于 2010-1-25 10:01:34 | 显示全部楼层
记号

出0入0汤圆

发表于 2010-3-21 19:09:03 | 显示全部楼层
不错!

出0入0汤圆

发表于 2010-3-29 08:00:41 | 显示全部楼层
不错

出0入0汤圆

发表于 2010-3-30 15:45:25 | 显示全部楼层
楼主关于SD卡的相关程序很详细,学习了。

出0入0汤圆

发表于 2010-3-30 16:56:03 | 显示全部楼层
做标记真是好办法学习了,程序下来慢慢研究了

出0入0汤圆

发表于 2010-4-1 00:51:30 | 显示全部楼层
addr=addr<<9;//addr=addr+512,将块地址(扇区地址)转化为字节地址

我知道一个扇区有512字节,但想不明白块地址与字节地址有什么关系

出0入0汤圆

发表于 2010-4-1 10:12:52 | 显示全部楼层
MARK

出0入0汤圆

发表于 2010-4-1 16:40:23 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-4-2 14:31:35 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-4-3 12:12:16 | 显示全部楼层
make

出0入0汤圆

发表于 2010-4-3 18:19:28 | 显示全部楼层
能不能说明一下原理

出0入0汤圆

发表于 2010-4-4 13:14:01 | 显示全部楼层
很好

出0入0汤圆

发表于 2010-4-10 19:52:43 | 显示全部楼层
回复【43楼】zpyws
-----------------------------------------------------------------------

very good!

出0入0汤圆

发表于 2010-4-10 20:35:16 | 显示全部楼层
好东西,顶起来!

出0入0汤圆

发表于 2010-4-18 08:49:38 | 显示全部楼层
好东西

出0入0汤圆

发表于 2010-4-18 22:56:19 | 显示全部楼层
貌似很详细的谢谢lz

出0入0汤圆

发表于 2010-4-18 23:00:28 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-4-22 10:56:00 | 显示全部楼层
mark----------

出0入0汤圆

发表于 2010-4-22 11:02:45 | 显示全部楼层
记号~~

出0入0汤圆

发表于 2010-4-22 11:38:36 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-4-26 17:54:13 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-4-26 18:09:38 | 显示全部楼层
标记

出0入0汤圆

发表于 2010-4-29 15:36:37 | 显示全部楼层
标记,学习了

出0入0汤圆

发表于 2010-5-6 18:36:11 | 显示全部楼层

出0入0汤圆

发表于 2010-5-6 21:35:04 | 显示全部楼层
谢谢,学习了

出0入0汤圆

发表于 2010-7-5 16:39:53 | 显示全部楼层
好,学习

出0入0汤圆

发表于 2010-7-5 17:00:22 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-12 14:44:04 | 显示全部楼层
mark啦

出0入0汤圆

发表于 2010-12-24 21:51:15 | 显示全部楼层
楼主人不错,向你学习!

出0入0汤圆

发表于 2010-12-25 14:12:13 | 显示全部楼层
谢谢分享 不错

出0入0汤圆

发表于 2010-12-27 11:11:00 | 显示全部楼层
好东西,谢谢分享

出0入0汤圆

发表于 2011-3-17 11:04:14 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-3-17 14:51:44 | 显示全部楼层
楼主,能将原理图上传一份吗?我也想学SD卡读写,但电平不匹配,我想看一下,楼主是如何解决这个问题的。

出0入0汤圆

发表于 2011-3-17 16:22:26 | 显示全部楼层
对,原理图~求发

出0入0汤圆

发表于 2012-3-1 15:10:20 | 显示全部楼层
马克

出0入0汤圆

发表于 2012-3-1 19:40:29 | 显示全部楼层
标记,学习了

出0入0汤圆

发表于 2012-3-1 21:53:43 | 显示全部楼层
回复【65楼】sherlockljt 缓刑三天
对,原理图~求发
-----------------------------------------------------------------------
仔细看帖与回复,

授人以渔

点lz的“资料”-》“发过的帖子”=》找类似帖子-》。。。。。有sch

出0入0汤圆

发表于 2012-3-3 10:59:49 | 显示全部楼层
先马克,用到再说

出0入0汤圆

发表于 2013-2-19 14:29:22 | 显示全部楼层
mark             

出0入0汤圆

发表于 2013-2-19 17:13:54 来自手机 | 显示全部楼层
学习一下....

出0入0汤圆

发表于 2013-2-20 11:34:32 | 显示全部楼层
MARK,以后留用

出0入0汤圆

发表于 2013-2-20 11:46:24 | 显示全部楼层
非常需要

出0入0汤圆

发表于 2013-2-20 11:50:25 | 显示全部楼层
mark

出0入0汤圆

发表于 2013-3-30 22:29:58 | 显示全部楼层
Mark!多谢楼主!

出0入0汤圆

发表于 2013-3-31 00:07:04 来自手机 | 显示全部楼层
see to study

出0入0汤圆

发表于 2013-5-23 15:28:07 | 显示全部楼层

出0入0汤圆

发表于 2013-5-23 15:35:12 | 显示全部楼层
mark,要用

出0入0汤圆

发表于 2013-5-30 10:49:45 | 显示全部楼层
LZ不错,mark

出0入0汤圆

发表于 2013-5-30 12:59:42 | 显示全部楼层
mark  mark
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-8-26 12:24

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表