Capitolo 1

Schemi a blocchi


 

SCHEMA A BLOCCHI DELL’APPARATO DI TRASMISSIONE DATI DALLA STAZIONE METEO AL PC

 

 

 

 

 

 

 

 

 

 

 

 


Computer Centrale

 
                              

 

 

 


Figura 2

 

 

 

 

 

Lo schema a blocchi di fig.2 può essere scomposto come indicato in fig.3                    


 

Blocco 1

 
 

 

 

 

 

 

 

 


RX

 

TX

 
                                                                                                                                                                                                                                                                                                                                                   

 

 

 

 

Blocco 3

 
 

 


Figura 3

 

 

 

 

Casella di testo: Blocco 1:

METEO: E’ la stazione meteorologica dove vengono misurate alcune grandezze atmosferiche ed elaborate tramite circuiti interni.

PIC: E’ il single chip inserito da noi. Contiene al suo interno EPROM, RAM e I/O.
 

 


 

Casella di testo: Blocco 2:

TX: Trasmettitore radio.

RX: Ricevitore radio.
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


Si nota che il blocco 2 di figura 3 può essere assimilato ad un collegamento seriale per la trasmissione di dati; ciò evidenzia la possibilità di pervenire ad uno schema funzionale equivalente, nel quale il link a radio-frequenza è sostituito da un cavo seriale.

Questa semplificazione permette di svincolare dal resto del sistema lo sviluppo e la realizzazione del modulo a radio-frequenza, che notoriamente è una fase delicata e di non immediata messa a punto.

 

Il programma residente nella stazione centrale dovrebbe avere a disposizione i dati della stazione meteorologica, che però saranno disponibili solo al termine della realizzazione della scheda del PIC. È evidente che, per evitare ritardi a catena nello sviluppo del progetto, è indispensabile svincolare le varie parti l’una dall’altra.

Abbiamo ottenuto questo sviluppando un progetto ridotto composto da tre blocchi funzionali come indicato nella figura 4.

 

Blocco 3

 
 

 

 

Figura 4

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


BLOCCO 1: simulatore della stazione meteo.

BLOCCO TX - RX: simula l’apparato di trasmissione e ricezione ed è composto da una semplice linea seriale.

BLOCCO 3: è il personal computer della stazione base.

 

 

 

Il programma di simulazione che gira sul PC del blocco 1  si limita a generare le stringhe seriali come previsto dal protocollo di comunicazione (vedi capitolo 3).

Il programma principale (blocco 3) riceve i segnali di input esattamente come se a monte avesse il sistema completo.

 

 

 

L’utilizzo del simulatore  ha un ulteriore vantaggio: permette di generare condizioni atmosferiche estreme, difficilmente raggiungibili nella pratica, come ad esempio valori molto elevati o molto bassi, o grandi escursioni in tempi brevi;  in generale qualsiasi configurazione di dati insolita, necessaria per il test del software.

 

 

 

 

 

 

 

 

Capitolo 2

La stazione meteorologica

 

La stazione rileva e misura le seguenti grandezze:

 

1.      Temperatura dell’aria

2.    Umidità dell’aria

3.    Pressione atmosferica

4.    Velocità del vento

 

Gli intervalli di variazione sono i seguenti:

 

T.     Compresa tra    –10 e +50 °C ;

U.     Compresa tra    0 %  e  100 % ;

P.      Compresa tra     900 mb e 1100 mb ;

V.     Compresa tra     0 e 100 Km/h .

 

Lo schema funzionale a blocchi è illustrato in fig. 5

Gli schemi elettrici dettagliati sono  nell’appendice 6.

 

Nel seguito di questo capitolo verranno illustrate le caratteristiche principali.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 



PIC

 
                                                                                                                                                                                                                                                                                                                                                                                                                                                         

Stazione meteorologica

 
La stazione meteorologica, come si può notare dallo schema a blocchi, può essere studiata prendendo in esame le varie componenti che la costituiscono:

 

Trasduttore di Temperatura

 
 


                                                          

 

 

 


                              

Trasduttore di

Umidità

 
Vengono rilevate le varie grandezze fisiche e trasformate in impulsi elettrici

 

Trasduttore di

Velocità

 
                                                                                                                                                                                                                                                                                                                                                                                                                                        

Tutti i segnali provenienti dai trasduttori sono inviati ai rispettivi circuiti di condizionamento

 

Circuiti di condizionamento

 
I circuiti di condizionamento sono utilizzati per amplificare il segnale in modo da renderlo adatto alle successive elaborazioni.

 

 

 

I segnali, dopo essere passati dai circuiti di condizionamento, vengono inviati a un multiplexer analogico.                                                                                      

Multiplexer

analogico

 
                                       Questo componente è utilizzato per convogliare tutti i dati provenienti dai circuiti di condizionamento in un’unica uscita per permettere la elaborazione numerica.

 

A questo punto i dati vengono inviati ad un convertitore analogico / digitale

 

Convertitore

A/D

 
                                       Questo componente è necessario per convertire il segnale da analogico a digitale per rendere possibile la lettura da parte del mcomputer.

 

A questo punto i dati sono rilevati sia dal microprocessore della centralina, che dal circuito progettato da noi. Quest’ultimo li elabora e, mediante un trasmettitore radio che utilizza la tecnica FSK (Frequency Shift Keying), li invia al computer centrale.

 

Il microprocessore a bordo della centralina, un sistema basato su un mP Z80, con 8 Kb di RAM e 8 Kb di Eprom, provvederà alla visualizzazione locale su display.

 

 

 

 

 

 

 

 

 

Il seguente diagramma può mostrarci sinteticamente le operazioni eseguite dallo Z80 a bordo della stazione meteo.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Elabora xxx

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 



I circuiti di condizionamento dei segnali analogici.

 

 

 

 

Per comprendere meglio il funzionamento dei circuiti di condizionamento dei segnali provenienti dai sensori, abbiamo studiato quello relativo alla pressione atmosferica.

 

 

 

 

 

 

.

 

 

 

Rilevamento di pressione

 

Per misurare la pressione atmosferica si utilizzano dispositivi che fanno uso di trasduttori di pressione, i quali si differenziano in base all’effetto fisico sul quale si basano. Questo può essere di tipo:

-Capacitivo- sono, in pratica, dei condensatori la cui capacità varia quando una delle armature subisce una deformazione non permanente della sua struttura a causa della pressione ad essa applicata. Il sensore è poco sensibile alla variazione di temperatura, presenta alta stabilità, ma richiede processi di fabbricazione molto complessi;

-Induttivo- sono basati sul principio della variazione di induttanza. Questo tipo di trasduttore presenta svantaggi sia per la sua dimensione sia per la scarsa sensibilità;

-Effetto hall- sono costituiti da una membrana sulla quale si sposta un piccolo magnete a causa della variazione di pressione;

-Piezoresistivo- sono costituiti da semiconduttori la cui resistenza varia per la deformazione meccanica (in genere un incurvamento) di una membrana sotto l’azione di una pressione applicata.

 

Nel nostro caso, il trasduttore di pressione che abbiamo utilizzato per la stazione meteo è di tipo piezoresistivo, mod. MPX100AP.

Il trasduttore ha le seguenti caratteristiche:

 

 

·     Il componente compie una misura di tipo assoluto, ovvero il ponte è all’equilibrio per una pressione di 0 Bar;

·     Il trasduttore rileva una pressione nel campo atmosferico: range 0 : 2 Bar;

·     Sensibilità di 0.6 mV/Kpa » 0.06 mV/mbar;

·     Linearità di -0.25% : 0.25%;

 

·     Zout » 1600 W.

 

 

Il segnale dovrà essere inviato ad un sistema digitale, pertanto è necessaria una conversione A/D.

Il convertitore che abbiamo utilizzato per trasformare il segnale  da analogico a digitale è del tipo ADC 0808 e fornisce un codice binario che varia da:

 

00H per V­­in = 0V a FFH per Vin = 5,12V

 

Per utilizzare completamente il campo di tensione d’ingresso del convertitore, occorre realizzare un circuito di condizionamento che faccia corrispondere l’escursione del segnale fornito dal trasduttore, con quella d’ingresso del convertitore.

 

 

 

 

 

 

Il circuito di figura 5 si compone di:

 

·        Trasduttore di pressione;

·        Un preamplificatore, realizzato mediante un amplificatore differenziale che riceve agli ingressi il segnale della diagonale di rilevamento del ponte integrato e ne effettua una prima amplificazione (condizione di basso rumore);

·        Un circuito di offset e fondo scala: occorre che il segnale d’uscita vari nel campo 0 .. 5.12V, in corrispondenza di una variazione dell’ingresso da 900 a 1100 mBar.


 

 

 

Fig. 5

 

 

 


 

Calcolo dell’escursione della tensione del trasduttore

 

Le tensioni di uscita dal trasduttore, per i limiti massimo e minimo previsti dalla nostra applicazione, sono le seguenti:

 

Vabm   = 900 * 0.06 = 54 mV      [1]

VabM = 1100 * 0.06 = 66 mV

 

 

PROGETTO DEL PREAMPLIFICATORE:

 

La tensione Vab viene inviata al preamplificatore, costituito da un amplificatore operazionale LM 324 in configurazione differenziale con guadagno = 10.

 

R2 = 1MW ed R1=100 MW

 

Si ottiene Vu1min = 0,54V (900mBar);   Vu1max = 0,66V (11mBar).

 

 

 

Circuiti di offset di fondo scala

 

 

OFFSET

 

L’offset si ottiene per mezzo di una tensione di riferimento, applicata all’ingresso invertente, che consente di avere Vu = 0 in corrispondenza della pressione minima.

La tensione di riferimento è ottenuta per mezzo di un trimmer multigiri collegato a un inseguitore di tensione . 


FONDO SCALA

 

Il fondo scala corretto si ottiene progettando il guadagno dell’amplificatore in modo che la tensione di uscita sia

Vumax = 5,12 Volt in corrispondenza di P = 1100 mBar.

 

Essendo la variazione massima di tensione pari a 12 mV per

DP = 1100 – 900 mBar (Vab maxVab min). [Vedi formula 1]

 

Si ha         5,12V / 12mV @ 416 = amplificazione totale 

 

Essendo l’amplificazione del 1° stadio pari a 10 si deve porre l’amplificazione del 2° stadio pari a 41,6 che si è ottenuta ponendo:

 

R5 = R8 = 1100 W

R6 = R7 = 47 KW

 


 

 

 

 

 

 

 

 

 

 

 

 

 

Capitolo 3

Il software nell’unità centrale
In questo capitolo verranno discussi i due programmi realizzati con un linguaggio ad alto livello ( BASIC ). L’analisi del software in assembler, residente nel PIC 16C84, verrà affrontato nel capitolo 5.

 

I due programmi qui presi in esame sono:

 

·        Simulatore della stazione meteorologica.

·        Programma principale per la raccolta, memorizzazione e gestione dei dati, situato nel computer centrale.

 

La scelta del Basic come linguaggio di programmazione è stata dettata dalla necessità di utilizzare un linguaggio semplice e nel contenuto potente e utilizzato a livello industriale.

 


Programma simulatore

 

Come illustrato nell’introduzione, si è resa necessaria la messa a punto di un programma in grado di simulare il comportamento della stazione meteorologica.

Questo ci ha permesso, non solo di fare a meno della presenza di quest’ultima in laboratorio, ma anche di simulare quei valori delle grandezze atmosferiche che raramente si presentano, come ad esempio forti variazioni improvvise.

Il programma si deve limitare a fornire alla stazione centrale le stringhe relative alle grandezze atmosferiche come se fosse effettivamente generate dalla centralina meteo; in particolare deve quindi rispettare i range di variazione previste dall’elettronica.

Il fine di permettere un corretto dialogo tra la stazione meteo e il computer centrale, abbiamo messo a punto un semplice protocollo di comunicazione tra master e slave.

 

 

 

 

 

 

 

 

 

 

