sobota, 12 maja 2018

Moduł czytnika kart microSD i SD - zapis danych na karcie

Moduł czytnika kart daje duże możliwości, jeśli chodzi magazynowanie danych i to skłoniło mnie do uruchomienia i sprawdzenia jego możliwości. Wbrew nazwie, modułem takim można także zapisywać dane na karcie. Wziąłem pod lupę dwa posiadane moduły czytników kart: mikroSD i SD. Ten drugi dzięki odpowiednim przejściówkom także oczywiście obsługuje te mniejsze karty. W praktyce jednak okazał się bezużyteczny z racji na brak konwertera poziomów logicznych o czym będzie więcej w akapicie o uruchomieniu czytnika. Dlatego dalej opisuję tylko ten pierwszy z czytników (na zdjęciu po lewej).

Moduły kart: mikroSD (po lewej) i SD (po prawej)

Specyfikacja
  • zasilanie 5V (moduł posiada regulator napięcia)
  • komunikacja
    • magistrala SPI
    • bezpośrednio z arduino (wbudowany konwerter poziomów napięć 3,3V - 5V) 

Piny
  • 5V, GND - zasilanie
  • CS, SCK, MOSI, MISO - piny magistrali SPI

Uruchomienie

Do uruchomienia użyłem biblioteki SDFat i moduł czytnika z konwerterem poziomów napięć oraz karty Sandiska microSD o pojemności 8GB sformatowanej w FAT32. Początkowo użyłem modułu z dzielnikami napięcia do konwersji napięć szyny SPI (pierwsze zdjęcie, po prawej), bo tylko taki miałem, ale okazało się to poważnym błędem. W dokumentacji SDFat jest on w ogóle odradzany, a jeśli już chcemy go koniecznie użyć, to wskazane jest obniżenie o połowę częstotliwości pracy szyny SPI (szczegóły - katalog extras z biblioteki). W moim przypadku, wzięty z brzegu i raczej podstawowy przykład ReadWrite.ino (tworzony jest plik, zapisywane są do niego dane, a potem odczytywane) z tej biblioteki nie działał. Wobec tego pogrzebałem w sieci i napisałem coś pod własne potrzeby (przykład poniżej), który raz działał, raz nie (dla tego samego kodu), czyli niestabilnie. Generalnie straciłem przy nim mnóstwo czasu, a sama zmiana modułu (na taki z konwerterem) sprawiła, że problemy z brakiem zapisu na kartę zniknęły jak ręką odjął.

Uruchomienie modułu
Opracowany przykład co 5 sekund generuje liczbę losową i zapisuje ją na kartę pamięci wraz z informacją o czasie wygenerowania.  Dane te, rozdzielone znakiem tabulatora, są zapisywane w kolejnych liniach do pliku csv. Ten z kolei można otworzyć na przykład w arkuszu kalkulacyjnym i przetworzyć wedle własnych potrzeb.

#include <SPI.h>
#include <TimeLib.h>
#include "SdFat.h"

#define SD_CS_PIN SS

SdFat sd;
File file;
ArduinoOutStream coutF(file);
ArduinoOutStream coutS(Serial);

void setup() {
    Serial.begin(9600);
    pinMode(SD_CS_PIN, OUTPUT);

    coutS << F("Initializing SD card...") << endl;

    if (!sd.begin(SD_CS_PIN)) {
        coutS << F("Initialization failed!") << endl;
    } else {
        coutS << F("Initialization done") << endl;
        coutS << F("Time\t\tValue") << endl;

        if (file.open("log.csv", FILE_WRITE)) {
            coutF << F("Time\t\tValue") << endl;
            file.flush();
        } else {
            coutS << F("Cannot open file") << endl;
        }
    }

    //Generowanie losowej wartości
    randomSeed(analogRead(0));
}

void loop() {
    long val = millis() / 1000;
    int days = elapsedDays(val);
    int hours = numberOfHours(val);
    int minutes = numberOfMinutes(val);
    int seconds = numberOfSeconds(val);
    int randomValue = random(40, 60);

    printToSerial(days, hours, minutes, seconds, randomValue);
    printToFile(days, hours, minutes, seconds, randomValue);

    delay(5000);
}

void printToSerial(int days, int hours, int minutes, int seconds, int randomValue) {
    coutS << int(days);
    coutS << ":" << ((hours < 10) ? "0" : "") << int(hours);
    coutS << ":" << ((minutes < 10) ? "0" : "") << int(minutes);
    coutS << ":" << ((seconds < 10) ? "0" : "") << int(seconds);
    coutS << "\t" << randomValue << endl;
}

void printToFile(int days, int hours, int minutes, int seconds, int randomValue) {
    coutF << int(days);
    coutF << ":" << ((hours < 10) ? "0" : "") << int(hours);
    coutF << ":" << ((minutes < 10) ? "0" : "") << int(minutes);
    coutF << ":" << ((seconds < 10) ? "0" : "") << int(seconds);
    coutF << "\t" << randomValue << endl;
    file.flush();
}

W kodzie dla oszczędności pamięci, łańcuchy znaków zapisuje w pamięci flash. Kolejna wygodna rzecz to klasa ArduinoOutStream z SDFat pozwalająca na wygodniejsze łączenie łańcuchów znaków w miejsce przydługawego klepania linii z funkcją print (dla Serial i File).

Podłączenia pinów arduino i modułu czytnika są następujące:
  • CS - pin 10
  • MOSI - pin 11
  • MISO - pin 12
  • CLK - pin 13


Dane z terminala i z pliku
W przypadku problemów warto też uruchomić kod z przykładu QuickStart. Kod pokazuje informacje na temat podłączania modułu jak i użytej karty pamięci.

QuickStart - podłączenia pinów

QuickStart - informacje o karcie
Użyta biblioteka SdFat daje wiele możliwości. Wystarczy zajrzeć do katalogu examples z mnóstwem przykładów. Z kolei w katalogu extras znajduje się dokumentacja biblioteki (wystarczy otworzyć plik SdFat.html w oknie przeglądarki internetowej).

Źródła
1) Biblioteka SdFat

Brak komentarzy:

Prześlij komentarz