Relazione di progetto per il corso di Misure Elettroniche
Progettazione e realizzazione di una piccola
STAZIONE METEOROLOGICA
Andrea Coslovich
Daniele Palazzolo
Fabio Piccolo
Università degli Studi di Trieste
Facoltà di Ingegneria
Dipartimento di Elettrotecnica, Elettronica ed Informatica
8 Aprile 2003
Indice
1 Introduzione
1
2 Progettazione dell’hardware
2.1 Circuiti analogici per la misura . . . . . . . .
2.1.1 Misura della temperatura interna . . .
2.1.2 Misura della temperatura esterna . . .
2.1.3 Misura dell’umidità . . . . . . . . . .
2.1.4 Misura della pressione atmosferica . .
2.2 Multiplexing e conversione analogico/digitale
2.2.1 Multiplexing . . . . . . . . . . . . . .
2.2.2 Conversione analogico/digitale . . . .
2.3 Le altre parti del circuito . . . . . . . . . . .
2.3.1 Alimentazione . . . . . . . . . . . . .
2.3.2 Riferimento . . . . . . . . . . . . . . .
2.4 Schema elettrico e lista dei componenti . . . .
2
2
2
3
3
4
4
4
5
5
5
5
5
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3 Realizzazione dell’hardware
11
3.1 Layout dei PCB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
4 Taratura
12
4.1 Temperatura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
4.2 Umidità . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
4.3 Pressione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
5 Realizzazione del software di gestione
5.1 Gestione della comunicazione . . . . . . . .
5.2 Serializzazione degli accessi all’hardware . .
5.3 Formati di output e loro utilizzo . . . . . .
5.4 Osservazioni sui permessi di accesso all’I/O
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
14
14
14
15
15
6 Bibliografia
16
7 Ringraziamenti
17
A APPENDICE: Codice sorgente del software di gestione
A.1 File meteo010.c . . . . . . . . . . . . . . . . . . . . . . . .
A.2 File semaf.c . . . . . . . . . . . . . . . . . . . . . . . . . .
A.3 File data.c . . . . . . . . . . . . . . . . . . . . . . . . . . .
A.4 File cgi.c . . . . . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
18
18
25
27
28
B APPENDICE: Esempio di registrazione dati meteorologici
30
C APPENDICE: Note sul copyright e sulla licenza d’uso
31
i
1
Introduzione
Questa relazione descrive il lavoro di progettazione e realizzazione di una piccola stazione meteorologica gestita da personal computer, per l’esame di Misure Elettroniche del professor Claudio
Mangivacchi.
L’obbiettivo del lavoro è stato quello di realizzare una semplice centralina di rilevamento di
dati meteorologici (temperatura, pressione ed umidità) interfacciata ad un computer, consentendo
la visione delle misure tramite rete informatica. Questo approccio ha portato alla progettazione di
un dispositivo collegabile al PC mediante porta parallela e di un software per il sistema operativo
Linux che gestisce l’hardware e sfrutta un web server, nel nostro caso Apache, per la distribuzione
delle informazioni in rete.
Al termine del lavoro ciò che si è ottenuto è:
• Misura della temperatura interna ed esterna con l’accuratezza di 0,5◦ C
• Misura dell’umidità relativa con l’accuratezza dell’1%RH
• Misura della pressione atmosferica con l’accuratezza di 1hPa
• Possibilità di vedere i dati su un qualsiasi PC collegato a InterNet (con web browser)
• Possibilità di memorizzare (su file) i dati ad intervalli di tempo fissi (per usi statistici)
Nei successivi capitoli verranno descritte in modo particolareggiato le fasi di progetto e realizzazione della parte circuitale e di programmazione.
1
2
Progettazione dell’hardware
Il sistema è stato progettato in moda da ottenere una realizzazione piuttosto economica. Questa
impostazione del lavoro ha portato a preferire la realizzazione di un hardware più semplice possibile,
scaricando la complessità sul software. Grazie a questa filosofia di fondo, il circuito realizzato, non
presenta dei componenti di particolare pregio ed è del tutto privo di trimmer o altri sistemi per la
tararura.
Lo schema a blocchi, studiato per il dispositivo, è riportato in figura 1.
Sensore di
temperatura
Condizionamento
Sensore di
temperatura
Condizionamento
Conversione
A/D
Multiplexing
Sensore di
umidità
Condizionamento
Sensore di
pressione
Condizionamento
Porta
Parallela
(Centronics)
PC
Figura 1: Schema a blocchi del sistema hardware
Si possono distinguere le seguenti parti:
• Circuiti di trasformazione delle grandezze fisiche d’interesse in segnali elettrici
• Circuiti di condizionamento (elaborazione dei segnali elettrici)
• Circuito di multiplexing
• Conversione analogico/digitale
2.1
2.1.1
Circuiti analogici per la misura
Misura della temperatura interna
Per la misura della temperatura interna è stato scelto un sensore di grandissima diffusione, l’LM335
della National Semiconductor. Questo dispositivo si comporta grossomodo come un diodo zener,
la cui tensione di zener dipende fortemente dalla temperatura alla quale è sottoposto. Il modo più
semplice per utilizzarlo è quello di alimentarlo mediante una resistenza di qualche kiloohm1 e di
prendere come uscita la tensione che cade ai suoi capi. L’LM335 presenta, inoltre, un terminale
aggiuntivo per la calibrazione che può rimanere inutilizzato se non sono necessarie particolari
funzioni di taratura.
Utilizzando il sensore come descritto poch’anzi si ottiene una tensione variabile all’incirca tra
2,53V e 3,14V per un range di temperature tra -20◦ C e 40◦ C. A questa tensione va quindi sottratto
un offset ed applicata un’amplificazione per portarla in un campo di valori tali da saturare quanto
più possibile la dinamica del convertitore A/D seguente. Per compiere queste operazioni è stato
1
Si è scelto un valore di 4,7KΩ.
2
adoperato un singolo amplificatore operazionale (si veda U3A in figura 3) in configurazione differenziale che provvede ad amplificare circa 5,6 volte e sottrarre una tensione di 14,1V, ricavata a
partire dalla tensione di riferimento di 2,5V (generata con un LM385). Una sifatta configurazione
permette di ottenere una risoluzione massima di 0,3◦ C con un convertitore da 8 bit su dinamica
0-5V che risulta appropriata in quanto l’accuratezza del sensore non supera 0,5◦ C.
La resistenza da 100Ω ed il diodo zener da 4,7V (si vedano D3 e R32), collocati tra il circuito
di condizionamento del segnale ed il CD4051, sono stati inseriti per evitare che eventuali tensioni
maggiori di 5V (l’amplificatore operazionale è stato alimentato a 9V in modo che i segnali tra 0 e
5 volt rientrino in zona di piena linearità) possano entrare nel multiplexer e nel convertitore A/D
danneggiandoli.
2.1.2
Misura della temperatura esterna
Per la misura della temperatura esterna è stato utilizzato il sensore AD590 della Analog Devices
avente in uscita una corrente proporzionale alla temperatura ambientale. Questa scelta consente
di risolvere il problema derivante dalla distanza tra il sensore, collocato all’esterno dell’edificio, ed
il restante circuito. L’uscita in corrente permette di porre il sensore sino a qualche decina di metri
di distanza dal circuito utilizzando del cavo schermato di buona qualità per il collegamento. Lo
schema applicativo tipico del sensore è molto semplice: è sufficente alimentarlo con una tensione
tra 5 e 40 volt2 e prelevare la corrente d’uscita.
Il sensore presenta una corrente nominale di 298µA a 25◦ C ed un coefficente di temperatura
nominale di 1µA/◦ C. Per sfruttarlo si è introdotta una conversione tensione/corrente con successiva
amplificazione e sottrazione di offset, effettuate mediante due amplificatori operazionali e qualche
resistenza. Per la conversione tensione/corrente è stata utilizzata una resistenza da 1KΩ (si veda R18 in figura 3) sulla quale cade una tensione variabile tra 0,250V e 0,325V per temperature
comprese tra -20◦ C e 50◦ C. A tale resistenza è stato fatto seguire un operazionale (U3B) in configurazione differenziale, impiegato per amplificare 56 volte e per la sottrarre un offset di 14,2V.
L’altro amplificatore utilizzato (U3C) ha il compito di fornire al primo una tensione di 0,25V ricavata a partire dai 2,5V di riferimento (generato con un LM385). La tensione d’uscita del circuito
di condizionamento varia tra 0 e 4 volt nel campo di temperature scelto. Con un convertirore ad
8 bit e dinamica 0-5V si arriva, quindi, ad una risoluzione di circa 0,3◦ C.
Anche in questo caso tra il circuito di condizionamento ed il multiplexer si trova un diodo zener
(D4) con funzioni analoghe a quelle di D3 descritte nel paragrafo precedente.
2.1.3
Misura dell’umidità
In commercio si trovano vari sensori igrometrici di tipo diverso ma in generale li si può dividere
in due grandi categorie: quella dei semplici sensori capacitivi e quella dei sensori con elettronica a
bordo, aventi come uscita una tensione proporzionale all’umidità relativa. Si è scelto un componente
del primo tipo seguendo criteri di economicità e reperibilità, perchè per gli altri si può spendere sino
a 10 volte tanto3 , con l’ulteriore problema della difficile reperibilità. In particolare si è adoperato
un sensore della Philips (sigla 2322-691) con capacità nominale variabile, in modo pressochè lineare,
tra 112pF e 144pF per umidità relative tra 10% e 90%.
Il circuito per l’impiego del sensore è stato realizzato mediante un integrato 7556. Questo integrato contiene al suo interno due multivibratori identici, ciascuno dei quali è uguale in tutto e per
tutto ad un 555. Il primo multivibratore è stato impiegato in configurazione astabile per generare
2
È stata scelta tensione di 9V perchè già utilizzata nel circuito.
In realtà a fronte di questa spesa si ottengono anche caratteristiche di precisione e affidabilità migliori, non
necessarie per l’applicazione quı̀ descritta.
3
3
un’onda quadra con frequenza attorno ai 100KHz4 . Il secondo è stato impiegato in configurazione monostabile, pilotato dai fronti di discesa del segnale generato dal primo. Come capacità del
monostabile è stato utilizzato il sensore di umidità e ciò comporta un segnale di uscita di tipo
PWM, in cui la larghezza d’impulso è proporzionale all’umidità relativa. Questo segnale può essere
trasmesso via cavo senza troppi problemi, consentendo di porre il rivelatore di umidità ad una certa
distanza dal resto del circuito.
La conversione analogico/digitale che segue, impone di trasformare il segnale PWM a 100KHz
in una forma d’onda a frequenza più bassa, caratterizzata da una tensione proporzionale all’umidità. Ciò può essere ottenuto semplicemente filtrando il PWM per ricavarne il valore medio.
Successivamente il segnale va condizionato per adattarlo alla dinamica del convertitore. Queste
operazioni sono state realizzate mediante: due filtri attivi di primo ordine (si vedano R5, C3, U2A,
R6, C4, U2B in figura 2), un operazionale in configurazione differenziale (U2C) e un operazionale
in configurazione non invertente (U2D). I filtri presentano una frequenza di taglio di 10Hz e guadagno unitario in banda passante. Il differenziale sottrae al segnale una tensione fissa di 3,75V
ed il seguente amplificatore ha guadagno 3,2. In uscita è stato ottenuto un segnale variabile tra
circa 0,6V e 4,4V per umidità relative tra 10% e 90%. Questo comporta una risoluzione massima
ottenibile con un covertitore ad 8 bit (dinamica 0-5V) di circa 0,5%RH, sufficente per la nostra
applicazione.
La presenza del diodo zener D2 e della resistenza R31 si spiega con considerazioni analoghe a
quelle fatte nei paragrafi precendenti per D3, R32 e D4, R33.
2.1.4
Misura della pressione atmosferica
La scelta del sensore di pressione è stata fortemente condizionata dalla scarsa disponibilità commerciale di questo tipo di dispositivi nella nostra zona. È stato quindi impiegato l’unico sensore di cui
era possibile effettuare l’acquisto senza la necessità di ordinare grandi quantitativi. Il componente
in questione è l’XFPM115KPA della Fujikura. Questo sensore contiene un ponte piezoelettrico e
fornisce in uscita una tensione variabile a seconda della pressione alla quale è sottoposto. Il suo
utilizzo risulta piuttosto semplice: è sufficente alimentarlo a 5V e prelevare la tensione presente
sulla sua uscita.
Per valori di pressione tra 960hPa e 1040hPa il sensore fornisce tensioni tra 3,84V e 4,20V.
A questo segnale va sottratto un offset ed applicata un’amplificazione per ottenere la saturazione
della dinamica del convertitore A/D seguente. Per queste operazioni sono stati impiegati due
amplificatori operazionali: il primo (si veda U4A in figura 3) è in configurazione differenziale,
amplifica 14 volte e sottrae 54V; il secondo (U4B) fornisce al primo un tensione di 3,6V ricavata
a partire dal riferimento di 2,5V. Con questo schema si è ottenuto un segnale d’uscita variabile
all’incirca tra 0 e 4,7 volt nel campo delle pressioni atmosferiche. Questo comporta una risoluzione
massima ottenibile con un convertitore ad 8 bit (dinamica 0-5V) di circa 0,3hPa, del tutto adeguata
alla nostra applicazione.
Anche in questo caso è presente un diodo zener (D5) avente il compito di limitare sotto i 5V i
segnali destinati al multiplexer ed al convertitore.
2.2
2.2.1
Multiplexing e conversione analogico/digitale
Multiplexing
Per il multiplexing è stato utilizzato un integrato di larghissima diffusione: il CD4051 della Farchild
Semiconductor. Degli otto ingressi disponibili quattro sono stati collegati direttamente alle uscite
dei circuiti descritti nei paragrafi precedenti e quattro sono stati resi disponibili mediante un
4
La frequnenza di 100KHz viene esplicitamente indicata sul datasheet del sensore igrometrico.
4
connettore per eventuali espansioni future. Gli ingressi digitali del multiplexer sono stati collegati
direttamente a tre linee della porta parallela (segnali DATA2, DATA3, DATA4) per il controllo da
personal computer (per lo schema dei collegamenti si faccia riferimento alla figura 4).
2.2.2
Conversione analogico/digitale
Per la conversione analogico/digitale è stato scelto l’integrato TLC549 della Texas Instruments. Si
tratta di un convertitore ad 8 bit con uscita seriale che necessita di una tensione di alimentazione
(Vcc) di 5V, e di riferimenti superiore (Ref+) ed inferiore (Ref–). Come riferimenti sono stati
utilizzati i 0V della massa ed i 5V della tensione di alimentazione. In questo modo la dinamica
del convertitore è stata fissata a 0V → +5V. L’ingresso analogico è stato collegato all’uscita del
multiplexer CD4051 mentre l’uscita digitale seriale è stata collegata ad un piedino della porta
parallela (segnale ERROR) per la lettura dei dati da personal computer. Anche gli ingressi di
clock (I/OCLK) e chip select (CS) sono stati collegati ad altrettante linee della porta parallela
(rispettivamente segnali DATA1 e AUTOFEED) per il controllo del dispositivo da PC. Lo schema
completo dei collegamenti è visibile in figura 4.
Informazioni dettagliate sulla comunicazione tra PC e convertitore A/D possono venir ricavate dalla lettura del codice sorgente del software di gestione e dai numerosi commenti che
l’accompagnano (si veda l’appendice A a pagina 18).
2.3
2.3.1
Le altre parti del circuito
Alimentazione
Per ottenere le tensioni di alimentazione di 5V e 9V necessarie al circuito sono stati utilizzati
due integrati regolatori LM78XX della National Semiconductor (si veda la figura 4). Per risolvere
alcuni problemi dovuti a rumori indotti sulle linee di alimentazione e massa sono stati inseriti dei
condensatori.
2.3.2
Riferimento
La tensione di riferimento di 2,5V utilizzata in varie parti del circuito è stata ottenuta mediante un
integrato LM385Z2.5 (si veda la figura 4) impiegato nella semplicissima configurazione consigliata
dal suo data-sheet.
2.4
Schema elettrico e lista dei componenti
Di seguito vengono riportati l’intero schema elettrico della stazione meteorologica e la lista dei
componenti utilizzati per realizzarla.
STAZIONE METEOROLOGICA - Lista componenti
C1
C2
C3
C4
C5
C6
C7
C8
C9
220pF ceramico *
0.1uF ceramico *
10uF 16V elettrolitico
10uF 16V elettrolitico
470nF poliestere
10uF 16V elettrolitico
470nF poliestere
10uF 16V elettrolitico
470nF poliestere
5
Figura 2: Schema elettrico - Prima parte
6
A
B
C
5
C3
10u
R5 10k
0
4
6
3
U1A
DIS
OUT
THR
1
5
2
U1B
DIS
OUT
THR
+
-
3
2
R6 10k
0
LM324
1
4
C4
10u
0
5
+
6
11
+2.5V
0
LM324
7
U2B
0
R7 150k
0
0.1u
0
R4
10M
Philips-2322-691
RH sensor
U2C
2
1
3
R9 100k
R8
100k
+
-
10
9
0
R10
Date:
Size
A
Title
150k
LM324
8
C5 470n
220k
0
LM324
14
U2D
R31
Stazione meteorologica
2
Wednesday, April 02, 2003
Document Number
1
0
1
+4.7 V
D2
A1
Sheet
1
1
of
3
Rev
D
Umidità relativa
100
A. Coslovich, D. Palazzolo, F. Piccolo
0
R11
100k
-
13
R12
+
12
+9 V
7556
13
9
12
C2
2
+9 V
0
C1
220p
R
TRG
CU
R3
33k
3
+9 V
4
HI
4
+9 V
U2A
7556
10
8
11
HI
R
TRG
CU
HI
R2
1k
+9 V
R1
39k
+9 V
+9 V
+9 V
HI
+9 V
4
HI
HI
11
11
D
5
HI
HI
4
HI
4
11
A
B
C
D
A
B
C
0
0
R21
C6
10u
3.9k
5
100k
R20
10k
100k
+9 V
R19
1
2
AD590
+2.5V
+2.5V
LM335
D1
R14
HI
R15
22k
3
+
U3A
R32
100
0
A2
U3B
R33
A3
0
0
R16
-
9
11
22k
0
LM324
1
10k
0
LM324
8
U3C
D3
+4.7 V
4
R23 10k
0
R18
1k
6
5
560k
0
LM324
7
C9 470n
R24
-
+
+9 V
Temperatura interna
C8
10u
C7 470n
R17
-
+9 V
R22
+
10
3.9k
0
2
0
3
Temperatura esterna
D4
+4.7 V
100
XFPM115KPA
Pressure sensor
Date:
Size
A
Title
+2.5V
0
C11
1n
R25
R26
3
+
0
R28
10k
0
680k
R30
220k
2
150k
0
6
5
LM324
7
Stazione meteorologica
2
Wednesday, April 02, 2003
Document Number
2
U4B
R34
100k
D5
+4.7 V
100
1
0
A4
Sheet
2
1
of
3
Rev
D
Pressione atmosferica
R29
-
+
+9 V
0
LM324
1
C10 470n
R27
-
U4A
A. Coslovich, D. Palazzolo, F. Piccolo
100k
4
11
D
1
2
3
4
5
6
LO
HI
4
HI
R13
4.7k
+9 V
C12
100n
2
+5 V
3
+9 V
4
HI
+5 V
5
LO
4
HI
4
11
4
HI
11
7
11
Figura 3: Schema elettrico - Seconda parte
A
B
C
D
A
B
C
1
2
3
4
0
FB
R36
100k
+2.5V
13
14
15
12
1
5
2
4
3
CD4051
5
X0
X1
X2
X3
X4
X5
X6
X7
X
U5
Riferimento di tensione
LM385Z2.5
U7
+9 V
ExpansionPort
A1
A4
A3
A2
VDD
VEE
EN
A
B
C
0
4
0
1
Vcc IN (12-30V)
16
7
6
11
10
9
2
D
HI
+
4
LO
C13
100u
+5 V
0
0
VIN
U8
LM7809
1
R35
100k
0
+5 V
LO
0
GND
2
5
3
3
3
TLC549
CS
I/OCLK
REF+
REF-
AIN
U6
VOUT
5
7
1
3
2
0
C14
47u
HI
GND
DOUT
VCC
Date:
Size
A
Title
+9 V
4
6
8
0
0
VIN
U9
LM7805
1
0
0
VOUT
Stazione meteorologica
2
Wednesday, April 02, 2003
Document Number
3
1
0
0
C16
47u
LO
+5 V
Sheet
3
1
of
3
Alimentazione
3
MUX + A/D conv.
CentronicsConnector
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Parallel Port
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
A. Coslovich, D. Palazzolo, F. Piccolo
C15
100u
2
GND
2
8
-
Figura 4: Schema elettrico - Terza parte
Rev
D
A
B
C
D
C10
C11
C12
C13
C14
C15
C16
D1
D2
D3
D4
D5
ParPort
PresSen
RH Sens
R1
R2
R3
R4
R5
R6
R7
R8
R9
R10
R11
R12
R13
R14
R15
R16
R17
R18
R19
R20
R21
R22
R23
R24
R25
R26
R27
R28
R29
R30
R31
R32
R33
R34
470nF poliestere
1nF ceramico
100nF ceramico
100uF 50V elettrolitico
47uF 16V elettrolitico
100uF 50V elettrolitico
47uF 16V elettrolitico
LM335 Temp. Sens.
Zener 4.7V
Zener 4.7V
Zener 4.7V
Zener 4.7V
CentronicsConnector
XFPM115KPA
Philips-2322-691 *
39Kohm 5% 1/4W *
1Kohm 5% 1/4W *
33Kohm 5% 1/4W *
10Mohm 5% 1/4W *
10Kohm 5% 1/4W
10Kohm 5% 1/4W
150Kohm 5% 1/4W
100Kohm 5% 1/4W
100Kohm 5% 1/4W
150Kohm 5% 1/4W
100Kohm 5% 1/4W
220Kohm 5% 1/4W
4.7Kohm 5% 1/4W
3.9Kohm 5% 1/4W
22Kohm 5% 1/4W
3.9Kohm 5% 1/4W
22Kohm 5% 1/4W
1Kohm 5% 1/4W
100Kohm 5% 1/4W
10Kohm 5% 1/4W
100Kohm 5% 1/4W
10Kohm 5% 1/4W
10Kohm 5% 1/4W
560Kohm 5% 1/4W
100Kohm 5% 1/4W
680Kohm 5% 1/4W
150Kohm 5% 1/4W
10Kohm 5% 1/4W
100Kohm 5% 1/4W
220Kohm 5% 1/4W
100ohm 5% 1/4W
100ohm 5% 1/4W
100ohm 5% 1/4W
100ohm 5% 1/4W
9
R35
R36
TempSen
U1
U2
U3
U4
U5
U6
U7
U8
U9
100Kohm 5% 1/4W
100Kohm 5% 1/4W
AD590 *
7556 *
LM324
LM324
LM324
CD4051
TLC549
LM385Z2.5
LM7809
LM7805
* I componenti segnalati con un asterisco sono stati
impiegati per realizzare l’unità remota per la
misura dell’umidità e della temperatura esterna.
10
3
Realizzazione dell’hardware
In un primo tempo, il circuito è stato realizzato provvisoriamente su bread-board per i test di
funzionamento, poi è stato montato in modo definitivo su circuito stampato. In particolare sono
stati disegnati ed utilizzati due distinti PCB: uno per l’unità principale ed uno per l’unità remota
da collocare all’esterno dell’edificio. Questa seconda piccola piastra è stata destinata ad ospitare
solamente il sensore di temperatura AD590 (vedi paragrafo 2.1.2 a pagina 3), quello di umidità e la
circuiteria necessaria per la generazione del segnale PWM (si veda paragrafo 2.1.3 a pagina 3). Sul
circuito stampato di dimensioni maggiori sono stati saldati tutti gli altri componenti. Entrambi i
circuiti sono stati inseriti in scatole e collegati tra di loro con un cavo di lunghezza opportuna.
3.1
Layout dei PCB
Di seguito sono riportati i disegni dei circuiti stampati utilizzati, completi di schema della disposizione dei componenti.
Figura 5: Circuito stampato principale
Figura 6: Circuito stampato per sensori di temperatura esterna e umidità
11
4
Taratura
Il circuito è stato progettato privo di qualsiasi dispositivo di taratura preferendo, sin dall’inizio,
la via software per realizzarla. Si è avuta, quindi, la necessità di arrivare in modo sperimentale
a determinare delle funzioni matematiche che legassero i valori dei byte forniti dal convertitore ai
corrispondenti valori delle grandezze fisiche misurate (temperatura, umidità e pressione). In generale il problema è stato risolto mediante una serie di prove sperimentali, in cui sono stati annotati
i valori forniti dal convertitore A/D della stazione meteorologica ed i corrispondenti valori delle
grandezze fisiche misurate con una stazione termo-igro-barometrica commerciale. Successivamente
i valori ottenuti sono stati utilizzati per ricavare delle rette di regressione.
4.1
Temperatura
Per tarare le sezioni di misura della temperatura, sia interna che esterna, è stata usata una borsa
termica al fine di ottenere un ambiente quanto più possibile isolato dall’esterno. All’interno della
borsa termica sono stati inseriti i sensori di temperatura interna ed esterna della stazione da tarare
ed il sensore della stazione commerciale usata come campione. Sono state effettuate tre diverse
prove per ciascuna delle seguenti situazioni:
• Ambiente freddo (borsa termica raffreddata con ghiaccio) - circa 8◦ C
• Ambiente a temperatura intermedia - circa 25◦ C
• Ambiente caldo (borsa termica riscaldata con vasi di acqua calda) - circa 45◦ C
In ogni prova è stato atteso uno stato quanto più vicino all’equilibrio termico5 prima della lettura
dei valori. Nella seguente tabella vengono riportati i valori letti:
Prima prova
Seconda prova
Terza prova
Temperatura interna
Ambiente freddo Ambiente intermedio
Byte* Temp** Byte*
Temp**
115
9,3◦ C
156
24,5◦ C
114
7,8◦ C
158
26,4◦ C
◦
116
8,6 C
155
25,9◦ C
Ambiente caldo
Byte* Temp**
199
46,6◦ C
201
46,5◦ C
197
44,7◦ C
Prima prova
Seconda prova
Terza prova
Temperatura estrerna
Ambiente freddo Ambiente intermedio
Byte* Temp** Byte*
Temp**
◦
113
9,3 C
167
24,5◦ C
◦
114
7,8 C
174
26,4◦ C
118
8,6◦ C
173
25,9◦ C
Ambiente caldo
Byte* Temp**
222
46,6◦ C
229
46,5◦ C
223
44,7◦ C
* Valore decimale del byte ottenuto dal convertitore A/D della stazione meteorologica da tarare.
** Valore di temperatura letto sulla stazione meteorologica utilizzata come campione.
Con questi valori sono state ottenute le due rette di regressione da utilizzare nel programma:
Temperatura interna: y = 0, 44x − 43
Temperatura esterna: y = 0, 34x − 31
5
In sostanza i valori sono stati rilevati in condizioni di temperatura costante.
12
4.2
Umidità
Per tarare la sezione igrometrica sono state fatte tre rilevazioni in condizioni diverse. La prima è
stata ottenuta all’interno di un ambiente piuttosto secco, mentre la seconda e la terza, in ambienti
umidificati mediante vapori derivanti da una grande quantità di acqua bollente. Per tutte le prove
si è attesa una situazione stabile, poi si è proceduto all’annotazione dei valori. Quanto ottenuto è
riportato nella seguente tabella:
Ambiente secco
Byte* RH**
83
32%
Umidità
Ambiente umido I
Byte*
RH**
169
78%
Ambiente umido II
Byte*
RH**
183
85%
* Valore decimale del byte ottenuto dal convertitore A/D della stazione meteorologica da tarare.
** Valore di umidità relativa letto sulla stazione meteorologica utilizzata come campione.
Con questi valori è stata ottenuta la retta di regressione da inserire nel programma:
y = 0, 53x − 12
4.3
Pressione
Per la sezione barometrica la taratura è stata fatta in due momenti successivi. In un primo
momento è stato determinato il coefficente angolare della retta di taratura, utilizzando due misure
di pressione effettuate ad altezze diverse sul livello del mare. Successivamente è stata individuata
l’intercetta della retta mediante una singola misura di pressione già compensata in altezza.
I due rilievi a differente altezza s.l.m. hanno portato ai seguenti risultati:
∼120m SLM
Byte* Press**
146
1013
0m SLM
Byte* Press**
122
1005
* Valore decimale del byte ottenuto dal convertitore A/D della stazione meteorologica da tarare.
** Valore di pressione letto sulla stazione meteorologica utilizzata come campione.
I rilievi sperimentali sono stati confrontati con i valori ottenuti in fase di progetto giungendo
ad assegnare al coefficente angolare un valore m = 1/3.
Per fissare l’intercetta della retta, in modo che la pressione indicata dalla stazione meteorologica
risulti riferita al livello del mare, si è reso necessario conoscere l’altezza s.l.m. del luogo in cui l’apparechio verrà utilizzato. Si è deciso di utilizzare come riferimento il piano terra del Dipartimento
di Elettrotecnica, Elettronica ed Informatica. Da misure effettuare mediante un GPS tale luogo
risulta all’incirca a 150m s.l.m. Il dato è stato inserito all’interno del sistema di compensazione
presente nella stazione meteorologica commerciale a nostra disposizione, permettendo la lettura
del valore di pressione rapportato al livello del mare (Pn ). Contemporaneamente è stato letto il
valore decimale del byte generato dal convertitore A/D della stazione meteorologica da tarare (B).
Il valore dell’intercetta è stato calcolato con la semplice formula:
q = Pn − mB = Pn −
B
3
In particolare, con i valori rilevati, è stato ottenuto:
q = 1026 −
Da cui la retta y = mx + q =
x
3
129
3
= 983
− 983 utilizzata nel programma.
13
5
Realizzazione del software di gestione
Per raggiungere gli obbiettivi prefissi il software di gestione della stazione meteorologica è stato
realizzato implementando le seguenti caratteristiche:
• Gestione della comunicazione tra PC e stazione meteorologica via porta parallela.
• Accesso serializzato all’hardware per evitare problemi di accesso contemporneo.
• Output dei dati in diversi formati:
1. Testuale esteso per output su consolle
2. Testuale tabellare per output da redirigere su file
3. HTML per output su world wide web tramite server HTTP
Per la realizzazione del programma è stato utilizzato il linguaggio C perchè è sostanzialmente
lo standard in ambiente Unix-Linux e perchè esiste un compilatore molto diffuso completamente
gratuito e liberamente utilizzabile (GCC).
5.1
Gestione della comunicazione
Per gestire facilmente la comunicazione tra il PC e la stazione meteorologica via porta parallela è
stata utilizzata la libreria di funzioni ParaPin realizzata e messa a disposizione da Jeremy Elson
della University of Southern California. Grazie a questa libreria è molto semplice agire sulle singole
linee della porta parallela attivandole o disattivandole a piacere. All’interno del programma sono
state utlizzate le seguenti funzioni di questa libreria:
pin_int_user(LPTn): Inizializza la porta LPTn (n=1 o n=2);
pin_output_mode(pin1|pin2|...): Attiva le linee pin1, pin2, . . . come uscite;
set_pin(pin1|pin2|...): Pone le linee pin1, pin2, . . . in stato logico alto (+5V);
clear_pin(pin1|pin2|...): Pone le linee pin1, pin2, . . . in stato logico basso (0V).
All’interno del codice sorgente (si veda l’appendice A a pagina 18) le funzioni che si occupano
della comunicazione con l’hardware sono la commuta (per la commutazione del multiplexer) e la
leggi_dato (per la generazione del clock del convertitore e la lettura del byte da esso generato).
5.2
Serializzazione degli accessi all’hardware
In un sistema multiprocesso e multiutente, come Linux, può accadere che due programmi o due
istanze dello stesso programma accedano ad una risorsa hardware in modo pressochè contemporaneo. Se ciò avviene, per effetto dei context-switch, la comunicazione con il dispositivo avviene in
istanti successivi a carico di uno o dell’altro processo in esecuzione. Questa situazione, in moltissimi casi, non è tollerabile e bisogna correre ai ripari creando una coda sequenziale di processi per
l’accesso all’hardware. Non fà eccezione il caso della comunicazione con la stazione meteorologica.
È evidente che se un processo stà leggendo un byte dal convertitore A/D, non è possibile che esso
interrompa questa operazione per consentire ad un altro di iniziare un analogo processo di lettura:
se lo facesse entrambi si ritroverebbero con dati non validi.
Il problema dell’accodamento per l’accesso alle risorse può essere risolto in vari modi. Nella
realizzazione di questo software sono state adoperate le strutture semaforiche messe a disposizione
dal sistema operativo. In pratica è stato creato un semaforo di mutua esclusione con il quale è
stata protetta la sezione critica del programma, costituita dall’accesso alla risorsa hardware. Tutte
le funzioni per la gestione del semaforo sono state ragruppate nel file semaf.c (si veda la sezione
A.2 dell’appendice a pagina 25).
14
5.3
Formati di output e loro utilizzo
Il programma è stato scritto per permettere l’output dei dati in vari formati. Questo garantisce
l’uso del software per tre scopi diversi: la visione dei dati meteorologici in tempo reale su consolle,
la consultazione dei medesimi dati via web e la loro registrazione su file per usi statistici. Le tre
modalità di output sono integrate nel medesimo codice (si veda il file meteo010.c nella sezione
A.1 dell’appendice a pagina 18). La scelta riguardo al tipo di output và fatta al momento della
compilazione. Compilando con l’opzione -DTAB si ottiene l’output di tipo tabellare, con l’opzione
-DCGI si ottiene la versione CGI con output in codice HTML (in questo caso vengono utilizzate
le funzioni contenute nel file cgi.c, si veda la sezione A.4 dell’appendice a pagina 28) mentre
compilando senza opzioni si ottiene la versione per uso consolle.
Per utilizzare la versione con output su consolle è sufficiente avviare il programma digitando il
suo nome, completo di path, al prompt del sistema operativo. Per utilizzare la versione in formato
tabellare è possibile inserire nella tabella di cron6 messo a disposizione del sistema operativo una
riga del tipo:
0,30 * * * * /percorso_del_programma/meteotab >> /percorso_del_file/meteo.data
In questo modo ogni 30 minuti i dati meteorologici verranno registrati nel file meteo.data (per
un esempio di file di questo tipo si veda l’appendice B a pagina 30). La versione CGI, invece, va
utilizzata in combinazione con un server HTTP. Solitamente, una volta installato opportunamente
il server, viene messa a disposizione una directory in cui è possibile inserire i programmi CGI
per renderli utilizzabili via world wide web. Quindi il file eseguibile del software della stazione
metorologica in versione CGI va semplicemente inserito in tale directory.
5.4
Osservazioni sui permessi di accesso all’I/O
Nei sistemi Linux solamente l’amministratore di sistema (root) può accedere in modo diretto alle
risorse hardware del PC. Questo vale, in particolare, anche per la porta parallela, quindi il software
di gestione della stazione meteorologica dev’essere eseguito con privilegi di root. Affinchè anche
gli altri utenti possano usufruire dei dati delle misure rilevate dalla stazione meteorologica, sia da
consolle che via web, è necessario che il file esguibile del programma abbia come proprietario root7 ,
sia eseguibile da tutti gli utenti ed abbia i bit di SUID (Set User ID) e SGID (Set Group ID) attivi8 .
6
Per le prove fatte e per questo esempio è stato utilizzato il sistema Vixie-Cron di Linux. In ogni caso è consigliabile
leggere il manuale del del proprio sistema cron prima di utilizzarlo.
7
Per attribuirsi la propietà del file meteo l’utente root può utilizzare il comando chown con la sintassi
chown root:root meteo.
8
Per attribuire queste caratteristiche al file meteo l’utente root può utilizzare il comando chmod con la sintassi
chmod ug+s,a+x meteo.
15
6
Bibliografia
1. C. Mangiavacchi, A. Zanini
Misure elettroniche
ed. Cedam, Padova, 1978
2. G. Biondo, E. Sacchi
Manuale di elettronica e telecomunicazioni
ed. Hoepli, Milano, 1996
3. Vincenzo Villa
Misura della pressione atmosferica e della temperatura
Sito web: http://www.vincenzov.org
4. Un altimetro da 0 a 1999 metri
Nuova Elettronica, n.204, anno 32, Aprile-Maggio 2000
5. Analog Devices
AD590 Datasheet
Sito web: http://www.analog.com/
6. Farchild Semiconductor
CD4051 Datasheet
Sito web: http://www.fairchildsemi.com/
7. Fujikura LTD
XFPM115KPA Datasheet
Sito web: http://www.fujikura.co.uk/
8. Maxim IC e Dallas Semicondictor
ICM7556 Datasheet
Sito web: http://www.maxim-ic.com/
9. National Semiconductor
LM324, LM335, LM385, LM78xx Datasheets
Sito web: http://www.national.com/
10. Texas Instruments
TLC549 Datasheet
Sito web: http://www.ti.com/
11. E. Mumolo
Dispense del corso di Sistemi Operativi
Università degli Studi di Trieste
12. Jeremy Elson
Parapin: A Parallel Port Pin Programming Library for Linux
Information Science Institute, University of Southern California
Sito web: http://www.circlemud.org/jelson/software/parapin
16
7
Ringraziamenti
Si ringraziano tutte le persone che in vario modo hanno favorito la realizzazione di questo progetto
ed in particolare: prof. Mangiavacchi (titolare del corso di Misure Elettroniche), sig. Pruni (tecnico
del laboratorio di Misure Elettriche), sig. Zibai (tecnico DEEI), tutti i dottorandi dell’APL, sig.
Colledani (laureando presso lo SmartLab che ci ha gentilmente fornito i valori rilevati di altezza
rilevati con il GPS), sig. Masarin (che ci ha messo a disposizione alcune apparecchiature utili alla
realizzazione pratica del progetto).
17
A
APPENDICE: Codice sorgente del software di gestione
A.1
File meteo010.c
/*
#=======================================================================================#
#
#
#
UNIVERSITA’ DEGLI STUDI DI TRIESTE
#
#
#
#
Facolta’ di Ingegneria
#
#
Dipartimento di Elettronica Elettrotecnica e Informatica
#
#
#
#
Corso di Laurea in Ingegneria Elettronica
#
#
#
#
Corso di Misure Elettroniche
#
#
#
#=======================================================================================#
#
#
#
**** PROGETTO STAZIONE METEOROLOGICA ****
#
#
#
#=======================================================================================#
# Andrea Coslovich ([email protected] - http://www.geocities.com/acoslovich)
#
# Daniele Palazzolo ([email protected])
#
# Fabio Piccolo ([email protected])
#
#=======================================================================================#
=== SOFTWARE DI GESTIONE ===
Versione 0.10 - 5/4/2003
- Prima versione rilasciata ufficialmente
Storia del programma:
* Parte del codice e’ stata tratta da programmi di test precedenti
* Versione 0.00 - 25/2/2003
- Stesura della struttura di massima del programma
- ATTENZIONE: In questa versione tutte le procedure di calcolo dei parametri
calcolano in realta’ il valore di TENSIONE applicato al convertitore.
* Versione 0.01 - 9/3/2003
- Risoluzione dei problemi di mutua esclusione:
Protezione della sezione critica (costituita dall’accesso alla risorsa
non condivisibile "circuito della stazione meteorologica") mediante
semaforo di mutua esclusione MUTEX
* Versione 0.02 - 9/3/2003
- Ripulitura del codice
* Versione 0.03 - 9/3/2003
- Ragruppamento delle procedure per la gestione del semaforo
di mutua esclusione in un file esterno: semaf.c
* Versione 0.04 - 10/3/2003
- Aggiunta della stampa della data e dell’ora
* Versione 0.05 - 10/3/2003
- Introduzione dell’output in stile CGI-BIN
* Versione 0.06 - 28/3/2003
- Inserite le formule per il calcolo di temperatura ed umidita’
* Versione 0.07 - 29/3/2003
- Ripulitura del codice
- Aggiunta dell’output in formato "tabella" pronto per l’invio verso un file
- Aggiunta una prima funzione approssimata per il calcolo della pressione atmosferica
* Versione 0.08 - 2/4/2003
- Ripulitura del codice in vista della versione definitiva
- Funzione definitiva per il calcolo della pressione atmosferica
ATTENZIONE: Il calcolo della pressione atmosferica viene eseguito tenendo
conto dell’altezza SLM del piano terra dell’edificio C2
dell’Università (circa 150m).
Il dato di pressione restituito dal programma è quello che
si averebbe a livello del mare.
FILES RICHIESTI:
meteoXXX.c
(questo file)
18
semaf.h
semaf.c
data.h
data.c
cgi.h
cgi.c
parapin.h
libparapin.a
(prototipi per gestione semaforo)
(procedure per gestione semaforo)
(prototipi per stampa di data ed ora)
(procedure per stampa di data ed ora)
(prototipi per stampa del codice HTML)
(procedure per stampa del codice HTML)
(prototipi di PARAPIN)
(libreria PARAPIN)
LIBRERIE RICHIESTE:
Questo programma fa’ uso della libreria PARAPIN (v. 0.95) di Jeremy Elson.
OSSERVAZIONI SULL’USO DEL CONVERTITORE:
* Per iniziare la lettura di un dato dal convertitore bisogna
abbassare la linea CS
A lettura terminata bisogna alzare la linea CS
* Temporizzazione tra clock e lettura bit:
1. ALZARE IL CLOCK
2. LEGGERE IL BIT
3. ABBASSARE IL CLOCK
...ripetere questo per NBIT volte... (NBIT=8 per il TLC549)
* Dopo la lettura di un dato va’ inserito un periodo di pausa che
permette al convertitore di effettuare la conversione del valore
successivo.
E’ importante inserire SEMPRE questa pausa, perche’ se non viene
rispettata questa temporizzazione il convertitore funziona male
fornendo dati vecchi o "assurdi".
ISTRUZIONI PER LA COMPILAZIONE:
- Per la ottenere la versione normale (output su consolle):
gcc -O3 meteo010.c -lm libparapin.a data.c semaf.c -o meteo
- Per ottenere la versione normale pronta per output su FILE (tabella):
gcc -O3 -DTAB meteo010.c -lm libparapin.a data.c semaf.c -o meteo_tab
- Per ottenere la versione cgi con output HTML:
gcc -O3 -DCGI meteo010.c -lm libparapin.a data.c semaf.c cgi.c -o meteo.cgi
*/
/* Librerie standard */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
/* Per la gestione dei segnali */
#include <signal.h>
/* Libreria matematica */
#include <math.h>
/* Procedure per la gestione del semaforo MUTEX */
#include "semaf.h"
/* Procedure per la stampa di data ed ora */
#include "data.h"
#ifdef CGI
/* Procedure per la stampa del codice HTML */
#include "cgi.h"
#endif /* CGI */
/* Libreria per la gesione della porta parallela */
#include "parapin.h"
#define SKEY
#define MUTEX
2740
0
/* Key dell’array di semafori utilizzato
*/
/* Numero del semaforo di mutua esclusione */
#define
#define
#define
#define
LP_PIN02
LP_PIN03
LP_PIN04
LP_PIN05
/*
/*
/*
/*
CLOCK
MUX_A
MUX_B
MUX_C
Data1
Data2
Data3
Data4
-----
Centronics
Centronics
Centronics
Centronics
PIN2
PIN3
PIN4
PIN5
19
*/
*/
*/
*/
#define DATA
#define CS
LP_PIN15
LP_PIN14
/* Error
-- Centronics PIN32 */
/* AutoFeed -- Centronics PIN14 */
#define VALORE_PAUSA 110
/* Numero dei cicli while della pausa */
#define
#define
#define
#define
#define
#define
#define
#define
/*
/*
/*
/*
/*
/*
/*
/*
TEMP_INT
TEMP_EST
PRESSIONE
UMIDITA
In4
In5
In6
In7
0
1
2
3
4
5
6
7
Ingresso
Ingresso
Ingresso
Ingresso
Ingresso
Ingresso
Ingresso
Ingresso
0
1
2
3
4
5
6
7
del
del
del
del
del
del
del
del
MUX
MUX
MUX
MUX
MUX
MUX
MUX
MUX
-
Sensore di temperatura interna */
Sensore di temperatura esterna */
Sensore di press. atmosferica */
Sensore di umidita */
Per espansione */
Per espansione */
Per espansione */
Per espansione */
void chiusura(int numsegnale)
{
/* ----------------------------------------- */
/* Gestione della terminazione del programma */
/* ----------------------------------------- */
puts("\n\nDisattivazione del convertitore...\n");
set_pin(CS);
clear_pin(CLOCK);
exit(0);
}
void commuta(int ingresso)
{
/* -------------------- */
/* Commutazione del MUX */
/* -------------------- */
long pausa;
if (ingresso & 1) set_pin(MUX_A); else clear_pin(MUX_A);
if (ingresso & 2) set_pin(MUX_B); else clear_pin(MUX_B);
if (ingresso & 4) set_pin(MUX_C); else clear_pin(MUX_C);
pausa=200*VALORE_PAUSA; while (pausa) pausa--; /* Attendo l’assestamento dopo la commutazione */
}
int
{
/*
/*
/*
leggi_dato(void)
--------------------------------- */
Lettura del dato dal convertitore */
--------------------------------- */
int dato;
long pausa;
clear_pin(CS); /* Inizio lettura del campione - ABBASSO LA LINEA CS */
set_pin(CLOCK); /* D7 - Bit piu’ significativo */
pausa=VALORE_PAUSA;
while (pausa) pausa--;
pausa=VALORE_PAUSA;
while (pausa) pausa--;
dato=(pin_is_set(DATA) / DATA)*128;
clear_pin(CLOCK);
set_pin(CLOCK); /* D6 */
pausa=VALORE_PAUSA;
while (pausa) pausa--;
pausa=VALORE_PAUSA;
while (pausa) pausa--;
dato=dato+(pin_is_set(DATA) / DATA)*64;
clear_pin(CLOCK);
set_pin(CLOCK); /* D5 */
pausa=VALORE_PAUSA;
20
while (pausa) pausa--;
pausa=VALORE_PAUSA;
while (pausa) pausa--;
dato=dato+(pin_is_set(DATA) / DATA)*32;
clear_pin(CLOCK);
set_pin(CLOCK); /* D4 */
pausa=VALORE_PAUSA;
while (pausa) pausa--;
pausa=VALORE_PAUSA;
while (pausa) pausa--;
dato=dato+(pin_is_set(DATA) / DATA)*16;
clear_pin(CLOCK);
set_pin(CLOCK); /* D3 */
pausa=VALORE_PAUSA;
while (pausa) pausa--;
pausa=VALORE_PAUSA;
while (pausa) pausa--;
dato=dato+(pin_is_set(DATA) / DATA)*8;
clear_pin(CLOCK);
set_pin(CLOCK); /* D2 */
pausa=VALORE_PAUSA;
while (pausa) pausa--;
pausa=VALORE_PAUSA;
while (pausa) pausa--;
dato=dato+(pin_is_set(DATA) / DATA)*4;
clear_pin(CLOCK);
set_pin(CLOCK); /* D1 */
pausa=VALORE_PAUSA;
while (pausa) pausa--;
pausa=VALORE_PAUSA;
while (pausa) pausa--;
dato=dato+(pin_is_set(DATA) / DATA)*2;
clear_pin(CLOCK);
set_pin(CLOCK); /* D0 - Bit meno significativo */
pausa=VALORE_PAUSA;
while (pausa) pausa--;
pausa=VALORE_PAUSA;
while (pausa) pausa--;
dato=dato+(pin_is_set(DATA) / DATA);
clear_pin(CLOCK);
set_pin(CS); /* fine lettura del campione - ALZO LA LINEA CS */
pausa=200*VALORE_PAUSA;
while (pausa) pausa--; /* Pausa per permettere al convertitore di effettuare la conv. successiva */
return dato;
}
float calcola_temp_int(int campione)
{
/* --------------------------------- */
/* Calcolo della temperatura interna */
/* --------------------------------- */
float temperatura;
temperatura=(0.4443*(float)campione)-43.036;
/* Arrotondamento al mezzo grado */
if (temperatura<(floorf(temperatura)+0.25))
{ temperatura=floorf(temperatura); }
else
{
if (temperatura<(floorf(temperatura)+0.75))
temperatura=floorf(temperatura)+0.5;
21
else
temperatura=floorf(temperatura)+1;
}
return temperatura;
}
float calcola_temp_est(int campione)
{
/* --------------------------------- */
/* Calcolo della temperatura esterna */
/* --------------------------------- */
float temperatura;
temperatura=(0.339*(float)campione)-31.02;
/* Arrotondamento al mezzo grado */
if (temperatura<(floorf(temperatura)+0.25))
{ temperatura=floorf(temperatura); }
else
{
if (temperatura<(floorf(temperatura)+0.75))
temperatura=floorf(temperatura)+0.5;
else
temperatura=floorf(temperatura)+1;
}
return temperatura;
}
float calcola_pressione(int
{
/* ----------------------/* Calcolo della pressione
/* -----------------------
campione)
*/
*/
*/
float pressione;
pressione=((float)campione/3)+983;
/* Arrotondamento ad un ettopascal */
if (pressione<floorf(pressione)+0.5) pressione=floorf(pressione);
else pressione=floorf(pressione)+1;
return (float)pressione;
}
float calcola_umidita(int campione)
{
/* ----------------------------- */
/* Calcolo del’umidita’ relativa */
/* ----------------------------- */
float umidita;
umidita=(0.5317*(float)campione)-12.099;
/* Arrotondamento all’uno percento di umidita’ */
if (umidita<floorf(umidita)+0.5) umidita=floorf(umidita);
else umidita=floorf(umidita)+1;
return umidita;
}
float calcola_tensione(int campione)
{
/* ---------------------- */
22
/* Calcolo della tensione */
/* ---------------------- */
/* Questa funzione non viene realmente utilizzata dal */
/* programma ma sua presenza nel sorgente puo’ essere */
/* utile in sessioni di debug o test dell’HW.
*/
return (float)campione*(5.06/255);
}
float leggi_valore(int tipolettura)
{
/* --------------------------------------------------- */
/* Effettua la lettura di un valore da uno dei sensori */
/* --------------------------------------------------- */
int campione;
commuta(tipolettura); /* Commuta il MUX sull’ingresso corretto */
/* Legge due volte il dato dal convertitore
*/
/* Si fanno due letture per evitare l’uso di dati vecchi */
campione=leggi_dato();
campione=leggi_dato();
if (tipolettura==TEMP_INT) return calcola_temp_int(campione);
else if (tipolettura==TEMP_EST) return calcola_temp_est(campione);
else if (tipolettura==PRESSIONE) return calcola_pressione(campione);
else if (tipolettura==UMIDITA) return calcola_umidita(campione);
/* Gli altri ingressi sono
else if (tipolettura==In4)
else if (tipolettura==In5)
else if (tipolettura==In6)
else if (tipolettura==In7)
disponibili per future espansioni */
return calcola_tensione(campione);
return calcola_tensione(campione);
return calcola_tensione(campione);
return calcola_tensione(campione);
}
int main(int argc, char *argv[])
{
int i, pausa;
int semid;
char buf[10];
float valore_letto[3];
/* Inizializzazione del semaforo */
semid=seminit(SKEY);
/* Attivazione della mutua esclusione - Inizio della sez. critica */
down(semid,MUTEX);
/* Inizializzazione della comunicazione su porta parallela */
if (pin_init_user(LPT1) < 0) exit(0); /* Esce dal programma se non e’ possibile inizializzare */
/* Controllo sulla terminazione del programma*/
signal(SIGINT, chiusura);
signal(SIGTERM, chiusura);
signal(SIGHUP, chiusura);
pin_output_mode(LP_DATA_PINS | LP_SWITCHABLE_PINS); /* Tutti i piedini di I/O usati come O */
clear_pin(CLOCK);
/* Abbasso il clock */
for ( i = 0 ; i < 4 ; i++ ) /* Ciclo per leggere gli ingressi della stazione */
{
valore_letto[i]=leggi_valore(i);
}
/* Disattivazione della mutua esclusione - Fine della sez. critica */
up(semid,MUTEX);
23
#ifdef CGI
/* Stampa del codice HTML dell’intestazione */
printhead();
/* Stampa del codice HTML del centro della pagina con i valori */
printdata(valore_letto[0],valore_letto[1],valore_letto[2],valore_letto[3]);
/* Stampa del codice HTML del pie di pagina */
printtail();
#else /* CGI */
#ifdef TAB
/* Stampa della data e dell’ora */
printdate();printf(" ");printtime();
/* Stampa dei dati letti */
printf(" %.1f ",valore_letto[0]);
printf("%.1f ",valore_letto[1]);
printf("%.0f ",valore_letto[2]);
printf("%.0f\n",valore_letto[3]);
#else /* TAB */
/* Header di presentazione del programma */
printf("\n
Micro-Stazione Meteorologica - Lettura valori\n");
printf("
=================================================\n\n");
/* Stampa dei dati letti */
printf("
TEMPERATURA INTERNA:
printf("
TEMPERATURA ESTERNA:
printf("
PRESSIONE:
printf("
UMIDITA’ RELATIVA:
In0=%.1f
In1=%.1f
In2=%.0f
In3=%.0f
gradi centigradi\n",valore_letto[0]);
gradi centigradi\n",valore_letto[1]);
ettoPascal\n",valore_letto[2]);
percento\n",valore_letto[3]);
/* Stampa della data */
printf("\n
Data ed ora attuali: ");printdate();printf(" ");printtime();printf("\n\n");
#endif /* TAB */
#endif /* CGI */
return 0;
} /* Fine del main */
24
A.2
File semaf.c
/*
#=======================================================================================#
#
**** PROGETTO STAZIONE METEOROLOGICA ****
#
#=======================================================================================#
# Andrea Coslovich, Daniele Palazzolo, Fabio Piccolo
#
#=======================================================================================#
=== FUNZIONI PER LA GESTIONE DEL SEMAFORO DI MUTUA ESCLUSIONE ===
Versione 1.00 - 29/3/2003
- Versione definitiva con ripulitura del codice
Storia del programma:
* Tutte le procedure incluse in questa libreria sono state provate
in precedenza come parte del codice meteo002.c
* Versione 0.00 - 9/3/2003
- Prima versione della libreria
Procedure prelevate del file meteo002.c
*/
#include "semaf.h"
int
{
/*
/*
/*
seminit(int semkey)
-------------------------------------- */
Inizializzazione dell’array semaforico */
-------------------------------------- */
int sid;
sid=semget(semkey,1,0700); /* Tento di agganciarmi ad un semaforo esistente */
if (sid==-1)
/* Errore nell’attivazione del semaforo */
{
if (errno==ENOENT) /* Il semaforo non esiste ancora */
{
/* Creo il semaforo e lo inizializzo */
if ((sid=semget(semkey,1,0700|IPC_CREAT))>0)
{ /* Semaforo creato... ora lo inizializzo... */
if (semctl(sid,0,SETVAL,1)!=0)
{
perror("Errore nell’inizializzazione del semaforo");
exit(1);
}
}
else
{ /* Errore nella creazione del semaforo */
perror("Errore nella creazione del semaforo");
exit(1);
}
}
else
{
perror("Errore nell’attivazione del semaforo");
exit(1);
}
}
return sid;
}
void down(int sid, int nsem)
{
/* -------------------------------------------- */
/* Down del semaforo numero nsem dell’array sid */
/* -------------------------------------------- */
struct sembuf op;
op.sem_num=nsem;
25
op.sem_op=-1;
op.sem_flg=SEM_UNDO;
semop(sid,&op,1);
}
void up(int sid, int nsem)
{
/* ------------------------------------------ */
/* Up del semaforo numero nsem dell’array sid */
/* ------------------------------------------ */
struct sembuf op;
op.sem_num=nsem;
op.sem_op=+1;
op.sem_flg=SEM_UNDO;
semop(sid,&op,1);
}
26
A.3
File data.c
/*
#=======================================================================================#
#
**** PROGETTO STAZIONE METEOROLOGICA ****
#
#=======================================================================================#
# Andrea Coslovich, Daniele Palazzolo, Fabio Piccolo
#
#=======================================================================================#
=== FUNZIONI PER LA STAMPA DI DATA ED ORA ===
Versione 1.00 - 29/3/2003
- Versione definitiva della libreria
*/
#include "data.h"
void printdate()
{
/* ------------------------------------------------- */
/* Stampa su stdio della data nel formato GG/MM/AAAA */
/* ------------------------------------------------- */
time_t tempo;
struct tm *data_ora;
int ora;
tempo=time(NULL);
data_ora=localtime(&tempo);
printf("%.2d/%.2d/%d", data_ora->tm_mday, ((data_ora->tm_mon)+1), ((data_ora->tm_year)+1900));
}
void printtime()
{
/* ------------------------------------------ */
/* Stampa su stdio dell’ora nel formato mm:oo */
/* ------------------------------------------ */
time_t tempo;
struct tm *data_ora;
int ora;
tempo=time(NULL);
data_ora=localtime(&tempo);
printf("%.2d:%.2d", data_ora->tm_hour, data_ora->tm_min);
}
27
A.4
File cgi.c
/*
#=======================================================================================#
#
**** PROGETTO STAZIONE METEOROLOGICA ****
#
#=======================================================================================#
# Andrea Coslovich, Daniele Palazzolo, Fabio Piccolo
#
#=======================================================================================#
=== FUNZIONI PER LA STAMPA DEL CODICE HTML ===
Versione 1.00 - 29/3/2003
*/
#include "cgi.h"
#include "data.h"
void printhead()
{
/* --------------------------------------- */
/* Stampa il codice HTML dell’intestazione */
/* --------------------------------------- */
printf("Content-type: text/html\n\n");
printf("<html>\n<head>\n");
printf("<title>Dati Stazione Meteorologica</title>\n</head>\n");
printf("<body text=’#000000’ vlink=’#000000’ link=’#000000’ bgcolor=’#FFFFFF’ marginheight=’0’");
printf(" marginwidth=’0’ topmargin=’0’ leftmargin=’0’ rightmargin=’0’>\n<center>\n");
printf("<br>\n");
printf("<table border=0 cellPadding=0 cellSpacing=1 width=780>\n");
printf("<tr><td align=’center’>\n");
/* INTESTAZIONE */
printf("<!------ INTESTAZIONE ------>\n");
printf("<table border=0 cellPadding=0 cellSpacing=2 width=778> <!-- Tab. intestaz. -->\n");
printf("<tr>\n");
printf("<td align=’right’> <!--- LOGO UNIVERSITA’ --->\n");
printf("<a href=’http://www.units.it’>\n");
printf("<img src=’/img/univlogo1.png’ alt=’Universita’ degli Studi di Trieste’");
printf(" WIDTH=99 HEIGHT=98 border=0>");
printf("</a>\n</td>\n");
printf("<td align=’center’ width=576> <!--- TITOLO --->\n");
printf("<span style=’font-family: Arial, Helvetica; font-size: 29px; color: #000000;");
printf(" font-weight: bold;’>Università degli Studi di Trieste</span><br>\n");
printf("<span style=’font-family: Arial, Helvetica; font-size: 8px; color: #000000; font-weight: bold;’><br></span>\n");
printf("<span style=’font-family: Arial, Helvetica; font-size: 20px; color: #000000;");
printf(" font-weight: bold;’>Dipartimento di Elettrotecnica Elettronica ed Informatica</span>\n");
printf("</td>\n");
printf("<td align=’left’> <!--- LOGO DEEI --->\n");
printf("<a href=’http://webdeei.units.it’>");
printf("<img src=’/img/deeilogo1.png’ alt=’Dipartimento di Elettrotecnica Elettronica");
printf(" ed Informatica’ WIDTH=99 HEIGHT=55 border=0>\n");
printf("</a>\n</td>\n</tr>\n</table>\n");
printf("<!--- FINE INTESTAZIONE --->\n");
/* FINE INTESTAZIONE */
}
void printdata(float tempin, float tempest, float press, float umid)
{
/* --------------------------------------------- */
/* Stampa il codice HTML del centro della pagina */
/* --------------------------------------------- */
printf("</td></tr>\n<tr><td align=’center’>\n");
/* CONTENUTO */
printf("<table border=0 cellPadding=2 cellSpacing=0 width=778> <!-- Tab. contenuto -->\n");
printf("<tr><td align=’center’>\n<br>\n");
printf("<span style=’font-size: 28px; color: #000000;’>Stazione meteorologica sperimentale</span>");printf("\n<br><br>\n");
printf("Dati rilevati alle ore ");printtime();
printf(" del ");printdate();
28
printf("<sup>(1)</sup><br><br>\n");
printf("<table border=1 cellPadding=5 cellSpacing=0> <!-- Tabella dati -->\n");
printf("<tr><td>Temperatura esterna:</td><td>%.1f<sup>o</sup>C</td></tr>\n",tempest);
printf("<tr><td>Temperatura interna<sup>(2)</sup>:</td><td>%.1f<sup>o</sup>C</td></tr>\n",tempin);
printf("<tr><td>Pressione atmosferica:</td><td>%.0f hPa</td></tr>\n",press);
printf("<tr><td>Umidità:</td><td>%.0f %%</td></tr>\n",umid);
printf("</table>\n<br><br>\n</td></tr>\n");
/* FINE CONTENUTO */
}
void printtail()
{
/* --------------------------------------- */
/* Stampa il codice HTML della fine pagina */
/* --------------------------------------- */
/* PIE’ DI PAGINA */
printf("<!--- PIE DI PAGINA --->\n");
printf("<tr><td align=’center’>\n<table border=0 cellPadding=0 cellSpacing=0 width=778>\n");
printf("<tr><td align=’center’>\n<hr>\n");
printf("<span style=’font-family: Arial, Helvetica; font-size: 12px; color: #000000;’>\n");
printf("(1) Se la data e l’ora non coincidono con quelle attuali si consiglia di caricare<br>\n");
printf("nuovamente la pagina con la funzione ’Aggiorna’ o ’Reload’ del proprio browser.<br>\n");
printf("(2) Temperatura rilevata all’interno dell’Aula D - Sede IEEE Student Branch<br>\n");
printf("ATTENZIONE: I dati presentati in questa pagina provengono da apparecchiature\n");
printf("non professionali e la loro correttezza non è garantita.\n");
printf("</span><hr>\n");
printf("<span style=’font-family: Arial, Helvetica; font-size: 12px; color: #000000;’>\n");
printf("INFORMAZIONI SULLA STAZIONE METEOROLOGICA: Questa stazione meteorologica è\n");
printf("stata realizzata da Andrea Coslovich, Daniele Palazzolo e Fabio Piccolo come tesina\n");
printf("per il corso di Misure Elettroniche del Prof. Claudio Mangiavacchi.\n");
printf("</span><hr>\n</td>\n</tr>\n</table>\n</td></tr>\n");
printf("<!--- FINE PIE DI PAGINA --->\n");
/* FINE PIE’ DI PAGINA */
printf("</table>\n</center>\n");
printf("</body>\n</html>\n");
}
29
B
APPENDICE: Esempio di registrazione dati meteorologici
30/03/2003
30/03/2003
30/03/2003
30/03/2003
30/03/2003
30/03/2003
30/03/2003
30/03/2003
30/03/2003
30/03/2003
30/03/2003
30/03/2003
30/03/2003
30/03/2003
30/03/2003
30/03/2003
30/03/2003
30/03/2003
30/03/2003
30/03/2003
30/03/2003
30/03/2003
30/03/2003
30/03/2003
30/03/2003
30/03/2003
09:00
09:30
10:00
10:30
11:00
11:30
12:00
12:30
13:00
13:30
14:00
16:30
17:00
17:30
18:00
18:30
19:00
19:30
20:00
20:30
21:00
21:30
22:00
22:30
23:00
23:30
22.0
22.5
22.5
22.5
24.0
25.5
26.0
26.5
26.5
26.5
26.5
26.5
27.0
27.0
26.5
27.0
27.0
27.0
27.0
27.0
27.0
27.0
27.0
26.5
26.5
26.5
22.5
22.5
23.0
23.0
24.5
25.5
25.5
26.0
26.0
26.5
26.0
26.5
26.5
26.5
26.5
26.5
27.0
26.5
27.0
27.0
27.0
27.0
27.0
27.0
27.0
26.5
1014
1014
1014
1014
1014
1014
1014
1014
1014
1014
1014
1012
1012
1012
1012
1012
1012
1012
1012
1012
1012
1013
1012
1012
1012
1012
48
49
49
49
51
50
49
49
48
47
47
45
46
46
46
46
45
43
43
43
43
43
43
43
42
42
30
C
APPENDICE: Note sul copyright e sulla licenza d’uso
Questo documento è copyright (C) 2003 di Andrea Coslovich, Daniele Palazzolo e Fabio Piccolo.
L’uso delle informazioni in esso contenute è sottoposto a licenza GPL.
Il testo della licenza può essere reperito a: http://www.gnu.org/licenses/gpl.html (traduzione
italiana non ufficiale: http://www.softwarelibero.it/gnudoc/gpl.it.txt)
31