Diodo ideale con Arduino.

Dialogo con Gemini.

Ciao vorrei sostituire il diodo ideale e il commutatore allo stato solido di un pacco batterie life 48V con un mosfet pilotato da Esp32. Hai dei suggerimenti?

Sostituire un diodo ideale o un commutatore con un MOSFET pilotato da ESP32 è un’ottima mossa per ridurre le cadute di tensione e avere il controllo totale via software.

Ecco i punti chiave per strutturare il circuito:

1. Scelta del MOSFET (Canale N vs Canale P)

  • Canale N (Consigliato): Più efficienti, economici e con  inferiore. Tuttavia, per interrompere il polo positivo (High-side), richiedono una tensione di gate superiore a quella della batteria (circa Vbatt. 10 V).
  • Canale P: Più semplici da pilotare sul positivo, ma scaldano di più e sono meno performanti per correnti elevate (comuni nei pacchi 48V).

2. Driver per il Gate

L’ESP32 eroga solo 3.3V, insufficienti per mandare in saturazione un MOSFET di potenza. Ti serve un Gate Driver:

  • Per il Canale N (High-side): Usa un driver con pompa di carica integrata (es. LTC7001 o IR2110). Questo genera internamente la tensione extra per aprire il MOSFET.
  • Per il Canale N (Low-side): Se puoi interrompere il negativo (più semplice), basta un driver come il TC4427 o un semplice traslatore di livello a transistor.

3. Protezioni Indispensabili

Lavorando a 48V (che a pieno carico arrivano a ~54V), non puoi trascurare la sicurezza:

  • Diodo di ricircolo (Flyback): Se il carico è induttivo (motori), è vitale per non bruciare il MOSFET ai distacchi.
  • Optoisolatore: Proteggi l’ESP32 usando un optoisolatore (es. PC817) tra il pin GPIO e l’ingresso del driver. Se il MOSFET salta, non distruggi il microcontrollore.
  • Dissipazione: Anche con bassa resistenza, calcola i Watt dissipati (). Un dissipatore o più MOSFET in parallelo sono spesso necessari.

4. Sensore di Corrente

Visto che usi un ESP32, potresti aggiungere un sensore ad effetto Hall (es. ACS758) per monitorare l’assorbimento e implementare un distacco software in caso di sovraccarico, emulando un fusibile intelligente.

Qual è la corrente massima (Ampere) che prevedi di gestire con questo pacco batterie?

La corrente media è di 10A, picco di 20 A, di apertura circuito oltre 30A. SI potrebbe monitorare anche la tensione del pacco. Potresti preparare uno schema di collegamento? Grazie!

Per gestire un pacco batterie da 48V con correnti di 10A (media) e 20A (picco), lo schema migliore prevede un MOSFET a canale N posizionato sul lato positivo (High-Side). Questa configurazione richiede un driver specifico per generare la tensione di gate necessaria (

).

Componenti Consigliati

  • MOSFET: Infineon IPT015N10N5 o simili (VDS > 80V, RDS(on) molto basso per evitare calore).
  • Gate Driver: Analog Devices LTC7001. È un driver specifico per switch statici high-side con pompa di carica integrata, perfetto per restare acceso indefinitamente.
  • Sensore Corrente: Allegro ACS758LCB-050B. Gestisce fino a 50A e isola galvanicamente la parte di potenza dall’ESP32.
  • Alimentazione ESP32: Un modulo Step-Down (Buck) DC-DC (es. basato su LM2596HV) per scendere da 48V a 5V. 

Schema di Collegamento (Logico)

1. Sezione di Potenza (High-Side Switch)

  • BAT+ (48V)  Drain del MOSFET.
  • Source del MOSFET  Ingresso del sensore ACS758  Carico+.
  • Gate del MOSFET  Collegato al pin TG del driver LTC7001.

2. Pilotaggio (LTC7001 & ESP32)

  • VCC (LTC7001): Alimentato a 12V (ottenuti da un piccolo regolatore o dallo stesso step-down se regolabile).
  • INP (LTC7001): Collegato a un GPIO dell’ESP32 (es. D21). Il driver accetta segnali a 3.3V.
  • TS (LTC7001): Collegato al Source del MOSFET

