G.F.A.rduino (Generatore di Funzioni Arbitrarie con Arduino)

GFA_rduino

Il progetto che vi presento è uno strumento da laboratorio indispensabile, un generatore di funzioni arbitrario. Piccolo di dimensioni ma con un grande potenziale grazie alla capacità di generare qualsiasi tipo di forma d'onda e con una precisione tale da poter regolare la frequenza a passi di 1 Hz o il Duty-Cycle a passi di 1%. Utile per calibrare strumenti di lettura o per gestire servomotori in robotica. Le regolazioni e le impostazioni sono gestite da un solo encoder rotativo e visualizzate tramite un display TFT a colori da 1,77 pollici.

Caratteristiche

Lo scopo principale che mi sono imposto durante la progettazione era di rendere questo strumento un dispositivo di facile utilizzo, eliminare tutti quei pulsanti per settare la forma d'onda o per impostare il range della frequenza e renderlo leggero per poterlo spostare comodamente tra casa e lavoro; obiettivo centrato in pieno utilizzando un Arduino UNO e un encoder rotativo. Tutti i comandi sono gestiti dalla rotazione e dal pulsante dell'encoder e per rendere l'utilizzo ancora più pratico, le regolazioni e le impostazioni sono visualizzate su un display TFT a colori di Arduino

Funzioni

Questo generatore è in grado di creare qualsiasi forma d'onda anche quelle con passaggio dallo zero, ossia in tensione duale. I segnali possono essere regolati in ampiezza fino a 15V picco/picco anche se tutto il circuito è alimentato con una tensione singola a 5V. Tra le onde memorizzate nello sketch troviamo: TTL; Sinusoidale; Triangolare; Rampa; Quadra. Il range della frequenza adoperabile parte da 1 Hz e si possono effettuare variazioni con passi a 1 Hz ma per velocizzare le regolazioni è possibile incrementare il fattore di moltiplicazione a 10X o a 100X. Per il segnale TTL, oltre alla frequenza, è possibile regolare in contemporanea anche il duty-cycle con passi da 1% per frequenza minore a 1500HZ o a passi del 10% con frequenza maggiori a 1500HZ.

Il circuito elettronico

Per la creazione della forma d’onda ho utilizzato un DAC tipo R2R ossia il TLC7524CN. Per non dilungarmi troppo rimando, per chi non conosce la tecnica della conversione digitale/analogico con scala R2R, a quest’articolo di EOSL’integrato TLC7524CN sostituisce la scala di resistenze ed è possibile scegliere riferimenti di tensioni sia per lo zero sia per il Vcc Max.

I comandi d’input sono collegati direttamente alla PORTA D dell’Atmega.
L’onda è generata con una risoluzione di 100 parti, ciò significa che il microcontrollore deve generare almeno un ciclo di 100 impulsi per creare un’onda a 1 Hz, pertanto dato che il limite di ON/OFF delle porte di Arduino è 100 KHz la frequenza massima dell’onda sarà di 1 Khz. Per aumentare il limite della frequenza ho optato nella riduzione della risoluzione dell’onda, realizzando un’equazione capace di ridurre la risoluzione in modo automatico man mano che incrementa la frequenza. Ho impostato come limite di Fmax a 5600 Hz perché ritenevo che a tale frequenza l’onda fosse abbastanza accettabile ma è possibile, cambiando un’impostazione nello sketch, aumentare ancora la frequenza sempre però a discapito della risoluzione.
L’onda in uscita generata dal DAC sarà amplificata dall'operazionale (LM358) in configurazione non invertente con un rapporto fisso, il trimmer R9 collegato al pin 2 è utilizzato per regolare la soglia massima di amplificazione.

Si noti, dallo schema, che tutta l’elettronica è alimentata da Arduino (5V) mentre tale l’operazionale è alimentato con una tensione maggiore (24V), per ottenere un’ampiezza del segnale fino a 15V picco/picco. Per erogare una tensione di 24V e rendere il circuito portatile ho deciso di utilizzare un DC-DC StepUp, anche questo dispositivo è alimentato da Arduino (5V) e genera una tensione in uscita regolabile fino a 30 V con corrente max di 500 mA (soglia massima di erogazione da Arduino). Un DC-DC StepUp può essere facilmente costruito con l'integrato LM2755 come da schema seguente:

Tuttavia ho scelto una versione già montata reperibile sulla rete a un prezzo modico.

Questa versione presenta un trimmer da 10 K per regolare la tensione in uscita, una volta impostata la tensione a 24 V il trimmer non verrà più utilizzato. Per variare l'ampiezza del segnale, invece, useremo il potenziometro da 10 K collegato al pin 1 del TLC7524CN, che regola il livello MSB dei dati sulla scala R2R. Invece per il segnale TTL ho utilizzato un transistor BC547 pilotato dal DAC, una soluzione per ottenere un segnale ben squadrato e con ampiezza di 5 V.

 

Regolazioni

Le regolazioni da compiere sono solo per l'amplificazione del segnale, eseguire i seguenti passi:

  1. regolare il trimmer del DC-DC StepUp per ottenere una tensione a carico di 24V;
  2. posizionare il trimmer dell'operazionale a metà corsa;
  3. avviare il generatore in modalità sinusoidale;
  4. con un oscilloscopio controllare la distorsione del segnale e correggerla col trimmer dell'operazionale;
  5. se l'onda presenta dei picchi superflui diminuire leggermente la tensione in uscita del StepUp, invece se l'onda risulta tagliata nell'estremità aumentare leggermente la tensione in uscita del StepUp.

Regolazione ultimata.

Elenco materiale utilizzato

1 – Arduino UNO
1 – Arduino LCD TFT 1,77"
1 – Encoder rotativo con pulsante
1 – DAC TLC7524
2 – Amp OP LM358
1 – Relè due vie 5V
N – materiale vario come resistenze, condensatori e transistor acquistabile presso conrad.it

Il programma

Il cuore del programma sta nell'utilizzo della funzione interrupt del Timer per pilotare i dati sulle porte D dell'Atmega collegato al TLC7524, per questo progetto ho scelto il Timer1 per i suoi 16 bit. L’interrupt è una routine di servizio (ISR – Interrupt Service Routine) al di fuori del programma originale che si avvia ad un specifico evento, in questo caso si avvia ogni volta che il contatore del Timer raggiunge una frequenza stabilita. A ogni evento d’interrupt, l’Atmega, invia sulla PORTD 1 delle 100 parti per la creazione dell’onda. Il registro per assegnare il valore da comparare al contatore del Timer è l’OCR1A (relativo al Timer1).
La formula di default è:

OCR1A = (16000000 / (prescaler * frequenza desiderata di interrupt)) -1

dove 16000000 è la frequenza di clock di Arduino.
In questo progetto invece la formula è stata impostata nel seguente modo:

OCR1A = (16000000 / (1 * (frequenza desiderata* 100))-1

Si noti che il prescaler è impostato a 1 e la frequenza è moltiplicata per 100 che sono le parti che compongono l'onda. Nello sketch risulta nel seguente modo:

OCR = (16000000/(Hz*K_Hz))-1;                       // riga n°164

Il valore di Hz è letto dall'encoder, la lettura avviene grazie ad una libreria creata da "Paul Stoffregen". Questa libreria conteggia il valore di rotazione dell'encoder in un contatore reso disponibile sia per la lettura tramite il comando:

Encoder.read();

sia per la scrittura, per impostare dei limiti, col comando:

Encoder.write(valore);

Per approfondire, ecco alcuni dettagli.

Dallo sketch si può notare che il ciclo fondamentale sono proprio queste due funzioni, la lettura dell'encoder e il settaggio del registro OCR1A.

void loop() {
encoder();
setting(Hz, K);
...}

Forma d'onda

Per la generazione delle forme d'onda ho realizzato quattro liste, una per ogni tipo di forma d'onda escluso il TTL.

byte sine[]= {127, 134, 142, 150, 158, ....};
byte triangle[] = {127, 132, 138, 143, .....};
byte saw[] = {255, 252, 250, 247, 245,....};
byte squar[] = {255, 255, 255, 255, ........};

Ogni lista è composta di 100 valori compresi tra 0 e 255. Dove 0 corrisponde a 0 V in uscita del DAC mentre 255 corrisponde a 5 V. È possibile creare una curva nuova rispettando però la condizione che lo zero del segnale corrisponda a 127, ossia a circa 2.5 V; questo permetterà di ottenere un segnale, grazie al condensatore di disaccoppiamento "C2", in tensione duale. È  consigliato sostituire la curva nuova con una di quelle già presenti.

Impostazione utente

Nello sketch ci sono alcune impostazioni che possono essere gestite dall'utente per personalizzare il progetto, come:

#define user_Hz_min 5               // Frequenza minima selezionabile
#define user_Hz_max 5600            // Frequenza massima selezionabile
#define user_Hz_start 100           // Frequenza iniziale dopo l'avvio del programma
#define Vmax_out 9.7                // Tensione max in uscita dall'ampl. operazionale
  • user_Hz_min: si può impostare il valore minimo della frequenza da selezionare con l'encoder;
  • user_Hz_max: si può impostare la frequenza massima regolabile con l'encoder. Di default è impostata a 5600, può essere aumentata ma a discapito della risoluzione dell'onda;
  • user_Hz_start: l'utente può impostare la frequenza d'inizio all'avvio del programma.

Regolazioni

Anche nel programma c'è una piccola impostazione da ultimare e riguarda la parte del Voltmetro. La lettura dell'ampiezza del segnale non avviene direttamente all'uscita dell'amplificatore operazionale LM358, una scelta fatta per evitare distorsioni del segnale e componenti aggiuntivi come inseguitori di tensioni. Ho preferito leggere la tensione al pin 1 del DAC che regola la soglia MSB dei dati, ovvio che la lettura non è reale ma conoscendo la tensione massima in uscita dell'amplificatore operazionale è possibile regolare lo script per ottenere un risultato preciso da visualizzare sul display. L'impostazione va settata inserendo il valore della tensione massima, letta con un multimetro, in uscita dall'amplificatore LM358 selezionando l'onda "Quadra". Tale valore deve essere inserito alla voce "Vmax_out" dell'impostazione utente.

I comandi

Tutte le impostazioni sono state divise in tre menù visibili sul display in tre sezioni, nel seguente modo:
1° sezione: Gestione frequenza (impostazione di default );

In questo menù, oltre alla regolazione della frequenza, si può impostare il fattore di moltiplicazione (1X, 10X o 100X).
2° sezione : Scelta forma d’onda;

In questa sezione si imposta la forma d'onda da generare.
3° sezione: Gestione Duty-Cycle (solo per TTL);

In quest'ultimo menù si regola il duty-cycle e la frequanza in contemporanea, valido solo per il segnale TTL.
Per passare da una sezione all’altra bisogna premere il pulsante dell’encoder e tenerlo premuto per almeno un secondo mentre per modificare la sezione scelta, bisogna premere una sola volta il pulsante dell’encoder. Tutte le scelte sono selezionabili in ordine come descritto sopra e a ripetizioni in loop. Quando si passa da una sezione all'altra il testo, della sezione scelta, cambia colore in giallo per indicare la possibilità di regolazione.

Realizzazione

Purtroppo per motivi di tempo non sono riuscito a realizzare uno stampato ma lo schema è stato disegnato con Eagle per tanto chiunque può crearne uno con pochi e semplici passaggi. Tra gli allegati sono presenti due librerie di Eagle, uno per il modulo Arduino e l'altro per l'encoder rotativo. Per chi volesse realizzare un PCB consiglio questa guida pubblicata su EOS.

Prossimamente

Il progetto può crescere e megliore, le idee per evolverlo sono tante come realizzare un applicazione con Processing per disegnare nuove curve e caricarle sul SD, presente sulla board del display, tramite la porta seriale di Arduino.

progetto in fase di lavorazione, disponibile al più presto nel prossimo articolo.

 

9 Comments

  1. adrirobot adrirobot 17 giugno 2014
  2. Ernesto.Sorrentino 17 giugno 2014
  3. Riccardo.Bertoglio 5 ottobre 2014
  4. Giorgio B. Giorgio B. 6 giugno 2014
  5. Ernesto.Sorrentino 6 giugno 2014
  6. Luigi.D'Acunto 11 giugno 2014
  7. Ernesto.Sorrentino 11 giugno 2014
  8. Luigi.D'Acunto 11 giugno 2014
  9. federico385 19 dicembre 2014

Leave a Reply