ARDUINO MEGA CON CD4059 (CD74HC4059)

 
    INTRODUZIONE
Data la scomodità di programmare il CD4059 con dei dip-switch ho deciso per questo scopo di utilizzare un microcontrollore, in particolare un Arduino Mega.
NOTA:
La programmazione può essere applicata sia al CD4059 che al CD74HC4059 allo stesso modo.

COME VA PROGRAMMATO  IL CD4059
Questo integrato è un divisore di frequenza programmabile che permettere di dividere da 3 a 15999 (N) la frequenza del segnale in ingresso, esso fornisce in uscita impulsi larghi un periodo del segnale d'ingresso con  frequenza pari a quella d'ingresso divisa N.
La formula su cui si basa il calcolo di N è la seguente:

N  = MODE * (preset valore) + resto  = MODE * (migliaia + centinaia + decine + unità) + resto

ed in particolare::

N =  MODE * ( D5 * 1000 + D4 * 100 + D3 * 10 + D2 * 1) + D1

Le due tabelle seguenti servono per il calcolo:



Ma partiamo subito con un esempio. Ammettiamo di volere che l'integrato divida per 5393.

N = 5393

in base a questo valore, tramite la colonna  DESIGN sotto  COUNTER RANGE scegliamo il mode, il valore scelto di N deve essere inferiore o uguale al massimo riportato in questa colonna. In questo caso possiamo scegliere tutti i MODE (evitare, se possibile, sempre il MODE 5 perché ci sono complicazioni circuitali con esso), decido per il MODE 2.
Nella colonna JAMP INPUT USED  sotto FIRST COUNTING SECTION con il MODE 2 abbiamo a disposizione per il resto (D1) solo J1, mentre nella colonna JAMP INPUT USED sotto LAST COUNTING SECTION abbiamo a disposizione  J2, J3, J4 (D5) per le migliaia del preset, gli altri gruppi di quattro bit hanno i seguenti significati:

D2 = unità del preset (
J8 J7 J6 J5)
D3 = decine del preset (J12 J11 J10 J9)
D4 = centinaia del preset (J16 J15 J14 J13)

Ricavo il preset valore:

preset valore = N / MODE = 5393 / 2 = 2696 con il resto di 1 (il resto lo si può calcolare anche con la calcolatrice di Windows, con il tasto "mod").

imposto quindi il resto a 1:

D1 = J1 = 1

imposto le migliaia, le centinaia, le decine e le unità  del preset:

D5 =  J4 J3 J2 = 2 = 010b (migliaia)
D4 = J16 J15 J14 J13 = 6 = 0110b (centinaia)
D3 = 9 =  J12 J11 J10 J9 = 9 = 1001b (decine)
D2 =  6 = J8 J7 J6 J5 = 6 = 0110B (unità)

ricapitolando la programmazione dei JAM (16 bit) è la seguente.

J16...J1 = 0110100101100101b

come conferma:

N =  MODE * ( D5 * 1000 + D4 * 100 + D3 * 10 + D2 * 1) + D1 = 2 * 2696 + 1 = 5963

i conti tornano.

ARDUINO MEGA ED IL PROGRAMMA


Per poter programmare il CD4059 è comodo usare un sistema a microcontrollore come, ad esempio, Arduino Mega. Ho utilizzato il modello Mega per la grande quantità di porte che ha a disposizione che in futuro potrebbero essere utilizzate per ampliare il presente progetto aggiungendo altre periferiche (ad esempio led, display, tastiere...). Arduino  deve essere programmato tramite il Serial Monitor per predisporre il divisore N del CD4059, basta collegare Arduino alla seriale, aprire il Serial Monitor, immettere il valore di N desiderato e premere invio. In risposta il programma stamperà sul monitor la scritta di avvenuta programmazione seguita dal  nuovo divisore N. Vedi foto successive (nell'esempio in foto il valore immesso è 3215):



Una volta che Arduino è stato programmato manterrà in EEprom i valori così impostati  e per l'utilizzo futuro, finché non si vorrà cambiare N, non servirà più il computer ed Arduino  potrà funzionare stand-alone assieme al CD4059. Comunque nel caso si dimentichi il valore di N programmato (magari perché si riprende in mano il sistema dopo un po' di tempo) basterà collegare Arduino di nuovo al computer con il Serial Monitor aperto e  resettarlo, sullo schermo apparirà il valore di N memorizzato seguito da quello del preset in formato binario. Vedi foto seguenti:


