En este artículo aprenderás a programar el módulo ESP32-CAM. Los módulos ESP32 Camera son relativamente económicos y muy útiles para construir sistemas simples de vigilancia o monitoreo. Por ejemplo, tomar automáticamente fotos de animales por la noche en tu jardín o anunciar visitantes en la puerta principal mediante una webcam son casos de uso comunes.
Sin embargo, subir y ejecutar programas en las placas de desarrollo comunes ESP32-CAM es un poco complicado. En este artículo analizamos diferentes métodos para programar y solucionar problemas en una placa ESP32-CAM.
Partes necesarias
A continuación encontrarás los componentes necesarios para construir el proyecto. Algunos de los elementos, como el cable USB, la tarjeta micro SD o el lector de tarjetas SD, quizás ya los tengas. No es necesario comprarlos, ya que ninguno es especial para este proyecto.
Si no tienes un adaptador FTDI USB-TTL, definitivamente es algo que querrás tener. Tarde o temprano lo necesitarás si sigues trasteando con microcontroladores ESP32. El que se lista es uno sencillo pero suficiente para la mayoría de los casos.

ESP32-CAM con Shield USB-TTL

Adaptador FTDI USB-TTL

Tarjeta MicroSD 4GB

Lector de Tarjetas SD

Cable de Datos USB

Arduino IDE
Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.
Conceptos básicos de la placa de desarrollo ESP32-CAM
La placa de desarrollo ESP32-CAM es un módulo compacto que combina un chip ESP32-S, una cámara, un flash integrado y una ranura para tarjeta microSD. La placa tiene Wi-Fi y Bluetooth integrados y soporta cámaras OV2640 u OV7670 con hasta 2 megapíxeles de resolución.


A continuación puedes encontrar la especificación detallada de la placa. Ten en cuenta que en el código de ejemplo nos referiremos al modelo original AI-Thinker de la placa ESP32-CAM, pero existen muchos clones con las mismas o similares especificaciones.
Generalmente se programan y usan de la misma manera. Hay una excepción: si tu placa tiene una matriz de pines con 6 filas (en lugar de solo 4), puede programarse más fácilmente usando el shield de programación. Mira la imagen a continuación para comparar:

También hay una diferencia en el pin GND (marcado con la flecha roja). En la Versión 1 (lado izquierdo) este pin está etiquetado como GND/R y se usa para resetear la placa. En la Versión 2 (lado derecho), este pin sirve como tierra (GND).
La Versión 2 a la derecha con 4 pines requiere que presiones manualmente los botones BOOT y RST al subir código (más adelante hablaremos de esto), mientras que la Versión 1 lo hace automáticamente. Desafortunadamente, la Versión 2 es bastante común y en este caso es más fácil usar un programador FTDI que el shield de programación.
Características
- Módulo SoC ultra pequeño 802.11b/g/n Wi-Fi + BT/BLE.
- CPU dual-core de 32 bits de bajo consumo para procesadores de aplicaciones.
- Frecuencia principal hasta 240MHz, potencia de cálculo hasta 600 DMIPS.
- SRAM incorporada de 520 KB, PSRAM externa de 4M.
- Soporta interfaces como UART/SPI/I2C/PWM/ADC/DAC.
- Soporta cámaras OV2640 y OV7670, flash incorporado.
- Soporta carga de imágenes vía WiFi, soporte para tarjeta TF.
- Soporta múltiples modos de suspensión.
- Soporta modos de trabajo STA/AP/STA+AP.
Especificaciones
- Tamaño: 27*40.5*4.5(±0.2)mm
- Flash SPI: 32Mbit por defecto
- RAM: Interna 520KB + PSRAM externa 4M
- BT: Estándares BT 4.2BR/EDR y BLE
- WiFi: 802.11 b/g/n/e/i
- Interfaces soportadas: UART, SPI, I2C, PWM
- Soporte para tarjeta TF: 4G (usualmente hasta 16GB funciona)
- Puertos IO: 9
- Formato de salida de imagen: JPEG (solo soportado por OV2640), BMP, GRAYSCALE
- Antena: antena integrada, ganancia 2dBi
- Seguridad: WPA/WPA2/WPAS-Enterprise/WPS
- Rango de alimentación: 5V
- Temperatura de trabajo: -20 °C a 85 °C
Consumo de energía
- Sin flash: 180mA@5V
- Con flash a máxima luminosidad: 310mA@5V
- Modo deep-sleep: 6mA@5V
- Modo modem-sleep: 20mA@5V
- Modo light-sleep: 6.7mA@5V
Pinout
La siguiente imagen muestra el pinout del ESP32-CAM. Ten en cuenta que en teoría el ESP32-CAM puede funcionar a 3.3V, pero se han reportado comportamientos inestables y fotos con marcas de agua. Por eso se recomienda una alimentación de 5V @ 2A.
También nota que IO0 está conectado al pin XCLK de la cámara y debe quedar flotante (sin conectar) cuando el ESP32 está en funcionamiento. Solo debes conectar IO0 a GND al subir código. Más adelante hablaremos de esto.

