Данный урок предназначен для изучения основных приемов работы с SD-картами с помощью MicroSD Card adapter.
ПЕРЕЧЕНЬ КОМПОНЕНТОВ СХЕМЫ
- ARDUINO UNO R3 (оригинальная плата)
- LCD дисплей 16х2 с модулем I2C
- Датчик DHT11 (температура, влажность)
- Модуль MicroSD Card Adapter
- Соединительные провода
ТЕОРИЯ
Для связи контроллера ATmel платы Ардуино и MicroSD Card Adapter изпользуется интерфейс SPI. Давайте немного разберемся, что это!
Serial Peripheral Interface или SPI — последовательный периферийный интерфейс, служит для связи периферии и микроконтроллера. Например, в качестве периферии может быть: дисплей, различные датчики, FLASH память, SD карта (да, да, SD карта или «флешка» которую вы используете в телефонах и фотоаппаратах общается с внешним миром с помощью интерфейса SPI) и т.д.
В SPI всегда есть один ведущий и один/несколько ведомых устройств.
Передачу данных всегда инициализирует ведущий. В SPI используются четыре линии связи:
- MOSI или SI — выход ведущего, вход ведомого (англ. MasterOutSlaveIn). Служит для передачи данных от ведущего устройства ведомому.
- MISO или SO — вход ведущего, выход ведомого (англ. MasterInSlaveOut). Служит для передачи данных от ведомого устройства ведущему.
- SCLK или SCK — последовательный тактовый сигнал (англ. SerialClock). Служит для передачи тактового сигнала для ведомых устройств.
- CS или SS — выбор микросхемы, выбор ведомого (англ. Chip Select, Slave Select).
P.S. Для обеспечения односторонней связи с одним устройством, достаточно использовать SCLK, MOSI (в случае если ведомое устройство только принимает) или SCLK, MISO (в случае если ведомое устройство ничего не принимает, а только передает информацию). На входе CS ведомого устройства должен быть установлен логический ноль, иначе ведомый не будет работать.
P.S. Если ведомое устройство и передает и принимает, то можно ограничиться тремя проводами – MISO, MOSI, SCLK, на вход CS ведомого устройства также необходимо установить логический ноль.
SPI может быть реализован в микроконтроллере аппаратно, тогда задача по управлению интерфейсом решается для каждого микроконтроллера отдельно, т.к. реализации могут быть разными. Например, для ATmega328Р (микроконтроллер компании Atmel) при работе с SPI нам нужно самим программным путем установить на CS логический ноль при начале приема/передачи и установить логическую единицу обратно при окончание передачи.
Источник информации: http://s-engineer.ru/interfejs-spi/
МАКЕТ СХЕМЫ
КОД ПРОГРАММЫ
Для начала приведем код программы, который позволяет провести подключение к MicroSD Card Adapter, создать на SD-карте файл и записать туда разовое сообщение.
# include <SPI.h>;
# include <SD.h>;
const int chipSelect = 10; // В нашем случае контакт CS мы подключили к pin10 платы Ардуино
void setup() {
pinMode(chipSelect, OUTPUT); // Этот пин обязательно должен быть определен как OUTPUT (см.теорию урока)
Serial.begin(9600); // Инициализируем монитор порта для вывода туда сервисных сообщений
Serial.print("Initializing SD card...");
// Пытаемся проинициализировать модуль
if (!SD.begin(chipSelect))
{
Serial.println("Card failed, or not present");
return; // Если что-то пошло не так, завершаем работу:
}
Serial.println("card initialized.");
}
void loop() {
File dataFile = SD.open("datalog.txt", FILE_WRITE);
dataFile.println("Тест");
dataFile.close(); Открыв монитор порта, в случае удачного подключения, мы увидим следующее сообщение.
Если все удачно и мы смогли подключится к MicroSD, то попробуем совместить программу, которую мы написали для датчика DHT11 на Уроке 9 и будем одновременно выводить значения температуры на LCD-дисплей и в текстовый файл.
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2);
#include <dht11.h>
#define DHT11_PIN 2
dht11 DHT;
const int chipSelect = 10;
// __________________________________________________________
void setup()
{
lcd.init();
lcd.backlight();
pinMode(chipSelect, OUTPUT);
Serial.begin(9600);
Serial.print("Initializing SD card...");
if (!SD.begin(chipSelect))
{
Serial.println("Card failed, or not present");
return;
}
Serial.println("card initialized.");
}
// ___________________________________________________________
void loop()
{
DHT.read(DHT11_PIN);
lcd.setCursor(0,0); lcd.print("Temperature-");
lcd.setCursor(12,0); lcd.print(DHT.temperature);
File dataFile = SD.open("datalog.txt", FILE_WRITE);
dataFile.println(DHT.temperature);
dataFile.close();
delay (1000);
} Согласитесь, это не совсем приятно. Запустить устройство для журналирования, быть спокойным, так как система сообщила об удачном подключении и через пару дней выяснить, что записывать данные было некуда.
Поэтому мы доработали предыдущую программу с тем условием, что при отсутствии SD-карты или ее изъятии в процессе работы на дисплей выдавалось соответствующее сообщение. Код программы представлен ниже.
Первое изменение коснулось блока void setup(). Мы включили блок, благодаря которому на SD-карте создается файл init.txt. Если карты нет, то и файл будет отсутствовать.
File initFile = SD.open("init.txt", FILE_WRITE);
initFile.close(); В основной блок мы добавили следующий код. Предлагаю ученикам самим разобраться, что выполняет эта часть программного кода )))))
SD.begin(chipSelect);
if (!SD.exists("init.txt"))
{ lcd.setCursor(0,1); lcd.print("Not card "); }
else
{ lcd.setCursor(0,1); lcd.print("Card initialized"); } Ну и наконец, полный листинг программы. Видео работы представлено чуть выше.
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2);
#include <dht11.h>
#define DHT11_PIN 2
dht11 DHT;
const int chipSelect = 10;
void setup()
{
lcd.init();
lcd.backlight();
pinMode(chipSelect, OUTPUT);
Serial.begin(9600);
Serial.print("Initializing SD card...");
if (!SD.begin(chipSelect))
{
Serial.println("Card failed, or not present");
return;
}
Serial.println("card initialized.");
File initFile = SD.open("init.txt", FILE_WRITE);
initFile.close();
}
void loop()
{
DHT.read(DHT11_PIN);
lcd.setCursor(0,0); lcd.print("Temperature-");
lcd.setCursor(12,0); lcd.print(DHT.temperature);
SD.begin(chipSelect);
if (!SD.exists("init.txt"))
{ lcd.setCursor(0,1); lcd.print("Not card "); }
else
{ lcd.setCursor(0,1); lcd.print("Card initialized"); }
File dataFile = SD.open("datalog.txt", FILE_WRITE);
dataFile.println(DHT.temperature);
dataFile.close();
delay (500);
}