Quindi non dobbiamo fare nessun calcolo per conoscere i livelli logici da applicare ai JAM per avere un  certo N, ci pensa il programma che  fornisce immediatamente sulla  porta A e sulla porta C i livelli logici  appropriati per quel valore di N. I collegamenti tra Arduino e il CD4059 sono raffigurati nel disegno seguente:



NOTA:
nella foto all'inizio di questa sezione si vede Arduino collegato a dei led anzìché all'integrato divisore, questo perché nella fase della stesura del programma mi è stato più semplice leggere il dato direttamente sui led anziché fare letture di frequenza all'ingresso e all'uscita del CD4059.

FUNZIONAMENTO DEL PROGRAMMA
Immaginiamo che è la prima volta che carichiamo il programma in Arduino, ovviamente in EEprom non è stato  ancora scritto nulla ed essa contiene dati casuali, per il momento saltiamo a piè pari  la funzione void setup() e iniziamo ad analizzare  quella void loop(). La prima istruzione che incontriamo è una IF (riga  32), le istruzioni contenute in essa vengono eseguite  solo se viene immesso qualcosa nel  Serial Monitor, se non viene immesso nulla  il programma salta alla IF successiva (riga 47), le istruzioni contenute in essa vengono eseguite solo quando viene premuto il tasto che dopo vedremo  a cosa  serve, per il momento non la consideriamo, facciamo finta che il tasto non è stato premuto ed il programma, quindi, torna alla riga 32 e così seguita di  continuo   fintantoché non attuiamo una delle due azione descritte sopra.

