ESP32-CAM: настройка, программирование, видеопоток и SD-карта
Как программировать ESP32-CAM: распиновка AI-Thinker, загрузка через ESP32-CAM-MB и USB-TTL, CameraWebServer, PSRAM, решение ошибок 0x105 и brownout, вспышка, фото на SD.
ESP32-CAM — недорогая плата Wi-Fi-камеры размером всего 27 × 40 мм, на которой есть процессор ESP32, 2-мегапиксельная камера OV2640, слот для microSD-карты и белый светодиод вспышки. Сама по себе она подключается к домашней сети, передаёт видео в браузер, делает фото и сохраняет их на SD-карту или отправляет через интернет. Это главная плата для камер видеонаблюдения, видеозвонков у двери, таймлапсов роста растений и роботов-машинок с видео, но USB-разъёма у неё нет, поэтому начало работы немного отличается от привычных плат ESP32.
Из этого руководства узнаешь распиновку AI-Thinker ESP32-CAM, как программировать её через адаптер ESP32-CAM-MB или USB-TTL-адаптер (включая соединение IO0-GND), как получить живую картинку в браузере с помощью готового примера CameraWebServer и какие настройки PSRAM и разделов памяти выбрать. Затем разберём причины самых частых ошибок Camera init failed with error 0x105 (камера не инициализирована) и brownout (просадка питания), научимся управлять вспышкой и соберём скетч, который по нажатию кнопки сохраняет фото на microSD-карту.

Что такое ESP32-CAM и как она работает?
Сердце платы — модуль ESP32-S с двухъядерным чипом ESP32, у которого есть Wi-Fi и Bluetooth. Камера подключается к 24-контактному разъёму на плате тонким шлейфом (FPC). ESP32 подаёт на камеру тактовый сигнал 20 MHz (XCLK) через GPIO 0 и настраивает её по похожей на I2C шине SCCB на GPIO 26 и 27. Сенсор OV2640 умеет сам сжимать изображение в JPEG, поэтому ESP32 получает не сырые пиксели, а небольшие JPEG-кадры. Эти кадры идут по 8-битной параллельной шине данных в 4 МБ PSRAM на плате, а дальше Wi-Fi доставляет их в браузер или на сервер.
| Параметр | Значение |
|---|---|
| Процессор | ESP32 (модуль ESP32-S), два ядра, до 240 MHz |
| Беспроводная связь | Wi-Fi 802.11 b/g/n (только 2,4 GHz), Bluetooth 4.2 и BLE |
| Память | 520 КБ встроенной SRAM + 4 МБ PSRAM, 4 МБ флеш-памяти |
| Камера | OV2640, 2 Мп, до 1600×1200 (UXGA), вывод в JPEG |
| Хранилище | Слот microSD (до 4 ГБ по официальной документации) |
| Подсветка | Белая вспышка (GPIO 4), красный светодиод состояния на обороте (GPIO 33) |
| Питание | 5 V на пин 5V (рекомендуется) или 3,3 V на пин 3V3 |
| Ток (при 5 V) | Около 180 mA с выключенной вспышкой, около 310 mA со вспышкой на полной яркости; пики при работе Wi-Fi выше |
| Размер | 27 × 40,5 × 4,5 мм |
Распиновка AI-Thinker ESP32-CAM: какие пины свободны?
Вдоль двух краёв платы 16 пинов, но по-настоящему свободных среди них совсем немного: одна только камера занимает 15 GPIO, а слот microSD делит ещё шесть. В таблице ниже собраны крайние пины и случаи, когда ими можно пользоваться. Общие особенности пинов ESP32 можно посмотреть и в утилите распиновки.
| Пин | Назначение | Можно использовать? |
|---|---|---|
| 5V | Вход питания (рекомендуется) | — |
| 3V3 | Вход питания 3,3 V | — |
| GND (3 пина) | Земля | — |
| VCC | Выход питания (по умолчанию 3,3 V) | Не используй его для питания платы |
| U0R (GPIO 3) | Последовательный RX: программирование и монитор порта | Только если последовательный порт не нужен |
| U0T (GPIO 1) | Последовательный TX: программирование и монитор порта | Только если последовательный порт не нужен |
| GPIO 0 | Тактирование камеры (XCLK) и режим загрузки | Нет; только замыкается на GND во время загрузки кода |
| GPIO 16 | На многих платах подключён к PSRAM | Нет |
| GPIO 2 | SD DATA0 | Если SD-карта не используется; пин конфигурации при старте (strapping) |
| GPIO 4 | SD DATA1 и вспышка | В 1-битном режиме SD или без SD |
| GPIO 12 | SD DATA2 | В 1-битном режиме SD или без SD; при старте должен быть LOW |
| GPIO 13 | SD DATA3 | В 1-битном режиме SD или без SD; самый безопасный свободный пин |
| GPIO 14 | SD CLK | Если SD-карта не используется |
| GPIO 15 | SD CMD | Если SD-карта не используется; пин конфигурации при старте (strapping) |
| GPIO 33 | Красный светодиод (не выведен на гребёнку) | Только светодиод; запись LOW включает его |
Как программировать ESP32-CAM? Два способа
На ESP32-CAM нет USB-UART-преобразователя, через который обычные платы ESP32 общаются с компьютером. Для загрузки кода есть два варианта: адаптер ESP32-CAM-MB, который вставляется снизу платы (небольшая базовая плата с чипом CH340 и разъёмом micro USB), или уже имеющийся USB-TTL-адаптер (FTDI, CH340, CP2102). Какой бы вариант ни был выбран, логика одна: если при старте GPIO 0 в LOW, ESP32 входит в режим загрузки и ждёт код; если в HIGH — запускает программу из флеш-памяти. Именно это делают кнопка IO0 на адаптере MB и провод IO0-GND, который добавляется при работе с USB-TTL-адаптером.

| USB-TTL-адаптер | ESP32-CAM | Примечания |
|---|---|---|
| GND | GND | Общая земля |
| 5V | 5V | Питает плату; выхода 3,3 V адаптера не хватает |
| TX | U0R (GPIO 3) | Перекрёстно: передатчик к приёмнику |
| RX | U0T (GPIO 1) | Перекрёстно: приёмник к передатчику |
| — | Между IO0 и GND | Только во время загрузки; короткий провод между двумя соседними пинами |
Если на адаптере есть перемычка выбора 3,3 V / 5 V, поставь её на 3,3 V, чтобы уровень линии TX подходил пинам ESP32. А вот питание на плату подавай с пина 5V адаптера. Выход 3,3 V у большинства адаптеров даёт лишь около 50–100 mA; как только ESP32-CAM включает Wi-Fi, это питание проседает, и плата перезагружается.
Настройки Arduino IDE: плата, схема разделов и PSRAM
- Открой в Arduino IDE «Менеджер плат» (Boards Manager) и установи пакет esp32 by Espressif Systems; подробно об этом — в руководстве Установка Arduino IDE.
- Выбери плату AI Thinker ESP32-CAM в Инструменты › Плата › esp32 (Tools › Board).
- Проверь, что в Partition Scheme (схема разделов) выбрано Huge APP (3MB No OTA/1MB SPIFFS): примеру с камерой нужно не меньше 3 МБ под программу.
- Подключи плату к адаптеру и выбери новый порт в Инструменты › Порт (COMx на Windows, /dev/cu.usbserial... или /dev/cu.wchusbserial... на macOS).
- Если порт вообще не появляется, установи драйвер CH340 или CP2102 и возьми USB-кабель с передачей данных.
| Настройка | Рекомендуемое значение | Почему? |
|---|---|---|
| Плата (Board) | AI Thinker ESP32-CAM | PSRAM, 4 МБ флеш-памяти и нужная схема разделов уже настроены |
| Partition Scheme | Huge APP (3MB No OTA/1MB SPIFFS) | Те самые 3 МБ под программу, которые нужны CameraWebServer |
| PSRAM | В этом описании платы всегда включена | С ESP32 Dev Module поставь PSRAM: Enabled; у ESP32 Wrover Module она уже включена |
| CPU Frequency | 240MHz (WiFi/BT) | Максимальная скорость для передачи изображения и Wi-Fi |
| Flash Mode / Flash Frequency | QIO / 80MHz | Если загрузка или запуск не проходят, попробуй DIO / 40MHz |
| Core Debug Level | None (Info при поиске неисправностей) | На уровне Info в монитор порта выводятся данные о камере и FPS |
| Upload Speed | 460800 (на этой плате не меняется) | Если загрузка постоянно обрывается, выбери ESP32 Wrover Module и попробуй 115200 |
Первая загрузка шаг за шагом
- Собери подключение: вставь плату в адаптер MB, совместив пины, или подключи USB-TTL-адаптер по таблице выше. С USB-TTL-адаптером добавь ещё и короткий провод между IO0 и GND.
- Переведи плату в режим загрузки: на адаптере MB зажми кнопку IO0, нажми и отпусти RST, затем отпусти IO0. С USB-TTL-адаптером просто нажми RST, когда провод IO0-GND на месте. Некоторые адаптеры MB со схемой автосброса загружают код вообще без нажатия кнопок.
- Нажми Загрузка в Arduino IDE. В выводе сначала появится Connecting..., а за ним — ход записи в процентах.
- Когда появится строка Hard resetting via RTS pin..., загрузка закончена. Если используется USB-TTL-адаптер, сейчас убери провод IO0-GND.
- Открой монитор порта на 115200 бод и нажми RST: новая программа запустится.
1// ESP32-CAM ilk yükleme testi / ESP32-CAM first upload test
2const int KIRMIZI_LED = 33; // arkadaki kırmızı LED, ters mantık / red LED on the back, inverted logic
3
4void setup() {
5 Serial.begin(115200);
6 pinMode(KIRMIZI_LED, OUTPUT);
7 delay(500);
8
9 // PSRAM kontrolü / PSRAM check
10 if (psramFound()) {
11 Serial.print("PSRAM bulundu / PSRAM found: ");
12 Serial.print(ESP.getPsramSize());
13 Serial.println(" bayt / bytes");
14 } else {
15 Serial.println("PSRAM yok / No PSRAM");
16 }
17}
18
19void loop() {
20 digitalWrite(KIRMIZI_LED, LOW); // LOW = yanar / LOW = on
21 delay(500);
22 digitalWrite(KIRMIZI_LED, HIGH); // HIGH = söner / HIGH = off
23 delay(500);
24}Если загрузка прошла, маленький красный светодиод на обороте платы мигает каждые полсекунды. У этого светодиода инверсная логика: запись LOW включает его, а HIGH выключает. В мониторе порта должно быть видно примерно 4 миллиона байт PSRAM; если там написано No PSRAM, проверь выбор платы, а если не помогает, возможно, на твоей плате нет чипа PSRAM. Этот короткий тест перед примером с камерой сразу показывает, в чём проблема — в загрузке или в камере.
Пример CameraWebServer: живая картинка в браузере
- Открой Файл › Примеры › ESP32 › Camera › CameraWebServer.
- Выбери модель камеры: в списке на вкладке board_config.h (новые версии) или в начале основного файла (старые версии) поставь // перед строкой CAMERA_MODEL_ESP_EYE и убери // перед строкой CAMERA_MODEL_AI_THINKER.
- Впиши имя и пароль своей Wi-Fi-сети 2,4 GHz в строки ssid и password.
- Переведи плату в режим загрузки и загрузи скетч; затем убери соединение IO0 и нажми RST.
- В мониторе порта появится строка вроде Camera Ready! Use 'http://192.168.1.45' to connect; открой этот адрес в браузере телефона или компьютера в той же сети.
- Запусти живую картинку кнопкой Start Stream на странице или сделай одно фото кнопкой Get Still.
1// board_config.h (eski sürümlerde CameraWebServer.ino) / (CameraWebServer.ino in older versions)
2//#define CAMERA_MODEL_ESP_EYE // Has PSRAM <- kapat / comment out
3#define CAMERA_MODEL_AI_THINKER // Has PSRAM <- aç / enable
4
5// CameraWebServer.ino
6const char *ssid = "AgAdi"; // Wi-Fi adı / Wi-Fi name
7const char *password = "Sifre123"; // Wi-Fi şifresi / Wi-Fi passwordИнтерфейс работает на двух отдельных серверах: страница настроек и адрес /capture, который возвращает одно фото, находятся на порту 80, а видеопоток — по адресу /stream на порту 81 (например, http://192.168.1.45:81/stream). Этот адрес потока можно добавить на свою веб-страницу или в систему умного дома. В меню слева меняются разрешение, качество JPEG, яркость, контраст и баланс белого, а если картинка перевёрнута, помогут переключатели V-Flip и H-Mirror; в новых версиях есть ещё ползунок LED Intensity для вспышки. Обычно плата обслуживает только одного зрителя потока за раз, поэтому поток, открытый во второй вкладке, может зависнуть. Если страница вообще не открывается, проверь, что телефон и плата в одной сети; при проблемах с подключением загляни в статью ESP32 не подключается к Wi-Fi.
Таблица разрешений и FPS для ESP32-CAM
На бумаге сенсор OV2640 выдаёт 15 кадров в секунду при 1600×1200, 30 при 800×600 и 60 в размере CIF. На практике частоту кадров в основном определяют Wi-Fi-канал и размер JPEG-кадра: с ростом разрешения и качества каждый кадр становится больше и медленнее проходит через сеть. Ниже — примерные диапазоны с CameraWebServer при хорошем сигнале Wi-Fi и качестве JPEG 10–12. Чтобы измерить свою плату, поставь Core Debug Level на Info: во время трансляции монитор порта печатает для каждого кадра строку вроде MJPG: ... (x fps).
| Разрешение | Пиксели | Примерный FPS (поток по Wi-Fi) | Для чего подходит |
|---|---|---|---|
| QQVGA | 160×120 | 25–30 | Обнаружение движения, очень слабые сети |
| QVGA | 320×240 | 20–30 | Роботы-машинки, плавное живое видео |
| CIF | 400×296 | 15–25 | Плавный просмотр на маленьких экранах |
| VGA | 640×480 | 10–20 | Живой просмотр общего назначения |
| SVGA | 800×600 | 8–15 | Более чёткий просмотр; самый большой размер без PSRAM |
| XGA | 1024×768 | 5–10 | Детальные изображения |
| HD | 1280×720 | 4–8 | Широкий кадр (16:9) |
| SXGA | 1280×1024 | 3–6 | Фото |
| UXGA | 1600×1200 | 2–5 | Фото в максимальном разрешении |
В своём коде разрешение, качество и ориентацию можно менять через объект сенсора после успешного запуска камеры. Качество JPEG задаётся числом от 0 до 63, и чем меньше число, тем выше качество; ниже 10 кадры становятся слишком большими, и изображения могут обрываться на середине.
1// esp_camera_init() başarılı olduktan sonra / after esp_camera_init() succeeds
2sensor_t *s = esp_camera_sensor_get();
3s->set_framesize(s, FRAMESIZE_VGA); // 640x480 çözünürlük / resolution
4s->set_quality(s, 12); // 0-63: küçük = daha kaliteli, 10 altı önerilmez / lower = better, below 10 not advised
5s->set_vflip(s, 1); // görüntüyü dikey çevir / flip vertically
6s->set_hmirror(s, 1); // yatay ayna / mirror horizontally
7s->set_brightness(s, 1); // parlaklık -2..2 / brightness -2..2Почему настройка PSRAM так важна для ESP32-CAM?
Встроенная память ESP32 — 520 КБ, и большую её часть занимает стек Wi-Fi. А один JPEG-кадр 1600×1200 в зависимости от сцены и качества может весить 100–250 КБ. Поэтому драйвер камеры размещает буферы кадров в PSRAM. CameraWebServer проверяет наличие PSRAM функцией psramFound(): если она есть, пример стартует с максимальным разрешением и двумя буферами кадров; если нет — ограничивает разрешение до SVGA (800×600) и держит один буфер во встроенной памяти.
Если запросить высокое разрешение при выключенной PSRAM, монитор порта покажет frame buffer malloc failed, а за ним Camera init failed with error 0xffffffff. Решение — выбрать плату AI Thinker ESP32-CAM (с ESP32 Dev Module поставить Инструменты › PSRAM: Enabled) или снизить разрешение и уменьшить число буферов кадров до 1. На некоторых дешёвых клонах чипа PSRAM может не быть вовсе; строка PSRAM в первом тестовом скетче сразу это покажет.
Ошибка Camera init failed with error 0x105 и другие ошибки камеры
Большинство ошибок камеры сводятся к одной из трёх причин: в коде выбрана не та модель камеры, шлейф плохо сидит в разъёме или питания не хватает. Код ошибки в мониторе порта быстро сужает круг причин:
| Сообщение в мониторе порта | Что означает | Решение |
|---|---|---|
| Camera probe failed with error 0x105(ESP_ERR_NOT_FOUND) (камера не найдена) | ESP32 не нашла камеру на шине SCCB | Проверь, что выбрана CAMERA_MODEL_AI_THINKER, переподключи шлейф, питай плату от 5 V / 2 A |
| Detected camera not supported и 0x106 | Та же ситуация в новых версиях драйвера: камера не найдена или не распознана | Те же шаги, что и для 0x105; если не помогает, замени модуль камеры |
| frame buffer malloc failed и 0xffffffff | Не удалось выделить память под буфер кадра | Включи PSRAM, снизь разрешение, поставь fb_count в 1 |
| cam_hal: EV-VSYNC-OVF или FB-OVF | Новый кадр пришёл раньше, чем обработан предыдущий, и кадр пропущен | Изредка — не страшно; если часто, снизь разрешение и улучши сигнал Wi-Fi |
| NO-SOI (нет маркера начала JPEG) | Повреждённый или неполный JPEG-кадр | Проверь питание и шлейф, поставь xclk_freq_hz в 10000000 |
| Половины изображения нет, оно зелёное или в полосах | Кадр не поместился в буфер, или питание шумит | Подними значение качества JPEG до 12 и выше, улучши питание |
Ошибка brownout и правильное питание (5 V / 2 A)
Если монитор порта показывает Brownout detector was triggered (сработал детектор просадки питания) и плата всё время перезагружается, напряжение питания ESP32 на мгновение упало ниже безопасного уровня. ESP32-CAM потребляет короткие, но сильные пики тока в момент включения Wi-Fi-передатчика и начала съёмки. Слабый USB-порт, тонкие и длинные перемычки или выход 3,3 V адаптера за этими пиками не успевают. Вот постоянные решения:
- Возьми источник питания на 5 V и не меньше 2 A и подключи его к пину 5V платы; стабилизатор на плате понизит напряжение до 3,3 V.
- Провода питания делай короткими и толстыми: макетные платы и длинные перемычки добавляют просадку напряжения.
- Поставь электролитический конденсатор на 470–1000 µF между пинами 5V и GND платы как можно ближе к ней (плюсовой вывод — к 5V).
- Если питаешь плату от компьютера, подключай её прямо к порту на задней стороне ПК, а не через USB-хаб.
- Для работы от батареи используй аккумулятор 18650 с повышающим модулем на 5 V; это гораздо стабильнее, чем связка батареек AA.

В интернете часто встречается строка WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0), которая отключает детектор просадки в коде. Перезагрузки она останавливает, но проблему не решает: напряжение продолжает проседать, и теперь плата может зависать, выдавать битые кадры или терять данные при записи во флеш-память. Используй её только для временного теста; полный список сообщений о перезагрузке — в руководстве ESP32: brownout и Guru Meditation. При оценке времени работы от батареи считай, что при непрерывной трансляции плата в среднем потребляет 180 mA: аккумулятор 18650 на 2600 mAh с повышающим преобразователем с КПД 85% даёт около 1600 mAh на стороне 5 V, то есть примерно 9 часов трансляции. Свои цифры можно посчитать в калькуляторе времени работы от батареи; учти, что даже в глубоком сне плата потребляет около 6 mA из-за стабилизатора и PSRAM.
Управление вспышкой (GPIO 4)
Яркий белый светодиод на лицевой стороне платы управляется через транзистор, подключённый к GPIO 4: пин только переключает транзистор, а большой ток светодиода идёт от линии питания. digitalWrite(4, HIGH) включает его, LOW — выключает. Светодиод очень яркий, и если он долго горит, греются и он, и плата; лучше зажигать вспышку всего на несколько сотен миллисекунд во время съёмки. GPIO 4 — это ещё и линия DATA1 microSD-карты, поэтому когда карта работает в 4-битном режиме, вспышка сама мигает при каждом чтении и записи. Чтобы этого не было, запускай SD-карту в 1-битном режиме (SD_MMC.begin("/sdcard", true)); на некоторых платах светодиод всё равно может еле заметно светиться.
Сохранение фото на microSD-карту с ESP32-CAM
Скетч ниже при каждом нажатии кнопки на GPIO 13 включает вспышку, делает фото 1600×1200 и сохраняет его на microSD-карту как foto1.jpg, foto2.jpg... Отформатируй microSD-карту в FAT32 на компьютере; хотя официальная документация упоминает карты до 4 ГБ, на практике карты FAT32 на 16–32 ГБ обычно работают нормально. Один вывод кнопки подключи к GPIO 13, другой — к GND; скетч включает встроенный подтягивающий резистор, так что дополнительный резистор не нужен. Как устроено подключение кнопки, читай в статье Как подключить кнопку к Arduino.
1#include "esp_camera.h"
2#include "FS.h"
3#include "SD_MMC.h"
4
5// AI-Thinker ESP32-CAM kamera pinleri / AI-Thinker ESP32-CAM camera pins
6#define PWDN_GPIO_NUM 32
7#define RESET_GPIO_NUM -1
8#define XCLK_GPIO_NUM 0
9#define SIOD_GPIO_NUM 26
10#define SIOC_GPIO_NUM 27
11#define Y9_GPIO_NUM 35
12#define Y8_GPIO_NUM 34
13#define Y7_GPIO_NUM 39
14#define Y6_GPIO_NUM 36
15#define Y5_GPIO_NUM 21
16#define Y4_GPIO_NUM 19
17#define Y3_GPIO_NUM 18
18#define Y2_GPIO_NUM 5
19#define VSYNC_GPIO_NUM 25
20#define HREF_GPIO_NUM 23
21#define PCLK_GPIO_NUM 22
22
23#define FLAS_LED 4 // beyaz flaş LED'i / white flash LED
24#define BUTON 13 // butonun diğer ucu GND'de / other button leg to GND
25
26int fotoNo = 1; // sıradaki dosya numarası / next file number
27bool hazir = false; // kamera ve SD hazır mı? / are camera and SD ready?
28
29bool kameraBaslat() {
30 camera_config_t config = {};
31 config.ledc_channel = LEDC_CHANNEL_0;
32 config.ledc_timer = LEDC_TIMER_0;
33 config.pin_d0 = Y2_GPIO_NUM;
34 config.pin_d1 = Y3_GPIO_NUM;
35 config.pin_d2 = Y4_GPIO_NUM;
36 config.pin_d3 = Y5_GPIO_NUM;
37 config.pin_d4 = Y6_GPIO_NUM;
38 config.pin_d5 = Y7_GPIO_NUM;
39 config.pin_d6 = Y8_GPIO_NUM;
40 config.pin_d7 = Y9_GPIO_NUM;
41 config.pin_xclk = XCLK_GPIO_NUM;
42 config.pin_pclk = PCLK_GPIO_NUM;
43 config.pin_vsync = VSYNC_GPIO_NUM;
44 config.pin_href = HREF_GPIO_NUM;
45 config.pin_sccb_sda = SIOD_GPIO_NUM;
46 config.pin_sccb_scl = SIOC_GPIO_NUM;
47 config.pin_pwdn = PWDN_GPIO_NUM;
48 config.pin_reset = RESET_GPIO_NUM;
49 config.xclk_freq_hz = 20000000; // 20 MHz kamera saati / 20 MHz camera clock
50 config.pixel_format = PIXFORMAT_JPEG;
51
52 if (psramFound()) {
53 config.frame_size = FRAMESIZE_UXGA; // 1600x1200
54 config.jpeg_quality = 10; // küçük = daha kaliteli / lower = better quality
55 config.fb_count = 2;
56 config.fb_location = CAMERA_FB_IN_PSRAM;
57 config.grab_mode = CAMERA_GRAB_LATEST;
58 } else {
59 config.frame_size = FRAMESIZE_SVGA; // PSRAM yoksa 800x600 / 800x600 without PSRAM
60 config.jpeg_quality = 12;
61 config.fb_count = 1;
62 config.fb_location = CAMERA_FB_IN_DRAM;
63 config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
64 }
65
66 esp_err_t err = esp_camera_init(&config);
67 if (err != ESP_OK) {
68 Serial.printf("Camera init failed 0x%x (%s)\n", err, esp_err_to_name(err));
69 return false;
70 }
71 return true;
72}
73
74void fotoCek() {
75 digitalWrite(FLAS_LED, HIGH); // flaşı yak / flash on
76 delay(150); // pozlama otursun / let exposure settle
77
78 camera_fb_t *fb = esp_camera_fb_get(); // eski kareyi at / discard the stale frame
79 if (fb) esp_camera_fb_return(fb);
80 fb = esp_camera_fb_get(); // asıl fotoğraf / the real photo
81 digitalWrite(FLAS_LED, LOW); // flaşı söndür / flash off
82
83 if (!fb) {
84 Serial.println("Kare alinamadi / Capture failed");
85 return;
86 }
87
88 String yol = "/foto" + String(fotoNo) + ".jpg";
89 File dosya = SD_MMC.open(yol, FILE_WRITE);
90 if (dosya) {
91 dosya.write(fb->buf, fb->len); // JPEG verisini yaz / write the JPEG data
92 dosya.close();
93 Serial.printf("Kaydedildi / Saved: %s (%u bayt / bytes)\n", yol.c_str(), (unsigned)fb->len);
94 fotoNo++;
95 } else {
96 Serial.println("Dosya acilamadi / Could not open file");
97 }
98 esp_camera_fb_return(fb); // tamponu geri ver / return the buffer
99}
100
101void setup() {
102 Serial.begin(115200);
103 pinMode(BUTON, INPUT_PULLUP);
104
105 if (!kameraBaslat()) return; // kamera yoksa dur / stop without a camera
106
107 // 1-bit mod: GPIO 4, 12 ve 13 boşta kalır / 1-bit mode keeps GPIO 4, 12 and 13 free
108 if (!SD_MMC.begin("/sdcard", true)) {
109 Serial.println("SD kart takilamadi / SD card mount failed");
110 return;
111 }
112 if (SD_MMC.cardType() == CARD_NONE) {
113 Serial.println("SD kart yok / No SD card");
114 return;
115 }
116
117 pinMode(FLAS_LED, OUTPUT);
118 digitalWrite(FLAS_LED, LOW);
119
120 // Var olan fotoğrafların üzerine yazma / don't overwrite existing photos
121 while (SD_MMC.exists("/foto" + String(fotoNo) + ".jpg")) fotoNo++;
122
123 hazir = true;
124 Serial.println("Hazir, butona bas / Ready, press the button");
125}
126
127void loop() {
128 if (!hazir) { // hata varsa bekle / wait if setup failed
129 delay(1000);
130 return;
131 }
132 if (digitalRead(BUTON) == LOW) {
133 delay(30); // buton sıçramasını (bounce) önle / debounce
134 if (digitalRead(BUTON) == LOW) {
135 fotoCek();
136 while (digitalRead(BUTON) == LOW) delay(10); // bırakılmasını bekle / wait for release
137 }
138 }
139}Скетч запускает SD-карту в 1-битном режиме, поэтому использует только GPIO 2, 14 и 15, а GPIO 4 остаётся для вспышки и GPIO 13 — для кнопки. Перед съёмкой один кадр захватывается и сразу возвращается: камера выдаёт кадры непрерывно, так что первый кадр в буфере мог быть снят ещё до включения вспышки, а автоэкспозиции нужна короткая пауза, чтобы подстроиться под новый свет. Номер файла определяется по файлам, которые уже лежат на карте, поэтому старые фото не перезаписываются даже после перезагрузки. Общие правила записи данных на SD-карту — в руководстве Модуль SD-карты.
MicroPython и новые платы с камерой
ESP32-CAM можно программировать и на MicroPython, но в официальной сборке MicroPython нет драйвера камеры; придётся записать прошивку от сообщества с добавленной поддержкой камеры. Поэтому для новичков путь через Arduino IDE гораздо проще. Если не хочется возиться с платой без USB-разъёма, присмотрись к платам с камерой на ESP32-S3, у которых есть USB и больше памяти (например, Seeed XIAO ESP32S3 Sense или ESP32-S3-EYE); эти платы тоже есть в списке моделей CameraWebServer.
Идеи проектов на ESP32-CAM
- Фото при движении: делай снимок, когда PIR-датчик замечает человека, и отправляй его на телефон; пошаговое руководство — в статье Фото с ESP32-CAM в Telegram.
- Таймлапс: пусть плата просыпается каждые 10 минут, делает фото, сохраняет его на SD-карту и снова уходит в глубокий сон; так можно наблюдать, как растёт растение или меняется погода.
- Камера дверного звонка: фотографируй порог при нажатии кнопки звонка и отправляй уведомление через Telegram-бота.
- Робот-машинка с видео: управляй машинкой, глядя на плавный живой поток QVGA на телефоне.
- Камера для питомца: смотри живой поток в домашней сети и при необходимости включай вспышку с веб-страницы.
- Своя панель управления: встрой живой поток в свою веб-страницу и добавь рядом показания датчиков и управление реле; путь показывает руководство ESP32 и WebSocket.
Частые ошибки и как их исправить
| Симптом | Вероятная причина | Решение |
|---|---|---|
| «Failed to connect to ESP32: No serial data received» (в старых версиях — «Timed out waiting for packet header»; нет ответа от платы) | Плата не в режиме загрузки, или перепутаны TX и RX | Соедини IO0 с GND или используй кнопку IO0, нажми RST; проверь, что TX идёт к U0R, а RX — к U0T |
| «Wrong boot mode detected (0x13)» (неверный режим загрузки) | При старте на GPIO 0 не было LOW | После соединения IO0-GND всегда нажимай RST |
| «waiting for download» в мониторе порта | IO0 всё ещё соединён с GND | Убери провод IO0 и нажми RST |
| Мусорные символы в мониторе порта | Неверная скорость | Поставь в мониторе порта 115200 бод |
| Платы нет в списке портов | Нет драйвера или кабель только для зарядки | Установи драйвер CH340 или CP2102, возьми кабель с передачей данных |
| Загрузка не проходит со вставленной SD-картой | GPIO 2 одновременно линия SD и пин конфигурации при старте | На время загрузки вынимай microSD-карту |
| Очень медленная или часто зависающая картинка | Слабый сигнал Wi-Fi или высокое разрешение | Перейди на VGA или QVGA, поставь плату ближе к роутеру, при необходимости используй внешнюю антенну |
| Вспышка постоянно слабо светится | SD-карта в 4-битном режиме или GPIO 4 висит в воздухе | Запускай SD-карту в 1-битном режиме, настрой GPIO 4 как OUTPUT и запиши LOW |
ESP32-CAM — самый простой способ собрать Wi-Fi-камеру на недорогой плате, и почти все трудности с ней связаны с подключением для программирования или с питанием. Когда эти две вещи в порядке, плата транслирует живое видео со своего веб-сервера, делает фото и сохраняет их на SD-карту. В приложении BlueGrays есть проекты на ESP32: подключение к Wi-Fi, веб-сервер, mDNS, запись данных на microSD и сигнализация движения с уведомлениями в Telegram — у каждого пошаговые схемы подключения и готовый код.
Частые вопросы
Как программировать ESP32-CAM?
У ESP32-CAM нет USB-разъёма, поэтому нужен адаптер ESP32-CAM-MB или USB-TTL-адаптер. В Arduino IDE выбирается плата AI Thinker ESP32-CAM, а плата переводится в режим загрузки нажатием RST, пока GPIO 0 соединён с GND (или пока зажата кнопка IO0 на MB). После загрузки убери соединение IO0 и снова нажми RST.
Можно ли программировать ESP32-CAM через Arduino Uno?
Да: если соединить пин RESET у Uno с GND, её USB-чип работает как мост USB-UART. В этом случае подключение прямое, а не перекрёстное: D0 (RX) у Uno идёт к U0R, D1 (TX) — к U0T, а IO0 по-прежнему замкнут на GND. Сигналы Uno — 5 V, и это работа ESP32 на пределе; для постоянного использования надёжнее адаптер MB или USB-TTL-адаптер на 3,3 V.
Какое напряжение нужно ESP32-CAM?
Рекомендуется питать плату от 5 V через пин 5V; стабилизатор на плате понизит напряжение до 3,3 V. Можно подать и 3,3 V на пин 3V3, но если источник не выдерживает пиков тока Wi-Fi, плата будет постоянно перезагружаться. Источник питания, способный выдать не меньше 2 A, предотвращает большинство ошибок brownout.
Как исправить ошибку Camera init failed на ESP32-CAM?
Код ошибки 0x105 или 0x106 означает, что камера вообще не найдена: сначала проверь, что в коде выбрана CAMERA_MODEL_AI_THINKER, затем что шлейф вставлен до конца, и питай плату от 5 V / 2 A. Если проблема остаётся, возможно, неисправен модуль камеры. Если видишь 0xffffffff вместе с frame buffer malloc failed, включи PSRAM или снизь разрешение.
Работает ли ESP32-CAM без интернета?
Да. Чтобы смотреть картинку, нужна только локальная сеть, а не интернет; ESP32-CAM может и сама создать Wi-Fi-сеть с помощью WiFi.softAP(), тогда она открывается в браузере по адресу 192.168.4.1. Её можно использовать и вовсе без сети — как камеру, которая только сохраняет фото на microSD-карту.
Может ли ESP32-CAM записывать видео?
Готовые примеры транслируют живое видео в MJPEG и делают отдельные фото; видеофайл напрямую они не записывают. Есть проекты от сообщества, которые пишут последовательные JPEG-кадры на microSD-карту и собирают из них файл AVI, но частота кадров ограничена даже на низких разрешениях. Микрофона на плате нет, так что и звук она записывать не может.
Что собрать после прочтения
Все проекты
Мигающий светодиод на ESP32
Учит базовой работе с выходами GPIO на ESP32. Эффект мигания получается включением и выключением светодиода с цифрового пина. Это ESP32-версия классического проекта мигания на Arduino UNO; базовые команды мигания в среде Arduino те же, но расположение пинов ESP32 и уровни GPIO 3,3 V отличаются от Arduino UNO.

Мигание встроенным светодиодом ESP32
Мигание встроенным синим светодиодом на ESP32 DevKit V1. Внешние компоненты не нужны! Первый проект, который стоит попробовать после покупки ESP32. Встроенный светодиод подключён к GPIO 2.

Подключение ESP32 к Wi-Fi в режиме STA (с экраном LCD)
В этом проекте ESP32 надёжно и устойчиво к сбоям подключается к домашней сети Wi-Fi в режиме станции (STA). SSID и пароль хранятся в отдельном файле secrets.h, чтобы не утекли в Git; настроено автоматическое переподключение, а уровень сигнала RSSI и IP-адрес выводятся на I2C LCD-экран. Встроенный светодиод служит индикатором состояния. Это менеджер подключения уровня реальных устройств.

Асинхронный веб-сервер на ESP32 (с выводом IP на LCD)
В этом проекте ESP32 превращается в асинхронный веб-сервер, которым можно управлять с телефона или компьютера в той же сети Wi-Fi. Благодаря библиотеке ESPAsyncWebServer сервер может обрабатывать несколько запросов одновременно (в отличие от классического WebServer.h, который блокируется на одном запросе). Открыв IP-адрес ESP32 в браузере, ты нажимаешь кнопки ON/OFF (маршруты /on и /off) и включаешь и выключаешь светодиод на GPIO 5.

