这次的sd卡内容比较多,写的比较多,关于卡的命令和寄存器方面内容较多下面只是简要题一下,我们只需要指导如何使用即可,深入研究相对比较困难。

什么是SD 卡?
SD 卡( Secure Digital Memory Card)中文翻译为安全数码卡, 它是在 MMC 的基础上发展而来, 是一种基于半导体快闪记忆器的新一代记忆设备,它被广泛地于便携式装置上使用,例如数码相机、个人数码助理(PDA)和多媒体播放器等。就是之前常用的内存卡,手机内存卡,数码相机内存卡,不过是容量和规格不一样的区别。

TF卡和SD卡?
SD卡又名安全数字卡,SD卡一般都用在大一些的电子设备上,如电脑、相机、摄像机等器材中。相比TF卡,SD卡的读写速度会更高,并且具备读写保护能力。TF卡又叫微型SD卡,一般常用于手机扩展内存或者行车记录仪,以及其他手持微型摄像设备,TF卡并不具备保护功能。

常见的SD卡如下图

SD卡的分类

  1. 一般SD卡 (SDSC/SD) 0—2G
  2. SDHK 高容量SD存储卡 2G—32G
  3. SDXC 容量扩大化的安全存储卡 32G–2T

通信模式

  1. SPI 模式
  2. SD模式(SDIO通信)

工作模式

  1. 卡识别模式 (主机上电复位,一直等操作命令)
  2. 数据传输模式(主机识别到卡后进入此模式)

