使用的芯片是STC15系列的IAP15F2K61S2,开发板是51的xl2000。把芯片座上的51芯片拔掉换成STC的,混合模式。(配置够低吧)
源码由51开发板例程的实验26修改而来。
浏览了网上的教程,目前SD卡基本有以下几种,对应着不同的初始化和读写方式:

一般来说刚上电时,
SD卡不支持CMD1而支持CMD55,
MMC卡不支持CMD55而支持CMD1.
通过CMD8来区分SD1.1和SD2.0卡,
通过ACMD41来区分SD2.0 SDSC or SDHC.

我手头有六张1~16GB的不同容量的SD卡,1G/2G/8G/16G各一张,4G两张。经过测试,已经可以成功地向其中的5张SD卡读写数据块,另有一张class6的4G卡没有读写成功。在这过程中,初始化的过程与大佬们前述的结果并不一样,例如协议1.0与2.0的卡在CMD8命令下均返回0x01,SD2.0 SDSC卡初始化可以返回正常值但不能读出写入,等等。在此列出1G,2G,4G及以上SD卡不同的初始化代码以及测试代码。

其中只有HAL.c的SdInit函数不一样,其他代码是共用的。

SD卡模块
HAL.h

#include "config.h"sbit SD_CS  =P1^1;
sbit SD_DI  =P1^2;
sbit SD_CLK =P1^3;
sbit SD_DO  =P1^4;unsigned char SdInit(void);
unsigned char SdReadBlock(unsigned char *Block, unsigned long address,int len);
unsigned char SdWriteBlock(unsigned char *Block, unsigned long address,int len);
unsigned char SdWriteBlock2(unsigned char *Block, unsigned long address,int len);void ComSendByte(unsigned char c);

HAL.c
1G卡:CMD0+CMD8+CMD1

#include "HAL.H"char csd[16];//============================================================
//写一字节到SD卡,模拟SPI总线方式
void SdWrite(unsigned char  n)
{unsigned char i;for(i=8;i;i--){SD_CLK=0;SD_DI=(n&0x80);n<<=1;SD_CLK=1;}SD_DI=1;
}
//================================================================
//从SD卡读一字节,模拟SPI总线方式
unsigned char SdRead()
{unsigned char n,i;for(i=8;i;i--){SD_CLK=0;SD_CLK=1;n<<=1;if(SD_DO) n|=1;}return n;
}
//================================================================
//检测SD卡的响应
unsigned char SdResponse()
{unsigned char i=0,response;while(i<=8){response = SdRead();if(response==0x00)break;if(response==0x01)break;i++;}return response;
}
//================================================================
//发命令到SD卡
void SdCommand(unsigned char command, unsigned long argument, unsigned char CRC)
{SdWrite(command|0x40);SdWrite(((unsigned char *)&argument)[0]);SdWrite(((unsigned char *)&argument)[1]);SdWrite(((unsigned char *)&argument)[2]);SdWrite(((unsigned char *)&argument)[3]);SdWrite(CRC);
}
//================================================================
//初始化SD卡
unsigned char SdInit(void)
{int delay=0, trials=0;unsigned char i;unsigned char response=0x01;SD_CS=1;for (i=0;i<0x0f;i++)    {SdWrite(0xff);}SD_CS=0;//Send Command 0 to put MMC in SPI modedo{SdCommand(0x00,0,0x95);response=SdResponse();trials++;if(trials>=200){return 0xfe;}}while(response!=0x01);trials=0;do{SdCommand(0x08,0x1AA,0x87);response=SdResponse();trials++;if(trials>=200){return 0xfd;}}while(response!=0x01);trials = 0;do{SD_CS=1;SdWrite(0xff);SD_CS=0;SdCommand(0x01,0x00ffc000,0xff);response=SdResponse();trials++;if(trials>=200){return 0xfa;}} while(response==0x01);SD_CS=1;SdWrite(0xff);return 1;
}
//================================================================
//往SD卡指定地址写数据,一次最多512字节
unsigned char SdWriteBlock(unsigned char *Block, unsigned long address,int len)
{unsigned int  count;unsigned char dataResp;//Block size is 512 bytes exactly//First Lower SSSD_CS=0;//Then send write commandSdCommand(0x18,address,0xff);if(SdResponse()==0x00){SdWrite(0xff);SdWrite(0xff);SdWrite(0xff);//command was a success - now send data//start with DATA TOKEN = 0xFESdWrite(0xfe);//now send datafor(count=0;count<len;count++) SdWrite(*Block++);for(;count<512;count++) SdWrite(0);//data block sent - now send checksumSdWrite(0xff);                              //两字节CRC校验, 为0XFFFF 表示不考虑CRCSdWrite(0xff);//Now read in the DATA RESPONSE tokendataResp=SdRead();//Following the DATA RESPONSE token//are a number of BUSY bytes//a zero byte indicates the MMC is busywhile(SdRead()==0);dataResp=dataResp&0x0f;   //mask the high byte of the DATA RESPONSE tokenSD_CS=1;SdWrite(0xff);if(dataResp==0x0b){//P0=0x0b;//printf("DATA WAS NOT ACCEPTED BY CARD -- CRC ERROR\n");return 0;}if(dataResp==0x05){//P0=0x05;return 1;}//printf("Invalid data Response token.\n");//P0=0x02;return 0;}//P0=0x01;//printf("Command 0x18 (Write) was not received by the MMC.\n");return 0;
}
//=======================================================================
//从SD卡指定地址读取数据,一次最多512字节
unsigned char SdReadBlock(unsigned char *Block, unsigned long address,int len)
{unsigned int count;int trials=0;//Block size is 512 bytes exactly//First Lower SS//  printf("MMC_read_block\n");SD_CS=0;//Then send write commandSdCommand(0x11,address,0xff);if(SdResponse()==0x00){    //command was a success - now send data//start with DATA TOKEN = 0xFEwhile(SdRead()!=0xfe);for(count=0;count<len;count++) *Block++=SdRead();    for(;count<512;count++)  SdRead();//data block sent - now send checksumSdRead();SdRead();//Now read in the DATA RESPONSE tokenSD_CS=1;SdRead();return 1;}
//  printf("Command 0x11 (Read) was not received by the MMC.\n");return 0;
}

