用STM32F103完成對SD卡的資料讀取
- 一、SD卡協議原理
- 1.SDIO協議
- 2.SD卡物理結構
- 3.SD卡暫存器串列
- 4.SD卡初始化(SPI模式)
- 5.SD卡讀寫(SPI模式)
- 6.采用SPI方式,連線
- 二、CubeMX創建工程
- 三、代碼
- 1.主函式
- 2.編譯
- 四、結果
- 參考
一、SD卡協議原理
1.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 設備進行資料傳輸,
2.SD卡物理結構

一般SD卡包括有存盤單元、存盤單元介面、電源檢測、卡及介面控制器和介面驅動器 5個部分,
存盤單元是存盤資料部件,存盤單元通過存盤單元介面與卡控制單元進行資料傳輸;
電源檢測單元保證SD卡作業在合適的電壓下,如出現掉電或上狀態時,它會使控制單元和存盤單元介面復位;
卡及介面控制單元控制SD卡的運行狀態,它包括有8個暫存器;
介面驅動器控制SD卡引腳的輸入輸出,
SD卡總共有8個暫存器,用于設定或表示SD卡資訊,
這些暫存器只能通過對應的命令訪問,SDIO定義64個命令,每個命令都有特殊意義,可以實作某一特定功能,SD卡接收到命令后,根據命令要求對SD卡內部暫存器進行修改,程式控制中只需要發送組合命令就可以實作SD卡的控制以及讀寫操作,
3.SD卡暫存器串列

4.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),在完成了初始化之后,就可以開始讀寫資料了,
5.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卡程序,
6.采用SPI方式,連線

我們在用USB轉TTL為STM32供電的時候一定需要接到5V上面去,并且在用32給SD卡模塊供電的時候一定一定要接到5V電源上,否則我們無法驅動該SD模塊
二、CubeMX創建工程
完整工程鏈接在最后
1.配置SYS

2.配置PA4如圖所示

3.配置USART1

4.配置SPI1為全雙工主模式

5.配置FATFS

6.管腳配置

7.配置時鐘樹

8.工程配置

這里一定要修改堆疊的大小,太小了會使我們無法讀取SD卡的資料,直接導致我們的程式跑飛
三、代碼
1.主函式
main.c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© 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 631907030429 石頭\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****/
2.編譯

編譯無錯,接下來燒錄即可,
四、結果



參考
用STM32F103完成對SD卡數的讀寫
STM32用cube配置FATFS模式下SPI讀寫SD卡
工程下載:
https://pan.baidu.com/s/12EJQf1qGzPf1M7w4I9alrg
提取碼:1111
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/390469.html
標籤:其他
上一篇:“ZETA over LoRa”亮相2021STM32全國研討會 推動LPWAN生態融合
下一篇:三步實作西門子PLC遠程監控
