新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > STC52單片機的SD卡底層驅(qū)動——SPI

STC52單片機的SD卡底層驅(qū)動——SPI

作者: 時間:2016-11-22 來源:網(wǎng)絡(luò) 收藏

最近在做SD卡以及單片機上的FAT32文件系統(tǒng),這個是我參考別人的源程序以后寫出來的自己的SD卡驅(qū)動,如有不完整的地方,還望大家不吝指教。

本文引用地址:http://m.butianyuan.cn/article/201611/319664.htm

定義聲明:

#ifndef _SD_H_
#define _SD_H_

#include

sbit SD_CS=P2^7; //SD卡片選信號
sbit SD_SI=P2^6; //SD卡數(shù)據(jù)輸入
sbit SD_SCL=P2^5; //SD卡時鐘信號
sbit SD_SO=P2^4; //SD卡數(shù)據(jù)輸出

#define DELAY_TIME 100 //SD卡的復(fù)位與初始化時SPI延時
#define TRY_TIME 200 //SD卡寫入命令以后,讀取SD卡的回應(yīng)次數(shù)


#define INIT_CMD0_ERROR 0x01 //CMD0錯誤
#define INIT_CMD1_ERROR 0x02//CMD1錯誤
#define WRITE_BLOCK_ERROR 0x03//寫塊錯誤
#define READ_BLOCK_ERROR 0x04//讀塊錯誤


unsigned char SD_Reset();
unsigned char SD_Init();
unsigned char SD_Write_Sector(unsigned long addr,unsigned char *buffer);
unsigned char SD_Read_Sector(unsigned long addr,unsigned char *buffer);

#endif

代碼實現(xiàn):

#include"SD.h"
#include"myfun.h"

unsigned char Is_init;

unsigned char bdata _dat;
sbit _dat7 = _dat^7;
sbit _dat6 = _dat^6;
sbit _dat5 = _dat^5;
sbit _dat4 = _dat^4;
sbit _dat3 = _dat^3;
sbit _dat2 = _dat^2;
sbit _dat1 = _dat^1;
sbit _dat0 = _dat^0;



void SD_spi_write(unsigned char x)
{
_dat=x;

SD_SI = _dat7;
SD_SCL = 0;
if(Is_init) Delay20us(DELAY_TIME);
SD_SCL=1;
if(Is_init) Delay20us(DELAY_TIME);

SD_SI = _dat6;
SD_SCL = 0;
if(Is_init) Delay20us(DELAY_TIME);
SD_SCL=1;
if(Is_init) Delay20us(DELAY_TIME);

SD_SI = _dat5;
SD_SCL = 0;
if(Is_init) Delay20us(DELAY_TIME);
SD_SCL=1;
if(Is_init) Delay20us(DELAY_TIME);

SD_SI = _dat4;
SD_SCL = 0;
if(Is_init) Delay20us(DELAY_TIME);
SD_SCL=1;
if(Is_init) Delay20us(DELAY_TIME);

SD_SI = _dat3;
SD_SCL = 0;
if(Is_init) Delay20us(DELAY_TIME);
SD_SCL=1;
if(Is_init) Delay20us(DELAY_TIME);

SD_SI = _dat2;
SD_SCL = 0;
if(Is_init) Delay20us(DELAY_TIME);
SD_SCL=1;
if(Is_init) Delay20us(DELAY_TIME);

SD_SI = _dat1;
SD_SCL = 0;
if(Is_init) Delay20us(DELAY_TIME);
SD_SCL=1;
if(Is_init) Delay20us(DELAY_TIME);

SD_SI = _dat0;
SD_SCL = 0;
if(Is_init) Delay20us(DELAY_TIME);
SD_SCL=1;
if(Is_init) Delay20us(DELAY_TIME);

}

unsigned char SD_spi_read()
{
SD_SO = 1;

SD_SCL = 1;
if(Is_init) Delay20us(DELAY_TIME);
SD_SCL = 0;
if(Is_init) Delay20us(DELAY_TIME);
_dat7 = SD_SO;

SD_SCL = 1;
if(Is_init) Delay20us(DELAY_TIME);
SD_SCL = 0;
if(Is_init) Delay20us(DELAY_TIME);
_dat6 = SD_SO;

SD_SCL = 1;
if(Is_init) Delay20us(DELAY_TIME);
SD_SCL = 0;
if(Is_init) Delay20us(DELAY_TIME);
_dat5 = SD_SO;

SD_SCL = 1;
if(Is_init) Delay20us(DELAY_TIME);
SD_SCL = 0;
if(Is_init) Delay20us(DELAY_TIME);
_dat4 = SD_SO;

SD_SCL = 1;
if(Is_init) Delay20us(DELAY_TIME);
SD_SCL = 0;
if(Is_init) Delay20us(DELAY_TIME);
_dat3 = SD_SO;

SD_SCL = 1;
if(Is_init) Delay20us(DELAY_TIME);
SD_SCL = 0;
if(Is_init) Delay20us(DELAY_TIME);
_dat2 = SD_SO;

SD_SCL = 1;
if(Is_init) Delay20us(DELAY_TIME);
SD_SCL = 0;
if(Is_init) Delay20us(DELAY_TIME);
_dat1 = SD_SO;

SD_SCL = 1;
if(Is_init) Delay20us(DELAY_TIME);
SD_SCL = 0;
if(Is_init) Delay20us(DELAY_TIME);
_dat0 = SD_SO;

return(_dat);
}