Flow chart simulatore

 

 

 

 

 

 

Inizio

 

 
                                                                                        

 

 

 

 

 

 

 

 

 

 


Casella di testo: Genera e spedisce la stringa della temperatura atmosferica con valori compresi tra –10 e +50°C.

Tx.Temp

 
                                              

 

 

 

 

 


La semplicità del software, evidenziata anche dal diagramma di figura, rende inessenziale un’analisi più approfondita.

Il protocollo di dialogo

 

 

Le grandezze rilevate dalla stazione meteo sono quattro; è quindi necessario prevedere un formato di comunicazione tra la centralina e il PC per mettere in grado quest’ultimo di discriminare quale di esse è quella che si sta trasmettendo.

Il protocollo che abbiamo messo a punto tiene conto delle possibili necessità.

La stringa trasmessa dalla centralina avrà il seguente formato:

 

[$grandezza+/-****#]

dove:

 

$                       Carattere di inizio stringa; è il primo              carattere trasmesso dalla stazione meteo che informa l’inizio del dato in arrivo al PC.

grandezza         T (Temperatura ), P (Pressione), U (Umidità),

                         V (Velocità del vento); riconosce quale di

                         questi valori gli verrà trasmesso.

+/-                    Segni: riconosce se la grandezza ha valore

                         positivo o negativo.

****                  4 Cifre numeriche.

#                      Carattere di fine stringa; indica la fine

                         della trasmissione del dato.

 

 

 

 

 

 

 

Programma principale

 

 

Le sue prestazioni sono le seguenti:

 

 

·        Riceve i dati trasmessi dalla stazione meteo;

·        Memorizza le informazioni su disco;

·        Traccia i grafici delle grandezze misurate, con possibilità di scelta tra: grafici in tempo reale, grafici storici giornalieri, settimanali, mensili, stagionali e annuali;

·        Esegue statistiche.

 

Nella figura seguente è schematizzato quanto sopra.

 

Prestazioni software

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


Come si è risolto il problema

 

 

Si è data la preferenza ad un interfaccia utente semplificata al massimo, in modo da permettere l’utilizzo del programma anche alle persone meno esperte.

La navigazione tra le varie opzioni è ottenuta con semplici menù di testo che illustrano chiaramente le varie funzioni.

 

Il diagramma seguente illustra le principali operazioni compiute dal processo.

 

Flow chart ricevitore

 

 

 

 

 

 

 

 

 

 

 


Casella di testo: Memorizza su file le grandezze ricevute

 

 

 

 

 

 

 

 


Il programma è stato progettato per tracciare i grafici delle grandezze atmosferiche misurate e per memorizzare permanentemente i dati su file.

I tipi di grafici possibili possono essere riassunti in:

 

a)     Tutti i grafici contemporaneamente.

b)    Un singolo grafico.

 

Tutti i diagrammi sono sempre riferiti ad una intera giornata ( dalle 0 alle 24 )

 

 

 

 

                                                                                                                                                                                                                                                                                                                                                                         

                                                                                                                                                                                                                                                         

 

 

 

 

     0                                                                                       24               

 

 

I campioni vengono plottati e memorizzati su file ogni 5 minuti; la loro organizzazione su file è la seguente: un file al giorno per ogni grandezza, quindi ogni giorno vengono generati 4 files distinti.         

 

I dati sul file contiengono, per ogni campione, le seguenti informazioni:

·        Data

·        Ora

·        Tipo di grandezza.

·        Valore della grandezza.

 

 

Per analizzare più in dettaglio le prestazioni del software, partiremo dall’esame delle varie opzioni previste dai menù del programma.

Sostanzialmente possiamo dividere le possibili scelte in due macro gruppi:

 

 

 

Diagrammi in tempo reale delle grandezze misurate

 
 

 

 

 

Diagrammi ricavati da registrazioni precedenti ( statistiche )

 
 

 

 

 

 

 

 

 


I diagrammi delle figure seguenti, mostrano in dettaglio quanto esposto.

 

 

 

 

 

 

 

Menù principale

 

 

Casella di testo: START

                         

TASTO 1
 
 

 

 

 

 

 

 


Casella di testo: Grafici di tutte le grandezze

EXIT

 

 

 

 

 

 


Casella di testo: TASTO 3Casella di testo: Grafico della temperatura atmosferica

Grafico della pressione atmosferica

 

EXIT

 
 

 


Casella di testo: TASTO 4

 

 


Casella di testo: TASTO 5

 

 

 

 

 

 

 

 

 

 


Casella di testo: EXIT

Casella di testo: Vedi  la  prossima  figura

 

 

 

 

 

 

Menù statistiche

 

 

 


Casella di testo: EXIT
Casella di testo: TASTO 2

TASTO 1

 
Casella di testo: TASTO 4

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


La figura seguente mostra la schermata principale del programma.

 

 


 

 

 


 

 

 

 

 

 

 

 

 


Capitolo 4

 

Il modulo ricetrasmettitore

 

 

 

 

 

 

 

 

 

Il progetto, la relazione e la messa a punto di un modulo per la trasmissione e la ricezione dati via radio presentano difficoltà non banali anche per un esperto del settore.

Tenuto conto che l’obbiettivo di questa esperienza, come illustrato nel capitolo 2, è indipendente dal tipo di trasmissione dati utilizzato, è sembrato opportuno ricorrere a kit commerciali di sicura affidabilità.

 

 

 

 

 

Caratteristiche dei kit a radiofrequenza utilizzati.

 

 

                        TRASMETTITORE MK 1645

 

Il trasmettitore utilizzato nel progetto è costituito da un modulo elettronico commerciale con le seguenti caratteristiche principali:

 

·        Frequenza di lavoro: 49,89 MHz

·        Alimentazione: tra 9 e 12V.

·        Assorbimento: 15 – 30 mA.

·        Modulazione sia in FM (DTMF) sia in FSK; nel nostro caso il trasmettitore lavorerà in FSK.

 

Le specifiche indicano che è sufficiente antenna a filo di 50 cm. per coprire la distanza necessaria per la nostra applicazione.

 

 

 

 

                        RICEVITORE MK 1945

 

Il ricevitore utilizzato nel progetto è costituito da un modulo elettronico commerciale con le seguenti caratteristiche principali:

 

·        Gamma di ricezione: tra 48 e 52 MHz.

·        Alimentazione: tra 9 e 12V.

·        Assorbimento: 10 mA.

·        Ricezione supereterodina a doppia conversione: a 10.7 MHz e 455 KHz con quarzo a 10.245 MHz.

·        Larghezza di banda 8.7 KHz (18dB – 12dB).

·        Uscita analogica e digitale (per modulazione FSK).

·        Massima velocità di trasmissione digitale: 2400 bit/s

 

 

 

Per maggiori dettagli si rimanda all’appendice.

 

 

 


Brevi cenni sulla modulazione

 

La modulazione è un processo che consiste nel traslare l'allocazione in frequenza della banda (finita) di un segnale informativo. Di fatto, la modulazione è l'alterazione sistematica di una forma d'onda, chiamata portante, secondo le caratteristiche di un'altra forma d'onda: la modulante, ovvero il messaggio.

I motivi per cui si rende necessario modulare un segnale per trasportare l’informazione sono almeno quattro:

 

·        Assegnazione di bande, cioè ripartizione delle medesime risorse fra più utenti che necessitano di comunicare nello stesso tempo e nello stesso luogo .

·        Agevolare l'irradiazione, cioè meglio adattare il segnale all’onda elettromagnetica.

·        Trasmettere contemporaneamente più segnali differenti, basti pensare alla televisione.

·        Riduzione del rumore e delle interferenze.

 

 

 

Possiamo schematizzare un canale di trasmissione nel seguente modo:

 

Sorgente Þ Modulatore Þ Filtro di Trasmissione [HT(f)] Þ Canale [HC(t)] Þ Filtro di Ricezione [HR(f)] Þ Demodulatore.

 

In questo modello HT(f), HC(f) ed HR(f) sono le funzioni di trasferimento dei rispettivi blocchi. Generalmente si suppone che il canale sia lineare ed il rumore sia additivo. Mentre, per quanto riguarda i filtri di trasmissione e di ricezione, che dovrebbero essere sempre presenti, si assume che siano filtri passabanda centrati attorno alla frequenza di riferimento della portante f0. Se f0 = 0, i filtri sono di tipo passa-basso e la trasmissione si dice in banda base. In questo ultimo caso utilizzato, ad esempio, per le comunicazioni fra due calcolatori via seriale o parallela, non vi è modulazione.

Le modulazioni possono essere divise in due grosse branche: analogiche e digitali. A loro volta, in base alle caratteristiche della modulazione stessa, verranno suddivise in altre tipologie. E’ possibile così avere almeno due categorie di modulazioni: analogiche e digitali.

 

 

 

 

 

 

Nella figura seguente è illustrato un semplice schema a blocchi delle categorie della modulazione:

 

PAM

 

Portante impulsiva

 

PWM

 

PPM

 

 PCM

 

Portante analogica

 

FSK

 

Frequenza

 

Fase

 

Digitale

 

Angolo

 

Ampiezza

 

Analogica

 

Modulazione

 
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  

 

 

 

Modulazioni digitali

 

 

 

La modulazione digitale,come visto nello schema, si divide anch’essa in due rami: modulazione a portante analogica e a portante impulsiva. Per la modulazione di tipo analogico ci limiteremo solo a descriverne i fondamenti principali dato che noi useremo la modulazione digitale. La modulazione digitale a portante analogica trasmette il segnale non modificando la banda, ma convertendo il segnale da digitale ad analogico. Nella fase di ricezione si rieffettua una conversione che in questo caso sarà da analogica a digitale; tutto questo viene fatto per utilizzare una banda decisamente più stretta, dato che il segnale digitale possiede una banda nell’ordine dei MHz.

 

 

 

Queste modulazioni prendono diverse sigle e sono: ASK, FSK, PSK, DPSK, QAM. Nell’ordine i loro acronimi sono: Amplitude Shift Keying, Frequency Shift Keying, Phase Shift Keying, Differential Phase Shift Keying.

La modulazione a portante impulsiva consiste nel trasmettere un treno di impulsi variando uno dei parametri dell’impulso (ampiezza, durata, posizione), rispetto ai campioni di segnale modulante. Come per le modulazioni a portante analogica, si hanno varie sigle di identificazione: PWM, PCM, PAM, PPM;  e i loro acronimi sono: Pulse Width Modulation, Pulse Code Modulation, Pulse Amplitude Modulation,  Pulse Position Modulation.

 Un segnale digitale può modulare l'ampiezza, la frequenza o la fase di una portante sinusoidale. Se la forma d'onda modulante consiste in impulsi rettangolari senza ritorno a zero, allora i parametri modulati saranno spostati [in inglese Keyed] da un valore discreto all'altro. Le modulazioni digitali più usate sono l'ASK [Amplitude Shift Keying], praticamente sinonimo di PAM [Pulse Amplitude Modulation], l'FSK [Frequency Shift Keying] e la PSK [Phase Shift Keying].

La modulazione digitale, come già detto prima, riguarda la trasmissione di un treno di impulsi binari in un mezzo qualsiasi; la modulazione usata nella nostra esperienza è una modulazione di tipo FSK.

In questo tipo di modulazione la portante viene trasmessa ad una frequenza f2 quando è presente l’impulso, ad una frequenza f1 in assenza di impulso; in sostanza è una modulazione di frequenza, in cui la portante slitta rapidamente tra le due frequenze f1  e f2.

 

 

Esempio:

Dato

 

0

 

1

 

1

 
             

                        

                                                         

                                                                                                             

t

 

FSK

 
 

 

 

 


t

 
 

 

 

 



Lo spettro è rappresentato nella figura seguente e può essere determinato considerando il segnale FSK come la sovrapposizione di due segnali ASK a frequenze diverse. Viene pertanto costruito affiancando due spettri ASK, riferiti uno alla frequenza f1, l’altro alla frequenza f2. Nell’esempio: Df = f2 – f1 = 12 fi.

                                                                                                                                                   

f1

 

f2

 
 

 

 

 

 


       

 

 


La modulazione FSK richiede una banda maggiore della modulazione ASK a causa della presenza delle due portanti; presenta però il vantaggio di non richiedere, come l’ASK, un livello di soglia variabile al rivelatore per minimizzare la probabilità d’errore: i valori della probabilità d’errore, in funzione del rapporto S/N, sono dello stesso ordine dei valori ottimali dell’ASK. La FSK è pertanto usata quando il mezzo di trasmissione ha caratteristiche variabili nel tempo, che producono variazioni del rapporto S/N: per avere la minima probabilità di errore, nell’ASK occorre variare il livello di soglia del rivelatore, mentre nella FSK il livello è indipendente da S/N.

Per ridurre la banda occupata e la potenza di trasmissione, si ricorre a trasmissioni di tipo SSB o VSB. Per aumentare la velocità di trasmissione si sfruttano tecniche multilivello, consistenti nell'associare a multiplette di bit livelli di tensione differenti, ad esempio, associamo alla parola 00 il livello di 0 V, a 01 1 V, a 10 2 V ed a 11 3 V. Nell'FSK, ai due livelli logici 1 e 0 corrispondono due differenti frequenze. Ad esempio, nella raccomandazione CCITT V.23 si associa allo 0 una frequenza di 2.1 kHz e all'1 quella di 1.3 kHz.

 

Comunicazione in FSK

 

La FSK è usata esclusivamente per le trasmissioni telegrafiche e simili; i valori usati della differenza fra le frequenze trasmesse sono: 170 Hz, 200 Hz, 400Hz, 850 Hz. La velocità di trasmissione è limitata di solito a valori inferiori a 100 Baud. A causa delle caratteristiche della propagazione delle onde HF, i segnali possono seguire percorsi multipli, arrivando al ricevitore con ritardi che possono essere anche di alcuni millisecondi; un impulso trasmesso, che ha seguito il percorso più lungo, si può sovrapporre all’impulso successivo, che ha seguito il percorso più breve. Per evitare ciò, è conveniente che gli impulsi abbiano durata superiore a 10 ms, con conseguente necessità di ridurre il numero di impulsi trasmessi al secondo a valori inferiori a 100.

Nella nostra applicazione si è potuto utilizzare una velocità di trasmissione di 1200 baud, essendo la distanza da RX a TX di poche decine di metri. Questo impedisce i grandi ritardi dovuti ai percorsi multipli.

 

 

ESEMPIO:                          TRASMETTITORE  FSK

Moltiplicatore   di frequenza

 

Oscillatore

 
 

 

 


                                                 L

 


                                                                                                                    

 

 

 

                                                                                    

L’informazione è sottoforma di impulsi. In presenza di un impulso, supposto positivo, il diodo D è in saturazione; il condensatore C è inserito nel circuito risonante di un’oscillatore e ne varia la frequenza di oscillazione. Presenza ed assenza di impulsi sono pertanto caratterizzate da due frequenze diverse. Il segnale di uscita dell’oscillatore è applicato ad un moltiplicatore di frequenza, che porta la frequenza al valore di trasmissione e quindi ad un amplificatore di potenza a radio frequenza, che aumenta il livello di potenza del segnale.

La modulazione FSK richiede una banda maggiore rispetto all’ASK, ciò a causa della presenza delle due portanti, tuttavia la si preferisce all’ASK per maggior semplicità dei circuiti di demodulazione e di rivelazione del segnale. Inoltre, essendo l’ampiezza del segnale modulato indipendente dal segnale modulante, questo tipo di modulazione sarà meno sensibile ad un rumore additivo che andrà a variare proprio l’ampiezza del segnale

 


 

 

Interconnesione remota di terminali mediante uso di interfaccia seriale e linee telefoniche

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


Standard seriale rs232

 

Lo standard seriale di interfacciamento e’ stato introdotto al fine di collegare dispositivi remoti a bassa velocita’ con un calcolatore centrale.

 

La caratteristica di un’interfaccia seriale e’ il meccanismo di serializzazione dei dati; questo meccanismo deve tener conto del fatto che, a causa della lunghezza di connessione, e’ possibile avere errori sia sui bit trasmessi; ad esempio un bit zero, a causa degli accoppiamenti parassiti, puo’ essere interpretato come un uno. A tale scopo  ai bit di dato vengono aggiunti alcuni bit di controllo e di sincronizzazione.

Normalmente le interfacce seriali possono essere impostate sia per una lunghezza di parola di 7 bit oppure di 8 bit. Quando il dispositivo di trasmissione deve inviare informazioni sulla linea, inizialmente porta il valore della stessa al valore logico 0 (space) e decide una velocita di trasmissione; in questo modo il ricevitore viene sincronizzato ed il bit corrispondente viene definito “Start Bit”. Vengono poi inviati  in sequenza i bit  d’informazione che alla fine della trasmissione della stessa viene inserito un bit di parita’ (parita’ pari o dispari), che serve per il controllo di eventuali errori occorsi durante la trasmissione, ed infine viene inserito un bit di stop.

All’atto della ricezione e’ possibile quindi verificare la presenza di errori ed eventualmente richiedere al sistema una ritrasmissione dell’informazione.

L’interfaccia seriale presa in considerazione necessita di collegamenti fra le due apparecchiature da interfacciare che vengono resi disponibili mediante l’uso di un connettore a 9 o 25 pin.


 

 

 

 

 

 

 

 

 

 

 

 

Capitolo 5

Il PIC 16C84

 

 


 

 

 

 

 

 

 


Il PIC 16C84 avrà il compito di :

 

1. Leggere i dati dalla stazione meteo ;

2. Generare le stringhe conformi al protocollo ;

3. Inviare le stringhe alla radiotrasmittente.

 

 

Descrizione del microprocessore

 

Recentemente l’impiego dei microcontrollori si sta diffondendo, oltre che nelle grandi industrie, anche a livello personale ed hobbistico, sia per la semplicità di programmazione che per l’esiguo numero di componenti esterni richiesto.

Il PIC16C84 è un microcontrollore in tecnologia CMOS a 8 bit caratterizzato dal basso  costo e alte prestazioni.

Tutta la famiglia dei PIC16/17 impiega un’avanzata tecnologia RISC che permette il buon funzionamento del dispositivo con solamente 35 istruzioni.

Quasi tutte le istruzioni sono eseguibili in un solo ciclo (400 ns) ; è dotato di una memoria programmabile da 1K di tipo EEPROM, 15 registri per funzioni speciali, 64 registri ad 8 bit EEPROM per i dati, 8 livelli di stack, 36 x 8 registri interni general purpouse (SRAM), 8 livelli di stak e 4 sorgenti di interrupt:

 

·  Pin INT esterno ;

·  Overflow del TIMER 0;

·  Cambio di stato sulla porta B <4..7>;

·  Fine ciclo di scrittura in EEPROM dati.

 

PRESTAZIONI DELLE PERIFERICHE:

 

Esistono 13 I/O pin con controllo individuale di direzione. Possono erogare 20 mA di corrente per pin e 25 mA di corrente come sink.

 

PRESTAZIONI SPECIALI DEL MICROCONTROLLORE:

 

La famiglia dei PIC16XX ha alcune funzioni speciali che permettono di ridurre i componenti esterni e quindi anche i costi, sia economici che di corrente; infatti si possono utilizzare quattro tipi di oscillatori:

 

1. Oscillatore RC, che comporta una soluzione a basso costo ;

2. Oscillatore LP, che minimizza il consumo di energia ;

3. XT, che è un quarzo standard ;

4. HS, che viene utilizzato per quarzi ad alte frequenze.

 

Per ridurre ulteriormente i consumi è prevista la modalità  SLEEP; l’assorbimento a 5V e 4 MHz minore di 2 mA, mentre l’assorbimento in fase di SLEEP è minore di 1 uA.

 

 

 

 

 

 

 

L’ HARDWARE:

 

L’hardware del PIC è particolarmente ricco di componenti elettronici ; andremo ora a spiegare il funzionamento base dei principali componenti :

    

·  Lo Status Register permette di far conoscere l’esito di una istruzione immediatamente dopo che è stata eseguita.

·  Il Working Register è il più sfruttato, essendo  l’unico che consente il passaggio dei dati da un registro all’altro.

·  Le periferiche sono: i 64 byte di EEPROM, il timer RTCC (Real Time Clock Counter) e i registri delle porte vere e proprie (il timer RTCC può anche essere chiamato TMR0).

·  I registri SRAM, sono suddivisi in due banchi, banco 0 e banco 1; quindi per poter effettuare operazioni su di essi, dovremo prima settare correttamente il bit che seleziona l’uno o l’altro di questi due banchi.

 

 

IL RESET DEL CHIP:

 

Esistono diversi modi per resettare il PIC, di cui il primo è la forzatura a massa del pin MCLR (Master CLeaR) : quando questo pin viene collegato a massa il chip si trova in fase di reset; il secondo sistema consente l’impiego del watchdog timer, che però deve essere abilitato o meno in fase di programmazione. Si può infine generare un segnale di reset dal riconoscimento della tensione di alimentazione, sempre che il chip parta sempre dallo stato che noi abbiamo previsto.

Abbiamo la possibilità, in aggiunta a questo, di abilitare un altro reset all’accensione, di durata maggiore rispetto al precedente; questo meccanismo viene in genere impiegato nel caso in cui il chip riceve l’alimentazione da un dispositivo collegato alla rete con un tempo di salita della tensione relativamente lungo.

 

 

Set di istruzioni del PIC16C84

 

Le seguenti istruzioni assembler sono comuni anche agli altri chip delle famiglie PIC16/12C/17CXX.

 

ISTRUZIONI ORIENTATE AL BYTE

 

ADDWF f,d   

Somma il vcalore del registro W a quello del registro f e mette il risultato in W se d=0, in f se d=1 (default)

ANDWF f,d

Esegue l’operazione booleana AND tra il registro W ed f e mette il risultato in W se d=0, in f se d=1 (default)

CLRF f

Pone a 0 il valore del registro f

CLRW

Pone a 0 il vcalore del registro W

COMF f,d

Complementa il valore del registro f e mette il risultato e mette il risultato in W se d=0, in f se d=1 (default)

DECF f,d

Sottrae 1 al registro f e mette il risultato in W se d=0, in f se d=1 (default)

DECFSZ f,d

Sottrae 1 al registro f, poi se il valore di tale registro è divenuto 0, salta l’istruzione altrimenti il risultato viene locato in W se d=0, in f se d=1 (default)

INCF f,d

Somma 1 al registro f e mette il risultato in W se d=0, in f se d=1 (default)

INCFSZ f,d

Somma 1 al registro f, poi se il valore di tale registro è divenuto 0, salta l’istruzione altrimenti il risultato viene locato in W se d=0, in f se d=1 (default)

IORWF f,d

Esegue l’operazione booleana OR tra il registro W e il registro f e mette il risultato in W se d=0, in f se d=1 (default)

MOVF f,d

Legge il valore del registro f e lo copia su se stesso se d=1 oppure in W se d=0

MOVWF f,d

Legge il valore di W e lo copia nel registro f.

NOP

Non esegue alcuna operazione

RLF f,d

Esegue l’operazione di shift a sinistra del registro f. Al bit 0 viene assegnato il valore del Carry, mentre il Carry prende il valore del bit 7 

RRF f,d

Esegue l’operazione di shift a destra del registro f. Al bit 7 viene assegnato il valore del Carry, mentre il Carry prende il valore del bit 0 

SUBWF f,d

Sottrae il valore del registro W al valore del registro f e mette il risultato in W se d=0, in f se d=1 (default)

SWAPF f,d

Scambia i due nibble del registro f e mette il risultato in W se d=0, in f se d=1 (default)

XORWF f,d

Esegue l’operazione booleana EX-OR tra il registro W ed f e mette il risultato in W se d=0, in f se d=1 (default)

 

 

Istruzioni orientate al bit

 

BCF f,b

Pone a 0 il valore del bit b del registro f

BSF f,b

Pone a 1 il valore del bit b del registro f

BTFSC f,b

Testa il valore del bit b del registro f : se tale il valore è 0 e salta l’istruzione immediatamente successiva

BTFSS f,b

Testa il valore del bit b del registro f : se tale il valore è 1 e salta l’istruzione immediatamente successiva

 

 

 

Istruzioni di controllo

 

ADDLW k

Somma la costante k al valore del registro W

ANDLW k

Esegue l’operazione booleana AND tra la costante k ed il registro W

CALL k

Effettua una chiamata alla subroutine k

CLRWDT

Pone a 0 il registro watchdog

GOTO k

Esegue un salto alla label k

IORLW k

Esegue l’operazione booleana OR tra la costante k ed il registro W

MOVLW k

Pone nel registro W il valore della costante k

RETFIE

Consente il ritorno dopo interrupt

RETLW k

Consente il ritorno dopo una CALL copiando il valore della costante k nel registro W

RETURN

Consente il ritorno dopo CALL 

SLEEP

Pone il controller in modalità SLEEP

SUBLW k

Sottrae la costante k al valore del registro W

XORLW k

Esegue l’ operazione booleana EX-OR tra la costante k ed il registro W

OPTION

Copia il valore del registro W nel registro OPTION

TRIS f

Copia il valore del registro W nel registro di settaggio direzione delle porte A e B ; f potrà valere solo 5 (porta A) o 6 (porta B)

 

 


Schema a blocchi dettagliato del programma del PIC

 

 

 

 


Spedisce stringa di identificazione dell’umidità

 

Spedisce stringa di identificazione della temperatura

 

Spedisce stringa finale

 

Spedisce il dato

 

No

 

 

No

 

 

No

 

 
Decisione: Canale
Temp?

Definisce le variabili e le costanti

 
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          

 

 

 

 

 

 

 

 

 

 

 

 


Il PIC ha essenzialmente la funzione di ricevere i dati dalla stazione meteorologica (8 bit in parallelo) e di convertirli in modo da ottenere una trasmissione seriale; i dati gli arrivano a intervalli molto lunghi tra uno e l’altro, quindi non ci sono problemi di velocità, e arrivano in sequenza ( temperatura, pressione, umidità e velocità del vento ). Al PIC giunge anche il segnale di selezione direttamente dalla stazione e in base ad esso, quando inizia la trasmissione, spedisce una stringa di identificazione in modo che il computer che riceve il dato possa facilmente stabilire quale grandezza sta ricevendo.

 

 

Schema di principio della funzione del PIC 16C84

 

 

 

Legge i dati che provengono dalla stazione meteorologica

 
 

 

 

 

 

 

 

 

Attua la conversione Parallelo/Seriale

 
 

 

 

 

Invia il dato seriale al trasmettitore

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


Conversione Parallelo/Seriale

 

 

Il PIC 16C84 non possiede un’istruzione o un comando che effettua direttamente la suddetta conversione, e per questo motivo si è ricorso alla progettazione di un programma che  realizza una trasmissione dati seriale utilizzando lo standard RS232.

Questo tipo di trasmissione può essere eseguita a diverse velocità standard : 150, 300, 600, 1200, 2400, 4800 e 9600 bit/s. Si è scelta una velocità di trasmissione di 1200 bit/s poiché è piuttosto semplice da realizzare e adatta alle nostre esigenze che non richiedono una grande velocità: i dati dalla stazione meteorologica vengono spediti con un ritardo di circa 2 secondi, permettendo al computer che riceve il dato di eseguire tutte le operazioni di ricezione, plottaggio e memorizzazione.

 

 

Esempio di trasmissione di una stringa di  7 bit mediante RS232:

 

 

 

 

 

 

 

 

 

 

 

Fine dati

 

Inizio dati

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SB        – Bit d'inizio (Start Bit)

D1..D7 – Bit di dati

PB        – Bit di parità (Parity Bit)

TB        – Bit di stop

 

 
 

 

 

 

 

 

 

 

 

 


NOTA: Il computer che riceve è in grado di decodificare sia questo tipo di trasmissione, cioè con livelli di -12 e +12 V, sia una  trasmissione con livelli di tensione +5 e 0 V.

 

 

Routine di ritardo

 

Alla velocità di trasmissione di 1200 bit/s corrisponde un ritardo di 833us; abbiamo progettato una subroutine che genera questo ritardo:

 

 

Casella di testo: rit_833u	movlw		.133	Periodo di 833 usec; sposta 133 decimale 
	movwf		reg	nel registro REG
RIT	clrwdt		Azzera il watchdog timer
	nop		Nessuna operazione
		decfsz		reg	Decrementa REG, salta l'istruzione 
			successiva se vale 0
	goto 	RIT		
	return
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


E’ una routine molto semplice che, in base alla velocità di clock (viene usato un quarzo a 3,2768 MHz), compie alcune operazioni in modo da far trascorrere il tempo desiderato.

Viene caricato nel registro di appoggio REG il valore 133 decimale, che rappresenta il numero di volte che occorre ripetere il ciclo RIT; dopo viene disabilitato il watchdog timer, in modo da non far resettare il sistema; si esegue NOP, cioè nessuna operazione; viene decrementato il registro REG e, se è a zero, salta l’istruzione immediatamente successiva (goto RIT) e quindi ritorna alla routine principale, altrimenti ricomincia il ciclo RIT.

Il numero di ripetizioni necessario è stato calcolato conoscendo il periodo di clock (1 / 3276800 = 0.305 us), il numero di cicli di esecuzione necessari ad ogni operazione     (clrwdt, nop, decfsz => 1 ciclo; goto => 2 cicli), e sapendo che ogni ciclo di esecuzione corrisponde a 4 cicli di clock:

 

833us = Tc x 4 x N°Cicli totali x N°Ripetizioni =>

 

=> N°Ripetizioni = 833 / ( Tc x 4 x N°Cicli totali ) =           833 / ( 0.305 x 10^-6 x 4 x ( 1+1+1+2 ) )

 

=>N°Ripetizioni = 833 / 6.1 = 133 ripetizioni

 

 

In questo modo, se si volesse cambiare la velocità di trasmissione, è sufficiente cambiare il numero di ripetizioni.

 

 

Routine di trasmissione RS232

 

La trasmissione seriale è centrata su un’operazione di shift a destra di un registro (reg_tx), che contiene il dato da trasmettere. Quando si esegue lo shift, al bit 7 del registro viene assegnato il valore del carry, mentre il carry prende il valore del bit 0; ogni volta che viene eseguita questa operazione, viene testato il valore del carry: se è 1 viene trasmesso 1 sul 5° bit della porta A, che rappresenta l’uscita del sistema, altrimenti trasmette 0. Il ciclo viene ripetuto per 8 volte (8 bit), dopo di che il sistema acquisisce e trasmette il dato successivo.

 

 

 

 

 

 

 

 

 

Schema a blocchi della routine di trasmissione:

 

 

Elaborazione alternativa: TXRS
 

 

 

 

 

Bit di start

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Elaborazione predefinita: Ritardo di 833 us
 

 

 

 

 

Bit di stop

 
 

 

 

 

 

Elaborazione predefinita: Ritardo di 833 us
 

 

 

 

 

Elaborazione alternativa: Ritorna
 

 

 

 

 

 

 


Listato della routine di trasmissione:

 

 

Casella di testo: TXRS  		movlw		.8		Definisce il numero di bit da 
	movwf	nbit		trasmettere: nel nostro caso sono 8
       	call 	tx_zero		Bit di start
	call	rit_833u		Attesa 833us

LOOPTX	rrf	reg_tx		Shifta reg_tx a destra
	btfsc	stat,0		Salta se Carry=0
	call    	tx_uno
	btfss	stat,0		Salta se Carry=1
	call    	tx_zero
	call	rit_833u		Attesa 833us
	decfsz	nbit		Decrementa nbit e salta se 0
	goto	LOOPTX	Va a LOOPTX

	call 	tx_uno		Bit di stop
	call	rit_833u		Attesa 833us
	return
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


La figura seguente mostra i collegamenti tra il PIC e l’elettronica della stazione meteorologica.

Al PIC

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


Il PIC riconosce il canale attivo leggendo l’uscita del selettore di canale (pilotato dallo Z80 della stazione meteorologica). I dati in uscita dall’A/D sono solitamente affetti da rumore, per questo vengono processati da una procedura numerica di filtraggio per ridurre l’effetto di eventuali spike. Vengono quindi spediti, senza nessuna ulteriore elaborazione, al PIC che provvede a convertirli per riportarli nel range previsto per la grandezza in esame.

 

 

Routine di filtraggio:

 

L’algoritmo è stato scelto volutamente molto semplice: in pratica si leggono 5 valori consecutivi di una grandezza (con un ritardo tra loro superiore al tempo di conversione dell’A/D) e degli 8 bit si prende il valore che compare più volte nelle 5 letture (tranne ai due meno significativi, che risultano affetti da rumore eccessivo).


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Appendice 1

Il programma nella stazione centrale.


 

'***************************************************************

'* meteo.bas

'*

'* Classe 5^ elettronici - Maggio 2000.

'***************************************************************

'NOTE: 1) Se sono attivi i menu' o la visualizzazione di un

'         grafico storico, non vengono memorizzati i nuovi

'         dati in arrivo dalla seriale

'      2) Non sono stati implementati i grafici su periodi

'         (stagionali, mensili,...).

'      3) Controlla.data() non prende in considerazione

'         tutti i casi di errore.

'      4) Sarebbe opportuno che il PIC spedisse il dato non

'         sull'ultimo digit numerico, ma lo codificasse in

'         BCD e lo mettesse su tutti i digit numerici.

'         Questo permetterebbe una pi— sicura sincronizzazione

'         della ricezione seriale.

'      5) Il posizionamento dei campioni sull'asse X sarebbe

'         opportuno farlo tenendo conto dell'orario.

'         Attualmente è sequenziale.

'---------------------------------------------------------------

 

 

CONST tempo.reale = 1

CONST storico = 2

 

CONST maxtemp = 50

CONST mintemp = -10

 

CONST maxbar = 1100

CONST minbar = 900

 

CONST maxigro = 100

CONST minigro = 0

 

CONST maxvel = 100

CONST minvel = 0

 

 

COMMON SHARED fileerrato

COMMON SHARED nome.file.temp$

COMMON SHARED nome.file.bar$

COMMON SHARED nome.file.igro$

COMMON SHARED nome.file.vel$

COMMON SHARED header.ricevuta$

 

COMMON SHARED num.file.attuale

COMMON SHARED num.file.temp

COMMON SHARED num.file.igro

COMMON SHARED num.file.vel

COMMON SHARED num.file.bar

 

 

COMMON SHARED delta.timer   'intervallo di memorizzazione tra campioni.

                            'espresso in secondi.

 

delta.timer = 280

 

 

 

 

 

COM(1) ON     'Attiva la gestione degli eventi che interessano la porta 1.

ON COM(1) GOSUB ricevi.seriale

 

flag.arriva.stringa = 0     'E' settato a 1 dall'interrupt della seriale.

 

 

'-----------------------------------------------------------------

' Setto la pagina grafica SCREEN 12

'max_x = 639

'max_y = 479

'-----------------------------------------------------------------

SCREEN 12

 

'-----------------------------------------------------------------

' Numeri files: 100 --> seriale

'               200 --> file attivo in modo reale

'               201 --> file storico temperatura

'               202 --> file storico umidità

'               203 --> file storico velocità

'               204 --> file storico pressione

'-----------------------------------------------------------------

num.file.ser = 100

num.file.attuale = 200

num.file.temp = 201

num.file.igro = 202

num.file.vel = 203

num.file.bar = 204

 

'------------------------------------------------

' Main-program

'------------------------------------------------

 

 

 

CALL apri.seriale(num.file.ser)

 

fun.attuale = 1       'parto con tutti i grafici

CALL genera.quadro(fun.attuale)

modo = tempo.reale

 

old.giorno$ = ""

 

DO

    giorno$ = MID$(DATE$, 4, 2)

    '-------------------------------------------------------

    ' Se cambia il giorno, genero i nuovi files e riparto

    ' con tutti i grafici

    '-------------------------------------------------------

    IF (giorno$ <> old.giorno$) THEN

        COM(1) OFF

        old.giorno$ = giorno$

        CALL controlla.file(nome.file.bar$, "#P")

        CALL controlla.file(nome.file.temp$, "#T")

        CALL controlla.file(nome.file.igro$, "#I")

        CALL controlla.file(nome.file.vel$, "#V")

        fun.attuale = 1       'parto con tutti i grafici

        CALL genera.quadro(fun.attuale)

        CALL chiudi.seriale(num.file.ser)

        CALL apri.seriale(num.file.ser)

        COM(1) ON

    END IF

 

    IF (modo = tempo.reale) THEN

        IF (flag.arriva.stringa <> 0) THEN

            '-------------------------------------------------

            ' L'interrupt della seriale ha rilevato una

            ' stringa in arrivo.

            '-------------------------------------------------

            flag.arriva.stringa = 0

            COM(1) OFF              'Disabilito l'interrupt seriale

          

            h$ = ricevi.stringa$(num.file.ser, valore$)

          

            v = decodifica.valore(h$, valore$)

           

            '---------------------------------------------

            ' traccio i grafici

            '---------------------------------------------

            CALL grafica.punto(h$, v, fun.attuale)

            COM(1) ON

        END IF

    END IF

  

    tasto$ = INKEY$

    IF (tasto$ = "m") OR (tasto$ = "M") THEN

        COM(1) OFF

        CALL chiudi.seriale(num.file.ser)

        CALL gestione.menu.principale(num.file.seriale, fun.attuale)

        CALL apri.seriale(num.file.ser)

        COM(1) ON

    END IF

 

    '---------------------------------------------

    ' Stampa di data e ora.

    '---------------------------------------------

    IF (TIME$ <> old.time$) THEN

        LOCATE 30, 1

        PRINT DATE$; " - "; TIME$;

        old.time$ = TIME$

    END IF

 

LOOP UNTIL tasto$ = CHR$(27)

 

CALL chiudi.seriale(num.file.ser)

 

 

 

END

 

 

 

 

 

'============================================================

' Gestione interrupt vari.

'============================================================

errore.seriale:

    CALL chiudi.seriale(num.file.ser)

    CALL apri.seriale(num.file.ser)

    RESUME NEXT

 

'-----------------------------------------

' Gestione errori apertura files

'-----------------------------------------

errorefile:

    fileerrato = 1

    RESUME NEXT

 

'-----------------------------------------

' Interrupt seriale

'-----------------------------------------

ricevi.seriale:

    flag.arriva.stringa = 1

    RETURN

 

 

‘*****************************************************************

‘*****************************************************************

‘* Definizione routines.

‘*****************************************************************

‘*****************************************************************

 

 

SUB apri.seriale (num.file)

'====================================================================

' Apertura del canale seriale: 1200 b/sec, 8 bit, no parity, 1 stop

'====================================================================

 

    OPEN "com1:1200,n,8,1,cd0,cs0" FOR INPUT AS num.file

 

END SUB

 

FUNCTION cerca.dollaro (a$)

'=================================================================

' Cerca la posizione del carattere "$" nella stringa di ingresso

' Se la trova rende la posizione, altrimenti rende 0

'=================================================================

        trovato = 0

        FOR i = 1 TO LEN(a$)

            IF (MID$(a$, i, 1) = "$") THEN

                trovato = 1

                EXIT FOR

            END IF

        NEXT

      

        IF (trovato = 1) THEN

            cerca.dollaro = i

        ELSE

            cerca.dollaro = 0

        END IF

 

END FUNCTION

 

SUB chiudi.seriale (num.file)

'==================================================================

' Chiude il canale seriale.

'==================================================================

 

        CLOSE num.file

 

END SUB

 

FUNCTION controlla.data (giorno$, mese$, anno$)

'================================================================

' Verifica se una data Š giusta.

' Rende 1 se ok, 0 se no.

'================================================================

    IF (LEN(giorno$) > 2) THEN

        controlla.data = 0

        EXIT FUNCTION

    END IF

 

    IF (LEN(giorno$) < 2) THEN

        giorno$ = "0" + giorno$

    END IF

 

  

    IF (LEN(mese$) > 2) THEN

        controlla.data = 0

        EXIT FUNCTION

    END IF

 

    IF (LEN(mese$) < 2) THEN

        mese$ = "0" + mese$

    END IF

 

    IF (LEN(anno$) > 2) THEN

        controlla.data = 0

        EXIT FUNCTION

    END IF

 

    IF (LEN(anno$) < 2) THEN

        anno$ = "0" + anno$

    END IF

 

 

    IF (VAL(giorno$) < 1) OR (VAL(giorno$) > 31) THEN

        controlla.data = 0

        EXIT FUNCTION

    END IF

 

    IF (VAL(mese$) < 1) OR (VAL(mese$) > 12) THEN

        controlla.data = 0

        EXIT FUNCTION

    END IF

 

    IF (VAL(anno$) < 0) THEN

        controlla.data = 0

        EXIT FUNCTION

    END IF

  

    controlla.data = 1

 

END FUNCTION

 

SUB controlla.file (nomefile$, tipo$)

'=============================================================

' Controllo se esiste il file con la data di oggi.

' Se esiste, ok, se no lo creo.

' Tipo$: #B, #I, #T, #V

'=============================================================

     SHARED fileerrato

  

     a$ = DATE$

     mese$ = MID$(a$, 1, 2)

     giorno$ = MID$(a$, 4, 2)

     anno$ = MID$(a$, 9, 2)

 

     nomefile$ = genera.nome.file(tipo$, giorno$, mese$, anno$)

     

     ON ERROR GOTO errorefile

     fileerrato = 0

     OPEN nomefile$ FOR INPUT AS 1

     CLOSE 1

  

     '-----------------------------------------------------------------

     ' Se il flag FILEERRATO vale 1 vuol dire che il file non esiste,

     ' quindi lo creo.

     '-----------------------------------------------------------------

     IF (fileerrato = 1) THEN

          OPEN nomefile$ FOR OUTPUT AS 1

     END IF

 

END SUB

 

SUB conv.x.y.bar (x, y)

'=====================================================================

' Traslazione del grafico della pressione atmosferica.

'=====================================================================

     y = -y + 480

 

END SUB

 

 

 

 

SUB conv.x.y.bar.mono (count.x, valore)

'======================================================================

' Traslazione del grafico della pressione atmosferica

' nel grafico singolo.

'====================================================================== 

    y = valore

    y = y * (480 / (maxbar - minbar))

    y = -y + 480

    valore = y

 

END SUB

 

SUB conv.x.y.igro (x, y)

'=======================================================

' Traslazione del grafico dell'umidità atmosferica.

'=======================================================  

    y = -y + 240

  

END SUB

 

SUB conv.x.y.igro.mono (count.x, valore)

'==================================================================

' Traslazione del grafico dell'umidità nel grafico singolo.

'==================================================================

    y = valore

    y = (y * (480 / (maxigro - minigro)))

    y = -y + 480

    valore = y

 

END SUB

 

SUB conv.x.y.temp (x, y)

'==================================================================

' Traslazione del grafico della temperatura nel grafico multiplo.

'==================================================================

    y = -y + 120

  

END SUB

 

SUB conv.x.y.temp.mono (count.x, valore)

'==================================================================

' Traslazione del grafico della temperatura nel grafico singolo.

'==================================================================

    y = valore

    y = y - mintemp

    y = y * (480 / (maxtemp - mintemp))

    y = -y + 480

    valore = y

 

END SUB

 

SUB conv.x.y.vel (x, y)

'==================================================================

' Traslazione del grafico della velocità del vento.

'==================================================================

    y = -y + 480

 

END SUB

 

SUB conv.x.y.vel.mono (count.x, valore)

'==========================================================================

' Traslazione del grafico della velocità del vento nel grafico singolo.

'==========================================================================

    y = valore

    y = y * (480 / (maxvel - minvel))

    y = -y + 480

    valore = y

 

END SUB

 

 

 

 

 

 

 

 

FUNCTION decodifica.valore (h$, valore$)

'================================================================

' H$: T, B, V, I - Indica che grandezza stiamo convertendo

'===============================================================

    r$ = MID$(valore$, 5, 1)

    a = ASC(r$)

 

    IF (h$ = "T") THEN

        x = ((60 * a) / 255) - 9

    ELSEIF (h$ = "V") THEN

        x = (100 * a) / 255

    ELSEIF (h$ = "U") THEN

        x = (100 * a) / 255

    ELSEIF (h$ = "P") THEN

        x = (200 * a) / 255 + 900

    END IF

  

    decodifica.valore = x

 

END FUNCTION

 

SUB del.quadro.bar (fun.attuale)

'====================================================================

' Cancello il rettangolo di video relativo al grafico della

' pressione nel modo grafici tutti.

'====================================================================

    VIEW (321, 241)-(639, 479)

    CLS 1

    VIEW (0, 0)-(639, 479)

  

    CALL genera.quadro(fun.attuale)

 

END SUB

 

SUB del.quadro.igro (fun.attuale)

'====================================================================

' Cancello il rettangolo di video relativo al grafico della

' umidit… nel modo grafici tutti.

'====================================================================

    VIEW (321, 0)-(639, 239)

    CLS 1

    VIEW (0, 0)-(639, 479)

 

    CALL genera.quadro(fun.attuale)

 

END SUB

 

SUB del.quadro.temp (fun.attuale)

'====================================================================

' Cancello il rettangolo di video relativo al grafico della

' temperatura nel modo grafici tutti.

'====================================================================

    VIEW (0, 0)-(319, 239)

    CLS 1

    VIEW (0, 0)-(639, 479)

  

    CALL genera.quadro(fun.attuale)

 

END SUB

 

SUB del.quadro.vel (fun.attuale)

'====================================================================

' Cancello il rettangolo di video relativo al grafico della

' velocit… nel modo grafici tutti.

'====================================================================

    VIEW (0, 241)-(319, 479)

    CLS 1

    VIEW (0, 0)-(639, 479)

  

    CALL genera.quadro(fun.attuale)

 

END SUB

 

 

 

 

 

 

FUNCTION genera.nome.file$ (h$, giorno$, mese$, anno$)

'=================================================================

' Genera il nome del file.

'=================================================================

     genera.nome.file$ = h$ + giorno$ + mese$ + anno$

 

END FUNCTION

 

SUB genera.quadro (fun.attuale)

'========================================================================

' Disegna il quadro iniziale

'========================================================================

    IF (fun.attuale = 1) THEN

        CALL quadro.tutti

    ELSEIF (fun.attuale = 2) THEN

        CALL quadro.igro

    ELSEIF (fun.attuale = 3) THEN

        CALL quadro.temp

    ELSEIF (fun.attuale = 4) THEN

        CALL quadro.bar

    ELSEIF (fun.attuale = 5) THEN

        CALL quadro.vel

    END IF

 

END SUB

 

SUB gestione.menu.principale (num.file.seriale, fun.attuale)

'=================================================================

' Gestione del menu' principale lanciato dal main program

' con la pressione di "M"

'=================================================================

    SHARED nome.file.temp$

    SHARED nome.file.bar$

    SHARED nome.file.igro$

    SHARED nome.file.vel$

 

    CALL chiudi.seriale(num.file.ser)

         