HAL.c
2G卡:CMD0+CMD8+CMD55+CMD1

#include "HAL.H"char csd[16];//============================================================
//写一字节到SD卡,模拟SPI总线方式
void SdWrite(unsigned char  n)
{unsigned char i;for(i=8;i;i--){SD_CLK=0;SD_DI=(n&0x80);n<<=1;SD_CLK=1;}SD_DI=1;
}
//================================================================
//从SD卡读一字节,模拟SPI总线方式
unsigned char SdRead()
{unsigned char n,i;for(i=8;i;i--){SD_CLK=0;SD_CLK=1;n<<=1;if(SD_DO) n|=1;}return n;
}
//================================================================
//检测SD卡的响应
unsigned char SdResponse()
{unsigned char i=0,response;while(i<=8){response = SdRead();if(response==0x00)break;if(response==0x01)break;i++;}return response;
}
//================================================================
//发命令到SD卡
void SdCommand(unsigned char command, unsigned long argument, unsigned char CRC)
{SdWrite(command|0x40);SdWrite(((unsigned char *)&argument)[0]);SdWrite(((unsigned char *)&argument)[1]);SdWrite(((unsigned char *)&argument)[2]);SdWrite(((unsigned char *)&argument)[3]);SdWrite(CRC);
}
//================================================================
//初始化SD卡
unsigned char SdInit(void)
{int delay=0, trials=0;unsigned char i;unsigned char response=0x01;SD_CS=1;for (i=0;i<0x0f;i++)    {SdWrite(0xff);}SD_CS=0;//Send Command 0 to put MMC in SPI modedo{SdCommand(0x00,0,0x95);response=SdResponse();trials++;if(trials>=200){return 0xfe;}}while(response!=0x01);trials=0;do{SdCommand(0x08,0x1AA,0x87);response=SdResponse();trials++;if(trials>=200){return 0xfd;}}while(response!=0x01);SdCommand(55, 0, 0);response=SdResponse();trials = 0;do{SD_CS=1;SdWrite(0xff);SD_CS=0;SdCommand(0x01,0x00ffc000,0xff);response=SdResponse();trials++;if(trials>=200){return 0xfa;}} while(response==0x01);SD_CS=1;SdWrite(0xff);return 1;
}
//================================================================
//往SD卡指定地址写数据,一次最多512字节
unsigned char SdWriteBlock(unsigned char *Block, unsigned long address,int len)
{unsigned int  count;unsigned char dataResp;//Block size is 512 bytes exactly//First Lower SSSD_CS=0;//Then send write commandSdCommand(0x18,address,0xff);if(SdResponse()==0x00){SdWrite(0xff);SdWrite(0xff);SdWrite(0xff);//command was a success - now send data//start with DATA TOKEN = 0xFESdWrite(0xfe);//now send datafor(count=0;count<len;count++) SdWrite(*Block++);for(;count<512;count++) SdWrite(0);//data block sent - now send checksumSdWrite(0xff);                              //两字节CRC校验, 为0XFFFF 表示不考虑CRCSdWrite(0xff);//Now read in the DATA RESPONSE tokendataResp=SdRead();//Following the DATA RESPONSE token//are a number of BUSY bytes//a zero byte indicates the MMC is busywhile(SdRead()==0);dataResp=dataResp&0x0f;   //mask the high byte of the DATA RESPONSE tokenSD_CS=1;SdWrite(0xff);if(dataResp==0x0b){//P0=0x0b;//printf("DATA WAS NOT ACCEPTED BY CARD -- CRC ERROR\n");return 0;}if(dataResp==0x05){//P0=0x05;return 1;}//printf("Invalid data Response token.\n");//P0=0x02;return 0;}//P0=0x01;//printf("Command 0x18 (Write) was not received by the MMC.\n");return 0;
}
//=======================================================================
//从SD卡指定地址读取数据,一次最多512字节
unsigned char SdReadBlock(unsigned char *Block, unsigned long address,int len)
{unsigned int count;int trials=0;//Block size is 512 bytes exactly//First Lower SS//  printf("MMC_read_block\n");SD_CS=0;//Then send write commandSdCommand(0x11,address,0xff);if(SdResponse()==0x00){    //command was a success - now send data//start with DATA TOKEN = 0xFEwhile(SdRead()!=0xfe);for(count=0;count<len;count++) *Block++=SdRead();    for(;count<512;count++)  SdRead();//data block sent - now send checksumSdRead();SdRead();//Now read in the DATA RESPONSE tokenSD_CS=1;SdRead();return 1;}
//  printf("Command 0x11 (Read) was not received by the MMC.\n");return 0;
}

