ESP32-CAM: tutorial para programarla, ver vídeo y guardar fotos
Cómo programar la ESP32-CAM: pines AI-Thinker, carga con ESP32-CAM-MB o USB-TTL, CameraWebServer, PSRAM, errores 0x105 y brownout, flash y fotos en la SD.
La ESP32-CAM es una placa de cámara Wi-Fi económica que, pese a medir solo 27 × 40 mm, incluye un procesador ESP32, una cámara OV2640 de 2 megapíxeles, una ranura para tarjeta microSD y un LED de flash blanco. Por sí sola se conecta a la red de casa, transmite vídeo en directo al navegador, hace fotos y las guarda en la tarjeta SD o las envía por internet. Es la placa más popular para cámaras de vigilancia, cámaras de timbre, time-lapses del crecimiento de una planta y coches robot con vídeo, pero como no tiene conector USB, la puesta en marcha es algo distinta a la de las placas ESP32 a las que quizá estés acostumbrado.
En esta guía conocerás los pines de la ESP32-CAM de AI-Thinker, cómo programarla con el adaptador ESP32-CAM-MB o con un convertidor USB-TTL (incluida la conexión IO0-GND), cómo ver la imagen en directo en el navegador con el ejemplo CameraWebServer y qué ajustes de PSRAM y de particiones debes usar. Después verás las causas de los errores más habituales, Camera init failed with error 0x105 y brownout, controlarás el LED de flash y crearás un sketch que guarda una foto en la microSD al pulsar un botón.

¿Qué es la ESP32-CAM y cómo funciona?
El corazón de la placa es el módulo ESP32-S, que lleva el chip ESP32 de doble núcleo con Wi-Fi y Bluetooth. La cámara se conecta a un conector de 24 pines de la placa mediante un cable plano fino (FPC). El ESP32 envía a la cámara una señal de reloj de 20 MHz (XCLK) por el GPIO 0 y la configura a través del bus SCCB, parecido al I2C, en los GPIO 26 y 27. Como el sensor OV2640 puede comprimir la imagen en JPEG por sí mismo, al ESP32 le llegan pequeñas imágenes JPEG en lugar de píxeles en bruto. Estas imágenes pasan por un bus de datos paralelo de 8 bits a los 4 MB de PSRAM de la placa, y el Wi-Fi las lleva al navegador o a un servidor.
| Característica | Valor |
|---|---|
| Procesador | ESP32 (módulo ESP32-S), doble núcleo, hasta 240 MHz |
| Inalámbrico | Wi-Fi 802.11 b/g/n (solo 2,4 GHz), Bluetooth 4.2 y BLE |
| Memoria | 520 KB de SRAM interna + 4 MB de PSRAM, 4 MB de flash |
| Cámara | OV2640, 2 MP, hasta 1600×1200 (UXGA), salida JPEG |
| Almacenamiento | Ranura microSD (hasta 4 GB según la documentación oficial) |
| Luz | LED de flash blanco (GPIO 4), LED rojo de estado en la parte trasera (GPIO 33) |
| Alimentación | 5 V en el pin 5V (recomendado) o 3,3 V en el pin 3V3 |
| Consumo (a 5 V) | Unos 180 mA con el flash apagado y unos 310 mA con el flash al máximo; los picos de Wi-Fi son mayores |
| Tamaño | 27 × 40,5 × 4,5 mm |
Pines de la ESP32-CAM de AI-Thinker: ¿cuáles están libres?
En los dos bordes de la placa hay 16 pines, pero solo unos pocos están realmente libres: la cámara usa por sí sola 15 GPIO y la ranura microSD comparte otros seis. La tabla resume los pines del borde y cuándo puedes usarlos. También puedes consultar las características generales de los pines del ESP32 en la herramienta Pinout.
| Pin | Función | ¿Uso libre? |
|---|---|---|
| 5V | Entrada de alimentación (recomendada) | - |
| 3V3 | Entrada de alimentación de 3,3 V | - |
| GND (3 pines) | Tierra | - |
| VCC | Salida de alimentación (3,3 V por defecto) | No la uses para alimentar la placa |
| U0R (GPIO 3) | RX serie: programación y Monitor Serie | Solo si no necesitas el puerto serie |
| U0T (GPIO 1) | TX serie: programación y Monitor Serie | Solo si no necesitas el puerto serie |
| GPIO 0 | Reloj de la cámara (XCLK) y modo de arranque | No; solo se conecta a GND al subir el código |
| GPIO 16 | Conectado a la PSRAM en muchas placas | No |
| GPIO 2 | SD DATA0 | Si no usas la SD; pin de arranque (strapping) |
| GPIO 4 | SD DATA1 y LED de flash | Con la SD en modo de 1 bit o sin SD |
| GPIO 12 | SD DATA2 | Con la SD en modo de 1 bit o sin SD; debe estar en LOW al arrancar |
| GPIO 13 | SD DATA3 | Con la SD en modo de 1 bit o sin SD; el pin libre más seguro |
| GPIO 14 | SD CLK | Si no usas la SD |
| GPIO 15 | SD CMD | Si no usas la SD; pin de arranque (strapping) |
| GPIO 33 | LED rojo (no está en el borde) | Solo el LED; se enciende con LOW |
¿Cómo se programa la ESP32-CAM? Dos opciones
El chip USB-serie que permite a las placas ESP32 normales hablar con el ordenador no está en la ESP32-CAM. Para subir el código tienes dos opciones: el adaptador ESP32-CAM-MB, que se coloca debajo de la placa (una pequeña placa base con chip CH340 y conector micro USB), o un convertidor USB-TTL que ya tengas (FTDI, CH340, CP2102). Elijas el que elijas, la lógica es la misma: si el GPIO 0 está en LOW al arrancar, el ESP32 entra en modo de descarga (download mode) y espera el código; si está en HIGH, ejecuta el programa de la flash. El botón IO0 del adaptador MB y el cable IO0-GND que pones con el USB-TTL hacen exactamente eso.

| Convertidor USB-TTL | ESP32-CAM | Nota |
|---|---|---|
| GND | GND | Tierra común |
| 5V | 5V | Alimenta la placa; la salida de 3,3 V del convertidor no es suficiente |
| TX | U0R (GPIO 3) | Cruzado: transmisor a receptor |
| RX | U0T (GPIO 1) | Cruzado: receptor a transmisor |
| - | Entre IO0 y GND | Solo al subir el código; un cable corto entre los dos pines contiguos |
Si tu convertidor tiene un jumper para elegir entre 3,3 V y 5 V, ponlo en 3,3 V para que la línea TX tenga un nivel adecuado para los pines del ESP32. Eso sí, alimenta la placa desde el pin 5V del convertidor. La salida de 3,3 V de la mayoría de los convertidores solo da unos 50–100 mA; en cuanto la ESP32-CAM activa el Wi-Fi, esa alimentación cae y la placa se reinicia.
Ajustes del Arduino IDE: placa, esquema de particiones y PSRAM
- Abre el Gestor de placas del Arduino IDE e instala el paquete esp32 by Espressif Systems; lo explicamos en detalle en instalar el Arduino IDE.
- Elige la placa AI Thinker ESP32-CAM en Herramientas > Placa > esp32.
- Comprueba que Partition Scheme esté en Huge APP (3MB No OTA/1MB SPIFFS); el ejemplo de la cámara necesita al menos 3 MB para la aplicación.
- Conecta la placa al adaptador o al convertidor y elige el puerto nuevo en Herramientas > Puerto (COMx en Windows, /dev/cu.usbserial... o /dev/cu.wchusbserial... en macOS).
- Si no aparece ningún puerto, instala el driver del CH340 o del CP2102 y usa un cable USB que transmita datos.
| Ajuste | Valor recomendado | ¿Por qué? |
|---|---|---|
| Placa | AI Thinker ESP32-CAM | Trae ya configurados la PSRAM, los 4 MB de flash y el esquema de particiones |
| Partition Scheme | Huge APP (3MB No OTA/1MB SPIFFS) | Los 3 MB de aplicación que necesita CameraWebServer |
| PSRAM | Siempre activa en esta placa | Con ESP32 Dev Module elige PSRAM: Enabled; en ESP32 Wrover Module ya está activa |
| CPU Frequency | 240MHz (WiFi/BT) | Máxima velocidad para la imagen y el Wi-Fi |
| Flash Mode / Flash Frequency | QIO / 80MHz | Si falla la carga o el arranque, prueba DIO / 40MHz |
| Core Debug Level | None (Info para buscar fallos) | En Info, el Monitor Serie muestra datos de la cámara y los FPS |
| Upload Speed | 460800 (fija en esta placa) | Si la carga se corta a menudo, elige ESP32 Wrover Module y prueba 115200 |
La primera carga, paso a paso
- Haz el cableado: coloca la placa sobre el adaptador MB con los pines alineados o conecta el convertidor USB-TTL según la tabla anterior. Si usas el USB-TTL, pon también el cable corto entre IO0 y GND.
- Pon la placa en modo de descarga: en el adaptador MB, mantén pulsado el botón IO0, pulsa y suelta RST y luego suelta IO0. Con el USB-TTL basta con pulsar RST mientras el cable IO0-GND está puesto. Algunos adaptadores MB con circuito de reinicio automático suben el código sin pulsar nada.
- Haz clic en Subir en el Arduino IDE. En la salida aparece primero Connecting... y luego el progreso de escritura en porcentaje.
- Cuando aparezca la línea Hard resetting via RTS pin..., la carga habrá terminado. Si usas el USB-TTL, quita ahora el cable IO0-GND.
- Abre el Monitor Serie a 115200 baudios y pulsa RST; el nuevo programa empieza a funcionar.
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}Si la carga ha funcionado, el pequeño LED rojo de la parte trasera parpadea cada medio segundo. Este LED funciona con lógica invertida: se enciende con LOW y se apaga con HIGH. En el Monitor Serie deberías ver unos 4 millones de bytes de PSRAM; si pone No PSRAM, revisa la placa elegida y, si no se arregla, puede que tu placa no tenga chip de PSRAM. Hacer esta prueba corta antes del ejemplo de la cámara te dice enseguida si el problema está en la carga o en la cámara.
El ejemplo CameraWebServer: imagen en directo en el navegador
- Abre Archivo > Ejemplos > ESP32 > Camera > CameraWebServer.
- Elige el modelo de cámara: en la lista de la pestaña board_config.h (versiones nuevas) o al principio del archivo principal (versiones antiguas), añade // delante de la línea CAMERA_MODEL_ESP_EYE y quita las // de delante de CAMERA_MODEL_AI_THINKER.
- Escribe en las líneas ssid y password el nombre y la contraseña de tu red Wi-Fi de 2,4 GHz.
- Pon la placa en modo de descarga y sube el código; después quita la conexión de IO0 y pulsa RST.
- En el Monitor Serie verás una línea como Camera Ready! Use 'http://192.168.1.45' to connect; abre esa dirección en el navegador de un móvil o un ordenador conectado a la misma red.
- Inicia la imagen en directo con el botón Start Stream o haz una sola foto con 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 passwordLa interfaz funciona con dos servidores distintos: la página de ajustes y la dirección /capture, que devuelve una sola foto, están en el puerto 80, mientras que el vídeo en directo está en /stream en el puerto 81 (p. ej. http://192.168.1.45:81/stream). Puedes añadir esta dirección del stream a tu propia página web o a un programa de domótica. En el menú de la izquierda cambias la resolución, la calidad JPEG, el brillo, el contraste y el balance de blancos, y si la imagen sale al revés, usa los interruptores V-Flip y H-Mirror; las versiones nuevas tienen además un control deslizante LED Intensity para el flash. La placa suele atender a un solo espectador del vídeo a la vez, y un stream abierto en una segunda pestaña puede congelarse. Si la página no abre, comprueba que el móvil y la placa estén en la misma red; para problemas de conexión, mira el ESP32 no se conecta al Wi-Fi.
Tabla de resolución y FPS de la ESP32-CAM
Sobre el papel, el sensor OV2640 da 15 fotogramas por segundo a 1600×1200, 30 a 800×600 y 60 en tamaño CIF. En la práctica, la velocidad la marcan sobre todo la conexión Wi-Fi y el tamaño de cada imagen JPEG: al subir la resolución y la calidad, cada fotograma pesa más y tarda más en cruzar la red. Los valores de abajo son rangos aproximados con CameraWebServer, buena señal Wi-Fi y calidad JPEG de 10–12. Para medir tu propia placa, pon Core Debug Level en Info; durante el stream, el Monitor Serie escribe para cada fotograma una línea como MJPG: ... (x fps).
| Resolución | Píxeles | FPS aprox. (stream Wi-Fi) | Ideal para |
|---|---|---|---|
| QQVGA | 160×120 | 25–30 | Detección de movimiento, redes muy débiles |
| QVGA | 320×240 | 20–30 | Coche robot, vídeo en directo fluido |
| CIF | 400×296 | 15–25 | Vista fluida en pantallas pequeñas |
| VGA | 640×480 | 10–20 | Vídeo en directo de uso general |
| SVGA | 800×600 | 8–15 | Imagen más nítida; el tamaño máximo sin PSRAM |
| XGA | 1024×768 | 5–10 | Imágenes con más detalle |
| HD | 1280×720 | 4–8 | Encuadre panorámico (16:9) |
| SXGA | 1280×1024 | 3–6 | Fotos |
| UXGA | 1600×1200 | 2–5 | Fotos a la máxima resolución |
En tu propio código puedes cambiar la resolución, la calidad y la orientación de la imagen a través del objeto del sensor, una vez que la cámara se ha iniciado correctamente. La calidad JPEG es un número de 0 a 63, y un número más bajo significa más calidad; bajar de 10 hace que los fotogramas pesen más y puede dar imágenes a medias.
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¿Por qué es tan importante la PSRAM en la ESP32-CAM?
La memoria interna del ESP32 es de 520 KB, y buena parte la usa la pila Wi-Fi. En cambio, una sola imagen JPEG de 1600×1200 puede ocupar entre 100 y 250 KB según la escena y la calidad. Por eso el driver de la cámara coloca sus búferes de imagen (frame buffer) en la PSRAM. CameraWebServer comprueba con la función psramFound() si hay PSRAM: si la hay, empieza con la resolución máxima y dos búferes; si no, limita la resolución a SVGA (800×600) y deja un único búfer en la memoria interna.
Si pides una resolución alta sin la PSRAM activada, el Monitor Serie muestra frame buffer malloc failed y luego Camera init failed with error 0xffffffff. La solución es elegir AI Thinker ESP32-CAM como placa (con ESP32 Dev Module, pon Herramientas > PSRAM: Enabled) o bajar la resolución y dejar un solo búfer. Algunos clones baratos pueden no llevar chip de PSRAM; la línea de PSRAM del primer sketch de prueba lo revela al instante.
Camera init failed with error 0x105 y otros errores de la cámara
La mayoría de los errores de la cámara tienen una de tres causas: un modelo de cámara equivocado en el código, un cable plano mal encajado en el conector o una alimentación insuficiente. Leer el código de error del Monitor Serie acota la causa rápidamente:
| Mensaje del Monitor Serie | Significado | Solución |
|---|---|---|
| Camera probe failed with error 0x105(ESP_ERR_NOT_FOUND) | El ESP32 no encontró ninguna cámara en el bus SCCB | Comprueba que esté elegido CAMERA_MODEL_AI_THINKER, vuelve a encajar el cable plano, alimenta con 5 V / 2 A |
| Detected camera not supported y 0x106 | La misma situación en versiones nuevas del driver: cámara no encontrada o no reconocida | Los mismos pasos que con 0x105; si sigue, cambia el módulo de cámara |
| frame buffer malloc failed y 0xffffffff | No se pudo reservar memoria para el búfer de imagen | Activa la PSRAM, baja la resolución, pon fb_count a 1 |
| cam_hal: EV-VSYNC-OVF o FB-OVF | Llegó un fotograma nuevo antes de procesar el anterior y se descartó uno | Inofensivo si aparece de vez en cuando; si es frecuente, baja la resolución y mejora la señal Wi-Fi |
| NO-SOI (JPEG start marker missing) | Fotograma JPEG dañado o incompleto | Revisa la alimentación y el cable plano, pon xclk_freq_hz a 10000000 |
| Imagen a medias, verde o con rayas | El fotograma no cupo en el búfer o la alimentación tiene ruido | Sube el valor de calidad JPEG a 12 o más, mejora la alimentación |
Error de brownout y la alimentación correcta (5 V / 2 A)
Si el Monitor Serie muestra Brownout detector was triggered y la placa se reinicia sin parar, la tensión de alimentación del ESP32 ha caído por un instante por debajo de un nivel seguro. La ESP32-CAM consume picos de corriente breves pero altos en cuanto activa el transmisor Wi-Fi y la cámara empieza a capturar. Un puerto USB débil, cables jumper finos y largos o la salida de 3,3 V del convertidor no pueden con esos picos. Estas son las soluciones definitivas:
- Usa una fuente de alimentación de 5 V y al menos 2 A y conéctala al pin 5V de la placa; el regulador de la placa la baja a 3,3 V.
- Usa cables de alimentación cortos y gruesos; la protoboard y los jumpers largos aumentan la caída de tensión.
- Añade un condensador electrolítico de 470–1000 µF entre los pines 5V y GND, lo más cerca posible de la placa (patilla positiva a 5V).
- Si la alimentas desde el ordenador, conéctala directamente a un puerto trasero en lugar de a un hub USB.
- Para funcionar con batería, usa una celda 18650 con un módulo elevador (boost) de 5 V; es mucho más estable que varias pilas AA en serie.

En internet verás a menudo la línea WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0), que desactiva el detector de brownout por código. Detiene los reinicios, pero no resuelve el problema: la tensión sigue cayendo y ahora la placa puede bloquearse, generar imágenes dañadas o perder datos al escribir en la flash. Úsala solo para una prueba temporal; todos los mensajes de reinicio están explicados en ESP32 brownout y Guru Meditation. Para calcular la autonomía, cuenta con que la placa consume de media 180 mA transmitiendo sin parar: una 18650 de 2600 mAh con un elevador del 85 % de rendimiento da unos 1600 mAh en el lado de 5 V, es decir, unas 9 horas de vídeo. Calcula tus propios valores con la calculadora de duración de batería, y recuerda que incluso en deep sleep la placa consume unos 6 mA por el regulador y la PSRAM.
Controlar el LED de flash (GPIO 4)
El LED blanco y brillante de la parte delantera se controla mediante un transistor conectado al GPIO 4: el pin solo conmuta el transistor y la corriente alta del LED sale de la alimentación. Con digitalWrite(4, HIGH) se enciende y con LOW se apaga. El LED es muy potente y, si se queda encendido mucho tiempo, se calientan tanto él como la placa; lo mejor es encender el flash solo unos cientos de milisegundos al hacer la foto. El GPIO 4 es además la línea DATA1 de la microSD, así que con la tarjeta en modo de 4 bits el flash parpadea solo en cada lectura y escritura. Para evitarlo, inicia la SD en modo de 1 bit (SD_MMC.begin("/sdcard", true)); en algunas placas el LED puede seguir brillando muy levemente.
Guardar fotos en la microSD con la ESP32-CAM
El siguiente sketch enciende el flash, hace una foto a 1600×1200 y la guarda en la microSD como foto1.jpg, foto2.jpg... cada vez que pulsas un botón conectado al GPIO 13. Formatea la tarjeta en el ordenador como FAT32; aunque la documentación oficial habla de tarjetas de hasta 4 GB, en la práctica las de 16–32 GB en FAT32 suelen funcionar sin problemas. Conecta una patilla del pulsador al GPIO 13 y la otra a GND; el sketch activa la resistencia pull-up interna, así que no hace falta ninguna resistencia extra. Para entender cómo se conecta un pulsador, mira cómo conectar un botón a 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}Como el sketch inicia la SD en modo de 1 bit, solo usa los GPIO 2, 14 y 15, y quedan libres el GPIO 4 para el flash y el GPIO 13 para el botón. Antes de la foto se toma un fotograma y se devuelve enseguida: la cámara genera imágenes sin parar, así que el primer fotograma del búfer puede ser de antes de encender el flash, y la exposición automática necesita una breve pausa para adaptarse a la nueva luz. El número de archivo se calcula mirando los archivos que ya hay en la tarjeta, así que las fotos antiguas no se sobrescriben aunque la placa se reinicie. Para las reglas generales de registro de datos en SD, echa un vistazo a el módulo de tarjeta SD.
MicroPython y placas de cámara más nuevas
También puedes programar la ESP32-CAM con MicroPython, pero la versión oficial de MicroPython no incluye driver de cámara; tienes que cargar un firmware de la comunidad que añada esa función. Por eso, para empezar, el camino del Arduino IDE es mucho más sencillo. Si prefieres no pelearte con una placa sin USB, mira también las placas de cámara basadas en el ESP32-S3, con USB y más memoria (p. ej. Seeed XIAO ESP32S3 Sense o ESP32-S3-EYE); también aparecen en la lista de modelos de CameraWebServer.
Ideas de proyectos con la ESP32-CAM
- Foto al detectar movimiento: haz una foto cuando un sensor PIR detecte a alguien y envíala al móvil; la guía paso a paso está en fotos de la ESP32-CAM a Telegram.
- Time-lapse: que la placa se despierte cada 10 minutos, haga una foto, la guarde en la SD y vuelva al deep sleep; observa cómo crece una planta o cómo cambia el tiempo.
- Cámara para el timbre: fotografía la puerta cuando alguien llame y envía un aviso con un bot de Telegram.
- Coche robot con vídeo: conduce el coche mientras ves en el móvil un vídeo fluido en QVGA.
- Cámara para mascotas: mira el vídeo en directo en la red de casa y enciende el flash desde la página web cuando haga falta.
- Tu propio panel de control: inserta el vídeo en tu propia página web y añade junto a él interruptores de relé y lecturas de sensores; la guía ESP32 WebSocket te enseña cómo.
Errores frecuentes y cómo solucionarlos
| Síntoma | Causa probable | Solución |
|---|---|---|
| Failed to connect to ESP32: No serial data received (Timed out waiting for packet header en versiones antiguas) | La placa no está en modo de descarga, o TX y RX están mal | Conecta IO0 a GND o usa el botón IO0 y pulsa RST; comprueba que TX vaya a U0R y RX a U0T |
| Wrong boot mode detected (0x13) | El GPIO 0 no estaba en LOW al arrancar | Pulsa siempre RST después de hacer la conexión IO0-GND |
| waiting for download en el Monitor Serie | El IO0 sigue conectado a GND | Quita el cable de IO0 y pulsa RST |
| Caracteres extraños en el Monitor Serie | Velocidad en baudios incorrecta | Pon el Monitor Serie a 115200 baudios |
| La placa no aparece en la lista de puertos | Falta el driver o el cable solo sirve para cargar | Instala el driver del CH340 o del CP2102 y usa un cable de datos |
| La carga falla con la tarjeta SD puesta | El GPIO 2 es a la vez línea de la SD y pin de arranque | Quita la microSD mientras subes el código |
| Imagen muy lenta o que se congela a menudo | Señal Wi-Fi débil o resolución alta | Baja a VGA o QVGA, acerca la placa al router y usa una antena externa si hace falta |
| El flash brilla débilmente todo el tiempo | SD en modo de 4 bits o GPIO 4 al aire | Inicia la SD en modo de 1 bit y pon el GPIO 4 como OUTPUT en LOW |
La ESP32-CAM es la forma más fácil de montar una cámara Wi-Fi con una placa económica, y casi todas las dificultades vienen de la conexión de programación o de la alimentación. Cuando resuelves esos dos puntos, la placa emite vídeo en directo desde su propio servidor web, hace fotos y las guarda en la SD. En la app BlueGrays encontrarás proyectos con ESP32 como la conexión Wi-Fi, un servidor web, mDNS, registro de datos en microSD y una alarma de movimiento con avisos por Telegram, cada uno con su esquema de circuito paso a paso y su código listo para usar.
Preguntas frecuentes
¿Cómo se programa la ESP32-CAM?
Como la ESP32-CAM no tiene conector USB, necesitas un adaptador ESP32-CAM-MB o un convertidor USB-TTL. En el Arduino IDE eliges la placa AI Thinker ESP32-CAM y pones la placa en modo de descarga pulsando RST mientras el GPIO 0 está conectado a GND (o mientras mantienes pulsado el botón IO0 del MB). Al terminar la carga, quitas la conexión de IO0 y vuelves a pulsar RST.
¿Se puede programar la ESP32-CAM con un Arduino Uno?
Sí; si conectas el pin RESET del Uno a GND, su chip USB funciona como un puente USB-serie. En ese caso la conexión es directa, no cruzada: el D0 (RX) del Uno va a U0R, el D1 (TX) va a U0T y el IO0 sigue conectado a GND. Como las señales del Uno son de 5 V, esto lleva al ESP32 al límite; para un uso continuado es más seguro un adaptador MB o un convertidor USB-TTL de 3,3 V.
¿Con cuántos voltios funciona la ESP32-CAM?
Lo recomendable es alimentarla con 5 V por el pin 5V; el regulador de la placa los baja a 3,3 V. También puedes darle 3,3 V por el pin 3V3, pero si la fuente no aguanta los picos de corriente del Wi-Fi, la placa se reiniciará una y otra vez. Una fuente que dé al menos 2 A evita la mayoría de los errores de brownout.
¿Cómo se soluciona el error Camera init failed de la ESP32-CAM?
Los códigos 0x105 o 0x106 indican que no se encontró ninguna cámara: primero comprueba que en el código esté elegido CAMERA_MODEL_AI_THINKER, luego que el cable plano esté bien encajado, y alimenta la placa con 5 V / 2 A. Si el problema sigue, el módulo de cámara puede estar averiado. Si ves 0xffffffff junto con frame buffer malloc failed, activa la PSRAM o baja la resolución.
¿Funciona la ESP32-CAM sin internet?
Sí. Para ver la imagen solo necesitas una red local, no internet; la ESP32-CAM también puede crear su propia red Wi-Fi con WiFi.softAP() y entonces se abre en el navegador en la dirección 192.168.4.1. Incluso puedes usarla sin ninguna red, como una cámara que solo guarda fotos en la microSD.
¿La ESP32-CAM puede grabar vídeo?
Los ejemplos incluidos transmiten la imagen en directo como MJPEG y hacen fotos sueltas; no graban un archivo de vídeo directamente. Hay proyectos de la comunidad que escriben fotogramas JPEG consecutivos en la microSD para formar un archivo AVI, pero la velocidad es limitada incluso a baja resolución. La placa no tiene micrófono, así que tampoco graba sonido.
Proyectos para hacer después de leer esto
Ver todos los proyectos
LED Parpadeante con ESP32
Enseña el uso básico de la salida GPIO con ESP32. Conseguimos un efecto de parpadeo encendiendo y apagando un LED desde el pin digital. Versión para ESP32 del clásico proyecto blink en Arduino UNO; los comandos básicos de blink en el entorno Arduino son los mismos, pero la distribución de pines y los niveles GPIO de 3,3 V del ESP32 difieren de los del Arduino UNO.