3. Monitoraggio (Sensori)

  • Corrente (ACS758):
    • Pin OUT del sensore  GPIO ADC dell’ESP32 (es. D34).
    • Nota: Usa un partitore di tensione se l’uscita del sensore (5V) supera i 3.3V dell’ESP32.
  • Tensione (Partitore):
    • Collega una resistenza da 100kΩ tra BAT+ e un nodo centrale.
    • Collega una resistenza da 4.7kΩ tra il nodo centrale e il GND.
    • Il nodo centrale va al GPIO ADC (es. D35). Questo riduce i ~54V a circa 2.4V, sicuri per l’ESP32.

Tabella dei Collegamenti Principali

Componente Pin SorgenteDestinazioneFunzione
MOSFETGateLTC7001 (TG)Comando di apertura/chiusura
LTC7001INPESP32 (GPIO 21)Segnale ON/OFF dal codice
ACS758VIOUTESP32 (GPIO 34)Lettura Ampere (analogica)
PartitoreCentroESP32 (GPIO 35)Lettura Volt (analogica)

Suggerimenti per la Sicurezza

  • Protezione Gate: Inserisci uno Zener da 12V-15V tra Gate e Source del MOSFET per proteggerlo da picchi transitori.
  • Fusibile: Anche se implementi un distacco software a 30A, un fusibile fisico da 40A è obbligatorio per sicurezza estrema.
  • Massa Comune: Assicurati che il GND dell’ESP32 e il polo negativo della batteria siano collegati (punto freddo). 

Vuoi che ti aiuti a scrivere una bozza di codice per gestire il distacco automatico oltre i 30A?

Si grazie.

Ecco una bozza di codice per l’ESP32. Il software monitora costantemente corrente e tensione, intervenendo come un fusibile elettronico ultra-rapido se i valori superano le soglie impostate.

cpp

// Pin Definition
const int PIN_MOSFET = 21;    // Comando al Gate Driver (LTC7001)
const int PIN_CORRENTE = 34;  // Output ACS758
const int PIN_TENSIONE = 35;  // Nodo centrale partitore

// Parametri di Taratura
const float SOGLIA_MAX_A = 30.0;     // Distacco immediato sopra 30A
const float TENSIONE_MIN_V = 40.0;   // Protezione scarica profonda (48V LiFePo4)
const float V_REF = 3.3;             // Tensione riferimento ESP32
const float ADC_RES = 4095.0;        // Risoluzione 12-bit

// Costanti Sensori (da affinare con test pratici)
const float SENS_ACS = 0.040;        // 40mV/A per ACS758 50B (controlla datasheet)
const float RATIO_PARTITORE = 22.27; // Rapporto per partitore 100k / 4.7k

void setup() {
  Serial.begin(115200);
  pinMode(PIN_MOSFET, OUTPUT);
  
  // Avvio in sicurezza: MOSFET spento
  digitalWrite(PIN_MOSFET, LOW);
  delay(1000);
  
  // Accensione sistema
  digitalWrite(PIN_MOSFET, HIGH);
  Serial.println("Sistema di Protezione Attivo");
}

void loop() {
  // 1. Lettura Tensione Batteria
  float vRaw = analogRead(PIN_TENSIONE);
  float tensioneBatt = (vRaw * V_REF / ADC_RES) * RATIO_PARTITORE;

  // 2. Lettura Corrente (Calcolo dello zero a 2.5V se alimentato a 5V)
  float iRaw = analogRead(PIN_CORRENTE);
  float vOutACS = (iRaw * V_REF / ADC_RES);
  // Nota: L'ACS758 a 0A eroga VCC/2. Se l'ESP32 legge tramite partitore, adegua l'offset.
  float corrente = abs((vOutACS - 1.65) / SENS_ACS); 

  // 3. Logica di Protezione (Safe Check)
  if (corrente > SOGLIA_MAX_A) {
    shutdownSistema("OVERCURRENT! - Distacco");
  }

  if (tensioneBatt < TENSIONE_MIN_V) {
    shutdownSistema("BATTERY LOW! - Distacco");
  }

  // Debug seriale ogni 500ms
  static unsigned long lastLog = 0;
  if (millis() - lastLog > 500) {
    Serial.printf("Volt: %.2fV | Ampere: %.2fA\n", tensioneBatt, corrente);
    lastLog = millis();
  }
}

void shutdownSistema(String motivo) {
  digitalWrite(PIN_MOSFET, LOW); // Spegne immediatamente il MOSFET
  while (1) {
    Serial.println(motivo);
    delay(2000); // Blocco di sicurezza, richiede riavvio fisico
  }
}

Note tecniche per la messa a punto:

  1. Offset Sensore: L’ACS758 eroga metà della sua alimentazione (es. 2.5V se alimentato a 5V) quando la corrente è zero. Poiché l’ESP32 accetta max 3.3V, dovrai usare un piccolo partitore sull’uscita del sensore e calibrare il valore 1.65 nel codice.
  2. Smoothing: Per evitare distacchi dovuti a picchi di rumore elettrico, potresti aggiungere una media mobile sulle letture (analogRead).
  3. Velocità: L’ESP32 è molto veloce, ma per una protezione “hardware” contro i cortocircuiti, il fusibile fisico resta comunque necessario.

Hai bisogno di indicazioni su come dimensionare il dissipatore per il MOSFET o su come alimentare l’ESP32 direttamente dai 48V?

e se volessi mettere un ulteriore mosfet in uscita ?

Se aggiungi un secondo MOSFET in uscita, solitamente lo fai per una di queste due ragioni: mettere i MOSFET in parallelo (per gestire più corrente e scaldare meno) o creare un interruttore bidirezionale (per bloccare la corrente in entrambi i sensi, come un vero relè).

Ecco come procedere nei due casi:

1. MOSFET in Parallelo (Per ridurre il calore)

Se vuoi semplicemente “rinforzare” il circuito per gestire meglio i picchi di 20-30A:

  • Collegamento: Collega il Drain del secondo MOSFET al Drain del primo, il Source al Source e il Gate al Gate.
  • Vantaggio: La resistenza totale () si dimezza. Se un MOSFET scalda a 10W, due MOSFET in parallelo scalderanno solo 2.5W ciascuno (perché la potenza dissipata è ).
  • Accortezza: Usa una piccola resistenza (es. 10 Ohm) su ogni singolo Gate prima di unirli al driver, per evitare oscillazioni.

2. Configurazione “Back-to-Back” (Protezione Totale)

Un singolo MOSFET ha un diodo parassita (body diode) interno. Questo significa che anche se il MOSFET è spento, la corrente può scorrere in una direzione (dal Source al Drain). Se vuoi che il circuito sia un vero isolatore (che blocchi anche la ricarica inversa non voluta), devi metterne due in serie con i Source in comune.

  • Collegamento:
    1. Batteria+ va al Drain del MOSFET 1.
    2. Il Source del MOSFET 1 va al Source del MOSFET 2.
    3. Il Drain del MOSFET 2 va al Carico.
    4. Gate sono collegati insieme e pilotati dallo stesso driver LTC7001.
  • Perché farlo: Questa è la configurazione usata nei BMS professionali. Impedisce alla corrente di fluire “all’indietro” verso la batteria o viceversa quando il sistema è spento.

Consigli Pratici

  1. Dissipazione: Con 10A continui, anche con un ottimo MOSFET, il componente diventerà caldo. Se usi due MOSFET in parallelo, potresti riuscire a lavorare senza un dissipatore ingombrante, usando solo il rame del PCB (se ben dimensionato).
  2. Il Driver: L’LTC7001 è perfettamente in grado di pilotare due o tre MOSFET in parallelo, poiché ha una corrente di picco sul gate molto robusta.
  3. Alimentazione ESP32: Per i 48V, ti consiglio un convertitore DC-DC step-down “High Voltage” (cerca quelli che accettano fino a 60-80V in ingresso), perché i comuni LM2596 economici esplodono sopra i 35-40V.

Quale delle due configurazioni ti interessa di più: aumentare la potenza (parallelo) o avere un blocco bidirezionale (back-to-back)?

In realtà vorrei usare un mosfet per la corrente di carica ed il secondo per prelevare corrente dal pacco…

Ottima idea. Questa configurazione trasforma il tuo circuito in un vero e proprio BMS (Battery Management System) a due canali indipendenti. Ti permette, ad esempio, di bloccare la scarica se la batteria è troppo bassa, pur continuando a permettere la carica.

Schema di Collegamento “Common Source”

Per gestire carica e scarica separatamente mantenendo i MOSFET sul lato positivo (High-Side), la configurazione standard prevede di unire i Source tra loro.

  1. MOSFET Scarica (Discharge):
    • Drain: Collegato al Polo Positivo Batteria.
    • Source: Collegato al Source del MOSFET di carica.
    • Gate: Pilotato dal Pin A (es. GPIO 21) tramite driver.
  2. MOSFET Carica (Charge):
    • Drain: Collegato al Caricabatterie / Ingresso Carica.
    • Source: Collegato al Source del MOSFET di scarica.
    • Gate: Pilotato dal Pin B (es. GPIO 22) tramite driver.

Nota: In questa configurazione, i diodi interni dei MOSFET sono contrapposti. Quando il MOSFET di scarica è spento, il suo diodo impedisce alla corrente di uscire, ma permette la carica. Viceversa per l’altro.

Cosa cambia nel Driver?

Dovrai raddoppiare la logica di pilotaggio. Hai due opzioni:

  • Usare due LTC7001 (uno per ogni MOSFET).
  • Usare un driver doppio come l’LTC7000 (che include anche il monitoraggio di corrente integrato).

Logica del Codice (ESP32)

Dovrai gestire due stati separati. Ecco come modificare la logica di controllo:

cpp

const int PIN_SCARICA = 21; 
const int PIN_CARICA = 22;

void loop() {
  float tensione = leggiTensione();
  float corrente = leggiCorrente(); // Positiva = Scarica, Negativa = Carica

  // LOGICA SCARICA
  if (tensione < 40.0) {
    digitalWrite(PIN_SCARICA, LOW); // Batteria scarica: stop prelievo
  } else {
    digitalWrite(PIN_SCARICA, HIGH);
  }

  // LOGICA CARICA
  if (tensione > 54.4) { // Soglia LiFePo4 piena
    digitalWrite(PIN_CARICA, LOW); // Batteria piena: stop carica
  } else {
    digitalWrite(PIN_CARICA, HIGH);
  }
}

Vantaggi di questa soluzione

  1. Indipendenza: Se hai un pannello solare o un caricatore sempre collegato, l’ESP32 può decidere di caricarla anche se hai spento l’uscita verso il carico.
  2. Protezione Inversa: Se colleghi un caricabatterie con polarità invertita, il MOSFET di carica (se spento) blocca il flusso proteggendo il pacco.
  3. Diodo Ideale: Pilotando correttamente i gate in base alla direzione della corrente (misurata con l’ACS758), puoi farli comportare come diodi a caduta quasi zero.

Ti serve aiuto per scegliere i pin specifici dell’ESP32 che non interferiscano con il boot (per evitare che i MOSFET si attivino accidentalmente all’accensione)?

Si grazie…

Scegliere i pin giusti sull’ESP32 è fondamentale: alcuni pin (chiamati Strapping Pins) emettono segnali PWM o cambiano stato durante l’avvio, il che potrebbe far “sfiammare” i MOSFET o attivare i carichi accidentalmente per qualche frazione di secondo.

Ecco i suggerimenti per i collegamenti e la gestione dei pin:

1. I Pin “Sicuri” da usare

Per pilotare i MOSFET (tramite i driver), ti consiglio di usare pin che rimangono Floating o LOW all’accensione:

  • GPIO 21 & GPIO 22: Sono pin eccellenti, solitamente usati per I2C ma configurabili come output digitali puliti.
  • GPIO 16 & GPIO 17: Stabili e privi di funzioni di strapping (disponibili sulla versione standard ESP32-WROOM).
  • GPIO 4 & GPIO 5: Generalmente sicuri.

