Arduino. Урок 15. SD карта.

Сегодня речь пойдет об использовании 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. Вот наглядная схема:

Подключение sd Arduino
Подключение sd Arduino

Обратите внимание на напряжение питания платы. Если на плате есть стабилизатор питания, то можете подавать на нее 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);
}


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

Запись на SD карту Arduino
Запись на SD карту Arduino

Подробно скетч моего регистратора показаний я расписывать не буду, потому что мы все это уже разбирали подробно в этом и прошлых уроках. В этом скетче сочетаются навыки из уроков по аналоговым входам, 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 метками. Надеюсь вам все было понятно.

1 комментарий

  1. Антон

    А нужно ли останавливать непрерывную запись в файл как-нибудь? Не испортится ли карта памяти при отключении непрерывно записываемых данных? Как отключать эту запись?

Добавить комментарий

Ардуино