HAL.c
4G以上:CMD0+CMD8+CMD55+CMD41

#include "HAL.H"//============================================================
//写一字节到SD卡,模拟SPI总线方式
void SdWrite(unsigned char  n)
{unsigned char i;for(i=8;i;i--){SD_CLK=0;SD_DI=(n&0x80);n<<=1;SD_CLK=1;}SD_DI=1;
}
//================================================================
//从SD卡读一字节,模拟SPI总线方式
unsigned char SdRead()
{unsigned char n,i;for(i=8;i;i--){SD_CLK=0;SD_CLK=1;n<<=1;if(SD_DO) n|=1;}return n;
}
//================================================================
//检测SD卡的响应
unsigned char SdResponse()
{unsigned char i=0,response;while(i<=8){response = SdRead();if(response==0x00)break;if(response==0x01)break;i++;}return response;
}
//================================================================
//发命令到SD卡
void SdCommand(unsigned char command, unsigned long argument, unsigned char CRC)
{SdWrite(command|0x40);SdWrite(((unsigned char *)&argument)[0]);SdWrite(((unsigned char *)&argument)[1]);SdWrite(((unsigned char *)&argument)[2]);SdWrite(((unsigned char *)&argument)[3]);SdWrite(CRC);
}
//================================================================
//初始化SD卡
unsigned char SdInit(void)
{int delay=0, trials=0;unsigned char i;unsigned char response=0x01;SD_CS=1;for (i=0;i<0x0f;i++)    {SdWrite(0xff);}SD_CS=0;//Send Command 0 to put MMC in SPI modedo{SdCommand(0x00,0,0x95);response=SdResponse();trials++;if(trials>=200){return 0xfe;}}while(response!=0x01);USB2.0trials=0;do{SdCommand(0x08,0x1AA,0x87);response=SdResponse();trials++;if(trials>=200){return 0xfd;}}while(response!=0x01);SD_CS=1;SdWrite(0xff);SD_CS=0;trials =0;do{SdRead();SdRead();SdRead();SdRead();SdCommand(55, 0, 0);response=SdResponse();if(response!=0x01){return 0xfb;}SdCommand(41, 0x40000000, 0);response=SdResponse();trials++;if(trials>=200){return 0xf7;}}while(response!=0x00);SD_CS=1;SdWrite(0xff);return 1;
}
//================================================================
//往SD卡指定地址写数据,一次最多512字节
unsigned char SdWriteBlock(unsigned char *Block, unsigned long address,int len)
{unsigned int  count;unsigned char dataResp;//Block size is 512 bytes exactly//First Lower SSSD_CS=0;//Then send write commandSdCommand(0x18,address,0xff);if(SdResponse()==0x00){SdWrite(0xff);SdWrite(0xff);SdWrite(0xff);//command was a success - now send data//start with DATA TOKEN = 0xFESdWrite(0xfe);//now send datafor(count=0;count<len;count++) SdWrite(*Block++);for(;count<512;count++) SdWrite(0);//data block sent - now send checksumSdWrite(0xff);                              //两字节CRC校验, 为0XFFFF 表示不考虑CRCSdWrite(0xff);//Now read in the DATA RESPONSE tokendataResp=SdRead();//Following the DATA RESPONSE token//are a number of BUSY bytes//a zero byte indicates the MMC is busywhile(SdRead()==0);dataResp=dataResp&0x0f;   //mask the high byte of the DATA RESPONSE tokenSD_CS=1;SdWrite(0xff);if(dataResp==0x0b){//P0=0x0b;//printf("DATA WAS NOT ACCEPTED BY CARD -- CRC ERROR\n");return 0;}if(dataResp==0x05){//P0=0x05;return 1;}//printf("Invalid data Response token.\n");//P0=0x02;return 0;}//P0=0x01;//printf("Command 0x18 (Write) was not received by the MMC.\n");return 0;
}
//=======================================================================
//从SD卡指定地址读取数据,一次最多512字节
unsigned char SdReadBlock(unsigned char *Block, unsigned long address,int len)
{unsigned int count;int trials=0;//Block size is 512 bytes exactly//First Lower SS//  printf("MMC_read_block\n");SD_CS=0;//Then send write commandSdCommand(0x11,address,0xff);  if(SdResponse()==0x00){  //command was a success - now send data//start with DATA TOKEN = 0xFEwhile(SdRead()!=0xfe);for(count=0;count<len;count++) *Block++=SdRead();    for(;count<512;count++)  SdRead();//data block sent - now send checksumSdRead();SdRead();//Now read in the DATA RESPONSE tokenSD_CS=1;SdRead();return 1;}
//  printf("Command 0x11 (Read) was not received by the MMC.\n");return 0;
}

