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