#include<reg52.h> #include<intrins.h> #define uint unsigned int #define uchar unsigned char //錯(cuò)誤碼定義// #define cmd0_error 0x01 #define cmd1_error 0x02 #define write_error 0x03 #define read_error 0x04 /*位定義*/ sbit so=P1^0; //定義主機(jī)接收位 sbit clk=P1^1; //定義時(shí)鐘位 sbit si=P1^2; //定義主機(jī)發(fā)送數(shù)據(jù)位 sbit cs=P1^3; //定義片選位 uchar xdata shuju[512]={0}; //定義數(shù)據(jù)緩沖數(shù)組 uchar flag_time; //定義標(biāo)志時(shí)間,因?yàn)楫?dāng)sd卡進(jìn)行初始化時(shí)需要降低 //通信速度,所以通過(guò)該標(biāo)志來(lái)寫(xiě)1來(lái)降低速度 void delay(uint x) //通信延時(shí)函數(shù) { while(x--) _nop_(); } void delay1(uint a) { uint i,j; for(i=0;i<a;i++) for(j=0;j<120;j++); } //寫(xiě)一字節(jié)數(shù)據(jù)// void write_sd(uchar date) { uchar i; CY=0; clk=1; for(i=0;i<8;i++) { clk=0; date=date<<1; si=CY; if(flag_time==1) //用來(lái)判斷是否處于初始化,如果是降低通信速度 delay(10); _nop_(); //用來(lái)讓io口數(shù)據(jù)更穩(wěn)定,也可以省略 clk=1; _nop_(); if(flag_time==1) delay(10); } } //讀取sd卡一個(gè)字節(jié)數(shù)據(jù)// uchar read_sd() { uchar i,temp=0; so=1; //一定要先將其置1否則會(huì)出現(xiàn)錯(cuò)誤 //因?yàn)槿绻戎?單片機(jī)io口寄存器相應(yīng)位電平為低當(dāng) //當(dāng)接收到高電平后可能sd卡電平不足使其io變?yōu)楦唠娖? clk=1; for(i=0;i<8;i++) { clk=0; if(flag_time==1) delay(10); temp<<=1; temp=temp|so; _nop_(); clk=1; _nop_(); if(flag_time==1) delay(10); } return temp; } //向sd卡寫(xiě)命令// uchar write_cmd(uchar *cmd) { uchar i,time,temp; si=1; for(i=0;i<6;i++) //發(fā)送六字節(jié)命令 { write_sd(cmd[i]); } time=0; do { temp=read_sd(); time++; } while((temp==0xff)&&(time<100)); //判斷命令是否寫(xiě)入成功,當(dāng)讀取到so不為0xff時(shí)命令寫(xiě)入成功 //當(dāng)temp==0xff時(shí)為真且沒(méi)發(fā)送100次為真繼續(xù)執(zhí)行 //但是又不能無(wú)限制等待所以讓命令寫(xiě)入100次結(jié)束 return temp; //返回讀取的數(shù)據(jù) } //復(fù)位函數(shù)// uchar sd_reset() { uchar i,temp=0xff,time; uchar table[]={0x40,0x00,0x00,0x00,0x00,0x95}; flag_time=1; cs=1; for(i=0;i<0x0f;i++) //復(fù)位時(shí)最少寫(xiě)入74個(gè)時(shí)鐘周期 { write_sd(0xff); } cs=0; time=0;//打開(kāi)片選 do { temp=write_cmd(table); //寫(xiě)入cmd0 time++; if(time==100) return(cmd0_error); } while(temp!=0x01); //等待命令CMD0的響應(yīng) cs=1; //關(guān)閉片選 write_sd(0xff); //補(bǔ)償8個(gè)時(shí)鐘 return 0; } //初始化函數(shù)此函數(shù)決定SD卡的工作模式 選擇SPI還是SD模式// uchar sd_init() { uchar time=0,temp=0xff; uchar table[]={0x41,0x00,0x00,0x00,0x00,0xff}; //命令碼 flag_time=1; cs=0; time=0; do { temp=write_cmd(table); time++; if(time==100) return 0x02; } while(temp!=0x00); //等待命令CMD1響應(yīng) flag_time=0; cs=1; write_sd(0xff); //補(bǔ)償8個(gè)時(shí)鐘 return 0; } //寫(xiě)sd卡扇區(qū)// uchar xie_sd_shanqu(unsigned long int add,uchar *buffer) { uchar temp,time; uint i; uchar table[]={0x58,0x00,0x00,0x00,0x00,0xff}; add=add<<9; //add=add*512 //由于sd卡操作一次性只能寫(xiě)一個(gè)扇區(qū)也就是512個(gè)字節(jié) //所以這里通過(guò)將長(zhǎng)整型地址左移九位來(lái)將地址乘上512 //用于地址操作 table[1]=((add&0xff000000)>>24); table[2]=((add&0x00ff0000)>>16); table[3]=((add&0x0000ff00)>>8); cs=0; time=0; do { temp=write_cmd(table); //寫(xiě)入寫(xiě)扇區(qū)命令 time++; if(time==100) { return(write_error); } } while(temp!=0x00); //判斷命令是否寫(xiě)入成功成功時(shí)返回0x00 for(i=0;i<20;i++) //補(bǔ)充若干時(shí)鐘 { write_sd(0xff); } write_sd(0xfe); //寫(xiě)入開(kāi)始字節(jié)0xfe,后面要寫(xiě)入512字節(jié)數(shù)據(jù) for(i=0;i<512;i++) { write_sd(buffer[i]); } write_sd(0xff); write_sd(0xff); //兩字節(jié)奇偶校驗(yàn) temp=read_sd(); //讀取返回值 if((temp&0x1f)!=0x05) //如果返回值是 xxx00101 說(shuō)明數(shù)據(jù)已經(jīng)被寫(xiě)入 { cs=1; return(write_error); } while(read_sd()!=0xff); //等待sd卡不忙 數(shù)據(jù)寫(xiě)入成功 cs=1; //關(guān)閉片選 write_sd(0xff); //補(bǔ)償8 個(gè)時(shí)鐘 return 0; } //讀取sd卡扇區(qū)// uchar duqushanqu(unsigned long add,uchar *buffer) { uchar temp,time=0; uint i; uchar table[]={0x51,0x00,0x00,0x00,0x00,0xff}; add=add<<9; table[1]=((add&0xff000000)>>24); table[2]=((add&0x00ff0000)>>16); table[3]=((add&0x0000ff00)>>8); cs=0; //打開(kāi)片選 do { temp=write_cmd(table); //寫(xiě)命令 time++; if(time==100) { return read_error; } } while(temp!=0); write_sd(0xff); //補(bǔ)償8個(gè)時(shí)鐘 while(read_sd()!=0xfe); //一直讀取等待0xfe for(i=0;i<512;i++) { buffer[i]=read_sd(); } write_sd(0xff); //兩字節(jié)奇偶校驗(yàn)位 write_sd(0xff); cs=1; write_sd(0xff); //補(bǔ)償8個(gè)時(shí)鐘 return 0; } /*在P0上接八個(gè)發(fā)光二極管用來(lái)顯示讀取到的數(shù)據(jù) 首先在數(shù)組(shuju)里面放入i用于顯示,再將其 寫(xiě)入SD卡扇區(qū),然后在讀取出SD卡里的數(shù)據(jù)*/ void main() { uint i=0; P2=0x00; P0=0xff; sd_reset(); sd_init(); ///初始化sd卡 for(i=0;i<512;i++) { shuju[i]=i; //向數(shù)據(jù)數(shù)組里面寫(xiě)入數(shù)據(jù) } for(i=0;i<512;i++) { xie_sd_shanqu(1,shuju); //將數(shù)據(jù)數(shù)組里面的數(shù)據(jù)寫(xiě)入sd卡 } for(i=0;i<2;i++) { shuju[i]=0; //清零數(shù)據(jù)數(shù)組用來(lái)存儲(chǔ)從sd卡讀取到的數(shù)據(jù) } duqushanqu(1,shuju); //讀取扇區(qū)數(shù)據(jù) while(1) { for(i=0;i<512;i++) { P0=shuju[i]; //顯示扇區(qū)數(shù)據(jù) delay1(200); } } }