Parpadeo del LED interno del ESP32
Parpadeo del LED azul incorporado en el ESP32 DevKit V1. ¡No se necesitan componentes externos! El primer proyecto que debe probar cuando compra un ESP32. GPIO 2 está conectado al LED interno.

Conexión Wi-Fi STA con ESP32 (con pantalla LCD)
En este proyecto, conectamos el ESP32 a la red Wi-Fi doméstica en modo Station (STA) de forma segura y tolerante a fallos. Separamos el SSID y la contraseña en el archivo `secrets.h` para evitar que se filtren a Git, configuramos un mecanismo de reconexión automática y mostramos el nivel de señal RSSI y la dirección IP en una pantalla LCD I2C. El LED interno actúa como indicador de estado.

Servidor web asíncrono ESP32 (con indicación de IP en la pantalla LCD)
En este proyecto, convertimos el ESP32 en un **servidor web asíncrono** que puedes controlar desde tu teléfono o tu ordenador, siempre que estén conectados a la misma red Wi-Fi. Gracias a la biblioteca ESPAsyncWebServer, el servidor puede procesar varias solicitudes al mismo tiempo (a diferencia del clásico `WebServer.h`, que se bloquea con una sola solicitud).

ESP32 mDNS: Acceso al dispositivo mediante bluegrays-esp.local (con pantalla LCD)
En este proyecto, al añadir el servicio mDNS (Multicast DNS) al ESP32, permitimos el acceso mediante un nombre de host legible, como `bluegrays-esp.local`, en lugar de una dirección IP. Aunque la IP asignada por el DHCP cambie, siempre podrás acceder al dispositivo con el mismo nombre. Además, al ejecutar un pequeño servidor web en él, enviamos comandos de control de los LED desde el navegador mediante la dirección `http://bluegrays-esp.local/`. En la pantalla LCD I2C se muestran el nombre de ho