unsigned char SD_Write_Cmd(unsigned char *pcmd)
{
unsigned char temp,time=0;

SD_CS=1;
SD_spi_write(0xff); //提高程序的兼容性
SD_CS=0;

SD_spi_write(pcmd[0]);
SD_spi_write(pcmd[1]);
SD_spi_write(pcmd[2]);
SD_spi_write(pcmd[3]);
SD_spi_write(pcmd[4]);
SD_spi_write(pcmd[5]);
do
{
temp = SD_spi_read();
time++;
}
while((temp==0xff)&&(timereturn(temp);
}

unsigned char SD_Reset()
{
unsigned char time,temp,i;
unsigned char pcmd[] = {0x40,0x00,0x00,0x00,0x00,0x95};

Is_init = 1;

SD_CS = 1; //關(guān)閉片選
for(i=0;i<0x0f;i++){
SD_spi_write(0xff); //補充120個時鐘,喚醒SPI
}
SD_CS = 0; //打開片選
time=0;
do{
temp=SD_Write_Cmd(pcmd);//寫入CMD0
time++;
if(time==TRY_TIME){
SD_CS = 1; //關(guān)閉片選
return(INIT_CMD0_ERROR); //CMD0 寫入失敗
}
}while(temp!=0x01);

SD_CS = 1; //關(guān)閉片選

SD_spi_write(0xff);//補充8個時鐘,提高兼容性

return 0 ; //返回0,復(fù)位操作成功
}

unsigned char SD_Init()
{
unsigned char time,temp;
unsigned char pcmd[] = {0x41,0x00,0x00,0x00,0x00,0xff};
SD_CS = 0; //打開片選

time = 0;
do{
temp = SD_Write_Cmd(pcmd);
time++;
if(time==TRY_TIME){ //CMD1寫入失敗
SD_CS=1;
return(INIT_CMD1_ERROR);
}
}while(temp!=0);

Is_init = 0; //講Is_init設(shè)置為0,提高SPI速度
SD_CS = 1;//關(guān)閉片選
SD_spi_write(0xff); //補充8個時鐘
return(0);
}



unsigned char SD_Write_Sector(unsigned long addr,unsigned char *buffer)
{
unsigned char temp,time;
unsigned int i;
unsigned char pcmd[]={0x58,0x00,0x00,0x00,0x00,0xff};

addr<<=9;
pcmd[1] = ((addr&0xff000000)>>24);
pcmd[2] = ((addr&0x00ff0000)>>16);
pcmd[3] = ((addr&0x0000ff00)>>8);

SD_CS = 0;
time = 0;

do{
temp=SD_Write_Cmd(pcmd);//寫入CMD0
time++;
if(time == TRY_TIME)
{
SD_CS = 1; //關(guān)閉片選
return(temp); //寫入失敗
}
}while(temp!=0);

for(i=0;i<100;i++) //插入若干個字節(jié)的時鐘,保持穩(wěn)定性
{
SD_spi_write(0xff);
}

SD_spi_write(0xfe); //寫入0xfe,后面就是要寫入的數(shù)據(jù)

for(i=0;i<512;i++)
{
SD_spi_write(buffer[i]);
}

SD_spi_write(0xff); //兩個字節(jié)的CRC校驗碼
SD_spi_write(0xff);

temp = SD_spi_read(); //讀取返回值
if((temp&0x1f)!=0x05){
SD_CS = 1;
return(WRITE_BLOCK_ERROR); //寫塊數(shù)據(jù)失敗
}
while(SD_spi_read()!=0xff);//SD卡忙狀態(tài),等待

SD_CS = 1;

SD_spi_write(0xff);//補充8個時鐘
return(0);

}


unsigned char SD_Read_Sector(unsigned long addr,unsigned char *buffer)
{
unsigned int j;
unsigned char time,temp;
unsigned char pcmd[]={0x51,0x00,0x00,0x00,0x00,0xff}; //CMD17的字節(jié)序列

addr<<=9; //addr=addr*512 將塊地址(扇區(qū)地址)轉(zhuǎn)為字節(jié)地址

pcmd[1]=((addr&0xff000000)>>24);//將字節(jié)地址寫入到CMD17字節(jié)序列中
pcmd[2]=((addr&0x00FF0000)>>16);
pcmd[3]=((addr&0x0000FF00)>>8);

SD_CS=0;//打開片選

time=0;
do{
temp = SD_Write_Cmd(pcmd);
time++;
if(time==TRY_TIME){
return(READ_BLOCK_ERROR);
}
}while(temp!=0);

while(SD_spi_read()!=0xfe); //讀到0xfe,說明后面是512字節(jié)的數(shù)據(jù)

for(j=0;j<512;j++)
{
buffer[j]=SD_spi_read();
}

SD_spi_read(); //讀取兩個字節(jié)的CRC校驗碼
SD_spi_read();

SD_CS=1;

SD_spi_write(0xff); //補充8個時鐘

return 0;

}



評論


技術(shù)專區(qū)

關(guān)閉