Comparado con una placa ESP32 estándar, la ESP32-CAM tiene muchos menos pines GPIO disponibles. Esto se debe a que la mayoría de los pines GPIO son usados por la cámara y el lector de tarjetas SD. Además, debes evitar usar GPIO1, GPIO3 y GPIO0, ya que son necesarios para programar la placa. Para más información, consulta el More GPIO pins for ESP32-CAM tutorial.
El pin P_OUT está etiquetado como VCC en algunas placas. Es un pin de salida de energía que entrega 3.3V o 5V dependiendo de un solder pad. ¡No puedes usar este pin para alimentar la placa! Usa el pin de 5V para eso.
También ten cuidado con los pines de tierra. Evita usar el pin GND junto a GPIO1. En algunas placas ESP32-CAM este pin está etiquetado como GND/R y se usa para resetear la placa. No puedes usarlo como tierra. Para estar seguro, siempre usa el pin GND cercano a GPIO0.
Finalmente, los pines GPIO 2, 4, 12, 13, 14 y 15 son usados por el lector de tarjetas SD. Si no usas el lector, están disponibles como GPIO. El LED Flash incorporado está conectado a GPIO 4, lo que hace que el LED se encienda cuando se usa el lector SD. Puedes usar el siguiente código para evitar esto:
SD_MMC.begin("/sdcard", true)
Puedes encontrar información adicional sobre el pinout de la placa ESP32-CAM en este tutorial de RandomNerd: ESP32-CAM AI-Thinker Pinout Guide: GPIOs Usage Explained.
Esquemas
Si necesitas entender en detalle el cableado interno de la placa ESP32-CAM, echa un vistazo a los siguientes esquemas (source). Haz clic en la imagen para abrir o download el PDF con los esquemas en alta resolución.

Instalando el Core ESP32
Para programar el ESP32-CAM necesitarás el Arduino IDE con el soporte para placas ESP32 instalado. Afortunadamente, instalar el Core ESP32 es muy sencillo. Solo inicia tu Arduino IDE y sigue los pasos que se describen a continuación. Si tienes problemas, puedes encontrar instrucciones más detalladas en nuestro tutorial How to Program ESP32 with Arduino IDE.
URLs adicionales para el gestor de placas
Primero abre el diálogo de Preferencias seleccionando «Preferences…» en el menú «File»:

Esto abrirá el diálogo de Preferencias que se muestra a continuación. En la pestaña Settings encontrarás un cuadro de edición en la parte inferior del diálogo etiquetado como «URLs adicionales para el gestor de placas«:

En este campo copia la siguiente URL: «https://espressif.github.io/arduino-esp32/package_esp32_dev_index.json«
Esto le indicará al Arduino IDE dónde encontrar las librerías del core ESP32. A continuación instalaremos las librerías del core ESP32 usando el Gestor de Placas.
Gestor de Placas
Abre el GESTOR DE PLACAS haciendo clic en el icono de la placa en la barra lateral como se muestra a continuación:

Verás aparecer el GESTOR DE PLACAS a la derecha de la barra lateral. Escribe «ESP32» en el campo de búsqueda en la parte superior y deberías ver dos tipos de placas ESP32; las «Arduino ESP32 Boards» y las placas «esp32 de Espressif». Queremos las librerías esp32 de Espressif. Haz clic en el botón INSTALL y espera hasta que la descarga e instalación se completen.

Una vez instalado, tu Gestor de Placas debería verse así, aunque la versión real (aquí 3.0.0-a) puede variar.

En el siguiente paso, te mostraré cómo seleccionar la placa ESP32 que quieres programar.
Seleccionar la placa
Para seleccionar una placa ve al menú Tools. Haz clic en Board: «Arduino Uno». Puede que veas una placa diferente a la mostrada aquí, no hay problema. Ve al submenú y deberías ver las «Arduino AVR Boards» y debajo las «esp32» (como puedes ver, también tengo instaladas las placas esp8266). Haz clic en «esp32» y obtendrás una lista amplia de placas disponibles.

Encuentra la placa AI Thinker ESP32-CAM en la lista y haz clic en ella.
Ahora estás listo para subir y ejecutar código en la placa ESP32-CAM. Te mostraré dos formas diferentes de hacerlo. Puedes usar uno de los Shields de Programación que a menudo se venden junto con el módulo ESP32-CAM. O puedes usar un programador FTDI separado y más universal. Empezamos primero con el Shield de Programación.
Subir código usando un Shield de Programación
Si quieres programar un chip ESP32 directamente necesitas usar la interfaz UART serial. Esto está disponible a través de los pines U0TXD y U0RXD que ves en el pinout. Sin embargo, queremos programar el ESP32 usando el puerto USB de nuestro ordenador (y el Arduino IDE). Para esto necesitamos un convertidor USB a UART.
Shield de Programación
Muchas placas de desarrollo con ESP32 tienen un chip integrado (CH340) que hace esta conversión USB a UART, pero el módulo ESP32-CAM desafortunadamente no. Por lo tanto, necesitas un Shield de Programación, como el que se muestra abajo, o un programador FTDI, que discutiremos más adelante.

