FREQUENZIMETRO DA 1 Hz A 45 MHz  CON ARDUINO MEGA

  

INTRODUZIONE
Con questo sistema, composto da Arduino Mega e da una manciata di integrati, è possibile leggere, su un display a cristalli liquidi, una frequenza da 1 Hz a 45 MHz, il limite massimo della frequenza che può essere letta  è dovuto ai contatori  che ho usato (in particolare il primo della catena, per il CD74HC4040 a 5V la massima frequenza tipica è circa 45 MHz).
Il compito di Arduino è solo quello di elaborare i dati che riceve, stamparli su display ed inviare un segnale di controllo al circuito,  per fare questo ha 1 sec. di tempo a disposizione, quindi Arduino non limita la massima frequenza che il sistema può leggere.

IL CIRCUITO



Lo schema a blocchi del circuito è il seguente:



Il segnale di frequenza incognita (FX) viene inviato ad un pin di una porta logica AND, sull'altro ingresso viene inviato un segnale a 0.5 Hz (segnale di GATE), sull'uscita si ha  una replica del segnale d'ingresso solo quando il segnale di GATE è a livello logico 1, quindi per un secondo il segnale d'ingresso giunge al pin CLK (sullo schema elettrico è chiamato P1) del contatore IC5. Ogni ciclo del segnale d'ingresso incrementa di uno il contatore, quindi il numero degli incrementi in un secondo corrispondono alla frequenza in Hz (100 incrementi = 100 Hz, 1000 incrementi = 1000 Hz e così via). Quando il contatore IC5 raggiunge il valore binario 111111111111 (corrispondente a 4095) al prossimo ciclo del segnale d'ingresso le sue uscite vanno a zero ma essendo IC5 collegato in cascata al secondo contatore  IC6 quest'ultimo incrementa di uno, quindi al 4096 ennesimo ciclo la situazione è la seguente: uscita IC6 = 000000000001, uscita IC5 = 000000000000, a sua volta quando IC6 raggiunge il valore binario 111111111111 al prossimo ciclo del segnale d'ingresso le sue uscite vanno a zero ma essendo IC6 collegato in cascata al terzo contatore  IC7 quest'ultimo incrementa di uno. Il massimo conteggio porta  tutte le uscite dei contatori  a 1, ovvero a
111 111111111111 111111111111 pari a 134.217.727 Hz che è  la teorica frequenza che il sistema potrebbe leggere, in pratica, però, questo non è possibile a causa dei limiti di velocità dei CD74HC4040 (in particolare di IC5), i contatori, infatti, a 5V riescono a gestire frequenze massime tipiche di 45 MHz.
Per avere un' ottima stabilità e precisione di misura occorre che il segnale di GATE sia a frequenza anch'essa stabile e precisa, questo è ottenuto dividendo la frequenza di 1 MHz di un  oscillatore quarzato per 1000000 (due divisori CD4059 in cascata da N = 1000 ciascuno) in modo che in uscita del secondo divisore sia presente un segnale a frequenza pari ad  1Hz. Dato che ne serve uno a 0.5 Hz con duty-cicle al 50 % (quello che esce dal divisore è un impulso di durata pari ad un ciclo della frequenza d'ingresso con frequenza pari alla frequenza d'ingresso / N) occorre inserire tra l'uscita del secondo divisore e l'ingresso della porta AND un FLIP-FLOP (IC3A).

NOTA:
per informazioni sul divisore CD4059 andare a questa pagina.

Quando il segnale di Gate va basso blocca il transito del segnale  d'ingresso verso IC5, i  contatori allora non incrementano più ma il loro ultimo valore rimane memorizzato sulle uscite, questo stato di inibizione del conteggio dura quindi un secondo.
Arduino non fa nessuna operazione fintanto che il segnale di GATE è alto, quindi per 1 secondo il programma su Arduino rimane il loop in attesa che il segnale vada basso. Quando questo succede Arduino legge i dati memorizzati alle uscite dei contatori, gli elabora, li stampa sul display e manda un impulso positivo sul pin RES (reset) dei contatori per azzerare le loro uscite. Quando il segnale di GATE torna altro il processo si ripete, avremo, quindi, una lettura di frequenza  ogni due secondi.
Qui sotto le temporizzazioni del sistema:


NOTA:
I tempi nella figura sopra non sono equiparabili tra i due segnali, il tempo di elaborazione, di stampa sul display e del reset sono stati enfatizzati per chiarezza del disegno.
Qui di seguito lo schema elettrico:

    IL PROGRAMMA
Alla riga 1 c'è l'inclusione della libreria "LiquidCrystal.h" che gestisce il display a cristalli liquidi. Alla riga 2 c'è la funzione che imposta i pin di Arduino per i vari segnali del display, in particolare "LiquidCrystal lcd(RS, E, DB4, BD5, DB6, DB7)".
Dalla riga 3 alla riga 10 ci sono le dichiarazioni delle variabili usate dal programma, sono tutte del tipo "long unsigned int" in modo che in esse possa essere memorizzato un numero fino a 4.294.967.295.
Nel "void setup()" alla riga 13 c'è l'istruzione che imposta il numero delle colonne e delle righe del display ("lcd.begin(colonne, righe)"), io ne ho usato uno a 16 colonne e 2 righe.
Alla riga 14 il programma setta il cursore del display alla colonna zero e alla riga zero.
Alla riga 15 il programma stampa "FREQUENZA" sul display.
Alla riga 16 il programma pone il pin 3 come uscita (reset contatori).
Alla riga 17 il programma pone il pin 2 come ingresso (segnale di GATE).
Alla riga 18 il programma manda a zero il pin 3 abilitando i contatori.
Nel "void loop()" la "IF" alla riga 22 non esegue il corpo fintanto il segnale di GATE è alto (pin 2), in questo stato, come abbiamo visto, i contatori sono attivi ed il programma rimane in loop senza fare nulla, appena il segnale di GATE va basso viene eseguito il corpo della "IF", dalla riga 24 alla riga 28 il programma legge, in ordine temporale, le porte A, D, C, L, G e salva i valori letti nei relativi registri.  Per chiarezza di spiegazione faccio un esempio, ammettiamo che il segnale da misurare abbia una frequenza di 20 MHz, il numero binario corrispondente è 0B1001100010010110100000000, in questa situazione i valori contenuti nei registri suddetti sono i seguenti (fate riferimento ai colori):

byte_basso_low =  0B00000000
byte_basso_high =  0B00001101
byte_alto_low =     0B00010010
byte_alto_high =     0B00000011
byte_extra_high  =  0B00000001

nella riga 29 il programma sposta a sinistra il contenuto del "byte_basso_low" di 8 bit, il risultato lo salva nello stesso registro:

byte_basso_high =  0B110100000000

nella riga 30 il programma somma i registri "byte_basso_high" e "byte_basso_low" ed il risultato viene salvato nel registro "byte_basso":

byte_basso = 0B110100000000 (non cambia nulla rispetto al registro "byte_basso_high" dato che per questa lettura il "byte_basso_low " è zero).
Nella riga 31 il programma sposta a sinistra il contenuto del "byte_basso_low" di 12 bit, il risultato lo  salva nello stesso registro:

byte_alto_low = 0B00010010000000000000

Nella riga 32 il programma sposta a sinistra il contenuto del "byte_basso_high" di 20 bit, il risultato lo  salva nello stesso registro:

byte_alto_high = 0B0000001100000000000000000000

nella riga 33 il programma somma i registri "byte_alto_high" e "byte_alto_low" ed il risultato lo salva nel registro "byte_alto":

byte_alto = 0B0000001100010010000000000000

Nella riga 34 il programma sposta a sinistra il contenuto del "byte_extra_high" di 24 bit, il risultato lo salva nello stesso registro:

byte_extra_high = 0B1000000000000000000000000

Nella riga 35 il programma esegue la somma dei registri "byte_basso", "byte_alto" e "byte_extra_high" ed il risultato lo salva nel registro "valore" come segue:

byte_basso =                                   110100000000 +
byte_alto =                  1100010010000000000000 +
byte_extra_high = 1000000000000000000000000 +
-------------------------------------------------------
valore =                 1001100010010110100000000

Nel registro valore adesso c'è il dato binario corrispondente a 20.000.000.
Nella riga 37 il programma cancella il testo sul display.
Nella riga 38 il programma stampa sul display  "FREQUENZA"
Nella riga 39 il programma posiziona il cursore alla colonna zero e alla riga 1.
Nella riga 40 il programma stampa sul  display il valore contenuto nel registro "valore".
Nella riga 41 il programma posiziona il cursore alla colonna 13 e alla riga 1.
Nella riga 42 il programma stampa sul display  "Hz"
Nella riga 43 e 44 il programma invia un impulso di reset ai contatori (pin 3).
Nella riga 45 il programma posiziona il cursore alla colonna zero e alla riga zero.
Nella riga 46 il programma attende fintantoché il segnale GATE (pin 2) è basso, quando esso torna alto il programma ritorna allo stato di loop.

Qui sotto i collegamenti tra Arduino e il display:


Qui sotto confronto di lettura tra il frequenzimetro con Arduino ed il  frequenzimetro JDS 6600:

 

    

Qui il programma

Ciao a tutti.
Fabio