Orai immaginiamo di immettere  nel Serial Monitor un valore N di nostro piacimento, ad esempio 3215, e premiamo enter (questa serie di caratteri, compreso l'invio, vengono memorizzati nel buffer della seriale). La IF alla riga 32  esegue ora la prima istruzione interna ad essa (riga 34)  la quale carica nel  registro BUF il primo carattere da noi immesso ovvero il 3. La successiva IF esegue le due istruzioni  (riga 37, 38) solo se il carattere contenuto in BUF corrisponde a quello dell'invio ('\r'), dato che il carattere contenuto è 3 le due istruzioni non vengono eseguite ma quelle sotto la ELSE si. La istruzione alla riga 42 moltiplica il registro DIVISOR per 10 e salva il risultato nel registro DIVISOR, ma dato che il registro DIVISOR è stato azzerato alla riga 2 il suo valore rimane  a zero.  La istruzione alla riga 43 converte il valore ascii del carattere 3 in valore numerico ( infatti il valore ascii del carattere 3 è  51, sottraendo ad esso 48 ottengo 3) ora il registro BUF contiene il valore 3 decimale.
La istruzione successiva (riga 44) somma il contenuto di BUF con quello di DIVISOR e salva il risultato nel registro DIVISOR, quindi ora quest'ultimo  contiene il valore 3 decimale. Il programma torna quindi alla riga 32 dato che non abbiamo premuto il tasto, Nel buffer della seriale il prossimo carattere è il 2 e le istruzioni (partendo dalla riga 34) si ripetono, ora però nel registro DIVISOR è contenuto il numero 3 decimale che moltiplicato per 10 diventa 30. Alla riga 44, dopo la solita conversione del valore ascii a valore decimale, viene sommato il numero 2 decimale (contenuto in BUF) con  quello contenuto in DIVISOR (ovvero 30 decimale), il risultato viene caricato in DIVISOR e questo ora contiene  il valore 32 decimale. Il programma esegue  le stesse operazioni fino a che in DIVISOR sarà presente il numero decimale 3215. Rimane ora un ultimo carattere nel buffer seriale  ovvero quello corrispondente al carattere invio ('\r'). La IF alla riga 35 legge  questo carattere ed esegue le due istruzioni appena sotto. Alla riga 37 c'è la chiamata alla funzione CALCOLO con argomenti DIVISOR e MODE.  

Nella funzione CALCOLO dalla riga 58 alla riga 64 ci sono le inizializzazioni delle variabili (ho l'abitudine di azzerare le variabili prima del loro utilizzo anche se spesso non serve), alla riga 65 viene  calcolato il PRESET, in questo caso PRESET = DIVISOR / MODE  = 3215 / 2 = 1607 (in questo programma il MODE è fisso e non si può cambiare a meno di fare sostanziali modifiche al programma stesso), nella riga 66 viene calcolato il resto (% significa modulo), RESTO = 1, nella riga 67 vengono calcolate le unità, UNITA = 5 (facendo il modulo di un numero per 10 si ottengono sempre le unità del numero stesso),  Nella riga 68 si divide il preset per 10, PRESET /10 = 321, nella riga 69 vengono calcolate le decine, DECINE = 1, nella riga 70 si divide ancora il preset per 10, PRESTET / 10 = 32, nella riga 71 vengono calcolate le centinaia, CENTINAIA = 2, nella riga 72 si divide ancora il preset per 10 PRESTET / 10 = 3 e si ottengono subito le migliaia, MIGLIAIA = 3.

Come spiegato nella sezione relativa al CD4059 con il MODE 2 i JAM riservati per le migliaia sono J2, J3, J4,  dato che il J1 è occupato dal resto (ovvero le migliaia ed il resto occupano i 4 bit bassi del byte basso, porta A) occorre spostare di un posto a sinistra il valore contenuto in MIGLIAIA, questo viene fatto con la istruzione alla riga 73 (operazione che servirà per dopo). Dato che le centinaia vengono rappresentate dai JAM J13, J14, J14, J16 ovvero nei quattro bit superiori al byte superiore (porta C) occorre spostare il valore delle centinaia di quattro posti a sinistra, i quattro posti a destra invece devono essere occupati dalle decine (J9, J10, J11, J12) allora basta effettuare una OR tra il registro CENTINAIA ed il registro DECINE, questa operazione viene effettuata dall'istruzione alla riga 75, il valor ottenuto è salvato nel registro BUFF e posto in uscita, sulla porta C nella istruzione successiva. Nella riga 77 lo stesso valore viene salvato nella EEPROM all'indirizzo 1.
Dato che le unità vengono rappresentate dai JAM J5, J6, J7, J8, ovvero dai quattro bit alti del byte basso (porta A) occorre effettuare una OR tra il resto le migliaia e le unità (le migliaia già erano state spostate alla riga 73), questa operazione viene effettuata dalla istruzione alla riga  79, il risultato viene memorizzato nel registro BUFF e nella istruzione successiva posto sulla porta A. Nella riga 81 lo stesso valore viene memorizzato nella EEPROM all'indirizzo 0. Le successive istruzioni stampano il valore N a schermo, l'istruzione alla riga 85 serve, come vedremo, nel caso che il tasto venga premuto. Il programma esce dalla funzione e va alla riga 38 dove viene azzerato il registro DIVISOR per predisporlo ad eventuali successivi calcoli.

Al reset o alla successiva accensione del sistema il programma esegue all'inizio le istruzioni contenute nella funzione void Setup(). Dalla riga 6 ala riga 9 in ordine, imposta la velocità della serale, pone la porta A come uscita, pone la porta  C come uscita, attiva il pull-up sull'ingresso 4  (tasto).
Dalla riga 10 alla riga 11 in ordine, legge i dati dalla EEPROM (precedentemente memorizzati in fase di programmazione) e li pone sulle porte corrispondenti, il CD4059 da questo momento in poi è programmato.
Come ho scritto all'inizio di questa sezione una volta resettato Arduino sul monitor si legge il valore N memorizzato, per fare questo il programma deve eseguire la istruzione alla riga 22, essa non è null'altro che la formula decimale per calcolare il divisore già vista nella sezione dedicata al CD4059. Per applicare questa formula bisogna però conoscere le migliaia, le centinaia, le decine , le unità ed il resto. Tutte queste quantità bisogna ricavarle dai valori memorizzati nella EEPROM.
Alla riga 12 viene memorizzato nel registro D1_D8 il contenuto della EEPROM all'indirizzo 0 (quello relativo al byte basso, porta A), in esso, ricordo, sono memorizzati, il resto, le migliaia e le unità. Il resto si può ricavare leggendo il bit 0 del suddetto registro tramite l'istruzione alla riga 13. Alla riga 14 viene memorizzato nel registro D9_D16 il contenuto della EEPROM all'indirizzo 1 (quello relativo al byte alto, porta C).
Nel registro D1_D4 vengono memorizzate le migliaia spostando di un posto a destra i dati contenuti nel registro D1_D8 (riga 15), dopo bisogna effettuare una and per azzerare i 4 bit superiori del registro D1_D4 (riga 16), in questa maniera in questo registro è contenuto solo il valore decimale 1 del preset (1607).
Per le centinaia si preleva il contenuto memorizzato nel registro D19_D16 e si effettua una and per azzerare i 4 bit più bassi (riga 17), l'istruzione alla riga 18 sposta a sinistra i 4 bit più alti in modo che nel registro D13_D16 sia presente il valore 6.
Dalla riga 19 alla riga 21 seguono operazioni simili a quelle appena descritte per le decine e per le unità ed il gioco è fatto, alla riga 22 il registro DIVISOR_1 conterrà il valore decimale N. Le istruzioni dalla riga 23 alla riga 28  servono per stampare a monitor il valore N e quello del preset in forma binaria. Il valore N viene anche memorizzato nel registro divisor_1 che serve per la routine  del tasto.

La funzione del tasto è quella di incrementare N di una unità. Ovviamente l'utilità di questo tasto è limitata dato che non viene implementato un limite (ovvero si può incrementare oltre  a N = 15999) e  non esiste la possibilità di decrementare. Ho inserito questa routine solo a titolo dimostrativo stimolando il lettore a modificarla per i propri scopi (per esempio aggiungendo un tasto per il decremento, inserendo il numero di step e così via).
Alla riga 47 troviamo la istruzione IF che esegue le istruzioni contenute in essa solo quando viene premuto il tasto (pin 4 a zero).  La prima istruzione alla riga 49 incrementa il registro DIVISOR_1 che contiene l'N attuale, alla riga 50 viene chiamata la funzione CALCOLO (che abbiamo già analizzato) con argomento DIVISOR_1 e MODE. Quando il programma ritorna dalla chiamata incontra, alla riga 51, l'istruzione WHILE e attende fintantoché il tasto rimane premuto, il ritardo di 600mS successivo serve per dare il tempo al livello di stabilizzarsi a +5V quando il tasto viene rilasciato (funzione anti rimbalzo).

Per finire alcune foto.

N= 3, frequenza ingresso 1 MHz (CH1,traccia superiore), segnale in uscita 333.333KHz (1MHz / 3, CH2, traccia inferiore):

 

N= 5, frequenza ingresso 1 MHz (CH1,traccia superiore), segnale in uscita 200 KHz (1MHz / 5, CH2, traccia inferiore):

 

N= 15, frequenza ingresso 1 MHz (CH1,traccia superiore), segnale in uscita 66.666 KHz (1MHz / 15, CH2, traccia inferiore):

 

Il file sorgente

Buon lavoro.
Fabio

HOME