Arduino SD記憶卡讀寫
好久沒發文了!
哈,真糟糕.因為最近工作繁忙,加上一有新想法就會再加入預設的題目中越做越大,
卻也沒辦法有個結束點.反而一直延後發文的期程.
所以改變一下策略,將預設的題目拆成若干小題目,先進行發表.
本次要介紹的是SD讀卡機,
我接下來要用這讀卡機去記錄一些Mega2560偵測到的資料.
以便做後續的分析.
硬體
這次採用的硬體是RepRap的Sdramps,
有興趣的可以參考網址https://reprap.org/wiki/Sdramps
我是直接去露x購買現成的大約5xNT.
使用方式很簡單直接插到Mega2560上就可以,如下圖
接腳的定義,如下圖
其中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()
{
}
|
Arduino SD卡讀寫由Pneg Yi-Hsing製作,以創用CC 姓名標示-非商業性-禁止改作 3.0 台灣 授權條款釋出。
留言列表