Solo apila el módulo ESP32-CAM sobre el Shield de Programación como se muestra abajo, conecta un cable USB del Shield a tu ordenador, y estarás listo para programar.

Conectando el Shield de Programación al ordenador
Primero asegúrate de que el cable USB está bien conectado y funciona. Deberías escuchar un sonido de conexión en tu ordenador y un LED rojo en el Shield debería encenderse al conectar el cable USB. Luego asegúrate de tener seleccionada la placa AI Thinker ESP32-CAM y el puerto serial correcto. Mira la imagen abajo.

El puerto serial que ves probablemente será diferente. Dependerá de tu ordenador y del puerto USB que uses para conectar el ESP32-CAM.
Modo de programación
Para subir un programa al ESP32-CAM necesitas hacer lo siguiente:
Inicia la subida con el botón de subir en el Arduino IDE:

En el Shield de Programación presiona y mantén presionado el botón IO0 que está al lado del módulo:

Espera hasta que aparezca el texto «Connecting …..» en el panel de salida:

Luego (mientras sigues presionando IO0) presiona y suelta el botón RST (medio segundo) en el ESP32-CAM (NO en el Shield de Programación!). Este botón está en una posición incómoda, pero el botón RST del Shield no me funcionó. La imagen abajo muestra la ubicación del botón RST que debes presionar.

Cuando los puntos en el texto «Connecting …..» dejen de aparecer, puedes soltar también el botón IO0. Después deberías ver el siguiente texto en el panel de salida, indicando que el código se está subiendo:

Modo de ejecución
Una vez que aparezca el texto «Hard resetting via RTS pin…» en el panel de salida, la subida está completa. Puedes ejecutar el programa subido presionando el botón RST en el módulo ESP32-CAM. Como antes, no uses el botón RST del Shield de Programación ni presiones el botón IO0.
Puedes usar el siguiente código de prueba para intentar la subida.
Código de prueba para ESP32-CAM con Shield de Programación
Este es un programa simple Blink que enciende el LED Flash del ESP32-CAM por 10 ms, luego espera 2 segundos y repite el ciclo.
int flashPin = 4;
void setup() {
pinMode(flashPin, OUTPUT);
}
void loop() {
digitalWrite(flashPin, HIGH);
delay(10);
digitalWrite(flashPin, LOW);
delay(2000);
}
Si ves el LED parpadeando, has subido exitosamente un programa al ESP32-CAM.
Quizás hayas notado que subir código al ESP32-CAM es un procedimiento realmente engorroso. Esperarías que el Shield de Programación cambiara automáticamente el ESP32 a modo programación y que no tuvieras que presionar botones, pero eso no funcionó con ninguno de los dos Shields que probé.
Aun así, el tiempo parece ser algo crítico y la comunicación es frágil. Frecuentemente tuve que intentar más de una vez para lograr una subida exitosa. A menudo desconectar y reconectar el cable USB ayudaba. A veces la subida comenzaba sin que yo presionara ningún botón después de cambiar de puerto USB.
En la siguiente sección te mostraré cómo usar un programador FTDI, que hace la subida de código un poco más fácil, aunque aún no es totalmente automática.
Subir código usando un programador FTDI
Un programador FTDI o adaptador FTDI USB-TTL hace esencialmente el mismo trabajo que el Shield de Programación para el ESP32-CAM. Convierte señales USB a señales seriales y te permite programar microcontroladores como Arduino y ESP32 vía la interfaz UART.

A diferencia del Shield de Programación, el programador FTDI no es para una placa específica, sino que puede usarse con todos los microcontroladores que soporten comunicación serial. Aunque el programador FTDI es más flexible, requiere que hagas el cableado entre el programador FTDI y el microcontrolador tú mismo. Y eso es lo que haremos en la siguiente sección.
Conectando el programador FTDI con ESP32-CAM
La siguiente imagen muestra cómo conectar el programador FTDI al módulo ESP32-CAM:

Las conexiones son simples. Comienza conectando GND del programador con GND del módulo ESP32-CAM (cable azul). Luego haz lo mismo con la alimentación de 5V (cable rojo). Nota que algunos programadores FTDI tienen jumpers o interruptores para cambiar entre 3.3V y 5V. Ten cuidado con eso.
Luego conectamos el pin U0T (U0TXD) del ESP32-CAM al pin RXD del programador (cable amarillo). De forma similar, U0R se conecta a TXD (cable verde). Con eso se establece la comunicación serial.
Para cambiar el ESP32-CAM a modo programación, el pin IO0 debe conectarse a tierra (GND). Pero si quieres ejecutar el programa, el pin IO0 debe quedar desconectado. Por eso añadí un interruptor entre IO0 y GND (cable morado) que me permite cambiar entre modo programación y modo ejecución. Mira la imagen abajo:

Seleccionando la placa ESP32-CAM
Conecta el programador FTDI con el ESP32-CAM conectado al puerto USB, haz clic en el menú desplegable en el Arduino IDE y luego en «Select other board and port…»:

Esto abrirá un diálogo donde escribes «ESP32-CAM» en la barra de búsqueda. Verás la placa «AI Thinker ESP32-CAM» bajo Boards. Haz clic en ella y selecciona el puerto COM para activarla, luego haz clic en OK:

ESP32-CAM no reconocido en el puerto COM
Si no puedes seleccionar un puerto a pesar de tener el ESP32-CAM conectado vía FTDI, entonces falta el driver CP210X. Ve a SILICON LABS Software Downloads y descarga el driver CP210x para tu sistema operativo, por ejemplo para Windows es «CP210x VCP Windows»:

Esto descargará un archivo ZIP. Descomprímelo y ejecuta el instalador. Después de eso tu ESP32-CAM debería aparecer conectado a un puerto USB. Si aún tienes problemas, puede que también necesites instalar el FTDI Driver para el programador FTDI.
Modo de programación
Programar usando el programador FTDI es muy similar a usar el Shield de Programación. Comienza cambiando el módulo ESP32-CAM a modo programación activando el interruptor (IO0 conectado a GND).
Luego presiona el botón Upload en el Arduino IDE:

Espera hasta que aparezca el texto «Connecting …..» en el monitor serial:

Luego presiona y suelta rápidamente el botón RST en el ESP32-CAM.

Los puntos después de «Connecting …..» deberían dejar de aparecer y deberías ver el progreso de subida en el panel de salida:

También parece funcionar cambiar el ESP32-CAM a modo programación (activar interruptor), luego presionar y soltar el botón RST, y después presionar el botón Upload en el Arduino IDE. Esto evita que tengas que «cronometar» el mensaje de conexión.
Modo de ejecución
Una vez que aparezca el texto «Hard resetting via RTS pin…» en el panel de salida, la subida está completa. Cambia el interruptor para salir del modo programación y presiona el botón RST en el ESP32-CAM para iniciar el programa.
Puedes usar el mismo código de prueba mostrado arriba o probar algo un poco más avanzado como el siguiente código.
Código de prueba para ESP32-CAM con programador FTDI
Este es esencialmente el mismo programa Blink, pero aumentamos lentamente el brillo del LED Flash en 255 pasos, luego lo apagamos por un segundo y repetimos el ciclo.
int flashPin = 4;
void setup() {
pinMode(flashPin, OUTPUT);
}
void loop() {
for (int b = 0; b < 255; b++) {
analogWrite(flashPin, b);
delay(1);
}
analogWrite(flashPin, 0);
delay(1000);
}
Dado que la programación sigue siendo engorrosa (incluso con el programador FTDI), querrás probar primero la función de la tarjeta SD y la cámara antes de intentar ejecutar un programa más complejo. En las siguientes dos secciones te muestro cómo hacerlo.
Probando la tarjeta SD
Según la hoja de datos, el ESP32-CAM solo soporta tarjetas microSD de 4GB. Sin embargo, las tarjetas microSD de 8GB y 16GB generalmente funcionan bien. Las tarjetas más grandes deben ser reformateadas con FAT32. Usa el guiformat.exe software de ridgecrop para formatear tarjetas SD más grandes con FAT32.
El siguiente programa de prueba crea un archivo de prueba, escribe texto en él y luego lee el texto. Si eso funciona, tu tarjeta SD funciona correctamente.
#include "SD_MMC.h"
#include "FS.h"
#include "LittleFS.h"
int flashPin = 4;
void setup() {
Serial.begin(115200);
SD_MMC.begin();
LittleFS.begin(true);
File file = LittleFS.open("/test.txt", FILE_WRITE);
file.print("*** Test successful ***");
file.close();
file = LittleFS.open("/test.txt");
while (file.available()) {
Serial.write(file.read());
}
file.close();
pinMode(flashPin, OUTPUT);
analogWrite(flashPin, 0);
}
void loop() {
}
Aquí una explicación más detallada del código.
Librerías e inicialización
Comenzamos incluyendo las librerías necesarias para operaciones con la tarjeta SD y el sistema de archivos: SD_MMC.h, FS.h y LittleFS.h.
#include "SD_MMC.h" #include "FS.h" #include "LittleFS.h"
También definimos una variable flashPin para representar el pin conectado al LED flash.
int flashPin = 4;
Función Setup
En la función setup() inicializamos la comunicación serial a una velocidad de 115200 baudios.
void setup() {
Serial.begin(115200);
Luego inicializamos la tarjeta SD y el sistema de archivos LittleFS. Llamar a LittleFS.begin con true asegura que el sistema de archivos para LittleFS esté creado. Normalmente solo necesitas hacer esto una vez, pero no hace daño llamar a la función así cada vez.
SD_MMC.begin(); LittleFS.begin(true);
A continuación, creamos un archivo llamado test.txt en modo escritura, escribimos un mensaje de prueba y cerramos el archivo.
File file = LittleFS.open("/test.txt", FILE_WRITE);
file.print("*** Test successful ***");
file.close();
Reabrimos el archivo en modo lectura, leemos su contenido carácter por carácter y lo imprimimos en el monitor serial.
file = LittleFS.open("/test.txt");
while (file.available()) {
Serial.write(file.read());
}
file.close();
Finalmente, configuramos el flashPin como pin de salida y apagamos el LED Flash estableciendo su valor PWM a 0. Hago esto porque escribir en la tarjeta SD enciende automáticamente el LED Flash, lo cual es molesto. El código de prueba funciona bien sin estas dos líneas, pero no me gustaba el flash en mis ojos cada vez que corría la prueba.
pinMode(flashPin, OUTPUT); analogWrite(flashPin, 0);
Función Loop
La función loop() queda vacía, ya que todo ocurre en la función setup. Para volver a ejecutar el programa necesitas resetear el ESP32-CAM.
void loop() {
}
Salida en el monitor serial
Si todo funciona correctamente, deberías ver las siguientes líneas en el monitor serial. Nota la última línea con «*** Test successful ***», que prueba que pudimos escribir y leer de la tarjeta SD.

Otras pruebas
Alternativamente, puedes ejecutar la prueba más compleja que viene con la librería ESP32. Tiene salida de depuración adicional, que puede ser útil. Mira el sketch SDMMC_Test.ino. El mismo código está disponible en los ejemplos de Sketch: File -> Examples -> Examples for AI-Thinker ESP32-CAM -> SDMMC -> SDMMC_Test.
Probando la cámara
Después de la tarjeta SD queremos probar la función de la cámara. El código a continuación es una versión simplificada de programas más complejos. Cada vez que el ESP32-CAM arranca (se presiona el botón reset), toma una foto y la guarda en la tarjeta SD.
Este código es específico para el modelo AI-Thinker pero funcionará bien en la mayoría de las otras placas de cámara basadas en ESP32, siempre que tengan PSRAM (ver model definitions). Solo necesitas reemplazar el pin definitions según tu modelo.
#include "esp_camera.h"
#include "soc/rtc_cntl_reg.h"
#include "SD_MMC.h"
#include "EEPROM.h"
// CAMERA_MODEL_AI_THINKER
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
void configCamera() {
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
config.frame_size = FRAMESIZE_UXGA;
config.jpeg_quality = 10;
config.fb_count = 2;
esp_err_t err = esp_camera_init(&config);
sensor_t* s = esp_camera_sensor_get();
s->set_brightness(s, 0);
s->set_contrast(s, 0);
s->set_saturation(s, 0);
s->set_special_effect(s, 0);
s->set_whitebal(s, 1);
s->set_awb_gain(s, 1);
s->set_wb_mode(s, 0);
s->set_exposure_ctrl(s, 1);
s->set_aec2(s, 0);
s->set_ae_level(s, 0);
s->set_aec_value(s, 300);
s->set_gain_ctrl(s, 1);
s->set_agc_gain(s, 0);
s->set_gainceiling(s, (gainceiling_t)0);
s->set_bpc(s, 0);
s->set_wpc(s, 1);
s->set_raw_gma(s, 1);
s->set_lenc(s, 1);
s->set_hmirror(s, 0);
s->set_vflip(s, 0);
s->set_dcw(s, 1);
s->set_colorbar(s, 0);
}
unsigned int incCounter() {
unsigned int cnt = 0;
int adr = 0;
EEPROM.get(adr, cnt);
EEPROM.put(adr, cnt + 1);
EEPROM.commit();
return cnt;
}
void skipPictures(int n) {
for(int i=0; i<n; i++) {
camera_fb_t* fb = esp_camera_fb_get();
esp_camera_fb_return(fb);
}
}
void takePicture() {
camera_fb_t* fb = esp_camera_fb_get();
unsigned int cnt = incCounter();
String path = "/pic" + String(cnt) + ".jpg";
Serial.println(path);
File file = SD_MMC.open(path.c_str(), FILE_WRITE);
file.write(fb->buf, fb->len);
file.close();
esp_camera_fb_return(fb);
}
void setup() {
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
Serial.begin(115200);
SD_MMC.begin();
EEPROM.begin(16);
configCamera();
skipPictures(n);
takePicture();
esp_deep_sleep_start();
}
void loop() {
}
Este código es un buen punto de partida para casos de uso más avanzados. Por ejemplo, si quieres tomar una foto cuando se active un sensor de movimiento o luz. O si quieres tomar fotos en intervalos de tiempo determinados. A continuación, un poco más de detalle sobre cómo funciona este código.
Constantes y librerías
Primero, incluimos las librerías necesarias como esp_camera.h, soc/rtc_cntl_reg.h, SD_MMC.h y EEPROM.h. Estas librerías proporcionan funcionalidades para configuración de la cámara, operaciones con la tarjeta SD y uso de EEPROM.
#include "esp_camera.h" #include "soc/rtc_cntl_reg.h" #include "SD_MMC.h" #include "EEPROM.h"
Configuración de la cámara
La función configCamera() configura los parámetros de la cámara como canal LEDC, pines para líneas de datos (D0-D7), XCLK, PCLK, VSYNC, HREF, SCCB SDA, SCCB SCL, PWDN, RESET y varios ajustes de cámara como formato de píxel, tamaño de cuadro, calidad JPEG, etc.
void configCamera() {
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
...
sensor_t* s = esp_camera_sensor_get();
s->set_brightness(s, 0);
s->set_contrast(s, 0);
s->set_saturation(s, 0);
...
}
Como se mencionó, dependiendo del tipo de cámara las definiciones de pines pueden cambiar. También, si no estás satisfecho con la calidad de las fotos, hay muchos parámetros con los que puedes jugar.
Función de incremento de contador
La función incCounter() lee e incrementa un valor contador almacenado en la memoria EEPROM. Recupera el conteo actual, lo incrementa, lo escribe de nuevo en la EEPROM y devuelve el conteo previo.
unsigned int incCounter() {
unsigned int cnt = 0;
int adr = 0;
EEPROM.get(adr, cnt);
EEPROM.put(adr, cnt + 1);
EEPROM.commit();
return cnt;
}
Esto asegura que tengamos un contador en marcha para las fotos tomadas, a pesar de resetear el ESP32-CAM cuando tomamos una foto. Este contador también se usa para crear nombres únicos para los archivos de imagen que guardamos en la tarjeta SD.
Si quieres resetear el contador, podrías subir y ejecutar el siguiente código:
#include "EEPROM.h"
void setup() {
EEPROM.begin(512);
unsigned int cnt = 0;
int adr = 0;
EEPROM.put(adr, cnt);
EEPROM.commit();
}
void loop() {
}
Ignorar imágenes
La función SkipPictures(n) captura n imágenes y las descarta. La razón por la que hacemos esto es la siguiente: La cámara tiene varias funciones automáticas integradas, por ejemplo balance de blancos automático y otras que tardan un tiempo y varios cuadros de imagen en ajustarse al entorno. Después de un reinicio desde deep sleep, necesitamos dar un poco de tiempo a la cámara para ajustarse.
void skipPictures(int n) {
for(int i=0; i<n; i++) {
camera_fb_t* fb = esp_camera_fb_get();
esp_camera_fb_return(fb);
}
}
Si tomas la primera imagen después de un reinicio, verás que es de calidad horrible. Típicamente con un fuerte tinte azul, o demasiado oscura o brillante. Sin embargo, después de saltar los primeros cuadros, generalmente (pero no siempre) obtienes imágenes de buena calidad.
También podrías intentar desactivar el balance de blancos automático y otras funciones automáticas en la configuración de la cámara, pero entonces necesitarás un entorno bastante estable para poder ajustar los otros parámetros. De lo contrario, será difícil obtener imágenes de buena calidad.
Captura y almacenamiento de imagen
La siguiente función captura una imagen usando la cámara y la guarda en la tarjeta SD. Recupera un buffer de cuadro de la cámara, incrementa el contador, crea una ruta de archivo única para la imagen, escribe los datos de la imagen en el archivo y libera el buffer de cuadro.
void takePicture() {
camera_fb_t* fb = esp_camera_fb_get();
unsigned int cnt = incCounter();
String path = "/pic" + String(cnt) + ".jpg";
Serial.println(path);
File file = SD_MMC.open(path.c_str(), FILE_WRITE);
file.write(fb->buf, fb->len);
file.close();
esp_camera_fb_return(fb);
}
Ten en cuenta que usamos la variable contador para crear los nombres de archivo. Si no te gustan los nombres, este es el lugar para cambiarlos.
Función Setup
En la función setup() primero desactivamos el detector de brownout. El ESP32-CAM es demasiado propenso a lanzar errores de brownout si la fuente de alimentación entrega poca corriente durante el arranque. Llamar a WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0) evita este problema.
Luego inicializamos la comunicación serial, arrancamos la tarjeta SD, comenzamos la EEPROM, configuramos la cámara, capturamos una imagen e iniciamos el modo deep sleep. Esto significa que cada vez que el ESP32-CAM arranca o se resetea, se toma una nueva foto y se guarda en la tarjeta SD.
void setup() {
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
Serial.begin(115200);
SD_MMC.begin();
EEPROM.begin(512);
configCamera();
takePicture();
esp_deep_sleep_start();
}
Función Loop
La función loop() está vacía. Todo ocurre durante setup y solo se toma una foto, después de lo cual la placa entra en deep sleep y espera un reinicio.
Ejemplo de servidor web de cámara
Si quieres usar una prueba que incluya las capacidades WiFi del ESP32, el ejemplo CameraWebServer es bueno. Lo puedes encontrar en File -> Examples -> ESP32 -> Camera -> CameraWebServer.

