Trasmissione Seriale - Andrea Asta

45
Relazione di Sistemi Trasmissione Seriale Standard RS232/C Protocollo Master/Slave con Eco Sviluppato in Linguaggio C++ Andrea Asta

Transcript of Trasmissione Seriale - Andrea Asta

Page 1: Trasmissione Seriale - Andrea Asta

Relazione di Sistemi

Trasmissione Seriale

Standard RS232/C Protocollo Master/Slave con Eco

Sviluppato in Linguaggio C++

Andrea Asta

Page 2: Trasmissione Seriale - Andrea Asta

2

Autore del fascicolo

Nome Andrea Asta Sito Web www.andrea-asta.com Email [email protected] Classe 5A INFO

Sommario

Autore del fascicolo............................................................................................................................2 Sommario............................................................................................................................................2 Introduzione .......................................................................................................................................3

1.1 Titolo del progetto................................................................................................................3 1.2 Descrizione del progetto ......................................................................................................3

2. Progettazione generale del sistema...............................................................................................3 2.1 Strati di progettazione ..........................................................................................................3 2.2 Strato fisico ..........................................................................................................................4 2.3 Strato logico .........................................................................................................................4 2.4 Strato di programmazione....................................................................................................5 2.5 Riepilogo dei vari strati........................................................................................................6

3. Analisi approfondita dello strato fisico ........................................................................................7 3.1 La trasmissione in generale..................................................................................................7 3.2 La trasmissione seriale asincrona.........................................................................................8 3.3 Standard RS232/C..............................................................................................................13 3.5 Trasmissione RS232/C Null – Modem ..............................................................................15 3.6 Programmazione RS232/C.................................................................................................16

4. Analisi approfondita dello strato logico.....................................................................................19 4.1 Definizione del protocollo .................................................................................................19 4.2 Studio del protocollo..........................................................................................................20 4.3 Limitazioni note .................................................................................................................24 4.4 Algoritmo "Master Trasmette"...........................................................................................25 4.5 Algoritmo "Master Riceve" ...............................................................................................27 4.6 Unione degli algoritmi .......................................................................................................28

5. Programmazione ..........................................................................................................................29 5.1 Scelta del linguaggio di programmazione..........................................................................29 5.2 Routine di base del programma .........................................................................................29 5.3 Traduzione degli algoritmi.................................................................................................32 5.5 Software di supporto ..........................................................................................................33 5.6 Codice completo del programma .......................................................................................33

6. Conclusioni ...................................................................................................................................42 6.1 Conclusioni ........................................................................................................................42 6.2 Fonti ...................................................................................................................................42

7. Allegati ..........................................................................................................................................43 7.1 Documentazione _bios_serialcom()...................................................................................43 7.2 Documentazione clock() ....................................................................................................45

Page 3: Trasmissione Seriale - Andrea Asta

3

Introduzione

1.1 Titolo del progetto Realizzazione di un sistema di comunicazione seriale RS232/C, trami-te la definizione di un protocollo Master/Slave con eco.

1.2 Descrizione del progetto L'intento prefissato è l'ideazione, progettazione e realizzazione di un sistema di comunicazione tra sistemi a microprocessore, attraverso la porta seriale RS232.

2. Progettazione generale del sistema

2.1 Strati di progettazione Il progetto sarà analizzato e realizzato a diversi strati, che permette-ranno un incremento graduale delle prestazioni del sistema. In altre pa-role, un primo livello di base permetterà la comunicazione fisica tra i due microprocessori; un secondo strato prevederà la definizione del si-stema logico di comunicazione (in che modo, in che ordine i due ela-boratori comunicheranno); infine, lo strato più esterno sarà costituito dal vero e proprio codice.

1. Strato fisico 2. Strato logico 3. Strato di programmazione

Figura 1: Strati di progettazione

Ogni strato, come si può osservare dall'immagine, è strettamente

dipendente dallo strato di livello inferiore: in particolare, possiamo di-re che uno strato esterno eredita, amplia e dipende dalle caratteristiche dello strato immediatamente più interno. Eliminando uno strato inter-no, anche tutti quelli immediatamente esterni perdono significatività.

Page 4: Trasmissione Seriale - Andrea Asta

4

Da questo si deduce come, prima di poter passare alla creazione di uno strato superiore, sia vitale testare il perfetto funzionamento di tutti gli strati più interni, in ogni sua parte. Infatti, come spiegato, ogni stra-to esterno è strettamente dipendente dagli strati interni, non può esiste-re senza di essi; ne consegue che un errore in uno strato interno com-promette il funzionamento anche dello strato esterno.

2.2 Strato fisico Lo strato fisico riguarda l'analisi e la gestione della comunicazione e-lementare tra due microprocessori. Per quanto stabilito, la trasmissione dovrà essere di tipo seriale e si atterrà allo standard di comunicazione RS232/C.

Lo strato fisico comprende quindi la gestione a livello hardware della comunicazione tra due microprocessori, il modo utilizzato per la sincronizzazione e i controlli basilari degli errori fisici di trasmissione.

Lo scopo finale dello strato fisico è quello di fornire algoritmi chiari all'utente per la trasmissione e la ricezione di un carattere attra-verso la porta seriale RS232/C del microprocessore.

2.3 Strato logico Completato lo strato basilare del progetto, ossia la trasmissione e la ri-cezione elementare attraverso lo standard RS232/C, è necessario am-pliare lo studio del progetto e aggiungere una serie di controlli aggiun-tivi che definiscano un protocollo chiaro di comunicazione.

In altre parole, una volta che i due microprocessori hanno a dispo-sizione gli strumenti necessari per comunicare (strato fisico) è necessa-rio che si prendano degli accordi sul modo in cui essi dovranno scam-biarsi i dati. Ad esempio, all'inizio dell'esecuzione, chi dovrà inviare un dato e chi dovrà riceverlo? Come potranno i due microprocessori sincronizzarsi? In che modo potremo verificare l'esattezza del dato ri-cevuto? Tutte queste domande troveranno risposta nel nostro protocol-lo.

In generale, un protocollo di comunicazione è un insieme di rego-le rigorose, chiare, il più possibili elementari e comunemente accettate che vengono definite per instaurare una comunicazione corretta.

Con il termine rigorose si intende che esse devono essere definite e non ambigue: in ogni istante della comunicazione deve essere chiaro in modo univoco che cosa si vuole fare.

Con il termine chiare si intende invece il fatto che i metodi utiliz-zati da un protocollo per instaurare la comunicazione devono essere di comprensione immediata, non ci devono essere incomprensioni tra i sistemi che tentano di comunicare.

Inoltre, siccome in genere il protocollo utilizza lo strato fisico per trasmettere parole speciali utilizzate come comandi, è necessario che esse siano il più possibile semplici ed elementari: bisogna escludere ogni comando superfluo, in quanto ogni trasmissione e ricezione in ec-cesso rallenta, anche se in minima parte, il tempo di esecuzione dell'in-tera trasmissione. Se, ad esempio, per trasmettere un singolo carattere, fosse prima necessario inviare una decina di parole chiave, più una de-cina di parole alla fine, probabilmente il protocollo definito non sareb-

Page 5: Trasmissione Seriale - Andrea Asta

5

be elementare e, in generale, il tempo speso per la trasmissione dei comandi sarebbe molto superiore rispetto a quello della trasmissione del dato.

Infine, il protocollo definito deve essere comunemente noto e ac-cettato, nel senso che esso deve essere rispettato da tutti i sistemi inte-ressati nella comunicazione.

Va aggiunto che, generalmente, lo strato fisico fornisce le routine per la gestione di un'unità elementare di dato: ad esempio, normalmen-te, con le routine RS232 non si potrà inviare più di un byte. Scopo del protocollo che sarà definito è anche quello di permettere l'invio di una quantità superiore di dati (generalmente una sequenza di dati elemen-tari) e controllare, mediante appositi strumenti, la correttezza dell'inte-ra sequenza inviata o ricevuta.

2.4 Strato di programmazione In realtà lo strato di programmazione non è un vero e proprio strato di progettazione, nel senso che esso dovrà, banalmente, tradurre lo strato fisico in codice e lo strato logico in codice (che utilizzi quello dello strato fisico): tuttavia, è bene ricordare che ogni linguaggio di pro-grammazione, per sua natura, ha pregi e difetti, quindi è possibile che, a seconda del linguaggio scelto, sia necessario applicare qualche pic-cola modifica, qualche piccolo cambiamento al progetto iniziale.

La gestione di input esterni, inoltre, porterà a controlli aggiuntivi, pertanto possiamo dire che il codice è, seppur in forma ridotta, un nuovo strato di progettazione, che deve essere curato come gli altri due.

Lo strato di programmazione sarà quindi quello che, oltre a tradur-re gli algoritmi degli strati fisico e logico, aggiungerà l'interattività fi-nale con l'utente esterno: ad esempio, si occuperà di ricevere in input i dati da trasmettere, o di fornire in output i dati ricevuti.

