In questo articolo imparerai a programmare il modulo ESP32-CAM. I moduli ESP32 Camera sono relativamente economici e molto utili per costruire semplici sistemi di sorveglianza o monitoraggio. Ad esempio, scattare automaticamente foto di animali di notte nel tuo giardino o annunciare i visitatori alla porta di casa tramite webcam sono casi d’uso comuni.
Tuttavia, caricare ed eseguire programmi sulle comuni schede di sviluppo ESP32-CAM è un po’ complicato. In questo articolo esamineremo diversi metodi per programmare e risolvere problemi su una scheda ESP32-CAM.
Componenti necessari
Di seguito trovi i componenti necessari per realizzare il progetto. Alcuni di questi, come il cavo USB, la micro SD Card o il lettore di schede SD, potresti già averli. Non è quindi necessario acquistarli, nessuno di questi componenti è specifico per questo progetto.
Se non hai un adattatore FTDI USB-TTL, allora è sicuramente qualcosa che ti servirà. Prima o poi ne avrai bisogno se continui a smanettare con microcontrollori ESP32. Quello elencato è semplice ma sufficiente per la maggior parte dei casi.

ESP32-CAM con shield USB-TTL

Adattatore FTDI USB-TTL

MicroSD Card 4GB

Lettore di schede SD

Cavo dati 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.
Nozioni di base sulla scheda di sviluppo ESP32-CAM
La scheda di sviluppo ESP32-CAM è un modulo compatto che combina un chip ESP32-S, una fotocamera, un flash integrato e uno slot per microSD. La scheda ha Wi-Fi e Bluetooth integrati e supporta una fotocamera OV2640 o OV7670 con risoluzione fino a 2 megapixel.


Di seguito trovi le specifiche dettagliate della scheda. Nota che nel codice di esempio faremo riferimento al modello originale AI-Thinker della scheda ESP32-CAM, ma esistono molte copie con specifiche uguali o simili.
Generalmente sono programmate e usate allo stesso modo. C’è però un’eccezione. Se la tua scheda ha una fila di pin con 6 righe (anziché solo 4), può essere programmata più facilmente usando lo shield di programmazione. Vedi l’immagine sotto per il confronto:

C’è anche una differenza nel pin GND (indicato dalla freccia rossa). Nella Versione 1 (lato sinistro) questo pin è etichettato GND/R ed è usato per resettare la scheda. Nella Versione 2 (lato destro), questo pin serve come massa (GND).
La Versione 2 a destra con i 4 pin richiede di premere manualmente i pulsanti BOOT e RST durante il caricamento del codice (ne parleremo più avanti), mentre la Versione 1 lo fa automaticamente. Purtroppo la Versione 2 è abbastanza comune ed è più facile usare un programmatore FTDI in questo caso piuttosto che lo shield di programmazione.
Caratteristiche
- Modulo SoC ultra-compatto 802.11b/g/n Wi-Fi + BT/BLE.
- CPU dual-core a basso consumo da 32 bit per processori applicativi.
- Frequenza principale fino a 240MHz, potenza di calcolo fino a 600 DMIPS.
- SRAM integrata da 520 KB, PSRAM esterna da 4M.
- Supporta interfacce come UART/SPI/I2C/PWM/ADC/DAC.
- Supporta fotocamere OV2640 e OV7670, flash integrato.
- Supporta upload immagini via WiFi, supporta scheda TF.
- Supporta molteplici modalità di sleep
- Supporta modalità di lavoro STA/AP/STA+AP.
Specifiche
- Dimensioni: 27*40.5*4.5(±0.2)mm
- SPI Flash: 32Mbit di default
- RAM: Interna 520KB + PSRAM esterna 4M
- BT: standard BT 4.2BR/EDR e BLE
- WiFi: 802.11 b/g/n/e/i
- Interfacce supportate: UART, SPI, I2C, PWM
- Supporto scheda TF: 4G (di solito fino a 16GB funziona)
- Porte IO: 9
- Formato output immagine: JPEG (supportato solo da OV2640), BMP, GRAYSCALE
- Antenna: antenna integrata, guadagno 2dBi
- Sicurezza: WPA/WPA2/WPAS-Enterprise/WPS
- Alimentazione: 5V
- Temperatura di lavoro: -20 °C a 85 °C
Consumo energetico
- Senza flash: 180mA@5V
- Con flash a massima luminosità: 310mA@5V
- Deep-sleep: 6mA@5V
- Modem-sleep: 20mA@5V
- Light-sleep: 6.7mA@5V
Pinout
L’immagine seguente mostra il pinout dell’ESP32-CAM. Nota che in teoria l’ESP32-CAM può funzionare a 3.3V ma sono stati segnalati comportamenti instabili e immagini con watermark. L’alimentazione consigliata è quindi 5V @ 2A.
Nota anche che IO0 è collegato al pin XCLK della fotocamera e dovrebbe rimanere flottante (non collegato) durante il funzionamento dell’ESP32. Devi collegare IO0 a massa solo durante il caricamento del codice. Ne parleremo più avanti.

