Arduino筆記(16):讀取/寫入 SD 卡資料

如果要在 Arduino 紀錄感測元件接收的數值,除了透過網路模組送出以外,開發板本身並不像 Raspberry Pi有外接 SD 或 Micro SD卡的介面,可以儲存在記憶卡上,要寫入資料到 SD卡上,就必須透過 SPI 的介面,才能將感測的資料寫入 SD卡。

我先測試一下 SD卡的模組是否能讀取/寫入檔案,如果可以,再改接網路擴展模組 W5100,看看相同的程式是否能存取W5100擴展板上 Micro SD卡的資料?結果如何呢?



[材料]

• Arduino Uno  x 1
• SD 卡模組  x1
• 連接線 x 6條

[接線圖]

• 註:上圖 DI 代表 SD卡模組 MOSI,DO代表 SD卡模組 MISO

• SD 卡模組連接線路
SD 卡模組
Arduino
GND
GND
+5V
5V
CS
Pin 4
MOSI
Pin 11
SCK (CLK)
Pin 13
MISO
Pin 12
SPI匯流排規定了4個保留邏輯訊號介面:(維基百科)
•  SCLK (Serial Clock):串行時鐘,由主機發出
•  MOSI (Master Output,Slave Input):主機輸出從機輸入訊號,由主機發出
•  MISO (Master Input,Slave Output):主機輸入從機輸出訊號,由從機發出
•  SS (Slave Selected) 或 Chip Select (CS):由主機發出,低電位有效

有關SPI的說明,可參考這篇:「Raspberry Pi 筆記(二):GPIO接腳與 I2C 及 SPI 安裝」。


[SD Library]

SD  Class
•  初始設定 SD卡及函式庫:SD.begin(cspin)
    cspin (選項): Arduino 連接SD卡模組 SS 或 CS的 Pin腳

•  檢查括號內的檔案名稱是否存在:exists()

•  建立目錄:SD.mkdir(filename)

•  開啟檔案:SD.open(filepath, mode)
   mode : FILE_READ  開啟唯讀檔案,從檔案開始處讀取.
               FILE_WRITE 開啟讀寫檔案,從檔案最後處開始寫入

•  移除檔案:SD.remove(filename)

•  移除目錄:SD.rmdir(filename)

File  Class
•  關閉檔案:file.close()

•  將data 字串寫到檔案中,不跳行:file.print(data)

•  將data 字串寫到檔案中,不跳行:file.println(data)

•  將 data 字串寫入檔案中:file.write(data)

[程式]

我參考Arduino IDE的兩個範例 cardinfo 跟 files,試著在 SD卡上,顯示 SD 卡的相關資訊,再建立一個檔案,寫入測試文字後,關閉檔案。以下是執行的測試程式:

#include <SPI.h>
#include <SD.h>

File myFile;

// 設定 SD library 功能變數:

Sd2Card card;
SdVolume volume;
SdFile root;

const int chipSelect = 4;

void setup() {

  Serial.begin(9600);  // 開啟通訊串列埠開啟
  while (!Serial) {    // 等待串列埠連線
  }

  //----------- 寫入檔案
  Serial.print("\nWaiting for SD card ready...");

  if (!SD.begin(4)) {
    Serial.println("Fail!");
    return;
  }
  Serial.println("Success!");

  myFile = SD.open("card.txt", FILE_WRITE);       // 開啟檔案,一次僅能開啟一個檔案
  
  if (myFile) {                                   // 假使檔案開啟正常
    Serial.print("Write to card.txt...");         
    myFile.println("Test to write data to SD card...");  // 繼續寫在檔案後面
    myFile.close();                               // 關閉檔案
    Serial.println("Completed!");
  } else {
    Serial.println("\n open file error ");    // 無法開啟時顯示錯誤
  }
  
   //----------- 顯示SD 卡資訊

  if (!card.init(SPI_HALF_SPEED, chipSelect)) {
    Serial.println("initialization failed. Check: SD Card");
    return;
  } else {
    Serial.println("============= Card Information ==================");
  }

  // 顯示SD卡類型

  Serial.print("Card type: ");
  switch (card.type()) {
    case SD_CARD_TYPE_SD1:
      Serial.println("SD1");
      break;
    case SD_CARD_TYPE_SD2:
      Serial.println("SD2");
      break;
    case SD_CARD_TYPE_SDHC:
      Serial.println("SDHC");
      break;
    default:
      Serial.println("Unknow");
  }

  // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
  if (!volume.init(card)) {
    Serial.println("Could not find FAT16/FAT32 partition.");
    return;
  }

  // 顯示類型和 FAT 空間大小
  uint32_t volumesize;
  Serial.print("Volume type is FAT");
  Serial.println(volume.fatType(), DEC);
  Serial.println();

  volumesize = volume.blocksPerCluster();    // clusters are collections of blocks
  volumesize *= volume.clusterCount();       // we'll have a lot of clusters
  volumesize *= 512;                            // SD card blocks are always 512 bytes
  Serial.print("Volume size (bytes): ");
  Serial.println(volumesize);
  Serial.print("Volume size (Kbytes): ");
  volumesize /= 1024;
  Serial.println(volumesize);
  Serial.print("Volume size (Mbytes): ");
  volumesize /= 1024;
  Serial.println(volumesize);

  Serial.println("\nFiles found on the card (name, date and size in bytes): ");
  root.openRoot(volume);

  // list all files in the card with date and size
  root.ls(LS_R | LS_DATE | LS_SIZE);

  Serial.println("================= Finished =====================");
}

void loop() {            // 在Setup()執行完成後,就等結束 
}

[執行結果]

換上W5100網路擴展板,程式一個字元都不需要更改,可以讀取擴展板上的 SD卡資料。我的 SD卡上有中文名稱,就會顯示部分中文沒問題,但大多數變成亂碼。檔案列表第一個 card.txt 就是測試時寫入的檔案。

[參考資料]

•  Arduino.cc :SD Library

8 留言

  1. 你好:我是arduino的初學者,想請問你SD 卡模組的型號是??在哪裡購買的??謝謝

    回覆刪除
    回覆
    1. 你好;我看一下SD卡上沒有標示型號,我有一個SD卡模組,另一個是Micro SD卡模組。前者是在台北光華商場買的,後者是在拍賣網路買的,只要是SPI介面,應該都可以用。

      刪除
  2. 您好:想請問一下 因為我有另外接一個RTC的時鐘模組,因此我有時間的數據
    那麼是否可以讓檔案名稱變為日期
    EX:今天是2018.01.23,那麼檔案名稱便為"2018.01.23.txt"這樣
    不好意思麻煩您了,謝謝您!

    回覆刪除
  3. 您好,在網路擴展板,連接網路的時候,需要做SSID跟password的設定。
    是否有辦法讓網路擴展板去讀取SSID跟password、讓控制板直接連網呢?

    回覆刪除
  4. 我想請問一下 怎麼寫入Flash memory

    回覆刪除
  5. 你好:
    我剛開始學
    想請問文章中的SD Library那邊的設定要從哪邊開始操作?

    回覆刪除
    回覆
    1. 你好,
      要載入SD Library,可以從Arduino的IDE選單,選擇「草稿碼」-> 「匯入程式庫」->「管理程式庫」,輸入 SD Library, 再安裝即可。有關Library安裝,可參考這裡的說明https://atceiling.blogspot.com/2019/09/arduino-arduino-ide-library.html

      刪除

張貼留言

較新的 較舊