Registrador de Temperatura ESP32 (DHT22 + DS1307 RTC + microSD + OLED)
¡Construye un registrador de temperatura con marca de tiempo con ESP32! Lee temperatura/humedad del DHT22 cada minuto, obtén la hora real del DS1307 RTC y registra en tarjeta microSD como CSV. El OLED muestra en vivo la temperatura (fuente grande), porcentaje de humedad, marca de tiempo y contador de registros. El archivo `/temp_log.csv` en la tarjeta SD se abre en Excel, Google Sheets o Python pandas para análisis — perfecto para monitoreo de invernadero, seguimiento de temperatura del hog

Sistema de Alarma de Movimiento ESP32 (PIR + Buzzer + LED + Telegram)
Un sistema inteligente de alarma de seguridad que activa el buzzer y el LED cuando el sensor PIR detecta movimiento, y envía simultáneamente una notificación instantánea al propietario vía Telegram. Cuenta con un tiempo de espera de 30 segundos para limitar la frecuencia de las alarmas repetidas; este mecanismo no comprueba la validez de las detecciones del sensor PIR ni elimina las falsas detecciones. Ideal para seguridad del hogar, vigilancia de garajes, almacenes o salas de trabajo. Con ESP32

Alarma con sensor de movimiento ESP32
En este proyecto, elaborado con un ESP32 y un sensor PIR, cuando se detecta movimiento, el zumbador se activa y emite una alarma sonora. Se trata de una aplicación sencilla y económica para un sistema de seguridad. (Las imágenes son ilustrativas; por favor, conéctelas según las instrucciones)
Más artículos
App BlueGrays
Monta este circuito paso a paso en tu teléfono
Esquema, código y lista de piezas en una sola pantalla. Más de 160 proyectos de Arduino, ESP32 y Pico listos para montar.
Escanea con tu teléfono
Apunta la cámara al código y se abrirá la tienda de apps de tu teléfono.
o ábrela en la tienda