Rispetto a una scheda ESP32 standard, la scheda ESP32-CAM ha un numero molto inferiore di pin GPIO disponibili. Questo perché la maggior parte dei pin GPIO sono usati dalla fotocamera e dal lettore di schede SD. Inoltre, dovresti evitare di usare GPIO1, GPIO3 e GPIO0, poiché sono necessari per programmare la scheda. Per maggiori informazioni vedi il More GPIO pins for ESP32-CAM tutorial.
Il pin P_OUT è etichettato come VCC su alcune schede. È un pin di uscita di alimentazione che fornisce 3.3V o 5V a seconda di un solder pad. Non puoi usare questo pin per alimentare la scheda! Usa il pin 5V per questo scopo.
Fai anche attenzione ai pin di massa.Evita di usare il pin GND accanto a GPIO1! Per alcune schede ESP32-CAM questo pin è etichettato GND/R ed è usato per resettare la scheda. Non puoi usarlo come massa. Per sicurezza, usa sempre il pin GND vicino a GPIO0.
Infine, i pin GPIO 2, 4, 12, 13, 14 e 15 sono usati dal lettore di schede SD. Se non usi il lettore di schede SD, sono disponibili come GPIO. Il LED flash integrato è collegato a GPIO 4, il che fa accendere il LED flash quando il lettore di schede SD è in uso. Puoi usare il seguente codice per evitarlo:
SD_MMC.begin("/sdcard", true)
Puoi trovare ulteriori informazioni riguardo al pinout della scheda ESP32-CAM in questo tutorial di RandomNerd: ESP32-CAM AI-Thinker Pinout Guide: GPIOs Usage Explained.
Schema elettrico
Se vuoi capire nel dettaglio il cablaggio interno della scheda ESP32-CAM, dai un’occhiata agli schemi seguenti (source). Clicca sull’immagine per aprirla o download il PDF con lo schema a piena risoluzione.

Installazione del Core ESP32
Per programmare l’ESP32-CAM, ti serve l’Arduino IDE con il supporto per le schede ESP32 installato. Fortunatamente, installare il Core ESP32 è molto semplice. Basta avviare il tuo Arduino IDE e seguire i passaggi indicati di seguito. Se hai problemi, puoi trovare istruzioni più dettagliate nel nostro tutorial How to Program ESP32 with Arduino IDE.
URL aggiuntivi per il Boards Manager
Per prima cosa apri la finestra Preferenze selezionando “Preferences…” dal menu “File”:

Si aprirà la finestra Preferenze mostrata qui sotto. Nella scheda Settings troverai una casella di testo in fondo alla finestra etichettata “URL aggiuntivi per il Boards Manager“:

In questo campo incolla il seguente URL: “https://espressif.github.io/arduino-esp32/package_esp32_dev_index.json“
Questo permetterà all’Arduino IDE di sapere dove trovare le librerie core ESP32. Successivamente installeremo effettivamente le librerie core ESP32 usando il Boards Manager.
Boards Manager
Apri il BOARDS MANAGER cliccando sull’icona della scheda nella barra laterale come mostrato qui sotto:

Vedrai apparire il BOARDS MANAGER a destra della barra laterale. Digita “ESP32” nel campo di ricerca in alto e dovresti vedere due tipi di schede ESP32; le “Arduino ESP32 Boards” e le schede “esp32 di Espressif”. Noi vogliamo le librerie esp32 di Espressif. Clicca sul pulsante INSTALL e attendi che il download e l’installazione siano completati.

Una volta installate, il tuo Boards Manager dovrebbe apparire così, anche se la versione effettiva (qui 3.0.0-a) potrebbe differire.

Nel passaggio successivo ti mostro come selezionare la scheda ESP32 che vuoi programmare.
Seleziona la scheda
Per selezionare una scheda vai al menu Tools. Clicca su Board: “Arduino Uno”. Potresti vedere una scheda diversa da quella mostrata qui sotto, va bene lo stesso. Vai nel sottomenu e dovresti vedere le “Arduino AVR Boards” e sotto “esp32” (come vedi, ho anche le schede esp8266 installate). Clicca su “esp32” e otterrai una lunga lista di schede disponibili.

Trova la scheda AI Thinker ESP32-CAM nella lista e cliccaci sopra.
Ora sei pronto per caricare ed eseguire codice sulla scheda ESP32-CAM. Ti mostrerò due modi diversi per farlo. Puoi usare uno degli shield di programmazione che spesso sono venduti insieme al modulo ESP32-CAM. Oppure puoi usare un programmatore FTDI separato e più universale. Iniziamo con lo shield di programmazione.
Caricare codice usando uno shield di programmazione
Se vuoi programmare un chip ESP32 direttamente devi usare l’interfaccia seriale UART. Questa è disponibile tramite i pin U0TXD e U0RXD che vedi nel pinout. Tuttavia, vogliamo programmare l’ESP32 usando la porta USB del nostro computer (e l’Arduino IDE). Per questo ci serve un convertitore USB-UART.
Shield di programmazione
Molte schede di sviluppo con ESP32 hanno un chip integrato (CH340) che fa questa conversione USB-UART, ma il modulo ESP32-CAM purtroppo no. Serve quindi uno shield di programmazione, come quello mostrato sotto, o un programmatore FTDI, di cui parleremo più avanti.

Basta impilare il modulo ESP32-CAM sopra lo shield di programmazione come mostrato sotto, collegare un cavo USB dallo shield al computer, e sei pronto per programmare.

Collegare lo shield di programmazione al computer
Per prima cosa assicurati che il cavo USB sia collegato correttamente e funzioni. Dovresti sentire un suono di riconoscimento dal computer e un LED rosso sullo shield dovrebbe accendersi quando colleghi il cavo USB. Poi assicurati di aver selezionato la scheda AI Thinker ESP32-CAM e la porta seriale corretta. Vedi l’immagine sotto.

La porta seriale che vedi sarà probabilmente diversa. Dipende dal tuo computer e dalla porta USB che usi per collegarti all’ESP32-CAM.
Modalità di programmazione
Per caricare un programma sull’ESP32-CAM devi fare quanto segue:
Avvia il caricamento premendo il pulsante di upload nell’Arduino IDE:

Sul shield di programmazione premi e tieni premuto il pulsante IO0 sul lato del modulo:

Aspetta che nel pannello Output appaia il testo “Connecting …..”

Poi (tenendo ancora premuto IO0) premi e rilascia il pulsante RST (per mezzo secondo) sull’ESP32-CAM (NON sullo shield di programmazione!). Questo pulsante è in una posizione scomoda, ma il pulsante RST sullo shield non ha funzionato per me. L’immagine sotto mostra la posizione del pulsante RST da premere.

Quando i puntini nel testo “Connecting …..” smettono di apparire puoi rilasciare anche il pulsante IO0. Dopo di che dovresti vedere apparire nel pannello Output il seguente testo, che indica che il codice sta caricando:

Modalità di esecuzione
Quando nel pannello Output appare il testo “Hard resetting via RTS pin…” il caricamento è completo. Puoi quindi eseguire il programma caricato premendo il pulsante RST sul modulo ESP32-CAM. Come prima, non usare il pulsante RST sullo shield di programmazione e non premere il pulsante IO0.
Puoi usare il seguente codice di test per provare il caricamento.
Codice di test per ESP32-CAM con shield di programmazione
Questo è un semplice programma Blink che accende il LED flash sull’ESP32-CAM per 10 msec, poi aspetta 2 secondi e ripete il ciclo.
int flashPin = 4;
void setup() {
pinMode(flashPin, OUTPUT);
}
void loop() {
digitalWrite(flashPin, HIGH);
delay(10);
digitalWrite(flashPin, LOW);
delay(2000);
}
Se vedi il LED lampeggiare, hai caricato con successo un programma sull’ESP32-CAM.
Avrai notato che caricare codice sull’ESP32-CAM è una procedura davvero macchinosa. Ti aspetteresti che lo shield di programmazione metta automaticamente l’ESP32 in modalità programmazione, senza dover premere alcun pulsante, ma non ha funzionato con nessuno dei due shield di programmazione che ho provato.
Anche così, il timing sembra essere piuttosto critico e la comunicazione fragile. Spesso ho dovuto provare più volte per ottenere un caricamento riuscito. Spesso scollegare e ricollegare il cavo USB aiutava. A volte il caricamento partiva senza che premessi alcun pulsante dopo aver cambiato porta USB.
Nella sezione successiva ti mostro come usare un programmatore FTDI, che rende il caricamento del codice un po’ più semplice ma comunque non completamente automatico.
Caricare codice usando un programmatore FTDI
Un programmatore FTDI o adattatore FTDI USB-TTL fa essenzialmente lo stesso lavoro dello shield di programmazione per l’ESP32-CAM. Converte i segnali USB in segnali seriali e ti permette di programmare microcontrollori come Arduino e ESP32 tramite l’interfaccia UART.

