本文使用到的硬件: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
|