ESP32 : Guide pour le module de carte MicroSD Arduino

ESP32 : Guide pour le module de carte MicroSD Arduino

Ce guide montre comment utiliser une carte microSD avec l’ESP32 : vous apprendrez à lire et à écrire des fichiers sur la carte microSD. Pour interfacer la carte microSD avec la carte ESP32, nous utiliserons un module de carte microSD (protocole de communication SPI). L’utilisation d’une carte microSD avec l’ESP32 est particulièrement utile pour l’enregistrement de données ou le stockage de fichiers qui ne rentrent pas dans le système de fichiers (SPIFFS). L’ESP32 sera programmé à l’aide du noyau Arduino.

Guide ESP32 pour le module de carte MicroSD utilisant Arduino IDE

Dans ce didacticiel, nous aborderons les sujets suivants :

Module de carte microSD

Il existe différents modules de carte microSD compatibles avec l’ESP32. Nous utilisons le module de carte microSD illustré dans la figure suivante – il communique à l’aide du protocole de communication SPI. Vous pouvez utiliser n’importe quel autre module de carte microSD avec une interface SPI.

Module de carte MicroSD pour ESP32 ESP8266 Arduino SPI

Ce module de carte microSD est également compatible avec d’autres microcontrôleurs comme l’Arduino et les cartes ESP8266 NodeMCU. Pour apprendre à utiliser le module carte microSD avec l’Arduino, vous pouvez suivre le tutoriel suivant :

Où acheter?

Vous pouvez cliquer sur le lien ci-dessous pour vérifier les différents magasins où vous pouvez obtenir le module de carte microSD :

Module de carte MicroSD pour ESP32 ESP8266 Arduino SPI

Brochage du module de carte MicroSD – SPI

Le module de carte microSD communique à l’aide du protocole de communication SPI. Vous pouvez le connecter à l’ESP32 en utilisant les broches SPI par défaut.

Module de carte microSD ESP32
3V3 3.3V
CS GPIO 5
MOSI GPIO 23
CLK GPIO 18
MISO GPIO 19
Terre Terre

Pièces requises

Schéma de câblage du module de carte microSD ESP32

Pour ce tutoriel, vous avez besoin des pièces suivantes :

Vous pouvez utiliser les liens précédents ou accéder directement à MakerAdvisor.com/tools pour trouver toutes les pièces pour vos projets au meilleur prix !

1677293532 256 ESP32 Guide pour le module de carte MicroSD Arduino

ESP32 avec module de carte microSD – Schéma de principe

Pour câbler le module de carte microSD à la carte ESP32, vous pouvez suivre le schéma suivant (pour les broches ESP32 SPI par défaut) :

Schéma de câblage du module de carte microSD ESP32

Lecture recommandée : Référence de brochage ESP32 : Quelles broches GPIO devez-vous utiliser ?

Préparation de la carte microSD

Avant de poursuivre le didacticiel, assurez-vous de formater votre carte microSD en FAT32. Suivez les instructions suivantes pour formater votre carte microSD ou utilisez un outil logiciel comme Formateur de carte SD (compatible avec Windows et Mac OS).

1. Insérez la carte microSD dans votre ordinateur. Allez dans Poste de travail et faites un clic droit sur la carte SD. Sélectionnez Format comme indiqué dans la figure ci-dessous.

Module de carte MicroSD format carte SD

2. Une nouvelle fenêtre apparaît. Sélectionnez FAT32, appuyez sur Démarrer pour initialiser le processus de formatage et suivez les instructions à l’écran.

Module de carte MicroSD format carte SD

Préparation de l’IDE Arduino

Nous allons programmer la carte ESP32 à l’aide de l’IDE Arduino. Assurez-vous donc que le module complémentaire ESP32 est installé. Suivez le tutoriel suivant :

Si vous préférez utiliser VSCode + PlatformIO, suivez plutôt le tutoriel suivant :

ESP32 Gestion des fichiers avec un module de carte MicroSD

Il existe deux bibliothèques différentes pour l’ESP32 (incluses dans le noyau Arduino de l’ESP32) : la Bibliothèque SD et le Bibliothèque SDD_MMC.h.

Si vous utilisez la bibliothèque SD, vous utilisez le contrôleur SPI. Si vous utilisez la bibliothèque SDD_MMC, vous utilisez le contrôleur ESP32 SD/SDIO/MMC. Vous pouvez en savoir plus sur le Pilote ESP32 SD/SDIO/MMC.

ESP32 Gérer les fichiers dans la carte microSD Exemple de lecture et d'écriture

Il existe plusieurs exemples dans Arduino IDE qui montrent comment gérer les fichiers sur la carte microSD à l’aide de l’ESP32. Dans l’IDE Arduino, accédez à Fichier > Exemples > SD(esp32) > SD_Test, ou copiez le code suivant.

/*
  Rui Santos
  Complete project details at https://Raspberryme.com/esp32-microsd-card-arduino/
  
  This sketch can be found at: Examples > SD(esp32) > SD_Test
*/

#include "FS.h"
#include "SD.h"
#include "SPI.h"

