?? sd.c
字號:
#include "sd.h"
#include "Delay.h"
/*******************************************************
+-------------------------------------+
| 振南電子 高級資源驅動 SD卡 部分 |
+-------------------------------------+
此源碼版權屬 振南 全權享有,如欲引用,敬請署名并告知
嚴禁隨意用于商業目的,違者必究,后果自負
振南電子
->產品網站 http://www.znmcu.cn/
->產品網店 http://shop.znmcu.cn/
->產品咨詢 QQ :987582714
MSN:yzn07@126.com
WW :yzn07
********************************************************/
//變量定義
//--------------------------------------------------------------
bit is_init; //在初始化的時候設置此變量為1,同步數據傳輸(SPI)會放慢
//---------------------------------------------------------------
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;
/******************************************************************
- 功能描述:IO模擬SPI,發送一個字節
- 隸屬模塊:SD卡模塊
- 函數屬性:內部
- 參數說明:x是要發送的字節
- 返回說明:無返回
- 注:其中is_init為1時,寫的速度放慢,初始化SD卡SPI速度不能太高
******************************************************************/
void SD_spi_write(unsigned char x)
{
_dat=x;
SD_SI=_dat7;
SD_SCL=0;
if(is_init) delay(DELAY_TIME);
SD_SCL=1;
if(is_init) delay(DELAY_TIME);
SD_SI=_dat6;
SD_SCL=0;
if(is_init) delay(DELAY_TIME);
SD_SCL=1;
if(is_init) delay(DELAY_TIME);
SD_SI=_dat5;
SD_SCL=0;
if(is_init) delay(DELAY_TIME);
SD_SCL=1;
if(is_init) delay(DELAY_TIME);
SD_SI=_dat4;
SD_SCL=0;
if(is_init) delay(DELAY_TIME);
SD_SCL=1;
if(is_init) delay(DELAY_TIME);
SD_SI=_dat3;
SD_SCL=0;
if(is_init) delay(DELAY_TIME);
SD_SCL=1;
if(is_init) delay(DELAY_TIME);
SD_SI=_dat2;
SD_SCL=0;
if(is_init) delay(DELAY_TIME);
SD_SCL=1;
if(is_init) delay(DELAY_TIME);
SD_SI=_dat1;
SD_SCL=0;
if(is_init) delay(DELAY_TIME);
SD_SCL=1;
if(is_init) delay(DELAY_TIME);
SD_SI=_dat0;
SD_SCL=0;
if(is_init) delay(DELAY_TIME);
SD_SCL=1;
if(is_init) delay(DELAY_TIME);
}
/******************************************************************
- 功能描述:IO模擬SPI,讀取一個字節
- 隸屬模塊:SD卡模塊
- 函數屬性:內部
- 參數說明:無
- 返回說明:返回讀到的字節
******************************************************************/
unsigned char SD_spi_read() //SPI讀一個字節
{
SD_SO=1;
SD_SCL=1;
if(is_init) delay(DELAY_TIME);
SD_SCL=0;
if(is_init) delay(DELAY_TIME);
_dat7=SD_SO;
SD_SCL=1;
if(is_init) delay(DELAY_TIME);
SD_SCL=0;
if(is_init) delay(DELAY_TIME);
_dat6=SD_SO;
SD_SCL=1;
if(is_init) delay(DELAY_TIME);
SD_SCL=0;
if(is_init) delay(DELAY_TIME);
_dat5=SD_SO;
SD_SCL=1;
if(is_init) delay(DELAY_TIME);
SD_SCL=0;
if(is_init) delay(DELAY_TIME);
_dat4=SD_SO;
SD_SCL=1;
if(is_init) delay(DELAY_TIME);
SD_SCL=0;
if(is_init) delay(DELAY_TIME);
_dat3=SD_SO;
SD_SCL=1;
if(is_init) delay(DELAY_TIME);
SD_SCL=0;
if(is_init) delay(DELAY_TIME);
_dat2=SD_SO;
SD_SCL=1;
if(is_init) delay(DELAY_TIME);
SD_SCL=0;
if(is_init) delay(DELAY_TIME);
_dat1=SD_SO;
SD_SCL=1;
if(is_init) delay(DELAY_TIME);
SD_SCL=0;
if(is_init) delay(DELAY_TIME);
_dat0=SD_SO;
return (_dat);
}
/******************************************************************
- 功能描述:向SD卡寫命令
- 隸屬模塊:SD卡模塊
- 函數屬性:內部
- 參數說明:SD卡的命令是6個字節,pcmd是指向命令字節序列的指針
- 返回說明:命令寫入后,SD卡的回應值,調用不成功,將返回0xff
******************************************************************/
unsigned char SD_Write_Cmd(unsigned char *pcmd) //向SD卡寫命令,pcmd是命令字節序列的首地址
{
unsigned char temp,time=0;
SD_CS=1;
SD_spi_write(0xff); //提高兼容性,如果沒有這里,有些SD卡可能不支持
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();//一直讀,直到讀到的不是0xff或超時
time++;
}while((temp==0xff)&&(time<TRY_TIME));
return(temp);
}
/******************************************************************
- 功能描述:復位SD卡,用到CMD0,使用SD卡切換到SPI模式
- 隸屬模塊:SD卡模塊
- 函數屬性:外部,供用戶調用
- 參數說明:無
- 返回說明:調用成功,返回0x00,否則返回INIT_CMD0_ERROR (sd.h中有定義)
******************************************************************/
unsigned char SD_Reset()//SD卡復位,進入SPI模式,使用CMD0(命令0)
{
unsigned char time,temp,i;
unsigned char pcmd[] = {0x40,0x00,0x00,0x00,0x00,0x95}; //命令0的字節序列
is_init=1; //將is_init置為1
SD_CS=1; //關閉片選
for(i=0;i<0x0f;i++) //初始時,首先要發送最少74個時鐘信號,這是必須的!??!
{
SD_spi_write(0xff); //120個時鐘
}
SD_CS=0; //打開片選
time=0;
do
{
temp=SD_Write_Cmd(pcmd);//寫入CMD0
time++;
if(time==TRY_TIME)
{
SD_CS=1; //關閉片選
return(INIT_CMD0_ERROR);//CMD0寫入失敗
}
}while(temp!=0x01);
SD_CS=1; //關閉片選
SD_spi_write(0xff); //按照SD卡的操作時序在這里補8個時鐘
return 0;//返回0,說明復位操作成功
}
/******************************************************************
- 功能描述:初始化SD卡,使用CMD1
- 隸屬模塊:SD卡模塊
- 函數屬性:外部,供用戶調用
- 參數說明:無
- 返回說明:調用成功,返回0x00,否則返回INIT_CMD1_ERROR (sd.h中有定義)
******************************************************************/
unsigned char SD_Init() //初始化,使用CMD1(命令1)
{
unsigned char time,temp;
unsigned char pcmd[] = {0x41,0x00,0x00,0x00,0x00,0xff}; //命令1的字節序列
SD_CS=0; //打開片選
time=0;
do
{
temp=SD_Write_Cmd(pcmd);
time++;
if(time==TRY_TIME)
{
SD_CS=1; //關閉片選
return(INIT_CMD1_ERROR);//CMD1寫入失敗
}
}while(temp!=0);
is_init=0; //初始化完畢,將is_init設置為0,為了提高以后的數據傳輸速度
SD_CS=1; //關閉片選
SD_spi_write(0xff); //按照SD卡的操作時序在這里補8個時鐘
return(0); //返回0,說明初始化操作成功
}
/****************************************************************************
- 功能描述:將buffer指向的512個字節的數據寫入到SD卡的addr扇區中
- 隸屬模塊:SD卡模塊
- 函數屬性:外部,供用戶調用
- 參數說明:addr:扇區地址
buffer:指向數據緩沖區的指針
- 返回說明:調用成功,返回0x00,否則返回WRITE_BLOCK_ERROR (sd.h中有定義)
- 注:SD卡初始化成功后,讀寫扇區時,盡量將SPI速度提上來,提高效率
****************************************************************************/
unsigned char SD_Write_Sector(unsigned long addr,unsigned char *buffer) //向SD卡中的指定地址的扇區寫入512個字節,使用CMD24(命令24)
{
unsigned char temp,time;
unsigned int i;
unsigned char pcmd[] = {0x58,0x00,0x00,0x00,0x00,0xff}; //向SD卡中單個塊(512字節,一個扇區)寫入數據,用CMD24
addr<<=9; //addr = addr * 512 將塊地址(扇區地址)轉為字節地址 [這里就限制了SD卡的最大容量為4G]
pcmd[1]=((addr&0xff000000)>>24); //將字節地址寫入到CMD24字節序列中
pcmd[2]=((addr&0x00ff0000)>>16);
pcmd[3]=((addr&0x0000ff00)>>8);
SD_CS=0;//打開SD卡片選
time=0;
do
{
temp=SD_Write_Cmd(pcmd);
time++;
if(time==TRY_TIME)
{
SD_CS=1; //關閉片選
return(temp); //命令寫入失敗
}
}while(temp!=0);
for(i=0;i<100;i++) //這里要插入若干時鐘信號
{
SD_spi_read();
}
SD_spi_write(0xfe);//寫入開始字節 0xfe,后面就是要寫入的512個字節的數據
for(i=0;i<512;i++) //將緩沖區中要寫入的512個字節寫入SD卡
{
SD_spi_write(buffer[i]);
}
SD_spi_write(0xff);
SD_spi_write(0xff); //兩個字節的CRC校驗碼,不用關心
temp=SD_spi_read(); //讀取返回值
if((temp&0x1F)!=0x05) //如果返回值是 XXX00101說明數據已經被SD卡接受了
{
SD_CS=1;
return(WRITE_BLOCK_ERROR); //寫塊數據失敗
}
while(SD_spi_read()!=0xff);//等到SD卡不忙(數據被接受以后,SD卡要將這些數據寫入到自身的FLASH中,需要一個時間)
//忙時,讀回來的值為0x00,不忙時,為0xff
SD_CS=1; //關閉片選
SD_spi_write(0xff);//按照SD卡的操作時序在這里補8個時鐘
return(0); //返回0,說明寫扇區操作成功
}
/****************************************************************************
- 功能描述:讀取addr扇區的512個字節到buffer指向的數據緩沖區
- 隸屬模塊:SD卡模塊
- 函數屬性:外部,供用戶調用
- 參數說明:addr:扇區地址
buffer:指向數據緩沖區的指針
- 返回說明:調用成功,返回0x00,否則返回READ_BLOCK_ERROR (sd.h中有定義)
- 注:SD卡初始化成功后,讀寫扇區時,盡量將SPI速度提上來,提高效率
****************************************************************************/
unsigned char SD_Read_Sector(unsigned long addr,unsigned char *buffer)//從SD卡的指定扇區中讀出512個字節,使用CMD17(17號命令)
{
unsigned int j;
unsigned char time,temp;
unsigned char pcmd[]={0x51,0x00,0x00,0x00,0x00,0xff}; //CMD17的字節序列
addr<<=9; //addr=addr*512 將塊地址(扇區地址)轉為字節地址
pcmd[1]=((addr&0xff000000)>>24);//將字節地址寫入到CMD17字節序列中
pcmd[2]=((addr&0x00FF0000)>>16);
pcmd[3]=((addr&0x0000FF00)>>8);
SD_CS=0;//打開片選
time=0;
do
{
temp=SD_Write_Cmd(pcmd); //寫入CMD17
time++;
if(time==TRY_TIME)
{
return(READ_BLOCK_ERROR); //讀塊失敗
}
}while(temp!=0);
while (SD_spi_read()!= 0xfe); //一直讀,當讀到0xfe時,說明后面的是512字節的數據了
for(j=0;j<512;j++) //將數據寫入到數據緩沖區中
{
buffer[j]=SD_spi_read();
}
SD_spi_read();
SD_spi_read();//讀取兩個字節的CRC校驗碼,不用關心它們
SD_CS=1; //SD卡關閉片選
SD_spi_write(0xff);//按照SD卡的操作時序在這里補8個時鐘
return 0;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -