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&agrave; 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&agrave;:</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 &egrave; 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 &egrave;\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