void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
  Serial.printf("Listing directory: %s\n", dirname);

  File root = fs.open(dirname);
  if(!root){
    Serial.println("Failed to open directory");
    return;
  }
  if(!root.isDirectory()){
    Serial.println("Not a directory");
    return;
  }

  File file = root.openNextFile();
  while(file){
    if(file.isDirectory()){
      Serial.print("  DIR : ");
      Serial.println(file.name());
      if(levels){
        listDir(fs, file.name(), levels -1);
      }
    } else {
      Serial.print("  FILE: ");
      Serial.print(file.name());
      Serial.print("  SIZE: ");
      Serial.println(file.size());
    }
    file = root.openNextFile();
  }
}

void createDir(fs::FS &fs, const char * path){
  Serial.printf("Creating Dir: %s\n", path);
  if(fs.mkdir(path)){
    Serial.println("Dir created");
  } else {
    Serial.println("mkdir failed");
  }
}

void removeDir(fs::FS &fs, const char * path){
  Serial.printf("Removing Dir: %s\n", path);
  if(fs.rmdir(path)){
    Serial.println("Dir removed");
  } else {
    Serial.println("rmdir failed");
  }
}

void readFile(fs::FS &fs, const char * path){
  Serial.printf("Reading file: %s\n", path);

  File file = fs.open(path);
  if(!file){
    Serial.println("Failed to open file for reading");
    return;
  }

  Serial.print("Read from file: ");
  while(file.available()){
    Serial.write(file.read());
  }
  file.close();
}

void writeFile(fs::FS &fs, const char * path, const char * message){
  Serial.printf("Writing file: %s\n", path);

  File file = fs.open(path, FILE_WRITE);
  if(!file){
    Serial.println("Failed to open file for writing");
    return;
  }
  if(file.print(message)){
    Serial.println("File written");
  } else {
    Serial.println("Write failed");
  }
  file.close();
}

void appendFile(fs::FS &fs, const char * path, const char * message){
  Serial.printf("Appending to file: %s\n", path);

  File file = fs.open(path, FILE_APPEND);
  if(!file){
    Serial.println("Failed to open file for appending");
    return;
  }
  if(file.print(message)){
      Serial.println("Message appended");
  } else {
    Serial.println("Append failed");
  }
  file.close();
}

void renameFile(fs::FS &fs, const char * path1, const char * path2){
  Serial.printf("Renaming file %s to %s\n", path1, path2);
  if (fs.rename(path1, path2)) {
    Serial.println("File renamed");
  } else {
    Serial.println("Rename failed");
  }
}

void deleteFile(fs::FS &fs, const char * path){
  Serial.printf("Deleting file: %s\n", path);
  if(fs.remove(path)){
    Serial.println("File deleted");
  } else {
    Serial.println("Delete failed");
  }
}

void testFileIO(fs::FS &fs, const char * path){
  File file = fs.open(path);
  static uint8_t buf[512];
  size_t len = 0;
  uint32_t start = millis();
  uint32_t end = start;
  if(file){
    len = file.size();
    size_t flen = len;
    start = millis();
    while(len){
      size_t toRead = len;
      if(toRead > 512){
        toRead = 512;
      }
      file.read(buf, toRead);
      len -= toRead;
    }
    end = millis() - start;
    Serial.printf("%u bytes read for %u ms\n", flen, end);
    file.close();
  } else {
    Serial.println("Failed to open file for reading");
  }


  file = fs.open(path, FILE_WRITE);
  if(!file){
    Serial.println("Failed to open file for writing");
    return;
  }

  size_t i;
  start = millis();
  for(i=0; i<2048; i++){
    file.write(buf, 512);
  }
  end = millis() - start;
  Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end);
  file.close();
}

void setup(){
  Serial.begin(115200);
  if(!SD.begin(5)){
    Serial.println("Card Mount Failed");
    return;
  }
  uint8_t cardType = SD.cardType();

  if(cardType == CARD_NONE){
    Serial.println("No SD card attached");
    return;
  }

  Serial.print("SD Card Type: ");
  if(cardType == CARD_MMC){
    Serial.println("MMC");
  } else if(cardType == CARD_SD){
    Serial.println("SDSC");
  } else if(cardType == CARD_SDHC){
    Serial.println("SDHC");
  } else {
    Serial.println("UNKNOWN");
  }

  uint64_t cardSize = SD.cardSize() / (1024 * 1024);
  Serial.printf("SD Card Size: %lluMB\n", cardSize);

  listDir(SD, "/", 0);
  createDir(SD, "/mydir");
  listDir(SD, "/", 0);
  removeDir(SD, "/mydir");
  listDir(SD, "/", 2);
  writeFile(SD, "/hello.txt", "Hello ");
  appendFile(SD, "/hello.txt", "World!\n");
  readFile(SD, "/hello.txt");
  deleteFile(SD, "/foo.txt");
  renameFile(SD, "/hello.txt", "/foo.txt");
  readFile(SD, "/foo.txt");
  testFileIO(SD, "/test.txt");
  Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
  Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
}

void loop(){

}

Afficher le code brut

Cet exemple montre comment effectuer presque toutes les tâches dont vous pourriez avoir besoin avec la carte microSD :

Vous pouvez également utiliser les exemples SD_MMC – ils sont similaires aux exemples SD, mais utilisent le pilote SDMMC. Pour le pilote SDMMC, vous avez besoin d’un module de carte microSD compatible. Le module que nous utilisons dans ce didacticiel ne prend pas en charge SDMMC.

Comment fonctionne le code

Tout d’abord, vous devez inclure les bibliothèques suivantes : FS.h pour gérer les fichiers, SD.h pour s’interfacer avec la carte microSD et SPI.h pour utiliser le protocole de communication SPI.

#include "FS.h"
#include "SD.h"
#include "SPI.h"

L’exemple fournit plusieurs fonctions pour gérer les fichiers sur la carte microSD.

Lister un répertoire

La fonction listDir() liste les répertoires sur la carte SD. Cette fonction accepte comme arguments le système de fichiers (SD), le nom du répertoire principal et les niveaux à atteindre dans le répertoire.

void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
  Serial.printf("Listing directory: %s\n", dirname);

  File root = fs.open(dirname);
  if(!root){
    Serial.println("Failed to open directory");
    return;
  }
  if(!root.isDirectory()){
    Serial.println("Not a directory");
    return;
  }

  File file = root.openNextFile();
  while(file){
    if(file.isDirectory()){
      Serial.print("  DIR : ");
      Serial.println(file.name());
      if(levels){
        listDir(fs, file.name(), levels -1);
      }
    } else {
      Serial.print("  FILE: ");
      Serial.print(file.name());
      Serial.print("  SIZE: ");
      Serial.println(file.size());
    }
     file = root.openNextFile();
  }
}

Voici un exemple d’appel de cette fonction. Le / correspond au répertoire root de la carte microSD.

listDir(SD, "/", 0);

Créer un répertoire

La fonction createDir() crée un nouveau répertoire. Passez en argument le système de fichiers SD et le chemin du nom du répertoire.

void createDir(fs::FS &fs, const char * path){
  Serial.printf("Creating Dir: %s\n", path);
  if(fs.mkdir(path)){
    Serial.println("Dir created");
  } else {
    Serial.println("mkdir failed");
  }
}

Par exemple, la commande suivante crée un nouveau répertoire à la root appelé mydir.

createDir(SD, "/mydir");

Supprimer un répertoire

Pour supprimer un répertoire de la carte microSD, utilisez la fonction removeDir() et passez en argument le système de fichiers SD et le chemin du nom du répertoire.

void removeDir(fs::FS &fs, const char * path){
  Serial.printf("Removing Dir: %s\n", path);
  if(fs.rmdir(path)){
    Serial.println("Dir removed");
  } else {
    Serial.println("rmdir failed");
  }
}

Voici un exemple:

removeDir(SD, "/mydir");

Lire le contenu du fichier

La fonction readFile() lit le contenu d’un fichier et imprime le contenu dans le moniteur série. Comme pour les fonctions précédentes, passez en argument le système de fichiers SD et le chemin du fichier.

void readFile(fs::FS &fs, const char * path){
  Serial.printf("Reading file: %s\n", path);

  File file = fs.open(path);
  if(!file){
    Serial.println("Failed to open file for reading");
    return;
  }

  Serial.print("Read from file: ");
  while(file.available()){
    Serial.write(file.read());
  }
  file.close();
}

Par exemple, la ligne suivante lit le contenu du fichier hello.txt.

readFile(SD, "/hello.txt")

Écrire du contenu dans un fichier

Pour écrire du contenu dans un fichier, vous pouvez utiliser la fonction writeFile(). Passer en argument, le filesystem SD, le chemin du fichier et le message

void writeFile(fs::FS &fs, const char * path, const char * message){
  Serial.printf("Writing file: %s\n", path);

  File file = fs.open(path, FILE_WRITE);
  if(!file){
    Serial.println("Failed to open file for writing");
    return;
  }
  if(file.print(message)){
    Serial.println("File written");
  } else {
    Serial.println("Write failed");
  }
  file.close();
}

La ligne suivante écrit Hello dans le fichier hello.txt.

writeFile(SD, "/hello.txt", "Hello ");

Ajouter du contenu à un fichier

De même, vous pouvez ajouter du contenu à un fichier (sans écraser le contenu précédent) à l’aide de la fonction appendFile().

void appendFile(fs::FS &fs, const char * path, const char * message){
  Serial.printf("Appending to file: %s\n", path);

  File file = fs.open(path, FILE_APPEND);
  if(!file){
    Serial.println("Failed to open file for appending");
    return;
  }
  if(file.print(message)){
    Serial.println("Message appended");
  } else {
    Serial.println("Append failed");
  }
  file.close();
}

La ligne suivante ajoute le message World!\n dans le fichier hello.txt. Le \n signifie que la prochaine fois que vous écrivez quelque chose dans le fichier, il sera écrit dans une nouvelle ligne.

appendFile(SD, "/hello.txt", "World!\n");

Renommer un fichier

Vous pouvez renommer un fichier en utilisant la fonction renameFile(). Passez comme arguments le système de fichiers SD, le nom de fichier d’origine et le nouveau nom de fichier.

void renameFile(fs::FS &fs, const char * path1, const char * path2){
  Serial.printf("Renaming file %s to %s\n", path1, path2);
  if (fs.rename(path1, path2)) {
    Serial.println("File renamed");
  } else {
    Serial.println("Rename failed");
  }
}

La ligne suivante renomme le fichier hello.txt en foo.txt.

renameFile(SD, "/hello.txt", "/foo.txt");

Supprimer un fichier

Utilisez la fonction deleteFile() pour supprimer un fichier. Passez en argument le système de fichiers SD et le chemin d’accès du fichier que vous souhaitez supprimer.

void deleteFile(fs::FS &fs, const char * path){
  Serial.printf("Deleting file: %s\n", path);
  if(fs.remove(path)){
    Serial.println("File deleted");
  } else {
    Serial.println("Delete failed");
  }
}

La ligne suivante supprime le fichier foo.txt de la carte microSD.

deleteFile(SD, "/foo.txt");

Tester un fichier

Les fonctions testFileIO() indiquent le temps nécessaire pour lire le contenu d’un fichier.

void testFileIO(fs::FS &fs, const char * path){
  File file = fs.open(path);
  static uint8_t buf[512];
  size_t len = 0;
  uint32_t start = millis();
  uint32_t end = start;
  if(file){
    len = file.size();
    size_t flen = len;
    start = millis();
    while(len){
      size_t toRead = len;
      if(toRead > 512){
        toRead = 512;
      }
      file.read(buf, toRead);
      len -= toRead;
    }
    end = millis() - start;
    Serial.printf("%u bytes read for %u ms\n", flen, end);
    file.close();
  } 
  else {
    Serial.println("Failed to open file for reading");
  }

  file = fs.open(path, FILE_WRITE);
  if(!file){
    Serial.println("Failed to open file for writing");
    return;
  }

  size_t i;
  start = millis();
  for(i=0; i<2048; i++){
    file.write(buf, 512);
  }
  end = millis() - start;
  Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end);
  file.close();
}

La fonction suivante teste le fichier test.txt.

testFileIO(SD, "/test.txt");

Initialiser la carte microSD

Dans setup(), les lignes suivantes initialisent la carte microSD avec SD.begin().

Serial.begin(115200);
if(!SD.begin()){
  Serial.println("Card Mount Failed");
  return;
}
uint8_t cardType = SD.cardType();

if(cardType == CARD_NONE){
  Serial.println("No SD card attached");
  return;
}

Si vous ne transmettez aucun argument à la fonction begin(), elle essaiera d’initialiser la communication SPI avec la carte microSD sur la broche de sélection de puce (CS) par défaut. Si vous souhaitez utiliser une autre broche CS, vous pouvez la passer en argument à la fonction begin(). Par exemple, si vous souhaitez utiliser GPIO 17 comme broche CS, vous devez utiliser les lignes de code suivantes :

Serial.begin(115200);
if(!SD.begin(17)){
  Serial.println("Card Mount Failed");
  return;
}
uint8_t cardType = SD.cardType();

Si vous souhaitez utiliser des broches SPI personnalisées avec la carte microSD, allez dans cette rubrique.

Obtenir le type de carte microSD

Les lignes suivantes impriment le type de carte microSD sur le moniteur série.

Serial.print("SD Card Type: ");
if(cardType == CARD_MMC){
  Serial.println("MMC");
} else if(cardType == CARD_SD){
  Serial.println("SDSC");
} else if(cardType == CARD_SDHC){
  Serial.println("SDHC");
} else {
  Serial.println("UNKNOWN");
}

Obtenir la taille de la carte microSD

Vous pouvez obtenir la taille de la carte microSD en appelant la méthode cardSize() :

uint64_t cardSize = SD.cardSize() / (1024 * 1024);
Serial.printf("SD Card Size: %lluMB\n", cardSize);

Test des fonctions de la carte MicroSD

Les lignes suivantes appellent les fonctions que nous avons vues précédemment.

listDir(SD, "/", 0);
createDir(SD, "/mydir");
listDir(SD, "/", 0);
removeDir(SD, "/mydir");
listDir(SD, "/", 2);
writeFile(SD, "/hello.txt", "Hello ");
appendFile(SD, "/hello.txt", "World!\n");
readFile(SD, "/hello.txt");
deleteFile(SD, "/foo.txt");
renameFile(SD, "/hello.txt", "/foo.txt");
readFile(SD, "/foo.txt");
testFileIO(SD, "/test.txt");
Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));

Manifestation

Téléchargez le croquis précédent sur votre carte ESP32. Après cela, ouvrez le moniteur série et appuyez sur le bouton RST embarqué ESP32. Si l’initialisation réussit, vous obtiendrez des messages similaires sur le moniteur série.

