Данный урок предназначен для изучения основных приемов работы с 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. Для обеспечения односторонней связи с одним устройством, достаточно использовать SCLKMOSI (в случае если ведомое устройство только принимает) или SCLKMISO (в случае если ведомое устройство ничего не принимает, а только передает информацию). На входе CS ведомого устройства должен быть установлен логический ноль, иначе ведомый не будет работать.

P.S. Если ведомое устройство и передает и принимает, то можно ограничиться тремя проводами – MISOMOSISCLK, на вход 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);        
      }

Исследование работы схемы выявило одну особенность. При проведении инициализации MicroSD контроллер Ардуино опрашивает именно устройство MicroSD Card Adapter и выдаст сообщение об удачном подключении, даже если самой SD-карты в устройстве нет.

Согласитесь, это не совсем приятно. Запустить устройство для журналирования, быть спокойным, так как система сообщила об удачном подключении и через пару дней выяснить, что записывать данные было некуда.

Поэтому мы доработали предыдущую программу с тем условием, что при отсутствии 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);        
      }