Сегодня речь пойдет об использовании SD и micro SD карт в Arduino. Мы разберемся как можно подключить SD карты к Ардуино, как записывать и считывать информацию. Использование дополнительной памяти может быть очень полезно во многих проектах. Если вы не знаете что такое SPI, I2C и аналоговые выводы, то советую вам посмотреть прошлые уроки и разобраться с этими интерфейсами связи Ардуино.
Подключить SD карту к Arduino напрямую не получится, так как она не поддерживает нужный протокол связи. Но мы можем использовать дополнительные модули или шилды для этого. К счастью, стоят они очень дешево и доступны в разных вариантах.
В этом уроке используется:
Отличный набор для начинающих: | Купить |
Arduino Uno: | Купить |
Инфракрасный датчик расстояния: | Купить |
Плата расширения для считывания micro SD карт c SPI интерфейсом: | Купить |
Шилд для Arduino Uno: | Купить |
Карты micro SD: | Купить |
Датчики освещенности: | Купить |
Датчик температуры I2C: | Купить |
Подключение sd карт к Arduino
Модуль и шилд для считывания sd карт подключается по интерфейсу SPI. Шилд просто вставляется в Arduino Uno сверху. А плата подключается к пинам D10 -> CS, D11 -> MOSI, D12 -> MISO, D13 -> SCLK, 5V -> VIN (если на плате есть стабилизатор, если нет то 3,3V), GND -> GND. Вот наглядная схема:

Обратите внимание на напряжение питания платы. Если на плате есть стабилизатор питания, то можете подавать на нее 5 В. Если же стабилизатора нет, то необходимо подвести 3.3 В. В остальном все так же как мы разбирали в уроке по SPI интерфейсу. Теперь перейдем к программной части.
Запись и считывание SD карты на Arduino
Для работы с картами памяти в Arduino есть библиотека SD.h. Она по умолчанию доступна в Arduino IDE. С ней мы и будем работать. Для начала напишем простую программу, которая будет записывать обычную строку на SD карту. Теперь посмотрим на скетч:
// Подключаем библиотеку
#include <SD.h>
// Назначаем пины
int CS_pin = 10;
int pow_pin = 8; // Если вы используете SD Shield
//
float refresh_rate = 5000.0;
void setup() {
// Открываем соединение с компьютером
Serial.begin(9600);
Serial.println("Initializing Card");
//Назначаем пин CS_pin выходом
pinMode(CS_pin, OUTPUT);
//Если мы используем шилд то назначаем выходом пин для питания шилда
pinMode(pow_pin, OUTPUT);
digitalWrite(pow_pin, HIGH);
// Проверяем доступность карты
if (!SD.begin(CS_pin)) {
Serial.println("Card Failure");
return;
}
Serial.println("Card Ready");
}
void loop() {
// Строка которую будем записывать на карту
String dataString = "Hello";
// Открываем файл и записываем строку
// В одно время можно открывать только один файл
// Если файла нет то он будет создан
File logFile = SD.open("LOG.txt", FILE_WRITE);
if (logFile) {
logFile.println(dataString);
logFile.close();
Serial.println(dataString);
} else {
Serial.println("LOG.txt");
Serial.println("Couldn't open log file");
}
// Задержка для того что бы данных было не слишком много
delay(refresh_rate);
}
Отлично! У меня все работает так как и было задумано. Теперь я хочу немного доработать этот скетч. Давайте закинем текстовый файл на карту памяти с каким-нибудь значением и попробуем считать это на Arduino. Например я создам текстовый файл в котором будет всего одно число. Это число я буду использовать в качестве задержки между записью нашей строки на эту же карту памяти. Немного доработаем предыдущий скетч.
// Подключаем библиотеку
#include <SD.h>
// Назначаем пины
int CS_pin = 10;
int pow_pin = 8; // Если вы используете SD Shield
// Переменная для хранения считанных данных
float refresh_rate = 0.0;
void setup() {
// Открываем соединение с компьютером
Serial.begin(9600);
Serial.println("Initializing Card");
//Назначаем пин CS_pin выходом
pinMode(CS_pin, OUTPUT);
//Если мы используем шилд то назначаем выходом пин для питания шилда
pinMode(pow_pin, OUTPUT);
digitalWrite(pow_pin, HIGH);
// Проверяем доступность карты
if (!SD.begin(CS_pin)) {
Serial.println("Card Failure");
return;
}
Serial.println("Card Ready");
// Считываем данные из файла (COMMANDS.txt)
File commandFile = SD.open("COMMANDS.txt");
if (commandFile)
{
Serial.println("Reading Command File");
// Эта конструкция подробно объясняется в видео
float decade = pow(10, (commandFile.available() - 1));
while(commandFile.available())
{
float temp = (commandFile.read() - '0');
refresh_rate = temp*decade+refresh_rate;
decade = decade/10;
}
Serial.print("Refresh Rate = ");
Serial.print(refresh_rate);
Serial.println("ms");
}
else
{
Serial.println("Could not read command file.");
return;
}
}
void loop() {
// Строка которую будем записывать на карту
String dataString = "Hello";
// Открываем файл и записываем строку
// В одно время можно открывать только один файл
// Если файла нет то он будет создан
File logFile = SD.open("LOG.txt", FILE_WRITE);
if (logFile) {
logFile.println(dataString);
logFile.close();
Serial.println(dataString);
} else {
Serial.println("LOG.txt");
Serial.println("Couldn't open log file");
}
// Задержка для того что бы данных было не слишком много
delay(refresh_rate);
}
Давайте теперь сделаем что-то более сложное и полезное. Добавим несколько датчиков и будем записывать их показания на карту памяти. Я подключу пару инфракрасных дальномеров, датчик температуры и фото резистор для определения уровня освещенности. Вот так все будет выглядеть:

Подробно скетч моего регистратора показаний я расписывать не буду, потому что мы все это уже разбирали подробно в этом и прошлых уроках. В этом скетче сочетаются навыки из уроков по аналоговым входам, I2C и SPI интерфейсам и подтягивающим резисторам. Вы можете найти все это в разделе сайта уроки по Arduino. Вот скетч:
#include <SD.h> // Библиотека для работы с SD картой
#include <Wire.h> // I2C библиотека
// Назначаем пины SD шилда
int CS_pin = 10;
int pow_pin = 8;
// Пины инфракрасных дальнометров
int IR1_pin = 2;
int IR2_pin = 3;
// Пин фото резистора
int light_pin = 1;
float refresh_rate = 0.0; // Задержка обновления данных
int temp_address = 72; // Адрес I2C датчика температуры
long id = 1; // Переменная для счетчика строк
void setup()
{
Wire.begin();
Serial.begin(9600);
Serial.println("Initializing Card");
//CS Pin is an output
pinMode(CS_pin, OUTPUT);
//SD Card will Draw Power from Pin 8, so set it high
pinMode(pow_pin, OUTPUT);
digitalWrite(pow_pin, HIGH);
//Initialize Card
if (!SD.begin(CS_pin))
{
Serial.println("Card Failure");
return;
}
Serial.println("Card Ready");
//Read the Configuration information (COMMANDS.txt)
File commandFile = SD.open("COMMANDS.txt");
if (commandFile)
{
Serial.println("Reading Command File");
float decade = pow(10, (commandFile.available() - 1));
while(commandFile.available())
{
float temp = (commandFile.read() - '0');
refresh_rate = temp*decade+refresh_rate;
decade = decade/10;
}
Serial.print("Refresh Rate = ");
Serial.print(refresh_rate);
Serial.println("ms");
commandFile.close();
}
else
{
Serial.println("Could not read command file.");
return;
}
//Write Log File Header
File logFile = SD.open("LOG.csv", FILE_WRITE);
if (logFile)
{
logFile.println(", , , ,"); //Just a leading blank line, incase there was previous data
String header = "ID, Light, Temp, IR1, IR2";
logFile.println(header);
logFile.close();
Serial.println(header);
}
else
{
Serial.println("Couldn't open log file");
}
}
void loop()
{
//Check Light Level
int light_level = analogRead(light_pin);
//Read Temperature
Wire.beginTransmission(temp_address); //Start talking
Wire.send(0); //Ask for Register zero
Wire.endTransmission(); //Complete Transmission
Wire.requestFrom(temp_address, 1); //Request 1 Byte
while(Wire.available() == 0); //wait for response
int temp_c = Wire.receive(); // Get the temp
int temp_f = round(temp_c*9.0/5.0 +32.0); //Convert to stupid American units
//Read Distances
int IR1_val = analogRead(IR1_pin);
int IR2_val = analogRead(IR2_pin);
//Create Data string for storing to SD card
//We will use CSV Format
String dataString = String(id) + ", " + String(light_level) + ", " + String(temp_f) + ", " + String(IR1_val) + ", " + String(IR2_val);
//Open a file to write to
//Only one file can be open at a time
File logFile = SD.open("LOG.csv", FILE_WRITE);
if (logFile)
{
logFile.println(dataString);
logFile.close();
Serial.println(dataString);
}
else
{
Serial.println("Couldn't open log file");
}
//Increment ID number
id++;
delay(refresh_rate);
}
На сегодня все. В следующий раз мы разберемся с подключением RFID метками. Надеюсь вам все было понятно.