Pin da EVITARE:

  • GPIO 0: Molto instabile all’avvio (usato per la modalità flash).
  • GPIO 2: Spesso collegato al LED di bordo e usato come strapping pin.
  • GPIO 12: Se forzato HIGH all’avvio, può impedire all’ESP32 di avviarsi se la tensione della flash è diversa (MTDI).
  • GPIO 15: Emette un segnale PWM all’accensione.

2. Schema di Sicurezza Hardware (Pull-Down)

Anche se scegli il pin giusto, durante i pochi millisecondi in cui l’ESP32 si avvia, i pin sono in alta impedenza. Per evitare che il gate driver capti disturbi e attivi i MOSFET:

  • Metti una resistenza di pull-down da 10kΩ tra il GPIO scelto e il GND. Questo garantisce che il segnale verso il driver sia rigorosamente LOW finché il codice non prende il controllo.

3. Assegnazione Consigliata

FunzionePin ESP32Note
MOSFET ScaricaGPIO 21Stabile, richiede pull-down 10k
MOSFET CaricaGPIO 22Stabile, richiede pull-down 10k
Lettura TensioneGPIO 35Solo Input (perfetto per ADC)
Lettura CorrenteGPIO 34Solo Input (perfetto per ADC)

4. Gestione dello “Zero” Corrente

Dato che l’ACS758 è un sensore bidirezionale, ti darà una tensione di uscita di circa 1.65V (se alimentato a 5V e partizionato per l’ESP32) quando la corrente è zero.

  • Se la lettura sale verso i 3.3V, la batteria si sta scaricando.
  • Se la lettura scende verso lo 0V, la batteria si sta caricando.

Un piccolo trucco software

Nel setup(), prima di attivare i pin come OUTPUT, assicurati di scrivere il valore:

cpp

void setup() {
  digitalWrite(PIN_SCARICA, LOW); // Pre-imposta lo stato
  digitalWrite(PIN_CARICA, LOW);
  pinMode(PIN_SCARICA, OUTPUT);
  pinMode(PIN_CARICA, OUTPUT);
  // Ora puoi decidere se accenderli dopo i controlli di sicurezza
}

Hai già scelto il modulo Step-Down per alimentare l’ESP32 dai 48V? È il componente più critico perché deve sopportare i picchi di tensione (fino a 60V) della ricarica.

Quale modello di Esp32 consigli?

Per questo progetto, ti consiglio l’ESP32-WROOM-32 (nella classica versione DevKit V1 a 30 o 38 pin).

Ecco perché è il modello ideale per il tuo caso:

  1. Pin ADC dedicati: Dispone di numerosi pin “Input Only” (GPIO 34, 35, 36, 39) che sono perfetti per leggere i sensori di tensione e corrente (ACS758) senza interferire con le funzioni digitali.
  2. Stabilità: È la versione più documentata e testata. Avendo a che fare con 48V e correnti elevate, la vasta community ti aiuta a trovare soluzioni pronte per i filtri software anti-rumore.
  3. Dimensioni: È abbastanza piccolo da stare in un case insieme ai MOSFET, ma ha pin sufficientemente distanziati per facilitare le saldature.

Un consiglio sulla versione specifica:

Cerca il modello con connettore USB-C (più robusto) e assicurati che sia il chip Dual Core. Il secondo core è utilissimo: puoi dedicare un core esclusivamente al monitoraggio di sicurezza “fusibile software” (che deve girare senza mai bloccarsi) e l’altro core alla gestione Wi-Fi/Bluetooth per vedere i dati sul telefono.

Nota sull’alimentazione:

Dato che userai un pacco 48V (che arriva a ~55V), l’ESP32 scalderà se il regolatore di bordo deve abbassare tensioni instabili. Ti suggerisco di accoppiarlo a un modulo Step-Down esterno di qualità (come quelli basati su LM2596HVS – la versione “HV” sta per High Voltage) tarato a 5V costanti da iniettare nel pin VIN dell’ESP32.

Vuoi che ti indichi anche un modello di regolatore step-down affidabile per i 48V?

Come faccio a gestire con il core separato il WiFi?

Per gestire il WiFi su un core separato, sfrutterai il sistema operativo FreeRTOS integrato nell’ESP32. Di default, Arduino usa il Core 1, quindi sposteremo la logica di controllo critico (MOSFET e sensori) sul Core 0.

Ecco come strutturare il codice:

1. Definizione dei Task

Creeremo due compiti distinti:

  • TaskSicurezza: Gira sul Core 0 (priorità massima). Si occupa solo di leggere i sensori e spegnere i MOSFET se necessario.
  • Loop Principale (WiFi): Gira sul Core 1. Gestisce la connessione, l’invio dei dati al telefono o al cloud.

2. Esempio di Codice Multicore

cpp

#include <WiFi.h>

// Definizione TaskHandle
TaskHandle_t TaskProtezione;

void setup() {
  Serial.begin(115200);
  
  // Configurazione Pin
  pinMode(PIN_SCARICA, OUTPUT);
  pinMode(PIN_CARICA, OUTPUT);
  digitalWrite(PIN_SCARICA, LOW); 

  // Creiamo il Task che girerà sul Core 0
  xTaskCreatePinnedToCore(
    LoopSicurezza,      // Funzione da eseguire
    "TaskProtezione",   // Nome del task
    10000,              // Stack size
    NULL,               // Parametri
    3,                  // Priorità massima (1-25)
    &TaskProtezione,    // Task handle
    0                   // Core 0
  );

  // Configurazione WiFi (girerà sul Core 1 di default)
  WiFi.begin("TuaRete", "Password");
}

// TASK CRITICO: Solo Sicurezza (Core 0)
void LoopSicurezza(void * pvParameters) {
  for(;;) { // Loop infinito del task
    float v = leggiTensione();
    float i = leggiCorrente();

    if (i > 30.0 || v < 40.0) {
      digitalWrite(PIN_SCARICA, LOW); // Spegnimento istantaneo
    }
    
    // Piccolo delay per cedere il controllo al sistema (fondamentale!)
    vTaskDelay(10 / portTICK_PERIOD_MS); 
  }
}

// LOOP STANDARD: WiFi e Log (Core 1)
void loop() {
  if (WiFi.status() == WL_CONNECTED) {
    // Invia i dati al tuo smartphone o server
    // Qui puoi mettere delay lunghi, non influenzeranno la sicurezza!
    Serial.println("Dati inviati via WiFi");
  }
  delay(1000); 
}

Perché questa struttura è fondamentale?

  • Indipendenza: Se il WiFi si blocca (ad esempio cercando di connettersi a un router spento), il Core 0 continua a monitorare la batteria. Senza multicore, il codice rimarrebbe fermo e non potrebbe spegnere il MOSFET in caso di sovraccarico.
  • Reattività: Il vTaskDelay(10) nel Core 0 assicura che il controllo avvenga ogni 10 millisecondi, rendendo il sistema estremamente veloce.
  • Condivisione Variabili: Puoi usare variabili volatile o Semaphore per passare i dati della tensione dal Core 0 al Core 1 per visualizzarli sul WiFi.

Ti interessa vedere come creare una piccola interfaccia web nell’ESP32 per leggere i Volt e gli Ampere dallo smartphone?

Proposta: Possiamo impostare un Web Server asincrono che non rallenta minimamente le prestazioni del microcontrollore.

E come possiamo realizzare il watch dog?

Per un sistema critico come un pacco batterie da 48V, il Watchdog Timer (WDT) è essenziale: se il codice si blocca per un disturbo elettromagnetico (generato magari dai picchi di corrente a 20-30A), il Watchdog riavvia l’ESP32 o spegne i MOSFET per sicurezza.

Nell’ESP32 abbiamo due livelli di protezione:

1. Watchdog Software (FreeRTOS)

Dato che stiamo usando il multicore, dobbiamo assicurarci che il Core 0 (quello della sicurezza) stia effettivamente girando. Se il Task di sicurezza si blocca, il Watchdog interverrà.

Ecco come aggiungerlo al codice precedente:

cpp

#include <esp_task_wdt.h>

// Definizione timeout (es. 2 secondi)
const int WDT_TIMEOUT = 2; 

