Худший жанр поломки — плавающий. Мой логгер на насосной станции неделю писал идеально на столе, увезли на объект — и за ночь в CSV поползли строки-уродцы: температура 99.9, метки с разрывом в полчаса, половина строк без завершения. SD.begin() при этом возвращал true, карта монтировалась, файлы создавались. Классическая диагностика из урока про SD.begin здесь бессильна: инициализация не падает, падает что-то дальше — и нужно понимать, на каком слое.
Этот урок — методика, а не список причин. Сначала научимся спрашивать у карты паспорт скетчем CardInfo: тип, объём, файловая система. Потом разложим отказы по трём слоям — не инициализируется, не открывается файл, мусор в данных — и у каждого слоя получим свой круг подозреваемых. В конце соберём чек-лист из шести шагов, который я теперь прогоняю на любой новой карте до того, как она уедет в корпус. К чек-листу я пришёл через блокнот: после третьей поездки, где я записывал, что менял и что помогло, в записях проступили слои, и методы перестали путаться между собой. Ниже — всё, что из того блокнота переписано начисто.
CardInfo: паспорт карты за десять секунд
В примерах Arduino IDE лежит скетч CardInfo, и я недооценивал его года полтора — пока не начал собирать логгеры для чужих рук. Смысл скетча: он ничего не пишет и не читает, он только опрашивает карту и печатает паспорт. Тип карты: SD1 — старые до 1 ГБ, SD2 — стандартные до 2 ГБ, SDHC — все современные от 4 ГБ. Файловая система: FAT16 или FAT32, плюс размер тома в гигабайтах и число кластеров. Дальше — список файлов с размерами. За десять секунд вы узнаёте главное: карта вообще отвечает (типа нет — разговора со стороны шины не случилось, смотрите питание и провода), карта того поколения, каким себя считает, и размечена ли она в FAT, который понимает библиотека.
Код отказа тоже полезен: если CardInfo печатает что-то вроде 0X1 — карта не прошла даже сброс командой CMD0, то есть шина жива, а ответа нет. Это почти всегда контакт, питание или мёртвая карта, и перебирать форматы в такой ситуации бессмысленно: до проверки FAT диалог ещё не дошёл.
Печать паспорта читается на пальцах. Карта на 8 ГБ покажет объём около 7.9 GB — расхождение в семь процентов с маркировкой заложено в саму разметку: производители считают по миллиардам байт, библиотека по степеням двойки. Тип SDHC у карты от 4 ГБ — если паспорт его напечатал, вы уже отсекли половину предположений о «старой несовместимости». А строка FAT32 означает, что инициализация прошла все три слоя: шина, карта, файловая система — и дальше искать надо не в них.
#include <SPI.h>#include <SD.h> const int chipSelect = 10;Sd2Card card;SdVolume volume; void setup() { Serial.begin(9600); if (!card.init(chipSelect)) { Serial.println("karta ne otvechaet: pitanie, provoda, kontakt"); while (true) { } } Serial.print("card type: "); if (card.type() == SD_CARD_TYPE_SDHC) { Serial.println("SDHC (4-32 GB)"); } else if (card.type() == SD_CARD_TYPE_SD2) { Serial.println("SD2 (do 2 GB)"); } else { Serial.println("SD1 (staraya)"); } if (!volume.init(card)) { Serial.println("FAT ne chitaetsya: format? ne exFAT li?"); while (true) { } } Serial.print("FAT"); Serial.println(volume.fatType()); // 16 ili 32 float gb = (float)volume.clusterCount() * volume.blocksPerCluster() / 2097152.0; Serial.print("volume GB: "); Serial.println(gb); Serial.println("karta v poryadke, mozhno rabotat");} void loop() { }Теперь раскладываем отказы по слоям — у каждого свой круг подозреваемых, и смешивать стратегии я перестал давно. Слой первый: SD.begin() или card.init() возвращают false. Карта не ответила даже на приветствие, круг узкий: питание модуля (импульс записи в 150 мА проваливает просевший вход ниже 4,4 В — на столе это видно редко, в сборке с длинными проводами постоянно), перепутанные MOSI и MISO, не тот номер CS относительно реального провода, не дожатая до щелчка карта. Конденсатор 100 мкФ на вход модуля и короткие провода — то, что мы считали в уроке про устройство модуля. Подсказка бесплатная: светодиод L на пине 13 мигает при каждом обращении к шине — если он даже не дёргается во время инициализации, провод скинулся раньше всяких тонкостей. Формат на этом слое обычно ни при чём: исключение одно — exFAT-карта иногда проходит init и ложится уже на монтировании, поэтому второй шаг после false — прочитать карту в компьютере и посмотреть формат.
Слой второй: карта монтируется, список файлов печатается, а конкретный SD.open() возвращает ложь. Тут формат почти всегда невиновен — смотрим имена и дисциплину работы с файлами.
Карта читается, а файл не открывается
Первая причина в моей практике — имена. FAT хранит короткие имена восемь-точка-три, длинные — надстройка, съедающая несколько записей каталога, а кириллица добавляет ещё и вопросы кодировки. Скетч пишет в файл Отчёт_за_январь.csv, а карта по дороге через телефон обзавелась новым именем — классика жанра. Я живу короткими: run.log, cfg.txt, d2512.csv — об этом уже был кусок в уроке про режимы открытия File. Вторая причина — файл уже открыт: библиотека держит один дескриптор на имя, повторный open того же файла при незакрытом первом возвращает ложь. Случай с двумя дескрипторами я ловил на конфиге теплицы: один open в setup, второй в loop — и вечная ложь, которая лечится одним close. Третья — карта заполнена или на адаптере microSD-в-SD стоит защита от записи: огонёк на модуле при этом весело горит, а запись молча не проходит.
Отдельный жанр — мусор в данных при живой инициализации и удачных open: записывается строка, а в ней обрывки, нули, температура 99.9. Здесь почти всегда питание: импульс записи проваливает питание, и карта пишет байт с искажением или бросает запись на середине. Провода короче, конденсатор на входе модуля, один общий провод на всё устройство — разбор просадок был в уроке про общий провод и грабли макетки. Если мусор повторяется через равные интервалы — ищите соседнего едока тока: реле или мотор, щёлкающие в тот же момент, когда пишется строка. Проверяется просадка без осциллографа: мультиметр в режиме Min/Max на входе питания модуля, пара записей — и прибор покажет минимум за период. У меня типичный провал был до 4.1 В на макетке с длинными проводами питания; после конденсатора и укороченных перемычек минимум поднялся до 4.7 В, и мусор ушёл вместе с ним.
| Шаг | Что делаем | Что увидим, если всё плохо |
|---|---|---|
| 1 | Перетыкать карту до двойного щелчка, проверить формат в ПК | exFAT или карта не видна в ПК — переформатировать в FAT32 |
| 2 | Мерить 5 В на входе модуля во время записи | ниже 4,4 В — провода короче, конденсатор 100 мкФ у модуля |
| 3 | Сверить провода: MOSI 11, MISO 12, SCK 13, CS 10 | перепутаны MISO/MOSI или CS ведёт не на тот пин |
| 4 | Паспорт карты: card type, FAT, объём, список файлов | типа нет — контакт; FAT не читается — формат |
| 5 | Пробник: запись probe.txt, чтение обратно, сверка size | размер не совпал — просадки питания или изношенная карта |
| 6 | Проверить имена 8.3 и дисциплину: один файл, close | длинные имена, второй open возвращает ложь, пустой файл |
Порядок шагов не случаен: от дешёвых и частых к дорогим и редким. Формат и контакт проверяются голыми руками за минуту, питание — мультиметром за пять, паспорт карты — одним скетчем, пробник записи — вторым. Ровно так мы в уроке про отладку через Serial печатали состояние программы по этапам — здесь тот же приём, только вместо переменных состояние железа. Дальше по разделу: как писать строки без потерь — урок про println и close, что разметить на карте — FAT16, FAT32 и размеры. Теперь симулятор: SD он не эмулирует, поэтому чек-лист показан моделью — кнопка D2 ведёт по шагам, каждый шаг печатает статус в Serial. И ещё правило, которое экономит деньги: подозреваемый круг сужается от дешёвого к дорогому. Карта стоит сотни рублей, модуль столько же, а ваш вечер дороже обоих — поэтому методы проверки идут в порядке цены часа, а не в порядке частоты в статьях.
- 1. Что печатает CardInfo, если карта не отвечает даже на сброс?
- 2. Инициализация падает, в ПК карта читается как FAT32. Что проверять первым?
- 3. Карта монтируется, файлы видны, а SD.open возвращает ложь на конкретное имя. Первая гипотеза?
- 4. Лог полон строк-уродцев: обрывки, 99.9, нули. Инициализация и open в порядке. Причина?
- 5. Сколько переменных менять за один прогон диагностики?
- CardInfo — паспорт карты: тип SD1/SD2/SDHC, FAT16/FAT32, объём и список файлов за десять секунд
- Код 0X1 — ответа на CMD0 нет: контакт, питание или мёртвая карта; формат тут ни при чём
- false при begin — слой шины: питание ниже 4,4 В на импульсе, MOSI/MISO, не тот CS, недожатая карта
- Карта монтируется, файл не открывается — имена восемь-точка-три без кириллицы и один открытый дескриптор
- Мусор в данных при живой записи — просадки питания: конденсатор 100 мкФ, короткие провода, один общий провод
- Шесть шагов чек-листа идут от дешёвых к дорогим; за прогон меняется одна переменная
Частые вопросы по теме урока
- Что печатает CardInfo, если карта не отвечает даже на сброс?
- Код 0X1 значит: шина жива, а ответа нет. Круг подозреваемых — контакт, питание, мёртвая карта. Формат тут ни при чём. Код вида 0X1 — ответа на CMD0 нет
- Инициализация падает, в ПК карта читается как FAT32. Что проверять первым?
- До проверки FAT диалог с картой не дошёл — виновата шина: питание ниже 4,4 В на импульсе, перепутанные линии, не тот CS, недожатая карта. Питание модуля и провода MOSI, MISO, CS
- Карта монтируется, файлы видны, а SD.open возвращает ложь на конкретное имя. Первая гипотеза?
- На этом слое формат обычно невиновен: короткие имена восемь-точка-три и один открытый дескриптор на файл закрывают девять случаев из десяти. Длинное или кириллическое имя, либо файл уже открыт
- Лог полон строк-уродцев: обрывки, 99.9, нули. Инициализация и open в порядке. Причина?
- Мусор в данных при живой записи — питание: импульс 150 мА проваливает вход ниже 4,4 В. Конденсатор 100 мкФ и короткие провода лечат. Просадки питания на импульсе записи
- Сколько переменных менять за один прогон диагностики?
- Меняя всё сразу, вы теряете диагноз. Шаг, на котором впервые появилось отличие от ожидания, — ваш слой поломки. Одну — иначе не понять, что именно сработало