SD卡讀寫(xiě)實(shí)驗(yàn)程序
掃描二維碼
隨時(shí)隨地手機(jī)看文章
//實(shí)驗(yàn)?zāi)康模簩W(xué)習(xí)SD卡的操作
//軟件設(shè)計(jì)
// 1、SD卡采用SPI通信
// 2、先往SD里順序?qū)懭?-255共256個(gè)數(shù)據(jù),然后再讀回送LCD1602顯示
//硬件要求:
// 撥碼開(kāi)關(guān)S11置ON
// 跳線(xiàn)J18全部接通
#include <p30f6014.h> //dsPIC30F6014標(biāo)準(zhǔn)頭文件
_FOSC(CSW_FSCM_OFF & XT_PLL4); //4倍頻晶振,F(xiàn)ailsafe 時(shí)鐘關(guān)閉
_FWDT(WDT_OFF); //關(guān)閉看門(mén)狗定時(shí)器
_FBORPOR(PBOR_OFF & MCLR_EN); //掉電復(fù)位禁止,MCLR復(fù)位使能。
_FGS(CODE_PROT_OFF); //代碼保護(hù)禁止
#define cs PORTGbits.RG9 //定義SD卡片選腳
#define rs LATBbits.LATB4 //定義LCD控制位(注意這里只能用LATB寄存器,不能直接用PORTB寄存器)
#define rw LATBbits.LATB5
#define e LATBbits.LATB6
unsigned char __attribute__((address(0x900))) lcd[3]={0,0,0};
void spi_init(); //申明系統(tǒng)初始函數(shù)
void spi_low(); //申明產(chǎn)生低波特率函數(shù)(SD卡初始化使用)
void spi_high(); //申明產(chǎn)生高波特率函數(shù)(SD卡初始化后使用)
unsigned char sd_reset(); //申明SD卡初始化函數(shù)
unsigned char SD_SendCommand(unsigned char cmd,unsigned long arg); //申明寫(xiě)SD卡命令函數(shù)
unsigned char SPI_WriteByte(unsigned char val); //申明寫(xiě)一字節(jié)函數(shù)
unsigned char SPI_ReadByte(void); //申明接收一字節(jié)函數(shù)
unsigned char SD_WriteSingleBlock(unsigned long sector); //申明寫(xiě)SD卡單BLOCK數(shù)據(jù)函數(shù)
unsigned char SD_ReadSingleBlock(unsigned long sector); //申明讀SD卡單BLOCK數(shù)據(jù)函數(shù)
void lcd_display(); //申明結(jié)果顯示函數(shù)
void delay(); //申明延時(shí)函數(shù)(顯示時(shí)用)
//系統(tǒng)初始化函數(shù)
void spi_init()
{
TRISG=0x00d0; //設(shè)置SDI為輸出,其他C口為輸出
TRISB=0X0000; //設(shè)置B口為輸出
TRISD=0X0000; //設(shè)置D口為輸出
SPI2CON=0x0278; //空閑時(shí)總線(xiàn)為高電平,fosc/64
SPI2STAT=0x8000; // 輸出數(shù)據(jù)的末尾采樣輸入數(shù)據(jù),上升沿發(fā)送數(shù)據(jù)
}
//*************************寫(xiě)LCD程序****************************************
//寫(xiě)一個(gè)字節(jié)數(shù)據(jù)函數(shù)
//在電平發(fā)生改變后需要插入一段延時(shí)時(shí)間,否則LCD反應(yīng)不過(guò)來(lái)。
void write(unsigned char x)
{
PORTD=x; //待顯示數(shù)據(jù)送PORTD口
delay();
rs=1; //該字節(jié)數(shù)據(jù)為數(shù)據(jù),而不是命令
delay();
rw=0; //此次操作為寫(xiě),而不是讀
delay();
e=0; //拉低使能信號(hào)
delay(); //保持使能信號(hào)為低一段時(shí)間
e=1; //拉高使能信號(hào),建立LCD操作所需要的上升沿
delay();
}
//********************LCD顯示設(shè)置函數(shù)**************************************
//在電平發(fā)生改變后需要插入一段延時(shí)時(shí)間,否則LCD反應(yīng)不過(guò)來(lái)。
void lcd_enable()
{
delay();
rs=0; //該字節(jié)數(shù)據(jù)為命令,而不是數(shù)據(jù)
delay();
rw=0; //此次操作為寫(xiě),而不是讀
delay();
e=0; //拉低使能信號(hào)
delay(); //保持使能信號(hào)為低一段時(shí)間
e=1; //拉高使能信號(hào),建立LCD操作所需要的上升沿
delay();
}
//*********************LCD初始化函數(shù)**************************************
void lcd_init()
{
PORTD=0X1; //清除顯示
lcd_enable();
PORTD=0X38; //8位2行5*7點(diǎn)陣
lcd_enable();
PORTD=0X0e; //顯示開(kāi),光標(biāo)開(kāi),閃爍
lcd_enable();
PORTD=0X06; //文字不動(dòng),光標(biāo)右移
lcd_enable();
PORTD=0X86; //時(shí)間顯示地址
lcd_enable();
}
//***********************LCD顯示函數(shù)************************************
void lcd_display()
{
unsigned char i,j;
lcd_init();
for(i=0;i<3;i++) //一共3字節(jié)數(shù)據(jù)
{
write(lcd[i]); //查表獲取數(shù)據(jù)并調(diào)用寫(xiě)一個(gè)字節(jié)數(shù)據(jù)函數(shù)送LCD顯示
for(j=0;j<5;j++) //延時(shí)一段時(shí)間(主要是為了控制顯示的速度)
{delay();}
}
}
//****************寫(xiě)一字節(jié)函數(shù)***************************
unsigned char SPI_WriteByte(unsigned char val)
{
SPI2BUF = val; //待發(fā)送數(shù)據(jù)裝載到發(fā)送寄存器
while(!IFS1bits.SPI2IF); //等待發(fā)送完成
IFS1bits.SPI2IF=0; //清除發(fā)送完成標(biāo)志位
return SPI2BUF; //讀取接收寄存器(即使是無(wú)效數(shù)據(jù)也需清空)
}
//****************接收一字節(jié)函數(shù)**************************
unsigned char SPI_ReadByte(void)
{
SPI2BUF = 0xff; //發(fā)送寄存器裝載數(shù)據(jù),以啟動(dòng)數(shù)據(jù)接收
while(!IFS1bits.SPI2IF); //等待接收完成
IFS1bits.SPI2IF=0; //清除接收完成標(biāo)志位
return SPI2BUF; //讀取接收到的數(shù)據(jù)
}
//*****************發(fā)送命令函數(shù)****************************
unsigned char SD_SendCommand(unsigned char cmd,unsigned long arg)
{
unsigned char r1;
unsigned char retry1=0; //重復(fù)操作次數(shù)
cs=0; //使能片選信號(hào)
SPI_WriteByte(cmd | 0x40); //分別寫(xiě)入命令
SPI_WriteByte(arg>>24); //數(shù)據(jù)段第4字節(jié)
SPI_WriteByte(arg>>16); //數(shù)據(jù)段第3字節(jié)
SPI_WriteByte(arg>>8); //數(shù)據(jù)段第2字節(jié)
SPI_WriteByte(arg); //數(shù)據(jù)段第1字節(jié)
SPI_WriteByte(0x95); //CRC效驗(yàn)和
while((r1 = SPI_WriteByte(0xff)) == 0xff)//等待響應(yīng)
if(retry1++ > 200) break;//超時(shí)退出
cs=1; //清初片選信號(hào)
return r1; //返回狀態(tài)值
}
//*******************SD開(kāi)初始化函數(shù)**************************[!--empirenews.page--]
unsigned char sd_reset()
{
unsigned char i,tmp;
unsigned char retry; //重復(fù)次數(shù)
unsigned char r1=0;
retry=0;
delay();
delay();
do
{
for(i=0;i<100;i++) SPI_WriteByte(0xff);
r1 = SD_SendCommand(0,0);//發(fā)idle命令
retry++;
if(retry>20) return 1; //超時(shí)退出
} while(r1 != 0x01); //等待IDLE命令返回
retry = 0;
cs=0;
do
{
for(i=0;i<100;i++) SPI_WriteByte(0xff);
r1 = SD_SendCommand(1, 0); //發(fā)Active命令
retry++;
if(retry>254) return 1; //超時(shí)退出
} while(r1);
for(i=0;i<100;i++) SPI_WriteByte(0xff);
r1 = SD_SendCommand(59, 0); //關(guān)crc
if (r1) return 1; //返回不正確,退出初始化
for(i=0;i<100;i++) SPI_WriteByte(0xff);
r1 = SD_SendCommand(16, 512); //設(shè)扇區(qū)大小512
if(r1!=0) return 1; //返回不正確,退出初始化
return 0; //正常返回
}
//********************寫(xiě)一個(gè)扇區(qū)**************************
unsigned char SD_WriteSingleBlock(unsigned long sector)
{
unsigned char r1;
unsigned int i;
unsigned char retry=0;
do
{
for(i=0;i<100;i++) SPI_WriteByte(0xff);
r1 = SD_SendCommand(24, sector<<9);//寫(xiě)命令
retry++;
if(retry>10) return 1; //超時(shí)退出
} while(r1 != 0x00);
cs=0;
SPI_WriteByte(0xff);
SPI_WriteByte(0xff);
SPI_WriteByte(0xff);
SPI_WriteByte(0xff);
SPI_WriteByte(0xff);
SPI_WriteByte(0xff);
SPI_WriteByte(0xfe); //發(fā)開(kāi)始符
for(i=0; i<512; i++) //送512字節(jié)數(shù)據(jù)
{
if(i<255) SPI_WriteByte(i); //發(fā)送0--255
else SPI_WriteByte(512-i); //發(fā)送255--0
}
SPI_WriteByte(0x95);
SPI_WriteByte(0x95); //16-bits CRC
r1 = SPI_WriteByte(0xff); //讀響應(yīng)位
if(retry++ >10) return 1; //超時(shí)退出
while(!((r1&0x0f)==5)); //等待數(shù)據(jù)成功接受返回信息
while(!(SPI_WriteByte(0xff))); //等待SD卡內(nèi)部編程完成
return 0;
}
//******************讀SD卡一個(gè)扇區(qū)************************
unsigned char SD_ReadSingleBlock(unsigned long sector)
{
unsigned char r1,temp;
unsigned int i,j;
unsigned char retry=0;
do
{
r1 = SD_SendCommand(17, sector<<9);//讀命令
retry++;
if(retry>10) return 1; //超時(shí)退出
} while(r1 != 0x00);
cs=0;
while(SPI_WriteByte(0xff)!= 0xfe) //等待接收到開(kāi)始字節(jié)
{
if(retry++ >100) return 1; //超時(shí)退出
}
for(i=0; i<512; i++) //讀512個(gè)數(shù)據(jù)
{
temp = SPI_WriteByte(0xff); //讀取接收到的數(shù)據(jù)
lcd[0]=(temp/100)+48;
lcd[1]=((temp%100)/10)+48;
lcd[2]=((temp%100)%10)+48;
lcd_display(); //讀取數(shù)據(jù)送顯示
for(j=0;j<500;j++) {delay();}
}
SPI_WriteByte(0xff); //偽16-bits crc
SPI_WriteByte(0xff);
cs=1;
return 0;
}
//***********************延時(shí)程序*************************
void delay() //延時(shí)程序
{
int i; //定義整形變量
for(i=0x100;i--;); //延時(shí)
}
//************************主函數(shù)**************************
int main(void)
{
unsigned char loop,res;
delay();
delay();
delay();
loop=1;
cs=1;
while(loop)
{
spi_init(); //調(diào)用系統(tǒng)初始化函數(shù)
res= sd_reset(); //調(diào)用SD卡初始化函數(shù)
if(res) break; //SD卡初始化是否正常,不正常,退出循環(huán),不執(zhí)行下面的讀寫(xiě)操作
SD_WriteSingleBlock(1); //調(diào)用寫(xiě)SD卡單BLOCK函數(shù),其中扇區(qū)號(hào)為1
if(res) break;
SD_ReadSingleBlock(1); //調(diào)用讀SD卡單BLOCK函數(shù),其中扇區(qū)號(hào)為1
if(res) break;
loop=0;
while(1);
}
while(1);
}