224   221     15   57    

Как использовать SD-карту с Arduino?

Отвечаем на вопрос читателя о том, как можно использовать модуль SD-карты для проектов Arduino с большим объемом данных, которые требуют больше памяти.

Свои вопросы вы можете присылать на электронную почту редакции проекта mail@arduinoplus.ru.

Комплектующие

Для того, чтобы платы Ардуино работали с SD-картами нам нужны следующие комплектующие проекта:

  • Arduino UNO
  • Адаптер SD-карты
  • Провода-перемычка

Когда нужна SD-карта

Некоторые проекты могут собирать большое количество данных, таких как данные датчиков, считываемые в течение месяца, которые вы хотите хранить постоянно. Этот большой объем данных, вероятно, не поместится в EEPROM. Кроме того, вы не сможете удобным образом перенести информацию на компьютер таким способом.

Тем не менее, если вы храните данные на SD-карте, вы можете легко переносить созданные файлы и работать с ними на любом компьютере с устройством для чтения SD-карт.

Эта статья покажет как подключить и использовать стандартный модуль SD-карты с Arduino. Весь код и тестовые программы можно найти в виде zip-файла в конце этой статьи.

Подключение Arduino к адаптеру карт

Эти модули обычно используют последовательный периферийный интерфейс (SPI) для связи с микроконтроллером. Поэтому он будет занимать три вывода GPIO на Arduino. Кроме того, вам необходимо подключить линию выбора микросхемы, чтобы включить SD-карту и линии питания для питания адаптера.

Схема подключения Arduino к адаптеру SD-карты
Схема подключения Arduino к адаптеру SD-карты

Зеленая (MISO) и желтая (MOSI) линии соединяются с контактами 12 и 11 Arduino. Clock (тактовый сигнал, синий) должен быть привязан к контакту 13. Обратитесь к документации Arduino, если вы не уверены, какие контакты необходимо использовать на Arduino.

Тестовая программа

После выполнения необходимых подключений пришло время подключить SD-карту. В коротком тестовом скетче отображает файлы, присутствующие на карте. Код можно взять ниже или в zip-файле в конце этой статьи как - sd_info.

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

#define CS 8

Sd2Card card;
SdVolume volume;
SdFile root;

boolean initCard()
{
  Serial.print("Connecting to SD card... ");

  // Initialize the SD card
  if(!card.init(SPI_HALF_SPEED, CS))
  {
    // An error occurred
    Serial.println("\nError: Could not connect to SD card!");
    Serial.println("- Is a card inserted?");
    Serial.println("- Is the card formatted as FAT16/FAT32?");
    Serial.println("- Is the CS pin correctly set?");
    Serial.println("- Is the wiring correct?");

    return false;
  }
  else
    Serial.println("Done!");

  return true;
}

void setup()
{
  Serial.begin(9600);

  if(!initCard())
    while(1);

  Serial.println("\n----------------");
  Serial.println("---Basic Info---");
  Serial.println("----------------");

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

  Serial.println(" type card got connected");

  // Try to open the filesysten on the card
  if(!volume.init(card))
  {
    Serial.println("Could not open / on the card!\nIs the card formatted as FAT16/32?");
    while(1);
  }
  else
  {
    Serial.print("The inserted card is formatted as: FAT");
    Serial.println(volume.fatType(), DEC);
    Serial.print("And the card has a size of: ");

    // Calculate the storage capacity of the volume
    uint32_t cardSize = volume.blocksPerCluster() * volume.clusterCount();

    Serial.print(cardSize / 2048);
    Serial.println("MB!");
  }

  Serial.println("\n----------------");
  Serial.println("--Stored files--");
  Serial.println("----------------");

  // Print a list of files that are present on the card
  root.openRoot(volume);
  root.ls(LS_R);
}

void loop(void) {
}

Как видите, большая часть кода обрабатывает вывод консоли. Всего несколько строк необходимо для подключения к устройству и инициализации файловой системы для чтения и записи файлов. В этом примере, однако, печатаются только некоторые основные свойства карты, такие как размер, тип и сохраненные файлы.

Запись в файлы на SD-карте

Теперь, когда мы знаем, что карта и модуль работают, пришло время записать некоторые значения в файл. Пример SD_write (найденный в архиве) записывает две строки в файл журнала, который хранится на SD-карте.

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

#define CS 8

int i = 0;
File logFile;

boolean initCard()
{
  Serial.print("Connecting to SD card... ");

  // Initialize the SD card
  if (!SD.begin(CS))
  {
    // An error occurred
    Serial.println("\nError: Could not connect to SD card!");
    Serial.println("- Is a card inserted?");
    Serial.println("- Is the card formatted as FAT16/FAT32?");
    Serial.println("- Is the CS pin correctly set?");
    Serial.println("- Is the wiring correct?");

    return false;
  }
  else
    Serial.println("Done!");

  return true;
}

void setup()
{
  Serial.begin(9600);

  if (!initCard())
    while (1);

  // Files that are opened for writing will be
  // created automatically if they don't already
  // exist on the SD card
  logFile = SD.open("log.txt", FILE_WRITE);

  if (!logFile)
  {
    Serial.println("Could not open logfile!");
    while (1);
  }
}

void loop()
{
  // Replace the condition with a meaningful one
  // To indicate that writing to the file is done
  // and it can be closed.
  if (i++ < 10)
  {
    // Dummy Value, replace with real readout
    long sensorValue = random(0, 1023);

    // Write a few lines to the logfile
    logFile.print("[ERROR: ");
    logFile.print(millis());
    logFile.print("] ");
    logFile.println("Sensor A missing!");

    logFile.print("[INFO: ");
    logFile.print(millis());
    logFile.print("] ");
    logFile.print("Sensor B reading: ");

    logFile.println(sensorValue);
  }
  else
  {
    logFile.close();
    Serial.println("Writing finished!");
  }

  delay(500);
}

Часть кода инициализации почти такая же, как в первой программе. Однако вместо открытия тома сама карта SD должна быть инициализирована. После инициализации файл должен быть открыт.

При открытии файла для записи файл создается автоматически, если он не существует. Курсор всегда находится в конце файла. Поэтому, если вы не перемещаете его при открытии файла, вы просто добавляете в него новый текст. Поскольку содержимое хранится на SD-карте, вы можете использовать свой компьютер для чтения содержимого файла.

Чтение из файла, хранящегося на SD-карте

Вы также можете использовать библиотеку SD-карты для чтения файла. Однако по сравнению со стандартными функциями C доступные методы довольно ограничены. Я обнаружил, что в библиотеке SD-карт часто возникают проблемы с поиском файлов в папках. В следующем примере (в папке SD_read в zip-файле) показано, как можно прочитать значение из файла, который содержит показания датчика.

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

#define CS 8

int i = 0;
File sensorFile;

boolean initCard()
{
  Serial.print("Connecting to SD card... ");

  // Initialize the SD card
  if (!SD.begin(CS))
  {
    // An error occurred
    Serial.println("\nError: Could not connect to SD card!");
    Serial.println("- Is a card inserted?");
    Serial.println("- Is the card formatted as FAT16/FAT32?");
    Serial.println("- Is the CS pin correctly set?");
    Serial.println("- Is the wiring correct?");

    return false;
  }
  else
    Serial.println("Done!");

  return true;
}

void setup()
{
  Serial.begin(9600);

  if (!initCard())
    while (1);
  
  // Files that are opened for reading have to
  // exist. They will not be created.
  sensorFile = SD.open("value.txt", FILE_WRITE);

  if (!sensorFile)
  {
    Serial.println("Could not open sensor file!");
    while (1);
  }
  else
  {
    // Move the cursor the the beginning of the file for reading
    sensorFile.seek(0);

    // Read the entire file and print
    // it to the serial console.
    while (sensorFile.available())
      Serial.write(sensorFile.read());
  }
}

void loop()
{
}

Код должен быть понятным. Единственная реальная разница между этим примером и примером записи заключается в том, что файл читается побайтно. Таким образом, вам нужно перебрать количество байтов, которые вы хотите прочитать из файла. Результат должен выглядеть примерно так:

Адаптеры/модули SD-карт могут быть полезны, если вы хотите оставить проект без присмотра и заставить его создавать файлы журнала или сохранять большое количество показаний датчиков в течение более длительного периода времени. Однако, важно понимать, что чтение файлов с SD-карты не всегда работает должным образом. Ниже вы можете скачать архив с программами, которые были также приведены выше:

Свои вопросы вы можете присылать на электронную почту редакции проекта mail@arduinoplus.ru.

Ардуино+