mDNS на ESP32: доступ к устройству через bluegrays-esp.local (с экраном LCD)
В этом проекте к ESP32 добавляется служба mDNS (Multicast DNS), и к устройству можно обращаться по понятному имени вроде bluegrays-esp.local вместо IP-адреса. Даже если IP, выданный DHCP, меняется, устройство всегда доступно по одному имени. На устройстве также работает маленький веб-сервер, через который по адресу http://bluegrays-esp.local/ из браузера отправляются команды светодиоду. I2C LCD показывает имя хоста, IP-адрес и состояние светодиода.

Регистратор температуры на ESP32 (DHT22 + DS1307 RTC + microSD + OLED)
Собери на ESP32 регистратор температуры с отметками времени! Каждую минуту читай температуру и влажность с DHT22, бери реальное время из DS1307 RTC и записывай всё на карту microSD в формате CSV. OLED показывает текущую температуру (крупным шрифтом), влажность в процентах, время и счётчик записей. Файл /temp_log.csv на SD-карте открывается в Excel, Google Sheets или Python pandas — идеально для теплиц, комнат, лабораторий и хранения продуктов.

Сигнализация движения на ESP32 (PIR + зуммер + светодиод + Telegram)
Умная охранная сигнализация, которая при обнаружении движения PIR-датчиком включает зуммер и светодиод и одновременно сразу отправляет владельцу уведомление в Telegram. В ней есть 30-секундная пауза, ограничивающая частоту повторных тревог; этот механизм не проверяет срабатывания PIR и не устраняет ложные тревоги. Подходит для дома, гаража, склада или мастерской. С ESP32-CAM можно добавить уведомления с фото, а с обычной ESP32 DevKit V1 приходят текстовые.
Другие статьи
Приложение BlueGrays
Собери эту схему шаг за шагом в телефоне
Схема подключения, код и список деталей на одном экране. 200+ проектов на Arduino, ESP32 и Pico готовы к сборке.
Наведи камеру телефона
Наведи камеру на код — откроется магазин приложений на телефоне.
или открыть магазин

