STM32F103完成对SD卡的数据读取(fat文件模式)

news/2025/2/26 19:52:44

文章目录

  • 一、实验要求
  • 二、SD卡协议
    • SDIO协议简介
    • SD卡物理结构
    • SD 卡寄存器
    • SD卡操作模式
    • SD卡初始化(SPI模式)
    • SD卡读取与写入(SPI模式)
  • 三、实验过程
    • 使用CubeMX创建工程:
    • 代码:
  • 四、实验结果
  • 五、实验总结
  • 六、参考

一、实验要求

掌握SD卡协议原理,用STM32F103完成对SD卡的数据读取(fat文件模式)。

二、SD卡协议

SDIO协议简介

SD卡(Secure Digital Memory
Card)在我们的生活中已经非常普遍了,控制器对SD卡进行读写通信操作一般有两种通信接口可选,一种是 SPI接口,另外一种就是
SDIO接口。SDIO 全称是 安全数字输入/输出接口,多媒体卡(MMC)、SD卡、SD I/O卡 都有
SDIO接口。STM32F103系列控制器有一个 SDIO主机接口,它可以与 MMC卡、SD卡、SD I/O卡 以及 CE-ATA
设备进行数据传输。

参考资料:
多媒体卡协会网站 www.mmca.org 中提供了有MMCA技术委员会发布的多媒体卡系统规范。
SD卡协会网站 www.sdcard.org 中提供了SD存储卡和SDIO卡系统规范。
CE-ATA工作组网站 www.ce-ata.org 中提供了CE_ATA系统规范。

SD卡物理结构

一张 SD卡包括有存储单元、存储单元接口、电源检测、卡及接口控制器和接口驱动器 5个部分
存储单元是存储数据部件,存储单元通过存储单元接口与卡控制单元进行数据传输;
电源检测单元 保证 SD卡工作在合适的电压下,如出现掉电或上状态时,它会使控制单元和存储单元接口复位;
卡及接口控制单元 5个部分控制 SD卡的运行状态,它包括有 8个寄存器;接口驱动器控制 SD卡引脚的输入输出。

SD卡功能框图如下:
在这里插入图片描述
SD卡的pin定义如下:
在这里插入图片描述

SD 卡寄存器

总共有 8个寄存器,用于设定或表示 SD 卡信息,如下:
在这里插入图片描述

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类,下表为几个比较重要的命令:
在这里插入图片描述

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),在完成了初始化之后,就可以开始读写数据了。

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卡过程。

我们在用USB转TTL为STM32供电的时候一定需要接到5V上面去,并且在用32给SD卡模块供电的时候一定一定要接到5V电源上,否则我们无法驱动该SD模块

三、实验过程

使用CubeMX创建工程:

配置SYS为Serial Wire
将PA4设置如图所示:
在这里插入图片描述

设置串口:配置USART1为默认Asynchronous

配置SPI1为全双工主模式:
在这里插入图片描述
配置FATFS:
在这里插入图片描述
在这里插入图片描述
配置时钟:
在这里插入图片描述
工程设置:
在这里插入图片描述
到这里工程就建好了我们只需要修改代码就好了

代码:

main.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under Ultimate Liberty license
  * SLA0044, the "License"; You may not use this file except in compliance with
  * the License. You may obtain a copy of the License at:
  *                             www.st.com/SLA0044
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "fatfs.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "SDdriver.h"




/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
SPI_HandleTypeDef hspi1;

UART_HandleTypeDef huart1;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI1_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
int fputc(int ch, FILE *f)    
{
    HAL_UART_Transmit(&huart1, (unsigned char *)&ch, 1, 0xFFFF);   
    return ch;
}
uint16_t uart_value[3];
uint8_t aRxBuffer1;	//uart rx buff 





void WritetoSD(BYTE write_buff[],uint8_t bufSize);
char SD_FileName[] = "123.txt";
uint8_t WriteBuffer[] = "01 631907030422 铁长风\r\n";

//uint8_t test_sd =0;	//用于测试格式化
uint8_t write_cnt =0;	//写SD卡次数




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);		 //取消挂载
	
}


void Get_SDCard_Capacity(void)
{
	FRESULT result;
	FATFS FS;
	FATFS *fs;
	DWORD fre_clust,AvailableSize,UsedSize;  
	uint16_t TotalSpace;
	uint8_t res;
	
	res = SD_init();		//SD卡初始化
	if(res == 1)
	{
		printf("SD卡初始化失败! \r\n");		
	}
	else
	{
		printf("SD卡初始化成功! \r\n");		
	}
	
	/* 挂载 */
	res=f_mount(&FS,"0:",1);		//挂载
	if (res != FR_OK)
	{
		printf("FileSystem Mounted Failed (%d)\r\n", result);
	}

	res = f_getfree("0:", &fre_clust, &fs);  /* 根目录 */
	if ( res == FR_OK ) 
	{
		TotalSpace=(uint16_t)(((fs->n_fatent - 2) * fs->csize ) / 2 /1024);
		AvailableSize=(uint16_t)((fre_clust * fs->csize) / 2 /1024);
		UsedSize=TotalSpace-AvailableSize;              
		/* Print free space in unit of MB (assuming 512 bytes/sector) */
		printf("\r\n%d MB total drive space.\r\n""%d MB available.\r\n""%d MB  used.\r\n",TotalSpace, AvailableSize,UsedSize);
	}
	else 
	{
		printf("Get SDCard Capacity Failed (%d)\r\n", result);
	}		
} 


