Arduino SD記憶卡讀寫

好久沒發文了!
哈,真糟糕.因為最近工作繁忙,加上一有新想法就會再加入預設的題目中越做越大,
卻也沒辦法有個結束點.反而一直延後發文的期程.
所以改變一下策略,將預設的題目拆成若干小題目,先進行發表.
本次要介紹的是SD讀卡機,
我接下來要用這讀卡機去記錄一些Mega2560偵測到的資料.
以便做後續的分析.

 

硬體

這次採用的硬體是RepRap的Sdramps,
有興趣的可以參考網址https://reprap.org/wiki/Sdramps
我是直接去露x購買現成的大約5xNT.
使用方式很簡單直接插到Mega2560上就可以,如下圖

Arduino SD卡讀寫

 

 

接腳的定義,如下圖

 

Arduino SD卡讀寫

 

其中Vcc我是用紅色線外接至Mega2560上的Vcc接腳.
基本上也可以直接插在Mega2560板上的Pin48,
然後將Pin48定義為輸出,並輸出HIGH電位,也可充當Vcc,但使用上需注意,
因其扇出(Fan-out)電流較小,若Mega2560所配置的硬體過多時,
就可能會造成不穩定現象,在電路偵錯上也會造成麻煩.

程式庫
這次用的是SdFat
https://github.com/greiman/SdFat
不會用程式庫的請參考我的另一篇文章
Arduino 程式庫 (Library)
SD Card使用上需注意,需用FAT32或FAT16的Format(格式)我稍微修改了一下LIB的範例,
使用上不難,就直接解析原始碼囉.

 

 

 

FOR READ

#include <SD.h>

Sd2Card card;          // Lib裡的類別
SdVolume volume;
SdFile root;
File myFile;