Sarà quindi suo compito principale quello di rendere la trasmis-sione trasparente all'utilizzatore, ricevendo in input solamente le in-formazioni strettamente necessarie e fornendo in output le informazio-ni più importanti. In altre parole, lo strado di programmazione dovrà fornire un'interfaccia elementare e trasparente all'utente finale.

Il prodotto finale dello strato di programmazione risulterà quindi un software di semplice utilizzo, che permetta a chiunque di scambiare dati mediante la porta seriale.

L'utente finale non dovrà conoscere i dettagli del protocollo di co-municazione e, tanto meno, dovrà essere a conoscenza dello strato fisi-co del progetto, ossia dei metodi hardware utilizzati per la trasmissio-ne. Tutto ciò che gli sarà richiesto sarà di connettere i due sistemi me-diante un cavo Null – Modem apposito e di eseguire il software da noi creato.

Page 6: Trasmissione Seriale - Andrea Asta

6

2.5 Riepilogo dei vari strati La tabella seguente riassume in forma sintetica le caratteristiche ed i compiti dei vari strati utilizzati per questo progetto. Strato Compiti Caratteristiche

Fisico

Gestione hardware della comunica-zione

Algoritmi efficienti per la comunica-zione elementare

Efficiente

Logico

Definizione di un protocollo di co-municazione

Gestione degli errori di comunica-zione

Rigoroso Chiaro Elementare Comunemente accettato

Programmazione

Creazione di un'interfaccia per l'uten-te finale

Definizione di un sistema di intera-zione con l'utente

Traduzione degli algoritmi fisici e logici in programma

Semplice Intuitiva Trasparente Efficiente

Page 7: Trasmissione Seriale - Andrea Asta

7

3. Analisi approfondita dello strato fisico

3.1 La trasmissione in generale Esistono diverse modalità di comunicazione tra due o più sistemi. Quella più elementare è semplicemente quella in cui i vari sistemi so-no fisicamente collegati per mezzo di una serie di connessioni elettri-che collegate a delle porte di input e output del sistema.

SistemaA

PortX1

Connessione fisica

SistemaB

PortX2

Figura 2: Collegamento fisico tra due sistemi

Esistono altri tipi di trasmissione: ad esempio esiste la trasmissione

via linee telefoniche, la trasmissione via fibre ottiche, via raggi infra-rossi, via bluetooth, via radio eccetera.

Nel nostro progetto ci occuperemo della trasmissione tramite col-legamento fisico.

A questo proposito, esistono ancora molti tipi di trasmissione, rag-gruppabili in genere in due grandi famiglie:

Trasmissione seriale Trasmissione parallela

In generale, la differenza tra questi due tipi di comunicazione sta nel modo utilizzato per trasmettere (e, di conseguenza, ricevere) un da-to: nel primo caso il dato è mandato bit per bit, quindi è necessaria una sola linea dati per la trasmissione. Nel secondo caso, invece, tutto il dato è trasmesso contemporaneamente, quindi saranno necessarie tante linee quanti sono i bit da trasmettere.

SistemaA

Serial#01

Parallel#01 n

SistemaB

Parallel#02

Serial#02

Figura 3: Comunicazione seriale e parallela

Ogni porta di input o output, in genere, dispone anche di ulteriori

segnali di controllo, chiamati segnali di hand – shaking. Questi se-

Page 8: Trasmissione Seriale - Andrea Asta

8

gnali sono ovviamente diversi per la trasmissione seriale e per quella parallela, in quando in ognuna delle due trasmissioni ci sono dei con-trolli differenti da effettuare.

Dalla descrizione, seppur sommaria, dei due tipi di trasmissione, si possono dedurre i principali pregi e difetti di questi due tipi di comuni-cazione.

Trasmissione Pregi Difetti Seriale E' sufficiente una sola linea

dati per la trasmissione dei dati

Minor rischio di interferenze Costi più ridotti Fili più lunghi

Trasmissione più lenta

Parallela Trasmissione più veloce Necessaria una linea dati per ogni bit, quindi utilizzo di cavi grossi ed ingombranti

Maggior rischio di interferen-ze

Costi più elevati

Va sottolineato inoltre che, negli ultimi anni, con l'introduzione delle trasmissioni seriali USB e FireWire, la velocità di trasmissione è cresciuta esponenzialmente, tanto da rendere queste due porte più ve-loci anche della trasmissione parallela.

Velocità di comunicazione Parallela 150KB/s - 2.4MB/s RS232 10,5 Kb/sec - 115,2 Kb/sec USB 480 Mb/sec (USB 2.0) FireWire 400 Mb/sec

3.2 La trasmissione seriale asincrona La trasmissione seriale nasce essenzialmente per collegare il mi-

croprocessore ad un modem (modulatore demodulatore), in grado di modulare i dati in frequenza, fase ed ampiezza e quindi trasferirli, per mezzo della linea telefonica, ad un altro modem. Nella trasmissione seriale si è soliti indicare il sistema microprocessore con la sigla DTE (Data Terminal Equipment) e il modem con DCE (Data Communica-tion Equipment).

Lineatelefonica

Seriale Seriale

Figura 4: Comunicazione con modem

Page 9: Trasmissione Seriale - Andrea Asta

9

Il primo problema che è necessario risolvere in una trasmissione seriale è il seguente: il microprocessore, per sua natura, lavora sempre e solo con dati paralleli: i suoi bus, infatti, non sono, per motivi ovvi legati alla velocità, di tipo seriale: ogni dato inviato in uscita sulle li-nee del Data Bus, quindi, sarà di tipo parallelo. L'unità elementare di trasmissione è, generalmente, il byte.

C'è quindi la necessità di convertire il dato parallelo in seriale: in termini tecnici questo problema è noto come serializzazione del dato. Per questo scopo esiste una particolare porta, chiamata UART (Unità Asincrona Ricezione Trasmissione) o USART (Unità Sincrona e Asin-crona Ricezione Trasmissione), in grado di serializzare il dato e gestire tutta la trasmissione seriale in generale.

UART8250uP

8

Figura 5: Interfaccia seriale Le UART e le USART sono dette interfacce seriali e sono presen-

ti sul mercato sotto forma di circuiti integrati interfacciabili con i di-versi microprocessori: ad esempio, per la famiglia Intel 80XX sono di-sponibili gli integrati 8250 (UART) e 8251 (USART).

Recentemente il nome UART è caduto in disuso, in favore del più recente ACE (Elementi di comunicazione asincrona).

Da quanto appena detto si deduce che esistono almeno due tipi di comunicazione seriale:

Comunicazione sincrona Comunicazione asincrona

Nella trasmissione asincrona il significato di ogni bit ricevuto di-pende dalla sua collocazione nell'ambito temporale, mentre nella tra-smissione sincrona è aggiunta una linea di clock che permette la sin-cronizzazione tra i due dispositivi.

La trasmissione sincrona è, nella pratica, poco utilizzata, in quanto perdere il sincronismo tra due clock è decisamente semplice e, perso il sincronismo di clock, la trasmissione è destinata ad avere esito negati-vo. Inoltre, tra due sistemi a microprocessore, l'aggiunta di una linea di clock è del tutto superflua.

Nella trasmissione asincrona, in genere, i due sistemi si sincroniz-zano prima dell'invio di ogni singolo pacchetto di dati, in questo modo la trasmissione risulta ancora più rallentata, ma decisamente più affi-dabile.

La trasmissione asincrona è caratterizzata dall'invio di un frame di dati: con questo termine si intende il dato vero e proprio (serializzato), più una serie di bit aggiuntivi utilizzati per il controllo del flusso di trasmissione: in altre parole, sulla linea dati non viaggiano solamente i veri e propri dati, ma anche alcuni segnali utilizzati per l'hand - sha-king.

Page 10: Trasmissione Seriale - Andrea Asta

10

Per quanto appena detto, un esempio di frame potrebbe essere: 1. Segnale di inizio trasmissione 2. Dato serializzato 3. Segnale di fine trasmissione

La trasmissione asincrona, quindi, non necessita di una linea ag-giuntiva per il clock: è intuibile tuttavia come sia necessaria una forma di sincronismo tra i due dispositivi in comunicazione.

Generalmente il sincronismo è definito grazie ad un parametro del-la comunicazione, la velocità di trasmissione.

I due dispositivi, quindi, lavoreranno alla stessa velocità di tra-smissione: una volta che è stato ricevuto il segnale di inizio trasmis-sione, il ricevitore controllerà la linea dati alla velocità impostata, se-gnalando il valore come bit del dato. Dopo 8 letture (se il dato è a 8 bit), si riceverà il bit di fine trasmissione e la comunicazione sarà ter-minata.

La velocità di trasmissione è misurabile mediante due unità di mi-sura differenti: i bps (bit per second) o baud.

I bps indicano, come indica il nome, il numero di bit trasmessi nel-l'unità di tempo.

Il baud, invece, indica il numero di transizioni che avvengono sulla linea nell'unità di tempo.

Se, ad esempio, la trasmissione avviene attraverso valori di tensio-ne variabili tra 0V e 7V e ogni singolo Volt corrisponde ad una parola diversa a 3 bit (0V = 000, 7V = 111), è logico pensare che, con una so-la transizione, sarò in grado di trasmettere 3 bit: in altre parole, in un caso del genere la velocità espressa in baudrate è un terzo di quella e-spressa in bps.

