Симулятор SD-карты Arduino онлайн: логирование данных без модуля
SD-карта — мой самый «обидный» модуль: я собрал даталоггер, неделю логировал температуру на даче, а в воскресенье открыл карту — а там пусто. Оказалось, я забыл file.close() между записями: SD-карта пишет секторами по 512 байт, и без close() последний сектор не уходит на флешку. Неделя данных осталась в буфере. В браузере этот затык ловится за минуту: SD.open, write, close — и список файлов в карточке модуля обновляется сразу.
Модуль ставится на стенд симулятора из каталога: зелёный провод с меткой SD, четыре пина SPI (CS на D10, MOSI на D11, MISO на D12, SCK на D13). Список файлов в карточке — log.csv, config.txt, datalog.bin; в скетче через SD.open открывается по имени. Ниже — стартовый скетч лога температуры, цикл open/write/close, список файлов и честная граница модели.
Что эмулируется на стенде
SD-модуль в каталоге — деталь «Модуль SD-карты»: четыре пина SPI (CS на D10, MOSI на D11, MISO на D12, SCK на D13), зелёный провод с меткой SD. На плашке устройства — список файлов через «|»: log.csv|config.txt|datalog.bin. Скетч через SD.open(name, FILE_WRITE) открывает файл, file.write или print пишет данные, file.close закрывает сессию и сбрасывает буфер на «карту». Ловушка про «забыл close()» — из заголовка: без close() последний сектор (512 байт) остаётся в буфере модуля, и данные не попадают на флешку.
- SPI на D10-D13: CS на D10, MOSI на D11, MISO на D12, SCK на D13 — стандартный расклад Uno.
- SD.begin(10): инициализация карты с CS на D10; без неё SD.open возвращает «ложный» дескриптор.
- SD.open("log.csv", FILE_WRITE): открывает для дописывания; FILE_READ — для чтения. Если файла нет, FILE_WRITE создаёт, FILE_READ — нет.
- file.write(byte) или file.print("строка\n"): запись байта или текста. write(65) пишет один байт 0x41, print(65) — два символа «6» и «5».
- file.close(): обязательный шаг — сбрасывает буфер на карту. Без close() последний сектор (512 байт) не уходит.
Стартовый скетч: лог температуры в CSV
#include <SPI.h>#include <SD.h> const int CS = 10;File f; void setup() { Serial.begin(9600); SPI.begin(); if (!SD.begin(CS)) { Serial.println("SD ne naidena"); while (1); } Serial.println("SD OK");} void loop() { f = SD.open("log.csv", FILE_WRITE); if (f) { f.print(millis()); f.print(","); f.print(25.0, 1); // температура °C f.println(); f.close(); // без close() данные не уйдут Serial.println("zapisano"); } else { Serial.println("oshibka otkrytiya"); } delay(1000);}Запустите скетч — каждую секунду в log.csv дописывается строка «millis, 25.0». Список файлов в карточке модуля обновляется: появился log.csv, и его размер растёт. Полный разбор цикла open-write-close и сверки чтением — в уроке про сессию файла; первый запуск и диагностика — в уроке про 10 шагов SD.begin.
Список файлов: openNextFile в цикле
#include <SPI.h>#include <SD.h> void setup() { Serial.begin(9600); SPI.begin(); SD.begin(10); File root = SD.open("/"); File entry = root.openNextFile(); while (entry) { Serial.print(entry.name()); Serial.print(" "); Serial.print(entry.size()); Serial.println(" b"); entry = root.openNextFile(); } Serial.println("Gotovo");} void loop() {}openNextFile перебирает записи каталога и печатает «log.csv 1024 b». Имена идут в порядке физического заполнения — то есть в порядке создания, не по алфавиту; FAT не сортирует. Полный разбор openNextFile, рекурсии по папкам и ловушек 8.3-имён — в уроке про список файлов карты.
Граница: модель против живой карты
| Проверка | Симулятор | Только железо |
|---|---|---|
| SPI: D10-D13, SD.begin(10) | да: модуль «на шине» | то же, плюс реальные тайминги SPI |
| SD.open, file.write/print, file.close | да: список файлов обновляется | то же, плюс реальная запись сектора 512 байт |
| openNextFile: оглавление каталога | да: имена и размеры | то же, плюс порядок FAT |
| Ротация файлов по размеру | логически да | то же, плюс физическое удаление файла |
| 3,3 В на карте против 5V на SPI | не моделируется | да — на плате нужен согласователь уровней |
| Обрыв питания и потеря сектора | не моделируется | да — последний сектор теряется |
Браузер пишет и читает файлы как на плате, а физика — нет: на живой SD-карте 3,3 В, и 5-вольтовая логика Uno требует согласователя (модуль с делителем, готовый шилд или CD4050B). Без согласователя на китайских модулях карта работает «через раз», а через пару месяцев деградирует. Разбор уровней 3,3/5 — в уроке про 3V3 и 5V на SD; питание и просадки — в уроке про питание SD.
Грабли SD-карты
- Забытый file.close(): последний сектор (512 байт) остаётся в буфере, данные не уйдут на флешку. close() — обязательный шаг после каждой записи.
- 3,3 В против 5V: SD-карта 3,3-вольтовая, прямое подключение к Uno (5V) деградирует. На готовых модулях делитель уже стоит; на «голом» адаптере нужен CD4050B или резисторы.
- FAT16 против FAT32: карты до 2 ГБ — FAT16, от 4 ГБ — FAT32. Библиотека SD.h на Uno поддерживает обе, но на старых картах с FAT12 — нет. Форматируйте в FAT16 или FAT32.
- Имена 8.3: logfile.csv ок, datalog.csv ок, a-very-long-name.csv — обрежется до 8 символов имени. Не используйте длинные имена без библиотеки SdFat.
- Скорость записи: реальная карта пишет 50-100 КБ/с, в браузере — мгновенно. На плате лог раз в секунду — нормально, раз в 10 мс — потеря данных.