求助,51单片机SPI通信读取SD卡的数据,不成功,显示不出图片

2019-03-24 17:46发布

最近假期在家里玩51单片机,看到有大神做了用51单片机和12864和SD卡模块来播放bad apple 【一个视频】觉得很厉害

自己就想也来尝试下,现在程序弄好了,SD卡程序是在网上找参考别人的。但是并没有用,也不懂错在哪里,问了别人

别人用这个程序是可以实现的,可是我自己就不行 想求各位大神解答一下。另外想问下SD卡模块的 MOSI,MISO是分别

对应DO和DI么?
111.jpg

目前程序烧进去,屏幕就显示乱码。插不插SD卡都是现实乱码
111.jpg

然后程序是这样。。。求大神帮看看哪里有错

#include <reg52.h>
#include <INTRINS.H>
#define uchar unsigned char
#define uint unsigned int
uint i=0;
uchar ints;         //初始化变速标志

sbit lcden=P2^7;
sbit lcdrw=P2^5;
sbit lcdrs=P2^6;
sbit rst=P2^4;
sbit psb=P2^2;           //串/并方式控制

sbit cs =P1^7;          //片选
sbit di =P1^6;         //SD卡数据输入  mosi
sbit clk=P1^5;         //时钟
sbit d0=P1^4;        //SD卡数据输出         miso

uchar xdata table[1024]; //设置片外指针

//错误代码//
#define cmd0        0x01         //复位错误
#define cmd1        0x02           //初始化错误
#define sdw                0x03   //sd写错误
#define sdr                0x0f  //sd读错误

void delay(uchar z)   //LCD延时
{
        uint x,y;
        for(x=z;x>0;x--)
                for(y=110;y>0;y--);
}

void delay2(uint z)
{
  while(z--);
}

/*****************并行基本函数*******************/
void lcd_busy(void)   //忙检测
{
        uchar busy;
    lcdrs=0;lcdrw=1;
         do{
             lcden=1;
                delay2(16);
                 /*_nop_();
                 _nop_();*/
                 busy=P3;
                delay2(15);
                 /*_nop_();
                 _nop_();*/
                 lcden=0;
           }while(busy&0x80);         
}


void write_com(uchar com)
{        
        lcd_busy();//测忙
        lcdrs=0;
        lcdrw=0;
        P3=com;
        lcden=1;
        _nop_();
        _nop_();
        //delay2(1);
        lcden=0;        
}
void write_data(uchar date)
{        
        lcd_busy();//测忙
        lcdrs=1;
        lcdrw=0;
        P3=date;
        lcden=1;
        _nop_();
        _nop_();
        //delay2(1);
        lcden=0;
}

void init(void)      //初始化函数
{
    rst=1;        
    psb=1;
        delay(10);
        write_com(0x30);//基本指令集
        delay(10);
        write_com(0x0c);//显示ON,游标OFF,游标位置OFF
        delay(10);
        write_com(0x01);//清除显示
        delay(10);
}

void T_display(uchar *p) //图片数据提取函数
{  
        uchar x,y,a,b,c;   
        //write_com(0x34); //关闭绘图功能  
        x=0x88;//设置水平坐标X  
        y=0x80;//设置垂直坐标Y   
        for(c=0;c<2;c++)  
        {   
                for(a=0;a<32;a++)   
                {   
                        write_com(y+a);   
                        write_com(x);                     
                        for(b=0;b<16;b++)     
                                write_data(*p++); //写入8位数据   
                }   
                x=0x80;//转换半屏   
        }   
        //write_com(0x36); //打开绘图功能  
        //write_com(0x30);   
}

void QP()  //清除DDRAM的数据:送入0
{  
        uchar x,y,a,b,c;  
        x=0x80;
        y=0x80;   
        write_com(0x34);//关闭绘图功能  
        for(a=0;a<2;a++)  
        {   for(b=0;b<32;b++)     
                {
                       write_com(y+b);   
                        write_com(x);   
                                for(c=0;c<16;c++)      
                                        write_data(0x00);   
                }   
                x=0x88;   
        }   
        write_com(0x36);//打开绘图功能  
        write_com(0x30);   
}

//***************************************************************************************//
//*********************************spi驱动**********************************************//
void spi_w(uchar dat)                //写数据
{
        unsigned char i;
        for(i=8;i;i--)
        {
                clk=0;
                 if(dat&0x80)
                        d0=1;
                else
                        d0=0;
               
                  dat<<=1;
                   clk=1;
         }
                d0=1;
}