Tendrás que cambiar un poco el código en CameraWebServer.ino. Primero, necesitas definir el modelo de cámara que estás usando. ¡Asegúrate de que solo esté definido el modelo que tienes!
// =================== // Select camera model // =================== //#define CAMERA_MODEL_WROVER_KIT // Has PSRAM //#define CAMERA_MODEL_ESP_EYE // Has PSRAM ... //#define CAMERA_MODEL_M5STACK_UNITCAM // No PSRAM #define CAMERA_MODEL_AI_THINKER // Has PSRAM //#define CAMERA_MODEL_TTGO_T_JOURNAL // No PSRAM //#define CAMERA_MODEL_XIAO_ESP32S3 // Has PSRAM
Luego, debes ingresar las credenciales WiFi de tu red doméstica:
// =========================== // Enter your WiFi credentials // =========================== const char* ssid = "**********"; const char* password = "**********";
Después de subir el código y resetear el ESP32-CAM deberías ver el siguiente texto en el monitor serial:

CameraWebServerNota la última línea, que te proporciona la URL (dirección IP) donde está corriendo el servidor web. Copia y pega esta URL en la barra de direcciones de tu navegador y deberías ver el siguiente sitio web, que transmite imágenes de la cámara de tu ESP32-CAM al navegador.

CameraWebServer en el navegador web¡Y eso es todo! Esto debería darte suficiente información y ejemplos para comenzar con el módulo ESP32-CAM.
Si necesitas un código de ejemplo más simple para transmitir video, echa un vistazo al tutorial Stream Video with ESP32-CAM. Y para una cámara activada por movimiento, mira el tutorial Motion Activated ESP32-CAM.
Resumen
El módulo ESP32-CAM es una placa agradable y capaz una vez que logras ponerla en marcha. Sin embargo, subir código de forma confiable al módulo es engorroso. A menudo tuve que intentar varias veces y desconectar el cable USB para que funcionara. En realidad, el método más confiable fue el siguiente:
- Desconectar el cable USB
- Cambiar la placa a modo programación
- Conectar el cable USB
- Iniciar la subida en Arduino IDE
Eso siempre funcionó y no requirió presionar el botón RST durante la subida. Para luego ejecutar el ESP32-CAM solo tuve que desactivar el modo programación y presionar reset. No fue necesario desconectar el cable USB para eso. Solo para subir un nuevo programa tuve que desconectar la placa y repetir los pasos.
Otro truco que encontré fue que quitar la tarjeta SD ayudaba cuando la placa se negaba a entrar en modo programación. Eso ocurría frecuentemente cuando el código previamente cargado usaba la tarjeta SD.
Si tienes dificultades con tu placa ESP32-CAM, a continuación hay algunos enlaces con información adicional y una lista de preguntas frecuentes con respuestas.
Finalmente, si buscas una placa que no requiera un shield de programación separado o un programador FTDI para flashear, echa un vistazo a la ESP32-WROVER CAM, que también tiene más GPIO libres pero es más grande. Si necesitas una placa muy pequeña y con micrófono, recomiendo la XIAO-ESP32-S3-Sense.
¡Disfruta trasteando!
Enlaces
Aquí algunos enlaces que encontré útiles para comenzar con el ESP32-CAM:
- Getting Started With ESP32-CAM
- How to Program / Upload Code to ESP32-CAM AI-Thinker (Arduino IDE)
- ESP32-CAM Troubleshooting Guide: Most Common Problems Fixed
- ESP32-CAM AI-Thinker Pinout Guide: GPIOs Usage Explained
- ESP32-CAM Take Photo and Save to MicroSD Card
- Camera Pin Definitions
- Supported Camera Models
Preguntas frecuentes
Y aquí algunas preguntas comunes y soluciones para ayudarte a solucionar problemas:
P: ¿Por qué mi ESP32-CAM no se conecta al Wi-Fi?
R: Verifica que hayas ingresado correctamente el SSID y la contraseña en tu código. Asegúrate de que la red Wi-Fi esté dentro del alcance y funcione correctamente.
P: ¿Cómo puedo mejorar la calidad de imagen de la cámara?
R: Ajusta la configuración de la cámara en tu código para optimizar la calidad de imagen. Experimenta con diferentes resoluciones y tasas de cuadros para encontrar la mejor configuración para tu proyecto.
P: ¿Cómo puedo añadir más GPIOs?
R: Puedes inicializar la interfaz de la tarjeta SD en modo de 1 bit, lo que libera dos pines GPIO más. Para más detalles, consulta el More GPIO pins for ESP32-CAMtutorial.
P: ¿Por qué mi ESP32-CAM no captura imágenes claras?
R: Las condiciones de iluminación pobres pueden afectar la calidad de la imagen. Asegúrate de tener una iluminación adecuada para que la cámara capture imágenes claras. Ajusta la configuración de la cámara en tu código para obtener la mejor calidad. También asegúrate de haber retirado la pequeña lámina protectora de la lente.

