temperatura interna temperatura irraggiamento temperatura ...
Progetto Di Un Misuratore Di Temperatura
-
Upload
lorenzo-columbo -
Category
Documents
-
view
161 -
download
1
Transcript of Progetto Di Un Misuratore Di Temperatura
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 1/58
1
POLITECNICO DI BARI
A.A. 2009/2010
Corso di Laurea Specialistica in Ingegneria
Elettronica (SEI)
Corso di Sistemi Digitali Programmabili
Prof. Ing. P. Dello Russo
PROGETTO DI UN MISURATORE DI
TEMPERATURA
Columbo Lorenzo
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 2/58
2
Introduzione
Obiettivi e caratteristiche generali del progettoIl progetto descritto nella presente relazione ha come prima finalità la comprensione delle
possibilità offerte dall'impiego di un microcontrollore in un sistema rivolto ad una specifica
applicazione, tale che richieda lo sviluppo di una determinata logica ma che non si esaurisca in essa.
Obiettivo successivo ma non secondario è l'apprendimento delle tecniche e l'utilizzo dei tools
disponibili per la programmazione del microcontrollore. Infine, è stato posto l'obiettivo di
sviluppare il flusso di progetto tipico di una scheda PCB, dalla rappresentazione dell'idea mediante
schema a blocchi fino alla generazione del layout.
In generale, un microcontrollore (MCU) è un dispositivo
elettronico integrato su singolo chip, nato comeevoluzione alternativa al microprocessore ed utilizzato
per applicazioni specifiche di controllo digitale. Il primo
processore a 8 bit (lo 8008, in Fig.1) venne proposto sul
mercato da Intel all'inizio degli anni '70, ed era costituito
unicamente da una semplice ALU e da una unità di
controllo in grado di gestire il flusso di dati e indirizzi
tra la ALU e la circuiteria esterna di supporto. Losviluppo tecnologico di questo tipo di dispositivi fu rapidissimo, e caratterizzato naturalmente da
una sempre crescente potenza di calcolo e complessità della struttura interna. Nonostante ciò, i
microprocessori (brevemente, CPU) continuarono nel tempo a richiedere l'utilizzo di unità
periferiche esterne per l'espletamento di funzioni che non
riguardassero strettamente l'elaborazione e il calcolo [1].
Proprio questo tipo di esigenza condusse allora alla
realizzazione dei microcontrollori (il primo dei quali, l'8048
della Intel, rappresentato in Fig.2, fu rilasciato nel 1975): si
trattava di sistemi completi che integravano in uno stesso
chip il processore, la memoria, i canali di I/O ed eventuali
altri blocchi in grado di svolgere funzioni altamente
specifiche. Di conseguenza, a differenza dei microprocessori classici, di fatto sistemi general
purpose, i microcontrollori furono (e sono tutt'ora) progettati per ottenere la massima
autosufficienza funzionale ed ottimizzare il rapporto prezzo-prestazioni in una specifica
applicazione. Il successo commerciale di questo genere di prodotto fu enorme. Tra i fattori che lo
determinarono, figurano sicuramente [2]:
Figura 1: Il primo microprocessore a 8 bit (Intel8008).
Figura 2: Il primo microcontrollore (Intel8048).
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 3/58
3
Il basso costo dei sistemi che consentono di realizzare, integrando al loro interno unità
funzionali che dovrebbero altrimenti essere introdotte mediante ulteriori dispositivi;
Ampia scalabilità di prestazioni, in termini di potenza di calcolo e di complessità funzionale,
nonché elevata varietà di dotazioni in periferiche e moduli specializzati;
Facilità di programmazione, garantita dall'esistenza di numerosi tools di sviluppo e dalla
larga disponibilità di documentazione, librerie e codici di esempio.
Non di rado, una volta individuato il produttore e il modello del MCU che si intende impiegare, la
scelta dell'ambiente di sviluppo cade sul relativo IDE (Integrated Devolopment Environment)
proprietario: è il caso ad esempio degli affermati PIC della Microchip e del relativo ambiente
MPLAB. Una scelta diversa è stata operata nell'ambito del presente progetto: il microcontrollore
impiegato è infatti il più tradizionale (e meno complesso) 80C32 della Philips, per la
programmazione del quale è stato utilizzato il semplice e potente ambiente di sviluppo Keil-
uVision. Tale IDE si è infatti rivelato in grado di unire ad un efficiente compilatore C utilissimi
tools quali un disassembler chiaro e preciso e un pratico debugger, completo di visuale su memoria
interna e periferiche del micro. Ulteriori dettagli relativi alle caratteristiche tecniche del micro e
dell'IDE impiegati sono riportati nei capitoli successivi.
Per quanto riguarda il flusso di progetto della PCB, il software CAD utilizzato è il popolare
pacchetto Orcad nella sua versione 9.2: in particolare, sono stati impiegati i tools Orcad Capture e
Orcad Layout. Il principale punto di forza di questa soluzione CAD è infatti proprio la funzione di
interfacciamento tra i due tools, che consente di passare rapidamente dal disegno schematico alla
disposizione dei dispositivi e dei componenti sulla scheda, quindi allo sbroglio automatico e alla
stampa su lucido di piste, vias e pad (nonché alla generazione di quei file Gerber impiegati dalle
macchine CNC per la produzione del circuito stampato).
Descrizione generale del sistemaLa specifica applicazione scelta è la rilevazione simultanea di misure di temperatura da un array di
sensori, disposti in linea in modo tale da consentire successive misure derivate di valore medio egradiente termico. Si richiede inoltre che le misure derivate vengano mostrate in tempo reale su un
display LCD, e che invece quelle dirette vengano eventualmente, su richiesta dell'utente, trasmesse
ad un personal computer connesso alla PCB mediante standard RS-232. Il sistema complessivo
includerà allora necessariamente un applicativo in grado di interfacciarsi alle porte seriali ed
effettuare semplici operazioni di elaborazione, rappresentazione e archiviazione delle misure
acquisite. Ulteriori dettagli relativi allo sviluppo di tale applicativo sono riportati in appendice.
Lo schema a blocchi generale del sistema progettato è quindi riportato in Fig.3:
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 4/58
4
Figura 3: Schema a blocchi del sistema realizzato.
Già in questa prima rappresentazione si comprende che si avrà a che fare con una parte analogica
estremamente ridotta, costituita essenzialmente dai quattro sensori di temperatura e da un blocco
che implementi il riferimento di tensione necessario (come descritto più avanti, esso sarà ottenuto
semplicemente dall'impiego opportuno di un integrato basato su diodo zener). Come evidenziato, il
micro dovrà fornire all'ADC e al MUX gli opportuni segnali di controllo, oltre che acquisire le
misurazioni di volta in volta prodotte dal convertitore, per il quale si è scelta la dimensione di 8 bit
(adeguata alle porte di I/O del micro). Allo stesso tempo, il micro produrrà in uscita i segnali di dati
e di controllo necessari a rappresentare sul display LCD le misure indirette calcolate e a trasmettere
sulla seriale le misure dirette acquisite.
Presentazione dello schematicoRispetto allo schema a blocchi già mostrato, lo schematico in Fig.4 chiarisce alcuni importanti
dettagli implementativi.
Figura 4: Schematico del circuito realizzato.
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 5/58
5
Innanzitutto, in questa versione dello schematico, finalizzata alla sola documentazione, si è preferito
non evidenziare, per comodità di rappresentazione, su tutti gli integrati la presenza dei pin VCC e
GND e delle relative connessioni alle linee di alimentazione (ad esempio, è il caso tra gli altri dei
quattro sensori di temperatura TSENSX).
Nell'implementare lo schema a blocchi descritto in un circuito, si è voluto rendere il riferimento di
tensione fornito all'ADC preciso ed eventualmente regolabile mediante l'impiego di un trimmer da 1
k , tale cioè da garantire che gran parte della corrente erogata dalla alimentazione sul ramo relativo
a R6 (resistenza di limitazione) finisca nel trimmer e non nel carico su cui si vuole realizzare il
riferimento.
Come si evince dallo schematico, inoltre, per la trasmissione dei bit convertiti tra l'ADC e il micro
si è scelto di adottare la tecnica della mappatura in memoria di una periferica: in pratica, la porta
dati dell'ADC è stata posta sulla stessa porta sulla quale il micro legge dalla ROM gli 8 bit relativi
alle istruzioni che deve ad ogni colpo di clock eseguire. I dettagli relativi all'implementazione di
questa tecnica sono riportati nella sezione relativa al codice C sviluppato. Per il momento, si
osserva soltanto come le porte di I/O del micro P0 e P2 siano di fatto speciali, perché preposte dalla
stessa struttura interna del micro a interfacciare quest'ultimo con le porte indirizzo e dati della ROM
contenente il codice macchina da eseguire.
Diversamente dall'ADC, il display LCD è stato posto direttamente su una porta di I/O semplice, che
dedica ad esso 6 dei suoi 8 pin. In particolare, i pin da P1.0 a P1.3 sono destinati a scambiare con il
display i byte di dati: in generale, questi byte potrebbero viaggiare sia dal micro al display,
rappresentando quindi ad esempio i caratteri che il display dovrà mostrare (ma, come si vedrà in
seguito, non solo), sia dal display al micro. La direzionalità di queste linee viene allora istante per
istante ad essere determinata dal valore assunto dal bit R/W (sempre in lettura sul relativo pin del
display): il fatto di mantenere tale bit forzato a 0 implica che il display si porrà sempre in lettura
sulla porta dati. Le altre due linee, En e RS, trasportano segnali di controllo diretti dal micro al
display: la loro funzione sarà chiarita nella sezione relativa al display impiegato.
Una sezione del tutto assente nello schema a blocchi e introdotta a questo livello è invece l'array didiodi LED in basso a destra nello schematico, ciascuno dei quali in serie ad una propria resistenza
di limitazione da 1.2 k (adatta cioè ad una alimentazione di 5 V e ad una corrente erogata sul
carico dell'ordine di qualche mA). Ciascuno di questi LED (che nel layout finale della scheda
verranno posti accanto al display LCD) è atto a segnalare uno specifico stato del sistema. In
particolare: D1 (verde) indica quando acceso lo stato di ON del sistema, quando spento lo stato di
OFF; D2 (rosso) indica quando acceso che il valore medio di temperatura calcolato supera un certo
livello di soglia superiore prefissato, viceversa quando spento; D3 (blu) indica quando acceso che il
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 6/58
6
valore medio di temperatura calcolato si trova al di sotto di un certo livello di soglia inferiore
prefissato, viceversa quando spento.
Il dispositivo D-LATCH svolge la funzione di garantire al micro l'accesso alla memoria programma
esterna ROM (e ad un eventuale memoria dati che però non è prevista nella nostra applicazione).
L'idea implementata è la seguente: quando il micro deve accedere al contenuto di una memoria
esterna, ad un assegnato indirizzo, esso innanzitutto produrrà sulla porta P0 la parte bassa
dell'indirizzo stesso; successivamente, invierà un impulso sull'ingresso di controllo del latch,
ottenendo e produrrà sulla porta P2 la parte alta dell'indirizzo. A questo punto, la porta P0 è in
lettura e l'indirizzo è completo all'ingresso della ROM (oppure, eventualmente, di entrambe le
ROM, nel caso in cui sia prevista anche una memoria dati esterna). L'operazione successiva del
micro è quindi l'invio di un impulso sulla linea di controllo della ROM: tale segnale produce in
uscita alla ROM il byte che era presente all'indirizzo di memoria selezionato, che nel nostro caso è
proprio l'istruzione che il micro dovrà eseguire. Essa viene quindi letta dal micro sulla porta P0.
Facciamo infine qualche considerazione relativa alla componentistica passiva. La cella RC
costituita da R5 e C6 ha unicamente la funzione di consentire all'ADC la generazione di un segnale
di clock di frequenza opportuna (tutto ciò sarà più chiaro nella sezione relativa all'ADC impiegato).
La cella RC costituita da R7 e C2 ha invece la funzione di garantire al microcontrollore il necessario
reset iniziale, a seguito della accensione (per questo motivo, tale blocco non è stato realizzato in
fase di emulazione, quando è il sistema di emulazione stesso che provvede al reset del micro). I due
condensatori C3 e C4, assieme al componente XTAL e all'amplificatore invertente integrato nel
micro tra i due pin indicati, costituiscono un oscillatore Colpitts quarzato che fornisce al micro
stesso il necessario segnale di clock (in questo caso, a 11.0592 MHz: il perché di tale specifico
valore sarà chiaro nella sezione relativa al microcontrollore e al baud-rate della UART). Le quattro
capacità elettrolitiche C5, C6, C7, C8 da 1 F sono semplicemente richieste dal convertitore di
protocollo HIN232 per il suo normale funzionamento (il motivo per il quale esse non sono state
integrate nel dispositivo è probabilmente la difficoltà di realizzare in forma integrata capacità di
dimensioni così elevate). Il componente indicato con la sigla CON9 è semplicemente il tipicoconnettore femmina DE-9 dello standard RS-232, del quale, come evidente, il sistema impiega
unicamente i pin 2, 3 e 5 (ovvero quelli relativi rispettivamente ai segnali in ricezione, in
trasmissione e al riferimento di massa).
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 7/58
7
Analisi dei dispositivi impiegati
PremessaNel presente capitolo verrà fornita una descrizione del principio di funzionamento, delle specifiche
funzionali e della struttura interna di ciascuno dei dispositivi impiegati (naturalmente, verranno
assunti i datasheet come principale riferimento bibliografico), con un grado di dettaglio sufficiente a
comprendere la collocazione del dispositivo nel sistema complessivo e le modalità di interazione
(eventuali segnali di controllo scambiati, timing, componentistica passiva di supporto, ecc.). Non si
è ritenuto opportuno approfondire nel dettaglio il funzionamento della ROM e del D-Latch
impiegati e riportati nello schematico, considerato il fatto che il loro utilizzo non attiene
strettamente alla specifica applicazione sviluppata.
LM35 (Sensore di temperatura)L'integrato LM35 è un sensore di temperatura in grado di riprodurre in maniera precisa e affidabile
una tensione di uscita linearmente proporzionale alla temperatura cui è esposto, misurata
direttamente in gradi centigradi. Per applicazioni che, come quella discussa, richiedono l'utilizzo di
questo tipo di scala, l'LM35 presenta allora un importante vantaggio su analoghi sensori calibrati
però in gradi Kelvin, che costringono, per ottenere la temperatura in °C, a sottrarre dalla loro uscita
una tensione costante di valore piuttosto grande.
Il sensore LM35 offre una accuratezza tipica di ± ¼ °C su un range di temperature che si può
estendere da -55 °C fino a 150°C. Il basso costo associato al suo impiego è assicurato dal fatto che
il dispositivo non richiede la calibrazione dall'esterno. Inoltre, la sua bassa impedenza di uscita e la
sua elevata linearità rendono l'interfacciamento verso il readout e la circuiteria di controllo
particolarmente immediato. Nondimeno, il sensore consente indifferentemente l'impiego di una
alimentazione singola o duale e produce un assorbimento di corrente bassissimo (circa 60 A): da
questo segue un effetto di self-heating molto basso. Il package del dispositivo impiegato è un TO-
92, quindi a 3 pin.
Facciamo infine qualche considerazione sul modo in cui la
tensione di uscita del sensore verrà letta: la Fig.5 (riportata
direttamente dal datasheet del dispositivo) mostra la semplice
configurazione in cui il sensore verrà impiegato. Assumiamo per le
temperature misurate un range esteso tra 0 °C e 128 °C: in questo
modo, per effetto della sensibilità di 10 mV/°C si tratterà di
misurare all'uscita del sensore una tensione compresa tra 0 V e 1.28
V. L'ADC impiegato quantizza a 8 bit, il che vuol dire che sarà possibile distinguere 28 = 256 valori
Figura 5: Configurazione del
sensore LM35.
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 8/58
8
di tensione al suo ingresso. Suddividendo il fondo scala ipotizzato in maniera uniforme, saremo in
grado di acquisire tutti i valori di temperatura compresi tra 0 °C e 127.5 °C a passo di 0.5 °C: da
queste considerazioni, come vedremo, seguirà il calcolo del valore opportuno per la tensione di
riferimento da fornire all'ADC. Come si evince dallo schematico rappresentato, ciascuno di questi
sensori sarà associato ad uno specifico indirizzo del multiplexer analogico, pilotato dal
microcontrollore: quest'ultimo sarà allora in grado di distinguere e conservare memoria di quale dei
quattro sensori impiegati ha prodotto uno specifico valore di temperatura acquisito.
LM385 (Riferimento di tensione)L'integrato LM385 è un riferimento di tensione a band-gap, regolabile e a
3 terminali. Alimentato con una tensione singola compresa tra 1.24 V e
5.3 V, esso produce un riferimento di tensione fisso di valore tipico 1.24
V e assorbe una corrente compresa tra 10 A e 20 mA. I principali
features del dispositivo sono un'impedenza di piccolo segnale
eccezionalmente bassa e una buona stabilità termica, oltre che un'elevata
precisione sul riferimento di tensione fornito. Altre caratteristiche
interessanti risultano una bassa rumorosità e una elevata resistenza del
dispositivo nel tempo.
La modalità in cui il riferimento verrà impiegato è descritta dalla Fig.6,
eccezion fatta unicamente per il valore della tensione di alimentazione
(nel nostro caso 5 V) e, di conseguenza, per il valore opportuno della resistenza di limitazione da
impiegare. Subito a valle del riferimento a 1.24 V, la presenza di un trimmer di valore
sufficientemente piccolo (nel nostro caso, 1 k ) consente di produrre su un terzo nodo una tensione
di riferimento del valore desiderato, ovvero 0.64 V (il motivo della necessità di questo riferimento è
chiarito nella sezione relativa all'ADC).
ADC0804 (Convertitore Analogico/Digitale)L'integrato ADC0804 è un convertitore analogico/digitale CMOS a 8 bit ad approssimazioni
successive, che usa una scala differenziale potenziometrica. Esso viene visto dai microprocessori
come una locazione di memoria o una porta di I/O, ovvero non richiede l'introduzione di ulteriore
logica di interfaccia. L'ingresso analogico a tensione differenziale consente di ottenere una migliore
reiezione di modo comune; inoltre riferimento dell'ADC può essere regolato, agendo su un
opportuno pin, in modo tale da codificare qualunque fondo scala, per quanto piccolo, utilizzando
tutti gli 8 bit di risoluzione (compatibilmente, com'è ovvio, alle specifiche di rumore del
dispositivo). I limiti imposti per il valore della tensione di alimentazione (da 4.5 V a 6.3 V) sono
Figura 6: Configurazioneper la generazione di una
VREF a 1.24 V.
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 9/58
9
perfettamente compatibili con l'alimentazione a 5 V disponibile; l'assorbimento di corrente tipico
dell'integrato è pari a 2.5 mA.
La configurazione con la quale il dispositivo viene impiegato dal sistema è mostrata in Fig.7: sulla
parte sinistra dell'integrato si distinguono gli I/O digitali, di controllo (i primi quattro) e di dati (gli
ultimi otto); sulla parte destra sono stati rappresentati i restanti otto I/O analogici, corrispondenti ai
pin di alimentazione (si osservi che, benché l'integrato offra la possibilità di distinguere massa
analogica e digitale, nella nostra applicazione i due pin saranno posti sullo stesso nodo), i due pin
per la generazione del segnale di clock, i due pin relativi all'ingresso differenziale e il pin destinato
a leggere un eventuale riferimento di tensione esterno, mediante il quale è possibile regolare il
fondo scala dell'ADC.
Prima di tutto, focalizziamo l'attenzione sulle problematiche relative agli ingressi analogici da
fornire al dispositivo. Per la generazione del segnale di clock, si propongono due alternative:
derivarlo direttamente da quello del micro oppure utilizzare la soluzione descritta in Fig.7 (ed
effettivamente implementata), ottenuta mediante un gruppo RC esterno e un trigger di Schmitt
integrato nel dispositivo. Dati i valori di R e C, si può valutare la frequenza del segnale di clock
ottenuto dalla formula f CLK = 1/(1.1*R*C): in corrispondenza dei valori scelti in Fig.7 si ottiene un
valore di f CLK pari a 606.1 kHz; diversamente, per i valori R = 10 k e C = 100 pF (ovvero quelli
scelti per la nostra applicazione, come desumibile dallo schematico di Fig.4) si ha f CLK = 909.1 kHz.
Risulta importante osservare che tale comportamento ideale si ottiene a patto di non caricare il pin
CLK R con una capacità parassita troppo grande (nel caso in cui si voglia utilizzare il segnale di
clock così generato anche per altri scopi): sono consentiti valori di capacità di carico fino a 50 pF,
che corrisponderebbe a 7 convertitori A/D di questo tipo pilotati dal clock di uno solo.
Discutiamo ora il riferimento di tensione da porre sul pin VREF /2. L'ADC è stato progettato in modo
tale che, se questo pin viene lasciato floating, il fondo scala si estende da 0 V a VCC. In pratica, la
tensione di riferimento impiegata dall'integrato può essere pari o a metà della VCC oppure alla
Figura 7: Configurazione di utilizzo dell'ADC0804.
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 10/58
10
tensione forzata dall'esterno sul pin VREF /2 (il guadagno
interno in corrispondenza del pin di ingresso VREF /2 è pari
a 2, così che la tensione di ingresso differenziale
corrispondente al fondo scala risulta pari a due volte la
tensione applicata al pin 9: si veda la Fig.8). Per maggiore
chiarezza, facciamo un esempio numerico. Se i valori
dell'ingresso analogico differenziale (VIN(+) - VIN(-))
cadono nel range compreso tra 0.5 V e 3.5 V, lo span che
si vorrebbe ottenere è pari a 3 V: si potrebbe allora porre
un valore di tensione pari a 0.5 V sul pin VIN(-), in modo
tale da assorbire l'offset, e uno pari a metà di 3 V, ovvero
1.5 V, sul pin VREF /2. In questo modo, si è effettivamente
adattato il fondo scala dell'ADC alla dinamica del segnale
di ingresso, producendo un ovvio miglioramento in termini
di risoluzione ottenuta. Nel nostro sistema, il segnale da convertire sarà di fatto l'uscita prodotta da
ciascuno dei sensori di temperatura utilizzati: la dinamica di ingresso dell'ADC sarà quindi estesa
tra 0 V e, come anticipato, 1.28 V, nelle nostre ipotesi. Si dovrà allora porre sul pin 9 dell'ADC0804
una VREF /2 pari a 0.64 V: nella sezione relativa al LM385 abbiamo già discusso come ciò è stato
ottenuto.
Focalizziamo ora l'attenzione sui segnali di controllo che l'ADC dovrà scambiare con il
microcontrollore affinché il suo corretto funzionamento sia garantito: si tratta dei segnali CS (Chip
Select), RD (Read Strobe), WR (Write Strobe) e INTR (Interrupt), ciascuno con una sua specifica
funzione e tutti attivi bassi. La procedura di dialogo tra micro e ADC si compie in due fasi. La
prima fase è quella di avvio della conversione (il diagramma temporale è riportato in Fig.9). Come
Figura 8: Circuito per la generazione delriferimento nell'ADC0804.
Figura 9: Diagramma temporale della fase di avvio conversione.
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 11/58
11
si evince dal diagramma, ciò che di fatto avvia la conversione è l'attivazione (transizione alto-basso)
prima del CS, poi del WR, in modo tale che l'impulso di WR sia tutto contenuto all'interno
dell'impulso sulla linea CS. In questa fase, il segnale INTR è a livello logico alto. A questo punto,
l'ADC legge il valore analogico di tensione differenziale ai suoi ingressi e produce in uscita la
parola di conversione: a partire dal ritorno a livello logico alto di WR, si dovrà aspettare un primo
intervallo di tempo di preparazione della conversione stessa, che come evidenziato nel diagramma,
si può estendere tra 1 e 8 volte il periodo di clock dell'ADC, e un secondo intervallo di tempo
associato alla conversione vera e propria e di durata TC (tempo di conversione). Per il valore di TC il
datasheet dichiara un valore minimo di 66 e massimo di 73 cicli di clock: se il valore vero di TC
fosse 70 cicli di clock, il tempo impiegato dal nostro ADC ad effettuare la conversione sarebbe, per
quanto detto, pari a 70*(1/909.1 kHz) = 77 s. Al termine di questa fase, l'ADC stesso attiva (porta
a livello logico basso) il segnale di INTR: tale segnale, allora, indica che la fase di lettura e
conversione è terminata. Si può procedere quindi alla seconda fase, ovvero quella di lettura della
parola di conversione prodotta (diagramma temporale in Fig.10). Si tratta di ripetere la sequenza di
commutazioni vista per i segnali CS e WR all'inizio della fase precedente semplicemente
sostituendo a WR il segnale RD: si deve cioè produrre un impulso di RD tutto contenuto all'interno
di un impulso di CS. Come si evince dal diagramma, e in perfetta simmetria con quanto descritto
nella fase precedente, già dopo la commutazione alto-basso del RD (e un successivo tempo di attesa
indicato con tACC e pari a 135 ns), i bit di dati iniziano a essere validi e la parola di conversione può
essere letta. Il ritorno a livello logico alto di RD indica all'ADC che la lettura della parola è stata
completata: di conseguenza, il dispositivo riporta i pin relativi alle bit dati di uscita ad alta
impedenza. Risulta immediato allora intuire che il CS agisce come una specie di abilitazione della
comunicazione per l'ADC, mentre l'INTR ha lo scopo di segnalare all'eventuale micro che userà il
Figura 10: Diagramma temporale della fase di lettura della parola di conversione.
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 12/58
12
dispositivo che l'operazione di conversione si è conclusa con successo: queste considerazioni
conducono in maniera diretta alla soluzione che si è scelto di implementare e che verrà descritta in
maniera dettagliata nel capitolo seguente, relativo al microcontrollore e alla sua programmazione.
L2014 (Display LCD)Il modulo L2014 è un display a cristalli liquidi (LCD) a matrice di punti a basso consumo di
potenza, caratterizzato da un pannello LCD ampio e ad alto contrasto e un controllore CMOS
integrato. Tutte le funzioni del display sono controllate da istruzioni, quindi il modulo è
particolarmente adatto ad essere interfacciato con un microprocessore (o, nel nostro caso, con un
microcontrollore). Questo rende ovviamente il modulo utilizzabile in un'ampia gamma di
applicazioni.
Il display è in grado di mostrare 20 caratteri, ciascuno ottenuto come una matrice di punti 5x7, su 4
linee. Esso include al suo interno una memoria ROM in grado di generare 192 tipi di caratteri (con
la possibilità di generarne altri arbitrari mediante una apposita area RAM), una memoria dati di t ipo
RAM di dimensione 80 bytes, leggibile anche dal MPU, un oscillatore e un circuito di reset
all'avvio integrati (di conseguenza non occorre fornire tali segnali dall'esterno). Risulta inoltre
possibile interfacciare il display con MPU a 4 e 8 bit. Il dispositivo richiede una alimentazione
singola a 5 V e tipicamente assorbe una corrente di 2.7 mA. Il modulo è in grado di operare in un
range di temperature che si estende da 0 °C a 50 °C.
Il dispositivo presenta 14 pin in linea, il simbolo di ciascuno dei quali è
riportato nella tabella di Fig.11. VSS e VDD sono i pin di alimentazione
(fissati rispettivamente a tensioni di 0 V e 5 V), mentre VLC è un pin su
cui si può agire con un riferimento di tensione in modo da variare il
contrasto dei cristalli liquidi (tale pin viene posto a massa, in modo da
ottenere dal display il massimo contrasto; RS è il pin associato al segnale
di Register Select: quando alto, il display e il micro stanno scambiando
dati, quando basso istruzioni o flag di controllo; R/W è il pin associato alsegnale di Read/Write: quando alto, il display è in scrittura sul bus dati,
quando basso è in lettura (nello schematico, tale pin viene fissato a
massa in quanto la nostra applicazione non richiede che venga scambiata
alcuna informazione dal display verso il micro); E è il pin associato al
segnale di Enable: per effettuare una qualsiasi operazione, un impulso su
questa linea è necessario affinché essa venga avviata; i pin indicati con
DBX sono quelli associati al bus dati: nella nostra specifica applicazione, solo la seconda metà di
questo bus viene utilizzato, e quindi parole di 8 bit verranno scambiate in due fasi successive (di
Figura 11: Simboli associati aipin del modulo L2014.
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 13/58
13
conseguenza, i primi 4 bit di questo bus restano, nello schematico mostrato, privi di connessioni
elettriche).
Il modulo L2014 si presenta piuttosto versatile: risulta d'altra parte opportuno, per ragioni di
brevità, focalizzare l'attenzione unicamente su quelle funzionalità che vengono utilizzate nella
nostra specifica applicazione. L'unica nostra esigenza è quella di scrivere linee di testo predefinite
sul display: si tratterà allora essenzialmente di essere in grado di trasmettere dal micro verso il
display istruzioni e dati. Abbiamo già detto che è il bit RS a indicare di volta in volta se una data
parola trasmessa dal micro al display è una parola di istruzioni o di dati (in questo secondo caso,
nient'altro che un singolo carattere). Restano allora da chiarire due aspetti: quali segnali di controllo
produrre per assicurare che il trasferimento della parola dal micro al display avvenga correttamente
e, in secondo luogo, quale significato associa il display a un dato byte ricevuto (in maniera più
concreta, si dovrà conoscere la lista delle istruzioni e la mappa dei caratteri).
La prima questione è risolta sinteticamente dalla Fig.12, che rappresenta il diagramma temporale
dei segnali di controllo da attivare per effettuare una operazione di scrittura sul modulo L2014 (la
linea "doppia", che indica un livello logico contemporaneamente alto e basso, corrisponde ad una
condizione "don't care").
Come si evince dal diagramma, si tratterà prima di tutto di porre il valore di RS al livello logico che
ci interessa, sulla base di quanto detto relativamente sul suo significato; in secondo luogo, si dovrà
porre a livello logico basso il pin R/W: stiamo effettuando un'operazione di scrittura;successivamente, si porterà il pin E, inizialmente basso, a livello alto. Poco tempo dopo, i bit
Figura 12: Diagramma temporale dei segnali di controllo per un'operazione di scrittura sul modulo L2014.
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 14/58
14
presenti sul bus dati verranno letti: è necessario che in questa fase essi rimangano stabili (per questo
motivo, è più semplice fare in modo che essi vengano stabiliti prima ancora dell'inizio
dell'operazione di scrittura e rimangano costanti per tutta la durata della stessa). Dopo un certo
intervallo di tempo minimo PWEH, è possibile concludere la procedura riportando il pin di E a
livello basso: com'è ovvio, tutti i valori dei tempi riportati sul diagramma sono commentati e
quantificati nel datasheet, ma è immediato osservare come tutti questi tempi, dell'ordine al più di
qualche centinaio di ns, risultino di fatto almeno di un ordine di grandezza inferiori ai tempi con cui
Figura 13: Lista delle istruzioni del modulo L2014.
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 15/58
15
il micro esegue le sue istruzioni. La schematizzazione che segue è allora molto semplice, soprattutto
nell'ipotesi posta per la quale R/W è fisso a livello basso: per effettuare un'operazione di scrittura
sul modulo L2014 sarà sufficiente scrivere il valore di RS, scrivere il valore dei bit sul bus, quindi
produrre un impulso alto sul pin di E (tale impulso viene prodotto dal micro nel modo più semplice
che si possa immaginare, come si evince dal codice C riportato nel capitolo seguente). Nel caso che,
come nella nostra applicazione, si utilizzino soli 4 bit del bus dati disponibile, la procedura resta
identica, con l'unica differenza che si dovranno trasferire separatamente, in due operazioni
successive di scrittura, la parte alta e la parte bassa della parola, dopo aver ovviamente settato il
modulo per lavorare in questa modalità operativa (è questa infatti, come spiegato subito di seguito,
una delle impostazioni che si può richiedere al modulo mediante la scrittura di un'istruzione).
Risolviamo a questo punto la seconda questione aperta, relativa a come il modulo interpreta le
parole che il micro scrive su di esso. La tabella in Fig.13 fornisce la lista completa delle istruzioni
disponibili del modulo L2014: ovviamente, non tutte queste istruzioni sono utili alla nostra
specifica applicazione. Commentiamo allora unicamente le istruzioni che verranno impiegate.
(1) Display clear: pulisce il display e riporta il cursore alla posizione di partenza. Di default,
tale posizione coincide con l'indirizzo 0, in alto a sinistra, ma può essere cambiata (per la
mappa degli indirizzi associati a ciascuna posizione sul display, si veda la Fig. 14);
(3) Entry Mode Set: imposta la direzione del movimento del cursore e se il display verrà
shiftato oppure no. L'istruzione prevede due parametri: il bit I/D determina se la posizione
del cursore verrà incrementata (I/D = 1) o decrementata (I/D = 0); il bit S determina se, in
corrispondenza di un'operazione di scrittura di un carattere, si effettuerà uno shift del display
(S = 1) oppure no (S = 0). Nella nostra applicazione, si porrà I/D = 1 e S = 0: il cursore verrà
incrementato e non verrà effettuato alcuno shift del display;
(4) Display ON/OFF control: determina lo stato di accensione del display complessivo e del
cursore ed, eventualmente, avvia l'effetto di blinking sul cursore (per dettagli sull'effetto di
blinking, nient'altro che l'oscuramento intermittente di tutti i punti di un dato carattere).
L'istruzione prevede tre parametri: il bit D determina se il display vero e proprio è nello
stato ON (D = 1) oppure OFF (D = 0), il che non ha a che fare, ovviamente, con lo stato di
accensione del modulo (anche con il display spento, se l'alimentazione viene mantenuta il
modulo continua ad operare, ad esempio i dati scritti nella RAM del display vengono
conservati); il bit C determina se il cursore è mostrato sul display (C = 1) oppure no (C = 0);
il bit B determina se l'effetto di blinking sul carattere nella posizione del cursore è attivo (B
= 1) oppure no (B = 0). Nella nostra applicazione, si porrà D = 1, C = 1 e B = 0: il display
sarà sempre acceso, con il cursore mostrato e il blinking inattivo.
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 16/58
16
(6) Function Set: imposta alcuni parametri di funzionamento in base al valore assunto dai tre
parametri che contiene: il bit DL (Data Length) determina la lunghezza del bus dati
nell'interfacciamento verso il micro a 4 bit (DL = 0) o 8 bit (DL = 1); il bit N determina il
duty ratio, fissandolo a 1/16 (N = 1) o a 1/8 (N = 0); il bit F determina il carattere
tipografico, rendendolo una matrice di punti 5x10 (F = 1) o 5x7 (F = 0). Nella nostra
applicazione, si porrà DL = 0, N = 1 e F = 0: l'interfacciamento avverrà sempre a 4 bit, il
duty ratio sarà imposto a 1/16 (scelta obbligatoria, come indicato dal datasheet, per lo
specifico dispositivo L2014) e il carattere tipografico sarà inquadrato in una matrice di punti
5x7 (in realtà, per N = 0 il datasheet osserva che tale bit diventa per il modulo una
condizione don't care e il carattere tipografico è necessariamente quello indicato).
Figura 14: Mappa degli indirizzi della DD RAM sul display.
Resta da chiarire in che modo il modulo associa ad una data word ricevuta uno specifico carattere
tipografico e in quale punto del display stampa questo carattere. Come anticipato, il display può
essere visto come una RAM di 80 byte, ovvero 20 caratteri per 4 linee: il nome con cui si fa
riferimento a tale RAM sul datasheet è appunto DD RAM, ovvero Display Data RAM. Ciascuna
locazione di tale memoria è ovviamente associata ad un indirizzo (esprimibile in due cifre
esadecimali) e ad una specifica posizione sul display. In assenza di shift, la mappa delle locazioni
della RAM sulle varie posizioni del display è in Fig. 14.
Semplicemente, gli indirizzi della DD RAM compresi tra 0x00 0x13 sono posti nella linea 1, quelli
compresi tra 0x40 e 0x53 nella linea 2, quelli compresi tra 0x14 e 0x27 nella linea 3, infine quelli
compresi tra 0x54 e 0x67 nella linea 4. Quindi, risultano consecutive le linee 1 e 3 e le linee 2 e 4.
Nel momento in cui viene scritta una stringa di byte nella DD RAM, allora, si parte dalla posizione
corrente del cursore (eventualmente, quella iniziale, o anche posizione "home") e si procede per
indirizzi consecutivi. Sebbene esista la possibilità di spostare il cursore arbitrariamente sul display,
la nostra applicazione non richiede necessariamente questo tipo di azione. La Fig.15 mostra infine il
contenuto della ROM da 192 byte per la scrittura di uno dei caratteri "standard": l'operazione di
scrittura di un carattere sul display, nella sua forma più immediata, consisterà allora semplicemente
nella selezione di uno di questi caratteri attraverso una parola scritta sul bus dati, secondo le
corrispondenze indicate nella stessa Fig.15.
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 17/58
17
Figura 15: Mappa dei caratteri standard per il modulo L2014.
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 18/58
18
In ultimo, anticipiamo che la procedura di inizializzazione (dettagliatamente commentata nella
sezione relativa alla descrizione del codice C sviluppato) si tradurrà in una sequenza di istruzioni
dei tipi visti e analizzati, da eseguire sul modulo prima del suo utilizzo vero e proprio.
CD74AC14E (Invertitore CMOS)L'integrato CD74AC14 contiene sei invertitori indipendenti. Questo dispositivo realizza
l'operazione booleana NOT mediante un trigger di Schmitt: gli invertitori hanno quindi differenti
tensioni di ingresso di soglia per le commutazioni basso-alto (VT+) e alto-basso (VT-). Più
precisamente, l'isteresi, definita come la differenza VT+ - VT-, ha un valore tipico di 0.5 V.
La tensione di alimentazione può essere compresa tra 1.5 V e 5.5 V; fissata la VCC, l'ingresso può
collocarsi tra 0 V e la VCC stessa. La corrente erogata dal dispositivo sul pin di uscita è, in
entrambi gli stati, pari a 24 mA.
La modalità, piuttosto tradizionale, in cui il dispositivo verrà impiegato nel sistema non richiede
l'indicazione di ulteriori dettagli. L'unica specifica che è opportuno focalizzare è il valore dei tempi
di commutazione, dell'ordine di qualche nanosecondo: si tratta di tempi del tutto trascurabili rispetto
a quelli con cui il micro svolge le sue operazioni (un clock a 11.0592 MHz equivale a un periodo di
circa 90 ns, senza contare che una singola istruzione richiede svariati cicli di clock per essere
completata: per ulteriori dettagli, si faccia riferimento al capitolo sul microcontrollore): potremo
allora considerare l'operazione di inversione tra IN e OUT istantanea. Si osserva infine che il
sistema utilizzerà una sola delle porte logiche messe a disposizione dall'integrato: come evidenziato
dallo schematico, gli altri ingressi e uscite verranno lasciate floating (in corrispondenza di questi e
altri nodi è stato utilizzato il simbolo Capture di "no connect").
HEF4051 (Multiplexer Analogico a 8 canali)L'integrato HEF4051 è un multiplexer analogico a 8 canali con tre ingressi di indirizzo, un ingresso
di enable attivo basso, otto ingressi indipendenti e un'uscita comune. L'operazione di multiplexing è
ottenuta mediante un array di 8 switch analogici bidirezionali tra gli ingressi e l'uscita. Con il pin di
enable basso, uno degli otto switch viene selezionato (stato di ON, bassa impedenza) in base ai
valori logici presenti sui pin di indirizzo. Viceversa, con enable alto, tutti gli switch si pongono in
alta impedenza, indipendentemente dal valore assunto dai bit di indirizzo.
VDD e VSS sono i pin di alimentazione per gli ingressi di controllo digitali (quelli di indirizzo e
l'enable). La differenza di potenziale tra i due pin deve essere compresa tra 3 V e 15 V. I segnali
presenti sui pin analogici (gli ingressi e l'uscita comune) possono variare tra la stessa VDD (come
limite superiore) e la tensione posta su un terzo pin, indicato con VEE. La differenza VDD-VEE
non può superare il valore di 15 V. Affinché il dispositivo funzioni come un multiplexer digitale, si
deve cortocircuitare VEE a VSS (che tipicamente viene posto a massa).
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 19/58
19
Nel nostro specifico caso, solo 4 degli 8 ingressi analogici disponibili verranno utilizzati: si tratterà
allora di porre a massa 1 dei 3 pin di selezione. Ad esempio, come verrà mostrato sia in fase di test
su breadboard sia in fase di realizzazione del layout, si può pensare di porre a massa il pin associato
al bit di indirizzo di peso più alto, quindi di utilizzare gli ingressi analogici indicizzati da 0 a 3.
Un'ultima osservazione da rilevare riguarda i ritardi di propagazione tra la variazione dei bit di
indirizzo e la variazione dell'uscita: tale ritardo corrisponde tipicamente a 150 ns. D'altra parte, a
differenza di quanto detto a proposito dell'inverter, tale delay non va confrontato con la durata del
clock, ma con il tempo impiegato dall'ADC a produrre la codifica (per ulteriori dettagli, si faccia
riferimento alle sezioni relative al timing dell'ADC e al codice sviluppato).
HIN232 (Adattatore di livello RS-232)L'integrato HIN232 è un'interfaccia per la trans/ricezione verso una porta RS-232 particolarmente
adatta a quelle applicazioni in cui la alimentazione a ± 12 V non è disponibile. Esso richiede una
alimentazione singola a 5 V e monta dei convertitori di tensione a pompa di carica che, partendo da
quella, generano una ulteriore tensione di alimentazione a ± 10 V richiesta dal funzionamento del
dispositivo stesso.
Alcuni dei principali features del dispositivo sono:
compatibilità CMOS e TTL all'ingresso, slew-rate
limitato sui segnali di uscita, un rate che può arrivare a
120 kbps, bassa dissipazione di potenza.
In Fig.16 è riportata la modalità in cui i condensatori
esterni da 1 F o da 0.1F (come descritto in NOTE 1,
sul datasheet) devono essere connessi al dispositivo. Il
simbolo circuitale utilizzato indica esplicitamente, se
ce ne fosse bisogno, che si debba trattare di
condensatori elettrolitici.
Il massimo valore consentito per la tensione dialimentazione è 6 V, la corrente assorbita è
tipicamente pari a 5 mA; le tensioni di soglia superiore
(per livello basso) e inferiore (per livello alto)
all'ingresso sono rispettivamente 0.8 V e 2 V. La minima tensione sul pin di enable che abilita il
relativo bit è 2.4 V (nello schematico proposto, tale pin è posto direttamente a massa).
Il datasheet del dispositivo offre ulteriori dettagli strutturali e funzionali del dispositivo; d'altra
parte, un ulteriore approfondimento di questi aspetti non risulta propedeutico alla comprensione del
funzionamento del sistema realizzato, quindi verrà tralasciato.
Figura 16: Pinout e connessione dei condensatori disupporto per l'integrato HIN232.
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 20/58
20
Il microcontrollore 80C32
Descrizione generale del dispositivoL'integrato 80C32, prodotto dalla Philips, è un microcontrollore ad alte prestazioni basato
sull'architettura dell'8051 e fabbricato mediante il processo tecnologico CMOS ad alta densità di
integrazione della Philips stessa.
Il dispositivo, privo di ROM al suo interno, contiene una RAM da 256 byte, 32 linee di I/O
parallelo (in pratica, 4 porte ciascuna da 8 bit), tre contatori (o timer) a 16 bit, una struttura di
interrupt a 4 livelli di priorità, una porta di I/O seriale UART destinata a comunicazioni con altri
microprocessori, un circuito di clock on-chip.
Il dispositivo, pensato per lavorare con una tensione di alimentazione singola compresa tra 2.7 V e
5.5 V, ha anche un consumo di potenza statica particolarmente basso, oltre che due soluzionisoftware per la riduzione del consumo di potenza (poiché tali modalità di utilizzo non verranno
impiegate, esse non verranno discusse).
Il pinout dell'integrato è riportato in Fig.17. Ciascun simbolo associato a ciascun pin richiama
mnemonicamente una funzione. In particolare:
VSS: riferimento di massa;
VCC: tensione di alimentazione singola (positiva);
P0.0-7: la porta 0 è una porta bidirezionale a 8 bit inconfigurazione open drain. I pin di tale porta che presentano un
valore logico alto scritto su di essi vengono visti come floating,
e possono quindi essere usati come ingressi ad alta impedenza.
La porta 0 ha anche una funzione speciale, durante gli accessi
alla ROM esterna: essa fornisce la parte bassa dell'indirizzo cui
accedere e legge la parola prodotta dalla memoria stessa;
P1.0-7: la porta 1 è una porta bidirezionale a 8 bit, tirata a VCC
da una rete di pull-up. Poiché i pin di tale porta presentano un
valore logico alto scritto su di essi dall'interno del micro, essi
possono essere usati come ingressi nel momento in cui li si
forzi a massa. Gli ultimi due pin della porta hanno anche una
funzione alternativa, che però non verrà utilizzata;
P2.0-7: la porta 2 è una porta bidirezionale a 8 bit, tirata a VCC da una rete di pull-up.
Poiché i pin di tale porta presentano un valore logico alto scritto su di essi dall'interno del
micro, essi possono essere usati come ingressi nel momento in cui li si forzi a massa. La
porta 2 ha anche una funzione speciale, durante gli accessi alla ROM esterna: essa fornisce
Figura 17: Pinoutdell'integrato 80C32.
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 21/58
21
la parte alta dell'indirizzo cui accedere alla ROM, sia che si tratti del fetch di una istruzione
sia che si tratti della lettura di un dato;
P3.0-7: la porta 3 è una porta bidirezionale a 8 bit, tirata a VCC da una rete di pull-up.
Poiché i pin di tale porta presentano un valore logico alto scritto su di essi dall'interno del
micro, essi possono essere usati come ingressi nel momento in cui li si forzi a massa. La
porta 3 assolve anche a numerose delle funzioni speciali associate ai features caratteristici
dei microcontrollori basati sull'architettura dell'8051: RxD e TxD sono rispettivamente
ingresso e uscita per la porta seriale; INT0 e INT1 sono gli ingressi associati all'interrupt
esterno; T0 e T1 sono gli ingressi esterni destinati al controllo dei timer; WR e RD sono
destinati rispettivamente ai segnali di write strobe e read strobe nelle fasi di accesso alla
memoria esterna (per la lettura di un dato);
RST: è il pin di reset. Un valore alto su questo pin per due cicli macchina (naturalmente,
mentre l'oscillatore è in funzionamento) resetta il dispositivo. Un resistore integrato posto
verso VSS consente un reset all'accensione utilizzando unicamente un condensatore esterno
posto verso VCC (è la soluzione adottata nella nostra applicazione, si veda lo schematico);
ALE: è il pin di Address Latch Enable, destinato al segnale di controllo per il D-Latch che
conserva memoria della parte bassa dell'indirizzo negli accessi alla memoria esterna.
Durante il normale funzionamento, il segnale di ALE è emesso a un rate costante di 1/6
della frequenza di oscillazione (esso viene saltato, invece, durante ogni istruzione di accesso
alla memoria dati esterna). Tale segnale può essere disabilitato settando un opportuno bit di
un SFR (si veda di seguito per maggiore chiarezza): in questo caso, l'impulso di ALE viene
prodotto unicamente durante un'istruzione di accesso alla memoria dati esterna (MOVX);
PSEN: è il pin di Program Store Enable, destinato al segnale di controllo per la memoria
ROM esterna nelle fasi di fetch delle istruzioni da eseguire. Quando il microcontrollore sta
eseguendo un codice dalla memoria di programma esterna, PSEN viene attivato due volte ad
ogni ciclo di clock, eccetto quando l'istruzione in corso sia l'accesso alla memoria dati
esterna (in tal caso, l'impulso viene "saltato");
EA/VPP: è il pin di External Access Enable. Tale pin deve essere mantenuto a valore logico
basso dall'esterno per abilitare il dispositivo a estrarre le istruzioni da eseguire dalla
memoria programmi esterna;
XTAL1: ingresso dell'amplificatore invertente integrato per ottenere l'oscillatore;
XTAL2: uscita dell'amplificatore invertente integrato per ottenere l'oscillatore.
Lo schema a blocchi del dispositivo 80C32 è riportato in Fig.18. Come già anticipato, l'architettura
di riferimento è quella dell'8051, con variazioni poco significative: i dettagli relativi al
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 22/58
22
funzionamento del micro in uso saranno allora raccolti dall'ampia bibliografia dedicata ad esso (in
particolare, si farà riferimento al tutorial disponibile online al link http://www.8052.com/tut8051).
Per la ragione appena esposta, si rimanda alla sezione successiva di questo capitolo la piena
comprensione del principio di funzionamento che lo schema a blocchi in Fig.18 sottende.
L'architettura di riferimento: il microcontrollore 8051Secondo un approccio già utilizzato nelle sezioni precedenti, dell'architettura generale del micro
verranno focalizzati unicamente quegli aspetti che risultano imprescindibili ai fini della piena
comprensione del progetto realizzato. Verranno in particolare discusse caratteristiche quali: la
memoria e i registri speciali, il tempo di esecuzione di un'istruzione, la porta seriale e i timer, gli
interrupt.
Figura 18: Schema a blocchi del microcontrollore 80C32.
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 23/58
23
La memoria e i registri specialiL'8051 prevede in generale l'utilizzo di tre tipi di memoria: memoria on-chip, memoria di
programma esterna e memoria RAM esterna.
La memoria di programma è quella che contiene le istruzioni che il micro deve eseguire, è limitata a
64 kB (da cui segue che la dimensione degli indirizzi è di 16 bit) e può essere sotto forma di
EPROM interna o, come avviene nella maggior parte delle applicazioni, inclusa la nostra, esterna
(si veda lo schematico): in particolare, solo in quest'ultimo caso essa può raggiungere la dimensione
massima indicata. In realtà, anche se il progetto discusso non ne prevede, esistono espedienti
hardware (che non verranno discussi) per fare in modo che l'8051 sia in grado di indirizzare una
memoria programma più estesa di 64 kB.
L'8051 prevede anche l'utilizzo di una RAM esterna, anch'essa limitata a 64 kB, quindi più ampia,
ma ovviamente più lenta, della memoria interna disponibile on-chip (tale soluzione non verrà
comunque implementata nel presente progetto).Come anticipato, l'8051 include una RAM interna
montata on-chip, che si suddivide a sua volta in due
aree (si faccia riferimento alla Fig.19): RAM interna
e Area Registri Speciali (SFR è appunto l'acronimo
di Special Function Register). La RAM interna ha
un'estensione di 128 byte: è la memoria più veloce e
flessibile in lettura e scrittura (com'è ovvio, si tratta
tuttavia di una memoria volatile). Tale area è
costituita unicamente da:
4 banchi di registri "R", per ciascun banco numerati da 0 a 7, destinati alla memorizzazione
di dati temporanei necessari ad una data operazione complessiva (ad esempio, un'addizione);
tra questi banchi, di default (all'accensione) è in uso il banco 0, ma si può modificare questa
impostazione agendo opportunamente sul valore di un SFR. Occorre osservare che ciascuna
locazione di questa area di memoria può essere indirizzata sia come un byte generico della
RAM interna sia come un registro (tale considerazione sarà chiara più avanti);
una sezione di memoria indirizzabile a bit, compresa tra gli indirizzi da 0x20 a 0x2F. Tale
sezione, oltre a poter essere indirizzata a byte come qualsiasi altra locazione della RAM
interna, è anche quella cui fanno riferimento alcune istruzioni che operano appunto "a bit"
quali SETB e CLR, mediante gli indirizzi che richiedono come argomento (da 0x00 a 0x7F);
una sezione (i restanti 80 byte), compresa tra l'indirizzo 0x30 e 0x7F, che può contenere
variabili utente cui si richiede di accedere in maniera frequente e veloce (tale area viene
utilizzata dal micro anche per le operazioni di stack, e risulta quindi spesso un po' esigua).
Figura 19: Schema della memoria interna dell'8051.
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 24/58
24
L'area SFR è costituita da registri che controllano specifiche funzionalità dell'8051. Per esempio, 4
registri SFR consentono l'accesso alle 32 linee di I/O parallelo, un altro consente di leggere e
scrivere sulla seriale, e così via. I registri di quest'area appaiono ancora come locazioni della RAM
interna, identiche alle altre ai fini dell'indirizzamento: benché non a tutte le locazioni di quest'area
(indirizzi compresi tra 0x80 e 0xFF) corrisponda uno specifico SFR, è altamente sconsigliato
utilizzare tali locazioni di memoria apparentemente "libere" come byte di memoria general purpose.
Di fatto, quindi, agire sui registri SFR vuol dire modificare in qualche modo la modalità operativa
del micro. I registri SFR dell'8051 standard sono 21, e ovviamente a ciascuno di essi è associato,
oltre ad un indirizzo, anche un nome mnemonico, utilizzato ad esempio nella programmazione C
dei microcontrollori (ciascun IDE dispone di librerie di file di intestazione che, fra le altre cose,
contengono queste associazioni tra gli indirizzi di memoria interna e i relativi alias degli SFR);
alcuni di questi, inoltre, sono accessibili a bit (i particolare, quelli associati a indirizzi multipli di 8).
Forniamo a questo punto una rapida panoramica degli SFR utilizzati dalla nostra applicazione:
P0: è la porta P0 di I/O. Ciascun bit di questo registro corrisponde ad un pin del
microcontrollore. Per esempio, il bit 0 è il pin P0.0, il bit 7 è il pin P0.7. Settare un bit di
questo registro SFR equivale a forzare ad un livello alto il corrispondente pin di I/O, mentre
resettarlo equivale a forzarlo ad un livello basso. Lo stesso discorso può essere ripetuto in
perfetta analogia per gli altri SFR, associati alle porte parallele (P1, P2 e P3);
SP: è lo stack pointer del microcontrollore, ovvero il registro che punta al prossimo valore
dello stack nella RAM interna. Se ad un certo punto del flusso di programma tale registro ha
valore x: la successiva istruzione di PUSH caricherà il valore indirizzato dall'argomento
nello stack, all'indirizzo x+1 (prima incrementa, poi carica); viceversa la successiva
istruzione di POP caricherà il valore dello stack all'indirizzo x in memoria all'indirizzo in
argomento (prima carica, poi decrementa);
DPL/DPH: sono i registri di Data Pointer (rispettivamente parte bassa e parte alta). Il
registro corrispondente ai 16 bit complessivi (indicato con DPTR) è un intero compreso tra 0
e 65535 con la funzione di puntare a uno specifico indirizzo di una memoria esterna da, al
più (come anticipato), 64 kB, che sia di codice o di dati;
TCON: è il registro di Timer Control, usato per configurare il modo di funzionamento dei
timer dell'8051; alcuni dei suoi bit sono invece destinati a configurare o segnalere gli
interrupt esterni (vedi sezioni sui timer e sugli interrupt);
TMOD: è il registro di Timer Mode, usato per configurare il modo di funzionamento di
ciascuno dei due timer (vedi sezione sui timer);
TL0/TH0: sono i registri che mantengono traccia dello stato corrente del timer 0,individuando un valore intero attraverso 16 bit; possono solo incrementare, e lo fanno a
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 25/58
25
seconda del valore assunto da TMOD. Lo stesso discorso può essere ripetuto per TL1/TH1,
con riferimento al timer 1;
SCON: è il registro di Serial Control, destinato alla configurazione e alla indicazione dello
stato della porta seriale (vedi sezione sulla porta seriale);
SBUF: è il registro di Serial Buffer, usato per inviare e ricevere i dati dalla porta seriale
dell'8051. Ogni valore scritto dal micro in questo registro verrà inviato serialmente sul pin
TxD, viceversa ogni valore letto dal pin RxD verrà scritto su questo buffer e reso quindi
disponibile al programma in esecuzione sul micro;
IE: è il registro di Interrupt Enable, usato per abilitare e disabilitare gli interrupt. I 7 bit
meno significativi di IE sono usati per l'abilitazione di ciascun interrupt individualmente,
mentre il bit più significativo è destinato all'abilitazione di tutti gli interrupt;
IP: è il registro di Interrupt Priority, usato per cambiare la priorità di ciascun interrupt (essa
può essere alta, se il bit corrispondente a quello specifico interrupt è alto, o, viceversa,
bassa). Un interrupt può interrompere solo un altro interrupt a priorità più bassa;
PSW: è il registro di Program Status Word, usato per memorizzare alcuni bit importanti che
vengono aggiornati nell'esecuzione delle istruzioni (ad esempio, flag di carry e di overflow);
ACC: è l'accumulatore del micro, il registro più usato, poiché coinvolto in molte istruzioni;
B: è un registro di supporto utilizzato solo per effettuare operazioni di moltiplicazione e
divisione. Può anche, all'occorrenza, essere usato per memorizzare valori temporanei.
Oltre ai già descritti SFR, esistono altri registri detti "registri base", che includono i già descritti
registri ACC, B e SP, ma ancora il PC e i registri "R". Il PC (Program Counter) è un indirizzo a 2
byte che punta alla locazione di memoria programma dove l'8051 andrà a prendere la prossima
istruzione da eseguire: di conseguenza, allo start-up varrà PC = 0x0000, nel normale flusso di
programma PC verrà incrementato (a seconda della lunghezza della istruzione corrente), mentre
durante l'esecuzione di istruzioni di controllo del flusso (e.g., istruzioni di salto incondizionato)
potrà essere fissato a qualsiasi valore intero a 16 bit. I registri "R" sono, come anticipato, un set di 8
registri denominati R0, R1 e così via fino a R7, utilizzati come registri ausiliari all'accumulatore in
molte operazioni (attraverso due bit del PSW è possibile impostare il banco di registri in uso).
Il tempo di esecuzione di un'istruzioneL'8051 opera sulla base di un clock fornito da un quarzo esterno, con una frequenza di risonanza
tipicamente (e nella nostra applicazione) pari a 11.059 MHz. Il micro opera allora sulla base dei
cosiddetti "cicli macchina": un singolo ciclo macchina è la minima quantità temporale che
un'istruzione dell'8051 richiede per essere eseguita (minima nel senso che l'esecuzione di alcune
istruzioni richiede più cicli macchina). Da un punto di vista fisico, un ciclo macchina corrisponde a
12 impulsi dell'oscillatore al quarzo: possiamo allora calcolare in maniera semplice quanti cicli
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 26/58
26
macchina al secondo possono essere eseguiti dall'8051, ovvero 11.059.000/12 = 921.583. A questo
punto, mediando approssimativamente sul numero medio di cicli macchina per istruzione richiesto
dal set di istruzioni del micro, possiamo concludere con una stima di circa 600.000 istruzioni al
secondo mediamente eseguite dal micro, ovvero un tempo medio di esecuzione per una singola
istruzione di circa 1/600.000 sec-1 = 1.67 sec (tutte queste considerazioni hanno valore solo per
l'8051 standard, in quanto in molti suoi derivati il timing delle istruzioni è di fatto diverso).
La porta seriale e i timerL'8051 classico dispone di due timer, che possono essere configurati, controllati e letti in maniera
indipendente. Ciascuno di questi timer può assolvere a tre funzioni generali: tenere traccia del
tempo trascorso (ad esempio per misurare la distanza temporale tra due eventi), contare il numero di
eventi e generare il baud-rate per la porta seriale. Di queste tre funzioni, la nostra applicazione
impiega solo la terza: per questa ragione, discuteremo i timer unicamente da questo punto di vista.
La porta seriale, o UART integrata, è una delle funzionalità più potenti dell'8051: essa rende
possibile ottenere una comunicazione tra due sistemi a microcontrollore in maniera semplice e
veloce. Una volta configurata la porta, sarà sufficiente leggere o scrivere il registro SBUF già
presentato per ricevere od inviare dei dati in linea: sarà il micro col suo hardware ad "avvertirci"
(manipolando il valore di opportuni flag del registro SCON) quando un dato byte è stato ricevuto
(ed è quindi pronto per la lettura da SBUF) oppure la trasmissione seriale di un dato byte
(precedentemente scritto in SBUF) è stata completata.
L'inizializzazione della porta seriale richiede di agire essenzialmente sul registro SCON, già
presentato e indirizzabile a bit (l'indirizzo "a byte" di tale SFR è 0x98, quindi i suoi bit avranno
indirizzo compreso tra 0x98, bit meno significativo, e 0x9F, bit più significativo). Vediamo nel
dettaglio la funzione di ognuno dei suoi bit, in ordine decrescente di peso:
SM0 (Serial Mode 0): bit 0 di modo;
SM1 (Serial Mode 1): bit 1 di modo;
SM2 (Serial Mode 2): abilitazione della comunicazione multiprocessore;
REN (Receive Enable): abilitazione della ricezione;
TB8 (Transmit Bit 8): nono bit da trasmettere nel modo 2 e 3;
RB8 (Receive Bit 8): nono bit da ricevere nel modo 2 e 3;
TI (Transmit Flag): flag che viene settato automaticamente quando il byte è stato trasmesso;
RI (Receive Flag): flag che viene settato automaticamente quando un byte è stato ricevuto;
Innanzitutto, osserviamo che solo i 4 bit più significativi del registro hanno una funzione in fase di
configurazione (degli altri 4, utilizzeremo solo gli ultimi 2, ovvero i flag di trasmissione e ricezione:
le modalità in cui verranno impiegati saranno chiare nella sezione relativa al codice C): di questi,
verranno utilizzati effettivamente i bit SM0, SM1 e REN. L'ultimo è semplicemente il bit che abilita
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 27/58
27
il micro a ricevere dati sulla porta seriale: ponendo REN = 0, si impedisce al micro di ricevere byte
dalla porta seriale.
A questo punto, dettagliamo meglio il significato dei bit di modo SM0 e SM1: la loro combinazione
fornisce la modalità operativa della UART, associabile ad un intero compreso fra 0 e 3 (ottenuto
ponendo SM0 a bit più significativo). La modalità 0 consiste nella trasmissione di 8 bit e fissa il
baud-rate della UART a un valore di f osc /12; la modalità 1 consiste nella trasmissione di 8 bit e
deriva il baud-rate della UART dall'overflow del timer 1; la modalità 2 consiste nella trasmissione
di 9 bit e fissa il baud-rate della UART a un valore di f osc /64; la modalità 3 consiste nella
trasmissione di 9 bit e deriva il baud-rate della UART dall'overflow del timer 1. Innanzitutto, la
porta seriale verrà utilizzata unicamente a 8 bit, quindi si tratterà di comprendere il funzionamento
delle modalità 0 e 1 e di scegliere quella più opportuna alle nostre esigenze. La differenza consiste,
come anticipato, unicamente nel modo in cui viene calcolato il baud rate, ovvero la frequenza di
simbolo della UART. Nel primo caso, esso risulta fissato unicamente dalla frequenza di clock: nella
modalità 0, il baud rate sarà inevitabilmente pari a 11.059.000/12 bps, ovvero circa 921.583 bps.
Tale valore non si adatta alla nostra applicazione, quindi la scelta della modalità 1 risulta
praticamente obbligata. Si tratta a questo punto di capire come impostare il timer 1 in modo tale che
il baud rate assuma il valore da noi desiderato, per esigenze di compatibilità con l'applicativo
sviluppato, assunto pari a 9600 bps: come anticipato, si dovrà allora mandare il timer 1 in overflow
proprio con questa frequenza.
Analizziamo a questo punto il funzionamento dei timer, con l'obiettivo di comprendere come
ottenere quanto richiesto. I due timer funzionano entrambi nella stessa maniera, e condividono i due
registri TCON e TMOD, destinati al loro controllo; come anticipato, d'altra parte, ciascun timer
dispone di due registri (valutabili come un unico registro da 16 bit) che mantengono traccia del loro
stato: si tratta dei registri TL0 e TH0 per il timer 0, TL1 e TH1 per il timer 1. Ad esempio, parlando
in decimali, quando il timer 0 ha valore 1000, TH0 conterrà il valore 3, TL0 il valore 232: noto il
valore scritto nei due registri, lo stato del timer 0 può essere indicato da un intero calcolabile come
TH0*256 + TL0. Ovviamente, lo stesso discorso può essere ripetuto identico per il timer 1. Segueallora che il valore decimale più grande che ciascun timer può assumere è 65535: quando uno dei
due timer raggiunge tale valore, un ulteriore impulso di clock lo resetterà o, per meglio dire, lo
manderà in overflow.
Prima di avviare ciascuno dei timer, tuttavia, è necessario stabilire la loro modalità operativa, in
analogia a quanto detto a proposito della UART: ciò viene ottenuto mediante il registro TMOD.
Esso è diviso in una parte alta destinata al timer 1 e una parte bassa destinata al timer 0. Ciascuna
parte è costituita da 4 bit, il cui valore stabilisce la modalità operativa di ciascuno dei due timer
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 28/58
28
(anche questo registro è indirizzabile a bit). Ad esempio, con riferimento alla metà più significativa
di TCON, si hanno in ordine decrescente di peso i bit:
GATE1: quando questo bit è settato, il timer 1 è attivo solo quando il pin P3.3 (indicato
anche con il simbolo INT1 nello schematico) è nello stato alto. Se tale bit è resettato, il timer
1 è svincolato dallo stato del pin P3.3;
C/T1: quando questo bit è settato, il timer 1 conta il numero degli eventi sul pin P3.5
(indicato anche con il simbolo T1 nello schematico). Se tale bit è resettato, il timer 1 viene
incrementato ogni ciclo macchina;
T1M1: bit 1 di modo del timer 1;
T1M0: bit 0 di modo del timer 1.
La parte bassa del registro presenta bit di analoghe funzioni per il timer 0. I modi operativi definiti
dai bit T1M1 e T1M0 possono essere associati, analogamente a quanto visto per i bit SM, a interi da
0 a 3. La modalità 0 è detta "timer a 13 bit" ed è presente nell'8051 unicamente per mantenere la
compatibilità col suo predecessore, l'8048 (non è quindi generalmente utilizzata nei nuovi sviluppi);
la modalità 1 è detta "timer a 16 bit", e prevede che TH1 venga incrementato ogni volta che TL1 va
in overflow (è come se si disponesse per lo stato del timer di un unico registro a 16 bit); nella
modalità 2, detta "timer a 8 bit con auto-reload", TH1 contiene il valore che deve essere caricato in
TL1 quando quest'ultimo va in overflow: in pratica, quando TL1 ha valore 255 e viene
ulteriormente incrementato, esso assume il valore caricato in TH1 invece di ripartire da 0; la
modalità 3, infine, detta "timer in splitted mode", consente di splittare in due timer da 8 bit il timer
0, assegnando i bit di controllo di timer 1 al timer TH0: il timer 1, quindi, potrà funzionare in una
qualsiasi delle modalità 0, 1 o 2, ma potrà essere solo incrementato a ogni ciclo macchina.
Per la nostra applicazione si richiede di utilizzare uno dei due timer (che sarà il timer 1) come
generatore di baud rate ad una frequenza prefissata. Poiché non si richiede l'utilizzo del timer 0 per
altri scopi, la modalità che appare più opportuna selezionare è il modo 2: affinché l'evento di
overflow sia generato dal timer 1 con la frequenza desiderata, entro la approssimazione migliore
possibile, si tratterà di calcolare il valore più opportuno da scrivere nel registro TH1. Si imposta
allora la seguente equazione (anch'essa riportata sulla guida, già citata, a cui questa sezione fa
riferimento):
TH1 = 256 - ((Fq/384)/Baud)
essendo Fq la frequenza del quarzo (come noto, 11.059 MHz) e Baud il baud-rate desiderato (pari a,
come già indicato, 9600 bps). Si ottiene in questo modo un valore di TH1 con ottima
approssimazione pari a 253.
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 29/58
29
Gli interrupt L'ultimo aspetto dell'architettura dell'8051 standard e del suo utilizzo su cui è il caso di soffermarsi
è la gestione degli interrupt. In termini generali, un interrupt è un evento che interrompe la normale
esecuzione di un programma. Il flusso di un programma è sempre di tipo sequenziale e può essere
alterato da particolari istruzioni che svolgono appositamente questa funzione (le funzioni di salto); a
differenze di queste, gli interrupt forniscono un meccanismo di "congelamento" del flusso di
programma in corso: solo in corrispondenza di un evento prestabilito che, appunto, genera
l'interrupt, viene eseguita una opportuna subroutine, denominata "interrupt handler", ovvero gestore
di interrupt. L'evento generatore può essere, ad esempio, il timer che va in overflow, oppure la
ricezione di un byte dalla seriale, o ancora un evento (transizione logica) su un apposito pin esterno
(come nel caso della nostra applicazione): l'8051 può essere configurato per gestire ciascuno di
questi eventi con un differente interrupt handler.
Ovviamente, tale capacità di interrompere la normale esecuzione di un programma quando unparticolare evento si verifica rende il programma stesso molto più efficiente nel gestire processi
asincroni, la qual cosa risulterebbe molto più onerosa se si dovesse implementare mediante un
codice che effettui, sufficientemente spesso, tutti i dovuti controlli: viceversa, la scrittura di un
interrupt handler in linguaggio C, come sarà possibile osservare, risulta particolarmente immediata.
Anche nel caso degli interrupt, tuttavia, è necessario configurare il microcontrollore in modo
opportuno: il registro SFR su cui si deve in questo caso intervenire è IE, che, come anticipato,
destina un bit per l'abilitazione di ciascun tipo di interrupt, eccetto il più significativo, destinato a
abilitare/disabilitare il sistema complessivo degli interrupt. Nel nostro caso, si dovrà abilitare
l'interrupt relativo all'evento esterno sul pin INT 0 (o anche pin P3.2): questo vuol dire che
dovranno essere portati a valore logico alto il bit più significativo e il bit relativo a tale interrupt,
ovvero il bit 0 del registro IE (per ulteriori dettagli, si consulti il riferimento citato). Poiché non si
richiede la gestione di più di un interrupt, non avrebbe senso porsi il problema di variare il
contenuto del già introdotto registro IP, relativo alle priorità di ciascun interrupt.
Scelte di progetto preliminari: linguaggio e IDEIl primo passo da compiere in questa fase è, ovviamente, la scelta del linguaggio di
programmazione tra le soluzioni alternative assembler e linguaggio C. Ad oggi, il dibattito su quale
sia in generale la scelta migliore è ancora aperto. Essenzialmente, l'assembler presenta il vantaggio
di fornire il completo controllo del microcontrollore ed è potenzialmente più efficiente (tale
potenzialità si concretizza, ovviamente, se il programmatore è in grado di produrre un codice
efficiente); il linguaggio C è teoricamente più portabile (il codice prodotto subisce meno variazioni
cambiando il microcontrollore in uso), quindi in generale più adatto a quei programmatori che non
sono legati ad una specifica architettura (eventualmente, conosciuta in modo approfondito). D'altra
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 30/58
30
parte, i moderni compilatori C sono in grado di generare un codice altamente ottimizzato, che
supera spesso in efficienza il codice assembler prodotto da un programmatore medio, specialmente
se questo non ha una particolare qualificazione nell'utilizzo della specifica architettura; un'ultima
considerazione può riguardare il costo dei compilatori C, di frequente molto più cari di quelli
assembler. Considerati questi elementi, appare opportuno orientarsi verso la scelta del linguaggio C.
Come anticipato, verrà utilizzato il software Keil uVision, dotato di tutti gli strumenti necessari a
una programmazione efficace. In fase di avvio del progetto, è possibile scegliere la architettura su
cui si sta sviluppando, nel nostro caso l'80C32 della NXP (fondata dalla Philips): questo ci
consentirà di avere a disposizione un header file (reg51.h) in cui ad ogni alias SFR è associato
l'indirizzo della memoria interna in cui è collocato (questo ci permetterà quindi di riferirci, nel
corpo del codice, ad ogni byte o anche ad ogni bit "speciale" del nostro micro semplicemente
richiamando il suo alias). Una volta scritto il codice su un text editor essenziale e intuitivo, sarà
possibile effettuarne una prima simulazione, con vista sulla memoria interna e su tutte le periferiche
dell'8051. Il tool di debug consente addirittura, attraverso un opportuno prompt di comandi, di
simulare segnali esterni con cui i pin del micro possono interagire. Accedendo alla finestra di
opzioni per il target (si veda il project workspace), è possibile anche impostare il valore della
frequenza di clock del micro, in modo che la successiva simulazione possa anche fornire indicazioni
sul tempo impiegato dal micro ad eseguire il codice sviluppato, step by step (questa possibilità
risulta di una certa importanza per applicazioni in cui il timing è un aspetto critico). Sempre nella
stessa finestra, è possibile specificare anche il tipo di output che il software dovrà produrre al
termine della fase di compilazione: nel nostro caso, si tratterà di produrre il file eseguibile
direttamente in codice macchina (formato HEX-80). Un'ultima funzionalità che appare importante
evidenziare è il disassembly: tale tool rende possibile osservare come ciascuna istruzione C del
sorgente venga tradotta dal compilatore in assembler. In particolare, l'utilità di quest'ultima
funzionalità sarà evidente nella fase successiva alla simulazione del codice nell'IDE, ovvero quella
di emulazione del codice compilato sull'architettura di riferimento e di test del sistema complessivo
(per ulteriori dettagli su questa fase, si faccia riferimento al capitolo successivo).
Il codice C sviluppatoIn questo paragrafo, il codice C sviluppato verrà riportato e descritto sezione per sezione, secondo
l'ordine del sorgente completo. Le sezioni di codice, comprensive delle linee di commento,
verranno riportate sotto forma di una o più screenshot acquisite direttamente dal text editor del Keil
e a ciascuna sezione seguirà la relativa descrizione e analisi.
Il principio generale che ha ispirato la produzione del presente codice (lungo solo 234 linee) è
l'efficacia: non è stato compiuto alcuno sforzo nel tentativo di rendere il codice riutilizzabile in altre
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 31/58
31
applicazioni (per questa ragione, non sono stati realizzati file di intestazione per l'area dichiarativa o
file di libreria per le funzioni richiamate, ma tutto il codice prodotto è riportato nell'unico file
programma.c). Tale scelta, seppure poco elegante, ha consentito una certa semplicità in fase di
progetto e non ha impedito di conservare un controllo completo sul codice, stante la sua moderata
complessità concettuale.
Sezione 1: direttive al preprocessore e dichiarazioni generaliLe primissime due linee di codice rappresentano le direttive al preprocessore. Sono semplici
istruzioni di inclusione: si richiede al preprocessore di ricercare eventuali variabili o funzioni
richiamate nel codice, ma non ivi definite, nei due file di intestazione "reg51.h" e "stdio.h". Di
questi due file, il primo è quello che, come anticipato, contiene la definizione degli alias per gli SFR
dell'80C32 (in pratica, quello che ci consente di riferirci ad esempio al SFR relativo alla porta
parallela P1 senza dover indicare il suo indirizzo nella memoria interna). Il secondo file è
l'intestazione di un file di libreria ("stdio.c") che contiene, tre la altre, la funzione "sprintf",
utilizzata nel seguito del programma.
Figura 20: Direttive al preprocessore e dichiarazioni generali.
Le primissime due linee di codice rappresentano le direttive al preprocessore. Sono semplici
istruzioni di inclusione: si richiede al preprocessore di ricercare eventuali variabili o funzioni
richiamate nel codice, ma non ivi definite, nei due file di intestazione "reg51.h" e "stdio.h". Di
questi due file, il primo è quello che, come anticipato, contiene la definizione degli alias per gli SFR
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 32/58
32
dell'80C32 (in pratica, quello che ci consente di riferirci ad esempio al SFR relativo alla porta
parallela P1 senza dover indicare il suo indirizzo nella memoria interna). Il secondo file è
l'intestazione di un file di libreria ("stdio.c") che contiene, tre la altre, la funzione "sprintf",
utilizzata nel seguito del programma.
L'area dichiarativa che segue risulta di comprensione particolarmente immediata. Nella sua prima
parte (linee 006-018) si stanno semplicemente ridefinendo con dei nomi mnemonici alcuni singoli
bit a cui il programma dovrà accedere. Il significato di ciascuno di questi bit nel seguito del codice è
illustrato nel seguente elenco puntato (ovviamente, ciascuna di queste ridefinizioni deve risultare
coerente con le connessioni hardware stabilite tra i vari dispositivi a livello di schematico):
D4-D7: sono i bit associati ai pin della porta parallela sui quali il micro comunicherà con il
display. Ogni comunicazione richiederà l'invio di due semi-byte: questo tipo di approccio si
è preferito alla destinazione di una intera porta parallela di 8 bit per la stessa funzione poiché
si ha la necessità di utilizzare diversamente gli altri 4 bit; inoltre, come si vedrà, la
comunicazione attraverso un bus di 4 linee non costituisce una grave complicazione, ma
presenta l'unica limitazione di risultare un po' più lenta;
EN: è il bit corrispondente al pin di I/O parallelo destinato al segnale di Enable del display;
RS: è il bit corrispondente al pin di I/O parallelo destinato al segnale di Register Select del
display;
HIGH, LOW: sono i bit, normalmente alti, corrispondenti ai pin di I/O parallelo destinati
all'accensione dei due LED rosso e blu (per ulteriori dettagli si veda la sezione relativa alla
presentazione dello schematico);
STATUS: è il bit, normalmente alto, corrispondente al pin di I/O parallelo destinato
all'accensione del LED verde di stato (ON/OFF);
sel0, sel1: sono i bit corrispondenti ai pin di I/O parallelo destinati al controllo del
multiplexer analogico che seleziona uno dei quattro sensori;
La seconda parte (linee 019-036), invece, dichiara nuove variabili o costanti. In generale, la
dichiarazione di una variabile o di una costante richiede che vengano specificati, nell'ordine:
1. il formato di dato, da cui dipenderà ovviamente il peso in byte del dato stesso. I formati
utilizzati nel programma sono solo due, ovvero unsigned char (numeri interi compresi tra 0 e
255, occupano un solo byte di memoria) e float (numeri reali a virgola mobile, con segno, di
modulo approssimativamente compreso tra 1.17E-38 e 3.40E+38, occupano ognuno 4 byte);
2. il tipo di memoria in cui il dato verrà allocato. Nel programma, alcune variabili sono state
allocate nella memoria RAM interna (idata, di dimensione 256 byte, come visto), altre nella
memoria accessibile in maniera "diretta" (data, di dimensione 128 byte), altre ancora nellamemoria di programma (code, di dimensione fino a 64 kbyte); infine, la sola variabile
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 33/58
33
ADC_out, è stata allocata nella memoria dati esterna (xdata, di dimensione fino a 64 kbyte):
il motivo di questa scelta sarà chiaro più avanti;
3. il nome e la dimensione (in termini vettoriali).
Introduciamo a questo punto il significato di ciascuna delle variabili (o costanti) dichiarate:
buffer[64]: è il vettore che conterrà i dati letti dal micro sulla porta di uscita dell'ADC,
prima di qualsiasi altra operazione su di essi; la sua dimensione è limitata a 64: poiché i
sensori sono 4, una volta che il vettore sia stato riempito, esso conterrà 16 misure ottenute da
ciascuno dei 4 sensori. Al termine di un ciclo di 64 acquisizioni, allora, prima di procedere
alla sovrascrittura del vettore stesso con le nuove acquisizioni, sarà possibile effettuare su
tali misure le semplici elaborazioni richieste (operazioni di media e gradiente);
temp: è una variabile di appoggio ad uso generale, impiegata in diverse sezioni del codice;
hex_val[2]: è il vettore che conterrà ciascuno dei due caratteri ASCII trasmessi, per ogni
misura di temperatura ottenuta, sulla porta seriale (si veda la sezione 5 del codice);
ADC_out : è la variabile che conterrà il valore letto dalla porta di uscita dell'ADC, dopo ogni
singola acquisizione effettuata. Come si evince, è l'unica variabile di tipo "xdata": si è cioè
effettuata la mappatura in memoria dell'ADC. L'idea è questa: poiché si dispone di una
memoria programma di 216 byte, dei quali verranno utilizzati sicuramente meno della metà
(data la ridotta complessità del codice), si è scelto di fare in modo che il micro veda l'ADC
come una locazione di memoria dati esterna, avente in particolare indirizzo 0xFFFF (a
questo serve la forma sintattica "_at_ 0xFFFF"). A questo punto, ogni volta che il codice
richiederà l'accesso alla variabile ADC_out , il micro procederà ad una lettura da memoria
dati esterna: tale procedura (implementata a livello hardware nel micro) consiste nell'invio
dell'indirizzo in due parti, in maniera del tutto analoga a quanto descritto per l'accesso a
memoria programma; in questo caso, tuttavia, l'impulso non verrà inviato sulla linea PSEN
(la memoria di programma mantiene quindi le sue uscite in alta impedenza), ma sulla linea
WR (P3.6) in caso di scrittura o sulla linea RD (P3.7) in caso di lettura da memoria dati
esterna. Quindi, il micro si aspetta di leggere il byte prodotto dalla memoria dati esterna
sulla porta P0. Se si confronta questa sequenza di segnali di controllo con quella richiesta
dall'ADC per la produzione della parola di conversione, esse risultano perfettamente
compatibili una volta che si effettuino le assegnazioni riportate nello schematico (in
particolare, si deve dedicare alla selezione dell'ADC il bit di indirizzo più significativo), ,
nel senso che gli impulsi di WR e RD vengono inviati quando CS è attivo. Questo è vero a
meno di una piccola differenza: il segnale di CS che l'ADC si aspetta di ricevere è attivo
basso, mentre quello prodotto dal micro non lo è (in pratica, quando il micro vuoleindirizzare ADC_out , alza tutti i bit dell'indirizzo, per la scelta operata, e il più significativo
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 34/58
34
di questi, con riferimento allo schematico, è proprio CS). La soluzione a questo problema è
ovviamente l'inversione logica operata dall'inverter CMOS impiegato e interposto fra l'uscita
P2.7 del micro e l'ingresso CS dell'ADC;
i: variabile intera utilizzata come indice per il vettore buffer ;
j: variabile intera utilizzata come generica variabile di ciclo;
*in_text : si tratta di una costante scritta nella memoria di programma (e associata ad una
stringa) e di cui in_text costituisce il puntatore;
hex_offset : è anch'esso una costante e rappresenta l'offset utilizzato per tradurre le misure da
trasmettere (e rappresentativi di ciascuna misura) in una coppia di caratteri ASCII;
ROW[20]: è il buffer in cui verrà temporaneamente memorizzata la stringa da stampare sul
display, prima dell'invio dell'istruzione allo stesso;
misure[4]: è il vettore in cui verranno memorizzate le misure di temperatura acquisite (alla
fine di una sequenza di 64 acquisizioni) mediate su ciascun sensore; svolge una funzione di
supporto ai successivi calcoli di media e gradiente;
mean, grad : variabili in cui verranno memorizzati rispettivamente il valor medio e il
gradiente complessivi calcolati, in termini di codici binari (valore compreso tra 0 e 255);
meanT, gradT : variabili in cui verranno memorizzati rispettivamente il valor medio e il
gradiente complessivi calcolati, in termini di gradi centigradi °C;
temp_max, temp_min: valori costanti per le soglie superiore e inferiore, con le quali verrà
confrontata la temperatura media misurata (la scelta di tali valori è arbitraria);
Sezione 2: procedure relative all'utilizzo dell'ADC
Figura 21: Procedure relative all'utilizzo dell'ADC.
Come già indicato, i segnali di controllo CS, WR e RD richiesti dall'ADC sono facilmente ottenuti
attraverso la mappatura dell'ADC in memoria. Esiste però un quarto segnale di controllo, diretto
questa volta dall'ADC al micro, che assolve nel programma una funzione fondamentale: è il segnale
di INTR (interrupt), che rende possibile la gestione asincrona della lettura delle parole prodottedall'ADC. Il dispositivo, infatti, come desumibile dai diagrammi temporali già analizzati, attiva
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 35/58
35
questo segnale nel momento in cui una conversione è stata completata e lo conserva in questo stato
fino alla ricezione dell'impulso sulla linea RD (che segnala la lettura della parola prodotta). Perché
tutto ciò possa avvenire occorre che il micro sia in grado di rispondere con la lettura della variabile
ADC_out in seguito alla ricezione del segnale di INTR: l'idea è allora porre questo segnale su uno
dei due pin disponibili per gli interrupt esterni (in questo caso, il pin INT0), attivare il relativo
interrupt e scrivere una adeguata procedura di interrupt handler. Proprio questa procedura è quella
riportata in questa sezione di codice: si tratta, in generale, della risposta del micro ad un livello
logico basso sul pin INT0.
La prima operazione che la procedura effettua è appunto la lettura della parola prodotta dall'ADC e
la scrittura di questo byte alla i-esima cella del vettore buffer . A questo punto, l'indice i viene
incrementato, e, normalmente, viene avviata una nuova conversione mediante l'accesso in scrittura
alla variabile esterna ADC_out : proprio questo accesso corrisponde infatti all'invio di un impulso di
WR. L'avvio della nuova conversione deve però essere preceduto dalla selezione del sensore di
temperatura successivo: le due operazioni booleane implementate corrispondono all'incremento
unitario dell'indirizzo [sel1 sel0] con cui viene controllato il multiplexer. Procedendo in questo
modo, il vettore buffer sarà riempito in modo tale che le misure relative al sensore x (per x
compreso tra 0 e 3) saranno collocate, nell'ordine, nelle celle corrispondenti ad indici i di modulo x
in base 4. Facciamo un esempio. Il valore corrente di i è 2, e si assegnano ai bit di selezione i valori
sel1 = 1 e sel0 = 0 (l'ADC sta convertendo la misura prodotta dal sensore 2); l'ADC termina la
conversione, quindi invia il segnale di INTR; il micro, ricevuto tale segnale, avvia l'interrupt
handler, procedendo alla lettura della parola di conversione e all'incremento di i, che passa al valore
3, cioè sel1 = 1 e sel0 = 1; l'impulso di WR avvia una nuova conversione, e tutta la procedura si
ripete; quando i verrà incrementato al valore 4, i bit di selezione verranno nuovamente incrementati
e torneranno quindi ad assumere valore sel1 = 0 e sel0 = 0, ovvero il multiplexer tornerà a
selezionare il sensore 0. Reiterando il discorso, questo vuol dire che sarà possibile trovare tutte le
misure successive acquisite dal sensore 0 nelle celle di buffer pari a 0, 4, 8 ecc., ovvero tutte le celle
da 0 a 63 il cui modulo in base 4 è pari a 0. Lo stesso ragionamento potrà essere ripetuto per gli altritre sensori. In generale, operando in questo modo sarà sempre possibile associare ad ogni elemento
del vettore buffer il sensore di temperatura da cui quella misura è stata prodotta (specifica
ovviamente fondamentale per ottenere successivamente misure derivate di gradiente).
A questo punto, giustifichiamo la presenza della condizione if: la sequenza di istruzioni commentata
dovrà essere eseguita unicamente nel caso in cui il valore di i non sia 64. Come sarà desumibile dal
seguito del programma, in corrispondenza di tale valore di i, il micro sospenderà la lettura delle
parole prodotte dall'ADC (quindi non consentirà la sovrascrittura del vettore buffer ) per dedicarsi al
calcolo delle misure derivate di media e gradiente e all'aggiornamento del display (nonché,
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 36/58
36
eventualmente, alla trasmissione seriale, come sarà chiaro in seguito). Solo dopo che queste altre
operazioni siano state eseguite, il valore di i verrà aggiornato a 0 e tutto si ripeterà con la
sovrascrittura di buffer con altre 64 misure.
Sezione 3: procedure relative all'utilizzo del displayIn questo caso, per la gestione del display sono state scritte e utilizzate quattro procedure distinte.
La prima e più semplice è la procedura delay, che assume come ingresso un intero positivo (a 16
bit, quindi compreso fra 0 e 65535). Tale procedura assolve unicamente alla funzione di fermare il
flusso di programma principale per un ritardo di durata regolabile attraverso l'argomento time. Il
suo principio di funzionamento si basa su un ciclo a decremento: la variabile time, dopo essere stata
opportunamente normalizzata, viene decrementata fino al valore 0, in corrispondenza del quale la
procedura termina e il flusso di programma principale riprende. Il valore di normalizzazione 8.95 è
stato calcolato in modo tale da consentire alla procedura di assumere in ingresso il tempo da
aspettare espresso direttamente in s. Tale procedura risulta di importanza fondamentale per la
gestione del display, che richiede spesso l'attesa di un certo intervallo di tempo tra due istruzioni
consecutive: per questa ragione, le procedure che seguono utilizzano a loro volta tale procedura.
La seconda procedura (lcd_init) è quella di inizializzazione, da eseguire nel main unicamente
all'avvio del programma, prima di eseguire qualsiasi altra operazione sul display. La prima
istruzione che viene eseguita è, appunto, l'attesa da parte del micro di 15 ms, tempo richiesto dal
display tra l'istante di accensione del modulo e l'istante in cui può ricevere la prima istruzione. Le
successive istruzioni realizzano una sequenza di impulsi sul pin di Enable del display, richiesti dallo
stesso in questa fase; in particolare, l'istruzione inviata al display nel segmento di codice (076-079)
gli indica che si intende utilizzare la modalità operativa a quattro bit.
La terza procedura (lcd_write) è quella che verrà utilizzata nel seguito del programma per inviare al
display istruzioni e dati: proprio il primo argomento di ingresso (il bit what ) serve a distinguere
questi due casi (quando pari a 0, si tratta di un'istruzione, quando pari a 1, si tratta di un dato),
mentre il secondo argomento di ingresso (il char word ) rappresenta il dato stesso da inviare. Viene
innanzitutto definita una variabile temporanea temp, che ovviamente, nello scope di questa
procedura, sostituisce la variabile temp globale, quindi si pone sul pin RS del display il valore
logico associato a what . A questo punto, può cominciare la trasmissione del byte, diviso in due
semiword. Viene trasmessa per prima la parte alta di word , e ciò viene ottenuto mediante i seguenti
passi: shift verso destra di 4 posizioni di word e scrittura del risultato in temp; mascheramento della
parte alta di temp (in seguito a questa operazione, solo i 4 bit meno significativi di temp potranno
essere non nulli, ovvero si forza a zero la parte alta di temp); mascheramento della parte bassa di P1
(si forza a zero la parte bassa di P1); operazione di OR logico bit a bit tra temp e P1; impulso di EN .
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 37/58
37
Figura 22(a-b): Procedure relative all'utilizzo del display
L'effetto complessivo ottenuto è in pratica la alterazione della sola parte bassa di P1, che viene in
particolare sovrascritta con la parte bassa di temp, ovvero quella che è la parte alta di word . La
sequenza di istruzioni nelle linee (094-099) ripete le stesse operazioni per la parte bassa di word ,
che viene quindi anch'essa trasmessa. Infine, il datasheet del display richiede di attendere 50 s
prima dell'invio di un'altra parola: a questo serve l'istruzione delay della linea (101).
Infine, la procedura lcd_config consente di effettuare la configurazione del display secondo le
impostazioni desiderate: verrà quindi richiamata nel main del programma prima dell'utilizzo del
display e una sola volta, dato che l'applicazione non richiede di variare più volte la modalità
operativa del display stesso. Confrontando le linee di commento di ogni istruzione con la
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 38/58
38
descrizione dell'istruction-set del display già riportata, è possibile comprendere l'effetto di ogni
linea di codice. Di fatto, si sta richiedendo complessivamente al display di operare secondo le
impostazioni: comunicazione a 4 bit, duty ratio pari a 1/16, cursore a incremento, assenza di shift,
display acceso, cursore nascosto ed effetto blinking disattivo.
Sezione 4: procedura principale (fase di inizializzazione e avvio)Con questa sezione di codice ha inizio la procedura principale: si tratta della fase di inizializzazione
dei vari dispositivi utilizzati.
Tra questi dispositivi è ovviamente incluso il micro stesso, all'inizializzazione del quale sono
destinate le linee di programma (118-129) con particolare riferimento ai suoi registri SFR. Prima di
tutto, vengono settati i valori iniziali da porre sulle porte di I/O parallelo: il bit STATUS viene
portato a 0, così da accendere il relativo LED, di colore verde; i bit sel0 e sel1 sono inizializzati
entrambi a 0, così che il multiplexer selezioni per primo il sensore di temperatura di indice 0; in
questa fase, viene abilitato l'interrupt esterno 0 (agendo sul bit EX0), associato all'ADC, ma solo
dopo aver disabilitato tutti gli interrupt agendo sul già introdotto bit speciale EA (bit più
significativo del SFR IE) impedendo così all'interrupt handler di assumere il controllo, per il
momento; l'attivazione del bit speciale IT0 imposta il modo di trigger dell'interrupt esterno 0 (con la
scelta operata, l'interrupt si attiva quando il micro vede sul pin INT0 una transizione di livello alto-
basso); le due istruzioni alla linea (124) impostano il già descritto modo 1 per la porta seriale;
analogamente, l'istruzione alla linea (125) imposta per il timer1 la modalità 2, mentre l'istruzione
successiva imposta il valore di auto-reload del timer1 al valore calcolato in precedenza, pari a 253;
quindi, le due istruzioni alle linee (127-128) abilitano il timer1 e la ricezione per la porta seriale.
Figura 23: Procedura principale (fase di inizializzazione e avvio).
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 39/58
39
Le linee (130-137) della presente sezione sono invece destinate al primo utilizzo del display, che
sarà ottenuto semplicemente richiamando le procedure già preparate e descritte: si procede quindi
alla inizializzazione, configurazione, puntamento alla prima locazione di memoria associata della
DD-RAM del modulo (che corrisponde a porre il cursore in alto a sinistra sul display), quindi
scrittura della stringa iniziale, puntata dalla variabile in_text . Quest'ultima funzione, in particolare,
si esaurisce, come evidente, nel ciclo for alle linee (135-136).
L'ultima parte della sezione corrisponde all'abilitazione del sistema di interrupt (che resterà attivo da
quel momento in poi fino allo spegnimento del sistema) e all'avvio della prima conversione A/D.
Sezione 5: procedura principale (ciclo principale)Questa sezione rappresenta il ciclo perpetuo in cui si esplicherà di fatto il funzionamento del
circuito: il sistema sarà in grado di effettuare tutte le operazioni richieste, ovvero acquisizione delle
misure, calcolo di media e gradiente, aggiornamento del display ed eventuale trasmissione delle
misure su porta seriale, per un tempo indefinito (in pratica, fino alla interruzione della
alimentazione).
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 40/58
40
Figura 24(a-b-c): Procedura principale (ciclo principale).
Le istruzioni corrispondenti alle linee di codice (145-148) hanno una funzione solo in fase di debug,
per questo sono state rimosse in fase di emulazione del sistema completo. In pratica, esse simulano
il riempimento del buffer che nel sistema funzionante dovrebbe essere scritto dall'ADC, nelle
modalità già discusse. In questo modo, è stato possibile anche in fase di simulazione sull'ambiente
Keil verificare il funzionamento del programma rispetto alle fasi di calcolo di media e gradiente in
gradi centigradi, pilotaggio del modulo LCD e trasmissione su porta seriale, senza dover utilizzare il
complesso strumento, fornito dall'IDE, di simulazione dei segnali esterni. In queste linee di codice,
allora, si può scegliere di riempire il buffer con tutti valori unitari, o ancora un valore intero che sia
pari a i o a 2*i, quindi proporzionale all'indice della rispettiva cella, e così via, in modo da verificare
volta per volta che i valori di media e gradiente calcolati risultino coerenti. Per descrivere il
funzionamento del sistema completo, quindi, ragioniamo in assenza di questo blocco di istruzioni.
Quello che si verifica in questa ipotesi, allora, è possibile dedurlo osservando che subito dopo il
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 41/58
41
blocco condizionale if non è presente alcuna istruzione: questo vuol dire che, se i è diverso da 64, il
ciclo verifica continuamente una condizione vera senza mai eseguire nessun'altra istruzione. In
questa condizione il micro è in attesa che il normale flusso di programma venga alterato.
L'unico evento che può generare questo tipo di deviazione è appunto l'interrupt esterno 0, la cui
procedura di gestione è stata descritta precedentemente. Un effetto di tale procedura è, come visto,
l'incremento dell'indice i: quando un ulteriore interrupt incrementerà la variabile i al valore 64,
all'interno della procedura di interrupt handler non verrà avviata alcuna nuova conversione, il
controllo ritornerà immediatamente al ciclo principale, che potrà eseguire le istruzioni contenute nel
blocco condizionale, compreso nelle linee (149-232).
Proprio questo blocco condizionale è quello che esegue tutte le operazioni richieste al micro
(eccetto quella, già realizzata, di acquisire le parole di conversione dall'ADC): la condizione di
partenza è quella di un vettore buffer di 64 acquisizioni completo e ordinato nel modo descritto
nella sezione relativa all'interrupt handler. Evidentemente, la prima operazione da realizzare a
questo punto è il calcolo delle misure indirette (in gradi centigradi) di media e gradiente: è appunto
la fase di elaborazione, inclusa nelle linee (151-169). Le linee (152-153) inizializzano a zero tutte le
celle del vettore misure, destinato a contenere, come anticipato, la media di 16 misure indipendenti
ottenute da ciascuno dei 4 sensori; le linee (154-155) calcolano l'elemento di indice x del vettore
misure come la cumulata delle 16 misure relative al sensore x, per x che va da 0 a 3 (viene scandito
tutto il vettore buffer e ciascun suo elemento viene cumulato all'opportuno elemento di misure); le
linee (156-157) dividono ciascun elemento di misure per 16, in modo da completare il calcolo delle
4 medie. Partendo dal vettore misure risultante, si può procedere quindi al calcolo della media
complessiva e del gradiente spaziale (ovviamente, si tratterà di un gradiente già mediato nel tempo,
poiché tale media temporale si è effettuata, come descritto, sul vettore misure): le linee (158-161)
effettuano il calcolo di mean nel modo più ovvio; le linee (162-166) valutano il gradiente medio su
una retta come la media delle tre differenze tra la misura di ogni sensore e quella del precedente
(ovviamente, perché tale calcolo abbia senso, si richiederà che i tre sensori vengano disposti sulla
PCB finale ordinati in linea retta secondo l'indirizzo con cui ciascuno di essi viene visto dalmultiplexer). A questo punto, le variabili reali mean e grad contengono i valori calcolati per media
e gradiente. Si tratta tuttavia di valori numerici puri: non è ancora stata effettuata l'operazione di
conversione da numeri binari (prodotti dall'ADC) a valori di temperatura in gradi centigradi. Le
linee (167-169) contengono quindi le istruzioni per effettuare questa conversione: avendo scelto per
l'ADC (a 8 bit) un fondo scala di 128 °C, il LSB assumerà valore 128 °C/28
= 0.5 °C. Questo vuol
dire che l'incremento unitario della parola di conversione dell'ADC corrisponde ad un incremento
della temperatura misurata di 0.5 °C: il coefficiente di proporzionalità per cui moltiplicare i valori
binari mean e grad per ottenere le stesse grandezze in °C (meanT e gradT ) è quindi proprio 0.5.
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 42/58
42
La prima operazione che viene effettuata sulle due nuove misure indirette calcolate è il confronto di
meanT con le due soglie (superiore e inferiore) predefinite, alle linee (170-180). I due test vengono
effettuati in maniera indipendente: se, ad esempio, meanT dovesse risultare inferiore alla soglia
minima prefissata, il micro pone a 0 il bit LOW , accendendo così il LED blu che segnala quindi una
temperatura media sotto soglia. Per il bit HIGH vale un discorso analogo.
La parte successiva del ciclo, compresa nelle linee (181-198) controlla l'aggiornamento del display
con entrambe le misure indirette calcolate. Per la preparazione della stringa da inviare al display
(bufferizzata nella variabile stringa ROW ) viene impiegata l'istruzione C sprintf, presente nella
libreria standard del linguaggio C "stdio.c", richiamata attraverso il relativo file header. La stringa
di formato impiegata per la rappresentazione dei due numeri reali meanT e gradT prevede l'utilizzo
di due cifre per la parte intera e una per la parte decimale (separate tra loro da un punto); il carattere
'C', stampato sul display, indica quindi che si tratta di misure espresse in °C. Il ciclo alle linee (185-
189) utilizza come condizione la fine della stringa: quando il carattere verificato coincide con il
carattere di terminazione della stringa (in linguaggio C, è il carattere '\0'), il ciclo si interrompe,
poiché la stringa ROW è stata stampata interamente. Lo stesso discorso può essere ripetuto in
maniera pressoché identica per la stampa della seconda linea del display, con l'unica differenza che
alla linea (191) viene ovviamente indirizzato il byte della DD-RAM relativo all'inizio della riga 2.
Il segmento di codice alle linee (199-229) è destinato all'eventuale svuotamento del vettore buffer
sulla porta seriale. Come desumibile dalla linea (200), non è detto che la trasmissione seriale delle
misure acquisite debba verificarsi ogni volta che il programma accede al blocco condizionale
associato alla condizione i == 64: la condizione che si deve verificare perché la trasmissione abbia
luogo è che essa venga esplicitamente richiesta dall'interlocutore attraverso l'invio di un qualche
carattere. In particolare, si è scelto di assumere un carattere specifico (nel caso mostrato, la lettera
'a') che, una volta verificato, possa avviare la trasmissione: questo ulteriore controllo, effettuato alla
linea (204), consente di evitare il rischio che un qualsiasi disturbo, magari anche a connettore
staccato, possa attivare questo segmento di codice. Una volta verificata questa condizione, si
procede alla trasmissione delle misure vera e propria, compresa nelle linee (205-228): la primaoperazione che viene effettuata è la disabilitazione della ricezione seriale, quindi si procede in un
ciclo for ad ogni iterazione del quale viene trasmesso un singolo elemento del vettore buffer . Poiché
il protocollo RS-232 è progettato unicamente per la trasmissione di dati alfanumerici, non sarebbe
possibile inviare le parole acquisite dall'ADC così come sono (ovvero dati binari), ma è necessario
sottoporle ad una conversione che le renda adatte al protocollo di comunicazione. Inizialmente si
era pensato di esprimere ognuno dei 256 valori possibili dell'i-esimo byte di buffer attraverso la sua
rappresentazione esadecimale, da cui il nome del vettore hex_val: così facendo, sarebbero state
sufficienti, com'è ovvio, due sole cifre alfanumeriche. Successivamente, si è osservato come questo
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 43/58
43
tipo di approccio risultava in una procedura di conversione di inutile complessità; la scelta operata è
stata allora quella di collocarsi in un qualsiasi punto della tavola ASCII mediante un opportuno
valore di offset (hex_offset , appunto) e inviare quindi i caratteri che si ottenevano sommando a
questo offset il valore binario da trasmettere. Per l'offset è stato scelto il valore 0x30 (48 in
rappresentazione decimale), che corrisponde proprio al carattere '0': sulla tavola ASCII seguono i
caratteri '1','2', e così via fino a '9', quindi ':', ';', e altri, fino ad arrivare all'elemento alla riga
hex_offset +15 (si intende questo nella linea di commento in cui si fa riferimento ad un codice
esadecimale "non standard": rispetto all'esadecimale noto, in fondo, si sono solo cambiati i simboli
relativi ai valori maggiori o uguali a 10). Quindi, si effettua separatamente la conversione in questo
formato della parte alta e della parte bassa del byte buffer[i], e si procede infine alla trasmissione
dei due caratteri ASCII dello stesso, alle linee (218-225): come la UART dell'8051 richiede di fare,
si pone a 0 il flag di trasmissione TI, si scrive il valore da trasmettere serialmente nel registro
SBUF, e si rinchiude il flusso di programma in un ciclo while che, per uscire, attende che il flag TI
venga attivato (è il segnale che la trasmissione del byte è conclusa); quindi, si ripete l'operazione
per entrambi i caratteri. La linea (227) contiene l'istruzione che riabilita la ricezione seriale, per le
iterazioni successive sul riempimento di buffer . Le ultime linee di codice (228-234), infine, oltre a
chiudere cicli e blocchi condizionali rimasti aperti, svolgono la sola funzione, alla fine del blocco if
(quindi ancora solo nel caso di i pari a 64) di azzerare la variabile i e avviare una nuova
conversione: esse consentono quindi la produzione di un successivo riempimento del vettore buffer ,
che viene così sovrascritto con le nuove misure acquisite.
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 44/58
44
Conclusioni
Le ultime fasi del flusso di progettoLa procedura di debug del codice C prodotto verrà svolta mediante le seguenti modalità. Una volta
che la simulazione del sorgente su ambiente Keil abbia dato esito positivo, il codice esadecimale
prodotto verrà passato all'emulatore e quindi testato direttamente su PCB. In questa fase, verrà
impiegato lo strumento di emulazione HITOP. Da un punto di vista hardware, è possibile connettere
l'emulatore alla PCB su cui sarà montato il circuito da testare attraverso un opportuno pad, sul quale
a sua volta sarà montato il nostro micro 80C32. Sarà in questo modo possibile già a questo punto
(prima quindi della realizzazione della PCB vera e propria) verificare la funzionalità del circuito in
ogni sua parte, fatta eccezione unicamente per la ROM e per il D-Latch (e relative connessioni),
sostituite nella funzione di fornire il codice da eseguire al micro dall'emulatore stesso.Procedendo in questo modo, sarà possibile individuare quali segmenti del codice assembler
producono errore e quindi, attraverso il disassembly del Keil, su quali istruzioni C del sorgente
intervenire. Tale procedura di test potrà essere ripetuta per ogni unità funzionale del circuito, prima
di essere effettuata sul circuito complessivo; in particolare, verranno testati separatamente il
funzionamento della unità di conversione A/D delle misure di temperatura, del display LCD e infine
della comunicazione su porta seriale con il PC. Relativamente a questo punto, il primo test verrà
effettuato mediante l'utilizzo dell'Hyper Terminal di Windows; da questo test, quindi, sarà possibile
produrre le specifiche di progetto per l'applicativo Visual Basic da sviluppare. Anche questo
applicativo verrà quindi sottoposto a test direttamente nella comunicazione seriale col micro. Infine,
sarà possibile testare il sistema complessivo (con il codice C sviluppato ancora in fase di
emulazione).
Come ovvio, per ragioni di brevità, la descrizione del lungo processo di "trial & error" che ha
portato alla produzione del codice completo e corretto è interamente omessa. Nelle sezioni seguenti
vengono piuttosto forniti alcuni dettagli relativi alla fase di test, le indicazioni principali sulla
realizzazione del layout della PCB e, infine, poche considerazioni su eventuali possibili sviluppi
futuri per un progetto di tipo analogo.
Test su breadboardLa breadboard di test realizzata è rappresentata in Fig.25. Essa è completa di tutte le connessioni,
fatta eccezione per i tre LED (di ridotta criticità rispetto agli obiettivi del test stesso) e per la
componentistica di supporto al micro (circuito di clock, D-LATCH, ROM) resa inutile dai segnali
forniti dall'emulatore stesso. In basso a sinistra è stata montata la sezione relativa al riferimento di
tensione destinato all'ADC (sono riconoscibili il trimmer e l'integrato TO-92, l'LM385); in basso a
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 45/58
45
destra è stata collocata la schiera degli LM35, disposti in modo arbitrario solo per la fase di test
(come anticipato, nel disegno del layout finale della scheda si opererà diversamente); il primo
integrato sulla destra a partire dal basso è il multiplexer analogico, la cui uscita è diretta all'ADC (il
terzo integrato a partire dal basso); il secondo integrato dal basso è l'inverter, mentre quello più in
alto è il convertitore di livello (è riconoscibile in questo caso la sezione di condensatori elettrolitici
richiesti dal dispositivo nel suo normale funzionamento); sulla parte sinistra della breadboard è stato
montato il pad, su cui è collocato a sua volta l'80C32 (anche se non visibile, il cavo che si
interrompe sulla sinistra è connesso al modulo HITOP); subito alla sinistra del pad è riconoscibile il
modulo L2014.
Figura 25: Breadboard montata per la fase di test.
Il display LCD è rappresentato nel dettaglio di Fig.26: in questa figura è possibile leggere (sebbene
sfocate) le misure indirette stampate sul display stesso. Si misura un valor medio complessivo di
+15.5 °C e un gradiente medio pari a -0.1 °C (come già indicato, in questa fase di test tale misura
non ha alcun significato, data la disposizione arbitraria dei sensori).
Figura 26: Dettaglio sul display LCD.
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 46/58
46
Ancora con riferimento alla Fig.25, è possibile distinguere un cavo che si allontana dalla breadboard
verso destra: si tratta del cavo seriale impiegato per realizzare la connessione verso il PC. In questa
fase di test si sono potute sperimentare anche le funzionalità dell'applicativo su PC destinato alla
raccolta, archiviazione, elaborazione e rappresentazione grafica delle misure acquisite (il sorgente
di tale programma, riportato per completezza in appendice, è stato prodotto in linguaggio Visual
Basic). La screenshot in Fig.27 riproduce la schermata principale dell'applicativo.
Figura 27: Schermata principale dell'applicativo VB.
Innanzitutto, nel menu "File" sono accessibili unicamente le scelte "About" (che produce un
messaggio con le informazioni sul programma) e "Exit" (che chiude il programma). Nel menu
"Opzioni", sono invece accessibili le scelte relative a quale porta seriale (COM1/COM2)
selezionare per la acquisizione delle misure. Come ulteriore alternativa (opzione "Test without
COM"), è possibile testare l'applicativo in assenza di acquisizioni via seriale: in questo caso,
chiaramente, il programma simulerà l'acquisizione di misure che saranno però valori pseudocasuali.
Al momento della acquisizione della screenshot in Fig.27, era selezionata l'opzione COM2 (la porta
COM1 del PC era stata destinata al modulo HITOP, quindi non era disponibile): le misure indirette
di media e gradiente riportate sono allora associate a valori di temperatura realmente acquisiti. La
prima casella di testo (in bianco) è l'unico testo editabile e ammette unicamente numeri interi
positivi: si tratta del numero di acquisizioni ripetute che si richiede al sistema di effettuare. La
casella di testo affianco contiene invece il numero complessivo di acquisizioni effettuate a partire
dall'ultimo reset fino a quel momento (naturalmente, le misure indirette riportate di seguito si
riferiscono a tutte queste acquisizioni). Quindi, le successive caselle di testo contengono i dati
descritti dalle rispettive label, tutti in unità °C: la media per un sensore rappresenta il valore medio
di temperatura calcolato su quel sensore; il gradiente per un sensore rappresenta il valore medio
delle differenze tra ogni coppia di valori di temperatura (si considerano in questo caso coppie di
valori acquisiti in maniera successiva nel tempo, il gradiente in questione è quindi di natura
temporale e non spaziale); la media complessiva rappresenta il valore medio di temperatura
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 47/58
47
calcolato su tutti i sensori; il gradiente complessivo rappresenta il valore medio delle differenze tra i
valori medi di temperatura su coppie di sensori adiacenti (questo è allora un gradiente spaziale).
Chiariamo ora la funzione dei button: il pulsante "Acquire" avvia le procedure destinate ad
effettuare il numero indicato di acquisizioni ripetute; il pulsante "Restart" effettua un reset del
programma (le misure precedentemente acquisite verranno quindi, eventualmente, perse); il
pulsante "Save" apre una finestra di dialogo per il salvataggio su file (in formato .txt) delle misure
acquisite fino a quel momento dal micro. A titolo di esempio, si riporta di seguito la prima riga
scritta dalla procedura di salvataggio su file in un file "misure.txt" prodotto durante il test finale:
|016,0-016,0-016,0-015,0-015,5-015,0-015,5-016,0-017,0-
016,0|015,5-015,5-015,5-015,5-016,5-016,0-016,0-015,5-015,5-
015,5|015,0-015,5-015,5-016,0-016,0-015,5-016,0-016,0-016,0-
015,0|014,5-015,5-015,0-016,0-015,0-015,0-015,5-015,5-016,0-
015,5|23/09/2007-18.02.33-COM2
Le misure vengono salvate in formato testuale, espresse in gradi centigradi. Il carattere speciale '|'
ha la funzione di terminazione: indica l'inizio e la fine della stringa di misure; il carattere speciale ','
ha la funzione di separare parte intera e parte decimale di ogni misura. Alla fine della stringa di 64
misure (ovvero di un buffer completo acquisito dal micro), vengono salvate anche ulteriori
informazioni, separate dal carattere '-' e relative alla specifica acquisizione effettuata, quali data e
ora dell'acquisizione da micro e porta seriale di comunicazione.
Infine, i quattro button "View PDF", associato ciascuno ad un sensore, consentono di rappresentareun grafico della densità di probabilità dei valori acquisiti dal relativo sensore. In Fig.28 sono
rappresentati due dei quattro grafici che era possibile ottenere, in particolare quelli relativi ai sensori
0 e 3 (come indicato nei titoli delle finestre).
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 48/58
48
Figura 28(a-b): Rappresentazione grafica della densità di probabilità dei valori acquisiti dai sensori 0 e 3.
Realizzazione layout della PCBCome già indicato, per lo sviluppo della documentazione relativa alla PCB è stato utilizzato il
pacchetto software Orcad, in particolare i tool Capture e Layout. Questo secondo tool è proprio
quello necessario a produrre i file gerber necessari alla realizzazione della PCB. Uno dei principali
punti di forza del pacchetto software scelto è probabilmente proprio l'immediatezza con cui è
possibile passare dalla rappresentazione del circuito sottoforma di schematico alla realizzazione del
layout: molte delle operazioni da effettuare (essenzialmente placement dei componenti e routing
delle piste) sono o possono essere rese automatiche, e ciò funziona particolarmente bene se, come
nel nostro caso, il circuito non presenta particolari criticità in termini di accoppiamento
elettromagnetico tra i componenti o tra le piste stesse.
Una volta realizzato lo schematico, Orcad Capture è in grado di produrre autonomamente la netlist,
ovvero un file di estensione .mnl che contiene la descrizione completa del circuito in formato
testuale. All'avvio di Orcad Layout, è possibile chiedere che il software carichi proprio tale netlist,
associandola ad un opportuno file template, contenente nient'altro che informazioni generali dinatura tecnologica sul tipo di scheda che si intende realizzare. L'unica operazione che si richiede
all'utente di effettuare è quella di associazione di un footprint adeguato ad ogni dispositivo (o più in
generale, ad ogni black-box) del circuito, fatta eccezione per i componenti già a livello di
schematico presi dalle librerie di Orcad. I possibili modi di procedere sono due: crearsi una libreria
di footprint adatti ai dispositivi utilizzati e destinata quindi allo specifico progetto; viceversa,
utilizzare i footprint già messi a disposizione dalle librerie di Orcad ma rinominare i pin di ciascun
dispositivo sullo schematico in modo tale che vi sia corrispondenza con il relativo footprint scelto
(nel nostro caso, è stata scelta la seconda opzione). Tutto ciò che segue può essere effettuato in
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 49/58
49
maniera automatica: nella nostra applicazione, si è richiesta una particolare disposizione per i
sensori di temperatura, che devono essere disposti in linea retta nell'ordine corretto (secondo quanto
già specificato) nel layout finale; ulteriori preferenze specifiche di collocazione della porta seriale,
del display e dei LED hanno suggerito di effettuare in maniera manuale il piazzamento dei
componenti della scheda. Viceversa, l'operazione di sbroglio delle connessioni è stata eseguita in
modo automatico: si è richiesta in particolare la generazione di uno sbroglio per una scheda a due
livelli (top e bottom).
Figura 29: Rappresentazione del layout complessivo (le piste relative ai due strati sono rappresentate con colori diversi).
Una volta corretti gli errori segnalati dal DRC (Design Rule Check) e ripetuto lo sbroglio, si è prima
di tutto ottenuta la rappresentazione del layout complessivo riportata in Fig.29, quindi le piste e le
vie stampate in distintamente per i due strati in Fig.30 (come spesso accade, lo strato di bottom è
stato specchiato rispetto all'originale).
Figura 30(a-b): Rappresentazione di piste e vie per il top (a sinistra) e per il bottom (a destra) della PCB.
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 50/58
50
Considerazioni finali: possibili sviluppiGli aspetti del sistema progettato che potrebbe risultare opportuno ottimizzare sono numerosi.
Innanzitutto, si potrebbe senza alcuno sforzo pensare di incrementare il numero di sensori di
temperatura impiegati, per esempio arrivando a 16: questo implicherebbe ovviamente anche
l'utilizzo di un multiplexer di dimensione doppia, il che a sua volta comporterebbe il problema di
dover rinunciare magari a qualcuno dei LED di segnalazione per far posto al nuovo bit di selezione
destinato al multiplexer. Tali 16 sensori potrebbero quindi essere disposti in maniera uniforme su
una superficie quadrata: in tal modo, sarebbe possibile ottenere dalle misure acquisite informazioni
sulla distribuzione superficiale di un campo di temperatura (risulterebbe tuttavia a questo punto
necessario calcolare solo il gradiente lungo due direzioni ortogonali). Si potrebbe ancora pensare di
migliorare l'aspetto relativo alla collocazione temporale delle misure acquisite, in modo tale da
consentire misure derivate di variazione della temperatura nel tempo. Ancora nell'ipotesi di riuscire
a fare posto a qualche segnale di controllo sulle porte parallele del micro, potrebbe risultare
possibile ottenere la comunicazione del circuito con un PC remoto attraverso connessione wireless a
corto raggio (ad esempio, in standard Bluetooth), il che renderebbe il sistema adatto ad effettuare
misure in condizioni più estreme (dove, generalmente, un operatore umano non può arrivare).
Infine, nulla esclude che il sistema progettato (inteso come interazione tra micro 8051-like, modulo
LCD, ADC e connessione via seriale con PC) possa essere modificato per adattarsi all'acquisizione
ed elaborazione elementare di dati prelevati da sensori diversi da quelli di temperatura.
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 51/58
51
Appendice: codice sorgente Visual Basic
Per ragioni di completezza, si riporta di seguito il codice sorgente VB dell'applicativo sviluppato
per l'interazione del PC con il micro via seriale. Naturalmente, tale sorgente è da ritenersi completo
solo in associazione alla sua parte visuale, la descrizione della quale è stata omessa nella presente
relazione.
In ogni caso, tutta la documentazione prodotta in ambiente VB durante lo sviluppo di tale
applicativo, così come quella prodotta in ambienti Orcad e Keil, è riportata in formato digitale nel
CD allegato alla presente relazione.
Option Explicit
Dim rs As Recordset
Dim buffer As String
Dim receive_req As Boolean
Dim porta As IntegerDim times As Long
Dim j As Integer
Private Sub About_Click()
MsgBox ("Misuratore di temperatura v1.0" & vbCr & "Authors: Columbo Lorenzo" & vbCr & "
Columbo Gaetano")
End Sub
Private Sub bt_acquire_Click()
'
' Controlla che sia stata operata la scelta "PORTA COM"
'
If COM1.Checked = False And COM2.Checked = False And Test_without_COM.Checked = False Then
MsgBox ("Seleziona porta COM da Opzioni")
Exit Sub
End If
If Test_without_COM.Checked = True Then porta = 0
If COM1.Checked = True Then porta = 1
If COM2.Checked = True Then porta = 2
If porta > 0 Then
If apri_porta = False Then
MsgBox ("Impossibile proseguire.")
Exit Sub
End If
End If
'
' Controlla che frm_acquire sia integer
'
If Not IsNumeric(frm_acquire) Then
MsgBox ("Valore non ammesso.")frm_acquire.SetFocus
Exit Sub
End If
If Not frm_acquire > 0 Then
MsgBox ("Valore non ammesso.")
frm_acquire.SetFocus
Exit Sub
End If
times = 1
'... Sollecita invio e attende ricezione buffer BYTEWISE (se non è test)
Frame1.Enabled = False
buffer = ""
If porta > 0 Then
MSComm1.Output = "a"
Else
For times = 1 To frm_acquire
buffer = genera
Call acquire
Next
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 52/58
52
Call elaborate
Frame1.Enabled = True
End If
End Sub
Private Sub acquire()
Dim ora As String
'
' Effettua una volta la scrittura nel rs delle 64 misure
'rs.AddNew
'... Ricevi buffer seriale alla data e ora e da sorgente
rs.Fields("data") = Date
ora = Time
rs.Fields("ora") = ora
Select Case porta
Case 0
rs.Fields("source") = "TEST"
Case 1
rs.Fields("source") = "COM1"
Case 2
rs.Fields("source") = "COM2"
End Select
'... Costruisci campi misure
For j = 1 To 128 Step 8
rs.Fields("misure_0") = rs.Fields("misure_0") & Format((codice(Mid(buffer, j + 0, 2)) *
0.5), "000.0")
rs.Fields("misure_1") = rs.Fields("misure_1") & Format((codice(Mid(buffer, j + 2, 2)) *
0.5), "000.0")
rs.Fields("misure_2") = rs.Fields("misure_2") & Format((codice(Mid(buffer, j + 4, 2)) *
0.5), "000.0")
rs.Fields("misure_3") = rs.Fields("misure_3") & Format((codice(Mid(buffer, j + 6, 2)) *
0.5), "000.0")
Next
bt_save.Visible = True
ridimensiona (1)
End Sub
Private Sub elaborate()Dim i As Integer
Dim w_media As Double
Dim w_media_c As Double
Dim w_grad As Double
Dim w_grad_c As Double
Dim w_num As Double
'
'... Calcola e visualizza le medie
'
w_media_c = 0
'... Calcola e visualizza la media di sensore 0
rs.MoveFirst
w_media = 0
Do While Not rs.EOFFor i = 1 To 80 Step 5
w_num = Mid(rs.Fields("misure_0"), i, 5)
w_media = w_media + w_num
Next
rs.MoveNext
Loop
w_media_c = w_media_c + w_media
w_media = w_media / (rs.RecordCount * 16)
frm_media(0) = Format(Round(w_media, 2), "##0.00")
'... Calcola e visualizza la media di sensore 1
rs.MoveFirst
w_media = 0
Do While Not rs.EOF
For i = 1 To 80 Step 5
w_num = Mid(rs.Fields("misure_1"), i, 5)
w_media = w_media + w_num
Next
rs.MoveNext
Loop
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 53/58
53
w_media_c = w_media_c + w_media
w_media = w_media / (rs.RecordCount * 16)
frm_media(1) = Format(Round(w_media, 2), "##0.00")
'... Calcola e visualizza la media di sensore 2
rs.MoveFirst
w_media = 0
Do While Not rs.EOF
For i = 1 To 80 Step 5
w_num = Mid(rs.Fields("misure_2"), i, 5)
w_media = w_media + w_num
Nextrs.MoveNext
Loop
w_media_c = w_media_c + w_media
w_media = w_media / (rs.RecordCount * 16)
frm_media(2) = Format(Round(w_media, 2), "##0.00")
'... Calcola e visualizza la media di sensore 3
rs.MoveFirst
w_media = 0
Do While Not rs.EOF
For i = 1 To 80 Step 5
w_num = Mid(rs.Fields("misure_3"), i, 5)
w_media = w_media + w_num
Next
rs.MoveNext
Loop
w_media_c = w_media_c + w_media
w_media = w_media / (rs.RecordCount * 16)
frm_media(3) = Format(Round(w_media, 2), "##0.00")
'... Calcola e visualizza la media complessiva
w_media_c = w_media_c / (rs.RecordCount * 64)
frm_media_c = Format(Round(w_media_c, 2), "##0.00")
'
'... Calcola e visualizza i gradienti
'
w_grad_c = 0
'... Calcola e visualizza il gradiente di sensore 0
rs.MoveFirst
w_grad = 0
Do While Not rs.EOFFor i = 1 To 71 Step 5
w_num = Mid(rs.Fields("misure_0"), i + 5, 5) - Mid(rs.Fields("misure_0"), i, 5)
w_grad = w_grad + w_num
Next
rs.MoveNext
Loop
w_grad = w_grad / (rs.RecordCount * 16 - 1)
frm_grad(0) = Format(Round(w_grad, 2), "##0.00")
'... Calcola e visualizza il gradiente di sensore 1
rs.MoveFirst
w_grad = 0
Do While Not rs.EOF
For i = 1 To 71 Step 5
w_num = Mid(rs.Fields("misure_1"), i + 5, 5) - Mid(rs.Fields("misure_1"), i, 5)
w_grad = w_grad + w_numNext
rs.MoveNext
Loop
w_grad = w_grad / (rs.RecordCount * 16 - 1)
frm_grad(1) = Format(Round(w_grad, 2), "##0.00")
'... Calcola e visualizza il gradiente di sensore 2
rs.MoveFirst
w_grad = 0
Do While Not rs.EOF
For i = 1 To 71 Step 5
w_num = Mid(rs.Fields("misure_2"), i + 5, 5) - Mid(rs.Fields("misure_2"), i, 5)
w_grad = w_grad + w_num
Next
rs.MoveNext
Loop
w_grad = w_grad / (rs.RecordCount * 16 - 1)
frm_grad(2) = Format(Round(w_grad, 2), "##0.00")
'... Calcola e visualizza il gradiente di sensore 3
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 54/58
54
rs.MoveFirst
w_grad = 0
Do While Not rs.EOF
For i = 1 To 71 Step 5
w_num = Mid(rs.Fields("misure_3"), i + 5, 5) - Mid(rs.Fields("misure_3"), i, 5)
w_grad = w_grad + w_num
Next
rs.MoveNext
Loop
w_grad = w_grad / (rs.RecordCount * 16 - 1)
frm_grad(3) = Format(Round(w_grad, 2), "##0.00")
'... Calcola e visualizza il gradiente complessivo
w_grad_c = Val(Replace(frm_media(3), ",", ".")) - Val(Replace(frm_media(0), ",", "."))
w_grad_c = w_grad_c / 3
frm_grad_c = Format(Round(w_grad_c, 2), "##0.00")
'... Visualizza numero totale acquisizioni al momento
frm_acquired = rs.RecordCount
End Sub
Private Function apri_porta() As Boolean
On Error GoTo errore
With MSComm1
If .PortOpen Then .PortOpen = False
.CommPort = porta
.Settings = "9600,N,8,1"
.RThreshold = 1
.SThreshold = 0 'default
.PortOpen = True
End With
apri_porta = True
Exit Function
errore:
MsgBox ("from apri_porta: " & Err.Description & ". Abort")
apri_porta = False
End Function
Private Function genera() As String
Dim i As Integer
Dim valore As Integer
Dim car As String
Dim cifra As IntegerFor i = 1 To 128
valore = Int(16 * Rnd) + 48
car = car & Chr(valore)
Next
' For i = 1 To 64
' valore = 1
' cifra = valore / 16
' car = car & Trim(Str(cifra)) & Trim(Str(valore - cifra * 16))
' Next
genera = car
End Function
Private Sub bt_save_Click()
salva_rsEnd Sub
Private Sub salva_rs()
Dim i As Integer
Dim riga As String
Dim filename As String
'... Verifica se rs esiste e non è vuoto
If rs Is Nothing Then Exit Sub
If rs.RecordCount = 0 Then Exit Sub
'... ottieni nome file
filename = get_filename
'... se "annulla", abbandona
If Len(Trim(filename)) = 0 Then Exit Sub
If SE_FILE_ESISTENTE(filename) Then
If MsgBox("Il file esiste. Sovrascrivo?", vbYesNo) = 7 Then
'... abbandona
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 55/58
55
Exit Sub
End If
End If
'... Scrittura del file
rs.MoveFirst
Open CommonDialog1.filename For Output As #1
Do While Not rs.EOF
riga = "|"
'... Rappresentazione misure per sensore
For i = 1 To 48 Step 5riga = riga & Mid(rs.Fields("misure_0"), i, 5) & "-"
Next
riga = Mid(riga, 1, Len(riga) - 1) & "|"
For i = 1 To 48 Step 5
riga = riga & Mid(rs.Fields("misure_1"), i, 5) & "-"
Next
riga = Mid(riga, 1, Len(riga) - 1) & "|"
For i = 1 To 48 Step 5
riga = riga & Mid(rs.Fields("misure_2"), i, 5) & "-"
Next
riga = Mid(riga, 1, Len(riga) - 1) & "|"
For i = 1 To 48 Step 5
riga = riga & Mid(rs.Fields("misure_3"), i, 5) & "-"
Next
riga = Mid(riga, 1, Len(riga) - 1) & "|"
riga = riga & rs.Fields("data") & "-"
riga = riga & rs.Fields("ora") & "-"
riga = riga & rs.Fields("source")
'... Scrittura su file
Print #1, riga
rs.MoveNext
Loop
Close #1
bt_save.Visible = False
End Sub
Private Function get_filename() As StringCommonDialog1.filename = ""
CommonDialog1.Filter = "File di testo (*.txt)|*.txt"
CommonDialog1.FilterIndex = 1
CommonDialog1.ShowOpen
If Len(CommonDialog1.filename) = 0 Then
MsgBox ("Nome file mancante")
Exit Function
End If
get_filename = CommonDialog1.filename
End Function
Private Function SE_FILE_ESISTENTE(File As String) As Boolean
Dim fs
Set fs = CreateObject("Scripting.FileSystemObject")
If fs.fileexists(Trim(File)) ThenSE_FILE_ESISTENTE = True
Else
SE_FILE_ESISTENTE = False
End If
End Function
Private Sub COM1_Click()
COM1.Checked = Not COM1.Checked
COM2.Checked = False
Test_without_COM.Checked = False
End Sub
Private Sub COM2_Click()
COM2.Checked = Not COM2.Checked
COM1.Checked = False
Test_without_COM.Checked = False
End Sub
Private Function codice(esa As String) As Integer
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 56/58
56
If Len(esa) <> 2 Then
MsgBox ("From codice: Valore esa errato")
codice = 0
Exit Function
End If
If Mid(esa, 1, 1) >= "0" And Mid(esa, 1, 1) <= "?" Then
Else
MsgBox ("From codice: Primo carattere esa errato della coppia: " & esa & " di indice: " & j)
codice = 0
Exit Function
End If
If Mid(esa, 2, 1) >= "0" And Mid(esa, 2, 1) <= "?" Then
Else
MsgBox ("From codice: Secondo carattere esa errato della coppia: " & esa & " di indice: " &
j)
codice = 0
Exit Function
End If
codice = ((Asc(Mid(esa, 1, 1)) - 48) * 16) + ((Asc(Mid(esa, 2, 1)) - 48) * 1)
End Function
Private Sub Exit_Click()
Unload MDIForm1
End Sub
Private Sub PDF0_Click()
Dim w_misure As String
Dim w_valore As Double
Dim i As Integer
'... Costruzione del vettore delle occorrenze normalizzato per il sensore 0
For v_ind = 0 To 255
rs.MoveFirst
v_occur(v_ind) = 0
Do While Not rs.EOF
w_misure = rs.Fields("misure_0")
For i = 0 To 15
w_valore = Mid(w_misure, (i * 5) + 1, 5)
If w_valore = v_gradi(v_ind) Then v_occur(v_ind) = v_occur(v_ind) + 1
Next
rs.MoveNextLoop
v_occur(v_ind) = v_occur(v_ind) / (rs.RecordCount * 16)
Next
'... Apre il frm_chart0
frm_chr0.Show
End Sub
Private Sub PDF1_Click()
Dim w_misure As String
Dim w_valore As Double
Dim i As Integer
'... Costruzione del vettore delle occorrenze normalizzato per il sensore 1
For v_ind = 0 To 255
rs.MoveFirstv_occur(v_ind) = 0
Do While Not rs.EOF
w_misure = rs.Fields("misure_1")
For i = 0 To 15
w_valore = Mid(w_misure, (i * 5) + 1, 5)
If w_valore = v_gradi(v_ind) Then v_occur(v_ind) = v_occur(v_ind) + 1
Next
rs.MoveNext
Loop
v_occur(v_ind) = v_occur(v_ind) / (rs.RecordCount * 16)
Next
'... Apre il frm_chart1
frm_chr1.Show
End Sub
Private Sub PDF2_Click()
Dim w_misure As String
Dim w_valore As Double
Dim i As Integer
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 57/58
57
'... Costruzione del vettore delle occorrenze normalizzato per il sensore 1
For v_ind = 0 To 255
rs.MoveFirst
v_occur(v_ind) = 0
Do While Not rs.EOF
w_misure = rs.Fields("misure_2")
For i = 0 To 15
w_valore = Mid(w_misure, (i * 5) + 1, 5)
If w_valore = v_gradi(v_ind) Then v_occur(v_ind) = v_occur(v_ind) + 1
Next
rs.MoveNextLoop
v_occur(v_ind) = v_occur(v_ind) / (rs.RecordCount * 16)
Next
'... Apre il frm_chart2
frm_chr2.Show
End Sub
Private Sub PDF3_Click()
Dim w_misure As String
Dim w_valore As Double
Dim i As Integer
'... Costruzione del vettore delle occorrenze normalizzato per il sensore 1
For v_ind = 0 To 255
rs.MoveFirst
v_occur(v_ind) = 0
Do While Not rs.EOF
w_misure = rs.Fields("misure_3")
For i = 0 To 15
w_valore = Mid(w_misure, (i * 5) + 1, 5)
If w_valore = v_gradi(v_ind) Then v_occur(v_ind) = v_occur(v_ind) + 1
Next
rs.MoveNext
Loop
v_occur(v_ind) = v_occur(v_ind) / (rs.RecordCount * 16)
Next
'... Apre il frm_chart2
frm_chr3.Show
End Sub
Private Sub bt_restart_Click()'... Riavvia il programma: svuota gli array e ridimensiona main
If Not rs Is Nothing Then
If rs.RecordCount > 0 And bt_save.Visible = True Then
If MsgBox("Salvo elaborazione precedente?", vbYesNo) = 6 Then
salva_rs
Else
bt_save.Visible = False
End If
End If
rs.Close
frm_acquired = ""
ridimensiona (0)
frm_acquire = ""
frm_acquire.SetFocus
apri_rs
End IfEnd Sub
Private Sub Form_Load()
'
'... Inizializza
'
set_v_gradi
ridimensiona (0)
apri_rs
End Sub
Private Sub set_v_gradi()
For v_ind = 0 To 255
v_gradi(v_ind) = v_ind * 0.5
Next
End Sub
Private Sub ridimensiona(aspetto As Integer)
Select Case aspetto
Case 0
5/9/2018 Progetto Di Un Misuratore Di Temperatura - slidepdf.com
http://slidepdf.com/reader/full/progetto-di-un-misuratore-di-temperatura 58/58
58
main.Height = 1300
main.ScaleHeight = 720
Case 1
main.Height = 4020
main.ScaleHeight = 3240
End Select
End Sub
Private Sub apri_rs()
'... Verifica che il recordset non sia già aperto
If Not rs Is Nothing Then
Set rs = NothingEnd If
Set rs = New ADODB.Recordset
'... Definisce la struttura del record set
rs.Fields.Append "misure_0", adVarChar, 80
rs.Fields.Append "misure_1", adVarChar, 80
rs.Fields.Append "misure_2", adVarChar, 80
rs.Fields.Append "misure_3", adVarChar, 80
rs.Fields.Append "data", adDate
rs.Fields.Append "ora", adVarChar, 8
rs.Fields.Append "source", adVarChar, 4
rs.CursorLocation = adUseClient
rs.Open , , adOpenStatic, adLockBatchOptimistic
End Sub
Private Sub Test_without_COM_Click()
Test_without_COM.Checked = Not Test_without_COM.Checked
COM1.Checked = False
COM2.Checked = False
End Sub
Private Sub MSComm1_OnComm()
Dim carattere
If MSComm1.CommEvent = comEvReceive Then
carattere = MSComm1.Input
If carattere = vbCr Then Exit Sub
buffer = buffer & carattere
End If
If Len(buffer) = 128 Then
acquire
If times < frm_acquire Then
buffer = ""
MSComm1.Output = "a"times = times + 1
Else
Call elaborate
Frame1.Enabled = True
End If
End If
End Sub