void setup() 
{
  Serial.begin(115200);
  Serial.print("\nInitializing SD card...");

  pinMode(SS_PIN, OUTPUT);           // 將SD Reader所對應的Pin定義為輸出 
  pinMode(SPI_MISO_PIN, INPUT);  // 將SD Reader所對應的Pin定義為輸入
  pinMode(SPI_MOSI_PIN, OUTPUT);  // 將SD Reader所對應的Pin定義為輸出 
  pinMode(SPI_SCK_PIN, OUTPUT);  // 將SD Reader所對應的Pin定義為輸出 

  digitalWrite(SPI_MOSI_PIN, LOW); // 將SD Reader所對應的Pin預設為低電壓
  digitalWrite(SPI_SCK_PIN, LOW); // 將SD Reader所對應的Pin預設為低電壓
  digitalWrite(SS_PIN, LOW); // 將SD Reader所對應的Pin預設為低電壓

  SD.begin(SS_PIN); // Chip Select

  if (!card.init(SPI_FULL_SPEED, SS_PIN))  // 初始化SD卡
  {
    Serial.println("initialization failed. Things to check:"); // 初始化失敗的訊息
    Serial.println("* is a card is inserted?");
    Serial.println("* Is your wiring correct?");
    Serial.println("* did you change the chipSelect pin to match your shield or module?");
  }
  else
  {
    Serial.println("SD Card OK!");  // 初始化成功的訊息
  }

  Serial.print("Card type: ");
  switch (card.type())  // 判斷SD卡種類
  {
  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("Unknown");
  }

  // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
  if (!volume.init(card)) // 判斷SD卡的格式是否為FAT16或FAT32
  {
    Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
  }

  // 計算SD卡的容量
    // 這段有些專業, 在我規畫的應用中也不太需要用到
    // 所以沒興趣的可先跳過這段.
    // 這段是先取出SD卡的blocksPerCluster數
    // 再取出clusterCount數
    // 1個blocksPerCluster是512Bytes
    // clusterCount = blocksPerCluster總數
    // 所以clusterCount*blocksPerCluster*512=總和Bytes數
    // 總和Bytes數/1024=總和MBytes數
    // 總和MBytes數/1024=總和GBytes數
    // 因為我的SD卡是8GBytes
    // 所以大小應該是8*1024=8192MBytes
    // 可以算出來的卻是-812MBytes
    // 那是因為long volumesize;這變數是32位元的
    // 32位元的整數範圍是0到4294967295
    // 而8G SD記憶體的Bytes總和
    // 應該是8*1024*1024*1024=8589934592
    // 又因為volumesize是long, 所以數值會溢位
    // 才會計算出-812MBytes這樣的數值

    long volumesize;
    Serial.print("Volume type is FAT");
    Serial.println(volume.fatType(), DEC);   
    volumesize = volume.blocksPerCluster();  
    volumesize *= volume.clusterCount();     
    //volumesize *= 512;                       
    //Serial.print("Volume size (bytes): ");
    //Serial.println(volumesize);
    Serial.print("Volume size (Kbytes): ");
    volumesize /= (1024/512);
    Serial.println(volumesize);
    Serial.print("Volume size (Mbytes): ");
    volumesize /= 1024;
    Serial.println(volumesize);

    // 改一下Code, 不去計算bytes數量, 讓volumesize不會溢位
    // 取出block後不要*512
    // 直接計算Kbytes, 變成volumesize /= (1024/512);
    // 算出的數值是7557120
    // Mbytes是7380
    // 根據Windows讀到的數值是7738490880bytes
    // 就是75571220Kbytes
    // 也是7380Mbytes
    // 跟我的數值一模一樣
    // 大約是7.2Gbytes
    // 不是8G整!!!
    // 那是因為製程的關係, 但好像又越拉越遠了, 製程這段就跳過不談了.


  Serial.println("Files 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);

  myFile = SD.open("test.txt"); // 打開test.txt這個檔案
  if (myFile)  // 檔案開啟成功, 就讀取檔案資料, 失敗就印出"error opening test.txt"
  {
    Serial.println("test.txt:");
    while (myFile.available())  // 取出檔案, 直到檔案結尾
    {
      Serial.write(myFile.read()); // 印出取出的檔案資料
    }
    myFile.close();
  }
  else 
  {
    Serial.println("error opening test.txt");
  }
}

void loop() 
{
}

 

跟讀檔的程式碼大同小異, 相同的部分就省略解釋囉. 

 

 

FOR WRITE

#include <SD.h>

Sd2Card card;
SdVolume volume;
SdFile root;
File myFile;

void setup() 
{
  Serial.begin(115200);
  Serial.print("\nInitializing SD card...");

  pinMode(SS_PIN, OUTPUT);
  pinMode(SPI_MISO_PIN, INPUT);
  pinMode(SPI_MOSI_PIN, OUTPUT);
  pinMode(SPI_SCK_PIN, OUTPUT);

  digitalWrite(SPI_MOSI_PIN, LOW);
  digitalWrite(SPI_SCK_PIN, LOW);
  digitalWrite(SS_PIN, LOW);

  SD.begin(SS_PIN);

  if (!card.init(SPI_FULL_SPEED, SS_PIN))
  {
    Serial.println("initialization failed. Things to check:");
    Serial.println("* is a card is inserted?");
    Serial.println("* Is your wiring correct?");
    Serial.println("* did you change the chipSelect pin to match your shield or module?");
  }
  else
  {
    Serial.println("SD Card OK!");
  }

  // print the type of card
  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("Unknown");
  }

  // 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.\nMake sure you've formatted the card");
  }


    long volumesize;
    Serial.print("Volume type is FAT");
    Serial.println(volume.fatType(), DEC);   
    volumesize = volume.blocksPerCluster();  
    volumesize *= volume.clusterCount();     
    //volumesize *= 512;                       
    //Serial.print("Volume size (bytes): ");
    //Serial.println(volumesize);
    Serial.print("Volume size (Kbytes): ");
    volumesize /= (1024/512);
    Serial.println(volumesize);
    Serial.print("Volume size (Mbytes): ");
    volumesize /= 1024;
    Serial.println(volumesize);


  Serial.println("Files 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);


  myFile = SD.open("test.txt", FILE_WRITE);   // 打開test.txt這個檔案, 指定為可寫入資料

  if (myFile) 
  {
    Serial.print("Writing to test.txt...");
    myFile.println("testing 1, 2, 3."); // 寫入"testing 1, 2, 3."這個字串
    myFile.close();                             // 關閉 test.txt這個檔案
    Serial.println("done.");
  }
  else 
  {
    Serial.println("error opening test.txt");
  }
}

void loop() 
{
}


 

創用 CC 授權條款
Arduino SD卡讀寫Pneg Yi-Hsing製作,以創用CC 姓名標示-非商業性-禁止改作 3.0 台灣 授權條款釋出。

arrow
arrow

    30sec 發表在 痞客邦 留言(0) 人氣()