gestione2:

    '------------------------------------

    'MENU delle opzioni disponibili

    '------------------------------------

    fun.attuale = menu.principale

          

    IF (fun.attuale <> 6) THEN

        '------------------------------------------------

        ' Ha scelto un grafico in tempo reale.

        '------------------------------------------------

        CALL genera.quadro(fun.attuale)

        CALL rileggi.dati.da.file(fun.attuale)

        CALL apri.seriale(num.file.ser)

    ELSE

        '------------------------------

        ' Ha scelto STATISTICHE

        '------------------------------

        tipo.statistica = scegli.tipo.statistica(giorno$, mese$, anno$,          inizio$, fine$)

        IF (tipo.statistica = 0) THEN

            '--------------------------------------------

            ' Annullata funzione statistiche

            '--------------------------------------------

            fun.attuale = 1

            CALL genera.quadro(fun.attuale)

            CALL rileggi.dati.da.file(fun.attuale)

            CALL apri.seriale(num.file.ser)

        ELSEIF (tipo.statistica = 1) THEN

            '--------------------------------------------

            ' Grafico di un certo giorno: Genero i nomi

            ' dei files con la data vecchia.

            '--------------------------------------------

            fun.attuale = 1     'Tutti i grafici

            CALL genera.quadro(fun.attuale)

            nome.file.bar$ = genera.nome.file("#B", giorno$, mese$, anno$)

            nome.file.temp$ = genera.nome.file("#T", giorno$, mese$, anno$)

            nome.file.igro$ = genera.nome.file("#I", giorno$, mese$, anno$)

            nome.file.vel$ = genera.nome.file("#V", giorno$, mese$, anno$)

          

       

            '--------------------------------------------

            ' Tracciamento del grafico.

            '--------------------------------------------

            CALL rileggi.dati.da.file(fun.attuale)

      

            '--------------------------------------------

            ' Rigenero i file con la data di oggi.

            '--------------------------------------------

            CALL controlla.file(nome.file.bar$, "#P")

            CALL controlla.file(nome.file.temp$, "#T")

            CALL controlla.file(nome.file.igro$, "#I")

            CALL controlla.file(nome.file.vel$, "#V")

          

            LOCATE 30, 1

            PRINT "Grafici del giorno "; giorno$; "-"; mese$; "-"; anno$;

            LOCATE 30, 58

            PRINT "Premi un tasto...     ";

          

            '-----------------------------------

            ' Vuoto il buffer della tastiera

            '-----------------------------------

            DO

            LOOP WHILE INKEY$ <> ""

          

            '-----------------------------------

            ' Aspetto un tasto

            '-----------------------------------

            DO

            LOOP WHILE INKEY$ = ""

          

            GOTO gestione2

        ELSEIF (tipo.statistica = 2) THEN

            '--------------------------------------------

            ' Grafico di un certo periodo

            '--------------------------------------------

            '

            ' Non implementata

        END IF

      END IF

 

   END SUB

 

SUB gra.bar (valore, modo$)

'=======================================================================

' Disegna i grafici della pressione ricevuta.(Grafico singolo)

' Modo$: "p" --> disegna punto

'        "v" --> scrive valore, non disegna punto

'        "i" --> inizializza

'=======================================================================

    STATIC count.x

    IF (modo$ = "i") THEN

        count.x = 0

        EXIT SUB

    END IF

 

    LOCATE 2, 2

    PRINT ; USING "####"; valore

    IF (modo$ = "p") THEN

      

        '----------------------------------------------------

        ' Si tracciano due punti per omologare con i grafici

        ' tutti che hanno 320 punti.

        '----------------------------------------------------

        FOR i = 0 TO 1

            count.x = count.x + 1

            IF (count.x > 639) THEN

                count.x = 1

            END IF

            valore = valore - 900

            CALL conv.x.y.bar.mono(count.x, valore)

            colore = 15

            PSET (count.x, valore), colore

        NEXT

    END IF

 

   END SUB

 

 

 

SUB gra.bar.due (valore, modo$)

'=======================================================================

' Disegna i grafici della pressione ricevuta.(In mod.GRAFICI TUTTI)

' Modo$: "p" --> disegna punto

'        "v" --> scrive valore, non disegna punto

'        "i" --> inizializza

'=======================================================================

    STATIC count.x

 

    IF (modo$ = "i") THEN

        count.x = 0

        EXIT SUB

    END IF

 

    LOCATE 17, 76

    PRINT ; USING "####"; valore;

 

    IF (modo$ = "p") THEN

        IF (count.x < 320) THEN count.x = 320

        count.x = count.x + 1

        IF (count.x > 639) THEN

            count.x = 1

        END IF

        valore = valore - 900

        valore = valore / 2

        CALL conv.x.y.bar(count.x, valore)

        PSET (count.x, valore), 15

    END IF

 

END SUB

 

SUB gra.igro (valore, modo$)

'=======================================================================

' Disegna i grafici sull'umidit… ricevuta.(Grafico singolo)

' Modo$: "p" --> disegna punto

'        "v" --> scrive valore, non disegna punto

'        "i" --> inizializza

'=======================================================================

    STATIC count.x

 

    IF (modo$ = "i") THEN

        count.x = 0

        EXIT SUB

    END IF

 

    LOCATE 2, 2

    PRINT ; USING "###.#"; valore

  

    IF (modo$ = "p") THEN

        '----------------------------------------------------

        ' Si tracciano due punti per omologare con i grafici

        ' tutti che hanno 320 punti.

        '----------------------------------------------------

        FOR i = 0 TO 1

            count.x = count.x + 1

            IF (count.x > 639) THEN

                count.x = 1

            END IF

            CALL conv.x.y.igro.mono(count.x, valore)

            colore = 2

            PSET (count.x, valore), colore

        NEXT

    END IF

 

END SUB

 

 

 

 

 

 

 

 

 

 

 

 

SUB gra.igro.due (valore, modo$)

'=======================================================================

' Disegna i grafici sull'umidit… ricevuta.(In mod.GRAFICI TUTTI)

' Modo$: "p" --> disegna punto

'        "v" --> scrive valore, non disegna punto

'        "i" --> inizializza

'=======================================================================

    STATIC count.x

 

    IF (modo$ = "i") THEN

        count.x = 0

        EXIT SUB

    END IF

 

    LOCATE 2, 76

    PRINT ; USING "###"; valore;

  

    IF (modo$ = "p") THEN

        IF (count.x < 320) THEN count.x = 320

        count.x = count.x + 1

        IF (count.x > 639) THEN

            count.x = 320

            CALL del.quadro.igro(fun.attuale)

        END IF

        CALL conv.x.y.igro(count.x, valore)

        colore = 2

        PSET (count.x, valore), colore

    END IF

 

END SUB

 

SUB gra.temp (valore, modo$)

'=======================================================================

' Disegna i grafici della temperatura ricevuta.(Grafico singolo)

' Modo$: "p" --> disegna punto

'        "v" --> scrive valore, non disegna punto

'        "i" --> inizializza

'=======================================================================

    STATIC count.x

 

    IF (modo$ = "i") THEN

        count.x = 0

        EXIT SUB

    END IF

 

    LOCATE 2, 2

    PRINT ; USING "###.#"; valore

 

    IF (valore < 0) THEN

        colore = 9

    ELSE

        colore = 4

    END IF

 

    IF (modo$ = "p") THEN

        '----------------------------------------------------

        ' Si tracciano due punti per omologare con i grafici

        ' tutti che hanno 320 punti.

        '----------------------------------------------------

        FOR i = 0 TO 1

            count.x = count.x + 1

            IF (count.x > 639) THEN

                count.x = 1

            END IF

            CALL conv.x.y.temp.mono(count.x, valore)

            PSET (count.x, valore), colore

        NEXT

    END IF

 

END SUB

 

 

 

 

 

 

 

 

SUB gra.temp.due (valore, modo$)

'=======================================================================

' Disegna i grafici della temperatura ricevuta.(In mod.GRAFICI TUTTI)

' Modo$: "p" --> disegna punto

'        "v" --> scrive valore, non disegna punto

'        "i" --> inizializza

'=======================================================================

    STATIC count.x

 

    IF (modo$ = "i") THEN

        count.x = 0

        EXIT SUB

    END IF

 

    LOCATE 2, 35

    PRINT ; USING "###.#"; valore;

 

    IF (valore < 0) THEN

        colore = 9

    ELSE

        colore = 4

    END IF

 

    IF (modo$ = "p") THEN

        count.x = count.x + 1

        IF (count.x > 320) THEN

            count.x = 1

            CALL del.quadro.temp(fun.attuale)

        END IF

          

        CALL conv.x.y.temp(count.x, valore)

 

        PSET (count.x, valore), colore

    END IF

 

END SUB

 

SUB gra.vel (valore, modo$)

'=======================================================================

' Disegna i grafici della velocita' ricevuta

' Modo$: "p" --> disegna punto

'        "v" --> scrive valore, non disegna punto

'        "i" --> inizializza

'=======================================================================

    STATIC count.x

 

    IF (modo$ = "i") THEN

        count.x = 0

        EXIT SUB

    END IF

 

    LOCATE 2, 2

    PRINT ; USING "###"; valore;

  

    IF (modo$ = "p") THEN

        '----------------------------------------------------

        ' Si tracciano due punti per omologare con i grafici

        ' tutti che hanno 320 punti.

        '----------------------------------------------------

        FOR i = 0 TO 1

            count.x = count.x + 1

            IF (count.x > 639) THEN

                count.x = 1

            END IF

            CALL conv.x.y.vel.mono(count.x, valore)

            colore = 3

            PSET (count.x, valore), colore

        NEXT

    END IF

 

 

END SUB

 

 

 

 

 

 

SUB gra.vel.due (valore, modo$)

'=======================================================================

' Disegna i grafici della velocit… ricevuta.(In mod.GRAFICI TUTTI)

' Modo$: "p" --> disegna punto

'        "v" --> scrive valore, non disegna punto

'        "i" --> inizializza

'=======================================================================

    STATIC count.x

 

    IF (modo$ = "i") THEN

        count.x = 0

        EXIT SUB

    END IF

 

    LOCATE 17, 37

    PRINT ; USING "###"; valore;

 

    IF (modo$ = "p") THEN

        count.x = count.x + 1

        IF (count.x > 320) THEN

            count.x = 1

            CALL del.quadro.vel(fun.attuale)

        END IF

        CALL conv.x.y.vel(count.x, valore)

        PSET (count.x, valore), 3

    END IF

 

END SUB

 

SUB grafica.punto (h$, v, fun.attuale)

'==========================================================

' Mette nel grafico opportuno il punto di valore V.