uchar spi_r(void)  //读数据
{
        unsigned char n,j;
          for(j=8;j;j--)
          {
                clk=0;
                delay2(40);        
                clk=1;
            delay2(40);         
                n<<1;
                if(di) n |= 1;
          }
          return (n);
}
//*********************************spi驱动**********************************************//
//***************************************************************************************//








//***************************************************************************************//
//*********************************SD卡驱动**********************************************//
uchar sd_com(uchar *com)
{
        
        uchar i,temp,time=0;
        cs=1; spi_w(0xff); cs=0;

        for(i=0;i<0x06;i++)    //写命令
        {
                spi_w(*com++);
        }
        spi_r();
        do
        {
                temp=spi_r();  //读到有返回
                time++;
        } while((temp==0xff)&&(time<100));
        return(temp);               
}


uchar sd_reset()
{
        uchar time,temp,i;
        uchar cmd[]={0x40,0x00,0x00,0x00,0x00,0x95};

        ints=1;//开启初始化延时
        cs=1;
        for(i=0;i<20;i++)//至少74个时钟
                 {spi_w(0xff);}

        cs=0;
        time=0;
        do                          //写cmd0
        {
                temp=sd_com(cmd);
                time++;
                if(time>=200)
                {return(0x01); }
        }while(temp!=0x01);

        cs=1;
        spi_w(0xff);
        return 0;
}

uchar sd_int()
{
        uchar time,temp;
        uchar cmd[]={0x41,0x00,0x00,0x00,0x00,0xff};
        cs=0;
        time=0;
        do
        {
                temp=sd_com(cmd);
                time++;
                if(time==100)
                  {return(0x02);}
        }while(temp!=0)        ;
        ints=0;        
        cs=1;
        spi_w(0xff);
        return 0;
}         

uchar sd_r(unsigned long add,uchar *buf)
{
        uchar time,temp;
        uint j;
        uchar cmd[]={0x51,0x00,0x00,0x00,0x00,0xff};//cmd17
        add<<=9;//  等于add*512 扇区地址转换为字节地址
        cmd[1]=((add&0xff000000)>>24);
        cmd[2]=((add&0x00ff0000)>>16);
        cmd[3]=((add&0x0000ff00)>>8);
        cs=0;
        time=0;
        do
        {
                temp=sd_com(cmd);
                time++;
                if(time==100)
                {return(1);}
        } while(temp!=0);  //说明命令写入成功


        while(spi_r()!=0xfe);//读到数据的开头

        for(j=0;j<512;j++)
        {
                *buf++ = spi_r();
        }

        spi_r();
        spi_r();//读2个CRC

        cs=1;
        spi_w(0xff);
        return (0);
}


//*********************************SD卡驱动**********************************************//
//***************************************************************************************//

void main()
{
        uint pic;
        unsigned long add=512;//定义扇区地址
        sd_reset();//SD卡复位
        sd_int(); //SD卡初始化
        init();        //12864初始化                                                
        QP();        //12864清屏

        for(pic=0;pic<8000;pic++)         //一共xxx张图
        {
        sd_r(add++,table);
        sd_r(add++,table+512);//读取两个扇区1024字节
        write_com(0x36);//开启绘图  
        T_display(table);
        if(pic<780)delay(45);
        if(pic>780&&pic<1200)delay(50);
        if(pic>1200&&pic<1600)delay(60);
        if(pic>1600&&pic<2000)delay(50);
        if(pic>2000&&pic<2300)delay(55);
        if(pic>2300)delay(50);
        if(pic)delay(60);
        }
        while(1);        
}




此帖出自小平头技术问答
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
8条回答
森森森123
1楼-- · 2019-03-25 15:16
shower.xu 发表于 2016-1-27 11:19
读扇区的话数据文件格式要和你写屏的顺序一直才行,这个需要仔细研究。可以参考
http://bbs.eeworld.com.c ...

现在不怎么理解winhex扇区地址的看法   我程序里是用逻辑扇区的地址  
但是在winhex查看的地址写进去没有用,我用的是1G的SD卡
shower.xu
2楼-- · 2019-03-25 17:12
 精彩回答 2  元偷偷看……

一周热门 更多>