Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Trasmissione
Seriale
Standard RS232/C
Protocollo Master/Slave con Eco
Sviluppato in Linguaggio C++
Andrea Asta
Autore del fascicolo
Nome Andrea Asta
Sito Web www.andrea-asta.com
Email asta.andrea@tin.it
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
2
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.
3
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.
5
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.
6
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.
Sistema Sistema
A B
Port Port
Connessione fisica
X1 X2
Sistema Sistema
A B
Parallel Parallel
#01 n #02
Serial Serial
#01 #02
7
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.
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
Linea
telefonica
Seriale Seriale
8
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.
8
UART
uP
8250
9
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:
1
1 baud = bps
n
1
1 baud = bps
log 2 k
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.
10
Dato
'1'
d0 d1 d2 d3 d4 d5 d6 d7 S
t
Riposo Dato Stop + Riposo
Start
Dato
T/2 T
Campionamenti
'1'
d0 d1 d2 d3 d4 d5 d6 d7 S1 S2
t
11
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'
d0 d1 d2 d3 d4 d5 d6 d7 P S1 S2
t
Riposo Dato
Start Parità
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.
12
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.
13
La tabella seguente illustra i nomi dei 9 segnali significativi per lo
standard.
DTE DCE
TD TD
RD RD
RTS RTS
CTS CTS
DCD DCD
DTR DTR
DSR DSR
SGND SGND
RI RI
14
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 DCE
TD TD
RD RD
RTS RTS
CTS CTS
DCD DCD
DTR DTR
DSR DSR
SGND SGND
RI RI
DTE1 DTE2
TD TD
RD RD
RTS RTS
CTS CTS
DCD DCD
DTR DTR
DSR DSR
SGND SGND
RI RI
b7 b0
V2 V1 V0 P1 P0 S L1 L0
16
b7…b5 Baud Rate (baud)
000 110
001 150
010 300
011 600
100 1200
101 2400
110 4800
111 9600
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
b1-b0 Parità
00 Configurazione non ammessa
01 Configurazione non ammessa
10 Parole a 7 bit
11 Parole a 8 bit
18
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 della
checksum 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.
19
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.
21
01
Eco
04
02
Dato (Errore)
05
00
22
Errore nel primo eco – Lo Slave pensa di ricevere
Master in ricezione
Master Slave
Decisione
01
0C
Eco
02
0B
Inizio trasmissione (Errore)
03
00
23
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.
24
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.
25
Inizio
Invia
0Bh
Eco Eco
Ricezione
= =
a vuoto
0Bh 0Ch
Yes
Yes
Invia
01h
Eco
=
01h
Yes
Invia
Dati
Invia
04h
Eco
=
04h
Yes
Invia
Checksum
Invia
00h
Yes Esito
=
59h
Trasmissione Trasmissione
corretta errata
Fine
26
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
27
4.6 Unione degli algoritmi
La parte finale è quella di unire gli algoritmi in precedenza progettati.
Inizio
Leggi
X
Yes No
X = 'T'
Algoritmo Algoritmo
"MASTER TRASMETTE" "MASTER RICEVE"
Yes
Ancora?
No
Fine
28
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
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.
29
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;
}
Invio di un byte
bool rs232_send (byte x, byte port, unsigned int secs)
// 1 = Errori, 0 = Ok
{
bool exit_value;
// Se c'è stato un errore di timeout esco
30
if (r)
{
// Invio il carattere
integer rs_res;
rs_res.word = _bios_serialcom (_COM_SEND , port, x);
if (mask)
exit_value = true;
else
exit_value = false;
}
else
exit_value = true; // C'è stato un errore
return exit_value;
Ricezione di un carattere
bool rs232_receive (byte* dato, byte port, int secs)
// 1 = Errori, 0 = Ok
{
integer result;
bool exit_value;
if (s)
{
// Non ci sono stati errori
result.word = _bios_serialcom (_COM_RECEIVE , port, 0);
if (mask)
exit_value = true;
else
exit_value = false;
}
else
exit_value = true;
31
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
// 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
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.
32
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.
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>
// 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
33
// Definizione del dato booleano
enum bool { false = 0 , true };
// 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);
// Programma principale
int main ()
{
// Protocollo utilizzato
byte protocol = RS232_PROTOCOL;
34
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);
// 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
35
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;
}
36
else
{
// Eco errato
if (echo == RS232_SLAVE_TR)
{
// Lo slave pensa di poter trasmettere!
// ...ma noi siamo più furbi!
}
else
errors = true;
}
else
errors = true;
}
else
{
// Master in ricezione
char str[256]; // Massimo 80 caratteri
int lung = 0; // Lunghezza della stringa ricevuta
// 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))
{
37
// 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
38
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;
} while (!esci);
39
{
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;
}
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);
if (mask)
exit_value = true;
else
exit_value = false;
}
else
exit_value = true; // C'Š stato un errore
return exit_value;
integer result;
bool exit_value;
if (s)
{
// Non ci sono stati errori
result.word = _bios_serialcom (_COM_RECEIVE , port, 0);
40
int mask = result.byte.high & 0x8E;
if (mask)
exit_value = true;
else
exit_value = false;
}
else
exit_value = true;
41
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
42
7. Allegati
7.1 Documentazione _bios_serialcom()
_bios_serialcom
Syntax
#include <bios.h>
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.
43
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:
15 Timed out
14 Transmission-shift register empty
13 Transmission-hold register empty
12 Break detected
11 Framing error
10 Parity error
9 Overrun error
8 Data ready
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:
Portability
ANSI/ISO C No
POSIX No
Example
44
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.
45