Caractéristiques de test du module de carte MicroSD de la carte ESP32 : lecture, écriture, suppression
Caractéristiques de test du module de carte MicroSD de la carte ESP32 : lecture, écriture, suppression

Utiliser des broches SPI personnalisées avec la carte MicroSD

Les bibliothèques SD.h et SD_MMC.h utilisent les broches VSPI SPI (23, 19, 18, 5) par défaut. Vous pouvez définir d’autres broches comme broches SPI. L’ESP32 dispose de deux interfaces SPI : HSPI et VSPI sur les broches suivantes :

IPS MOSI MISO CLK CS
VSPI GPIO 23 GPIO 19 GPIO 18 GPIO 5
HSPI GPIO 13 GPIO 12 GPIO 14 GPIO 15

Lecture recommandée : Référence de brochage ESP32 : Quelles broches GPIO devez-vous utiliser ?

Pour utiliser d’autres broches SPI, vous pouvez procéder comme suit :

Au début de votre code, déclarez les pins que vous souhaitez utiliser, par exemple :

#define SCK  17
#define MISO  19
#define MOSI  23
#define CS  5

Créez une nouvelle classe SPI sur HSPI ou VSPI. Nous utilisons VSPI. Les deux fonctionneront bien.

SPIClass spi = SPIClass(VSPI);

Dans le setup(), initialisez le protocole de communication SPI sur les broches définies précédemment :

spi.begin(SCK, MISO, MOSI, CS);

Enfin, initialisez la carte microSD avec la méthode begin(). Passez en argument la broche CS, l’instance SPI que vous souhaitez utiliser et la fréquence du bus.

if (!SD.begin(CS,spi,80000000)) {
  Serial.println("Card Mount Failed");
  return;
}

Voici l’exemple de code modifié pour utiliser des broches SPI personnalisées :

/*
  Rui Santos
  Complete project details at https://Raspberryme.com/esp32-microsd-card-arduino/
  
  This sketch was mofidied from: Examples > SD(esp32) > SD_Test
*/

#include "FS.h"
#include "SD.h"
#include "SPI.h"

#define SCK  17
#define MISO  19
#define MOSI  23
#define CS  5

SPIClass spi = SPIClass(VSPI);

void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
  Serial.printf("Listing directory: %s\n", dirname);

  File root = fs.open(dirname);
  if(!root){
    Serial.println("Failed to open directory");
    return;
  }
  if(!root.isDirectory()){
    Serial.println("Not a directory");
    return;
  }

  File file = root.openNextFile();
  while(file){
    if(file.isDirectory()){
      Serial.print("  DIR : ");
      Serial.println(file.name());
      if(levels){
        listDir(fs, file.name(), levels -1);
      }
    } else {
      Serial.print("  FILE: ");
      Serial.print(file.name());
      Serial.print("  SIZE: ");
      Serial.println(file.size());
    }
    file = root.openNextFile();
  }
}

void createDir(fs::FS &fs, const char * path){
  Serial.printf("Creating Dir: %s\n", path);
  if(fs.mkdir(path)){
    Serial.println("Dir created");
  } else {
    Serial.println("mkdir failed");
  }
}

void removeDir(fs::FS &fs, const char * path){
  Serial.printf("Removing Dir: %s\n", path);
  if(fs.rmdir(path)){
    Serial.println("Dir removed");
  } else {
    Serial.println("rmdir failed");
  }
}

void readFile(fs::FS &fs, const char * path){
  Serial.printf("Reading file: %s\n", path);

  File file = fs.open(path);
  if(!file){
    Serial.println("Failed to open file for reading");
    return;
  }

  Serial.print("Read from file: ");
  while(file.available()){
    Serial.write(file.read());
  }
  file.close();
}

void writeFile(fs::FS &fs, const char * path, const char * message){
  Serial.printf("Writing file: %s\n", path);

  File file = fs.open(path, FILE_WRITE);
  if(!file){
    Serial.println("Failed to open file for writing");
    return;
  }
  if(file.print(message)){
    Serial.println("File written");
  } else {
    Serial.println("Write failed");
  }
  file.close();
}

void appendFile(fs::FS &fs, const char * path, const char * message){
  Serial.printf("Appending to file: %s\n", path);

  File file = fs.open(path, FILE_APPEND);
  if(!file){
    Serial.println("Failed to open file for appending");
    return;
  }
  if(file.print(message)){
    Serial.println("Message appended");
  } else {
    Serial.println("Append failed");
  }
  file.close();
}

void renameFile(fs::FS &fs, const char * path1, const char * path2){
  Serial.printf("Renaming file %s to %s\n", path1, path2);
  if (fs.rename(path1, path2)) {
    Serial.println("File renamed");
  } else {
    Serial.println("Rename failed");
  }
}

void deleteFile(fs::FS &fs, const char * path){
  Serial.printf("Deleting file: %s\n", path);
  if(fs.remove(path)){
    Serial.println("File deleted");
  } else {
    Serial.println("Delete failed");
  }
}

void testFileIO(fs::FS &fs, const char * path){
  File file = fs.open(path);
  static uint8_t buf[512];
  size_t len = 0;
  uint32_t start = millis();
  uint32_t end = start;
  if(file){
    len = file.size();
    size_t flen = len;
    start = millis();
    while(len){
      size_t toRead = len;
      if(toRead > 512){
        toRead = 512;
      }
      file.read(buf, toRead);
      len -= toRead;
    }
    end = millis() - start;
    Serial.printf("%u bytes read for %u ms\n", flen, end);
    file.close();
  } else {
    Serial.println("Failed to open file for reading");
  }


  file = fs.open(path, FILE_WRITE);
  if(!file){
    Serial.println("Failed to open file for writing");
    return;
  }

  size_t i;
  start = millis();
  for(i=0; i<2048; i++){
    file.write(buf, 512);
  }
  end = millis() - start;
  Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end);
  file.close();
}

void setup(){
  Serial.begin(115200);
  spi.begin(SCK, MISO, MOSI, CS);

  if (!SD.begin(CS,spi,80000000)) {
    Serial.println("Card Mount Failed");
    return;
  }
  uint8_t cardType = SD.cardType();

  if(cardType == CARD_NONE){
    Serial.println("No SD card attached");
    return;
  }

  Serial.print("SD Card Type: ");
  if(cardType == CARD_MMC){
    Serial.println("MMC");
  } else if(cardType == CARD_SD){
    Serial.println("SDSC");
  } else if(cardType == CARD_SDHC){
    Serial.println("SDHC");
  } else {
    Serial.println("UNKNOWN");
  }

  uint64_t cardSize = SD.cardSize() / (1024 * 1024);
  Serial.printf("SD Card Size: %lluMB\n", cardSize);

  listDir(SD, "/", 0);
  createDir(SD, "/mydir");
  listDir(SD, "/", 0);
  removeDir(SD, "/mydir");
  listDir(SD, "/", 2);
  writeFile(SD, "/hello.txt", "Hello ");
  appendFile(SD, "/hello.txt", "World!\n");
  readFile(SD, "/hello.txt");
  deleteFile(SD, "/foo.txt");
  renameFile(SD, "/hello.txt", "/foo.txt");
  readFile(SD, "/foo.txt");
  testFileIO(SD, "/test.txt");
  Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
  Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
}

void loop(){

}

Afficher le code brut


Exemple : Enregistrement de données ESP32 sur une carte microSD

L’utilisation d’une carte microSD est particulièrement utile pour les projets d’enregistrement de données. À titre d’exemple, nous allons vous montrer comment enregistrer les lectures de capteur d’un capteur BME280 avec des horodatages (heure d’époque).

Enregistrement de données ESP32 Aperçu du projet de carte BME280-microSD

Conditions préalables

Pour cet exemple, assurez-vous que les bibliothèques suivantes sont installées :

Vous pouvez installer ces bibliothèques à l’aide du gestionnaire de bibliothèque Arduino. Dans votre IDE Arduino, accédez à Sketch> Inclure la bibliothèque> Gérer les bibliothèques… Ensuite, recherchez les noms des bibliothèques et installez-les.

Si vous utilisez VS Code avec PlatformIO, copiez les lignes suivantes dans le fichier platformio.ini pour inclure toutes les bibliothèques nécessaires.

lib_deps = adafruit/Adafruit BME280 Library @ ^2.1.0
  adafruit/Adafruit Unified Sensor @ ^1.1.4

Diagramme schématique

Pour cet exemple, vous devez câbler le module de carte microSD et le capteur BME280 à l’ESP32. Voici une liste des pièces nécessaires :

Câblez le circuit en suivant le schéma suivant.

Schéma de circuit de la carte microSD ESP32 BME280

Vous pouvez également consulter les tableaux suivants :

BME280 ESP32
NIV 3V3
Terre Terre
SCL GPIO 22
SDA GPIO 21
Module de carte microSD ESP32
3V3 3.3V
CS GPIO 5
MOSI GPIO 23
CLK GPIO 18
MISO GPIO 19
Terre Terre

Code

Copiez le code suivant dans votre IDE Arduino. Cette esquisse obtient les lectures du capteur BME280 (température, humidité et pression) et les enregistre dans un fichier sur la carte microSD toutes les 30 secondes. Il enregistre également l’horodatage (heure d’époque demandée à un serveur NTP).