'==========================================================

    SHARED delta.timer

  

    STATIC old.timer.t

    STATIC old.timer.v

    STATIC old.timer.p

    STATIC old.timer.u

    STATIC old.giorno$

   

    giorno$ = MID$(DATE$, 4, 2)

    '-------------------------------------------------------

    ' Se cambia il giorno, azzero il timer

    '-------------------------------------------------------

    IF (giorno$ <> old.giorno$) THEN

        old.timer.t = 0

        old.timer.v = 0

        old.timer.p = 0

        old.timer.u = 0

        old.giorno$ = giorno$

    END IF

 

    '-----------------------------------------------------------------------

    ' Se sono passati pi— di delta.timer secondi, traccio il

    ' punto (modo$ = "p"), altrimenti, scrivo solo il valore  (modo$ = "v")

    '-----------------------------------------------------------------------

    IF (h$ = "T") THEN

        IF (TIMER - old.timer.t) > delta.timer THEN

            old.timer.t = TIMER

            modo$ = "p"

        ELSE

            modo$ = "v"

        END IF

    END IF

 

    IF (h$ = "V") THEN

        IF (TIMER - old.timer.v) > delta.timer THEN

            old.timer.v = TIMER

            modo$ = "p"

        ELSE

            modo$ = "v"

        END IF

    END IF

 

   

 

   

    IF (h$ = "U") THEN

        IF (TIMER - old.timer.u) > delta.timer THEN

            old.timer.u = TIMER

            modo$ = "p"

        ELSE

            modo$ = "v"

        END IF

    END IF

 

    IF (h$ = "P") THEN

        IF (TIMER - old.timer.p) > delta.timer THEN

            old.timer.p = TIMER

            modo$ = "p"

        ELSE

            modo$ = "v"

        END IF

    END IF

 

  

    '---------------------------------------------------------------------

    ' Selezione del grafico da fare

    '---------------------------------------------------------------------

    IF (fun.attuale = 1) THEN

        IF (h$ = "T") THEN

            CALL gra.temp.due(v, modo$)

        ELSEIF (h$ = "V") THEN

            CALL gra.vel.due(v, modo$)

        ELSEIF (h$ = "U") THEN

            CALL gra.igro.due(v, modo$)

        ELSEIF (h$ = "P") THEN

            CALL gra.bar.due(v, modo$)

        END IF

    ELSEIF (fun.attuale = 2) THEN

        IF (h$ = "U") THEN CALL gra.igro(v, modo$)

    ELSEIF (fun.attuale = 3) THEN

        IF (h$ = "T") THEN CALL gra.temp(v, modo$)

    ELSEIF (fun.attuale = 4) THEN

        IF (h$ = "P") THEN CALL gra.bar(v, modo$)

    ELSEIF (fun.attuale = 5) THEN

        IF (h$ = "V") THEN CALL gra.vel(v, modo$)

    END IF

 

END SUB

 

SUB memorizza (stringa$, tipo$)

'================================================================

' Memorizzo su disco la stringa della pressione.

' Si salva un campione ogni delta.timer secondi.

' Tipo$ = "P", "V", "T", "I"

'================================================================

 

    SHARED nome.file.bar$

    SHARED nome.file.temp$

    SHARED nome.file.igro$

    SHARED nome.file.vel$

    SHARED delta.timer

    SHARED num.file.attuale

 

    STATIC old.timer.t

    STATIC old.timer.p

    STATIC old.timer.v

    STATIC old.timer.u

  

    STATIC old.giorno$

  

 

 

    giorno$ = MID$(DATE$, 4, 2)

    '-------------------------------------------------------

    ' Se cambia il giorno, azzero il timer

    '-------------------------------------------------------

    IF (giorno$ <> old.giorno$) THEN

        old.timer.t = 0

        old.timer.p = 0

        old.timer.v = 0

        old.timer.u = 0

        old.giorno$ = giorno$

    END IF

 

    SELECT CASE tipo$

        CASE "T": nome.file$ = nome.file.temp$

                  old.timer = old.timer.t

        CASE "V": nome.file$ = nome.file.vel$

                  old.timer = old.timer.v

        CASE "P": nome.file$ = nome.file.bar$

                  old.timer = old.timer.p

        CASE "U": nome.file$ = nome.file.igro$

                  old.timer = old.timer.u

        CASE ELSE: EXIT SUB

    END SELECT

 

 

    IF (TIMER - old.timer) >= delta.timer THEN

        OPEN nome.file$ FOR APPEND AS num.file.attuale

        d$ = LEFT$(DATE$, 10)

        t$ = LEFT$(TIME$, 8)

        '----------------------------------------------

        ' Cerco "$" in stringa$, poi prendo come

        ' caratteri buoni gli 8 seguenti.

        '----------------------------------------------

        FOR i = 1 TO LEN(stringa$)

            IF (MID$(stringa$, i, 1) = "$") THEN

                inizio = i

                fine = i + 7

                IF (fine > LEN(stringa$)) THEN

                    '------------------------------------

                    ' La stringa non e' abbastanza lunga

                    '------------------------------------

                    CLOSE num.file.attuale

EXIT SUB

                END IF

            END IF

        NEXT

      

        SELECT CASE tipo$

            CASE "T": nome.file$ = nome.file.temp$

                      old.timer.t = TIMER

            CASE "V": nome.file$ = nome.file.vel$

                      old.timer.v = TIMER

            CASE "P": nome.file$ = nome.file.bar$

                      old.timer.p = TIMER

            CASE "U": nome.file$ = nome.file.igro$

                      old.timer.u = TIMER

            CASE ELSE: EXIT SUB

        END SELECT

      

        ss$ = d$ + t$ + stringa$

        PRINT #num.file.attuale, ss$

        CLOSE num.file.attuale

    END IF

 

END SUB

 

FUNCTION menu.principale

'=================================================================

' Gestione del menu' principale lanciato dal main program

' con la pressione di "M"

' Rende la funzione scelta dall'utente

'=================================================================

   

    CLS

 

    PRINT "Scegli: 1 --> Tutti i grafici"

    PRINT "        2 --> Grafico della umidit…"

    PRINT "        3 --> Grafico della temperatura"

    PRINT "        4 --> Grafico della pressione atmosferica"

    PRINT "        5 --> Grafico della velocit… del vento"

    PRINT "        6 --> Statistiche"

 

    DO

        DO

            a$ = INKEY$

            scelta = VAL(a$)

        LOOP UNTIL scelta > 0

    LOOP WHILE scelta < 1 OR scelta > 6

 

    menu.principale = scelta

    CLS

 

END FUNCTION

 

SUB quadro.bar

'==================================================================

' Disegna il quadro del grafico singolo della pressione.

'==================================================================

   

    CLS

 

    '-----------------------------------------

    'Inizializzo i contatori

    '-----------------------------------------

    CALL gra.bar(0, "i")

 

    LINE (0, 639)-(0, 0)

    'LINE (0, 240)-(639, 240)

    LINE (639, 0)-(639, 479)

    LINE (0, 479)-(639, 479)

    LINE (639, 0)-(0, 0)

 

    LOCATE 3, 26

    PRINT "Pressione (Da 900 a 1100 bar)"

    LOCATE 1, 36: PRINT "Pmax"

 

    LOCATE 30, 58

    PRINT "M = menu' - ESC = fine";

 

END SUB

 

 

 

 

 

SUB quadro.igro

'==================================================================

' Disegna il quadro del grafico singolo della umidità atmosferica.

'==================================================================

   

    CLS

 

    '-----------------------------------------

    'Inizializzo i contatori

    '-----------------------------------------

    CALL gra.igro(0, "i")

 

    LINE (0, 639)-(0, 0), 2

    'LINE (0, 240)-(639, 240)

    LINE (639, 0)-(639, 479), 2

    LINE (0, 479)-(639, 479), 2

    LINE (639, 0)-(0, 0), 2

 

    LOCATE 3, 28

    PRINT "Umidit… (Da 0 a 100%)"

    LOCATE 1, 36: PRINT "Umax"

 

    LOCATE 30, 58

    PRINT "M = menu' - ESC = fine";

 

END SUB

 

SUB quadro.temp

'==================================================================

' Disegna il quadro del grafico singolo della temperatura.

'==================================================================

   

    CLS

   

    '-----------------------------------------

    'Inizializzo i contatori

    '-----------------------------------------

    CALL gra.temp(0, "i")

 

    d = maxtemp - mintemp

    d = ABS(mintemp) * 480 / d

    d = 480 - d

  

    LINE (0, d)-(639, d)

  

    LINE (639, 0)-(639, d), 4

    LINE (0, 0)-(0, d), 4

  

    LINE (639, d)-(639, 479), 9

    LINE (0, d)-(0, 479), 9

  

    LOCATE 3, 28

    PRINT "Temperatura (Da -10ø a +50ø)";

    LOCATE 1, 36: PRINT "Tmax";

    LOCATE 30, 40: PRINT "Tmin";

  

    LINE (1, 479)-(639, 479), 9, , &HF0F0

    LINE (1, 1)-(639, 1), 4, , &HF0F0

 

    LOCATE 30, 58

    PRINT "M = menu' - ESC = fine";

 

END SUB

 

 

 

 

 

 

 

 

 

 

 

 

SUB quadro.tutti

'==============================================================

' Disegna i il quadro per tutti i grafici contemporaneamente

'==============================================================

   

    CLS

 

    '-----------------------------------------

    'Inizializzo i contatori

    '-----------------------------------------

    CALL gra.bar.due(valore, "i")

    CALL gra.temp.due(valore, "i")

    CALL gra.vel.due(valore, "i")

    CALL gra.igro.due(valore, "i")

 

    '-----------------------------------------

    ' Disegno il quadro

    '-----------------------------------------

    LINE (0, 120)-(320, 120)

    LINE (0, 240)-(639, 240)

    LINE (320, 0)-(320, 479)

    LINE (0, 479)-(0, 0)

    LINE (0, 0)-(639, 0)

    LINE (639, 0)-(639, 479)

    LINE (0, 479)-(639, 479)

    LINE (0, 150)-(320, 150), 9, , &HF0F0

    LINE (0, 60)-(320, 60), 4, , &HF0F0

    LINE (320, 138)-(639, 138), 2, , &HF0F0

    LINE (320, 330)-(639, 330), 15, , &HF0F0

    LINE (0, 378)-(320, 378), 3, , &HF0F0

 

    LOCATE 17, 1.5

    PRINT "Velocit… (Da 0 a 100 Km/h)"

    LOCATE 24, 16: PRINT "Vmax"

 

    LOCATE 17, 42

    PRINT "Pressione (Da 900 a 1100 bar)"

    LOCATE 21, 55: PRINT "Pmax"

 

    LOCATE 1.5, 42

    PRINT "Umidit… (Da 0 a 100%)"

    LOCATE 9, 55: PRINT "Umax"

    LOCATE 1.5, 1.5

    PRINT "Temperatura (Da -10ø a +50ø)"

    LOCATE 3.5, 18: PRINT "Tmax"

    LOCATE 10.5, 23: PRINT "Tmin"

    LOCATE 30, 58

    PRINT "M = menu' - ESC = fine";

 

END SUB

 

SUB quadro.vel

'==================================================================

' Disegna il quadro del grafico singolo della velocit….

'==================================================================

 

    CLS

 

    '-----------------------------------------

    'Inizializzo i contatori

    '-----------------------------------------

    CALL gra.vel(0, "i")

 

    LINE (0, 639)-(0, 0), 3

    LINE (639, 0)-(639, 479), 3

    LINE (0, 479)-(639, 479), 3

    LINE (639, 0)-(0, 0), 3

 

    LOCATE 3, 26

    PRINT "Velocit… (Da 0 a 100 Km/h)"

    LOCATE 1, 34: PRINT "Vmax"

 

    LOCATE 30, 58

    PRINT "M = menu' - ESC = fine";

 

END SUB

 

 

 

 

 

FUNCTION ricevi.stringa$ (num.file.seriale, valore.trovato$)

'==================================================================

' Riceve la stringa dalla seriale, e rende l'intestazione della

' stessa, se la stringa e' lunga abbastanza.(8 char)

' Provvede a memorizzare su file le grandezze ricevute.

'

' Rende uno dei seguenti caratteri: "T", "P", "U", "V"

' In VALORE.TROVATO$ mette il valore della grandezza ricevuta.

