Misura frequenza e induttanza

Ero indeciso se postare in hardware oppure in software, spostatelo dove ritenete sia meglio metterlo se non và bene quà in generale.
Ho provato le librerie FreqCounter e FreqMeasure con scarsi risultati, ho provato il metodo con pulseIn() alto o basso, sempre con risultati inattendibili.
Una volta che si conosce la frequenza, in un circuito LC o RLC parallelo o in serie, è possibile conoscere anche l'induttanza, tenendo fisso il condensatore.
In particolare a mè interessava leggere la reale induttanza di alcuni induttori che avevo costruito (per un metal detector) considerando il diametro del filo, il numero di spire, diametro induttore e la lunghezza totale e vedere se corrispondevano alle formule matematiche.
Online si trovano vari progetti per costruire un induttometro, ad esempio questo che fà anche una buona descrizione del funzionamento :

e che si basa poi nella misurazione del comando pulseIn()
In genere si basano sugli IC comparatori LM311 o LM 339, io ho ottenuto risultati migliori con LM311.
E qua metto un'immagine di LTSpice in cui si vedono il segnale in arrivo da Arduino, la sinusoidale generata dal circuito LC e il risultato all'uscita del comparatore.
Potete anche vedere i componenti utilizzati.


In blù il segnale di partenza proveniente da Arduino, in rosso la sinusoidale che si genera dal circuito LC e in azzurro il segnale che esce dal comparatore.
Come potete vedere, sin che il segnale della sinusoidale è sopra i 0 volt(non ho capito di quanto) il comparatore emette un segnale di onda quadra che facilita il nostro Arduino nella lettura di quanti segnali vengono emessi e a capire la distanza tra un segnale e il successivo.
Ma girando e leggendo le lamentele rispetto alle 2 librerie inizialmente menzionate, ho trovato una semplice soluzione che utilizza gli interrupt del Pin 2 e questa ha dato risultati decisamente migliori.
Bisogna prestare però molta attezione a quando cominciare la lettura di questi segnali, perchè il nostro LM311 amplifica anche i segnali di quando sale il segnale proveniente da Arduino e non solo quando scende, per cui il totale degli impulsi risulterebbe sbagliato.
Ho visto che attendendo 440 millisecondi dopo che il segnale proveniente da Arduino viene messo in off si ottiene una lettura precisa anche confrontandola con 2 oscilloscopi.
Se il circuito non fosse un circuito LC ma un oscillatore di Colpitts la cosa sarebbe più semplice, perchè basterebbe collegarlo ad una alimentazione fissa e lui continuerebbe a oscillare con la stessa intensità (non sarebbe una sinusoidale che và a zero una volta scaricato il condensatore), per cui utilizzando il timer potremmo capire quante oscillazioni esegue in un dato periodo, e più tempo dedichiamo al timer e più precisa sarebbe la lettura.
Ma il circuito di Colpitt richiede maggiore attenzione nei componenti utilizzati nella costruzione.
Purtroppo ho potuto verificare il funzionamento solo con induttori che vanno da 1000 uH a 3500 uH, non sò come si comporti con induttori minori o superiori a questi valori
Considerando che la tensione e la corrente vengono molto amplificate in un circuito LC (ho misurato anche 700 Volt non in questo circuito ma in uno per metal detector che partiva da un'alimentazione di 12 V e 40A partendo da 2A) ho scelto come condensatore un 1uF 250V che misurato mi dava 1.04uF.
Non ho messo una resistenza in uscita da Arduino per non impoverire la sinusoidale, ma cmq c'è un diodo prima di entrare nel circuito tank LC (che abbassa cmq la tensione di 0,5V e limita le oscillazioni avanti e indietro del circuito LC) e poi ho messo un diodo Zener per limitare l'eventuale uscita dal comparatore.
Ma se proprio volete stare sul sicuro potete usare un optoisolatore e inviare + tensione al circuito tank proveniente da una batteria ad esempio, per ottenere una sinusoidale + lunga nel tempo.
Se avete a disposizione induttori di cui conoscete la misura, postate pure i risultati quà.
E buon divertimento a tutti

// Connettere l'uscita del comparatore al pin 2 di Arduino (digital pin 2 on an Arduino Uno/Nano)
// per il segnale di start io ho utilizzato il Pin 10 che potete vedere in  digitalWrite(10, HIGH); e in  digitalWrite(10, LOW);

volatile unsigned long firstPulseTime;
volatile unsigned long lastPulseTime;
volatile unsigned long numPulses;
float inductance;
float capacitance = 0.00000104;  //Farad del condensatore utilizzato 1.04uF

void isr() {
  unsigned long now = micros();
  if (numPulses == 0) {
    firstPulseTime = now;
  } else {
    lastPulseTime = now;
  }
  ++numPulses;
}

void setup() {
  Serial.begin(115200);
  pinMode(10, OUTPUT);
}

// Measure the frequency over the specified sample time in milliseconds, returning the frequency in Hz
unsigned int readFrequency(unsigned int sampleTime) {
  numPulses = 0;                    // prime the system to start a new reading
  attachInterrupt(0, isr, RISING);  // enable the interrupt
  delay(sampleTime);
  detachInterrupt(0);
  return (numPulses < 2) ? 0 : (1000000UL * (numPulses - 1)) / (lastPulseTime - firstPulseTime);
}

void loop() {
  digitalWrite(10, HIGH);
  delay(5);  // carico il condensatore
  digitalWrite(10, LOW);
  delayMicroseconds(440);// <<<<<<< importante altrimenti vengoono conteggiati anche quando l'impulso sale
  unsigned int freq = readFrequency(1000);
  inductance = 1.0 / (capacitance * freq * freq * 4.0 * 3.14159 * 3.14159);// Farad
  inductance *= 1000000L;// uF
  Serial.print(freq);
  Serial.print(" Hz   Durata >> ");
  Serial.print((lastPulseTime - firstPulseTime));
  Serial.print("  Numero Impulsi >> ");
  Serial.print(numPulses);
  Serial.print("  Singolo Impulso >> ");
  Serial.print(((lastPulseTime - firstPulseTime) / (numPulses-1)));
  Serial.print(" uS   Induttanza L >> ");
  Serial.print(inductance,2);
  Serial.println(" uH");
  delay(1000);
}

Lascio aperto questo post perchè stò facendo la versione per ESP32 a giorni, con interfaccia grafica e anche generatore di forme d'onda con AD9833.
E lo schema sarà differente
Poi non capisco l'idea di chiudere il post dopo 6 mesi, visto che sia l'Ide di Arduino che le istruzioni di Espressif cambiano, oltre agli aggiornamenti delle librerie, sarebbe opportuno dare la possibilità di cambiare gli sketch, altrimenti si incappa in programmi che poi non funzionano con le versioni recenti

ESP32

Ok sono riuscito a fare una versione funzionante anche per ESP32 e direi anche precisa, modificando hardware e software.
Innanzitutto non possiamo usare LM311 perchè prevede un'alimentazione minima di 3.5 Volt, mentre ESP32 ha come massima uscita 3.3 V, per cui come comparatore di segnali ho utilizzato un LM393P.
Quà sotto riporto lo schema di LTSpice con inserite 2 immagini prese da un'oscilloscopio di quando si forma l'onda sinusoidale nel circuito CL tank e la successiva uscita dal comparatore.


L'oscilloscopio è un modello molto economico (FNIRSI1013D) che però mi ha aiutato molto perchè dispone di 2 ingressi, per cui nel primo ingresso (giallo) possiamo vedere l'impulso di partenza generato da ESP32, e nel secondo canale (azzurro/cyan) possiamo vedere il risultato rispettivamente nel circuito CL e sull'uscita del comparatore con la resistenza da 3Kohm.
L'oscilloscopio dispone anche di un salvataggio della forma d'onda e dei dati principali in un formato .wav che non c'entra niente coi file .wav audio, ma i cui dati corrispondono non alle tensioni misurate (purtroppo) ma alla posizione dei vari plot sullo schermo dell'oscilloscopio salvati in formato sia in big endian che little endian a seconda dei dati.
Trovando in parte online la spiegazione di come vengono trasmessi i dati ho potuto sviluppare un mio programma in .net dove posso vedere tutti i dati in arrivo dall'oscilloscopio (che non vanno ad occupare parte del display come avviene sull'oscilloscopio), scorrere a destra/sinistra la forma d'onda salvata(nei limiti del buffer salvato), trovare la frequenza e il periodo dell'onda sia in automatico che in manuale, inoltre clikkando con il mouse sul display può dirmi la tensione in quel punto a seconda del fattore ingrandimento salvato nel file .wav. e per ultimo può salvare i dati della forma d'onda in formato CSV per cui in formato testo utilizzabile in altri programmi.
Metto quà sotto uno screenshot del mio programma e se qualcuno ha lo stesso oscilloscopio ed è interessato mi contatti.

Ho realizzato anche un video su questo programma spiegando le differenze tra i dati provenienti dall'oscilloscopio e quelli reali della forma d'onda che ci interessa esaminare:

https://youtu.be/Kp6KP1_wTSg

Il circuito CL ha un induttore di 1400 uH circa con una frequenza di 1319 Hz e un periodo di 760 uS, e all'uscita del comparatore possiamo vedere un'uscita compresa tra -166 e +165 volt.
I 2 diodi schottky servono ad evitare rimbalzi verso ESP32 generati dal circuito CL, mentre il comparatore garantisce che non esca un'onda quadra verso ESP32 che superi 3.3V.
Ho scelto un condensatore da 10uF (Polipropilene Metallizzato) per avere come risultato un'onda sinusoidale con un periodo lungo, in modo che fosse più facile e più precisa la misurazione dei tempi.

Come metodo per rilevare la durata del ciclo e quindi la frequenza di oscillazione ho utilizzato sempre gli interrupt,ma a differenza dello schetck usato su Arduino Nano, quà ho utlizzato il comando :
attachInterrupt(17, isr, CHANGE); e non RISING che ha dimostrato maggiore precisione e falsi cambiamenti di stato.
Ma la precisione è aumentata nel momento che ho considerato solo i primi 2 segnali in arrivo dal comparatore e non tutti i segnali diviso per il tempo impiegato.
E questo si spiega facilmente, ovvero l'onda in arrivo è una sinusoidale generata dal circuito CL, per cui i primi segnali sono alti ma poi vanno decrescendo sino ad annullarsi, e questo fà sì che il comparatore generi un numero diverso di segnali variabili (tenendo conto che ho fatto le prove con alimentazione USB che non è stabile).
Per cui alla fine ottengo gli stessi risultati come frequenza uguali a quelli letti dall'oscilloscopio, e da quelli tramite formula e capacità del condensatore (il cui valore và misurato con un buon tester) si ottiene il valore dell'induttore.
Direi che è già un buon risultato.

