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