Esercitazioni
PIC Baseline
|
21A - Applicazioni delle uscite digitali:
Trasmissione RS232.
Lo scopo dell' esercitazione è verificare la possibilità degli I/O
digitali del microcontroller, usati per generare segnali in una trasmissione
su linea RS232.
Abbiamo visto nella parte del corso dedicato ai Baseline essenzialmente applicazioni in cui sono messe in
finzione uscite digitali, accendendo LED.
Ovviamente le possibilità non si esauriscono a questo, ma, attraverso la
manipolazione di queste uscite digitali, possiamo sviluppare moltissime altre
applicazioni, ad esempio una comunicazione su seriale RS232.
Trasmettere dati su RS-232
Trasmettere su una line RS232 permette ad dispositivo governato da un
microcontroller di comunicare all' esterno, ad esempio verso un Personal
Computer, i risultati di una acquisizione
dati o lo stato del processo controllato.
Si tratta di una applicazione che pare complessa e che, usualmente, viene
demandata ad una periferica
specializzata (UART, USART, EUSART).
In effetti, si può realizzare una funzione simile con una semplice
movimentazione di un pin configurato come output digitale, con le temporizzazioni
opportune.
Questa soluzione diventa necessaria per i PIC delle famiglia Baseline, che sono privi di
modulo di comunicazione seriale, ma lo stesso principio è applicabile a qualsiasi altro
microcontroller delle famiglie superiori.
Vogliamo, dunque, trasmettere dati su RS-232, a partire dal PIC e verso un
personal computer.
Non implementiamo particolari protocolli, eseguendo una semplice trasmissione
bit bang in una modalità standard 9600,n,8,1 , ovvero 9600 baud, senza
parità, 8 bit più uno stop.
Non è compito di questo corso una descrizione dettagliata della
comunicazione seriale nello standard RS-232C. Se avete necessità di
informazioni sull' argomento, potete consultare queste
pagine o le molteplici altre presenti in rete. Qui, dobbiamo
specificare quanto ci riguarda per poter far si che il microcontroller possa inviare dati sulla linea
seriale RS-232.
In breve, si tratta di due punti essenziali: come avviene la
trasmissione e cosa dobbiamo utilizzare come interfaccia.
Come trasmettere il dato.
Come si trasmette un dato sulla linea seriale RS232?
Innanzitutto va detto che:
- i dati sono trasmessi solitalmente come byte, ovvero blocchi di 8 bit,
che è poi la larghezza del bus dati dei microcontroller di cui ci stiamo
occupando. Se devo trasmettere più bit, li suddividerò in più bytes.
- il byte viene trasmesso ponendo sulla linea un bit dopo l' altro,
iniziando dal meno significativo. Ovvero, viene trasmesso per primo il bit
0 e per ultimo il bit 7
- il bit resta in linea per un tempo prestabilito, dato che la
trasmissione è del tipo asincrono e non prevede un clock separato dal segnale. Questo, se fa risparmiare un conduttore,
richiede una temporizzazione precisa durante la trasmissione dei bit.
Questa temporizzazione è standardizzata e suddivisa in valori multipli di
75, denominati baudrate, e che esprimono la frequenza con cui i bit sono
inviati in linea. Abbiamo così valori di baudrate che vanno da 75 a 19200Hz
(75/150/300/1200/2400/4800/9600/19200). Inizialmente, questi limiti erano dovuti alla bassa
velocità delle periferiche e delle linee di trasmissione ed alla ridotta
capacità di elaborazione dei circuiti elettronici (lo standard ha oltre 40
anni di età e nasce in un periodo in cui molte periferiche erano totalmente
elettromeccaniche, come le telescriventi). Più recentemente sono diventati
comuni baudrate maggiori (standard RS-562 a 64kHz), mentre nei personal
computer sono possibili velocità superiori a 115200Hz e più, data la più elevata
capacità di elaborazione disponibile.
Usualmente la trasmissione è gestita da una periferica dedicata, denominata UART,
USART, EUSART, che scarica il processore (e il programma) dalla
gestione della comunicazione, la quale, dove siano presenti segnali di controllo e
flusso bidirezionale (full duplex) può essere molto complessa.
Però, dato che la trasmissione di un bit richiede un tempo molto maggiore di
quanto un attuale microcontroller impieghi per eseguire un ciclo di istruzione, ne deriva che, nonostante esistano queste periferiche specifiche,
dove non siano richieste prestazioni elevate, la trasmissione e la ricezione
sono possibili anche utilizzando i semplici I/O digitali maneggiati dal
programma. Possiamo così far comunicare in seriale anche piccoli PIC come i
Baseline, che non dispongono di modulo UART integrato
Poichè operiamo attraverso una emulazione software dell' attività di un
UART, ovvero determinando interamente dal programma la gestione della
comunicazione, dobbiamo limitare la frequenza di trasmissione alle possibilità
di elaborazione del microcontroller, dove l' unico modo per valutare il tempo è dipendente dal suo clock.
Con un clock di
4MHz è possibile arrivare a 19200 baud e più; utilizzando un quarzo esterno si otterrà una ottima precisione e
stabilità dei tempi, ma questo richiede componenti addizionali e determina
una perdita di pin cosa poco gradita su microcontroller con un pinout
limitato.
Se, invece, utilizziamo l'oscillatore interno, recuperiamo pin e non abbiamo bisogno di altri
componenti. Per contro, riduciamo precisione e stabilità. All'atto pratico,
però, si può verificare che l'1% di errore eventualmente introdotto dall' oscillatore
interno non influisce su una trasmissione con frequenze fino a 9600 baud.
Ovviamente sarà indispensabile la calibrazione dell' oscillatore.
9600 baud indica che abbiamo un periodo
di:
periodo = 1/f = 1/9600 = 104.166us
Con un clock di 4MHz, abbiamo un ciclo istruzione di 1us e
dovremo arrotondare il periodo calcolato a 104us.
Per ottenere il preciso valore dobbiamo usare un clock multiplo del valore voluto, ad esempio
1.8432MHz o 2.4576MHz e simili, il che necessita di un quarzo esterno, con i
relativi componenti.
Però, se valutiamo l' errore di tempo che si ottiene utilizzano 104us al
posto di 104,166us, considerando anche il possibile errore dell' oscillatore
interno (1%) esso risulta inferiore all'2% e questo valore è tollerato dalla
maggior parte dei sistemi di ricetrasmissione. Queste considerazioni sono
valide per frequenze di comunicazione non eccessivamente elevate (dove la breve durata dell' impulso
relativo ad ogni bit richiede una altrettanto elevata precisione del tempo di
emissione).
Un altro punto da considerare riguarda il formato del dato da trasmettere:
- gli 8 bit del dato vero e proprio richiedono un bit addizionale di start ed uno di stop.
Il loro scopo è quello di informare l' apparato ricevente dell' inizio e
della fine della trasmissione, permettendo il sincronismo tra
trasmettitore e ricevitore.
Solitamente si utilizza il tempo di un impulso per lo start ed altrettanto
per lo stop, ottenendo così la trasmissione di 10 bit per ogni 8 di dati
effettivi (start + 8bit dati + stop). Ad essi può essere aggiunto un bit di
parità che ha lo scopo di aumentare la sicurezza della trasmissione, bit che
nel nostro esempio non aggiungiamo.
|
In sostanza, dovendo trasmettere il byte di valore '10111110'
dovremo variare il livello del pin usato per la trasmissione come nel
diagramma a lato.
Ogni bit viene sostenuto sulla linea per il tempo stabilito dal
baudrate. La trasmissione del dato inizia con il bit di start e
termina con quello di stop. |
Ne risulta che la trasmissione, al minimo, è composta da 10 impulsi pari al
valore del bit trasmesso, della durata ognuno di 104us, ovvero
complessivamente un byte viene inviato in 10x104=1.040ms. Questo è un
risultato facilmente ottenibile, ad esempio nel modo simile a quanto abbiamo
visto nelle esercitazioni precedenti. Si tratta solo di comandare
opportunamente un pin di I/O configurato come uscita digitale.
Osserviamo che viene inviato per primo il bit 0, il meno significativo, e
per ultimo il bit 7 del dato (il byte è trasmesso "al contrario",
cioè va letto da destra verso sinistra).
Una ultima considerazione: quanto detto, se è sufficiente dal punto di vista del programma, non lo è da
quello dell' hardware, nel senso che il microcontroller e la linea RS-232
hanno livelli di tensione molto differenti: il microcontroller è alimentato
da una unica tensione positiva rispetto alla massa, tipicamente tra 3 e 5V. La
linea RS232 impegna una tensione bipolare che varia tra +V e -V.
|
La linea si trova normalmente nello stato di riposo (MARK o idle
- nessun dato in transito), alla massima tensione negativa; la
transizione di livello passa da segnale negativo a positivo (SPACE
- massima tensione positiva) e indica l’inizio della trasmissione,
ovvero il bit di start).
La tensione positiva può spaziare tra 3 e 25V ed altrettanto quella
negativa. In pratica, nei PC si utilizzano il +12V e il -12V
forniti dall' alimentatore AT/ATX. |
Per comandare la linea RS-232, a tensione bipolare e
con un livello maggiore, occorre una interfaccia tra microcontroller e linea
seriale. Questa è facilmente realizzabile, dato che sono stati costruiti
numerosi circuiti integrati che effettuano questa conversione di livello, cosa
peraltro possibile anche con semplici transistor.
Da notare che, per la logica dello standard, si ha l' equivalenza riportata
nella tabella precedente, che comporta una "inversione" e i circuiti
di interfaccia sono effettivamente invertenti; si ha, quindi, questa
equivalenza:
Bit |
Microcontroller |
RS-232 |
0 |
Vss (0V) |
+12V |
1 |
Vdd (5V) |
-12V |
Ne deriva che, sul lato microcontroller, il pin di uscita dovrà essere
comandato in questo modo:
ovvero, a riposo, l'uscita si trova a livello alto.
Vediamo, dunque, che la trasmissione consiste in una semplice manipolazione
dell'I/O tra i livelli 1 e 0 secondo temporizzazioni precise, cosa che
possiamo fare con le istruzioni bcf e bsf e valutando i tempi attraverso la
durata delle istruzioni stesse.
Ma per prima cosa come aggiungere al nostro circuito l' interfaccia
richiesta.
Hardware RS-232
Abbiamo detto che la trasmissione del nostro microcontroller sarà diretta
al personal computer. Però va fatta una osservazione: dopo l' avvento dell' USB
(che è pure un protocollo seriale), la connessione RS-232, che fino a poco
tempo fa era presente in tutti i personal, attualmente è diventata
piuttosto rara, nonostante sia ancora la principale interfaccia usata dai
sistemi industriali, principalmente per la sua semplicità di implementazione
e le sue caratteristiche che ben si prestano alla trasmissione di dati tra
apparati digitali nell' ambito della strumentazione, del controllo di
processo, delle periferiche dedicate, ecc.
|
E' evidente che volete ricevere una comunicazione RS-232 sul vostro
PC, è necessario che questo disponga della relativa interfaccia. Anche
se su una buona parte dei personal desktop una linea seriale è
presente, questo non è vero per i portatili, dove parallela e seriale
sono sparite, sostituite da USB.
Se sul vostro personal computer non è presente una connessione
RS-232, essa può essere realizzata molto facilmente con l' aggiunta
di una scheda sul bus PCI o PCIe per i desktop oppure, più semplicemente, con un
dongle che trasforma un port USB in un port RS-232, soluzione adatta
per i notebook. Questi oggetti
sono facilmente reperibili ed hanno un costo limitato.
|
Un secondo problema riguarda la necessità di applicare al microcontroller
una interfaccia che adegui l' uscita digitale al livello di tensione della
linea seriale.
La nostra LPCuB non ha a bordo una simile interfaccia, in quanto
abbiamo detto che la RS-232 è solamente una delle tante possibili modalità
di comunicazione seriale.
Però esiste una predisposizione per il collegamento di moduli di interfaccia
esterni.
|
In questo modo sarà possibile sperimentare non solo RS-232,
ma anche RS-422, RS485, Current Loop, USB,
SATA, Ethernet, LIN, CAN, I2C,
comunicazioni sincrone, bus per domotica, ecc., tutte gestibili dal
microcontroller, attraverso interfacce specifiche, tra di loro assai
diverse.
Per dare il più ampio spettro di possibilità, non è stata
integrata nella scheda alcuna interfaccia specifica, rimandando all'
uso di elementi esterni, peraltro spesso assai semplici e poco
costosi, quasi tutti realizzabili in casa da un hobbista attrezzato.
Anche perchè, pur restando semplicemente nel campo della RS-232,
l' interfaccia con la linea può essere realizzata in molti modi e non
solo con chip specifici, come MAX232 o MAX3232 di Maxim, Texas, ecc.. |
Una interfaccia con la linea RS-232 di facile realizzazione è descritta
qui.
|
Se si preferisce il già pronto, esistono moltissimi prodotti
commerciali, ad esempio i moduli di Mikroelektronika, per i quali
occorre realizzare solamente il cavetto di connessione.
In ogni caso il WEB offre una miriade di adattatori analoghi e c'è
solo l'imbarazzo della scelta.
|
Schema elettrico.
C'è poco da dire sullo schema elettrico. Un solo pin è utilizzato per la
connessione all'interfaccia RS232.
Viene usato il pin GP2, che è collegato
ad una interfaccia per la linea RS232 attraverso il JSC e da questa al
PC con un cavetto DB9 M/F. Utilizzando un driver MAX232/MAX3232 la lunghezza
della connessione non dovrà superare i 25m.
Il chip usa il suo clock interno a 4MHz.
Sulla LPCuB l'unico collegamento è quello tra il pin di trasmissione e il
connettore di uscita, dove si trova collegata l'interfaccia seriale.
Come al solito, osservare la posizione del chip nello zoccolo e quella dei
due jumper "blu" di selezione.
Il programma
Come primo esempio, trasmettiamo un breve messaggio, cadenzato una volta
ogni secondo.
Per rilevare la trasmissione dovremo utilizzare sul PC un qualunque emulatore di terminale, dal Hyperterminal
di Windows ad uno dei tanti free o share disponibili sul WEB (Realterm,
Terminal.exe,
ecc.).
Dal lato del microcontroller la soluzione più semplice consiste nel creare
una subroutine che effettui le operazioni di movimentazione dei bit necessari
all'invio di un byte di dati. In questo modo abbiamo un blocco software che
potremo usare in ogni altra circostanza; La routine consente essenzialmente di
aggiungere una porta di uscita seriale a qualsiasi PIC.
;********************************************************************
;--------------------------------------------------------------------
; XMIT-232.asm
;
; Titolo : Trasmissione di 8 bit + 1 bit di start e
1 bit di stop
;
no parità a 9600 (9600,8,N,1).
;
Il dato da trasmettere è passato attraverso W.
;
Uscita su un qualsiasi I/O digitale (Txpin) per comando
;
di driver invertente.
;
Se usato con collegamento diretto bcf txpin va cambiato
;
in bsf txpin e viceversa.
;
9600 ->104.166us approssimato a 104us
; PIC : Baseline
; Supporto : MPASM
; Versione : 1.0
; Risorse : RAM necessaria 3 bytes: bitcntr, d1, savew
; Data : 01-05-2013
; Ref. hdw :
; Autore : afg
;
;********************************************************************
;####################################################################
Xmit232 movf savew
; salva dato da trasmettere
movlw
8 ; 8
bit
movwf
bitcntr
; start bit
bcf
txpin ; start bit ---|
movlw
0x22 ; 97 cicli
|
movwf
d1 ;
|
xmt0 decfsz d1, f
;
|
goto
xmt0 ; 97us
goto
$+1 ;
2us
; data byte
|
xmtlp rrf
savew,f ; lsb prima 1us--1us
skpnc
; 1us
2us
goto
xmt1 ;
2us |
skpc
;
| 1us
bcf
txpin ;
| 1us¬104us (5us)
goto
xmt2 ;
|
2us
xmt1 bsf
txpin ;
1us¬104us----(5us) |
goto
$+1 ;
2us |
xmt2 movlw 0x1F
; 94 cicli
| |
movwf
d1 ;
| |
xmt3 decfsz d1, f
;
| |
goto
xmt3 ;
94us 94us
decfsz
bitcntr ;
1us 2us
goto
xmtlp ;
104us¬2us |
; stop bit
|
bsf
txpin ; stop bit
104us¬1us
movlw
0x21 ; 100 cicli ----|
movwf
d1 ;
|
xmt4 decfsz d1, f
;
|
goto
xmt4 ;
100us
goto
$+1 ;
2us
retlw
0 ;
2us¬104us
;********************************************************************
;#################################################################### |
Il dato da trasmettere viene passato attraverso W e viene salvato in una
locazione temporanea (savew). Viene
trasmesso il bit di start da 104us, quindi gli 8 bit del dato. E' usata l'
istruzione di rotazione verso destra, che manda al Carry il bit meno
significativo. Il suo valore viene riflesso sul pin di uscita.
Un contatore caricato con 8 (bitcntr)
viene decrementato ad ogni emissione, che dura 104us, per determinare gli 8
bit da trasmettere.
Da osservare che le temporizzazioni, basate sulla durata del ciclo
istruzione, sono calcolate per un clock di 4MHz (Tcyc = 1us). Con clock
di frequenza diversa occorrerà ricalcolare i tempi; così, per un clock di
8MHz (tcyc = 500ns), la trasmissione avverrà a velocità doppia (19200 baud).
Accanto alle linee di istruzione è aggiunto come commento il conteggio dei
cicli. Possiamo vederlo nel dettaglio.
Per il bit di start la situazione è semplice:
; start bit
bcf
txpin ; start bit ---|
movlw
0x22 ; 97 cicli
|
movwf
d1 ;
|
xmt0 decfsz d1, f
;
|
goto
xmt0 ; 97us
goto
$+1 ;
2us
; data byte
|
xmtlp rrf
savew,f ; lsb prima 1us--1us
skpnc
; 1us
2us
goto
xmt1 ;
2us |
skpc
;
| 1us
bcf
txpin ;
| 1us¬104us (5us)
goto
xmt2 ;
|
2us
xmt1 bsf
txpin ;
1us¬104us----(5us) |
goto
$+1 ;
2us | |
Dal momento in cui viene clearato il txpin
(1us) al test del bit da trasmettere viene inserito un ritardo di 97us, per un
totale di 99us e si innesta nel test del bit dati da trasmettere. La verifica
del valore del bit viene effettuata sul Carry, in cui la rotazione rrf
savew,f sposta il bit meno significativo; questa sequenza impiega
5us, per il totale voluto di 104us tra il momento di inizio del bit di start e
quello del primo bit dati (i branch skpnc/skpc
impiegano 1us se non effettuano il salto e 2us se lo effettuano). 2us sono
addizionati dal goto $+1
per pareggiare i due rami della selezione.
Una volta che il primo bit di dati è posto in uscita, viene inserita una
attesa di 94us. Sono quindi necessari 3us per verificare la condizione del
contatore dei bit da trasmettere, per un totale di 99us.
Ora il l riparte dal test del bit successivo, che andrà "in linea"
dopo 5us. Il bit precedente è rimasto "in linea" per i 104us
richiesti (99+5).
; data byte
|
xmtlp rrf
savew,f ; lsb prima 1us--1us
skpnc
; 1us
2us
goto
xmt1 ;
2us |
skpc
;
| 1us
bcf
txpin ;
| 1us¬104us (5us)
goto
xmt2 ;
|
2us
xmt1 bsf
txpin ;
1us¬104us----(5us) |
goto
$+1 ;
2us |
xmt2 movlw 0x1F
; 94 cicli
| |
movwf
d1 ;
| |
xmt3 decfsz d1, f
;
| |
goto
xmt3 ;
94us 94us
decfsz
bitcntr ;
1us 2us
goto
xmtlp ;
104us¬2us | |
Esauriti i bit da trasmettere, occorre aggiungere alcuni microsecondi per
compensare il loop non più eseguito, aggiungendo 5us:
decfsz
bitcntr ;
1us 2us
goto
xmtlp ;
104us¬2us |
; stop bit
|
bsf
txpin ; stop bit
104us¬1us
movlw
0x21 ; 100 cicli ----|
movwf
d1 ;
|
xmt4 decfsz d1, f
;
|
goto
xmt4 ;
100us
goto
$+1 ;
2us
retlw
0 ;
2us¬104us |
A questi si somma il ciclo iniziale dello stop bit, per il totale voluto di
104us.
Alla fine, il bit di stop dura anch'esso, per pignoleria, 104us; all' atto
pratico, si potrebbe risparmiare l' ultimo goto
$+1 dato che, a questo punto, la routine è rilasciata e le
istruzioni del mainloop aggiungeranno
anche più dei 2us mancanti. In pratica, lo stop bit è una situazione di
linea "vuota" (idle o MARK) che è prevista per permettere alla
periferica ricevente di trattare il dato e predisporsi per quello successivo
ed ha una lunghezza minima, ma non un massimo, dato che dopo di esso la
trasmissione potrebbe anche essere sospesa per qualsiasi durata di tempo.
Da notare che clrc e sknc
sono pseudo opcode di MPASM; l' editor a colori evidenzia la differenza.
Una volta scritta questa subroutine, il main risulta del tutto banale:
; invia il messaggio sulla linea RS232
txloop movlw 0
; azzera puntatore
movwf index
txlp1 call TxTable
; prendi carattere dalla tabella
movwf savew
; salva provvisoriamente
xorlw 0
; ultimo carattere ?
skpz
; si, salta
goto nextchr
; no, riprendi
; fine caratteri - trasmette CR & LF
movlw 0x0D
; CR
call
Xmit232
movlw 0x0A
; LF
call
Xmit232
call
Delay1s ; attesa 1s
goto
txloop ; loop continuo
nextchr movf savew,w
; recupera carattere
call
Xmit232 ; invia il carattere in linea
incf
index,f ; aggiorna puntatore
movf
index,w
goto
txlp1 ; loop del messaggio |
Vengono trasmessi in successione i caratteri del messaggio, dopo di che
viene emessa la coppia carriage
return (CR) e line feed (LF), seguita da una attesa di 1 secondo. Poi il ciclo
ricomincia.
Il messaggio è costituito da una semplice lookup table costituita da una
tabella retlw che è chiusa da uno 0.
; Tabella messaggio
; Il messaggio termina con 0
TxTable addwf PCL,f
dt "Hello !",0 |
La tabella e le subroutines per la trasmissione e per il ritardo di 1 secondo sono
incluse all' inizio del sorgente, date le pesanti limitazioni che impongono i
Baseline.
; include subroutines
; trasmissione 9600n81 @ 4MHz
#include C:\PIC\LIBRARY\Baseline\Xmit232.asm
; ritardo di 1s @ 4MHz
#include C:\PIC\LIBRARY\Baseline\Delays\Delay1s.asm |
Ovviamente, se nel vostro hard disk le subroutines sono conservate
diversamente, occorrerà adeguare il relativo path di inclusione.
|
Ecco come si presenta all' oscilloscopio la prima parte della trasmissione.
Si notano bene le diverse durate degli impulsi a seconda che si
stia trasmettendo un 1 o uno 0. |
|
Ed ecco il messaggio ricevuto nella finestra di
RealTerm,
che consente di visualizzare anche i caratteri ASCII di controllo CR e
LF. |
Il sorgente è fornito all'interno del completo progetto
MPLAB. Questo è
stato verificato su un PIC10F206. Se usate un diverso componente, modificate
la selezione del chip dal menù Configuration. Il sorgente si compila per 10F200/202/204/206, ma è facilmente portabile
su qualsiasi altro PIC di qualsiasi famiglia, semplicemente cambiando la
definizione del processore,
il relativo config e l'adattamento dell' I/O digitale utilizzato.
|