Se la trasmissione si serve di due soli valori logici '0' e '1', come nella maggior parte dei casi, è logico che ogni transizione permetterà di trasmettere un solo bit, quindi baudrate e bps coincideranno.

Riassumendo, se con una transizione si trasmettono 2n bit, si può scrivere la seguente relazione:

bpsn

baud 11 =

Volendo essere più generali, se con una transizione sono trasmessi

k bit, la relazione tra baud e bps diventa la seguente:

bpsk

baud2log

11 =

In genere, la linea dato è a riposo sul valore logico '1'. Nel momen-

to in cui il suo valore è spostato sul valore '0', la trasmissione ha inizio e i due dispositivi inizieranno a trasferire i bit del dato.

In particolare, il trasmettitore avrà cura di cambiare la linea del bit opportunamente, mentre il ricevitore si limiterà a leggere la linea dati in relazione alla velocità di trasmissione impostata.

Terminato l'invio, la linea tornerà a riposo e la trasmissione del frame sarà ultimata.

Page 11: Trasmissione Seriale - Andrea Asta

11

t

Dato

'1'

Riposo Dato

d0 d1 d2 d3 d4 d5 d6

Start

Stop + Riposo

d7 S

Figura 6: Esempio di invio di un frame

Il primo problema che sorge quando si parla di sincronismo è l'i-

stante in cui il dato deve essere campionato: se, ad esempio, la velocità di trasmissione è impostata a 300b/s, il bit dovrà essere campionato ogni

s

sb

bvst

tsv

3001

300

1dddd

===⇒=

Tuttavia, se si legge esattamente ogni trecentesimo di secondo, an-

che il più piccolo ritardo nel cambiamento della linea da parte del tra-smettitore causerebbe un errore nella comunicazione (ad esempio, se il ricevitore legge poco prima che il trasmettitore cambi la linea, si a-vrebbe una lettura errata). Generalmente le UART risolvono il pro-blema campionando il bit a metà del periodo, in questo modo la pro-babilità che un piccolo ritardo generi errori di trasmissione è molto bassa. In questo modo, quando la linea viene posta a '0', il ricevitore lascerà passare la metà di un trecentesimo di secondo (trovandosi quindi a metà del periodo di permanenza dello '0'), quindi inizierà a campionare regolarmente ogni trecentesimo di secondo.

t

'1'd2 d3 d4 d5 d6 d7

CampionamentiT/2 T

Dato

d0 d1 S2S1

Figura 7: Campionamento dei bit

Va notato che la fine della trasmissione è trattata esattamente come

un ulteriore bit: in altre parole, la linea portata allo stato di riposo è nuovamente campionata. Il bit così rilevato è chiamato bit di stop. In alcuni casi, per maggiore sicurezza durante la trasmissione, la linea è

Page 12: Trasmissione Seriale - Andrea Asta

12

mantenuta alta per un secondo ciclo, in questo caso la comunicazione avrà due bit di stop.

Al frame di comunicazione, infine, è spesso aggiunto il bit di pari-tà, che può essere pari o dispari1. In questo caso, il frame necessita di un'ulteriore aggiunta, generalmente posta prima dei bit di stop.

Dato

'1'

Riposo Dato

d0 d1 d2 d3 d4 d5 d6

Start

d7 P

Parità

Bit di Stop + Riposo

S2S1

t

Figura 8: Frame completo

Va notato che il controllo sul bit di parità è totalmente affidato al-

l'hardware, non al software. In altre parole, sarà la UART del ricevito-re a valutare la correttezza del bit di parità e fornire segnali di hand – shaking appropriati.

Dallo studio del frame si evince come, in effetti, la trasmissione se-riale asincrona risulti da 10 (dato, start, stop) a 13 (dato, start, doppio stop, parità) volte più lento di una trasmissione parallela. Come detto, tuttavia, si hanno vantaggi legati all'affidabilità e alla lunghezza mas-sima dei cavi di connessione.

Le trasmissioni seriali possono essere di tre tipi: Simplex Half – Duplex Full – Duplex

Questa divisione indica in quale direzione è possibile comunicare: nella comunicazione simplex, essa avviene "a senso unico", ossia in una sola direzione. Nella trasmissione duplex, invece, è possibile avere comunicazione bidirezionale, con una piccola differenza: nel caso del-la half – duplex, la trasmissione bidirezionale è possibile, ma non può essere contemporanea, caratteristica permessa invece nelle comunica-zioni full – duplex.

In conclusione, affinché una trasmissione seriale asincrona avven-ga in modo corretto, i due dispositivi devono avere accordi precisi e comuni riguardo a:

Numero di bit del dato Numero di bit di stop Numero di bit di parità e sua tipologia Velocità di trasmissione

1 Il bit di parità pari è il numero di '1' da aggiungere al dato affinché il numero di '1' al suo interno sia pari. Ad esempio, se il dato è 10101100, il bit di parità pari è '0', visto che il numero di '1' nel dato è 4, ossia pari. La parità dispari funzio-na allo stesso modo, ma indica il numero di '1' da aggiungere affinché il numero di '1' al suo interno sia dispari.

Page 13: Trasmissione Seriale - Andrea Asta

13

3.3 Standard RS232/C Lo standard RS232 nacque nell'anno 1962 per opera della Electronic Industries Association ed era orientato alla comunicazione tra i main-frame e i terminali attraverso la linea telefonica e un modem. Esso in-cludeva le caratteristiche elettriche dei segnali, la struttura e temporiz-zazioni dei dati seriali, la definizione dei segnali e dei protocolli per il controllo del flusso di dati seriali su un canale telefonico, il connettore e la disposizione dei suoi pin ed infine il tipo e la lunghezza massima dei possibili cavi di collegamento.

Nel corso degli anni lo standard fu più volte corretto e sistemato, per poter essere accettato su scala sempre più vasta: nell'anno 1962 fu definita la versione più famosa e ancora oggi più diffusa, la versione RS232/C. Tuttavia, la sua diffusione si ebbe solo nel 1982, quando per la prima volta l'IBM incluse in un suo computer una porta COM, la prima porta seriale diffusa su scala mondiale.

Da allora seguirono altre versioni fino alla RS232/F, ma la mag-gior parte dei sistemi a microprocessore integra oggi solamente la ver-sione C. C'è da aggiungere, inoltre, che la comunicazione seriale qui descritta sta lentamente scomparendo dai moderni calcolatori, per dare spazio alle più veloci tecnologie USB, FireWire, Ethernet e in fibra ot-tica.

Lo standard RS232/C è caratterizzato dalle seguenti proprietà: La trasmissione è di tipo seriale asincrona La trasmissione è di tipo full – duplex E' possibile inserire 1 o 2 bit di stop (in alcuni casi anche 1 e ½) Ogni transizione permette la trasmissione di un bit, quindi il baud

rate e i bps coincidono Connettori a 9 pin (originariamente 25 di cui 10 significativi)

Lo standard, inoltre, si serve di particolari valori elettrici per defi-nire i valori logici '0' e '1', diversi da quelli utilizzati, ad esempio, dalle tecnologie TTL o CMOS.

Valore Logico Tensione TTL Tensione RS232/C Denominazione '0' 0V Da +3V a +25V Space '1' 5V Da -3V a -25V Mark

La velocità di trasmissione è legata alla lunghezza massima dei cavi: Baud Rate (baud) Distanza (m)

50 4800 110 2182 300 800 600 400 1200 200 2400 100 3600 67 4800 50 7200 33 9600 25 19200 14

Page 14: Trasmissione Seriale - Andrea Asta

14

La tabella seguente illustra i nomi dei 9 segnali significativi per lo standard.

Segnale Significato Direzione TD Transmitted Data DTE DCE RD Received Data DTE DCE RTS Request To Send DTE DCE CTS Clear To Send DTE DCE DCD Data Carrier Detect DTE DCE DTR Data Terminal Ready DTE DCE DSR Data Set Ready DTE DCE SGND Signal Ground --- RI Ring Indicator DTE DCE

Quando il sistema entra in funzione, il DTE attiva la linea Data

Terminal Ready. Il DCE, a sua volta, quando pronto attiverà la linea Data Set Ready. Infine, il DCE controllerà se è disponibile un dispo-sitivo esterno in ascolto (in altre parole, se esiste un altro modem pron-to a ricevere, attraverso la linea telefonica, ciò che stiamo trasmetten-do) e fornirà l'esito mediante il segnale Data Carrier Detect.

A questo punto, i due dispositivi sono pronti per la comunicazione seriale.

Quando il DTE vuole trasmettere un dato serializzato, attiva la li-nea Request To Send e attende il "via libera" dal DCE mediante la li-nea Clear To Send: in generale, prima di attivarla, il DCE controllerà la portante. A questo punto il DTE è pronto ad inviare un dato sulla li-nea Transmitted Data. Se, invece, è il DCE a dover trasmettere, la li-nea utilizzata sarà la Received Data.

Il modo più semplice e diffuso per connettere i due terminali è quello di connettere semplicemente ogni segnale con l'omonimo nel dispositivo di destinazione.

DCE

TDRDRTSCTSDCDDTRDSRSGNDRI

DTE

TDRD

RTSCTSDCDDTRDSR

SGNDRI

Figura 9: Connessione RS232/C tra DTE e DCE

Tuttavia, esistono altri diversi modi di connessione.

Page 15: Trasmissione Seriale - Andrea Asta

15

In alcuni casi, i cavi seriali incrociano alcuni segnali, in modo da avere più segnali di hand – shaking anche quando è il DCE a dover trasmettere un dato.

DTE

TDRD

RTSCTSDCDDTRDSR

SGNDRI

DCE

TDRDRTSCTSDCDDTRDSRSGNDRI

Figura 10: Collegamento con incroci

3.5 Trasmissione RS232/C Null – Modem Spesso si ha la necessità, come nel nostro progetto, di connettere due computer, ma non si ha invece bisogno di passare attraverso un mo-dem: ad esempio, se i due terminali risiedono ad una breve distanza tra loro, sarebbe superfluo passare per il modem.

Lo standard RS232/C può essere adattato anche per creare una connessione, detta Null – Modem, che permette di collegare due ter-minali senza necessità di un modem.

Anche in questo caso, esistono differenti versioni di collegamento: di seguito è riportata la più diffusa, nonché quella da noi utilizzata.

DTE2

TDRDRTSCTSDCDDTRDSRSGNDRI

DTE1

TDRD

RTSCTSDCDDTRDSR

SGNDRI

Figura 11: Connessione Null – Modem

Come si nota, alcuni segnali sono corto – circuitati, infatti l'assenza

di modem comporta il fatto che non ci sia bisogno di rilevare portanti o verificare l'accensione di questo dispositivo. Allo stesso modo,

Page 16: Trasmissione Seriale - Andrea Asta

16

quando il primo terminale è pronto a trasmettere, può farlo senza a-spettare conferme, visto che il modem non è presente.

3.6 Programmazione RS232/C La porta RS232 è programmabile in tre modi diversi:

Accedendo direttamente alla porta Attraverso gli interrupt BIOS Attraverso gli interrupt DOS

Nel nostro progetto, sviluppato sotto ambiente Windows XP, ci serviremo degli interrupt BIOS, che rappresentano un buon compro-messo tra semplicità d'uso ed affidabilità (che sarebbe maggiore nel caso di accesso diretto alla porta).

L'interrupt software BIOS 14h fornisce una serie di routine per la gestione delle porte COM1, COM2, COM3, COM4.

Dei vari servizi a disposizione, ce ne sono quattro particolarmente importanti: Servizio 0: Inizializzazione porta seriale Servizio 1: Invio di un carattere Servizio 2: Ricezione di un carattere Servizio 3: Stato della porta

Ognuno di questi servizi prevede dei parametri in ingresso, tra cui, sempre, il numero di porta COM a cui ci si riferisce.

In generale, ogni porta utilizzata deve essere inizializzata, quindi è possibile richiedere operazioni di invio e ricezione, controllando even-tualmente lo stato della porta in caso di errori. Inizializzazione della porta Questa operazione è necessaria per programmare la porta seriale, im-postando quindi i corretti valori per:

Velocità di trasferimento Bit di parità Lunghezza della parola Numero di bit di stop

E' logico che la programmazione della porta seriale dovrà essere identica su tutti e due i dispositivi interessati alla trasmissione.

La parola di programmazione è generalmente costituita da un byte, che racchiude al suo interno le informazioni sopraccitate. In particolare esso è così costituito:

V1V2 V0 P1 P0 S L1 L0

b7 b0

Figura 12: Programmazione della porta seriale

I tre bit più significativi servono ad impostare la velocità di trasfe-

rimento, secondo questi valori:

Page 17: Trasmissione Seriale - Andrea Asta

17

b7…b5 Baud Rate (baud) 000 110 001 150 010 300 011 600 100 1200 101 2400 110 4800 111 9600

I successivi due bit impostano la parità:

b4-b3 Parità 00 Nessun bit di parità 01 Parità dispari 10 Nessun bit di parità 11 Parità pari

Il bit successivo indica quanti bit di stop devono essere inclusi nel

frame:

b2 Stop 0 1 bit di stop 1 2 bit di stop

Gli ultimi due bit, infine, impostano la lunghezza delle parole da

trasferire:

b1-b0 Parità 00 Configurazione non ammessa 01 Configurazione non ammessa 10 Parole a 7 bit 11 Parole a 8 bit

Il risultato della programmazione è esattamente uguale al risultato

dell'invocazione dello stato della porta seriale e sarà quindi descritto in seguito. Utilizzo della porta Una volta programmata, la porta è pronta ad essere utilizzata. In gene-rale, le routine di invio e ricezione utilizzeranno una variabile a 7 o 8 bit (a seconda di come è stata programmata la porta) per l'invio o la ri-cezione di un carattere. Esisterà poi un flag che indicherà la corretta esecuzione dell'operazione. In caso di errore, sarà possibile richiamare la routine di status per maggiori informazioni. Stato della porta Il servizio di stato della porta seriale restituisce due byte, in cui il pri-mo indica lo stato della linea, il secondo lo stato del modem.

Se, come nel nostro caso, si utilizza una connessione Null - Mo-dem del tipo precedentemente descritto, è chiaro che lo stato del mo-

Page 18: Trasmissione Seriale - Andrea Asta

18

dem sarà irrilevante, visto che non vi è interconnessione tra i segnali di hand – shaking di un dispositivo con quelli dell'altro.

Stato della linea b7 b6 b5 b4 b3 b2 b1 b0 Significato 1 Dato pronto da ricevere 1 Errore di sovrapposizione (Overrun Error) 1 Errore di parità (Parity Error) 1 Errore di composizione (Framing Error) 1 Segnale di Break (Break Interrupt) 1 Registro di trasmissione THR vuoto 1 Registro di trasmissione TSR vuoto 1 Errore di timeout (Timeout Error)

Stato del modem b7 b6 b5 b4 b3 b2 b1 b0 Significato 1 La linea CTS ha cambiato valore dopo l'ultima lettura 1 La linea DSR ha cambiato valore dopo l'ultima lettura 1 La linea RI ha cambiato valore dopo l'ultima lettura 1 La linea DCD ha cambiato valore dopo l'ultima lettura X Valore del segnale CTS X Valore del segnale DSR X Valore del segnale RI X Valore del segnale DCD In generale, prima di una trasmissione bisognerà attendere che i

registri di trasmissione siano vuoti (tutto ciò che prima era presente è stato trasmesso, i due registri vengono svuotati solo alla fine della tra-smissione), mentre prima di una ricezione bisognerà verificare che sia settato il bit di Data is Ready, che indica se è presente un nuovo dato da leggere.

Nel nostro programma implementeremo una funzione con un time-out, in modo che il programma non rimanga all'infinito a provare la trasmissione o la ricezione, ma solo per un tempo prefissato.

Page 19: Trasmissione Seriale - Andrea Asta

19

4. Analisi approfondita dello strato logico

4.1 Definizione del protocollo Il protocollo che andremo a definire sarà di tipo Master – Slave con eco.

Un protocollo è di tipo Master – Slave quando una delle due parti in gioco ha il potere di decidere chi compierà una determinata opera-zione. Nel nostro caso, il Master deciderà, ad ogni iterazione, quale tra i due dispositivi sarà in trasmissione e quale in ricezione. Lo Slave do-vrà quindi attenersi alle disposizioni del Master.

Un protocollo è di tipo Con Eco quando ad ogni parola comando inviata corrisponde un eco di conferma. Se, ad esempio, uno dei due dispositivi manda il comando "Inizio Trasmissione", l'altro rimanderà lo stesso comando "Inizio Trasmissione" per confermare di aver ben inteso l'operazione che si dovrà eseguire. Questo tipo di controllo per-mette maggiore sicurezza nel flusso del programma.

Il nostro protocollo prevederà, inoltre, una seconda forma di con-trollo sulla completezza del dato inviato: si aggiungerà infatti un'ulte-riore parola, la checksum del dato inviato.

Il trasmettitore manderà un segnale di inizio trasmissione, quindi un pacchetto di dati di lunghezza variabile, ed un segnale di fine tra-smissione, seguito da una parola di controllo degli errori.

Il ricevitore manderà l'eco per ogni comando e fornirà l'esito dellachecksum II e, quindi, della comunicazione in generale.

Per la comunicazione, quindi, si seguirà una procedura di questo tipo:

Il Master decide chi trasmetterà Inizio della trasmissione Invio del dato Fine della trasmissione Invio della checksum Esito della trasmissione

Dovendoci basare unicamente sullo strato fisico, è chiaro che le parole chiave saranno dei normali dati inviati.

Sarà inoltre definita una parola errore che, quando ricevuta, indi-cherà di riposizionarsi all'inizio dell'esecuzione e ricominciare la tra-smissione dall'inizio.

Definiamo quindi i seguenti valori costanti come keywords:

Valore Descrizione 0Bh Il Master decide di trasmettere 0Ch Il Master decide che trasmetterà lo Slave 01h Inizio della trasmissione 04h Fine della trasmissione 00h Errore 59h Checksum corretta, trasmissione riuscita 4Eh Checksum errata, trasmissione fallita

II La checksum è il bit di parità pari eseguito sull'intera serie dei dati. In altre parole, il bit bi della checksum altro non è che il bit di parità dell'intera serie dei bit bi del pacchetto dati in questione.

Page 20: Trasmissione Seriale - Andrea Asta

20

4.2 Studio del protocollo Una volta definito il protocollo, si esegue una serie di test per verifi-carne la validità.

I primi test sono quelli eseguiti in assenza di errori.

Test di correttezza in assenza di errori Master in trasmissione

Master Slave

01 Decisione 0B

02 Eco 0B

03 Inizio trasmissione 01

04 Eco 01

05 Dato XX

06 Fine trasmissione 04

07 Eco 04

08 Checksum YY

09 Esito 59 or 4E

Test di correttezza in assenza di errori Master in ricezione

Master Slave

01 Decisione 0C

02 Eco 0C

03 Inizio trasmissione 01

04 Eco 01

05 Dato XX

06 Fine trasmissione 04

07 Eco 04

08 Checksum YY

09 Esito 59 or 4E

A questo punto, l'analisi si sposta nello studio di ogni tipo di errore

che può avvenire nella trasmissione. Dobbiamo innanzitutto distingue-re tra errori fisici (errori causati dalla trasmissione e ricezione RS232) ed errori logici (eco sbagliato, checksum errata). A questo riguardo,

Page 21: Trasmissione Seriale - Andrea Asta

21

stabiliamo che, in ogni caso, sarà inviato il codice di errore e la tra-smissione ricomincerà dall'inizio. E' logico pensare che il dato utilizza-to per l'errore non potrà essere presente all'interno di alcun dato, visto che, ad ogni istante, la ricezione di un codice di errore comporterà l'az-zeramento della trasmissione.

Importante è notare la seguente questione: se è stato riportato un errore fisico in trasmissione, chi ci assicura che il codice di errore in-viato da una parte all'altra arrivi correttamente? In effetti nessuno. Tut-tavia, la probabilità che fallisca anche questa seconda trasmissione è piuttosto bassa e, comunque, non abbiamo altra scelta in merito.

Analizziamo ora il caso in cui avvenga un errore durante la tra-smissione del Master.

Errore nel primo eco Master in trasmissione

Master Slave

01 Decisione 0B

02 Eco 0D

03 Errore 00

Esiste tuttavia un caso particolare che va ben tenuto presente: se lo

Slave capisce che sarà lui a trasmettere, non si mette in ascolto di un comando, ma tenterà di inviare il codice di inizio trasmissione. In que-sto caso il Master dovrà attendere una lettura e quindi mandare il codi-ce di errore come eco dell'inizio trasmissione.

Errore nel primo eco – Llo slave pensa di trasmettere Master in trasmissione

Master Slave

01 Decisione 0B

02 Eco 0C

03 Inizio trasmissione 01

04 Errore 00

Negli altri casi, invece, ci si limita ad inviare un codice di errore e

si ricomincia la trasmissione.

Errore nell'eco di inizio trasmissione Master in trasmissione

Master Slave

01 Decisione 0B

02 Eco 0B

03 Inizio trasmissione

Page 22: Trasmissione Seriale - Andrea Asta

22

01

04 Eco 02

05 Dato (Errore) 00

Errore nell'eco di fine trasmissione Master in trasmissione

Master Slave

01 Decisione 0B

02 Eco 0B

03 Inizio trasmissione 01

04 Eco 01

05 Dato XX

06 Fine trasmissione 04

07 Eco 02

08 Checksum (Errore) 00

09 Esito 59 or 4E

Come si nota, anche questo caso appare particolare: infatti, se in-

viamo il codice di errore dopo l'eco di fine trasmissione, lo Slave lo in-terpreterà come una normale checksum. Tuttavia, come è facile imma-ginare, la checksum può valere esattamente zero. Tuttavia, il pro-blema non si pone, per il seguente motivo: se lo Slave interpreta la fine della trasmissione come un comando diverso, esso lo considererà an-cora come dato, quindi sarà sufficiente inviare un codice di errore.

Nel caso in cui sia lo Slave a trasmettere, si ricorrerà, generalmen-te, agli stessi metodi. Ancora una volta, vanno tenuti presente i casi particolari.

Errore nel primo eco Master in ricezione

Master Slave

01 Decisione 0C

02 Eco 0E

03 Inizio trasmissione (Errore) 00

Da qui si evince che, se lo Slave non pensa di dover trasmettere, si

posizionerà comunque in condizione di ricezione, attendendo il codice di errore.

Page 23: Trasmissione Seriale - Andrea Asta

23

Errore nel primo eco – Lo Slave pensa di ricevere Master in ricezione

Master Slave

01 Decisione 0C

02 Eco 0B

03 Inizio trasmissione (Errore) 00

Errore nell'eco di inizio trasmissione Master in ricezione

Master Slave

01 Decisione 0C

02 Eco 0C

03 Inizio trasmissione 01

04 Eco 02

05 Dato (Errore) 00

Anche lo Slave, quindi, ha la possibilità di inviare un codice di er-

rore, ma solamente nel caso dell'invio del dato.

Errore nell'eco di fine trasmissione Master in trasmissione

Master Slave

01 Decisione 0C

02 Eco 0C

03 Inizio trasmissione 01

04 Eco 01

05 Dato XX

06 Fine trasmissione 04

07 Eco 05

08 Checksum (Errore) 0

Nel caso in cui si verifichino errori fisici nella trasmissione, si pro-

verà comunque ad inviare il carattere di errore e ci si posizionerà all'i-nizio della nuova trasmissione.

L'ultimo studio importante riguarda i timeout: come già spiegato, saranno implementati dei timeout nelle routine di trasmissione e rice-zione, in modo che non si aspetti all'infinito. Tuttavia, esiste un caso in

Page 24: Trasmissione Seriale - Andrea Asta

24

cui la strategia adottata non è sufficiente: quando il Master invia il co-mando allo Slave che indica che sarà quest'ultimo a trasmettere, non è possibile impostare un timeout nell'attesa del comando di inizio tra-smissione. Infatti, solo dopo il comando del Master lo Slave potrà ri-cevere in input dall'esterno un dato da mandare, quindi l'utente potreb-be impiegare parecchio tempo per l'input. Non sarebbe formalmente corretto imporre un timeout in questo caso, quindi sarà importante ri-muoverlo.

L'ultima modifica apportata al protocollo è stata la seguente: do-vendo essere il Master ad avere potere decisionale su ogni situazione, abbiamo stabilito che esso confermerà anche il codice di errore ricevu-to dallo Slave, prima di riposizionarsi all'inizio dell'esecuzione. Questa ulteriore forma di controllo, seppur non strettamente necessaria, ci aiu-ta a mantenere coerenza con il fatto che è sempre il Master a prendere le decisioni. Partendo da questa base, una possibile evoluzione futura sarebbe che, ad esempio, quando il Master riceve un codice di errore, ha la possibilità di eseguire altre operazioni, quindi mandare l'eco del-l'errore allo Slave e poter quindi autorizzare il reset della comunica-zione.

4.3 Limitazioni note Esistono alcune limitazioni al nostro protocollo, riassunte di seguito.

1. Il dato non potrà contenere byte uguali al codice di errore 2. Il dato non potrà contenere byte uguali al codice di fine tra-

smissione 3. Si suppone che, in seguito ad un errore fisico o logico, l'invio

del codice di errore possa avvenire 4. Si suppone l'utilizzo di uno strato fisico RS232 con collega-

