新聞中心

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

        STC52單片機(jī)的SD卡底層驅(qū)動(dòng)——SPI

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

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

        本文引用地址:http://www.104case.com/article/201611/319664.htm

        定義聲明:

        #ifndef _SD_H_
        #define _SD_H_

        #include

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

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


        #define INIT_CMD0_ERROR 0x01 //CMD0錯(cuò)誤
        #define INIT_CMD1_ERROR 0x02//CMD1錯(cuò)誤
        #define WRITE_BLOCK_ERROR 0x03//寫(xiě)塊錯(cuò)誤
        #define READ_BLOCK_ERROR 0x04//讀塊錯(cuò)誤


        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

        代碼實(shí)現(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); //補(bǔ)充120個(gè)時(shí)鐘,喚醒SPI
        }
        SD_CS = 0; //打開(kāi)片選
        time=0;
        do{
        temp=SD_Write_Cmd(pcmd);//寫(xiě)入CMD0
        time++;
        if(time==TRY_TIME){
        SD_CS = 1; //關(guān)閉片選
        return(INIT_CMD0_ERROR); //CMD0 寫(xiě)入失敗
        }
        }while(temp!=0x01);

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

        SD_spi_write(0xff);//補(bǔ)充8個(gè)時(shí)鐘,提高兼容性

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

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

        time = 0;
        do{
        temp = SD_Write_Cmd(pcmd);
        time++;
        if(time==TRY_TIME){ //CMD1寫(xiě)入失敗
        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); //補(bǔ)充8個(gè)時(shí)鐘
        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);//寫(xiě)入CMD0
        time++;
        if(time == TRY_TIME)
        {
        SD_CS = 1; //關(guān)閉片選
        return(temp); //寫(xiě)入失敗
        }
        }while(temp!=0);

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

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

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

        SD_spi_write(0xff); //兩個(gè)字節(jié)的CRC校驗(yàn)碼
        SD_spi_write(0xff);

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

        SD_CS = 1;

        SD_spi_write(0xff);//補(bǔ)充8個(gè)時(shí)鐘
        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é)地址寫(xiě)入到CMD17字節(jié)序列中
        pcmd[2]=((addr&0x00FF0000)>>16);
        pcmd[3]=((addr&0x0000FF00)>>8);

        SD_CS=0;//打開(kāi)片選

        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,說(shuō)明后面是512字節(jié)的數(shù)據(jù)

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

        SD_spi_read(); //讀取兩個(gè)字節(jié)的CRC校驗(yàn)碼
        SD_spi_read();

        SD_CS=1;

        SD_spi_write(0xff); //補(bǔ)充8個(gè)時(shí)鐘

        return 0;

        }



        評(píng)論


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

        關(guān)閉
        主站蜘蛛池模板: 莱阳市| 黄浦区| 新竹市| 孝昌县| 芦溪县| 诸暨市| 镇江市| 罗山县| 吉木萨尔县| 策勒县| 北宁市| 庄河市| 同江市| 红安县| 临沂市| 冕宁县| 綦江县| 玉环县| 安吉县| 长治县| 搜索| 于田县| 惠来县| 电白县| 乌拉特中旗| 五原县| 呈贡县| 荔波县| 怀仁县| 恩平市| 襄汾县| 新蔡县| 富平县| 星子县| 开阳县| 沙田区| 秦皇岛市| 全州县| 凤翔县| 旬邑县| 阳曲县|