嵌入式20STM32F103完成对SD卡的数据读取详细操作
Posted 噗噗的罐子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了嵌入式20STM32F103完成对SD卡的数据读取详细操作相关的知识,希望对你有一定的参考价值。
本文主要利用STM32F103完成对SD卡的数据读取,介绍该实验的详细操作
一、题目要求
掌握SD卡协议原理,用STM32F103完成对SD卡的数据读取(fat文件模式)。
二、SD卡协议原理
1、SD卡简述
很多单片机系统都需要大容量存储设备,以存储数据。目前常用的有 U 盘,FLASH 芯片,SD 卡等。他们各有优点,综合比较,最适合单片机系统的莫过于 SD 卡了,它不仅容量可以做到很大(32GB 以上),支持 SPI/SDIO 驱动,而且有多种体积的尺寸可供选择(标准的 SD 卡尺寸,以及 TF 卡尺寸等),能满足不同应用的要求。
只需要少数几个 IO 口即可外扩一个高达 32GB 以上的外部存储器,容量从几十 M 到几十G 选择尺度很大,更换也很方便,编程也简单,是单片机大容量外部存储器的首选。
2、SD卡物理结构
一般SD卡包括有存储单元、存储单元接口、电源检测、卡及接口控制器和接口驱动器 5个部分。
- 存储单元是存储数据部件,存储单元通过存储单元接口与卡控制单元进行数据传输;
- 电源检测单元保证SD卡工作在合适的电压下,如出现掉电或上状态时,它会使控制单元和存储单元接口复位;
- 卡及接口控制单元控制SD卡的运行状态,它包括有8个寄存器; 接口驱动器控制SD卡引脚的输入输出。
3、SD卡寄存器
SD卡总共有8个寄存器,用于设定或表示SD卡信息。
这些寄存器只能通过对应的命令访问,SDIO定义64个命令,每个命令都有特殊意义,可以实现某一特定功能,SD卡接收到命令后,根据命令要求对SD卡内部寄存器进行修改,程序控制中只需要发送组合命令就可以实现SD卡的控制以及读写操作。
名称 | bit宽度 | 描述 |
---|---|---|
CID | 128 | 卡识别号(Card identification number):用来识别的卡的个体号码(唯一的) |
RCA | 16 | 相对地址(Relative card address):卡的本地系统地址,初始化时,动态地由卡建议,主机核准 |
DSR | 16 | 驱动级寄存器(Driver Stage Register):配置卡的输出驱动 |
CSD | 128 | 卡的特定数据(Card Specific Data):卡的操作条件信息 |
SCR | 64 | SD配置寄存器(CD Configuration Register):SD卡特殊特性信息 |
OCR | 32 | 操作条件寄存器(Operation conditiongs register) |
SSR | 512 | SD状态(SD Status):SD卡专有特征的信息 |
CSR | 32 | 卡状态(Card Status):卡状态信息 |
4、SD卡操作模式
SD卡一般都支持 SDIO 和 SPI 这两种接口。
其中SD卡模式的信号线有:CLK、CMD、DAT0-DAT3,6根线。
SPI模式的信号线有:CS、CLK、MISO(DATAOUT)、MOSI(DATAIN),4根线。
SD卡的命令格式:命令CMD0就是0,CMD16就是16,以此类推。
SD卡的命令总共有12类,下表为几个比较重要的命令:
命令 | 参数 | 回应 | 描述 |
---|---|---|---|
CMD0(0X00) | NONE | R1 | 复位SD卡 |
CMD8(0X08) | VHS+Check Pattern | R7 | 发送接口状态命令 |
CMD9(0X09) | NONE | R1 | 读取卡特定数据寄存器 |
CMD10(0X0A) | NONE | R1 | 读取卡标志数据寄存器 |
CMD16(0X10) | 块大小 | R1 | 设置块大小(字节数) |
CMD17(0X11) | 地址 | R1 | 读取一个块的数据 |
CMD24(0X18) | 地址 | R1 | 写入一个块的数据 |
CMD41(0X29) | NONE | R3 | 发送给主机容量支持信息和激活卡初始化过程 |
CMD55(0X37) | NONE | R1 | 告诉SD卡,下一个是特定应用命令 |
CMD58(0X3A) | NONE | R3 | 读取OCR寄存器 |
5、SD卡初始化(SPI模式)
SPI操作模式下:在SD卡收到复位命令时,CS为有效电平(低电平),则SPI模式被启用,在发送CMD之前要先发送74个时钟,64个为内部供电上升时间,10个用于SD卡同步;之后才能开始CMD操作,在初始化时CLK时钟不能超过400KHz。
1、初始化与SD卡连接的硬件条件(MCU的SPI配置,IO口配置);
2、上电延时(>74个CLK);
3、复位卡(CMD0),进入IDLE状态;
4、发送CMD8,检查是否支持2.0协议;
5、根据不同协议检查SD卡(命令包括:CMD55、CMD41、CMD58和CMD1等);
6、取消片选,发多8个CLK,结束初始化
这样我们就完成了对SD卡的初始化,注意末尾发送的8个CLK是提供SD卡额外的时钟,完成某些操作。通过SD卡初始化,我们可以知道SD卡的类型(V1、V2、V2HC或者MMC),在完成了初始化之后,就可以开始读写数据了。
6、SD卡读取与写入(SPI模式)
1、发送CMD17;
2、接收卡响应R1;
3、接收数据起始令牌0XFE;
4、接收数据;
5、接收2个字节的CRC,如果不使用CRC,这两个字节在读取后可以丢掉。
6、禁止片选之后,发多8个CLK;
以上就是一个典型的读取SD卡数据过程,SD卡的写于读数据差不多,写数据通过CMD24来实现,具体过程如下:
1、发送CMD24;
2、接收卡响应R1;
3、发送写数据起始令牌0XFE;
4、发送数据;
5、发送2字节的伪CRC;
6、禁止片选之后,发多8个CLK;
以上就是一个典型的写SD卡过程。
三、实验操作
1、硬件准备
SD卡模块及SD卡
内部结构:
部分 | 说明 |
---|---|
控制接口 | 共 6 个引脚(GND、VCC、MISO、MOSI、SCK、CS),GND 为地,VCC 为供 电电源,MISO、MOSI、SCK 为 SPI 总线,CS 为片选信号脚 |
3.3V 稳压电路 | LDO 稳压输出的 3.3V 为电平转换芯片、Micro SD 卡供电 |
电平转换电路 | 往 Micro SD 卡方向的信号转换成 3.3V,MicroSD 卡往控制接口方向的 MISO 信号也转换成了 3.3V,一般 AVR 单片机系统都能读取该信号 |
Micro SD 卡座 | 是自弹式卡座,方便卡的插拔 |
定位孔 | 4 个 M2 螺丝定位孔,孔径为 2.2mm,使模块便于安装定位,实现模块间组合 |
2、连线
stm32 | SD卡模块 |
---|---|
PA4 | SDCS |
PA5 | SCK |
PA7 | MOSI |
PA6 | MISO |
VCC | VCC |
GND | GND |
3、HAL库配置
因为STM32要连接SD卡模块,所以我们要进行相应配置。
之后导出即可。
4、代码分析
完整工程代码如下(hal库版本)
链接:https://pan.baidu.com/s/1YxLpaIM6HMQ4d_9yh4M4ww
提取码:276d
针对main主函数进行分析
int main(void)
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration---------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_SPI1_Init();
MX_FATFS_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(&huart1,&aRxBuffer1,1); //enable uart
printf(" main \\r\\n");
Get_SDCard_Capacity(); //得到使用内存并选择格式化
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
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);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
/* USER CODE END 3 */
说明:
这里我们看下write_cnt
初始定义的值,计算写入次数循环要求。
(在main.c文件头部)
从0开始,write_cnt=0
,因此要写入超过11次,之后不再写入内容。
写入函数WritetoSD
void WritetoSD(BYTE write_buff[],uint8_t bufSize)
FATFS fs;
FIL file;
uint8_t res=0;
UINT Bw;
res = SD_init(); //SD卡初始化
if(res == 1)
printf("SD卡初始化失败! \\r\\n");
else
printf("SD卡初始化成功! \\r\\n");
res=f_mount(&fs,"0:",1); //挂载
// if(test_sd == 0) //用于测试格式化
if(res == FR_NO_FILESYSTEM) //没有文件系统,格式化
// test_sd =1; //用于测试格式化
printf("没有文件系统! \\r\\n");
res = f_mkfs("", 0, 0); //格式化sd卡
if(res == FR_OK)
printf("格式化成功! \\r\\n");
res = f_mount(NULL,"0:",1); //格式化后先取消挂载
res = f_mount(&fs,"0:",1); //重新挂载
if(res == FR_OK)
printf("SD卡已经成功挂载,可以进进行文件写入测试!\\r\\n");
else
printf("格式化失败! \\r\\n");
else if(res == FR_OK)
printf("挂载成功! \\r\\n");
else
printf("挂载失败! \\r\\n");
res = f_open(&file,SD_FileName,FA_OPEN_ALWAYS |FA_WRITE);
if((res & FR_DENIED) == FR_DENIED)
printf("卡存储已满,写入失败!\\r\\n");
f_lseek(&file, f_size(&file));//确保写词写入不会覆盖之前的数据
if(res == FR_OK)
printf("打开成功/创建文件成功! \\r\\n");
res = f_write(&file,write_buff,bufSize,&Bw); //写数据到SD卡
if(res == FR_OK)
printf("文件写入成功! \\r\\n");
else
printf("文件写入失败! \\r\\n");
else
printf("打开文件失败!\\r\\n");
f_close(&file); //关闭文件
f_mount(NULL,"0:",1); //取消挂载
从写入函数中,我们可以知道,针对SD卡文件的每个步骤,我们都进行了相应的字段输出,来具体判断究竟进行到了什么地步。
5、实验结果分析
最开始,要么初始化失败,要么没反应,要么初始化成功之后没反应,各种情况吧。
之后改变了接线电压,SD卡模块接5v,STM32也接了5v,还是失败。
然后重新接线,换成了新的杜邦线,然后就成功了,只能说这个实验很玄学
就很秃然
然后打开sd卡确实看到了hello文本文件写入了内容。
这里有两个情况
我最开始在SD卡下建立了hello.txt文件(里面最开始写了数字1),因为担心初始化不成功,然后SD卡写入成功后,SD卡内容是这样的:
之后,我把hello.txt文件删了,看看SD卡能不能自己建立一个txt文本文件:
果然是成功的,而且内容是一样的。
但是左侧出现了乱码情况,因此对主函数进行修改
再烧录一次试试
有序写入,说明是成功的。
然后分析一下串口收到的内容:
可以证明,确实写入次数超过11次后,会不断返回while值,而txt文本里有11行内容,之后也不会再写入了。
四、总结
为了让这个实验成功还是花费了蛮多的时间,做实验可能就是这样的跌宕起伏,毕竟人生不如意十有八九,八九才是大多数。
整个实验操作很简单,了解了SPI协议,按部就班去做,并不难实现,但是很容易卡死在初始化的环节,线务必接好,接触不良就很容易失败,多按压一下板子也会有用可能。
祝各位好运。
参考
[1] https://blog.csdn.net/m0_53089598/article/details/121985861
[2] https://blog.csdn.net/lqmlmo/article/details/80830082
[3] https://blog.csdn.net/fengxiaocheng/article/details/81411117
以上是关于嵌入式20STM32F103完成对SD卡的数据读取详细操作的主要内容,如果未能解决你的问题,请参考以下文章
ArduinoSTM32 利用DS18B20读取温度 on STM32F103C8