mento mediante cavo Null – Modem senza interconnessione tra i segnali di handshaking dei due dispositivi (l'unica connessio-ne è tra i segnali di ricezione e trasmissione, incrociati)

Ognuna di queste limitazioni è già stata motivata in precedenza: in

particolare, le limitazioni sulla tipologia del dato sono causate dal fatto che le informazioni vietate (errore, fine trasmissione) sarebbero inter-pretate dal nostro algoritmo come comandi, quindi tutte le informazio-ni inviate di seguito risulterebbero inattese e genererebbero un errore.

La limitazione sull'invio del codice di errore, invece, è causata dal fatto che è comunque necessario rendere noto ad entrambi i dispositivi la presenza di un errore, quindi l'unico modo disponibile è appunto quello di tentare una nuova trasmissione. Se anche questa trasmissione dovesse fallire, è chiaro che il problema sarebbe di dimensioni troppo vaste per poter essere gestito efficacemente e, presumibilmente, il si-stema genererà spontaneamente un errore e terminerà l'esecuzione del programma. Un'ulteriore ipotesi è che il programma risulti "bloccato" e che l'utente termini forzatamente dall'esterno la sua esecuzione.

Page 25: Trasmissione Seriale - Andrea Asta

25

4.4 Algoritmo "Master Trasmette" Il nostro progetto si interesserà della creazione del programma del Master. Il primo punto è quindi quello di creare un algoritmo efficiente nel caso in cui sia il Master a Trasmettere. Algoritmo Master-Trasmette

1. Send 0Bh 2. X Ricevi() 3. error 0 4. Se X = 0Bh

1. Send 01h 2. Y Ricevi() 3. Se Y = 01h

1. Send dati 2. Send 04h 3. Z Ricevi() 4. Se Z = 04h

1. Send Checksum 2. CS Ricevi() 3. Se CS = 59h

1. Trasmissione corretta 4. Altrimenti

1. Trasmissione errata 5. Altrimenti

1. error 1 4. Altrimenti

1. error 1 5. Altrimenti

1. Se X = 0Ch 1. Ricevi()

2. error 1 6. Se error = 1

1. Send 00h Questa versione dell'algoritmo si cura solamente degli errori logici:

il controllo sugli errori fisici verrà, per comodità, aggiunto solamente in fase di stesura del codice; del resto, sarà sufficiente impostare a 1 la variabile di errore se si è riscontrato un errore fisico.

Di seguito è riportato il diagramma a blocchi dell'algoritmo: alcune parti sono state leggermente modificate rispetto all'algoritmo scritto (che, per ragioni legate alla programmazione e allo stile, impone di non usare determinate tecniche di salto), in modo da rendere più chiaro il ragionamento.

Page 26: Trasmissione Seriale - Andrea Asta

26

Inizio

Yes

Eco=

0Ch

Ricezionea vuoto

Invia0Bh

Eco=

0Bh

Eco=

01h

Invia01h

InviaDati

Invia04h

Eco=

04h

InviaChecksum

Esito=

59h

Trasmissionecorretta

Trasmissioneerrata

Fine

Yes

Yes

Invia00h

Yes

Yes

Page 27: Trasmissione Seriale - Andrea Asta

27

4.5 Algoritmo "Master Riceve" Il secondo punto da creare è quello riguardante il Master in ricezione. Algoritmo Master-Riceve

1. Send 0Ch 2. X Ricevi() 3. error 0 4. Stringa s 5. i 0 6. Se X = 0Ch

1. Y Ricevi() 2. Se Y = 01h

1. Send 01h 2. Ripeti

1. C Ricevi() 2. Se ( C ≠ 00h && C ≠ 04h )

1. s[i] C 2. i i + 1

3. finché ( C ≠ 00h && C ≠ 04h ) 4. Se C ≠ 00h

1. Z Ricevi() 2. Se Z = 04h

1. Send 04h 2. CS Ricevi() 3. CS2 CalcolaChecksum (str) 4. Se CS = CS2

1. Send 59h 2. Trasmissione corretta

5. Altrimenti 1. Send 4Eh 2. Trasmissione errata

3. Altrimenti 1. error 1

5. Altrimenti 1. error 1

3. Altrimenti 1. error 1

7. Altrimenti 1. error 1

8. Se error = 1 1. Send 00h

Questo algoritmo è simile a quello precedente: nella maggior parte

dei casi, la scelta adottata è quella di rendere possibile solo al Master l'invio di un valore di errore: l'unico caso in cui lo Slave ha questa pos-sibilità è durante il dato e, in ogni caso, dovrà attendere il codice di er-rore del master prima di riposizionarsi all'inizio.

Anche in questo caso, gli errori fisici porteranno sempre al codice di errore.

Page 28: Trasmissione Seriale - Andrea Asta

28

4.6 Unione degli algoritmi La parte finale è quella di unire gli algoritmi in precedenza progettati.

X = 'T'

Algoritmo"MASTER RICEVE"

Algoritmo"MASTER TRASMETTE"

LeggiX

Ancora?

Fine

Inizio

Yes

No

No Yes

Page 29: Trasmissione Seriale - Andrea Asta

29

5. Programmazione

5.1 Scelta del linguaggio di programmazione La scelta del linguaggio di programmazione è critica, nel senso che da essa dipendono alcune caratteristiche aggiuntive al progetto.

In generale, i linguaggi su cui scegliere sono stati il C++ e l'As-sembly 8086. E' stato preferito il C++ per i seguenti motivi:

Dispone di ottime librerie per la gestione delle funzioni fisiche RS232

E' un linguaggio strutturato, quindi il programma risulterà di comprensione più immediata

Fornisce interessanti routine predisposte per la gestione dei time-out

Contiene routine di utilizzo immediato per l'input e l'output con l'utente, sia per l'utilizzo della console video testuale che per la gestione dei file

5.2 Routine di base del programma Per prima cosa, utilizzando il C++, si definiscono alcune strutture dati considerate essenziali per la semplificazione del programma. Tipi di dati di base // Definizione del dato booleano enum bool { false = 0 , true }; // Definizione della word union integer { unsigned int word; struct { unsigned char low; unsigned char high; } byte; }; // Definizione del dato byte typedef unsigned char byte;

Nel caso del tipo di dato bool, è possibile che alcuni compilatori lo

implementino di default: se così non fosse, sarà necessario (e comodo) definirlo.

Il tipo byte, invece, è stato creato per rendere più immediata la comprensione del codice: del resto, questa nomenclatura è decisamen-te più efficace rispetto a "unsigned char".

Per quanto riguarda il tipo integer, esso permette di riferirsi ad una locazione da 2 byte indifferentemente in modo totale oppure riferendo-si ai singoli byte che lo compongono.

Il file di header bios.h include una funzione che permette la ge-stione delle porte seriali, che si serve degli interrupt hardware.

unsigned _bios_serialcom(unsigned cmd, unsingned serialport, unsigned data);

Page 30: Trasmissione Seriale - Andrea Asta

30

Utilizzando la documentazione della funzione, è possibile scrivere le routine di base di inizializzazione, invio e ricezione.

Tuttavia, per prima cosa, è necessario definire una routine per la gestione dello stato della porta seriale, che renda possibile anche la gestione di un timeout. In particolare, ci interesserà controllare lo stato finché non si ottiene uno stato ben definito (ad esempio, prima di rice-vere, aspetteremo che ci sia un nuovo dato), ma ovviamente fino ad un tempo massimo prefissato. Ci serviremo delle funzioni di clock della libreria time.h per gestire il clock.

Funzione di stato bool rs232_status (unsigned int mask, byte port, int secs) // 1 = Ok, 0 = Errore { // secs = 0 -> Ci provo una sola volta // secs < 0 -> Ci provo all'infinito (Attenzione, la routine ha il controllo del programma) clock_t start, end; start = end = clock(); integer result; bool esci = false; while ( ((end-start)/CLK_TCK <= secs || secs < 0) && !esci) { result.word = _bios_serialcom (_COM_STATUS , port, 0); // In ESCI ho il valore, devo fare la maschera result.word &= mask; if (result.word == mask) esci = true; end = clock(); } return esci; }

A questo punto si possono definire anche le funzioni di inizializza-

zione, invio e ricezione.

Inizializzazione porta seriale void rs232_initialize (byte protocol, int port) { _bios_serialcom (_COM_INIT , port, protocol); }

La funzione di inizializzazione può fornire solamente errori nella

linea del modem: utilizzando noi una connessione Null – Modem, è logico pensare che non vi saranno errori legati a questa periferica. Il valore di ritorno della funzione, pertanto, può essere ignorato.

Invio di un byte bool rs232_send (byte x, byte port, unsigned int secs) // 1 = Errori, 0 = Ok { // Aspetto che eventuali trasferimenti in corso siano terminati bool r = rs232_status (0x6000, port, secs); bool exit_value; // Se c'è stato un errore di timeout esco

Page 31: Trasmissione Seriale - Andrea Asta

31

if (r) { // Invio il carattere integer rs_res; rs_res.word = _bios_serialcom (_COM_SEND , port, x); // Maschero per controllare eventuali timeout fisici int mask = rs_res.byte.high & 0x80; if (mask) exit_value = true; else exit_value = false; } else exit_value = true; // C'è stato un errore return exit_value; }

Questa funzione attende che eventuali invii precedenti siano termi-

nati, quindi tenta l'invio e restituisce l'esito dell'operazione. Ricezione di un carattere bool rs232_receive (byte* dato, byte port, int secs) // 1 = Errori, 0 = Ok { integer result; // Aspetto che ci sia un dato da leggere bool s = rs232_status (0x0100,port,secs); bool exit_value; if (s) { // Non ci sono stati errori result.word = _bios_serialcom (_COM_RECEIVE , port, 0); // Maschero il risultato per vedere eventuali errori int mask = result.byte.high & 0x8E; if (mask) exit_value = true; else exit_value = false; } else exit_value = true; // Imposto il dato ricevuto nel parametro di output *dato = result.byte.low; return exit_value; }

In questa routine, si attende (nei limiti del timeout) che ci sia un

nuovo dato da leggere, quindi si procede con l'operazione e si restitui-sce il dato letto, più il controllo degli errori.

Page 32: Trasmissione Seriale - Andrea Asta

32

I controlli effettuati in queste routine sono legati al modo di opera-re della funzione di gestione della porta seriale (legata, a sua volta, agli interrupt BIOS), quindi si rimanda alla documentazione della stessa (allegata a questo documento) per maggiori dettagli.

Per semplificare il codice, infine, sono state definite delle costanti che riassumono i valori necessari allo strato fisico e allo strato logico.

Costanti di sistema // Secondi prima del timeout #define RS232_TIMEOUT 5 // Definizione del protocollo di comunicazione utilizzato #define RS232_PROTOCOL ( _COM_CHR8 | _COM_STOP1 | _COM_EVENPARITY | _COM_300 ) // Parole di comando #define RS232_MASTER_TR 0x0B #define RS232_SLAVE_TR 0x0C #define RS232_START_TR 0x01 #define RS232_END_TR 0x04 #define RS232_CHECKSUM_OK 0x59 #define RS232_CHECKSUM_ERR 0x4E #define RS232_ERROR 0x00 // Definizione della porta seriale #define COM1 0 #define COM2 1 #define COM3 2 #define COM4 3

E' stata inoltre scritta una funzione di errore generico, che si oc-

cuperà di inviare allo Slave il codice di errore e di stampare a schermo un messaggio di errore.

Routine di errore generico void generic_error(char* msg, byte port) { // Manda uno 0 allo slave byte command = 0; rs232_send (command,port,0); cout << "\a" << msg << "\a" << endl; return; }

Per quanto precedentemente assunto, si suppone che questa fun-

zione possa sempre essere eseguita, quindi si tralascia il ritorno di una variabile di controllo errori.

5.3 Traduzione degli algoritmi Una volta predisposte tutte le routine di gestione della porta seriale, è sufficiente tradurre in codice gli algoritmi precedentemente progettati. Una serie di condizioni annidate permetterà di ottenere un unico punto in cui gestire gli errori.

Dovendo gestire le stringhe come strutture statiche (l'utilizzo di strutture dinamiche complicherebbe il codice più di quanto in realtà sia necessario), stabiliamo che la lunghezza massima sia di 255 caratteri.

Page 33: Trasmissione Seriale - Andrea Asta

33

In questo modo, anche un eventuale programma che si serva di inter-rupt DOS per l'interazione esterna con l'utente potrà essere compatibile con la struttura del programma.

Infine, è importante decidere come avverrà l'interazione con l'uten-te: per comodità stabiliamo che l'utente potrà interagire con il pro-gramma mediante la console. Riceverà messaggi a schermo e potrà in-serire input da tastiera. Per la corretta gestione si utilizzeranno le fun-zioni di gestione della console previste in C++ dalla classe iostream.

5.5 Software di supporto Per testare il funzionamento del programma ci siamo serviti anzitutto del debugger integrato nel software Turbo C++, che ci ha permesso di eseguire ogni routine passo per passo e verificare quindi l'esito di ogni frammento di codice.

Ci siamo serviti inoltre di PROCOM, un software testato e fun-zionante per il trasferimento di dati attraverso la porta seriale. Una vol-ta programmata la porta, il programma stamperà a schermo tutto ciò che la porta riceve e invierà in output tutto ciò che viene digitato da ta-stiera. Il software gestisce la porta in modo diretto, andando a lavorare con i registri interessati, quindi il suo funzionamento è decisamente si-curo e affidabile.

5.6 Codice completo del programma Di seguito è riportato il codice intero del programma sviluppato. File rs_master.cpp #include <iostream.h> #include <conio.h> #include <dos.h> #include <string.h> #include <ctype.h> #include <time.h> #include <bios.h> #include <stdio.h> // Secondi prima del timeout #define RS232_TIMEOUT 5 // Definizione del protocollo di comunicazione utilizzato #define RS232_PROTOCOL ( _COM_CHR8 | _COM_STOP1 | _COM_EVENPARITY | _COM_300 ) // Parole di comando #define RS232_MASTER_TR 0x0B #define RS232_SLAVE_TR 0x0C #define RS232_START_TR 0x01 #define RS232_END_TR 0x04 #define RS232_CHECKSUM_OK 0x59 #define RS232_CHECKSUM_ERR 0x4E #define RS232_ERROR 0x00 // Definizione della porta seriale #define COM1 0 #define COM2 1 #define COM3 2 #define COM4 3

Page 34: Trasmissione Seriale - Andrea Asta

34

// Definizione del dato booleano enum bool { false = 0 , true }; // Definizione della word union integer { unsigned int word; struct { unsigned char low; unsigned char high; } byte; }; // Definizione del dato byte typedef unsigned char byte; // FUNZIONI DI SISTEMA RS232 // Stato della porta bool rs232_status (unsigned int mask, byte port, int secs = 0); // Inizializzazione della porta void rs232_initialize (byte protocol, int port); // Invio di un byte bool rs232_send (byte x, byte port, unsigned int secs); // Ricezione di un byte bool rs232_receive (byte* dato, byte port, int secs); // Routine generica di invio errore allo slave void generic_error(char* msg, byte port); // Programma principale int main () { // Pulizia dello schermo clrscr(); // Porta seriale utilizzata int port = COM1; // Protocollo utilizzato byte protocol = RS232_PROTOCOL; // Inizializzazione porta seriale rs232_initialize(protocol,port); // Carattere di comando e variabile di controllo byte command; // Carattere di eco e variabile di controllo byte echo; // Checksum e variabile di controllo byte checksum; // Esito della checksum e variabile di controllo byte cs_return; // Controllo del loop

Page 35: Trasmissione Seriale - Andrea Asta

35

int esci; bool errors; // Loop infinito do { // Trasmetto o ricevo? char tr; do { cout << "[T]rasmettere o [R]icevere?"; cin >> tr; tr = toupper (tr); } while (tr != 'T' && tr != 'R'); if (tr == 'T') { char str[256]; // Massimo 255 caratteri cout << "Dato da mandare: "; gets(str); int lung = strlen (str); // Calcolo della checksum checksum = 0; for (register int i = 0; i < lung; ++i) checksum ^= str[i]; // Voglio trasmettere command = RS232_MASTER_TR; if (!rs232_send(command,port,RS232_TIMEOUT)) { // Attendo l'eco if (!rs232_receive(&echo,port,RS232_TIMEOUT)) { // Controllo l'eco if (echo == RS232_MASTER_TR) { // Eco corretto // Inizio trasmissione command = RS232_START_TR; if (!rs232_send(command,port,RS232_TIMEOUT)) { // Attendo l'eco if (!rs232_receive(&echo,port,RS232_TIMEOUT)) { if (echo == RS232_START_TR) { // Eco corretto, mando il dato for (register int j = 0; j < strlen (str) && error == false; ++j) { command = str[j]; if (rs232_send(command,port,RS232_TIMEOUT)) error = true; } if (error == false) { // Fine trasmissione

Page 36: Trasmissione Seriale - Andrea Asta

36

command = RS232_END_TR; if (!rs232_send(command,port,RS232_TIMEOUT)) { // Attendo l'eco if (!rs232_receive(&echo,port,RS232_TIMEOUT)) { if (echo == RS232_END_TR) { // Eco corretto // Mando la checksum if (!rs232_send(checksum,port,RS232_TIMEOUT)) { if (!rs232_receive(&cs_return,port,RS232_TIMEOUT)) { if (cs_return == RS232_CHECKSUM_OK) { // Trasmissione corretta cout << "Trasmissione corretta" << endl; } else { // Trasmissione errata errors = true; } } else errors = true; } else errors = true; } else { // Eco errato errors = true; } } else errors = true; } else errors = true; } } else { // Eco errato errors = true; } } else errors = true; } else errors = true; }

Page 37: Trasmissione Seriale - Andrea Asta

37

else { // Eco errato if (echo == RS232_SLAVE_TR) { // Lo slave pensa di poter trasmettere! // ...ma noi siamo più furbi! // Ora facciamo un'imboscata allo slave... // ... facciamo finta di accettare la sua trasmissione... if (rs232_receive(&echo,port,-1)) { // E ora possiamo impostare l'errore errors = true; } } else errors = true; } else errors = true; } else errors = true; } else { // Master in ricezione char str[256]; // Massimo 80 caratteri int lung = 0; // Lunghezza della stringa ricevuta // Calcolo della checksum checksum = 0; // Voglio ricevere command = RS232_SLAVE_TR; if (!rs232_send(command,port,RS232_TIMEOUT)) { if (!rs232_receive(&echo,port,RS232_TIMEOUT)) { // Controllo l'eco if (echo == RS232_SLAVE_TR) { // Eco corretto, aspetto l'inizio della trasmissione if (rs232_receive(&command,port,-1)) { if (command == RS232_START_TR) { // Inizio trasmissione ricevuto, mando l'eco echo = RS232_START_TR; if (!rs232_send(echo,port,RS232_TIMEOUT)) { // Echo mandato // Ricevo il dato byte data_rx; do { if (!rs232_receive(&data_rx,port,RS232_TIMEOUT)) {

Page 38: Trasmissione Seriale - Andrea Asta

38

// Vediamo se è fine trasmissione if (data_rx != RS232_END_TR && data_rx != RS232_ERROR) { // E' un carattere str[lung++] = data_rx; checksum ^= data_rx; } else { if (data_rx == RS232_END_TR) { str[lung] = '\0'; } } } else errors = true; } while (data_rx != RS232_END_TR && data_rx != RS232_ERROR && errors == false); if (errors == false) { if (data_rx == RS232_END_TR) { // Trasmissione terminata, mando l'eco echo = RS232_END_TR; if (!rs232_send(echo,port,RS232_TIMEOUT)) { // Ora ricevo la checksum byte cs_received; if (!rs232_receive(&cs_received,port,RS232_TIMEOUT)) { if (cs_received == checksum) cs_return = RS232_CHECKSUM_OK; else cs_return = RS232_CHECKSUM_ERR; // Mando l'esito if (!rs232_send(cs_return,port,RS232_TIMEOUT)) { if (cs_return == RS232_CHECKSUM_OK) { // Trasmissione corretta cout << "RICEVUTO: " << str << endl; } else { // Trasmissione errata cout << "Trasmissione errata" << endl; } } else errors = true; } else errors = true; } else

Page 39: Trasmissione Seriale - Andrea Asta

39

errors = true; } else { // C'Š stato un errore, bisogna tornare all'inizio errors = true; } } } else errors = true; } else errors = true; } else errors = true; } else errors = true; } else errors = true; } else errors = true; } // Ci sono stati errori? if (errors == true) generic_error ("Errore nella comunicazione" , port); cout << "Ancora? (S/N)"; char risp = getche(); if (risp == 's' || risp == 'S') esci = 0; else esci = 1; } while (!esci); // Attesa del carattere getch(); return 0; } bool rs232_status (unsigned int mask, byte port, int secs) // 1 = Ok, 0 = Errore { // secs = 0 -> Ci provo una sola volta // secs < 0 -> Ci provo all'infinito (Attenzione, la routine ah il controllo del programma) clock_t start, end; start = end = clock(); integer result; bool esci = false; while ( ((end-start)/CLK_TCK <= secs || secs < 0) && !esci)

Page 40: Trasmissione Seriale - Andrea Asta

40

{ result.word = _bios_serialcom (_COM_STATUS , port, 0); // In ESCI ho il valore, devo fare la maschera result.word &= mask; if (result.word == mask) esci = true; end = clock(); } return esci; } void rs232_initialize (byte protocol, int port) { _bios_serialcom (_COM_INIT , port, protocol); } bool rs232_send (byte x, byte port, unsigned int secs) // 1 = Errori, 0 = Ok { // Aspetto che eventuali trasferimenti in corso siano terminati bool r = rs232_status (0x6000, port, secs); bool exit_value; // Se c'Š stato un errore di timeout esco if (r) { // Invio il carattere integer rs_res; rs_res.word = _bios_serialcom (_COM_SEND , port, x); // Maschero per controllare eventuali timeout fisici int mask = rs_res.byte.high & 0x80; if (mask) exit_value = true; else exit_value = false; } else exit_value = true; // C'Š stato un errore return exit_value; } bool rs232_receive (byte* dato, byte port, int secs) // 1 = Errori, 0 = Ok { integer result; // Aspetto che ci sia un dato da leggere bool s = rs232_status (0x0100,port,secs); bool exit_value; if (s) { // Non ci sono stati errori result.word = _bios_serialcom (_COM_RECEIVE , port, 0); // Maschero il risultato per vedere eventuali errori

Page 41: Trasmissione Seriale - Andrea Asta

41

int mask = result.byte.high & 0x8E; if (mask) exit_value = true; else exit_value = false; } else exit_value = true; // Imposto il dato ricevuto nel parametro di output *dato = result.byte.low; return exit_value; } void generic_error(char* msg, byte port) { // Manda uno 0 allo slave byte command = 0; rs232_send (command,port,0); cout << "\a" << msg << "\a" << endl; return; }

Page 42: Trasmissione Seriale - Andrea Asta

42

6. Conclusioni

6.1 Conclusioni La realizzazione di questo progetto si è rilevata ben più ostica di quan-to ci si aspettasse: la porta seriale, gestita mediante gli interrupt BIOS (come fanno le routine C++), è sicuramente di comprensione semplice, ma il suo funzionamento non è costante e, addirittura, un programma che funziona un giorno potrebbe non funzionare il giorno seguente.

Tuttavia, alla fine siamo riusciti a far funzionare adeguatamente il programma in ogni situazione, cercando di eliminare le limitazioni su-perflue e tentando di prevedere il maggior numero possibile di errori.

Il software finale risulta nel complesso funzionante e testato. Grazie a questa prova abbiamo appreso l'importanza del controllo

di un processo complesso quale la comunicazione tra due sistemi: ogni operazione deve essere rigorosamente controllata e ogni comando, per maggiore sicurezza, deve essere seguito da un eco. Trasmettendo un pacchetto di dati, inoltre, è necessario aggiungere un controllo sull'in-tero pacchetto, controllo che noi abbiamo aggiunto sotto forma di che-cksum.

Inoltre abbiamo completato il lavoro relativo alla trasmissione dati iniziata in precedenza con la trasmissione parallela: è da segnalare che la trasmissione seriale è decisamente più complessa da realizzare, in quanto i controlli da eseguire sono superiori rispetto a quelli per la tra-smissione parallela.

In conclusione, il progetto risulta completo, testato e funzionante.

6.2 Fonti Informazioni sulla trasmissione seriale

www.wikipedia.org Corso di Sistemi Volume 3 Presentazione Power Point (professoressa Amaroli) www.giobe2000.it

Informazioni e guida di riferimento funzioni C++ www.cplusplus.com http://www.cplusplus.com/ref/ctime/clock.html (funzione clock) http://www.delorie.com/djgpp/doc/libc/libc_68.html (funzione _bios_serialcom)

Page 43: Trasmissione Seriale - Andrea Asta

43

7. Allegati

7.1 Documentazione _bios_serialcom() _bios_serialcom

Syntax

#include <bios.h> unsigned _bios_serialcom(unsigned cmd, unsingned serialport, unsigned data);

Description

The _bios_serialcom routine uses INT 0x14 to provide serial communications services. The serial-port argument is set to 0 for COM1, to 1 for COM2, and so on. The cmd argument can be set to one of the following manifest constants:

_COM_INIT Initialize com port (data is the settings) _COM_RECEIVE Read a byte from port _COM_SEND Write a byte to port _COM_STATUS Get the port status

The data argument is ignored if cmd is set to _COM_RECEIVE or _COM_STATUS. The data ar-gument for _COM_INIT is created by combining one or more of the following constants (with the OR operator):

_COM_CHR7 7 bits/character_COM_CHR8 8 bits/character_COM_STOP1 1 stop bit _COM_STOP2 2 stop bits _COM_NOPARITY no parity _COM_EVENPARITY even parity _COM_ODDPARITY odd parity _COM_110 110 baud _COM_150 150 baud _COM_300 300 baud _COM_600 600 baud _COM_1200 1200 baud _COM_2400 2400 baud _COM_4800 4800 baud _COM_9600 9600 baud

The default value of data is 1 stop bit, no parity, and 110 baud.

Page 44: Trasmissione Seriale - Andrea Asta

44

Return Value

The function returns a 16-bit integer whose high-order byte contains status bits. The meaning of the low-order byte varies, depending on the cmd value. The high-order bits are as follows:

Bit Meaning if Set 15 Timed out 14 Transmission-shift register empty13 Transmission-hold register empty 12 Break detected 11 Framing error 10 Parity error 9 Overrun error 8 Data ready

When service is _COM_SEND, bit 15 is set if data cannot be sent.

When service is _COM_RECEIVE, the byte read is returned in the low-order bits if the call is suc-cessful. If an error occurs, any of the bits 9, 10, 11, or 15 is set.

When service is _COM_INIT or _COM_STATUS, the low-order bits are defined as follows:

Bit Meaning if Set 7 Receive-line signal detected 6 Ring indicator 5 Data-set-ready 4 Clear-to-send 3 Change in receive-line signal detected2 Trailing-edge ring indicator 1 Change in data-set-ready status 0 Change in clear-to-send status

Portability

ANSI/ISO C No POSIX No

Example

/* 9600 baud, no parity, one stop, 8 bits */ _bios_serialcom(_COM_INIT, 0, _COM_9600|_COM_NOPARITY|_COM_STOP1|_COM_CHR8); for(i=0; buf[i]; i++) _bios_serialcom(_COM_SEND, 0, buf[i]);

Page 45: Trasmissione Seriale - Andrea Asta

45

7.2 Documentazione clock() clock_t clock ( void );

Return number of clock ticks since process start. Returns the number of clock ticks elapsed. A macro constant called CLK_TCK defines the relation betwen clock tick and second (clock ticks per second).

Parameters.

(none)

Return Value. The number of clock ticks elapsed since start. clock_t type is defined by default as long int by most compilers.

Portability. Defined in ANSI-C.