void LoopSicurezza(void * pvParameters) {
  // Inizializza il Watchdog per questo Task
  esp_task_wdt_init(WDT_TIMEOUT, true); // true = riavvia l'ESP32 al timeout
  esp_task_wdt_add(NULL); // Aggiunge il task corrente al monitoraggio

  for(;;) {
    // --- Logica di controllo MOSFET ---
    float v = leggiTensione();
    if (v < 40.0) digitalWrite(PIN_SCARICA, LOW);

    // Se tutto è ok, "resetta" il timer del Watchdog (sfama il cane)
    esp_task_wdt_reset(); 

    vTaskDelay(10 / portTICK_PERIOD_MS); 
  }
}

2. Watchdog Hardware (Il “Fail-Safe” Estremo)

Se l’ESP32 dovesse bloccarsi con il pin del MOSFET su HIGH, la batteria rimarrebbe collegata anche in caso di emergenza. Per evitare questo, si usa un circuito di sicurezza hardware:

  • Il Condensatore di Accoppiamento: Invece di inviare un segnale statico (HIGH/LOW) al driver del MOSFET, l’ESP32 invia un segnale PWM (es. 10kHz).
  • Pompa di Carica/Filtro: Il driver del MOSFET viene attivato solo se riceve questa frequenza. Se l’ESP32 si blocca (su HIGH o su LOW), il segnale diventa statico, il condensatore si scarica e il MOSFET si spegne automaticamente per via hardware.

3. Gestione del “Safe State” al riavvio

Quando il Watchdog riavvia l’ESP32, vuoi sapere se è successo un crash. Puoi usare questo comando nel setup() per agire di conseguenza:

cpp

esp_reset_reason_t reason = esp_reset_reason();

if (reason == ESP_RST_WDT) {
  // Il sistema si è riavviato a causa del Watchdog!
  // Magari tieni i MOSFET spenti finché l'utente non preme un tasto
  Serial.println("ALERT: Riavvio da Watchdog rilevato!");
}

Suggerimento Pratico

Dato che lavori con 48V e 20A, il rumore elettrico sarà alto. Oltre al Watchdog, aggiungi un condensatore ceramico da 100nF vicinissimo ai pin di alimentazione dell’ESP32 e scherma i cavi dei sensori (tensione e corrente) per evitare letture errate che potrebbero far scattare il Watchdog inutilmente.

Vuoi che approfondiamo lo schema del filtro hardware per rendere il comando del MOSFET immune ai blocchi del software?

Prossimo passo consigliato: Definire la interfaccia web per monitorare i reset del Watchdog.

Si grazie sia filtro hardware che interfaccia web …

Ottimo, stiamo rendendo il sistema industriale e a prova di guasto. Ecco come gestire la sicurezza fisica (Filtro Hardware) e la visualizzazione remota (Web Interface).

1. Filtro Hardware: Il “Segnale di Vita” (Heartbeat)

Invece di pilotare il MOSFET con un segnale statico (HIGH), useremo un segnale PWM. Se l’ESP32 si blocca (su HIGH o LOW), il filtro hardware toglierà tensione al Gate del MOSFET, spegnendolo.

Circuito (Charge Pump semplificata):

  1. Pin ESP32  Resistenza 1k  Condensatore ceramico 100nF.
  2. Dal condensatore, colleghi un Diodo 1N4148 verso massa (catodo al condensatore) e un altro verso il driver del MOSFET (anodo al condensatore).
  3. Aggiungi una resistenza di pull-down da 100k e un piccolo condensatore da 10nF verso massa all’ingresso del driver.

Risultato: Il driver riceve tensione solo se il pin dell’ESP32 sta oscillando (PWM attivo). Se l’ESP32 si blocca, il segnale diventa statico e il driver si spegne fisicamente.


2. Interfaccia Web Asincrona

Useremo la libreria ESPAsyncWebServer perché non blocca il Core 1 durante le connessioni WiFi, permettendo al Core 0 di gestire la sicurezza in tempo reale.

Codice per il Server Web (Core 1):

cpp

#include <WiFi.h>
#include <ESPAsyncWebServer.h>