A differenza dello shield di programmazione, il programmatore FTDI non è specifico per una scheda ma può essere usato con tutti i microcontrollori che supportano la comunicazione seriale. Pur essendo più flessibile, richiede di fare il cablaggio tra programmatore FTDI e microcontrollore da soli. Ed è quello che faremo nella sezione seguente.
Collegare il programmatore FTDI con ESP32-CAM
L’immagine seguente mostra come collegare il programmatore FTDI al modulo ESP32-CAM:

Le connessioni sono semplici. Inizia collegando il GND del programmatore con il GND del modulo ESP32-CAM (filo blu). Poi fai lo stesso con l’alimentazione 5V (filo rosso). Nota che alcuni programmatori FTDI hanno jumper o interruttori per passare da 3.3V a 5V. Fai attenzione.
Poi colleghiamo il pin U0T (U0TXD) dell’ESP32-CAM al pin RXD del programmatore (filo giallo). Analogamente, U0R va collegato a TXD (filo verde). Così si stabilisce la comunicazione seriale.
Per mettere l’ESP32-CAM in modalità programmazione il pin IO0 deve essere collegato a massa (GND). Ma se vuoi eseguire il programma, il pin IO0 deve rimanere scollegato. Ho quindi aggiunto un interruttore tra IO0 e GND (filo viola) che mi permette di passare dalla modalità programmazione a quella esecuzione e viceversa. Vedi immagine sotto:

Selezione della scheda ESP32-CAM
Collega il programmatore FTDI con l’ESP32-CAM collegato alla porta USB, clicca sul menu a tendina nell’Arduino IDE e poi su “Select other board and port…”:

Si aprirà una finestra dove inserire “ESP32-CAM” nella barra di ricerca. Vedrai la scheda “AI Thinker ESP32-CAM” sotto Boards. Cliccaci sopra, seleziona la porta COM per attivarla e poi clicca OK:

ESP32-CAM non riconosciuta sulla porta COM
Se non riesci a selezionare una PORTA nonostante l’ESP32-CAM sia collegata via FTDI, allora manca il driver CP210X. Vai su SILICON LABS Software Downloads e scarica il driver CP210x per il tuo sistema operativo, ad esempio per Windows è “CP210x VCP Windows”:

Scaricherai un file ZIP. Estrailo ed esegui l’installer. Dopo di che l’ESP32-CAM dovrebbe apparire come connessa a una porta USB. Se hai ancora problemi, potresti dover installare anche il FTDI Driver per il programmatore FTDI.
Modalità di programmazione
Programmare usando il programmatore FTDI è molto simile all’uso dello shield di programmazione. Inizia mettendo il modulo ESP32-CAM in modalità programmazione azionando l’interruttore (IO0 collegato a GND).
Poi premi il Upload nell’Arduino IDE:

Aspetta che nel monitor seriale appaia il testo “Connecting …..”

Poi premi rapidamente e rilascia il pulsante RST sull’ESP32-CAM.

I puntini dopo “Connecting …..” dovrebbero smettere di apparire e dovresti vedere il progresso del caricamento nel pannello Output:

Quello che sembra funzionare è mettere l’ESP32-CAM in modalità programmazione (interruttore acceso), poi premere e rilasciare il pulsante RST, e infine premere il pulsante Upload nell’Arduino IDE. Così eviti di dover “temporalizzare” il messaggio di connessione.
Modalità di esecuzione
Quando nel pannello Output appare il testo “Hard resetting via RTS pin…” il caricamento è completo. Spegni l’interruttore per passare dalla modalità programmazione a quella esecuzione e premi il pulsante RST sull’ESP32-CAM per avviare il programma.
Puoi usare lo stesso codice di test mostrato sopra o provare qualcosa di leggermente più avanzato come il seguente codice.
Codice di test per ESP32-CAM con programmatore FTDI
È essenzialmente lo stesso di un programma Blink, ma aumentiamo lentamente la luminosità del LED flash in 255 passi, poi lo spegniamo per un secondo e ripetiamo il 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);
}
Poiché la programmazione rimane macchinosa (anche con il programmatore FTDI), è meglio testare prima la funzione della scheda SD e della fotocamera prima di provare a eseguire un programma più complesso. Nelle due sezioni seguenti ti mostro come fare.
Test della scheda SD
Secondo il datasheet, l’ESP32-CAM supporta solo microSD da 4GB. Tuttavia, schede microSD da 8GB e 16GB funzionano generalmente bene. Le schede più grandi devono essere riformattate in FAT32. Usa il guiformat.exe software di ridgecrop per formattare schede SD più grandi in FAT32.
Il seguente programma di test crea un file di prova, scrive del testo al suo interno e lo legge. Se funziona, la tua scheda SD funziona.
#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() {
}
Ecco una spiegazione più dettagliata del codice.
Librerie e inizializzazione
Iniziamo includendo le librerie necessarie per le operazioni su scheda SD e file system: SD_MMC.h, FS.h, e LittleFS.h.
#include "SD_MMC.h" #include "FS.h" #include "LittleFS.h"
Definiamo anche una variabile flashPin per rappresentare il pin collegato al LED flash.
int flashPin = 4;
Funzione setup
Nella funzione setup() inizializziamo la comunicazione seriale a 115200 baud.
void setup() {
Serial.begin(115200);
Inizializziamo poi la scheda SD e il file system LittleFS. Chiamare LittleFS.begin con true assicura che il file system per LittleFS sia creato. Di solito serve farlo una sola volta, ma non fa male chiamare la funzione così ogni volta.
SD_MMC.begin(); LittleFS.begin(true);
Successivamente creiamo un file chiamato test.txt in modalità scrittura, scriviamo un messaggio di test e chiudiamo il file.
File file = LittleFS.open("/test.txt", FILE_WRITE);
file.print("*** Test successful ***");
file.close();
Riapriamo il file in modalità lettura, leggiamo il contenuto carattere per carattere e lo stampiamo sul monitor seriale.
file = LittleFS.open("/test.txt");
while (file.available()) {
Serial.write(file.read());
}
file.close();
Infine impostiamo il flashPin come pin di output e spegniamo il LED flash impostando il suo valore PWM a 0. Faccio questo perché scrivere sulla scheda SD accende automaticamente il LED flash, cosa fastidiosa. Il codice di test funziona anche senza queste due righe, ma non mi piaceva il flash negli occhi ogni volta che eseguivo il test.
pinMode(flashPin, OUTPUT); analogWrite(flashPin, 0);
Funzione loop
La funzione loop() è lasciata vuota, poiché tutto avviene nella funzione setup. Per rieseguire il programma devi resettare l’ESP32-CAM.
void loop() {
}
Output nel monitor seriale
Se tutto funziona correttamente, dovresti vedere le seguenti righe nel monitor seriale. Nota l’ultima riga con “*** Test successful ***”, che dimostra che siamo riusciti a scrivere e leggere dalla scheda SD.

Altri test
In alternativa puoi eseguire il test più complesso fornito con la libreria ESP32. Ha output di debug aggiuntivi, che potrebbero essere utili. Vedi lo sketch SDMMC_Test.ino. Lo stesso codice è disponibile negli esempi Sketch: File -> Examples -> Examples for AI-Thinker ESP32-CAM -> SDMMC -> SDMMC_Test.
Test della fotocamera
Dopo la scheda SD vogliamo testare la funzione della fotocamera. Il codice sotto è una versione semplificata di programmi più complessi. Ogni volta che l’ESP32-CAM si avvia (premendo il pulsante reset), scatta una foto e la salva sulla scheda SD.
Questo codice è specifico per il modello AI-Thinker ma funziona bene anche con altre schede camera basate su ESP32, purché abbiano PSRAM (vedi model definitions). Devi solo sostituire il pin definitions in base al tuo modello.
#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() {
}
Questo codice è un buon punto di partenza per casi d’uso più avanzati. Ad esempio, se vuoi scattare una foto quando un sensore di movimento o di luce viene attivato. Oppure se vuoi scattare foto a intervalli di tempo prestabiliti. Di seguito un po’ più di dettagli su come funziona questo codice.
Costanti e librerie
Per prima cosa includiamo le librerie necessarie come esp_camera.h, soc/rtc_cntl_reg.h, SD_MMC.h, e EEPROM.h. Queste librerie forniscono funzionalità per la configurazione della fotocamera, operazioni sulla scheda SD e uso della EEPROM.
#include "esp_camera.h" #include "soc/rtc_cntl_reg.h" #include "SD_MMC.h" #include "EEPROM.h"
Configurazione della fotocamera
La funzione configCamera() imposta i parametri di configurazione della fotocamera come canale LEDC, pin per le linee dati (D0-D7), XCLK, PCLK, VSYNC, HREF, SCCB SDA, SCCB SCL, PWDN, RESET e varie impostazioni della fotocamera come formato pixel, dimensione frame, qualità JPEG, ecc.
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);
...
}
Come detto, a seconda del tipo di fotocamera le definizioni dei pin possono cambiare. Inoltre, se non sei soddisfatto della qualità delle immagini, ci sono molti parametri con cui puoi giocare.
Funzione di incremento contatore
La funzione incCounter() legge e incrementa un valore contatore memorizzato nella memoria EEPROM. Recupera il conteggio attuale, lo incrementa, lo scrive di nuovo in EEPROM e restituisce il conteggio precedente.
unsigned int incCounter() {
unsigned int cnt = 0;
int adr = 0;
EEPROM.get(adr, cnt);
EEPROM.put(adr, cnt + 1);
EEPROM.commit();
return cnt;
}
Questo assicura che abbiamo un contatore progressivo per le foto scattate, anche dopo il reset dell’ESP32-CAM. Questo contatore viene anche usato per creare nomi unici per i file immagine che salviamo sulla scheda SD.
Se vuoi resettare il contatore, puoi caricare ed eseguire il seguente codice:
#include "EEPROM.h"
void setup() {
EEPROM.begin(512);
unsigned int cnt = 0;
int adr = 0;
EEPROM.put(adr, cnt);
EEPROM.commit();
}
void loop() {
}
Saltare le prime immagini
La funzione SkipPictures(n) cattura n immagini e le scarta. Il motivo è il seguente: la fotocamera ha diverse funzioni automatiche integrate, come il bilanciamento del bianco automatico, che richiedono tempo e diversi frame per adattarsi all’ambiente. Dopo un riavvio da deep sleep, dobbiamo quindi dare alla fotocamera un po’ di tempo per adattarsi.
void skipPictures(int n) {
for(int i=0; i<n; i++) {
camera_fb_t* fb = esp_camera_fb_get();
esp_camera_fb_return(fb);
}
}
Se scatti la prima immagine subito dopo un riavvio, noterai che è di pessima qualità. Tipicamente con una forte dominante blu, o troppo scura o troppo luminosa. Tuttavia, saltando i primi frame si ottengono per lo più (ma non sempre) immagini di buona qualità.
Potresti anche provare a disabilitare il bilanciamento del bianco automatico e altre funzioni automatiche nelle impostazioni della fotocamera, ma in tal caso devi avere un ambiente abbastanza stabile per poter regolare le altre impostazioni. Altrimenti sarà difficile ottenere immagini di buona qualità.
Acquisizione e salvataggio immagine
La funzione seguente cattura un’immagine usando la fotocamera e la salva su una scheda SD. Recupera un buffer frame della fotocamera, incrementa il contatore, crea un percorso file unico per l’immagine, scrive i dati dell’immagine nel file e libera il buffer frame.
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);
}
Nota che usiamo la variabile contatore per creare i nomi dei file. Se non ti piacciono i nomi dei file, questo è il punto dove modificarli.
Funzione setup
Nella funzione setup() disabilitiamo prima il brownout detector. L’ESP32-CAM è troppo sensibile a lanciare errori di brownout se l’alimentazione fornisce poca corrente all’avvio. Chiamare WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0) evita questo problema.
Poi inizializziamo la comunicazione seriale, avviamo la scheda SD, inizializziamo la EEPROM, configuriamo la fotocamera, scattiamo un’immagine e avviamo la modalità deep sleep. Questo significa che ogni volta che l’ESP32-CAM si avvia o resetta, scatta una nuova foto e la salva sulla scheda 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();
}
Funzione loop
La funzione loop() è vuota. Tutto avviene durante il setup e viene scattata una sola foto, dopo di che la scheda va in deep sleep e aspetta un riavvio.
Esempio Camera Web Server
Se vuoi un test che includa l’uso delle capacità WiFi dell’ESP32, l’esempio CameraWebServer è molto utile. Lo trovi sotto File -> Examples -> ESP32 -> Camera -> CameraWebServer.