// Connettere l'uscita del comparatore al pin 17 di ESP32
// per il segnale di start del circuito LC tank ho utilizzato il Pin 16 che potete vedere in  digitalWrite(16, HIGH); e in  digitalWrite(16, LOW);

volatile unsigned long Time1;
volatile unsigned long Time2;
double Periodo;
volatile unsigned long numPulses;
double freq;
double inductance;
double capacitance = 0.000001039;  //Farad del condensatore utilizzato 10.39uF

void setup() {
  Serial.begin(115200);
  while (!Serial)
    ;
  pinMode(16, OUTPUT);
  digitalWrite(16, LOW);  // 70nS da on a off e viceversa
  pinMode(17, INPUT);
  Serial.println("OK");
  delay(200);
}
void IRAM_ATTR isr() {
  unsigned long now = micros();
  if (numPulses == 0) {
    Time1 = now;
  } else {
    Time2 = now;
    detachInterrupt(17);// disattivo interrupt dopo il secondo segnale
  }
  ++numPulses;
}
void readTime() {
  // Opzioni: DISABLED RISING FALLING CHANGE ONLOW ONHIGH ONLOW_WE ONHIGH_WE (wake up the ESP32 from light sleep)
  attachInterrupt(17, isr, CHANGE);
  delay(5);
  //formula frequenza = 1 / Periodo
  Periodo = (float)(Time2 - Time1) * 2.0;
  freq = 1.0 / Periodo;
  freq *= 1000000.0;  // Hz
}

void loop() {
  numPulses = 0;
  digitalWrite(16, HIGH);
  delay(10);  // carico il condensatore
  digitalWrite(16, LOW);
  delayMicroseconds(30);  // <<<<<<< lasso di tempo tra fine segnale ESP32 e inizio oscillazione circuito CL tank
  readTime();
  inductance = (float)(pow(1.0 / (6.283185307 * freq), 2)) / capacitance;
  inductance *= 100000L;  // uF
  if (numPulses > 0) {
    Serial.print(freq, 2);
    Serial.print(" Hz   Periodo >> ");
    Serial.print(Periodo, 2);
    Serial.print(" uS   Impulsi >> ");
    Serial.print(numPulses);
    Serial.print("  Induttanza L >> ");
    Serial.print(inductance, 2);
    Serial.println(" uH");
  } else {
    Serial.println("Inserire induttore");
  }
  delay(2000);
}

