Sommario:

Contatore di frequenza ad alta risoluzione: 5 passaggi (con immagini)
Contatore di frequenza ad alta risoluzione: 5 passaggi (con immagini)

Video: Contatore di frequenza ad alta risoluzione: 5 passaggi (con immagini)

Video: Contatore di frequenza ad alta risoluzione: 5 passaggi (con immagini)
Video: Tutorial su come risolvere se il segnale di un televisore é debole o assente 2024, Dicembre
Anonim

Questo istruibile mostra un frequenzimetro reciproco in grado di misurare le frequenze velocemente e con ragionevole precisione. È realizzato con componenti standard e può essere realizzato in un fine settimana (mi ci è voluto un po' di più:-))

EDIT: il codice è ora disponibile su GitLab:

gitlab.com/WilkoL/high-resolution-frequency-counter

Passaggio 1: conteggio della frequenza della vecchia scuola

Conteggio della frequenza della vecchia scuola
Conteggio della frequenza della vecchia scuola
Conteggio della frequenza della vecchia scuola
Conteggio della frequenza della vecchia scuola

Il modo vecchia scuola per misurare la frequenza di un segnale consiste nell'utilizzare una porta logica AND, inviare il segnale da misurare in una porta e un segnale con un tempo di esattamente 1 secondo sull'altra porta e contare l'uscita. Funziona abbastanza bene per segnali di pochi kHz ben dentro i GHz. Ma cosa succede se si desidera misurare un segnale a bassa frequenza con una buona risoluzione? Supponiamo che tu voglia misurare la frequenza di rete (qui 50 Hz). Con il metodo della vecchia scuola vedrai un 50 costante sul tuo display se sei fortunato, ma più probabilmente vedrai il display passare da 49 a 50 o da 50 a 51. La risoluzione è di 1 Hz, e basta. Non vedrai mai 50.002 Hz a meno che tu non sia disposto ad aumentare il tempo di gate a 1000 secondi. Sono più di 16 minuti, per una singola misurazione!

Un modo migliore per misurare i segnali a bassa frequenza è misurarne il periodo. Prendendo nuovamente come esempio la rete, ha un periodo di 20 millisecondi. Prendi la stessa logica AND-gate, alimentala con, diciamo, 10 MHz (0,1 us impulsi) e il tuo segnale sull'altra porta e ne escono 200000 impulsi, quindi il periodo di tempo è 20000,0 uS e questo si traduce di nuovo in 50Hz. Quando misuri solo 199650 impulsi, la frequenza è 50,087 Hz, è molto meglio, ed è in appena un secondo di tempo di misurazione. Sfortunatamente questo non funziona bene con le frequenze più alte. Prendiamo ad esempio, ora vogliamo misurare 40 kHz. Con la stessa frequenza di ingresso di 10 MHz del riferimento, ora misuriamo solo 250 impulsi. Quando contiamo solo 249 impulsi il calcolo dà 40161 Hz e con 251 il risultato è 39840 Hz. Non è una risoluzione accettabile. Ovviamente aumentando la frequenza di riferimento si migliorano i risultati ma c'è un limite a quello che si può usare in un microcontrollore.

Passaggio 2: la via reciproca

La Via Reciproca
La Via Reciproca
La Via Reciproca
La Via Reciproca

Una soluzione che funziona sia per le basse che per le alte frequenze è un contatore di frequenza reciproco. Provo a spiegarne il principio. Inizi con un tempo di misurazione che è di circa 1 secondo, non deve essere molto preciso ma è un tempo ragionevole per una misurazione. Alimenta questo segnale da 1 Hz in un flipflop D sull'ingresso D. Non accade ancora nulla sulle uscite. Collega il segnale che vuoi misurare all'ingresso CLOCK del flipflop D.

Non appena questo segnale passa da BASSO ad ALTO, l'uscita del flipflop D trasferisce lo stato dell'ingresso D all'uscita (Q). Questo segnale RISING in corso viene utilizzato per iniziare a contare il segnale di ingresso e un segnale di clock di riferimento.

Quindi stai contando DUE segnali esattamente allo stesso tempo, il segnale che vuoi misurare e un clock di riferimento. Questo clock di riferimento deve avere un valore preciso ed essere stabile, va bene un normale oscillatore a cristallo. Il valore non è molto importante fintanto che è un'alta frequenza e il suo valore è ben noto.

Dopo un po' di tempo, diciamo qualche millisecondo, rendi di nuovo basso l'input D del flipflop D. Al successivo ingresso CLOCK l'uscita Q segue lo stato dell'ingresso, ma non succede nient'altro perché il microcontrollore è impostato per reagire solo ad un segnale RISING. Quindi, dopo che il tempo di misurazione è terminato (circa 1 secondo) si imposta l'ingresso D ALTO.

Di nuovo al successivo ingresso CLOCK segue l'uscita Q e questo segnale RISING attiva il microcontrollore, questa volta per terminare il conteggio di entrambi i contatori.

Il risultato sono due numeri. Il primo numero è il numero di impulsi contati dal riferimento. Poiché conosciamo la frequenza di riferimento, sappiamo anche il tempo impiegato per contare quegli impulsi.

Il secondo il numero è il numero di impulsi dal segnale di ingresso che stiamo misurando. Poiché siamo partiti esattamente sui fronti di SALITA di questo segnale, siamo molto fiduciosi sul numero di impulsi di questo segnale di ingresso.

Ora è solo un calcolo per determinare la frequenza del segnale in ingresso.

Un esempio, diciamo che abbiamo questi segnali e vogliamo misurare l'f-input. Il riferimento è 10 MHz, generato da un oscillatore al quarzo. f_input = 31,416 Hz f_reference = 10000000 Hz (10 MHz), il tempo di misurazione è di ca. 1 secondo

In questo tempo abbiamo contato 32 impulsi. Ora, un periodo di questo segnale richiede 1/31.416 = 31830.9 uS. Quindi 32 periodi ci hanno impiegato 1.0185892 secondi, che è poco più di 1 secondo.

In questo 1.0186 secondo avremo anche contato 10185892 impulsi del segnale di riferimento.

Questo ci dà le seguenti informazioni: input_count = 32 reference_count = 10185892 f_reference = 10000000 Hz

La formula per calcolare la frequenza risultante è questa: freq = (input_count * f_reference) / ref_count

Nel nostro esempio è: f-input = (32 * 10000000) / 10185892 = 31,416 Hz

E questo funziona bene sia per le basse frequenze che per le alte frequenze, solo quando il segnale di ingresso si avvicina (o addirittura superiore) alla frequenza di riferimento è meglio usare il metodo di misurazione standard "gate". Ma poi potremmo anche semplicemente aggiungere un divisore di frequenza al segnale di ingresso poiché questo metodo reciproco ha la stessa risoluzione per qualsiasi frequenza (fino al riferimento di nuovo). Quindi, se si misurano 100 kHz direttamente o divisi da un divisore esterno 1000x, la risoluzione è la stessa.

Passaggio 3: hardware e relativo schema

Hardware e il suo schema
Hardware e il suo schema
Hardware e il suo schema
Hardware e il suo schema

Ho realizzato alcuni di questo tipo di frequenzimetri. Molto tempo fa ne ho fatto uno con un ATMEGA328 (lo stesso controller che c'è in un Arduino), in seguito con i micro controller ARM di ST. L'ultimo è stato realizzato con un STM32F407 con clock a 168 MHz. Ma ora mi chiedevo cosa succede se faccio lo stesso con uno *molto* più piccolo. Ho scelto un ATTINY2313, che ha solo 2kbyte di memoria FLASH e 128 byte di RAM. Il display che ho è un MAX7219 con 8 display a sette segmenti, questi display sono disponibili su Ebay per soli 2 euro. Un ATTINY2313 può essere acquistato per circa 1,5 euro, il resto delle parti che ho usato costano solo centesimi al pezzo. La più costosa era probabilmente la scatola del progetto in plastica. Successivamente ho deciso di farlo funzionare con una batteria agli ioni di litio, quindi ho dovuto aggiungere uno stabilizzatore di tensione (LDO) da 3,3 V, un modulo di ricarica della batteria e la batteria stessa. Questo aumenta un po' il prezzo, ma immagino che possa essere costruito per meno di 20 euro.

Passaggio 4: il codice

Il codice
Il codice
Il codice
Il codice

Il codice è stato scritto in C con Atmel (Microchip) Studio 7 e programmato nell'ATTINY2313 utilizzando un OLIMEX AVR_ISP (clone?). Apri il (main.c) nel file zip qui sotto se vuoi seguire la descrizione qui.

INIZIALIZZAZIONE

Innanzitutto l'ATTINY2313 è stato impostato per utilizzare un cristallo esterno poiché l'oscillatore RC interno è inutile per misurare qualsiasi cosa. Uso un cristallo da 10 MHz che sintonizzo sulla corretta frequenza di 10 000 000 Hz con un piccolo condensatore variabile. L'inizializzazione si occupa di impostare le porte su ingressi e uscite, impostare i timer e abilitare gli interrupt e l'inizializzazione del MAX7219. TIMER0 è impostato per contare un clock esterno, TIMER1 il clock interno e anche per catturare il valore del contatore al fronte di salita di ICP, proveniente dal D-flipflop.

Discuterò il programma principale per ultimo, quindi le prossime sono le routine di interrupt.

TIMER0_OVF

Poiché TIMER0 conta fino a 255 (8 bit) e quindi passa a 0, è necessario un interrupt per contare il numero di overflow. Questo è tutto ciò che fa TIMER0_OVF, conta solo il numero di overflow. Successivamente questo numero viene combinato con il valore del contatore stesso.

TIMER1_OVF

TIMER1 può contare fino a 65536 (16 bit), quindi l'interrupt TIMER1_OVF conta anche il numero di overflow. Ma fa di più. Decrementa anche da 152 a 0 che impiega circa 1 secondo e quindi imposta un pin di uscita, andando all'ingresso D del flipflop. E l'ultima cosa che viene eseguita in questa routine di interrupt è diminuire il contatore di timeout, passando da 765 a 0, il che richiede circa 5 secondi.

TIMER1_CAPT

Questo è l'interrupt TIMER1_CAPT che viene attivato ogni volta che il flipflop D gli invia un segnale, al fronte di salita del segnale di ingresso (come spiegato sopra). La logica di cattura si occupa di salvare il valore del contatore TIMER1 al momento della cattura, viene salvato così come il contatore di overflow. Sfortunatamente TIMER0 non ha una funzione di cattura dell'ingresso, quindi qui viene letto il suo valore attuale e il suo valore attuale del contatore di overflow. Una variabile di messaggio è impostata su uno per il programma principale per dirgli che si tratta di nuovi dati.

Le prossime sono due funzioni per controllare il MAX7219

SPI

Sebbene nel chip sia disponibile un'interfaccia seriale universale (USI), ho scelto di non utilizzarla. Il display MAX7219 deve essere controllato tramite SPI e ciò è possibile con l'USI. Ma il bitbanging SPI è così semplice che non ho avuto il tempo di farlo con l'USI.

MAX7219

Anche il protocollo per configurare il MAX7219 è abbastanza semplice una volta letto il manuale di esso. Ha bisogno di un valore a 16 bit per ogni cifra che consiste di 8 bit per il numero della cifra (da 1 a 8) seguiti da 8 bit per il numero che deve visualizzare.

MAIN-PROG

L'ultima cosa è spiegare il programma principale. Funziona in un ciclo infinito (while (1)) ma in realtà fa qualcosa solo quando c'è un messaggio (1) dalla routine di interrupt o quando il contatore di timeout è sceso a zero (nessun segnale di ingresso).

La prima cosa da fare quando il messaggio variabile è impostato a uno, è azzerare il contatore di timeout, in fondo sappiamo che c'è un segnale presente. Il D-flipflop viene resettato per renderlo pronto per il prossimo trigger che arriverà dopo il tempo di misurazione (wait-a-second).

I numeri registrati nell'interrupt di cattura vengono aggiunti per fornire il conteggio di riferimento e il conteggio della frequenza di ingresso. (dobbiamo assicurarci che il riferimento non possa mai essere zero poiché lo divideremo in seguito)

Il prossimo è il calcolo della frequenza effettiva. Sicuramente non voglio usare numeri flottanti su un microcontrollore con solo 2kbyte di flash e solo 128 byte di ram. Uso interi. Ma le frequenze possono essere come 314.159 Hz, con diversi decimali. Pertanto moltiplico la frequenza di ingresso non solo con la frequenza di riferimento ma anche con un moltiplicatore, quindi aggiungo un numero a dove dovrebbe andare il punto decimale. Questi numeri diventeranno molto molto grandi quando lo fai. Per esempio. con un ingresso di 500 kHz, un riferimento di 10 MHz e un moltiplicatore di 100, questo dà 5 x 10^14, è davvero enorme! Non si adatteranno più a un numero a 32 bit, quindi uso numeri a 64 bit che arriveranno fino a 1,8 x 10 ^ 19 (che funziona bene su un ATTINY2313)

E l'ultima cosa da fare è inviare il risultato al display MAX7219.

Il codice viene compilato in circa 1600 byte, quindi si adatta alla flash da 2048 byte disponibile in ATTINY2313.

I registri dei fusibili dovrebbero essere così:

ESTESA 0xFF

ALTO 0xDF

BASSO 0xBF

Passaggio 5: accuratezza e precisione

Accuratezza e precisione
Accuratezza e precisione
Accuratezza e precisione
Accuratezza e precisione
Accuratezza e precisione
Accuratezza e precisione

Accuratezza e precisione sono due bestie separate. La precisione qui è di sette cifre, la precisione effettiva dipende dall'hardware e dalla calibrazione. Ho calibrato i 10 MHz (5 MHz sul punto di prova) con un altro frequenzimetro che ha un oscillatore disciplinato dal GPS.

E funziona abbastanza bene, la frequenza più bassa che ho provato è 0,2 Hz, la più alta 2 MHz. È a posto. Sopra i 2 MHz il controller inizia a perdere gli interrupt, il che non sorprende quando si sa che a 2 MHz il segnale di ingresso TIMER0 genera oltre 7800 interrupt al secondo. E l'ATTINY2313 deve fare anche altre cose, gli interrupt dal TIMER1, ad altri 150 interrupt al secondo e ovviamente fare i calcoli, controllare il display e D-flipflop. Quando guardi il dispositivo reale vedrai che uso solo sette delle otto cifre del display. Lo faccio per diversi motivi.

Il primo è che il calcolo della frequenza di ingresso è una divisione, avrà quasi sempre un resto, che non vedi perché è una divisione intera. Il secondo è che l'oscillatore al cristallo di quarzo non è stabilizzato in temperatura.

I condensatori che lo sintonizzano sui 10 MHz corretti sono ceramici, molto sensibili alle variazioni di temperatura. Poi c'è il fatto che TIMER0 non ha una logica di cattura incorporata e tutte le funzioni di interruzione richiedono del tempo per svolgere il loro lavoro. Penso che sette cifre siano sufficienti comunque.

Consigliato: