Semplice frequenzimetro con Arduino


Dopo aver fatto un pò di pratica con la misura degli intervalli di tempo, proveremo adesso a realizzare un frequenzimetro.
Considerando varie tecniche e possibilità, la soluzione più semplice è quella di effettuare una misura del periodo, cioè del tempo che impiega il segnale a compiere un certo numero di cicli completi.
Come si può misurare questo intervallo di tempo? Per esempio facendo due letture con la funzione millis(): la prima lettura corrispondente all'istante in cui viene intercettato l'inizio della fase HIGH del segnale, e la lettura finale all'inizio del primo stato HIGH successivo al numero di cicli che si è scelto di conteggiare.
Con i valori così ottenuti, il calcolo della frequenza è semplice: basta eseguire la differenza fra i valori trovati con le due letture millis() e dividere il tempo che risulta per il numero di cicli; dopo di che, l'inverso di tale valore darà esattamente la frequenza.
Come si vede nell'immagine che segue, il valore finale ottenuto risulta leggibile, come sempre, sul monitor seriale, la comoda finestrella che appare sullo schermo del PC quando è in funzione il software di Arduino.

valori di frequenza mostrati su monitor seriale di arduino

Dal punto di vista hardware, c'è poco da dire. Il segnale entra sul pin 7, appunto dichiarato come "input", naturalmente collegando al ground l'altro polo del cavo di entrata. La resistenza RIN da 1 kohm serve come protezione, nel caso di segnali aventi una tensione eccessiva.

cavo di entrata segnale su scheda arduino

In mancanza di un generatore di funzioni, ho provato a leggere un segnale a onda quadra, generato tramite un integrato NE555, e poi il segnale sinusoidale proveniente da un generatore autocostruito. Si trattava in entrambi i casi di frequenze audio (circa 1000 hz l'onda quadra e 400 Hz la sinusoidale), quindi non so fino a che frequenza sia possibile far funzionare il progetto. Posso dire comunque che i valori letti sul monitor corrispondevano esattamente a quelli che mi dava un frequenzimetro digitale collegato in parallelo.
Quanto alla sensibilità, è chiaro che se non si fa uso di un preamplificatore non è possibile attendersi dei miracoli: il valore minimo per una lettura affidabile risulta di circa 2,5 Vpp
Questo modo di misurare la frequenza ha una caratteristica un pò particolare: il valore presentato sul monitor seriale si aggiorna tanto più spesso quanto maggiore è la frequenza. Può apparire strano, ma è una logica conseguenza del metodo utilizzato: un segnale a bassa frequenza impiega più tempo a compiere un dato numero di cicli, e naturalmente la lettura è disponibile solo quando il contatore ha totalizzato tutti i cicli previsti.
Magari in un progetto futuro si potrebbe prevedere una miglioria, ovvero la possibilità di effettuare il conteggio su di un numero di cicli non fisso, ma selezionabile a piacere in funzione della frequenza da misurare.

Di seguito c'è il codice del progetto:
boolean state = 0;
boolean alert = 0;
unsigned int pulseCount = 0;
unsigned long time0 = 0;
unsigned long timeT = 0;
unsigned long frequency = 0;


void setup() {
pinMode(7, INPUT);
Serial.begin(9600);
}

void loop() {
state = digitalRead(7);

if (state == LOW) {
alert = 1;
}

if (state == HIGH && alert == 1 && pulseCount == 0) {
time0 = millis();
}

if (state == HIGH && alert == 1) {
pulseCount = (pulseCount + 1);
alert = 0;
}

if (pulseCount == 1000) {
timeT = millis();
frequency = 1000000/(timeT-time0);
Serial.print("frequenza = ");
Serial.print(frequency);
Serial.println(" Hz");
pulseCount = 0;
alert = 0;
}

}
Nelle prime sei righe di codice vengono dichiarate le variabili, il cui tipo viene scelto in funzione dei valori che devono contenere.
Per esempio, per le variabili "state" e "alert" è opportuno scegliere il tipo "boolean", che permette di memorizzare solo due valori logici (tipo "true" o "false", o ancora HIGH o LOW ovvero 1 o 0).
Il numero di impulsi da conteggiare è stato impostato al valore massimo di 1000, quindi va bene una variabile di tipo "unsigned int" (unsigned perchè dobbiamo memorizzare un valore positivo, e quindi non ci interessa il segno)
Invece per le letture effettuate tramite millis() è bene usare variabili di tipo "unsigned long"; la funzione millis() fornisce infatti il numero di millisecondi trascorsi dall'accensione della scheda, ed il valore può anche essere elevato.
Per la frequenza si poteva usare anche una variabile "unsigned int", ma il valore massimo che tale variabile può contenere è 65535; nel caso che si misurassero frequenze di valore più elevato, tale variabile non andrebbe più bene

Chi volesse provare a misurare la frequenza di rete, può costruirsi il circuito che segue, ovvero un "generatore" a 50 Hz. Lo schema, riportato qui sotto, può essere realizzato con componenti di fortuna:

schema generatore 50 hz da tensione di rete

Personalmente ho usato un trasformatore con secondario da circa 15 V; comunque, poichè non occorre potenza, va bene il più piccolo trasformatore che si riesce a trovare (trasformatori da 1 o 2 VA, magari di quelli incapsulati)
Servono poi D1, un diodo qualsiasi tipo 1N4007, una resistenza Rz da 470 ohm, un diodo zener (io ne ho usato uno da 7,5 V, perchè avevo solo quello) e un partitore di uscita, formato da Rp1 (1,5k) e Rp2 (2,2k).
Il valore di Rp1 va comunque adattato in funzione del trasformatore utilizzato e del voltaggio del diodo zener; ciò che conta è che il segnale in uscita sia inferiore a 5 Vpp.
Tenete presente che leggendo una frequenza di 50 hz, il valore appare sul monitor dopo 20 secondi! Quindi abbiate pazienza, e non pensate che il progetto non stia funzionando.

Nel caso qualcuno sia interessato a leggere anche piccoli segnali, dell'ordine di poche decine di mV, aggiungo lo schema di un semplice preamplificatore di segnale:

preamplificatore di segnale per frequenzimetro

Pensando che molti di coloro che fanno pratica con Arduino non hanno una eccessiva dimestichezza con l'elettronica, ho preferito uno schema di tipo "fotografico" che consentisse di capire con chiarezza quali collegamenti realizzare.
Il segnale entra sul condensatore C1 (punto IN). TR1 è un transistor darlington (BC517 o equivalenti) usato come inseguitore di emettitore, e garantisce un'alta impedenza allo stadio di entrata; questo è importante, per non alterare il segnale che si intende leggere. Il secondo stadio usa un BC547 con emettitore a massa; dal suo collettore viene prelevato il segnale amplificato (punto OUT) da mandare alla scheda Arduino. Il circuito funziona a 5 V, quindi può essere collegato alla scheda, senza che sussista il pericolo di inviare segnali di tensione superiore.
Valori dei componenti: C1 = 0,47µF; C2 = 1µF; R1 = 2,2Mohm; R2 = 4,7Mohm; R3 = 2,2kohm; R4 = 3,9Kohm; R5 = 150Kohm; TR1 = BC517 (o equivalenti); TR2 = BC547 (o equivalenti)


ebook "Introduzione all'elettronica"


Ritorna all'indice generale