|
本文使用到的硬件:STM32F103C8T6、Micro SD卡模块CH376S SPI接口、杜邦线、USB转TTL接口 本文使用到的软件:Keil MDK、串口调试助手
一、SPI读写SD卡介绍
SPI外设只具有两条数据线MISO和MOSI,分别用作数据的输入和输出,由于引脚较少,所以控制相对较容易。 
1.1 SPI模式
在SPI模式下,数据都是以 字节(Byte)为单位进行传输的。此时SD卡作为从机设备,一般的操作是MCU发送带有参数的命令,SD卡接收到命令和参数后进行操作,并且返回响应,MCU根据返回的响应进行下一步操作。

1.2 命令
SD卡的命令有6个字节(48位),由以下几部分组成: 第一字节的最高位b7为起始位,始终为0 接下来为传输位,始终为1 b5-b0为命令代码 第2~5字节为命令的参数,共4个字节 最后一个字节的前7为CRC7校验位,最后一位为停止位,始终为1
常用命令:
| 命令 | 参数 | 响应类型 | 简写 | 描述 |
|---|
| CMD0 | 0 | R1 | GO_IDLE_STATE | 软件复位 | | CMD8 | (*1) | R7 | SEND_IF_COND | 发送MCU的电压范围,检测SD卡是否满足MCU的电压范围 | | ACMD41(*2) | (*3) | R1 | SD_SEND_OP_COND | 开始SD卡初始化和检测SD卡是否完成初始化 | | CMD9 | 0 | R1 | SEND_CSD | 读取CSD寄存器的值 | | CMD10 | 0 | R1 | SEND_CID | 读取CID寄存器的值 | | CMD12 | 0 | R1b | STOP_TRANSMISSION | 停止读取操作 | | CMD16 | 数据块长度[31:0] | R1 | SET_BLOCKLEN | 设置数据块长度(*4) | | CMD17 | 地址[31:0] | R1 | READ_SINGLE_BLOCK | 读取单个数据块 | | CMD18 | 地址[31:0] | R1 | READ_MULTIPLE_BLOCK | 读取多个块数据 | | CMD24 | 地址[31:0] | R1 | WRITE_BLOCK | 写单个块数据 | | CMD25 | 地址[31:0] | R1 | WRITE_MULTIPLE_BLOCK | 写多个块数据 | | CMD55 | 0 | R1 | APP_CMD | 定义下一条命令为ACMD命令 | | CMD58 | 0 | R3 | READ_OCR | 读取OCR寄存器 |
1.3 初始化操作
SPI模式下的初始化操作有:上电->进入SPI模式(CMD0)->检测当前MCU电压是否符合SD卡的要求(CMD8)->开始初始化(ACMD41)->读取卡类型(CMD58)
初始化过程中,SD卡时钟信号周期需为100KHz~400KHz之间,不能大于400KHz。
-
上电 当电压达到SD卡的最小工作电压的后,MCU必须使CS,DI为高电平,输出最少74个时钟脉冲后,才能开始发送第一个命令。 -
初始化过程 SD卡上电后处于SD Bus模式,使CS保持为0,并且发送CMD0命令,SD卡就会进入到SPI模式。在SPI模式下,命令的CRC校验功能默认是禁止的(CMD8命令除外),但是发送第一个CMD0命令时,SD卡是处于SD Bus模式,该模式下CRC校验功能是启动的,因此第一个CMD0命令必须要有正确的CRC校验。正确的CMD0命令应为:0x40, 0x00, 0x00, 0x00, 0x00, 0x95。 CMD8用于检测SD卡接口电压是否满足要求,该命令的参数包括当前MCU接口的电压范围VHS([11:8]),以及用于检测通信的Check Pattern([7:0])。如果SD卡能满足当前MCU的接口电压,它就会返回VHS和Check Pattern的值。需要注意的是,CMD8的CRC校验值必须正确,假如CRC校验不对,SD卡返回的R1值中的CRC错误位就会置1。 ACMD41命令用于开始初始化SD卡及检测其是否完成初始化。该命令的参数HCS([30])表示MCU是否支持SDHC和SDXC,若支持HCS置1,反之置0。如果ACDM41命令返回R1的值为0x01,说明SD卡正在初始化,MCU需要重复发送ACMD41,直到返回值R1为0。 初始化完成后,通过发送CMD58指令读取卡的类型(OCR寄存器的CCS位[30]), CCS为1表示当前卡的类型为SDXC或者SDHC,为0表示卡的类型为SDSC。

1.4 读写数据(多数据)
-
读取数据 读取多个数据块操作和读取单个数据块的相似,先发送命令CMD18,然后开始等待数据块的起始标识符。需要停止读取操作时,发送CMD12命令,返回响应为0表示SD卡处于忙碌状态,只有返回任何不为0的值后,MCU才能发送下一条命令。  -
写入数据 当SD卡接收到写入多个数据块命令CMD25后,发送数据包起始符为(0xFC), 只有当DO不为0时,才能继续发送第二个数据包。如果要结束写入操作,则发送停止发送标识符(0xFD)。 
二、实验配置
2.1 源代码
链接:https://pan.baidu.com/s/1lXiepBi4sLZra6uo3yJgOw 提取码:dnjs
2.2 硬件连线
| STM32 | SD卡模块 |
|---|
| PA4 | SDCS | | PA5 | SCK | | PA7 | MOSI | | PA6 | MISO | | VCC | VCC | | GND | GND |
2.3 部分代码分析
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_SPI1_Init();
MX_FATFS_Init();
MX_USART1_UART_Init();
HAL_UART_Receive_IT(&huart1,&aRxBuffer1,1);
printf(" mian \r\n");
Get_SDCard_Capacity();
while (1)
{
WritetoSD(WriteBuffer,sizeof(WriteBuffer));
HAL_Delay(500);
WriteBuffer[0] = WriteBuffer[0] +10;
WriteBuffer[1] = WriteBuffer[1] +10;
write_cnt ++;
while(write_cnt > 10)
{
printf(" while \r\n");
HAL_Delay(500);
}
}
}
- WritetoSD(WriteBuffer,sizeof(WriteBuffer));
写入SD卡程序,我们可以在文件的开始定义我们要写入SD卡的内容  - SD_init();
SD初始化函数,完成发送命令及鉴别SD卡  - while
 write_cnt>10,write_cnt我们设置的初始值为0,表示当写入的次数达到11次我们就不再写入,输出while表示写入完成。
三、实验结果分析


- 查看文档

四、总结
注意在接线时一定要保证5V电压,否则无法初始化,只可以完成烧录程序。虽然得到了最终结果,但理解原理是最重要的。
参考文章: https://www.cnblogs.com/mr-bike/p/3546228.html https://blog.csdn.net/qq_46467126/article/details/122033766 https://blog.csdn.net/IssacMi/article/details/102785961
|