/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
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] +0;
		WriteBuffer[1] = WriteBuffer[1] +1;
		write_cnt ++;
		
		while(write_cnt > 5)
		{	
			printf(" while \r\n");
			HAL_Delay(500);
		}		
		
		

		
		
		
		
		
		
		
		
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV2;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief SPI1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_SPI1_Init(void)
{

  /* USER CODE BEGIN SPI1_Init 0 */

  /* USER CODE END SPI1_Init 0 */

  /* USER CODE BEGIN SPI1_Init 1 */

  /* USER CODE END SPI1_Init 1 */
  /* SPI1 parameter configuration*/
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI1_Init 2 */

  /* USER CODE END SPI1_Init 2 */

}

/**
  * @brief USART1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(SD_CS_GPIO_Port, SD_CS_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin : SD_CS_Pin */
  GPIO_InitStruct.Pin = SD_CS_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(SD_CS_GPIO_Port, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */

  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{ 
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/


 /* 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();	//得到使用内存并选择格式化

这一段使进行初始化,并且为了证明reset,显示main。

 while (1)
  {
		
		
		
		WritetoSD(WriteBuffer,sizeof(WriteBuffer));		

		
		
//		HAL_Delay(500);
		WriteBuffer[0] = WriteBuffer[0] +0;
		WriteBuffer[1] = WriteBuffer[1] +1;
		write_cnt ++;
		
		while(write_cnt > 5)
		{	
			printf(" while \r\n");
			HAL_Delay(500);
		}		
		

这一段使写入函数和每次写入都进行延时,并且用while语句来设置写入的次数
超过之后就会在串口助手里面显示while

编译没错之后就开始烧入:
在这里插入图片描述

四、实验结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

五、实验总结

这次的实验最开始的时候有许多的问题,到后面都是照着别人做好的博客来做出来了,也是遇到了许多要注意的点,首先使要接5V,烧录和供电的时候都是,其实你需要将SD卡格式化的时候选择FAT模式或者FAT32等等问题,也是靠着同学和老师的帮助完成了这次的实验。

六、参考

https://blog.csdn.net/qq_46467126/article/details/122033766
https://blog.csdn.net/qq_57611233/article/details/122089187?spm=1001.2014.3001.5501


http://www.niftyadmin.cn/n/675694.html

相关文章

和我一起学Windows Workflow Foundation(1)-----创建和调试一个WF实例

今天开始&#xff0c;我打算开始学习WWF&#xff0c;从网上搜索到了部分相关资料&#xff0c;也找到了一些文档和实验。但是&#xff0c;资料以英文的占多数&#xff0c;所以&#xff0c;在学习起来似乎比较吃力&#xff0c;不过相信我能坚持下来&#xff0c;顺便提高点英语阅读…

安装Altium Designer 18并且完成STM32+SD卡 的系统原理图设计

文章目录一、实验要求&#xff1a;二、Altium Designer 18的安装&#xff1a;三、原理图设计一、实验要求&#xff1a; 掌握电路原理图绘制。安装Altium Designer 18&#xff0c;学习使用Altium Designer绘制一个stm32最小系统的电路原理图&#xff0c;并在此基础上完成STM32S…

跟我一起学Windows Workflow Foundation(5)-----使用activity设计器创建一个整合的定制activity...

Lab01已经完了,lab02中说的是创建自定义的Activity Activities是工作流模型的一个可执行单元&#xff0c;它可以被重用&#xff0c;也可以把多个Activities整合成一个Activities。一个工作流可以由多个Activities组成&#xff0c;一个Activities也可以由其他的Activities构成&a…

音频数据的Flash读取与DAC STM32F103C8T6

文章目录一、FLASH的介绍&#xff1a;二、搭建工程三、DAC介绍四、DAC输出音频1、输出2kHz的单音音频2、使用Adobe Audition截取一段喜欢的音乐五、总结六、参考一、FLASH的介绍&#xff1a; 不同型号的 STM32&#xff0c;其 FLASH 容量也有所不同&#xff0c;最小的只有 16K …

html5新增标签_好程序员web前端分享HTML5与HTML之间有什么区别?

好程序员web前端分享HTML5与HTML之间有什么区别&#xff1f;很多没有学过HTML5大前端的同学&#xff0c;对HTML5并不了解&#xff0c;经常会提出疑问&#xff1a;HTML5与传统HTML有什么区别?今天&#xff0c;就为大家讲一下两者比较明显几个区别。首先&#xff0c;HTML5已经远…

SqlSelect-在查询结果前面加一列序号列

select id identity(int,1,1) , comp_name into #temp from tbl_companyselect * from #temp 转载于:https://www.cnblogs.com/htht66/archive/2007/09/11/889703.html

[Google]Google-演示文稿(Presentation)和Google Reader(中文版)上线

今天可谓是G粉的节日&#xff0c;前一阵子谣传的Google Presentation&#xff08;中文名&#xff1a;Google演示文稿&#xff09;和中文版的Google Reader今天终于如约上线&#xff01;值得一提的是Google Presentation&#xff08;中文名&#xff1a;Google演示文稿&#xff0…

fastdfs删除图片_FastDFS多个storage节点存在的细节问题

起因&#xff1a;当我们部署FastDFS集群多个storage节点环境时&#xff0c;有这么一种情况&#xff0c;上传一张图片后&#xff0c;立马访问有时会出现图片不存在的情况&#xff0c;当然这个立马访问指的是程序去调用&#xff0c;也就是图片路径返回后及时去访问。这一系列步骤…