main.c
略有改动,以确认读出的数据确实是之前写入。

#include <string.h>
#include "HAL.H"char buf[16];
char buf2[16]={0xAA,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0};//=======================================================
//延时子程序
void delay()
{unsigned int i;for(i=0;i<0x8000;i++);
}
//=======================================================
//主程序
char code SST516[3] _at_ 0x003b;
main()
{
unsigned char rsp;CLK_DIV=0x03;P0M0=0xff;//          00000000   11111111  高阻 下同P0M1=0xff;//   P1M0=0xff;//           11111111  11111111 P1M1=0xff;//P2M0=0xff;//  11111111   111111111P2M1=0xff;//常规       P3M0=0xff; P3M1=0xff;//TXD推挽RXD常规    11111111   11111111P4M0=0xff; P4M1=0xff;//11111111   11111111P5M0=0xff; P5M1=0xff;// 00000000   00000010P1M0=0xef;//           11111111  11110001 P1M1=0xe1;//           P11 推挽 P12推挽 P13推挽 P14常规/*
sbit SD_CS  =P1^1;     //SD/MMC接口定义  qinyg@163.net
sbit SD_DI  =P1^2;
sbit SD_CLK =P1^3;
sbit SD_DO  =P1^4;*/delay();                                   //上电延时delay();delay();delay();delay();                                  //上电延时delay();delay();delay();SdInit();while(1) {rsp=SdInit(); //P0=rsp;if(rsp==1)                          //初始化SD卡{SdReadBlock(buf2,1024,16);             //从SD卡地址为1024的地方读16字节数据到BUFFER,  最多一次只能读512字节//buf2[0]+=2;P0 = buf2[0];                          //只用第一字节, 送到P0口buf[0]++;                              //自加1delay();//rewrapBlock();//delay();                             //延时SdWriteBlock(buf,1024,sizeof(buf));//写回SD卡   }delay();  //延时}   }

测试成功,得出判断是所有的卡都支持2.0,其中1G卡很可能是SD SC卡,2G卡类型还不确定,4G及以上都是SD HC卡。
很可惜,还有一张class6的4G卡虽然初始化返回正确但无法读写数据(成功的那张是class4)。尝试了不同的读写速度也无济于事。留待日后琢磨。
不像51必须用IO口模拟时序,STC15自带SPI机制。所以接下去打算利用芯片的SPI功能改写读写逻辑,以及学习利用znFTP或CH375/376实现文件访问。

STC15单片机读写大容量SD卡(IO口模拟SPI模式)相关推荐

  1. io口模拟spi,stm32f103与MS5611基于spi总线的温度压力高度数据读取

    以下文件为源文件 /** -----------------------MS5611驱动 && IO口模拟SPI驱动------------------------- ******** ...

  2. STM32+MAX6675利用io口模拟SPI获取实时温度数据程序及代码

    STM32+MAX6675利用io口模拟SPI获取实时温度数据程序及代码 本文采用的芯片为STM32F103RCT6 温度芯片为MAX6675 因为芯片的spi口只有3个,有部分需要外接W25Q128 ...

  3. 单片机IO口模拟SPI四种模式的程序

    2013年09月21日 10:00:02 zyboy2000 阅读数:23924 #include "iom8535v.h" #define _CPOL 1 #define _CP ...

  4. STM32 IO口模拟ISO7816(PSAM卡)协议

    单片机:stm32f103c8t6   实现方式:纯IO口模拟(RST.I/O.CLK均为普通IO口) 实现功能:接触式CPU卡.PSAM.SIM读(写) 网上有很多相关的代码,有的是用自带的智能卡接 ...

  5. WINCE5.0+S3C2440支持大容量SD卡(SDHC卡)

    ********************************LoongEmbedded************************ 作者:LoongEmbedded(kandi) 时间:201 ...

  6. 单片机IO口模拟串口程序(发送+接收

    单片机IO口模拟串口程序(发送+接收)[转] qcmc 发表于 - 2011-6-23 0:42:00 前一阵一直在做单片机的程序,由于串口不够,需要用IO口来模拟出一个串口.经过若干曲折并参考了一些 ...

  7. 串口发送程序linux,单片机IO口模拟串口程序(发送+接收

    前一阵一直在做单片机的程序,由于串口不够,需要用IO口来模拟出一个串口.经过若干曲折并参考了一些现有的资料,基本上完成了.现在将完整的测试程序,以及其中一些需要总结的部分贴出来. 程序硬件平台:11. ...

  8. 20120726-分析解决“STM8L101单片机IO口模拟串口通讯发生的奇怪现象”

    近日因工作关系,需要用STM8L101F3P6这款单片机用IO口模拟串行通讯,波特率2400bps,前辈同事已经写完了程序,我需要拿来研究一下该款MCU的低功耗的情况,而在调试的过程中,发现1个奇怪的 ...

  9. 国产单片机IO口模拟IrDA1.0协议

    单片机IO口模拟IrDA1.0协议 IrDA1.0协议是一种利用红外通信的无线传输协议,可以很好的解决一些便携式设备与主机之间通信的问题,具有携带方便,低功耗,成本低,传输可靠等特点,缺点是传输距离较 ...

最新文章

  1. 996 成福报?拼多多个别部门让员工在 “11-11-6” 和 996 中二选一
  2. tasklist 妙用
  3. python爬虫数据分析可以做什么-自学Python爬虫学到什么程度?就可以去找工作了?...
  4. 依次提取二进制1位置的数字,
  5. Conversion to Dalvik format failed with error 1
  6. vf求计算机系统当前日期的年份数,计算机二级VF常用函数列表
  7. 执行ios命令_MEDUZA:一款针对iOS应用程序的通用SSL解绑工具
  8. Java 8 八年不倒、IntelliJ IDEA 力压 Eclipse
  9. 一个导入到本地读取文档的方法
  10. Rabbitmq消息过期时间设置
  11. 计算机网络class5(分层结构、协议、接口、服务)
  12. unity shader base pass and additional pass
  13. 移动端图片裁剪上传—jQuery.cropper.js
  14. 可不可以拿树莓派学python_【如何利用树莓派学习Linux及Python?】-看准网
  15. CU的递归划分详细介绍
  16. 4种“附近的人”实现方式
  17. win10计算机屏幕暗怎么办,Win10电脑屏幕亮度调不了怎么办
  18. 拼多多商家推广常见问题解答!
  19. lol服务器显示40ms,一个简单insert 语句执行 40ms 原因剖析
  20. 网络硬盘(简称网盘)

热门文章

  1. 常见的网络状态码(HTTP状态码)
  2. 类脑智能:人造超级大脑
  3. 昌平北七家空调移机-空调安装电话
  4. python 写的一些ctf脚本
  5. 由浅至深探探webpack(初)
  6. Invalid bound statement (not found) 终极解决办法
  7. 银户通便捷服务加速金融智能化进程
  8. 012 相关性与线性表示总结;向量组的秩、向量组等价
  9. [已解决] EnvironmentLocationNotFound: Not a conda environment: C:\Program Files\Anaconda3
  10. Anaconda/pip 更换阿里源,助力 conda create -n 虚拟环境搭建