本文主要利用STM32F103完成對SD卡的資料讀取,介紹該實驗的詳細操作
- 一、題目要求
- 二、SD卡協議原理
- 1、SD卡簡述
- 2、SD卡物理結構
- 3、SD卡暫存器
- 4、SD卡操作模式
- 5、SD卡初始化(SPI模式)
- 6、SD卡讀取與寫入(SPI模式)
- 三、實驗操作
- 1、硬體準備
- 2、連線
- 3、HAL庫配置
- 4、代碼分析
- 5、實驗結果分析
- 四、總結
一、題目要求
掌握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
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/389263.html
標籤:其他
上一篇:物流前沿理論與方法1