'==================================================================

 

    ON ERROR GOTO errore.seriale

 

    stringa$ = ""

    ok = 0

    DO

        vt$ = INPUT$(9, #num.file.seriale)

        'LINE INPUT #num.file.seriale, vt$

        stringa$ = stringa$ + vt$

        pos.dollaro = cerca.dollaro(stringa$)

        len.stringa = LEN(stringa$)

       

        IF (len.stringa - pos.dollaro >= 7) THEN

 

            IF (MID$(stringa$, pos.dollaro + 1, 1) = "P") THEN

                ricevi.stringa$ = "P"

                valore.trovato$ = MID$(stringa$, pos.dollaro + 2, 5)

                ok = 1

                CALL memorizza(stringa$, "P")

            ELSEIF (MID$(stringa$, pos.dollaro + 1, 1) = "T") THEN

                ricevi.stringa$ = "T"

                valore.trovato$ = MID$(stringa$, pos.dollaro + 2, 5)

                ok = 1

                CALL memorizza(stringa$, "T")

            ELSEIF (MID$(stringa$, pos.dollaro + 1, 1) = "U") THEN

                ricevi.stringa$ = "U"

                valore.trovato$ = MID$(stringa$, pos.dollaro + 2, 5)

                ok = 1

                CALL memorizza(stringa$, "U")

            ELSEIF (MID$(stringa$, pos.dollaro + 1, 1) = "V") THEN

                ricevi.stringa$ = "V"

                valore.trovato$ = MID$(stringa$, pos.dollaro + 2, 5)

                ok = 1

                CALL memorizza(stringa$, "V")

            END IF

        END IF

    LOOP UNTIL (ok = 1)

 

END FUNCTION

 

FUNCTION ricevi.stringa.da.file$ (num.file, valore$)

'===================================================================

' Legge la prossima riga del file numero NUM.FILE

' Se il file e' finito, rende ""

'===================================================================

  

    IF (EOF(num.file)) THEN

        ricevi.stringa.da.file$ = ""

        EXIT FUNCTION

    END IF

 

ancora2:

    trovato = 0

    DO

        car$ = INPUT$(1, #num.file)

        a$ = a$ + car$

        IF (car$ = "#") THEN

         

 

 

 

 

 

 

 

 

            '--------------------------------------------

            ' carico CR & LF

            '--------------------------------------------

            car$ = INPUT$(1, #num.file)

            a$ = a$ + car$

            car$ = INPUT$(1, #num.file)

            a$ = a$ + car$

 

            fine = LEN(a$)

            inizio = fine - 29 + 1

            IF (inizio < 1) THEN GOTO ancora2

          

            a$ = MID$(a$, inizio, 29)

            trovato = 1

            EXIT DO

        END IF

    LOOP UNTIL EOF(num.file)

 

    ricevi.stringa.da.file$ = ""

    IF (trovato > 0) THEN

        h$ = MID$(a$, 21, 1)'Rendo la lettera '20

        valore$ = MID$(a$, 22, 5) 'stringa,start,len 'Rendo il valore (21)

    END IF

 

    ricevi.stringa.da.file$ = h$

END FUNCTION

 

SUB rileggi.dati.da.file (fun.attuale)

'=================================================================

' Rilegge i dati dal/dai file di oggi e li mostra sul grafico

' che e' attualmente visualizzato.

'=================================================================

 

    SHARED nome.file.temp$

    SHARED nome.file.bar$

    SHARED nome.file.igro$

    SHARED nome.file.vel$

    SHARED delta.timer

    SHARED num.file.temp

    SHARED num.file.igro

    SHARED num.file.vel

    SHARED num.file.bar

 

    '----------------------------------------------------

    ' Se delta.timer = 0 le routine di plottaggio non

    ' aspettano il tempo minimo per tracciare il punto.

    '----------------------------------------------------

    old.delta = delta.timer

    delta.timer = 0

 

    OPEN nome.file.temp$ FOR INPUT AS num.file.temp

    IF (fileerrato = 1) THEN

        CLOSE num.file.temp

        CLOSE num.file.igro

        CLOSE num.file.vel

        CLOSE num.file.bar

        EXIT SUB

    END IF

  

    OPEN nome.file.bar$ FOR INPUT AS num.file.bar

    IF (fileerrato = 1) THEN

        CLOSE num.file.temp

        CLOSE num.file.igro

        CLOSE num.file.vel

        CLOSE num.file.bar

        EXIT SUB

    END IF

  

    OPEN nome.file.igro$ FOR INPUT AS num.file.igro

    IF (fileerrato = 1) THEN

        CLOSE num.file.temp

        CLOSE num.file.igro

        CLOSE num.file.vel

        CLOSE num.file.bar

        EXIT SUB

    END IF

  

 

    OPEN nome.file.vel$ FOR INPUT AS num.file.vel

    IF (fileerrato = 1) THEN

        CLOSE num.file.temp

        CLOSE num.file.igro

        CLOSE num.file.vel

        CLOSE num.file.bar

        EXIT SUB

    END IF

 

    fine.temp = 0

    fine.igro = 0

    fine.bar = 0

    fine.vel = 0

    count = 0

    DO

        fine = fine.temp + fine.bar + fine.igro + fine.vel

        IF (fine >= 4) THEN

            CLOSE num.file.temp

            CLOSE num.file.igro

            CLOSE num.file.vel

            CLOSE num.file.bar

            delta.timer = old.delta

            EXIT SUB

        END IF

 

        '-----------------------------------------------

        ' Scelgo a rotazione un file da leggere

        '-----------------------------------------------

        IF (count = 0) THEN

            num.file = num.file.temp

        ELSEIF (count = 1) THEN

            num.file = num.file.igro

        ELSEIF (count = 2) THEN

            num.file = num.file.bar

        ELSEIF (count = 3) THEN

            num.file = num.file.vel

        END IF

 

        leggi = 0

        SELECT CASE count

            CASE IS = 0: IF (fine.temp = 0) THEN leggi = 1

            CASE IS = 1: IF (fine.igro = 0) THEN leggi = 1

            CASE IS = 2: IF (fine.bar = 0) THEN leggi = 1

            CASE IS = 3: IF (fine.vel = 0) THEN leggi = 1

        END SELECT

        count = count + 1

        IF (count > 3) THEN count = 0      

 

        IF (leggi <> 0) THEN

            h$ = ricevi.stringa.da.file(num.file, valore$)

      

            IF (h$ = "") THEN

                IF (num.file = num.file.temp) THEN

                    fine.temp = 1

                END IF

                IF (num.file = num.file.bar) THEN

                    fine.bar = 1

                END IF

                IF (num.file = num.file.igro) THEN

                    fine.igro = 1

                END IF

                IF (num.file = num.file.vel) THEN

                    fine.vel = 1

                END IF

              

                fine = fine.temp + fine.bar + fine.igro + fine.vel

                IF fine >= 4 THEN

                    CLOSE num.file.temp

                    CLOSE num.file.igro

                    CLOSE num.file.vel

                    CLOSE num.file.bar

 

 

 

 

 

 

 

                    '----------------------------------------------------

                    ' Rimetto delta.timer originale.

                    '----------------------------------------------------

                    delta.timer = old.delta

                    EXIT SUB

                END IF

            ELSE

                v = decodifica.valore(h$, valore$)

                CALL grafica.punto(h$, v, fun.attuale)

            END IF

        END IF

    LOOP

 

    '----------------------------------------------------

    ' Rimetto delta.timer originale.

    '----------------------------------------------------

    delta.timer = old.delta

 

END SUB

 

FUNCTION scegli.tipo.statistica (giorno$, mese$, anno$, inizio$, fine$)

'==================================================================

' REnde: 1 --> Di un certo  giorno

'        2 --> Di un certo periodo

'        0 --> Annullato

'==================================================================

 

ancora:

    CLS

 

    PRINT "Quale tipo di statistica vuoi vedere ?"

    PRINT

    PRINT "Scegli: 1 --> Statistica di un determinato giorno "

    PRINT "        2 --> Statistica di un determinato periodo"

    PRINT "        3 --> Annulla"

 

    DO

        DO

            a$ = INKEY$

            scelta = VAL(a$)

        LOOP UNTIL scelta > 0

    LOOP WHILE scelta < 1 OR scelta > 3

 

    IF (scelta = 1) THEN

        DO

            PRINT

            PRINT

            INPUT "Digita giorno che vuoi prendere in esame (gg):"; giorno$

            INPUT "Digita il mese che vuoi prendere in esame(mm):"; mese$

            INPUT "Digita l'anno che vuoi prendere in esame(aa):"; anno$

        LOOP WHILE controlla.data(giorno$, mese$, anno$) = 0

    ELSEIF (scelta = 2) THEN

        PRINT

        PRINT

        PRINT "Quale periodo vuoi prendere in esame ?"

        PRINT "1) Dal 1 Gennaio al 31 Marzo"

        PRINT "2) Dal 1 Aprile al 30 Giugno"

        PRINT "3) Dal 1 Luglio al 30 Settembre"

        PRINT "4) Dal 1 Ottobre al 31 Dicembre"

        PRINT

        PRINT

        PRINT "ATTENZIONE: Funzione non attivabile. Premi un tasto."

        DO

        LOOP UNTIL INKEY$ <> ""

        GOTO ancora

    ELSE

        scelta = 0

    END IF

  

    scegli.tipo.statistica = scelta

 

END FUNCTION


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Appendice 2

Simulatore meteo.


 

 

'***************************************************************************

'* sim_mete.bas

'*

'* Simulatore della stazione meteorologica.

'*

'* Protocollo di comunicazione tra stazione meteo e ricevitore

'*

'*                     [$grandezza+/-****#]

'*

'* $         = Carattere di inizio stringa;

'* grandezza = T(Temperatura),U(Umidità),P(Pressione),V(Velocità del vento);

'* +/-       = Segni;

'* ****      = Cifre numeriche;

'* #         = Carattere di fine stringa;

'*

'***************************************************************************

 

 

 

DIM SHARED xold  'vecchia posizione asse x

DIM SHARED yold  'vecchia posizione asse y

 

COMMON SHARED flag.out

COMMON SHARED outport

COMMON SHARED inport1

COMMON SHARED inport2

COMMON SHARED rit1

COMMON SHARED rit2

 

 

'------------------------------------------------

' Main-program

'------------------------------------------------

 

 

CALL apri.seriale(100)

 

rit = 2500  'Ritardo in millisecondi tra i campioni spediti

 

GOTO tutti

DO

      CALL tx.temp(100)

      CALL ritmilli(rit)

LOOP UNTIL INKEY$ <> ""

END

 

tutti:

DO

     CALL tx.igro(100)

     CALL ritmilli(rit)

  

      CALL tx.bar(100)

      CALL ritmilli(rit)

 

      CALL tx.vel(100)

      CALL ritmilli(rit)

   

      CALL tx.temp(100)

      CALL ritmilli(rit)

 

LOOP UNTIL INKEY$ <> ""

 

CALL chiudi.seriale(100)

 

 

END

 

 

 

 

 

 

 

 

 

 

 

 

‘*******************************************************************

‘*******************************************************************

‘* Definizione routines.

‘*******************************************************************

‘*******************************************************************

 

 

SUB apri.seriale (num.file)

'==================================================================

'==================================================================

   

     OPEN "com1:1200,n,8,1,cd0,cs0" FOR OUTPUT AS num.file

 

END SUB

 

SUB chiudi.seriale (num.file)

'==================================================================

'==================================================================

 

    CLOSE num.file

 

END SUB

 

SUB ritmilli (r)

'===================================================================

' Esegue un ritardo di R millisecondi

'===================================================================

  

    init = TIMER

    DO

    LOOP UNTIL TIMER > (init + r / 1000)

 

END SUB

 

SUB tx.bar (num.file)

'==================================================================

'==================================================================

 

    STATIC valore.trasmesso

 

 

    valore.trasmesso = valore.trasmesso + 1

 

    IF (valore.trasmesso > 255) THEN

        valore.trasmesso = 0

    END IF

 

 

    vt$ = "$P+000"

    vvtt = valore.trasmesso

    vt$ = vt$ + CHR$(vvtt)

 

    vt$ = vt$ + "#"

    PRINT #num.file, vt$

    PRINT vt$; "  -->"; vvtt

 

END SUB

 

SUB tx.igro (num.file)

'==================================================================

'==================================================================

 

       

    STATIC valore.trasmesso

 

 

 

    valore.trasmesso = valore.trasmesso + 1

 

    IF (valore.trasmesso > 255) THEN

        valore.trasmesso = 0