Dovrai modificare leggermente il codice in CameraWebServer.ino. Per prima cosa devi definire il modello di fotocamera che stai usando. Assicurati che sia definito solo il modello che possiedi!
// =================== // 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
Poi devi inserire le credenziali WiFi della tua rete domestica:
// =========================== // Enter your WiFi credentials // =========================== const char* ssid = "**********"; const char* password = "**********";
Dopo aver caricato il codice e resettato l’ESP32-CAM dovresti vedere il seguente testo nel monitor seriale:

CameraWebServerNota l’ultima riga, che ti fornisce l’URL (indirizzo IP) a cui il WebServer è attivo. Copia e incolla questo URL nella barra degli indirizzi del browser e dovresti vedere il sito seguente, che trasmette le immagini della fotocamera dal tuo ESP32-CAM al browser.

CameraWebServer nel browser webE questo è tutto! Dovrebbe darti abbastanza informazioni ed esempi per iniziare con il modulo ESP32-CAM.
Se ti serve un esempio di codice più semplice su come trasmettere video, dai un’occhiata al tutorial Stream Video with ESP32-CAM. E per una fotocamera attivata dal movimento vedi il tutorial Motion Activated ESP32-CAM.
Riepilogo
Il modulo ESP32-CAM è una scheda bella e capace una volta che la fai funzionare. Tuttavia, caricare codice in modo affidabile è macchinoso. Spesso ho dovuto provare più volte e scollegare il cavo USB per farlo funzionare. In realtà, il metodo più affidabile è stato il seguente:
- Scollega il cavo USB
- Metti la scheda in modalità programmazione
- Collega il cavo USB
- Avvia il caricamento nell’Arduino IDE
Questo ha sempre funzionato e non richiedeva di premere il pulsante RST durante il caricamento. Per eseguire l’ESP32-CAM ho solo disabilitato la modalità programmazione e premuto reset. Non è stato necessario scollegare il cavo USB per questo. Solo per caricare un nuovo programma ho dovuto scollegare la scheda e ripetere i passaggi.
Un altro trucco che ho trovato è che rimuovere la scheda SD aiuta quando la scheda rifiuta di entrare in modalità programmazione. Questo succedeva spesso quando il codice precedentemente caricato usava la scheda SD.
Se hai difficoltà con la tua scheda ESP32-CAM, qui sotto ci sono alcuni link con informazioni aggiuntive e una lista di domande frequenti con risposte.
Infine, se cerchi una scheda che non richieda uno shield di programmazione separato o un programmatore FTDI per il flashing, dai un’occhiata al ESP32-WROVER CAM, che ha anche più GPIO liberi ma è più grande. Se ti serve una scheda molto piccola con microfono, ti consiglio la XIAO-ESP32-S3-Sense.
Buon divertimento a smanettare!
Link
Ecco alcuni link che ho trovato utili per iniziare con l’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
Domande frequenti
Ecco alcune domande comuni e soluzioni per aiutarti a risolvere problemi:
D: Perché il mio ESP32-CAM non si connette al Wi-Fi?
R: Controlla di aver inserito correttamente SSID e password nel codice. Assicurati che la rete Wi-Fi sia nel raggio d’azione e funzioni correttamente.
D: Come posso migliorare la qualità dell’immagine della fotocamera?
R: Regola le impostazioni della fotocamera nel codice per ottimizzare la qualità dell’immagine. Sperimenta con diverse risoluzioni e frame rate per trovare la configurazione migliore per il tuo progetto.
D: Come posso aggiungere più GPIO?
R: Puoi inizializzare l’interfaccia della scheda SD in modalità 1-bit, che libera due pin GPIO in più. Per maggiori dettagli vedi il tutorial More GPIO pins for ESP32-CAM.
D: Perché il mio ESP32-CAM non cattura immagini nitide?
R: Condizioni di illuminazione scarse possono influire sulla qualità dell’immagine. Assicurati di avere una buona illuminazione per la fotocamera. Regola le impostazioni della fotocamera nel codice per una qualità ottimale. Assicurati anche di aver rimosso la pellicola protettiva della lente.

D: Cosa devo fare se il mio ESP32-CAM non risponde ai comandi dal monitor seriale?
R: Controlla le impostazioni della comunicazione seriale nel codice e assicurati che la velocità di trasmissione (115200) sia impostata correttamente sia nel codice che nel monitor seriale. Verifica le connessioni tra la scheda ESP32-CAM e il computer.
D: Perché la mia scheda SD non viene rilevata?
R: Assicurati che la scheda SD sia inserita correttamente nello slot e formattata correttamente (FAT32). Controlla il codice per assicurarti che l’inizializzazione della scheda SD sia fatta correttamente. Schede da 4-16GB dovrebbero funzionare bene. Schede di capacità superiore possono causare problemi.
D: Il mio ESP32-CAM si scalda, è normale?
R: È normale che l’ESP32-CAM si riscaldi durante il funzionamento, ma se diventa eccessivamente caldo, controlla che non ci siano cortocircuiti o problemi di alimentazione.
D: Come posso ridurre il consumo energetico dell’ESP32-CAM?
R: Disabilita periferiche non necessarie e ottimizza il codice per minimizzare il consumo energetico. Considera l’uso delle modalità sleep per risparmiare energia quando la scheda non è in uso.
D: Perché le immagini scattate dall’ESP32-CAM hanno una dominante blu dopo un riavvio?
R: La fotocamera ha funzioni automatiche, come il bilanciamento del bianco automatico, che richiedono tempo per adattarsi all’ambiente. Senza questo, otterrai immagini con dominante blu o troppo scure o luminose. Un modo semplice per evitarlo è scattare diverse foto dopo un riavvio e ignorarle. Vedi la funzione skipPictures() nel tutorial che fa esattamente questo.
D: Perché il mio ESP32-CAM non cattura immagini?
R: Controlla che il modulo fotocamera sia collegato correttamente alla scheda ESP32-CAM. Assicurati che i pin della fotocamera siano cablati correttamente e che il modulo fotocamera sia supportato dal tuo codice.
D: Come posso trasmettere video dall’ESP32-CAM?
R: Implementa un server di streaming sull’ESP32-CAM usando librerie come ESP32-CAM-Webserver per trasmettere video via Wi-Fi. Assicurati che la tua rete possa gestire la larghezza di banda dello streaming video.
D: Perché il mio ESP32-CAM non viene riconosciuto dall’Arduino IDE?
R: Assicurati di aver installato il pacchetto di supporto per le schede ESP32 nell’Arduino IDE. Controlla il cavo USB e le connessioni della porta per garantire una comunicazione corretta con la scheda ESP32-CAM.
D: Perché il mio ESP32-CAM continua a mostrare “Timed out waiting for packet header” durante il caricamento del codice?
R: Questo errore può verificarsi a causa di una connessione USB lenta o instabile. Prova a usare un cavo USB o una porta diversa e assicurati che la scheda ESP32-CAM sia accesa e in modalità bootloader prima di caricare il codice.
D: Cosa devo fare se il mio ESP32-CAM si blocca durante il caricamento del codice?
R: Scollega il cavo USB, resetta la scheda ESP32-CAM e prova a caricare di nuovo il codice. Assicurati che il tuo codice non causi blocchi o crash durante il caricamento.
D: Posso caricare codice sull’ESP32-CAM in modalità wireless?
R: Sì, puoi caricare codice in modalità wireless sull’ESP32-CAM usando la programmazione OTA (Over-The-Air). Implementa la funzionalità OTA nel tuo codice e segui i passaggi necessari per caricare il codice senza connessione USB.
D: Perché il mio ESP32-CAM non entra in modalità bootloader per il caricamento del codice?
R: Controlla bene la connessione del pin GPIO0 a massa sulla scheda ESP32-CAM. Assicurati di premere il pulsante reset al momento giusto per entrare in modalità bootloader per il caricamento del codice.
D: Come posso risolvere l’errore “A fatal error occurred: Failed to connect to ESP32: Timed out waiting for packet header” durante il caricamento del codice?
R: Questo errore può verificarsi a causa di impostazioni errate della velocità di trasmissione o di un cavo USB difettoso. Prova a cambiare la velocità di trasmissione nelle impostazioni dell’Arduino IDE o usa un cavo USB diverso per stabilire una connessione stabile con la scheda ESP32-CAM.
D: Quali passi devo seguire se vedo “esptool.FatalError: Timed out waiting for packet header” durante il caricamento del codice sull’ESP32-CAM?
R: Questo errore può indicare un problema di timeout nella comunicazione tra computer e scheda ESP32-CAM. Controlla il cavo USB, la porta e le connessioni della scheda per eventuali problemi. Riavvia l’IDE, resetta la scheda e prova a caricare di nuovo il codice.
D: Cosa devo fare se vedo l’errore “Brownout detector was triggered”?
R: Questo errore di solito si verifica se l’alimentazione all’ESP32-CAM è insufficiente e causa un calo di tensione. Un circuito interno dell’ESP32 rileva questo problema, invia questo messaggio di errore al monitor seriale e resetta la scheda. Assicurati di alimentare l’ESP32-CAM dal pin 5V con un alimentatore che possa fornire 1A di corrente. Per maggiori informazioni vedi il nostro tutorial Fix brownout of ESP32-CAM.

