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.
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 sorgenteBuon lavoro.
Fabio