引脚排序如下图所示
![在这里插入图片描述](https://img-blog.csdnimg.cn/a7dd9940bcea461b9c83c47ff639db10.png

普通SD卡有9个引脚,使其反面朝上,最左边为9号引脚,然后从左到右依次是1号~8号

针脚 1 2 3 4 5 6 7 8 9
SD卡模式 CD/DAT3 CMD VSS VCC CLK VSS DAT0 DAT1 DAT2
SPI模式 CS MOSI VSS VCC CLK VSS MISO NC NC

与单片机的连接接电路图

上图可以看出支持2种模式spi 和sdio

上图仅支持sdio 模式

SD卡总线拓扑
SD总线有6根通信线和三根电源供应线:
CMD——命令线是双向信号线。主机和卡通过push pull 模式工作。
DAT0-3——数据线是双向信号线。主机和卡通过push pull 模式工作。
CLK——时钟是从主机到卡的信号。CLK通过push pull 模式操作。
VDD—VDD是所有卡的电源供应线。
VSS[1:2]—VSS是2根地线。


SK卡的寄存器

  1. SD卡操作电压范围为2~3.6V。然而从内存中访问数据的电压是2.7–3.6V(32位的操作条件寄存器存储了VDD电压范围)。CSD寄存器包含访问卡数据所需的配置信息。SD卡和MMC卡的CSD不同,
  2. SD卡分为2个区: 用户区—用户通过读写命令存储安全和非安全数据。 安全保护区(Security Protected
    Area)—版权保护应用程序用来保存安全相关数据,通过SD安全规范中定义的条件验证后,由主机使用安全的读写指令完成操作。安全保护区的大小大概是总大小的1%。
**SD卡的命令**


下面是几个常用的命令(卡的命令约有50多个,根据不同产品厂商会提供参考说明)

SD卡初始化流程图解析如下图

下面是对上面流程图的分解




-----------------------------------下面会使用 模式1SPI模式进行卡的读取---------------------------------------------------------------------

SD卡初始化过程:
1、初始化与 SD 卡连接的硬件条件( MCU 的 SPI 配置, IO 口配置)**卡槽(后面会提)**电路连接好,直接插入sd卡即可;
2、上电延时( >74 个 CLK);
上电后,主机开始时钟并在CMD线上发送初始化序列,初始化序列由连续的逻辑“1”组成。序列长度为最大1毫秒,74个时钟或supply-ramp-up时间。额外的10个时钟(64个时钟后卡已准备就绪)用来实现同步。

3、复位卡( CMD0),进入 IDLE 状态;

4、发送 CMD8,检查是否支持 2.0 协议;

5、根据不同协议检查 SD 卡(命令包括: CMD55、 CMD41、 CMD58 和 CMD1 等);
上电后,包括热插入,卡进入idle状态。在该状态SD卡忽略所有总线操作直到接收到ACMD41命令。ACMD41命令是一个特殊的同步命令,用来协商操作电压范围,并轮询所有的卡。除了操作电压信息,ACMD41的响应还包括一个忙标志,表明卡还在power-up过程工作,还没有准备好识别操作,即告诉主机卡还没有就绪。主机等待(继续轮询)直到忙标志清除。单个卡的最大上电时间不能操作1秒。

6、取消片选,发多 8 个 CLK,结束初始化

SD 卡读取数据,这里通过 CMD17 来实现,具体过程如下:
1、发送 CMD17;
2、接收卡响应 R1;
3、接收数据起始令牌 0XFE;
4、接收数据;
5、接收 2 个字节的 CRC,如果不使用 CRC,这两个字节在读取后可以丢掉。
6、禁止片选之后,发多 8 个 CLK;

SD 卡的写与读数据差不多,写数据通过 CMD24来实现,具体过程如下
1、发送 CMD24;
2、接收卡响应 R1;
3、发送写数据起始令牌 0XFE;
4、发送数据;
5、发送 2 字节的伪 CRC;
6、禁止片选之后,发多 8 个 CLK;

控制程序流程(核心掌握的)

  1. 初始化SD卡
  2. SD卡读写块函数
  3. 编写主函数

/**************************下面上才源码,仅供参考*********************************/

spi.c 初始化IO口和SPI 的初始化以及准备工作

#include "spi.h"//以下是SPI模块的初始化代码,配置成主机模式
//SPI口初始化
//这里针是对SPI1的初始化
void SPI1_Init(void)
{GPIO_InitTypeDef  GPIO_InitStructure;SPI_InitTypeDef  SPI_InitStructure;/* SPI的IO口和SPI外设打开时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);/* SPI的IO口设置 */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工SPI_InitStructure.SPI_Mode = SPI_Mode_Master;     //设置SPI工作模式:设置为主SPISPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;       //设置SPI的数据大小:SPI发送接收8位帧结构SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;       //串行同步时钟的空闲状态为高电平SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;  //串行同步时钟的第二个跳变沿(上升或下降)数据被采样SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;     //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;     //定义波特率预分频的值:波特率预分频值为256SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始SPI_InitStructure.SPI_CRCPolynomial = 7;  //CRC值计算的多项式SPI_Init(SPI1, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器SPI_Cmd(SPI1, ENABLE); //使能SPI外设SPI1_ReadWriteByte(0xff);//启动传输
}//SPI1速度设置函数
//SPI速度=fAPB2/分频系数
//@ref SPI_BaudRate_Prescaler:SPI_BaudRatePrescaler_2~SPI_BaudRatePrescaler_256
//fAPB2时钟一般为84Mhz:
void SPI1_SetSpeed(u8 SPI_BaudRatePrescaler)
{SPI1->CR1&=0XFFC7;//位3-5清零,用来设置波特率SPI1->CR1|=SPI_BaudRatePrescaler; //设置SPI1速度 SPI_Cmd(SPI1,ENABLE); //使能SPI1
} //SPI1 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
u8 SPI1_ReadWriteByte(u8 TxData)
{                    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);//等待发送区空  SPI_I2S_SendData(SPI1, TxData); //通过外设SPIx发送一个byte  数据while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); //等待接收完一个byte  return SPI_I2S_ReceiveData(SPI1); //返回通过SPIx最近接收的数据 }//SPI口初始化
//这里针是对SPI2的初始化
void SPI2_Init(void)
{GPIO_InitTypeDef  GPIO_InitStructure;SPI_InitTypeDef  SPI_InitStructure;/* SPI的IO口和SPI外设打开时钟 */RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);/* SPI的IO口设置 */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //PB13/14/15复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工SPI_InitStructure.SPI_Mode = SPI_Mode_Master;       //设置SPI工作模式:设置为主SPISPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;       //设置SPI的数据大小:SPI发送接收8位帧结构SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;       //串行同步时钟的空闲状态为高电平SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;  //串行同步时钟的第二个跳变沿(上升或下降)数据被采样SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;     //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;     //定义波特率预分频的值:波特率预分频值为256SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始SPI_InitStructure.SPI_CRCPolynomial = 7;  //CRC值计算的多项式SPI_Init(SPI2, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器SPI_Cmd(SPI2, ENABLE); //使能SPI外设SPI2_ReadWriteByte(0xff);//启动传输
}//SPI2速度设置函数
//SPI速度=fAPB1/分频系数
//@ref SPI_BaudRate_Prescaler:SPI_BaudRatePrescaler_2~SPI_BaudRatePrescaler_256
//fAPB1时钟一般为36Mhz:
void SPI2_SetSpeed(u8 SPI_BaudRatePrescaler)
{SPI2->CR1&=0XFFC7;//位3-5清零,用来设置波特率SPI2->CR1|=SPI_BaudRatePrescaler; //设置SPI速度 SPI_Cmd(SPI2,ENABLE); //使能SPI2
} //SPI2 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
u8 SPI2_ReadWriteByte(u8 TxData)
{                    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);//等待发送区空  SPI_I2S_SendData(SPI2, TxData); //通过外设SPIx发送一个byte  数据while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET); //等待接收完一个byte  return SPI_I2S_ReceiveData(SPI2); //返回通过SPIx最近接收的数据 }

spi.h

#ifndef _spi_H
#define _spi_H#include "system.h"void SPI1_Init(void);             //初始化SPI1口
void SPI1_SetSpeed(u8 SpeedSet); //设置SPI1速度
u8 SPI1_ReadWriteByte(u8 TxData);//SPI1总线读写一个字节void SPI2_Init(void);             //初始化SPI2口
void SPI2_SetSpeed(u8 SpeedSet); //设置SPI2速度
u8 SPI2_ReadWriteByte(u8 TxData);//SPI2总线读写一个字节#endif

下面是sd 的驱动相关内容
sd.c

#include "sd.h"
#include "spi.h"
#include "usart.h"
#include "SysTick.h"u8 SD_Type=0;//SD卡的类型//data:要写入的数据
//返回值:读到的数据
u8 SD_SPI_ReadWriteByte(u8 dat)
{return SPI2_ReadWriteByte(dat);
}//SD卡初始化的时候,需要低速
void SD_SPI_SpeedLow(void)
{SPI2_SetSpeed(SPI_BaudRatePrescaler_256);//设置到低速模式
}//SD卡正常工作的时候,可以高速了
void SD_SPI_SpeedHigh(void)
{SPI2_SetSpeed(SPI_BaudRatePrescaler_2);//设置到高速模式
}//SPI硬件层初始化
void SD_SPI_Init(void)
{GPIO_InitTypeDef  GPIO_InitStructure;//关闭其他使用SPI2总线的片选 EN25QXX-PG13,ENC28J60-PB12,NRF24L01-PF9RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOG|RCC_APB2Periph_GPIOF, ENABLE);     //使能PB端口时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;               //PB12 推挽 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;         //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB,GPIO_Pin_12);                      //PB12上拉GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14;                 //PG13 PG14推挽GPIO_Init(GPIOG, &GPIO_InitStructure);GPIO_SetBits(GPIOG,GPIO_Pin_13);SPI2_Init();SD_CS=1;
}//取消选择,释放SPI总线
void SD_DisSelect(void)
{SD_CS=1;SD_SPI_ReadWriteByte(0xff);//提供额外的8个时钟
}//选择sd卡,并且等待卡准备OK
//返回值:0,成功;1,失败;
u8 SD_Select(void)
{SD_CS=0;if(SD_WaitReady()==0)return 0;//等待成功SD_DisSelect();return 1;//等待失败
}//等待卡准备好
//返回值:0,准备好了;其他,错误代码
u8 SD_WaitReady(void)
{u32 t=0;do{if(SD_SPI_ReadWriteByte(0XFF)==0XFF)return 0;//OKt++;          }while(t<0XFFFFFF);//等待 return 1;
}//等待SD卡回应
//Response:要得到的回应值
//返回值:0,成功得到了该回应值
//    其他,得到回应值失败
u8 SD_GetResponse(u8 Response)
{u16 Count=0xFFFF;//等待次数                             while ((SD_SPI_ReadWriteByte(0XFF)!=Response)&&Count)Count--;//等待得到准确的回应       if (Count==0)return MSD_RESPONSE_FAILURE;//得到回应失败   else return MSD_RESPONSE_NO_ERROR;//正确回应
}//从sd卡读取一个数据包的内容
//buf:数据缓存区
//len:要读取的数据长度.
//返回值:0,成功;其他,失败;
u8 SD_RecvData(u8*buf,u16 len)
{                 if(SD_GetResponse(0xFE))return 1;//等待SD卡发回数据起始令牌0xFEwhile(len--)//开始接收数据{*buf=SPI2_ReadWriteByte(0xFF);buf++;}//下面是2个伪CRC(dummy CRC)SD_SPI_ReadWriteByte(0xFF);SD_SPI_ReadWriteByte(0xFF);                                                           return 0;//读取成功
}//向sd卡写入一个数据包的内容 512字节
//buf:数据缓存区
//cmd:指令
//返回值:0,成功;其他,失败;
u8 SD_SendBlock(u8*buf,u8 cmd)
{   u16 t;            if(SD_WaitReady())return 1;//等待准备失效SD_SPI_ReadWriteByte(cmd);if(cmd!=0XFD)//不是结束指令{for(t=0;t<512;t++)SPI2_ReadWriteByte(buf[t]);//提高速度,减少函数传参时间SD_SPI_ReadWriteByte(0xFF);//忽略crcSD_SPI_ReadWriteByte(0xFF);t=SD_SPI_ReadWriteByte(0xFF);//接收响应if((t&0x1F)!=0x05)return 2;//响应错误                                                         }                                                                                   return 0;//写入成功
}//向SD卡发送一个命令
//输入: u8 cmd   命令
//      u32 arg  命令参数
//      u8 crc   crc校验值
//返回值:SD卡返回的响应
u8 SD_SendCmd(u8 cmd, u32 arg, u8 crc)
{u8 r1; u8 Retry=0; SD_DisSelect();//取消上次片选if(SD_Select())return 0XFF;//片选失效 //发送SD_SPI_ReadWriteByte(cmd | 0x40);//分别写入命令SD_SPI_ReadWriteByte(arg >> 24);SD_SPI_ReadWriteByte(arg >> 16);SD_SPI_ReadWriteByte(arg >> 8);SD_SPI_ReadWriteByte(arg);    SD_SPI_ReadWriteByte(crc); if(cmd==CMD12)SD_SPI_ReadWriteByte(0xff);//Skip a stuff byte when stop reading//等待响应,或超时退出Retry=0X1F;do{r1=SD_SPI_ReadWriteByte(0xFF);}while((r1&0X80) && Retry--);  //返回状态值return r1;
}//获取SD卡的CID信息,包括制造商信息
//输入: u8 *cid_data(存放CID的内存,至少16Byte)
//返回值:0:NO_ERR
//       1:错误
u8 SD_GetCID(u8 *cid_data)
{u8 r1;    //发CMD10命令,读CIDr1=SD_SendCmd(CMD10,0,0x01);if(r1==0x00){r1=SD_RecvData(cid_data,16);//接收16个字节的数据   }SD_DisSelect();//取消片选if(r1)return 1;else return 0;
}//获取SD卡的CSD信息,包括容量和速度信息
//输入:u8 *csd_data(存放CSD的内存,至少16Byte)
//返回值:0:NO_ERR
//       1:错误
u8 SD_GetCSD(u8 *csd_data)
{u8 r1;  r1=SD_SendCmd(CMD9,0,0x01);//发CMD9命令,读CSDif(r1==0){r1=SD_RecvData(csd_data, 16);//接收16个字节的数据 }SD_DisSelect();//取消片选if(r1)return 1;else return 0;
}   //获取SD卡的总扇区数(扇区数)
//返回值:0: 取容量出错
//       其他:SD卡的容量(扇区数/512字节)
//每扇区的字节数必为512,因为如果不是512,则初始化不能通过.
u32 SD_GetSectorCount(void)
{u8 csd[16];u32 Capacity;  u8 n;u16 csize;                          //取CSD信息,如果期间出错,返回0if(SD_GetCSD(csd)!=0) return 0;       //如果为SDHC卡,按照下面方式计算if((csd[0]&0xC0)==0x40)  //V2.00的卡{ csize = csd[9] + ((u16)csd[8] << 8) + 1;Capacity = (u32)csize << 10;//得到扇区数            }else//V1.XX的卡{  n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;csize = (csd[8] >> 6) + ((u16)csd[7] << 2) + ((u16)(csd[6] & 3) << 10) + 1;Capacity= (u32)csize << (n - 9);//得到扇区数   }return Capacity;
}//初始化SD卡
u8 SD_Init(void)
{u8 r1;      // 存放SD卡的返回值u16 retry;  // 用来进行超时计数u8 buf[4];  u16 i;SD_SPI_Init();        //初始化IOSD_SPI_SpeedLow();   //设置到低速模式 for(i=0;i<10;i++)SD_SPI_ReadWriteByte(0XFF);//发送最少74个脉冲retry=20;do{r1=SD_SendCmd(CMD0,0,0x95);//进入IDLE状态}while((r1!=0X01) && retry--);SD_Type=0;//默认无卡if(r1==0X01){if(SD_SendCmd(CMD8,0x1AA,0x87)==1)//SD V2.0{for(i=0;i<4;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF);    //Get trailing return value of R7 respif(buf[2]==0X01&&buf[3]==0XAA)//卡是否支持2.7~3.6V{retry=0XFFFE;do{SD_SendCmd(CMD55,0,0X01);  //发送CMD55r1=SD_SendCmd(CMD41,0x40000000,0X01);//发送CMD41}while(r1&&retry--);if(retry&&SD_SendCmd(CMD58,0,0X01)==0)//鉴别SD2.0卡版本开始{for(i=0;i<4;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF);//得到OCR值if(buf[0]&0x40)SD_Type=SD_TYPE_V2HC;    //检查CCSelse SD_Type=SD_TYPE_V2;   }}}else//SD V1.x/ MMC   V3{SD_SendCmd(CMD55,0,0X01);        //发送CMD55r1=SD_SendCmd(CMD41,0,0X01);  //发送CMD41if(r1<=1){     SD_Type=SD_TYPE_V1;retry=0XFFFE;do //等待退出IDLE模式{SD_SendCmd(CMD55,0,0X01); //发送CMD55r1=SD_SendCmd(CMD41,0,0X01);//发送CMD41}while(r1&&retry--);}else{SD_Type=SD_TYPE_MMC;//MMC V3retry=0XFFFE;do //等待退出IDLE模式{                                                r1=SD_SendCmd(CMD1,0,0X01);//发送CMD1}while(r1&&retry--);  }if(retry==0||SD_SendCmd(CMD16,512,0X01)!=0)SD_Type=SD_TYPE_ERR;//错误的卡}}SD_DisSelect();//取消片选SD_SPI_SpeedHigh();//高速if(SD_Type)return 0;else if(r1)return r1;        return 0xaa;//其他错误
}//读SD卡
//buf:数据缓存区
//sector:扇区
//cnt:扇区数
//返回值:0,ok;其他,失败.
u8 SD_ReadDisk(u8*buf,u32 sector,u8 cnt)
{u8 r1;if(SD_Type!=SD_TYPE_V2HC)sector <<= 9;//转换为字节地址if(cnt==1){r1=SD_SendCmd(CMD17,sector,0X01);//读命令if(r1==0)//指令发送成功{r1=SD_RecvData(buf,512);//接收512个字节      }}else{r1=SD_SendCmd(CMD18,sector,0X01);//连续读命令do{r1=SD_RecvData(buf,512);//接收512个字节    buf+=512;  }while(--cnt && r1==0);     SD_SendCmd(CMD12,0,0X01);   //发送停止命令}   SD_DisSelect();//取消片选return r1;//
}//写SD卡
//buf:数据缓存区
//sector:起始扇区
//cnt:扇区数
//返回值:0,ok;其他,失败.
u8 SD_WriteDisk(u8*buf,u32 sector,u8 cnt)
{u8 r1;if(SD_Type!=SD_TYPE_V2HC)sector *= 512;//转换为字节地址if(cnt==1){r1=SD_SendCmd(CMD24,sector,0X01);//读命令if(r1==0)//指令发送成功{r1=SD_SendBlock(buf,0xFE);//写512个字节      }}else{if(SD_Type!=SD_TYPE_MMC){SD_SendCmd(CMD55,0,0X01);   SD_SendCmd(CMD23,cnt,0X01);//发送指令   }r1=SD_SendCmd(CMD25,sector,0X01);//连续读命令if(r1==0){do{r1=SD_SendBlock(buf,0xFC);//接收512个字节   buf+=512;  }while(--cnt && r1==0);r1=SD_SendBlock(0,0xFD);//接收512个字节 }}   SD_DisSelect();//取消片选return r1;//
}

sd.h 定义一些值,以及指令

#ifndef _sd_H
#define _sd_H#include "system.h"#define SD_CS PGout(14)         //SD_CS// SD卡类型定义
#define SD_TYPE_ERR     0X00
#define SD_TYPE_MMC     0X01
#define SD_TYPE_V1      0X02
#define SD_TYPE_V2      0X04
#define SD_TYPE_V2HC    0X06    // SD卡指令表
#define CMD0    0       //卡复位
#define CMD1    1
#define CMD8    8       //命令8 ,SEND_IF_COND
#define CMD9    9       //命令9 ,读CSD数据
#define CMD10   10      //命令10,读CID数据
#define CMD12   12      //命令12,停止数据传输
#define CMD16   16      //命令16,设置SectorSize 应返回0x00
#define CMD17   17      //命令17,读sector
#define CMD18   18      //命令18,读Multi sector
#define CMD23   23      //命令23,设置多sector写入前预先擦除N个block
#define CMD24   24      //命令24,写sector
#define CMD25   25      //命令25,写Multi sector
#define CMD41   41      //命令41,应返回0x00
#define CMD55   55      //命令55,应返回0x01
#define CMD58   58      //命令58,读OCR信息
#define CMD59   59      //命令59,使能/禁止CRC,应返回0x00//数据写入回应字意义
#define MSD_DATA_OK                0x05
#define MSD_DATA_CRC_ERROR         0x0B
#define MSD_DATA_WRITE_ERROR       0x0D
#define MSD_DATA_OTHER_ERROR       0xFF
//SD卡回应标记字
#define MSD_RESPONSE_NO_ERROR      0x00
#define MSD_IN_IDLE_STATE          0x01
#define MSD_ERASE_RESET            0x02
#define MSD_ILLEGAL_COMMAND        0x04
#define MSD_COM_CRC_ERROR          0x08
#define MSD_ERASE_SEQUENCE_ERROR   0x10
#define MSD_ADDRESS_ERROR          0x20
#define MSD_PARAMETER_ERROR        0x40
#define MSD_RESPONSE_FAILURE       0xFF                                                                                   extern u8 SD_Type;//SD卡的类型
//函数申明区
u8 SD_SPI_ReadWriteByte(u8 data);
void SD_SPI_SpeedLow(void);
void SD_SPI_SpeedHigh(void);
u8 SD_WaitReady(void);                          //等待SD卡准备
u8 SD_GetResponse(u8 Response);                 //获得相应
u8 SD_Init(void);                           //初始化
u8 SD_ReadDisk(u8*buf,u32 sector,u8 cnt);       //读块
u8 SD_WriteDisk(u8*buf,u32 sector,u8 cnt);      //写块
u32 SD_GetSectorCount(void);                    //读扇区数
u8 SD_GetCID(u8 *cid_data);                     //读SD卡CID
u8 SD_GetCSD(u8 *csd_data);                     //读SD卡CSD#endif

主函数的引用


int main()
{u8 i=0;u32 sd_size;u8 sd_buf[6];SysTick_Init(72);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //中断优先级分组 分2组LED_Init();USART1_Init(115200);TFTLCD_Init();          //LCD初始化FRONT_COLOR=RED;//设置字体为红色 LCD_ShowString(10,10,tftlcd_data.width,tftlcd_data.height,16,"STM32F1");   LCD_ShowString(10,30,tftlcd_data.width,tftlcd_data.height,16,"SD CARD TEST");   while(SD_Init())//检测不到SD卡{LCD_ShowString(10,80,tftlcd_data.width,tftlcd_data.height,16,"SD Card Error!");printf("SD Card Error!\r\n");delay_ms(500);                  }FRONT_COLOR=BLUE; //设置字体为蓝色 //检测SD卡成功             printf("SD Card OK!\r\n");    LCD_ShowString(10,80,tftlcd_data.width,tftlcd_data.height,16,"SD Card OK    ");/* 显示SD卡类型 */if(SD_Type == 0x06){LCD_ShowString(10, 100,tftlcd_data.width,tftlcd_data.height,16,"SDV2HC OK!");}else if(SD_Type == 0x04){LCD_ShowString(10, 100,tftlcd_data.width,tftlcd_data.height,16,"SDV2 OK!");}else if(SD_Type == 0x02){LCD_ShowString(10, 100,tftlcd_data.width,tftlcd_data.height,16,"SDV1 OK!");}else if(SD_Type == 0x01){LCD_ShowString(10, 100,tftlcd_data.width,tftlcd_data.height,16,"MMC OK!");}LCD_ShowString(10,120,tftlcd_data.width,tftlcd_data.height,16,"SD Card Size:     MB");sd_size=SD_GetSectorCount();//得到扇区数sd_size=sd_size>>11;  //显示SD卡容量   MBprintf("\nSD卡容量为:%dMB\n", sd_size);sd_buf[0]=sd_size/10000+0x30;sd_buf[1]=sd_size%10000/1000+0x30;sd_buf[2]=sd_size%10000%1000/100+0x30;sd_buf[3]=sd_size%10000%1000%100/10+0x30;sd_buf[4]=sd_size%10000%1000%100%10+0x30;sd_buf[5]='\0';LCD_ShowString(115,120,tftlcd_data.width,tftlcd_data.height,16,sd_buf);}

总结

  1. SD卡是基于flash的存储卡。
  2. SD卡和MMC卡的区别在于初始化过程不同。
  3. SD卡的通信协议包括SD和SPI两类。
  4. 掌握工作模式,通信模式
  5. 不同的板子主要看电路图其中的sd 卡是否支持sdio 大部分支持spi 根据不同的模式选择

注释 关于SD卡相关中文数据手册说明和文档,发消息会转发文档给
这里额外提一下卡槽(卡槽图片来源博主jiangfutao的)

SD卡(Secure Digital Memory Card)是一种基于半导体闪存工艺的存储卡,中文名称“安全数码卡”,是一种基于半导体快闪记忆器的新一代记忆设备,它被广泛地于便携式装置上使用,例如数码相机、个人数码助理(外语缩写PDA)和多媒体播放器等。
而SD卡槽就是一种放置SD卡的装置,它是没有存储功能的,它只是为SD卡服务的,和读卡器起到的作用有些类似,但它们还是有很大区别的,比如说SD卡槽是固定在设备当中的,而读卡器则是可以移动的。
SD卡座属于一种弹跳式的装置,在SD卡座的卡槽底部一般都是有一个复位的装置结构。按一下可以将SD卡弹跳出来,它的其工作原理是,在SD卡座中卡槽的底部有个小直径和小线径的弹簧或者是一种切口式弹片,我们对其进行按压SD卡就嵌在卡座里面,相反在按一下就可以弹跳出来。因此SD卡座不但可以临时锁死结构,还可以临时弹出等,其实主要的就是靠这种复位的装置进行操作。
除此之外,还有SD储存卡座的工作原理,在卡槽有相对应的凸起开口,将其SD卡插入到SD卡座的卡槽内,然后我们可以通过SD卡座以命令形式的传输来控制SD卡的读写操作,并且能够根据命令对多块SD卡或单块SD卡进行读写操作。

相信大家都知道SD卡座在日常生活与工作中使用非常广泛,目前已经成为了最通用的数据存储卡、储存记忆卡。比如通讯数码产品、安防产品、带储存类产品等设备上都是使用SD卡来进行数据储存。如今的SD卡之所以能德到大家如此广泛的使用,是因为SD卡的优点诸多,比如性价比高、存储容量大、使用便捷、通用性以及安全性强等。如果将它加入到单片机应用开发系统中来,将使系统变得更加出色。这就需要对SD卡的硬件与读写时序进行研究。

上一节 学习STM32 RS485 原理与应用

stm32 SD(SDSC)卡的学习与SPI 模式应用(卡槽介绍)相关推荐

  1. stm32 SD(SDSC)卡的学习SDIO 模式连接SD卡

    本次的SD卡连接使用的是SDIO模式与之前的SPI模式相对应,都是对stm32 使用SD卡的介绍也为了和后面的FATFS文件系统使用铺垫.就直接上源码,也有看不明白的抢先看上一节的stm32 SD(S ...

  2. SD卡读写实验(SPI模式)

    对于 SD 卡的 SPI 模式而言,采用的 SPI 的通信模式为模式 3,即 CPOL=1,CPHA=1,在 SD 卡 2.0 版 本协议中,SPI_CLK 时钟频率可达 50Mhz. SD 卡的 S ...

  3. STM32 HAL库 实现基于SPI模式的SD卡、TF卡FATS文件系统+模拟U盘的应用笔记

    前言 很多单片机不带SDIO接口,所以在使用SD卡时必须使用SPI模式进行读写. 想做一个基于SPI的SD卡文件系统读写SD卡上的文件,再配合USB接口做一个模拟U盘.只能利用业余时间慢慢更新,也不知 ...

  4. SD卡 SPI模式操作(1)初始化SD卡

    原文(本人转载):帆登小站-SD卡 SPI模式操作(1)初始化SD卡 作者是初学者,水平有限,本文仅作为个人学习笔记使用,不能保证内容的正确性.部分资料来源于网络,参考了SD卡协议2.0手册等资料,如 ...

  5. SD卡SPI模式入门教程

    ▼我是阿荣,关注我,在技术路上一起精进!▼ SD卡简介 SD卡是一种基于半导体快闪记忆器的新一代记忆设备,英文全称Secure Digital Memory Card,中文名又称安全数码卡. 尺寸分类 ...

  6. Micro SD 卡(TF卡) spi 模式实现方法

    首先贴上一写SD卡SPI模式下的参考电路,以及一些比较不错的帖子的连接: 1:http://www.go-gddq.com/html/s733/2009-12/477854.htm 2:http:// ...

  7. MicroSD卡(TF卡)SPI模式实现方法

    一下这篇文章是转载一位仁兄的,写的非常好! MicroSD卡(TF卡)SPI模式实现方法 现在我们手机的内存卡多为Micro SD卡,又叫TF卡,所以Micro SD卡比SD卡常见.自己曾经也想写写S ...

  8. STM32开发板入门教程(十三) - SPI模式读写SD卡

    功能介绍 :使用SPI模式 读写SD卡block数据 可通过串口发送到PC机查看 SD卡是Secure Digital Card卡的简称,直译成汉语就是"安全数字卡",是由日本松下 ...

  9. SD卡学习(SDIO和SPI模式)

    SD卡学习(SDIO和SPI模式) ** SD卡的操作模式:SD卡模式(SDIO).SPI模式(默认为SD模式). 其中SD卡模式的信号线有:CLK.CMD.DAT0-DAT3,6根线. SPI模式的 ...

最新文章

  1. 延迟开学会影响毕业?这些高校有答案了!
  2. MFC 学习的基本概念
  3. Windows 命令行大全
  4. Java的迭代器—— Iterator
  5. NOS跨分区灾备设计与实现
  6. idea打包meven镜像_Intelij IDEA中修改maven为国内镜像
  7. docker-compose.yml配置文件详解
  8. 38..Node.js工具模块---底层的网络通信--Net模块
  9. (转)json+flexgrid+jbox组合运用页面刷新jsp
  10. DHCP、PNF、SXE、DNS等综合实验
  11. tcl电视显示服务器异常1500,TCL电视机使用常见故障及维修方法
  12. java你的线上欧美_JAVA 线上故障排查全套路
  13. 公众号文章怎么批量下载导出?
  14. JsonFormat注解转换时间错误问题解决方案
  15. 让你嘿嘿嘿!最新windows7升级win10方法!
  16. 吉林农业大学计算机类考研,吉林农业大学考研难吗?一般要什么水平才可以进入?...
  17. 【高等数学】微分方程
  18. Lazy Binomial Heaps
  19. 微信小程序 生成小程序码 + Java后台
  20. 周易测算网站H5源码在线起名运势测算网站系统源码

热门文章

  1. Stanford cs231n'18 课程及作业详细解读
  2. mysql unicode转utf8_Unicode UTF-8 转换
  3. python小游戏贪吃蛇下载_python小游戏之贪吃蛇
  4. 欢迎试用Android定时达人~
  5. 魅族16支持html吗,支持MIMO技术的手机有多牛,看了魅族16手机就知道了!
  6. 万能Makefile
  7. 使用DWM API画自定义Aero效果窗口
  8. oppo手机解锁_oppo手机屏幕锁密码忘记了怎么办?oppo手机强制解锁教程
  9. C4d win7 64bit安装好之后,点击启动无反应
  10. linux硬盘对拷后不能启动,变动硬盘位置或dd对拷更换硬盘后系统无法正常启动的解决方法...