Un temporizzatore è
senz'altro utile in molte applicazioni. In laboratorio, ad esempio, per il
bromografo o per reazioni chimiche.
Vediamo come realizzarne uno, supportato da un microcontroller PIC.
Linee guida del progetto.
Si vuole ottenere un oggetto semplice, economico e facile da utilizzare.
Questa ultima caratteristica è solitamente quella chiave per tutte le
apparecchiature che devono prevedere una interfaccia che sia maneggiata da un
utente. Però, è normale che una facile manovrabilità da parte
dell'utilizzatore richieda una certa complessità dell'interfaccia.
Nel caso del nostro timer, il problema principale è quello di permettere
l'impostazione del tempo, in modo quanto più possibile intuitivo.
|
In questa direzione, l' uso di commutatori genere Contraves (nella
foro un componente Cherry, distribuito da
Conrad) consente una
impostazione del contatore immediata e nello stesso tempo mantiene la
selezione anche a sistema spento. E' la soluzione classica adottata nei circuiti a
logica cablata TTL/CMOS.
La gestione di questi commutatori non è problematica, anche se
richiede almeno quattro I/O più uno per ogni elemento. Avrebbero inoltre il
sensibile vantaggio che non occorre neppure un display ad indicare il tempo;
bastano un paio di LED.
A fronte di questi vantaggi, l'inciampo principale è costituito dal
costo assai elevato (8-10€ al pezzo). Se non ne avete in casa,
recuperati da qualche apparecchiatura, sicuramente la spesa di una
trentina di euro per tre di questi oggetti è eccessiva. |
Possiamo anche considerare l' uso di un tastierino a 12 tasti, ma anche in
questo caso abbiamo contro il costo e la necessità di disporre di un certo
numero di I/O, almeno 7 per la configurazione classica a matrice, il che fa lievitare le dimensioni del microcontroller; non che
ci siano problemi in tal senso: usando un package SMD, anche un 64 pin occupa
un paio di centimetri quadrati, ma diventa difficile saldarlo in un
laboratorio amatoriale, mentre il circuito stampato richiede una precisione
anche questa raggiungibile da pochi hobbisti.
Dobbiamo, allora, ripiegare sull'uso di pulsanti, complicando un poco la
vita all'utente.
E va considerato che meno pulsanti ha l' apparecchiatura, più complessa sarà
la gestione dell' interfaccia con l' utente.
Per quanto riguarda la presentazione del conteggio, ci orientiamo verso
l'impiego di tre display a sette segmenti; sarebbe possibile utilizzare anche
un piccolo LCD a caratteri, ma, se permette una
messaggistica estesa, ha costo e dimensioni non minimali.
Optiamo dunque per tre digit a 7 segmenti, comandati in multiplex per
ridurre il numero di pin del microcontroller
L'uscita sarà un relè con contatto di scambio (SPDT) o quant' altro serve
alla nostra applicazione, ad esempio un SSR.
Durante la definizione delle specifiche del timer sono state via via
aggiunti altri "optionals", non indispensabili al funzionamento, ma
utili nella pratica.
Così abbiamo un cicalino per avvertire dello scadere del tempo e un certo
numero di funzioni ausiliarie, come il test del carico collegato, una modalità
di hold per sospendere il conteggio, un pulsante di stop per annullarlo e
qualche memoria per salvare valori di conteggio di uso comune.
Tutto questo risulta gestibile senza eccessive complicazioni con solo
quattro pulsanti, a cui aggiungiamo LED di segnalazione.
Per cui le caratteristiche finali saranno queste:
|
- Countdown fino a 999s
- 3 display a 7 segmenti
- 4 pulsanti di programmazione
- 4 led indicatori, corrispondenti ad ogni pulsante
- Uscita con relè SPDT
- Cicalino di avviso fine conteggio
- 6 funzioni: - START/HOLD
- STOP/TEST
- ReCallMemory
- SETUP
- Alimentazione 12V cc/ca o 230Vca
|
Hardware.
Dopo aver definite le specifiche del progetto, scegliamo il microcontroller.
Occorrono 8 + 3 I/O per il multiplex del display, a cui vanno aggiunti altri
due I/O per relè e cicalino ed almeno un altro per i pulsanti. Un totale di
almeno 14 pin, il che permetterebbe l'impiego di un chip a 18 pin.
Ne scegliamo, invece, uno a 20 pin per avere un margine di sicurezza nel caso
si aggiunga qualche altra funzione durante lo sviluppo. La differenza di costo
e dimensioni è minima.
Ma quale PIC? Escludiamo decisamente qualsiasi chip obsoleto.
Intendiamoci: nulla vieta di utilizzare 16F84 o 16F876, ma non ha alcun
senso iniziare un nuovo progetto con i vecchi chip, che, tra l'
altro, finiscono per costare parecchie volte di più di un chip più recente
(e più performante). Inoltre, è molto opportuno non fossilizzarsi su alcuni
componenti e considerare quello che risulta dal continuo sviluppo della
tecnologia, in modo da essere costantemente aggiornati.
Occorre senz'altro la disponibilità di interrupt per la
gestione di varie task, oltre alla disponibilità di EEPROM per mantenere i
tempi programmati anche in mancanza di alimentazione.
La scelta si dirige sui PIC18FxxK, economici e potenti, oppure sui recenti Enhanced
Midrange, che hanno prestazioni notevoli e costi quanto mai limitati.
Ci indirizziamo su questi ultimi, anche per metterli alla prova in una
applicazione reale. Possiamo usare 16F1507/8/9, tre chip analoghi a 20
pin,
appartenenti ad un gruppo uniforme assieme a 12F1501 (8 pin) e 16F1503 (14
pin).
Date le caratteristiche simili, è possibile scrive un sorgente unico per i
tre chip, osservando che si differenziano per quantità di memoria integrata.
In effetti, 16F1507 è privo di USART e MSSP, ma queste funzioni non sono
previste nel progetto; la loro assenza e la ridotta quantità di memoria ne
fanno il chip meno costoso del gruppo, per cui è la scelta ottimale.
A questo punto possiamo stendere il disegno del circuito elettrico. Questa
è "l'unità centrale":
PORTC è dedicato ai segmenti dei display (7 + il dp), mentre gli
RB sono
utilizzati per comandare i catodi comuni (ovviamente è possibile implementare
anche display ad anodo comune, variando opportunamente il circuito).
I LED addizionali sono collegati anch'essi a catodo comune sul multiplex,
come "quarto" digit. Questo consente di minimizzare i pin richiesti.
Occorrono, quindi, quattro step, per comandare i 4 elementi.
Gli RB sono bufferati con transistor NPN (generici, tipo BC237, BC547, 2N4401,
2N3904, ecc).
Le basi hanno la corrente limitata da resistenze in serie (dipendente dal
guadagno dei transistor, ma, in generale, 4k7 è un valore adeguato). Si
possono sostituire i transistor BJT con MOSFET genere 2N7000, riducendo a 10
ohm o eliminando le resistenze di gate. Oppure, usando display a bassa
corrente (2mA/segmento, ovvero 16mA per gli otto LED contemporaneamente
accesi, il che non supera i 25mA limite dell' I/O) si potranno collegare i
catodi comuni direttamente agli I/O, con un ulteriore risparmio di componenti.
Resistenze di limitazione sono poste in serie ai pin che comandano i LED
(220-820 ohm a seconda della loro sensibilità).
I tasti sono collegati tra i pin di comando delle basi e un pin comune (in
questo caso RA3 o RA4), mantenuto a livello basso con un pull-down (10k). Se un
tasto è premuto nel momento in cui il relativo RB va a livello alto per
accendere il transistor collegato, questo livello si trova su RA3 e può essere
letto. Se il tasto non è premuto, si leggerà 0. I diodi in serie evitano
problemi nel caso in cui si premessero più pulsanti contemporaneamente.
Un connettore a 7 poli consente di collegare alimentazione, relè e
cicalino, posti su un'altra scheda, mentre, usato solamente per i primi sei
poli è un ingresso ICSP per collegare il Pickit (da osservare che per i
16F150x occorre il Pickit3).
In questo modo è possibile modificare il firmware senza togliere il chip
dalla scheda.
Ma non solo questo.
Il PIC utilizzati hanno il motore ICD integrato: questo consente il debug
in circuit direttamente attraverso il Pickit3, cosa estremamente utile durante
lo sviluppo e anche per la didattica e l' apprendimento.
La sezione di alimentazione è separata per varie ragioni: il circuito può essere alimentato con una
tensione già esistente e relè di
uscita e cicalino possono assumere forme diverse a seconda delle necessità dell'applicazione.
Quindi, come base generica, è stato realizzato un supporto del tutto tradizionale,
facilmente modificabile a seconda delle proprie esigenze:
Un piccolo trasformatore EI30 da 1.5/2VA con secondario 9V alimenta un comune
regolatore 7805 che produce la tensione stabilizzata di 5V per l' unità
centrale. La tensione non stabilizzata viene usata per alimentare un relè
SPDT.
Un jack coassiale consente di collegare in alternativa una tensione esterna,
cc o ca, da 9 a 12V, disponibile da una qualsiasi fonte in grado di fornire la
corrente necessaria al circuito (circa 30mA + il consumo del relè), ad
esempio un wall plug o una batteria veicolare.
Il cicalino è collegabile sia alla tensione del relè che a quella
stabilizzata, in modo da poter usare una ampia gamma di modelli.
I componenti sono del tutto comuni e per nulla critici.
TR1 |
EI30 9V |
R1,R2 |
4k7 |
D2 |
ponte 1A |
R3/R4 |
22K |
C1 |
1000uf/25V |
D1 |
1N4148, 1N4001 |
C2,C3 |
100nf |
JP1 |
pinhead 2.54, 7 poli |
C4 |
100uf/10V |
CN1 |
5 poli passo 5.08 |
VR1 |
7805 |
BZ |
Cicalino |
Q1,Q2 |
NPN |
Ry |
Relè 12V |
Potranno essere aggiunti condensatori spegni arco sui contatti del relè
Dal punto di vista costruttivo, entrambi i circuiti sono realizzati su
circuiti stampati a singola faccia, con un numero limitato di ponticelli, ma facilmente
riproducibili in casa:
e questo è il risultato:
Sull'unità centrale sono stati usati componenti SMD per i transistore e
per il condensatore da 100nF
Per l' alimentatore gli unici componenti SMD sono i due condensatori da 100nf
tra i pin del regolatore.
I due circuiti sono sovrapponibili, ottenendo un pacchetto molto compatto:
Le specifiche di funzionamento.
Il timer conta a ritroso per un massimo di 999 secondi, visualizzabili su un display a tre cifre a sette segmenti, ben leggibili in qualsiasi condizione di luce.
Un relè con contatto di scambio (SPDT) viene acceso all’ avvio del conteggio e spento al termine. Un cicalino avvisa l’ utente al termine del conteggio.
Sono disponibili quattro pulsanti di controllo:
Alcuni pulsanti possono assumere diverse funzioni a seconda della modalità
richiamata.
Ogni pulsante è associato ad un LED.
Il timer di dispone di alcune funzioni di base:
- START - il conteggio viene avviato. Al termine, il cicalino si
attiva, avvisando l' utente
- STOP - in qualsiasi momento il conteggio può essere annullato
Sono disponibili anche varie funzioni ausiliarie:
- HOLD – il conteggio è arrestato, mentre il relè è attivo; il timer rimane in stato di HOLD fino a che non viene premuto il tasto START o il tasto STOP.
Con il tasto START il conteggio riparte dal punto in cui era stato arrestato e con il tasto STOP il conteggio è annullato.
- TEST – a conteggio inattivo, la pressione di questo tasto consente si accendere il relè per verificare il carico collegato. Il relè è attivato fino a che il tasto è premuto.
- SET – consente di modificare il valore del conteggio
- RCM - consente di richiamare tre valori memorizzati
Operatività.
All’accensione, il display riporta il valore della memoria corrente.
Durante il conteggio il valore presentato si riduce di una unità ogni secondo.
I tasti possono avere più funzioni, a seconda della modalità attivata al momento.
La pressione dei tasti non attivi durante una determinata fase ha come effetto l’ emissione di un beep.
Il led relativo al tasto START, durante il conteggio, indica lo stato del relè: se acceso, anche il relè è acceso.
Al termine del conteggio, il cicalino è attivato e può essere tacitato con la pressione di un qualsiasi tasto.
All’ avviamento sono attivi i tasti:
- START – punto 1.
- TEST – punto 2.
- SET – punto 5.
- RCM – punto 6.
Funzione dei tasti.
1. AVVIO TEMPORIZZAZIONE – Tasto START
Se il valore presentato sul display è 000, premendo il tasto START si ottiene un beep; occorre passare al punto 5 e caricare un valore diverso da 0 per poter avviare il timer.
Se il valore presentato sul display è diverso da 0, premendo START il led relativo si accende, il relè viene attivato e inizia il conteggio alla rovescia.
Esaurito il conteggio, il display presenta 000, il relè viene disattivato e il cicalino inizia a suonare una volta al secondo.
Il cicalino viene tacitato premendo qualsiasi pulsante. Questo fa ricaricare il contatore con il valore iniziale, che appare sul display, mentre il timer è pronto ad una nuova operazione.
Durante il conteggio, qualsiasi tasto che non sia HOLD o STOP ha come solo effetto un beep.
2. TEST – Tasto TEST
Il suo scopo è quelle di azionare il relè per verificare il
funzionamento del carico collegato.
Se il conteggio non è avviato, il tasto STOP/TEST, quando premuto, porta in modalità test:
- il relè viene attivato
- si accende il led sul tasto START che indica l’ attivazione del relè
- il led sul tasto TEST lampeggia
- il display presenta il messaggio “tSt”
Questa condizione permane fino a che si mantiene premuto il tasto TEST. Al rilascio, i led si spengono e il relè viene disattivato.
Il display torna a presentare il valore della memoria di conteggio corrente.
3. SOSPENSIONE DEL CONTEGGIO – Tasto HOLD
La sua funzione è quella di sospendere momentaneamente il conteggio,
mantenendo il carico acceso.
Una volta avviato il conteggio (punto 1.), premendo il tasto START/HOLD, il timer entra in modo HOLD:
- il conteggio si arresta
- il led del tasto lampeggia una volta al secondo
- il relè resta attivato
Premendo ancora il tasto START/HOLD, il conteggio riparte dal punto in cui era stato arrestato e il led del tasto è acceso fisso. Se non si interviene ancora sui tasti, il conteggio si esaurisce come al punto 1.
Premendo, invece, il tasto STOP/TEST, il conteggio viene annullato, il relè è disattivato e tutti i led sono spenti. Il contatore si riposiziona con il valore iniziale, che appare sul display, mentre il timer è pronto ad una nuova operazione.
4. ANNULLAMENTO DEL CONTEGGIO – Tasto STOP
La sua funzione è quella di terminare il conteggio prima dell'
esaurimento del tempo.
Una volta avviato il conteggio (punto 1.), premendo il tasto STOP/TEST, il conteggio viene annullato, il relè è disattivato e tutti i led sono spenti. Il contatore si riposiziona con il valore iniziale, che appare sul display, mentre il timer è pronto ad una nuova operazione.
5. SETUP DEL CONTATORE – Tasto SET
La sua funzione è quella di consentire l' impostazione del tempo.
Se il conteggio non è attivo, la pressione del tasto SET porta il timer alla modalità di impostazione del valore del contatore.
Sono attivi i tasti:
- START/HOLD, corrispondente al display a sinistra (più significativo)
- STOP/TEST, corrispondente al display centrale
- RCM, corrispondente al display a destra (meno significativo)
Premendo uno di questi tasti, il punto decimale del display corrispondente si accende e il valore contenuto si decrementa di una unità. In questo modo è possibile aggiustare ogni singola cifra
assai rapidamente.
Una volta eseguita la modifica, la pressione del tasto SET consente di uscire dalla modalità di setup, mentre il nuovo valore viene memorizzato e sarà richiamato alla prossima accensione.
6. GESTIONE MEMORIE – Tasto RCM
Il timer dispone di tre tempi memorizzati che sono richiamabili quando il conteggio non è attivo. Uno di questi valori viene utilizzato come memoria corrente e sarà utilizzato ad ogni riavvio fino ad una diversa programmazione.
Le memorie sono accessibili premendo il tasto RCM; tutti i led dei tasti vengono accesi.
Sono attivi i tasti:
- START , corrispondente alla memoria 3
- STOP, corrispondente alla memoria 2
- RCM, corrispondente alla memoria 1
Premendo questi tasti, viene richiamato a display il valore della memoria relativa, mentre il led del tasto lampeggia. E’ possibile premere successivamente i tasti per visualizzare i valori salvati nelle memorie.
Una volta scelto il valore voluto, premendo il tasto SET due volte si copia questo valore nella memoria corrente ed esso viene trasferito al contatore e al display.
Se si desidera modificare questo valore, premere il tasto SET una sola volta: questo porta in modalità setup, come al punto 5.
Se si desidera modificare più di un valore, ripetere la procedura.
I valori modificati sono conservati nella memoria non volatile del processore anche quando il timer è spento.
Il firmware.
Per varie ragioni, diversamente dallo stile di questo sito, viene
rilasciato solamente il file .hex per programmare un PIC16F1507.
Nonostante questo, ci siamo impegnati a fornire comunque una serie di linee
guida e informazioni per consentire la creazione di un proprio sorgente.
Innanzitutto va detto chiaramente che questo è uno dei moltissimi casi in
cui, prima di scrivere una qualsiasi riga di istruzioni, occorre avere ben
chiaro cosa si vuole ottenere.
Occorre, pertanto, stendere il flow chart che descrive cosa il programma
dovrà fare; senza questo preliminare, scrivere istruzioni è del tutto
insensato.
Questo è il flow chart dell' interrupt:
Abbiamo a che fare con un programma di complessità non elementare, in cui
un interrupt viene utilizzato come elemento di tempo che ha lo scopo di
condizionare sia il ciclo de multiplex, ma anche l'intervento del cicalino, la
scansione dei tasti ed il loro debounce e il conteggio principale.
Il resto del programma dovrà gestire le funzioni legate ai tasti.
Come elemento di tempo è stato utilizzato il Timer0, con un ciclo di
interrupt a 4ms. Questo fa si che ogni digit e i LED ausiliari siano accesi
per 4ms ogni 16ms. La stessa cadenza è utilizzata per identificare i pulsanti
premuti. Dato che ogni pulsante è verificato ogni 16ms, questo tempo è anche
quello di debounce, che è più che adeguato per pulsanti di buona qualità.
Se proprio dove introdurre componenti scadenti con tempi di rimbalzo maggiori,
occorrerà allungare il tempo di debounce, ad esempio ad un doppio ciclo
(32ms) o più.
Non viene gestita la pressione di tasti multipli, che, comunque, nella
realizzazione fisica del pannello frontale, non facilmente ottenibile per
errore.
L' interrupt a 4ms alimenta un contatore da 100ms (25 x 4ms), usato per il
lampeggio dei LED e per il cicalino.
Inoltre, alimenta un contatore da 1s (250x4ms) per il countdown principale.
Alcuni flag hanno funzione di switch per attivare conteggio, lampeggio, buzzer.
La precisione del tempo dipende dalla precisione del clock interno, che il
foglio dati dichiara all'1%, il che è più che adeguato per l' applicazione,
senza ricorrere a cristalli esterni (nel peggior caso si tratta 10s su 16 minuti). Se si
desidera una precisione maggiore, è possibile agire in due modi:
- agire sul punto della routine di interrupt dove si collocano le
istruzioni di ricarica del TMR0. Spostandole in avanti si rallenterà,
aggiungendo cicli non compensati. Dovendo accelerare si userà un valore
minore di carica del contatore del timer e si sposteranno le istruzioni
fino a compensare il giusto valore di cicli.
- usare Timer1, che, essendo a 16 bit, consente un aggiustamento più fine
nel valore di carica di TMR1
Il ciclo relativo al programma principale consiste essenzialmente nell'
analisi dei tasti.
Ogni tasto, se premuto dopo la fine del conteggio, cancella il cicalino e
riporta al display il contatore corrente.
Il tasto START è attivo se il conteggio non è avviato. In tal caso, se il
contatore non è a zero, viene avviato il countdown e acceso il relè. Il LED
del tasto START è acceso.
Se il conteggio è attivo, il tasto assume la funzione HOLD, arrestando il
conteggio, senza spegnere il relè. Il LED del tasto START lampeggia.
Il conteggio riprende appena premuto ancora il tasto START oppure viene
annullato (e il relè spento) con il tasto STOP.
Una serie di flag è usata per identificare per ogni fase, quali LED
accendere, lampeggiare, ecc.
Il tasto STOP, se premuto al di fuori del conteggio, ha funzione di TEST:
fino a che è premuto, il relè è attivato e il display presenta il messaggio
"tSt". Il LED del tasto START è acceso, quello del tasto STOP
lampeggia.
Rilasciando il tasto, il relè e i LED si spengono e il display riprende and
indicare il contatore corrente.
Il tasto SET, ha, come gli altri, il compito di cancellare il cicalino a
fine conteggio e ripristinare il contatore.
Se premuto durante il conteggio, genera un beep.
Se premuto al di fuori del conteggio, introduce la funzione di setup.
Questa si ottiene con i tasti START, STOP e RCM che corrispondono ognuno ad un
digit. Quando premuti, il punto decimale del digit corispondente si accende,
per identificarlo con chiarezza, mentre il valore viene decrementato di uno ad
ogni pressione. In questo modo è possibile variare il contatore in pochi
istanti.
una nuova pressione del tasto SET memorizza il valore.
Il contatore è direttamente in BCD; questo permette di evitare la conversione
BIN->BCD e viceversa.
La funzione del tasto di richiamo della memoria è analoga, a fine
conteggio, a quella degli altri.
Se premuto durante il conteggio genera un beep.
Se premuto al di fuori del conteggio attiva la modalità di richiamo delle
memorie.
Si tratta di tre valori che sono conservati nella EEPROM. Ognuno corrisponde
ad uno dei tre tasti START/STOP/RCM.
Iil LED relativo al tasto premuto lampeggia e il display presenta il valore
della memoria.
Premendo SET, si passa alla fase di setup di questo valore. Se premiamo due
volte consecutive SET il valore diventa quello della memoria corrente in uso
nel contatore primario.
Enhanced Midrange.
Trasformare i flowchart in istruzioni e semplice, ma può esserlo meno se
si affrontano per la prima volta gli Enhanced Midrange, che creano subito
disorientamento negli utenti poco esperti, a causa di fogli dati di 400 e più
pagine.
Dispongono di un set impressionante di periferiche integrate, tra cui le
nuove, non presenti neppure nei PIC18F, oltre ad un set di istruzioni che
contiene opcodes che pure non esistono negli altri PIC a 8 bit.
L' elevato numero delle periferiche e delle funzioni fa si che l'area RAM sia
distribuita su ben 32 banchi, cosa che, di nuovo, mette a disagio il
principiante.
Va detto che si tratta di PIC come gli altri, da affrontare con le stesse
cautele e sicurezze del resto degli 8 bit: hanno i loro punti oscuri, ma
presentano anche diversi vantaggi.
Tra i problemi iniziali, il primo che i programmatore arriva ad affrontare
è quello del config iniziale, che, dato l' elevato numero di periferiche, è
suddiviso su due registri:
;####################################################################
;
CONFIGURAZIONE
errorlevel -303 ; suppress bogus CONFIG wordsize warning
; Oscillatore interno, no Clkout, no WDT, no CP, no MCLR
__config _CONFIG1,_FOSC_INTOSC & _CLKOUTEN_OFF & _WDTE_OFF & _MCLRE_OFF & _PWRTE_OFF & _BOREN_ON & _CP_OFF
; no WRT, no LVP, no STVREN, BOR LP
__config _CONFIG2,_WRT_OFF & _STVREN_OFF & _BORV_LO & _LPBOR_ON & _LVP_OFF
errorlevel +303 ; reenable wordsize warning
|
A causa di un bug dell' Assembler, è probabile che la compilazione generi
un errore di oversize del dato di configurazione. Poco male: basta
disabilitare il messaggio di errore, riabiltandolo poi in uscita.
E' uno dei pochi casi in cui errorlevel- è
utilizzabile sensatamente.
Mentre, invece, non va
assolutamente inserito il famigerato errorlevel-302.
Questo farebbe perdere i messaggi (che non impediscono la compilazione !) di
segnalazione relativi a registri che non sono in banco 0 e quindi si rischia,
per una qualsiasi piccola distrazione, di avere un programma che funziona in modo
insensato, problema difficile da debuggare senza le segnalazioni del banco.
Se proprio vi danno fastidio i warning nel listato e nella finestra di output,
prima ottenete un programma perfettamente funzionante, poi
potrete inserire l' errorlevel-302.
Un altro particolare che può impressionare è il numero di funzioni
concorrenti su uno stesso pin e, memori dei tranelli tesi da altri chip, ci si
può aspettare una dura lotta per arrivare alle semplici funzioni digitali:
Fortunatamente la situazione è meno grave del previsto: tutte le nuove
funzioni (CWG, CLC, NCO, PWM) e anche DAC e Vref non sono abilitate al POR.
PEr abilitarle occorre programmare i relativi registri. Quindi le possiamo
tranquillamente ignorare.
Restano le funzioni analogiche e in particolare gli ingressi del modulo
ADC, che vanno disabilitati agendo sui registri relativi:
; azioni in bank3
banksel ANSELA
; bank3
clrf ANSELA
; no input analogici
clrf ANSELB
clrf ANSELC |
Da considerare che i registri sono in banco 3.
Invece, lieta sorpresa, il comparatore (finalmente) NON è abilitato al POR
e quindi può essere ignorato.
Un particolare da considera, invece, è la frequenza dell' oscillatore
interno, che, per default al POR è 500kHz. Occorre modificare il default se
si desidera un diverso valore (anche se il programma può funzionare a
500kHz):
; clock 4MHz
movlw b'01101011'
movwf OSCCON
btfss OSCSTAT, HFIOFS ; wait for oscillator stable
bra $-1 |
OSCCON è in banco 1.
Il Timer0 è gestito dal solito OPTION_REG:
; azioni in bank1
banksel OPTION_REG ; bank1
; disabilita T0CKI da RB5, prescaler 1:16 al Timer0
; b'11111111'
; 1------- !WPUEN siailitato
; -1------ INTEDG rising
; --0----- clock interno
; ---1---- falling
; ----0--- prescaler al Timer0
; -----011 1:16
movlw b'11010011'
movwf OPTION_REG
; per 500kHz TMR0=4(6) prescaler 1 -> option 01010000 |
Gli Enhanced Midrange hanno il registro LAT dei port accessibile come i
PIC18F: questo permette di eliminare il problema R-M-W
che affligge Baseline e
Midrange. Purtroppo i LAT stanno in banco2 e se il programma opera normalmente
al di fuori, occorre agire sullo switch di banco, il che è un aggravio per l'
esecuzione. Si potrebbe pensare di mantenere l' esecuzione sul banco 2, ma i
registri PORT sono in banco 0 e dove è necessaria una lettura degli I/O, il
problema della commutazione dei banchi si ripresenta.
Nel nostro programma la soluzione è quella classica delle shadow, che, nello
stesso tempo, fungono da registri dei flag.
Lo stato dei tasti è analizzato durante la routine di interrupt, nello
step del relativo digit.
Ad esempio, per il digit 0, a cui è associato il tasto 0 (RCM):
; ---------------------------------------------------------
; display prima cifra LSdigit
Int_0:
; LSdigit
movf bcd1,w
; low middle counter
call SegTable
; converti in segmenti
btfss dp0
; check for dp
bra i_01
; =0 - no dp
iorlw b'10000000'
; =1 - add dp
i_01 movwf segmport
; in uscita
bsf digk0
; accendi digit
nop
bcf key0
; preset key flag
btfsc keyin
; key input=0?
bsf key0
; n - set flag
; reload digit counter
movlw digitnumber
movwf digitcntr
bra Int_end |
Il contatore principale è in BCD (2 bytes packed) e questo evita la necessità di avere una
conversione BIN>BCD e viceversa per passare il contatore la display.
Occorre, invece, la solita lookup table:
; segment data table - display catodo comune
SegTable
andlw 0x0F
; solo nibble basso
brw
retlw b'00111111' ; "0" -|-|F|E|D|C|B|A
retlw b'00000110' ; "1" -|-|-|-|-|C|B|-
retlw b'01011011' ; "2" -|G|-|E|D|-|B|A
retlw b'01001111' ; "3" -|G|-|-|D|C|B|A
retlw b'01100110' ; "4" -|G|F|-|-|C|B|-
retlw b'01101101' ; "5" -|G|F|-|D|C|-|A
retlw b'01111101' ; "6" -|G|F|E|D|C|-|A
retlw b'00000111' ; "7" -|-|-|-|-|C|B|A
retlw b'01111111' ; "8" -|G|F|E|D|C|B|A
retlw b'01101111' ; "9" -|G|F|-|D|C|B|A
retlw b'00000000' ; " " -|-|-|-|-|-|-|- Ah = blank
retlw b'01111000' ; "t" -|G|F|E|D|-|-|- Bh = t
retlw b'01010100' ; "n" -|G|-|E|-|C|-|- Ch = n
retlw b'01110001' ; "H" -|G|F|E|-|C|B|- Dh = H
retlw b'01111001' ; "E" -|G|F|E|D|-|-|A Eh = E
retlw b'01101101' ; "S" -|G|F|-|D|C|-|A Fh = S |
che permette di presentare sia le cifre decimali cha alcuni caratteri.
Da notare l' uso dell'opcode brw al posto
del solito addwf PCL,f.
I contatori sono salvati in HEF, la EEPROM dei PIC più recenti.
Sull'argomento, trovate maggiori
informazioni qui.
L'unico neo della HEF è il fatto che costringa a lavorare su una intera riga (in questo caso
di 32
bytes) anche se ne vanno salvati solo 8. Comunque, i meccanismi di scrittura e
di movimentazione di array di dati sono efficienti e nel chip è comunque
disponibile una discreta quantità di risorse dei memoria.
Ad esempio, il trasferimento di n bytes da un punto ad un altro della
memoria dati è realizzabile con una semplice macro, che fa uso dell'
indirizzamento indiretto post indicizzato e delle istruzioni moviw e movwi
.
Ricordiamo che l' uso dei puntatori indiretti consente di accedere all' intera
RAM senza preoccuparsi dei banchi.
; Copy n bytes da source a target
COPYMEM MACRO source, target, nbyte
local c_0
movlw nbyte
movwf temp
movlw low(source)
movwf FSR0L
movlw high(source)
movwf FSR0H
movlw low(target)
movwf FSR1L
movlw high(target)
movwf FSR1H
c_0 moviw FSR0++
movwi FSR1++
decfsz temp,f
bra c_0
ENDM |
Dato che la macro può essere richiamata più volte, occorre utilizzare per
il branch bra o il simbolo $-
o, come in questo caso, una label, condizionata come local.
Nel caso del 16F1507 il programma, non particolarmente ottimizzato, data la
sua originale destinazione per didattica, impiega circa il 45% della memoria
programma e il 25% della RAM dati.
Volendo scrive il sorgente con un compilatore C, si potrà optare inizialmente
per 16F1509, che ha risorse di memoria molto più ampie, per poi passare, una
volta ottimizzato l'eseguibile, al chip "minore".
ICD.
16F1507/08/09 hanno il motore ICD
integrato, il che è di grandissima utilità durante il debug ed è un
elemento essenziale per una attività di apprendimento dei meccanismi di
funzionamento del microcontroller.
Quindi, è possibile eseguire il debug in circuit direttamente con il Pickit3.
Va specificato che occorre l'ambiente MPLAB-X, dato che
MPLAB-IDE, fermatosi alla versione 8.92, non supporta correttamente i nuovi
processori.
|
Per chi volesse utilizzare questa funzione, consigliamo di spostare
il pin di ingresso dei pulsanti su RB4, dato che RB3 serve all'ICD per
il debug.
Segnaliamo comunque che esiste un header, AC
244051, molto interessante, dato che permette il debug in
circuit, senza alcuna perdita di pin, per 12F1501, 16F1503 e
16F1507/8/9. |
Per ultimo, ricordiamo che questi chip esistono anche nella versione LF,
con un range di alimentazione da 1.8 a 3.6V.
|