AsyncWebServer server(80);

// Pagina HTML in memoria Flash
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
  <title>BMS ESP32 Monitor</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>
    body { font-family: Arial; text-align: center; background: #1a1a1a; color: white; }
    .card { background: #333; padding: 20px; border-radius: 10px; display: inline-block; margin: 10px; }
    .value { font-size: 2em; color: #00ff00; }
  </style>
</head>
<body>
  <h1>Pacco Batteria 48V</h1>
  <div class="card"><h2>Tensione</h2><div class="value">%VOLT% V</div></div>
  <div class="card"><h2>Corrente</h2><div class="value">%AMP% A</h2></div>
  <script>
    setInterval(function() { location.reload(); }, 2000); // Refresh ogni 2s
  </script>
</body></html>)rawliteral";

// Funzione per sostituire i dati nel testo HTML
String processor(const String& var) {
  if(var == "VOLT") return String(tensioneGlobale); // Variabili globali aggiornate dal Core 0
  if(var == "AMP") return String(correnteGlobale);
  return String();
}

void setupWeb() {
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html, processor);
  });
  server.begin();
}


3. Logica PWM per il Filtro Hardware (Core 0)

Per far funzionare il filtro hardware, nel tuo Task di sicurezza invece di digitalWrite(HIGH), userai:

cpp

// Nel setup()
ledcSetup(0, 10000, 8); // Canale 0, 10kHz, 8 bit risoluzione
ledcAttachPin(PIN_SCARICA, 0);

// Nel task di sicurezza sul Core 0
if (tensioneOk && correnteOk) {
    ledcWrite(0, 127); // Duty cycle 50%: genera l'onda quadra per il filtro
} else {
    ledcWrite(0, 0);   // Spegne il segnale: il filtro hardware stacca tutto
}

Use code with caution.

Riassunto Architettura Finalizzata

  • CORE 0: Monitora Volt/Ampere e genera un segnale PWM da 10kHz. Se c’è un errore o un blocco, il PWM smette di oscillare.
  • FILTRO HW: Riceve il PWM e lo converte in tensione per il Gate Driver. Se il PWM sparisce, spegne il MOSFET meccanicamente.
  • CORE 1: Gestisce il WiFi e la pagina web, leggendo i dati dalle variabili globali senza mai disturbare il Core 0.

Vuoi che ti aiuti a creare una lista della spesa definitiva con i modelli precisi dei componenti per assemblare il prototipo?

Nota: Per il server web ti servirà installare le librerie ESPAsyncWebServer e AsyncTCP tramite il gestore librerie di Arduino.

Ho pubblicato l’articolo.

Ho visitato il tuo blog: il progetto è molto interessante e l’approccio “Diodo Ideale” con Arduino è un ottimo punto di partenza per chiunque voglia ottimizzare l’efficienza energetica nei sistemi a batteria. [1, 2]

Passare dall’implementazione con Arduino a quella con ESP32, come abbiamo discusso, porterà il tuo progetto a un livello superiore grazie a:

  1. Protezione Multicore: La separazione tra gestione WiFi e sicurezza (BMS) tramite i due core è un “plus” professionale che garantisce affidabilità estrema.
  2. Monitoraggio Remoto: La possibilità di vedere tensione e correnti di picco (fino a 20-30A) direttamente dallo smartphone tramite l’interfaccia web asincrona.
  3. Sicurezza Fail-Safe: L’aggiunta del filtro hardware PWM trasforma il software in un sistema “deterministico”, dove il MOSFET si spegne anche se il microcontrollore dovesse bloccarsi fisicamente.

Se deciderai di aggiornare l’articolo con la versione ESP32 Dual-MOSFET (Carica/Scarica), avrai un vero e proprio sistema di gestione batterie smart, ideale per applicazioni a 48V come accumuli solari o e-bike.

Pensi di creare un secondo post dedicato proprio all’evoluzione del progetto con la gestione bidirezionale e il controllo remoto?

Prossimo passo: Posso aiutarti a perfezionare i grafici in tempo reale (come quelli degli oscilloscopi) da integrare direttamente nella tua pagina web su ESP32.