/*
  Rui Santos
  Complete project details at https://Raspberryme.com/esp32-microsd-card-arduino/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

// Libraries for SD card
#include "FS.h"
#include "SD.h"
#include <SPI.h>

//Libraries for BME280 sensor
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

// Libraries to get time from NTP Server
#include <WiFi.h>
#include "time.h"

// Replace with your network credentials
const char* ssid     = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Timer variables
unsigned long lastTime = 0;
unsigned long timerDelay = 30000;

// BME280 I2C
Adafruit_BME280 bme;

// Variables to hold sensor readings
float temp;
float hum;
float pres;
String dataMessage;

// NTP server to request epoch time
const char* ntpServer = "pool.ntp.org";

// Variable to save current epoch time
unsigned long epochTime; 

// Function that gets current epoch time
unsigned long getTime() {
  time_t now;
  struct tm timeinfo;
  if (!getLocalTime(&timeinfo)) {
    //Serial.println("Failed to obtain time");
    return(0);
  }
  time(&now);
  return now;
}

// Initialize WiFi
void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
}

// Init BME280
void initBME(){
  if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }
}

// Initialize SD card
void initSDCard(){
   if (!SD.begin()) {
    Serial.println("Card Mount Failed");
    return;
  }
  uint8_t cardType = SD.cardType();

  if(cardType == CARD_NONE){
    Serial.println("No SD card attached");
    return;
  }
  Serial.print("SD Card Type: ");
  if(cardType == CARD_MMC){
    Serial.println("MMC");
  } else if(cardType == CARD_SD){
    Serial.println("SDSC");
  } else if(cardType == CARD_SDHC){
    Serial.println("SDHC");
  } else {
    Serial.println("UNKNOWN");
  }
  uint64_t cardSize = SD.cardSize() / (1024 * 1024);
  Serial.printf("SD Card Size: %lluMB\n", cardSize);
}

// Write to the SD card
void writeFile(fs::FS &fs, const char * path, const char * message) {
  Serial.printf("Writing file: %s\n", path);

  File file = fs.open(path, FILE_WRITE);
  if(!file) {
    Serial.println("Failed to open file for writing");
    return;
  }
  if(file.print(message)) {
    Serial.println("File written");
  } else {
    Serial.println("Write failed");
  }
  file.close();
}

// Append data to the SD card
void appendFile(fs::FS &fs, const char * path, const char * message) {
  Serial.printf("Appending to file: %s\n", path);

  File file = fs.open(path, FILE_APPEND);
  if(!file) {
    Serial.println("Failed to open file for appending");
    return;
  }
  if(file.print(message)) {
    Serial.println("Message appended");
  } else {
    Serial.println("Append failed");
  }
  file.close();
}

void setup() {
  Serial.begin(115200);
  
  initWiFi();
  initBME();
  initSDCard();
  configTime(0, 0, ntpServer);
  
  // If the data.txt file doesn't exist
  // Create a file on the SD card and write the data labels
  File file = SD.open("/data.txt");
  if(!file) {
    Serial.println("File doesn't exist");
    Serial.println("Creating file...");
    writeFile(SD, "/data.txt", "Epoch Time, Temperature, Humidity, Pressure \r\n");
  }
  else {
    Serial.println("File already exists");  
  }
  file.close();
}

void loop() {
  if ((millis() - lastTime) > timerDelay) {
    //Get epoch time
    epochTime = getTime();
    
    //Get sensor readings
    temp = bme.readTemperature();
    //temp = 1.8*bme.readTemperature() + 32;
    hum = bme.readHumidity();
    pres = bme.readPressure()/100.0F;

    //Concatenate all info separated by commas
    dataMessage = String(epochTime) + "," + String(temp) + "," + String(hum) + "," + String(pres)+ "\r\n";
    Serial.print("Saving data: ");
    Serial.println(dataMessage);

    //Append the data to file
    appendFile(SD, "/data.txt", dataMessage.c_str());

    lastTime = millis();
  }
}

Afficher le code brut

Insérez vos informations d’identification réseau dans les variables suivantes et le code fonctionnera immédiatement :

const char* ssid     = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

Cet exemple utilise les fonctions que nous avons vues précédemment pour écrire et ajouter des données à la carte microSD (fonctions writeFile() et appendFile()).

Pour mieux comprendre le fonctionnement de cet exemple, nous vous recommandons de jeter un œil aux tutoriels suivants :

Manifestation

Téléchargez le code sur votre tableau. Vous pouvez vérifier sur le moniteur série si tout fonctionne comme prévu.

Enregistrement de données ESP32 BME280 sur carte microSD moniteur série

Laissez le projet fonctionner pendant un certain temps pour recueillir quelques lectures. Ensuite, insérez la carte microSD sur votre ordinateur et vous devriez avoir un fichier appelé data.txt avec les lectures du capteur.

Enregistrement de données ESP32 BME280 vers fichier sur carte microSD

Exemple : Serveur Web ESP32 avec fichiers de la carte microSD

Vous pouvez enregistrer les fichiers pour créer un serveur Web avec l’ESP32 sur une carte microSD (fichiers HTML, CSS, JavaScript et image). Cela peut être utile si les fichiers sont trop volumineux pour tenir sur le système de fichiers ESP32, ou cela peut également être plus pratique en fonction de votre projet.

Serveur Web ESP32 avec fichiers de la carte microSD Comment ça marche

Pour vous montrer comment procéder, nous allons créer un serveur Web simple qui sert un fichier HTML, un CSS et un fichier PNG pour créer une page Web et afficher un favicon.

Déplacez les fichiers suivants sur votre carte microSD (cliquez sur les liens pour télécharger les fichiers) :

Remarque : déplacez uniquement les fichiers vers la carte microSD, pas les dossiers.

Ensuite, téléchargez le code suivant sur votre IDE Arduino.

/*
  Rui Santos
  Complete project details at https://Raspberryme.com/esp32-web-server-microsd-card/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include "FS.h"
#include "SD.h"
#include "SPI.h"

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);

void initSDCard(){
  if(!SD.begin()){
    Serial.println("Card Mount Failed");
    return;
  }
  uint8_t cardType = SD.cardType();

  if(cardType == CARD_NONE){
    Serial.println("No SD card attached");
    return;
  }

  Serial.print("SD Card Type: ");
  if(cardType == CARD_MMC){
    Serial.println("MMC");
  } else if(cardType == CARD_SD){
    Serial.println("SDSC");
  } else if(cardType == CARD_SDHC){
    Serial.println("SDHC");
  } else {
    Serial.println("UNKNOWN");
  }
  uint64_t cardSize = SD.cardSize() / (1024 * 1024);
  Serial.printf("SD Card Size: %lluMB\n", cardSize);
}

void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
}

void setup() {
  Serial.begin(115200);
  initWiFi();
  initSDCard();

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SD, "/index.html", "text/html");
  });

  server.serveStatic("/", SD, "/");

  server.begin();
}

void loop() {
  
}

Afficher le code brut

Insérez vos informations d’identification réseau dans les variables suivantes et le code devrait fonctionner immédiatement :

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

Manifestation

Après avoir téléchargé les fichiers sur la carte microSD et l’esquisse sur votre carte ESP32, ouvrez le moniteur série à un débit en bauds de 115200. Appuyez sur le bouton RST intégré à l’ESP32. L’adresse IP ESP32 sera affichée sur le moniteur série.

Serveur Web ESP32 avec fichiers de la carte microSD Démonstration du moniteur série Arduino IDE

Sur votre réseau local, ouvrez un navigateur Web et saisissez l’adresse IP ESP32. Vous devriez avoir accès à la page Web suivante construite avec les fichiers stockés sur la carte microSD.

Serveur Web ESP32 avec fichiers de la carte microSD

Pour une explication détaillée de ce projet, reportez-vous au tutoriel suivant :

Conclusion

Dans ce tutoriel, vous avez appris à interfacer une carte microSD avec l’ESP32 et à lire et écrire des fichiers. Vous avez également appris à l’utiliser pour des projets d’enregistrement de données ou à stocker des fichiers à servir dans vos projets de serveur Web.

Pour des projets plus approfondis avec la carte microSD, nous vous recommandons de jeter un œil à ce qui suit :

Nous espérons que vous avez trouvé ce tutoriel utile. En savoir plus sur l’ESP32 avec nos ressources :

Cette vidéo vous emmène dans l’histoire de Raspberry Pi :

YouTube video

  • AZDelivery 5 x SPI Reader Mémoire Lecteur Micro SD TF Memory Card Module Shield Compatible avec Arduino incluant Un E-Book!
    ✅ Notre AZ-Delivery SPI Reader Micro est une extension facile à utiliser et économique de votre espace de stockage microcontrôleur en utilisant une fente pour carte SD. ✅ Ces lecteurs de cartes SD pratiques vous permettront de communiquer facilement avec le microcontrôleur via le protocole SPI. ✅ AZ-Delivery Micro SD Card SPI Reader Module supporte les cartes Micro SD (2G), Micro SDHC (32G) (carte haute vitesse). ✅ Notre module SPI Reader Micro SD Card Reader Shield Module supporte une alimentation de 5 volts. ✅ Ce produit inclut un E-Book qui fournit des informations utiles sur la façon de commencer votre projet. Il permet une installation rapide et fait gagner du temps sur le processus de configuration. On y trouve une série d'exemples d'applications, des guides d'installation complets et des bibliothèques.
  • kwmobile Lot 2X Module Carte Micro SD - Lecteur Carte mémoire - Compatible avec Cartes Arduino Raspberry et Autres microcontrôleurs
    LIRE ET ÉCRIRE : Avec le module card micro-SD de kwmobile, lecture et écriture de données sont possibles sur Arduino par exemple. PETIT ET PRATIQUE : Grâce à son design compact, vous pouvez amener votre accessoire partout. DONNÉES TECHNIQUES : Les tensions d'entrée sont comprises entre 4,5 et 5,5 Volts. Le module dispose de 6 broches. COMPATIBLE AVEC : des cartes Arduino, Raspberry Pi ainsi que d'autres micro contrôleurs. UTILISATION : Vous pouvez par exemple vous servir du module pour installer une station de contrôle avec carte mémoire externe ou pour faire de votre Arduino un lecteur MP3.
  • HALJIA SPI 3 pcs Lecteur Carte mémoire Micro SD TF Carte mémoire Shield Module de Lecture écriture des données Compatible avec Arduino Raspberry Pi
    Avec ce module de carte Micro SD, vous pouvez lire et écrire des données sur votre Arduino, Raspberry Pi, etc Tension d'entrée : 5 V Prend en charge les cartes Micro SD, les cartes Micro SDHC (carte haute vitesse) L'interface de communication est l'interface SPI standard 4 trous de vis M2, facile à installer