Accendere o spegnere un LED con digitalWrite() è il primo esercizio con qualunque microcontrollore. Il passo successivo — farlo diventare più o meno luminoso in modo graduale, o controllare la velocità di un motorino DC — richiede il PWM (Pulse Width Modulation): un segnale digitale che si accende e spegne molto rapidamente, dove la percentuale di tempo "acceso" (duty cycle) determina la potenza media percepita dal carico.
Perché LEDC e non un semplice delay
Si potrebbe simulare il PWM a mano con delay() o delayMicroseconds(), ma occuperebbe la CPU al 100% e non reggerebbe frequenze utili per motori o audio. L'ESP32 ha invece un periferico hardware dedicato, LEDC (LED Control), che genera il segnale in autonomia: la CPU imposta i parametri una volta sola e il segnale continua a uscire dal pin senza ulteriore intervento del programma.
Configurazione base (Arduino core 3.x)
const int PIN_LED = 5;
const int FREQ_HZ = 5000; // frequenza del PWM
const int RISOLUZIONE = 8; // bit: 8 bit = valori 0-255
void setup() {
ledcAttach(PIN_LED, FREQ_HZ, RISOLUZIONE);
}
void loop() {
for (int duty = 0; duty <= 255; duty++) {
ledcWrite(PIN_LED, duty);
delay(10);
}
for (int duty = 255; duty >= 0; duty--) {
ledcWrite(PIN_LED, duty);
delay(10);
}
}
Con questo sketch il LED si accende e spegne gradualmente in un effetto "respiro" continuo, senza che la CPU debba gestire il timing del singolo impulso: se ne occupa il periferico hardware.
Scegliere frequenza e risoluzione giuste
- LED: 1-5 kHz bastano, l'occhio umano non percepisce lo sfarfallio già sopra i 100 Hz circa; risoluzioni a 8 bit (256 livelli) sono più che sufficienti per una dissolvenza fluida.
- Motori DC piccoli: 20-25 kHz evita il fastidioso fischio udibile che si sente a frequenze più basse (il motore stesso "canta" alla frequenza del PWM se questa cade nel range udibile).
- Servo motori: i servo standard non vogliono un PWM qualunque, ma un impulso specifico ripetuto ogni 20ms con larghezza tra 1 e 2 ms — per quello conviene usare la libreria
ESP32Servoinvece di configurare LEDC a mano, gestisce automaticamente i parametri corretti.
Attenzione al limite corrente dei pin GPIO
Il PWM controlla la potenza media, ma il pin dell'ESP32 può erogare al massimo circa 12-20mA in modo sicuro (dipende dal pin e dalla configurazione). Un motore DC anche piccolo assorbe molto di più: va sempre pilotato tramite un transistor o un driver dedicato (es. modulo con MOSFET, o driver L298N/DRV8871 per motori più grandi), mai collegato direttamente al pin GPIO. Il PWM va al gate/ingresso di controllo del driver, non al carico.
Un caso pratico: dimmer con controllo da web
Combinando LEDC con un piccolo web server (vedi il tutorial dedicato "ESP32 come Web Server") si ottiene un dimmer controllabile da smartphone in pochissimo codice:
server.on("/luminosita", HTTP_GET, [](AsyncWebServerRequest *request){
if (request->hasParam("val")) {
int val = request->getParam("val")->value().toInt();
ledcWrite(PIN_LED, constrain(val, 0, 255));
}
request->send(200, "text/plain", "OK");
});
Un dettaglio da non trascurare: valida sempre l'input ricevuto (qui con constrain()) prima di scriverlo sul PWM — un valore fuori range non danneggia l'hardware LEDC in sé, ma è buona norma non fidarsi mai ciecamente di un parametro arrivato da rete.