Il ritardo dopo l'attivazione dell'interrupt:
attachInterrupt(17, isr, CHANGE);
delay(5);
Serve a dare il tempo di risposta dopo la disattivazione del segnale proveniente da ESP32, che sarebbe di 27us.
Come potete vedere in questo screenshot l'onda gialla del segnale è separata da quella azzurra della risposta.


e come potete vedere il risultato è molto stabile:
11:55:55.397 -> 1312.34 Hz Periodo >> 762.00 uS Impulsi >> 2 Induttanza L >> 1415.58 uH
11:55:57.368 -> 1312.34 Hz Periodo >> 762.00 uS Impulsi >> 2 Induttanza L >> 1415.58 uH
11:55:59.382 -> 1312.34 Hz Periodo >> 762.00 uS Impulsi >> 2 Induttanza L >> 1415.58 uH
11:56:01.428 -> 1312.34 Hz Periodo >> 762.00 uS Impulsi >> 2 Induttanza L >> 1415.58 uH
11:56:03.429 -> 1312.34 Hz Periodo >> 762.00 uS Impulsi >> 2 Induttanza L >> 1415.58 uH
11:56:05.408 -> 1312.34 Hz Periodo >> 762.00 uS Impulsi >> 2 Induttanza L >> 1415.58 uH
11:56:07.422 -> 1312.34 Hz Periodo >> 762.00 uS Impulsi >> 2 Induttanza L >> 1415.58 uH
11:56:09.453 -> 1312.34 Hz Periodo >> 762.00 uS Impulsi >> 2 Induttanza L >> 1415.58 uH
11:56:11.482 -> 1312.34 Hz Periodo >> 762.00 uS Impulsi >> 2 Induttanza L >> 1415.58 uH
11:56:13.487 -> 1312.34 Hz Periodo >> 762.00 uS Impulsi >> 2 Induttanza L >> 1415.58 uH
11:56:15.462 -> 1312.34 Hz Periodo >> 762.00 uS Impulsi >> 2 Induttanza L >> 1415.58 uH
11:56:17.473 -> 1312.34 Hz Periodo >> 762.00 uS Impulsi >> 2 Induttanza L >> 1415.58 uH
11:56:19.489 -> 1312.34 Hz Periodo >> 762.00 uS Impulsi >> 2 Induttanza L >> 1415.58 uH
11:56:21.535 -> 1312.34 Hz Periodo >> 762.00 uS Impulsi >> 2 Induttanza L >> 1415.58 uH
11:56:23.535 -> 1312.34 Hz Periodo >> 762.00 uS Impulsi >> 2 Induttanza L >> 1415.58 uH
11:56:25.517 -> 1312.34 Hz Periodo >> 762.00 uS Impulsi >> 2 Induttanza L >> 1415.58 uH
11:56:27.554 -> 1312.34 Hz Periodo >> 762.00 uS Impulsi >> 2 Induttanza L >> 1415.58 uH

Il prossimo passo è integrare questo progetto a un generatore di onde con AD9833 e un'interfaccia grafica

1 Like

Anzichè creare un'interfaccia su touch collegato ad ESP32, sto finendo un'app per visualizzare l'uscita/ingresso su Android collegato con BLE, modificabile (fatta con Mit app inventor), per cui si liberano pin su ESP32 e possiamo utilizzare anche un telefono vecchio (basta che abbia il bluetooth BLE) e risparmiamo energia per alimentare un touch collegato a ESP32....metto quà uno screenshot ma penso di aprire un altro articolo per parlare in dettaglio della cosa...ciaooooo

... purché non cadi nel cross-posting, aprendo un'altra discussione per parlare, alla fine, delle stesse cose :wink:

Guglielmo

ma no, questo post tratta di come costruire un lettore di induttanza sia con Arduino che con ESP32 (diversi come hardware e software), mentre quello che farò permette di visualizzare dati da ESP32 ma anche da Arduino dotato di BLE (che possono interessare vari progetti) direttamente su un telefono Android, ovvero senza aver bisogno di un touch screen dedicato su quel progetto, ovviamente andranno modificati sia la parte Mit inventor che lo sketch, ma cmq uno dispone già di una base funzionante che invia o riceve dati o pressione di tasti tra ESP32 e Android e a seconda del tasto o del dato in arrivo ESP32 esegue una routine o un'altra....ciaoooo

:+1: :+1: :+1:

Guglielmo