P: ¿Qué debo hacer si mi ESP32-CAM no responde a comandos desde el monitor serial?
R: Verifica la configuración de comunicación serial en tu código y asegúrate de que la velocidad en baudios correcta (115200) esté configurada tanto en el código como en el monitor serial. Revisa las conexiones entre la placa ESP32-CAM y el ordenador.
P: ¿Por qué no se detecta mi tarjeta SD?
R: Asegúrate de que la tarjeta SD esté correctamente insertada en la ranura y formateada correctamente (FAT32). Revisa tu código para asegurarte de que la inicialización de la tarjeta SD se haga correctamente. Las tarjetas de 4 a 16GB deberían funcionar bien. Las de mayor capacidad pueden causar problemas.
P: Mi ESP32-CAM se calienta, ¿es normal?
R: Es normal que el ESP32-CAM se caliente durante la operación, pero si está excesivamente caliente, revisa si hay cortocircuitos o problemas en la fuente de alimentación.
P: ¿Cómo puedo reducir el consumo de energía del ESP32-CAM?
R: Desactiva periféricos innecesarios y optimiza tu código para minimizar el consumo. Considera usar modos de suspensión para ahorrar energía cuando la placa no esté en uso.
P: ¿Por qué las imágenes tomadas por el ESP32-CAM tienen un tinte azul después de un reinicio?
R: La cámara tiene funciones automáticas, como el balance de blancos automático, que tardan un tiempo en ajustarse al entorno. Sin esto, obtendrás imágenes con tinte azul o muy oscuras o brillantes. Una forma fácil de evitarlo es tomar varias fotos después de un reinicio y descartarlas. Consulta la función skipPictures() en el tutorial que hace exactamente eso.
P: ¿Por qué mi ESP32-CAM no captura imágenes?
R: Verifica que el módulo de cámara esté conectado correctamente a la placa ESP32-CAM. Asegúrate de que los pines de la cámara estén cableados correctamente y que el módulo de cámara sea compatible con tu código.
P: ¿Cómo puedo transmitir video desde el ESP32-CAM?
R: Implementa un servidor de streaming en el ESP32-CAM usando librerías como ESP32-CAM-Webserver para transmitir video por Wi-Fi. Asegúrate de que tu red pueda manejar el ancho de banda del streaming de video.
P: ¿Por qué mi ESP32-CAM no es reconocido por el Arduino IDE?
R: Asegúrate de haber instalado el paquete de soporte para placas ESP32 en el Arduino IDE. Revisa tu cable USB y las conexiones de puerto para asegurar una comunicación adecuada con la placa ESP32-CAM.
P: ¿Por qué mi ESP32-CAM muestra «Timed out waiting for packet header» durante la subida de código?
R: Este error puede ocurrir por una conexión USB lenta o inestable. Prueba con otro cable USB o puerto, y asegúrate de que la placa ESP32-CAM esté encendida y en modo bootloader antes de subir el código.
P: ¿Qué debo hacer si mi ESP32-CAM se congela durante la subida de código?
R: Desconecta el cable USB, resetea la placa ESP32-CAM y vuelve a intentar subir el código. Asegúrate de que tu código no cause que la placa se cuelgue o falle durante la subida.
P: ¿Puedo subir código al ESP32-CAM de forma inalámbrica?
R: Sí, puedes subir código inalámbricamente al ESP32-CAM usando programación OTA (Over-The-Air). Implementa la funcionalidad OTA en tu código y sigue los pasos necesarios para subir código sin conexión USB.
P: ¿Por qué mi ESP32-CAM no entra en modo bootloader para subir código?
R: Verifica la conexión del pin GPIO0 a GND en la placa ESP32-CAM. Asegúrate de presionar el botón reset en el momento adecuado para entrar en modo bootloader para subir código.
P: ¿Cómo puedo resolver el error «A fatal error occurred: Failed to connect to ESP32: Timed out waiting for packet header» al subir código?
R: Este error puede ocurrir por configuraciones incorrectas de velocidad en baudios o un cable USB defectuoso. Prueba cambiando la velocidad en baudios en la configuración del Arduino IDE o usando otro cable USB para establecer una conexión estable con la placa ESP32-CAM.
P: ¿Qué pasos debo seguir si veo «esptool.FatalError: Timed out waiting for packet header» al subir código al ESP32-CAM?
R: Este error puede indicar un problema de tiempo de espera en la comunicación entre el ordenador y la placa ESP32-CAM. Revisa el cable USB, el puerto y las conexiones de la placa. Reinicia el IDE, resetea la placa y vuelve a intentar subir el código.
P: ¿Qué debo hacer si veo el error «Brownout detector was triggered»?
R: Este error suele ocurrir si la fuente de alimentación del ESP32-CAM es insuficiente y causa una caída en el voltaje de suministro. Un circuito interno del ESP32 detecta este problema, envía este mensaje de error al monitor serial y resetea la placa. Debes asegurarte de alimentar el ESP32-CAM desde el pin de 5V con una fuente que pueda entregar 1A de corriente. Para más información, consulta nuestro Fix brownout of ESP32-CAMtutorial.

