I Microcontrollore PIC18FXX2
Descrizione
dei microcontrollori
I microcontrollori sono dei
dispositivi elettronici di piccole dimensioni che, per molti versi, possono
essere assimilati a dei veri e propri computer. Essi, infatti, contengono al
proprio interno tutti i dispositivi tipici di un sistema a microprocessore,
ovvero:
La presenza di tutti questi
dispositivi in uno spazio estremamente contenuto, consente al progettista di
avvalersi degli enormi vantaggi derivanti dall'uso di un sistema a
microprocessore, anche in quei circuiti che fino a poco tempo fa erano
destinati ad essere realizzati con circuiterie tradizionali.
La memoria non volatile
serve a contenere il programma software che dovrà essere eseguito ripetutamente
affinché il dispositivo svolga la funzione desiderata. La memoria volatile, ha
il compito di immagazzinare i dati elaborati dall’ALU; le linee di I/O,
collegate a numerosi piedini che fuoriescono dalla struttura del
microcontrollore, servono ad interfacciare il dispositivo con il mondo esterno.
Quasi sempre questi dispositivi contengono al loro interno anche altri circuiti
per comunicazioni seriali, dei comparatori e dei convertitori Analogico/Digitale.
Le funzioni delle porte di I/O e i rispettivi stati logici sono direttamente
controllabili dal firmware contenuto nella memoria flash del microcontrollore
(interpretato dall’unita logica), questo consente, ad esempio, di collegare un
pulsante ad una porta d’ingresso per poter rilevare il suo stato, e, in
conseguenza di questo accendere o spegnere un LED collegato ad un piedino
d’uscita.
Ovviamente, per realizzare
tale funzione, dovremo scrivere un programma adatto allo scopo. Prima di
procedere alla stesura del software è consigliabile descrivere “a parole” le
operazioni da eseguire, tracciando cioè quello che viene chiamato “Flow chart”,
un diagramma di flusso della sequenza delle operazioni da impartire al nostro
dispositivo.
Variando semplicemente
il firmware lo stesso dispositivo che legge il pulsante e accende il LED, può
essere utilizzato indifferentemente per leggere una tastiera, pilotare un
display, controllare la velocità di un motore e quant’altro si possa
immaginare. Il microcontrollore è dunque un dispositivo che non si può usare
così come si compra, poiché, ovviamente, viene venduto senza alcun programma
inserito al suo interno.
Il programma deve
essere memorizzato dopo l’acquisto, allo stesso modo in cui si programma una
normale memoria Eprom, utilizzando, però, un programmatore apposito, che varia
a seconda della famiglia di controllori.
I programmi per i PIC
vengono generalmente scritti in un linguaggio assembler o, a livello più
professionale, in C, Basic o altri linguaggi di programmazione ad alto livello.
Il programma scritto
in assembler [C], viene poi assemblato [compilato], ovvero tradotto in una
sequenza di byte (codice macchina comprensibile dal dispositivo) che,
memorizzata nella memoria interna, permette al microcontrollore di lavorare nel
modo desiderato.
Esistono diverse famiglie di dispositivi in grado di
svolgere queste funzioni come ad esempio lo Z80, ST6 e il più evoluto 8088; tra
i più semplici e diffusi dispositivi oggi in commercio ci sono i cosi detti
PIC, prodotti e distribuiti dalla Microchip.
Le famiglie di
Microcontrollori
Fin dalla sua nascita
è apparsa evidente l’enorme potenzialità di questi dispositivi e le case
produttrici di componenti elettronici hanno investito moltissimo nella ricerca
e nello sviluppo di dispositivi sempre più completi e prestanti.
Questo ha determinato
la nascita di tutta una serie di dispositivi che differiscono per diverse
caratteristiche funzionali. In particolare, parlando di microcontrollori, si fa
generalmente riferimento alle famiglie, intendendo con questo termine dei
dispositivi che hanno in comune diverse caratteristiche, fra cui ad esempio il
linguaggio di programmazione (che è per tutte l’assembler, ma le cui singole
istruzioni variano a seconda dei dispositivi), l’organizzazione della memoria
interna, la gestione delle periferiche e così via.
All’interno di ogni
famiglia, vi sono diversi dispositivi con caratteristiche differenti da uno
all’altro (più o meno memoria, velocità di funzionamento, presenza di
periferiche analogiche quali convertitori e così via) per rispondere al meglio
alle esigenze di un certo progetto.
E’ abbastanza
intuitivo, infatti, che realizzare un semplice circuito per fare accendere e
spegnere dei LED richiede componenti con prestazioni ben diverse rispetto, ad
esempio, ad una centralina antifurto programmabile.
Una breve panoramica sui
Microcontrollori
I Microcontrollori si
distinguono per il numero di bit che riescono ad elaborare contemporaneamente,
per la quantità di memoria dati di cui dispongono, per la quantità di memoria
riservata ai programmi, per la tipologia di quest’ultima, per la quantità di Timer a disposizione etc.
La grande maggioranza
dei micro è ad 8 bit, ma esistono famiglie a 16 bit ed anche a 32 bit. Questi
ultimi sono i più rari e, ovviamente, i più costosi.
Fra i dispositivi ad 8
bit, sicuramente il capostipite è stato l’8051, prodotto dall’Intel, che ha
dato luogo a tutta una serie di derivati con prestazioni sempre superiori.
Un altro gigante
dell’elettronica, Motorola, è ben rappresentato nel mercato degli 8 bit
attraverso il 68HC11. Motorola, per inciso, è uno dei maggiori produttori di
micro a 16 e 32 bit, che sono dei derivati del famoso 68000. Anche la Zilog
(Z80) ha una famiglia di micro a 8 bit, gliZ8, che presentano delle caratteristiche
elevate per quanto riguarda il rapporto costo/prestazioni.
SGS-Thomson produce
gli ST6, una famiglia di micro che ha avuto una larga diffusione soprattutto
sul mercato europeo.
Fra gli ultimi
arrivati, ma diventati in breve tempo i microcontrollori più significativi ed
importanti, troviamo i PIC, prodotti da un’azienda americana, l’Arizona
Microchip specializzata proprio nella costruzione di microcontrollori ad 8 bit
e di memorie EPROM.
Le memorie non
volatili, necessarie per la memorizzazione del programma, differiscono, come
gia detto, oltre che per la quantità anche per il tipo. Esistono PIC con
memorie di tipo EEPROM, cioè cancellabili e riscrivibili elettronicamente, con
memorie di tipo Flash, che sono da preferire nelle fasi di sperimentazione
grazie al maggior numero di scritture possibili; ne esistono versioni con
memorie OTP (One Time Programmable), cioè si programmano una sola volta,
versioni UV con memoria che una volta scritta può essere cancellata solo
mediante raggi ultravioletti.
La Famiglia Microchip
PIC18FXX2
I microcontrollori PIC della famiglia 18FXX2 sono contenuti in packages
con 28, 40 o 44 pin. I PIC contenuti in packages da 28 pin non hanno porte
parallele implementate e il numero di convertitori Analogico Digitale (AD) sono
solo 5. I PIC della sottofamiglia 18F2XX, dove X sta ad indicare un numero
1,2,3,4… hanno 20 pin, mentre quelli appartenenti alla sottofamiglia denominata
18F4XX ne hanno 40 o 44. Tutti i dispositivi della famiglia 18FXXX possono
essere contenuti in contenitori di tipo PLCC, TQFP, DIP, oppure SOIC.
Nelle tabelle seguenti sono riportate in forma abbreviata le
caratteristiche salienti dei PIC della famiglia 18FXXX e le differenze tra i
vari device.
Tabella 3.1: Caratteristiche
salienti dei PIC della famiglia 18FXXX.
Tabella 3.2: Differenze tra
i PIC della famiglia 18FXXX.
Fig. 3.3: Diagramma a
blocchi PIC della famiglia 18F2XX (28
pin).
Fig. 3.4: Diagramma a
blocchi PIC della famiglia 18F4XX (40 o
44 pin).
Caratteristiche della CPU
L’architettura utilizzata per il set d’istruzioni è di tipo RISC e ogni istruzione viene
identificata da una parola di 16 bit. Questa caratteristica impone un set
limitato d’istruzioni (75 istruzioni),
ma in ogni caso superiore a quello dei PIC delle altre famiglie, come ad
esempio per la 16FXXX che, prevedono una lunghezza di parola delle istruzioni
di solo 14 bit, aveva un set d’istruzioni ancora più piccolo (solo 35);
mancavano quindi istruzioni come la moltiplicazione e la divisione che per
poter essere svolte richiedevano più colpi di clock. Le CPU dei PIC della
famiglia 18FXXX sono invece definite High Performance RISC CPU, infatti esse integrano al proprio interno un
moltiplicatore 8 X 8 di tipo hardware, questo rende la moltiplicazione
un'operazione hardware che può essere eseguita in un solo ciclo di clock. Il
risultato di tale operazione è senza segno, ha una lunghezza di 16 bit e viene
immagazzinato in un registro a 16 bit formato dalla coppia di registri
denominati PRODH-PRODL.
L’ operazione di moltiplicazione non implica
l’innalzamento di nessun flag nel registro ALUSTA.
La possibilità di eseguire moltiplicazioni in
un singolo colpo di clock ha i seguenti vantaggi:
1)
Aumentare la capacità computazionale del dispositivo.
2)Ridurre le dimensioni del codice richiesto
per implementare
gli
algoritmi di moltiplicazione
La tabella seguente riporta il confronto tra
le prestazioni tra un device che implementa la moltiplicazione in hardware in
un singolo ciclo ed uno che non la implementa.
Tabella 3.3: Confronto tra le prestazioni di device con e senza
moltiplicatore hardware.
Oltre alle “classiche”
funzionalità le CPU di molti dispositivi della Microchip integrano al loro
interno molte altre caratteristiche il cui scopo principale è quello di
massimizzare l’affidabilità del sistema, minimizzare il costo di
apparecchiature che integrano PIC, eliminando altri componenti hardware le cui
funzioni possono essere svolte senza problemi dal PIC stesso e, in fine,
garantire un consumo di corrente basso.
Le caratteristiche extra implementate nei PIC della
famiglia 18FXXX sono:
• OSC Selection
• RESET
- Power-on Reset (POR)
- Power-up Timer (PWRT)
- Oscillator Start-up Timer
(OST)
- Brown-out Reset (BOR)
• Interrupts
• Watchdog Timer (WDT)
• SLEEP
• Code Protection
• ID Locations
• In-Circuit Serial Programming
Tutti i dispositivi della
famiglia 18FXX2 hanno un Watchdog Timer che è sempre abilitato tramite i
configuration bit o tramite il software di controllo. Ci sono due timers che
offrono la possibilità di avere un ritardo dopo l’accensione: Oscillator
Start-up Timer (OST) e Powerup Timer (PWRT).
L’ OST ha lo scopo di tenere
il dispositivo in RESET fino a quando l’oscillatore appena acceso non si è
stabilizzato, il PWRT garantisce un ritardo prestabilito solo al momento
dell’accensione. Il suo scopo è quello di tenere il dispositivo in condizione
di _RESET fino a quando la tensione d’alimentazione non si è stabilizzata.
La modalità di funzionamento
denominata SLEEP è stata progettata per garantire assorbimenti di corrente
molto bassi. Si può uscire dalla condizione di SLEEP mediate un RESET esterno,
mediante l’operazione di wake-up da parte del Watchdog Timer oppure mediante la
richiesta d’interrupt.
Sono previsti più modi per
realizzare il circuito oscillante al fine di poter personalizzare il più
possibile il dispositivo in base alle esigenze personali, ad esempi se si è
interessati al contenimento dei costi allora si può realizzare l’oscillatore
mediante un cappio RC, mentre se si vuole consumare meno corrente possibile si
può optare per un circuito oscillante LP a cristallo.
Configuration Bits
I bit di configurazione (
Configuration Bits ) possono essere programmati o meno, per selezionare varie
configurazioni del dispositivo. I bit che sono stati programmati saranno posti
a ‘0’, mentre quelli non programmati conterranno il valore ‘1’. Questi bit sono
mappati in memoria ( nella Program Memory ) a partire dalla locazione
‘300000h’, cioè appena oltre lo spazio riservato al programma dell’utente.
La programmazione dei
registri di configurazione è fatta in maniera molto simile alla programmazione
della memoria FLASH. L’unica differenza consiste nel fatto che i registri di
configurazione vengono scritti un byte per volta.
Watchdog Timer
(WDT)
Il Watchdog Timer (WDT) è
costituito da un circuito risonante di tipo RC il cui funzionamento è
indipendente da quello che accade al dispositivo e, inoltre, per poter
funzionare non richiede l’aggiunta di nessun componente esterno. Questo
consente a tale oscillatore RC di continuare a lavorare anche se il clock
principale, cioè quello esterno collegato al pin OSC1/CLCK1 o al pin
OSC2/CLOCK0/RA6, è stato fermato come conseguenza di un comando, come ad
esempio SLEEP.
Se il dispositivo sta
funzionando regolarmente, cioè non è in modalità SLEAP, il time-out del WDT
causa solo un reset del device (Watchdog Timer Reset ), mentre se il device è
in SLEAP mode viene riattivato dal time-out del WDT. Il WDT può essere
abilitato mediante un opportuno bit del Configuration Bits. Se tale bit è
abilitato il WDT non si può disabilitare per via software se, al contrario,
tale bit non è abilitato, si può procedere all’abilitazione e alla
disabilitazione software del WDT.
Power-down
Mode (SLEEP)
Il Power-down Mode viene
attivato mediante l’istruzione SLEEP. In questa modalità si ha lo spegnimento
della sorgente di clock, le porte di I/O mantengono lo stato logico in cui si
trovavano prima dell’esecuzione dell’istruzione SLEEP e i pin definiti come
uscite vengono portati o al valore VDD o VSS in funzione
dello stato logico in cui si trovano. Quest’ultimo accorgimento consente di
minimizzare la corrente assorbita, infatti, in questo modo nessun circuito
esterno può prelevare corrente dalle porte.
Il device può uscire dalla
condizione di Power-down nei seguenti modi:
1. External RESET ( portando
allo stato logico alto il pin MCLR).
2. Watchdog Timer Wake-up
(solo se il WDT era stato abilitato).
3. Interrupt proveniente dal
pin INT, cambiamenti sulla porta RB
oppure richiesta d’Interrupt da parte
di una periferica.
Non tutti gli interrupt provenienti da parti
periferiche del PIC possono generare il wake-up.
Solo le seguenti fanno uscire il dispositivo dalla
modalità Power-down:
1. PSP read or
write.
2. TMR1 interrupt. Timer1
must be operating as
an asynchronous counter.
3. TMR3 interrupt. Timer
must be operating as
an asynchronous counter.
4. CCP Capture mode
interrupt.
5. Special event trigger
(Timer1 in Asynchronous
mode using an external
clock).
6. MSSP (START/STOP) bit
detect interrupt.
7. MSSP transmit or receive
in Slave mode
(SPI/I2C).
8. USART RX or TX
(Synchronous Slave mode).
9. A/D conversion (when A/D
clock source is RC).
10. EEPROM write operation
complete.
11. LVD interrupt
Organizzazione
della memoria
Questo tipo di PIC prevede l’organizzazione della memoria in tre
blocchi che sono i seguenti:
•
Program Memory
• Data RAM
• Data EEPROM
La Data Memory e la Program Memory prevedono dei bus separati al fine
di garantire un acceso concorrente a questi blocchi.
Viene utilizzato un contatore a 21 bit Per indicizzare 2 Mega Byte di
Program Memory. Se si accede in lettura alle locazioni di memoria comprese tra
quella fisicamente implementata (32 MB per la famiglia 18FX52) e quella
indicizzabile, si leggeranno tutti zero (A NOP INSTRUCTION).
I PIC 18F252 e 18F452 hanno entrambi 32 Kilo bytes di memoria flash,
mentre i PIC 18F242 e 18F442 ne hanno 16 Kilo bytes. Questo significa che i
device della famiglia 18FX52 possono contenere un programma di lunghezza
massima pari a sedicimila word (16K Word Instruction), mentre i device della
famiglia 18FX42 possono contenere al massimo un programma di 8K Word
Instruction. Il vettore RESET è mappato in memoria all’indirizzo ‘0000h’ mentre
i vettori delle interrupt sono mappati agli indirizzi ‘0008h’ e ‘0018h’.
La figura seguente mostra l’architettura della Program Memory:
Struttura della Program Memory per PIC 18FX42 e 18FX52.
Lo stack di ben trentuno Return Address permetta una qualsiasi
combinazione di chiamate a sottoprogrammi e interruzioni. Il PC (Program
Counter) viene posto pari al valore contenuto in uno dei trentuno valori dello
stack quando viene eseguita una chiamata a sottoprogramma o viene servita una
interrupt mediante le funzioni CALL o RCALL. Il valore del PC viene spostato da
quello dello stack mediante la chiamata delle funzioni RETURN, RETLW o RETFIE.
Lo spazio riservato allo stack dei puntatori non fa parte del programma
o dei dati. il puntatore allo stack può essere sia letto che scritto e
l’indirizzo all’inizio dello stack può essere letto e scritto mediante il
registro SFR.
La memoria Data Memory è implementata mediante l’uso di una memoria
RAM. Ogni registro della Data Memory ha un indirizzo costituito da 12 bit,
consentendo così, di avere una memoria dati indirizzabile di 4096 bytes. La mappa della memoria dati
viene suddivisa in 16 banchi da 256 bytes ciascuno (16 X 256 bytes = 4096 bytes).
I quattro bit meno significativi del Bank Select Register (BSR <3:0>)
indicano quale banco della memoria accedere. Gli altri quattro bit del BSR,
quelli più significativi (BSR <7:4>) non vengono utilizzati. La Data
Memory contiene indirizzi specifici, Special Function Registers (SFR), e registri
generici, General Purpose Registers (GPR). GLI Special Function Registers sono
utilizzati per effettuare operazioni di controllo, per contenere informazioni
riguardanti lo stato del controllore e delle periferiche, mentre i General
Purpose Registers vengono usati per immagazzinare i dati elaborati dal
microcontrollore.
I Special Function Registers iniziano dall’ultima locazione di memoria
del quindicesimo banco ( ‘0XFFF’ ) e si estendono verso il l’alto. Tutto lo
spazio rimanente nel banco di memoria oltre agli Special Function Registers può
essere usato per registri generici. I General Purpose Registers partono dal
primo indirizzo del banco di memoria ‘0’ e si sviluppano verso il basso. Se si
prova a leggere ad una locazione di memoria non implementata si otterrà come
risultato uno zero (‘0’).
L‘ intera memoria dati può essere acceduta sia direttamente che
indirettamente. L’ indirizzamento diretto può richiedere l’uso del BSR
Register. L’ indirizzamento indiretto richiede l’uso di un File Select Register
(FSRn) e di un corrispondente Indirect File Operand (INDFn). Ogni File Select
Register contiene un indirizzo di 12 bit che può essere usato per indirizzare
ad una qualsiasi locazione della Data Memory senza alcun bisogno di conoscere a
quale banco appartiene.
L'insieme d’istruzioni e l’architettura permettono operazioni su tutti
i banchi di memoria. Questo può essere fatto mediante indirizzamento indiretto
oppure mediante l'uso dell'istruzione di MOVFF.
L'istruzione di MOVFF è un'istruzione di two-word/two-cycle che
permette spostare un valore da un registro ad un altro.
Il File Select Register (FSRn) è allocato nella prima metà del
quindicesimo banco di memoria, dall’indirizzo ‘0XF80’ all’indirizzo ‘0XFF’.
Di seguito viene riportato uno schema che illustra l’organizzazione
della Data Memory:
Fig. 3.6:
Struttura della Data Memory dei PIC
18F252 e 18F452.
Gli Special Function
Registers sono registri utilizzati dalla CPU e dalle unita periferiche per
controllare il funzionamento del dispositivo. Essi possono essere classificati
in due categorie:
1) Special Function Registers
associati alle funzionalità interne.
2) Special Function Registers
associati alle funzionalità periferiche.
I registri speciali, che
servono per la gestione delle periferiche, sono implementati nelle vicinanze
delle stesse periferiche a cui fanno riferimento.
Una tabella con la mappa
degli SFR e riportata di seguito:
Tabella 3.4: Mappa degli Special Function Registers.
Lo Status Register
Lo STATUS Register ha lo
scopo di contenere lo stato aritmetico dell’ALU; esso può essere la
destinazione per alcune istruzioni, proprio come accade per tutti gli altri
registri di uso comune.
Se ad esempio un’istruzione
ha effetto sui bit Z, DC, C, OV ed N dello Status Register, allora viene
disabilitata la possibilità di scrivere o cancellare questi cinque bit. Essi
vengono settati o cancellati in base alla logica del dispositivo. Per questo
motivo un’istruzione sullo Status Register può avere un risultato diverso da
quello previsto. Rifacendoci, ad esempio, al caso precedente in cui i cinque
bit meno significativi sono già riservati per l’esecuzione di un’istruzione, se
viene dato il comando “CLRF STATUS”, che dovrebbe cancellare tutti gli otto bit
dello Status Register, esso cancellerà i primi tre bit (quelli non ancora
riservati all’esecuzione di alcuna istruzione) e setterà il bit Z al valore
uno.
Avremo così lo Status Register nella seguente Forma:
0 0 0 U U 1 U U
Dove U sta per Unchanged (Invariato).
Per questo motivo è
raccomandabile usare solo istruzioni come BCF, RSF, SWAPF, MOVFF e MOVWF per
alterare lo Status Register, in quanto non hanno alcun effetto sui bit Z, C,
DC, OV e N.
Nella figura seguente viene fornita una
rappresentazione dello Status Register:
Fig. 3.7:
Rappresentazione dello Status Register.
Gli Interrupt
I PIC della famiglia 18FXX2
hanno molte possibili sorgenti d’interrupt e un meccanismo che consente di
assegnare a ciascuna possibile sorgente d’interrupt un livello di priorità alto
o basso.
Il vettore degli interrupt
ad alta priorità si trova mappato in memoria all’indirizzo ‘000008h’, mentre il
vettore delle interrupt a bassa priorità all’indirizzo ‘000018h’.
Il verificarsi di
un’interrupt con alta priorità prevarrà su tutte le interrupt a bassa priorità
che possono già essere state accolte.
Esistono dieci registri
usati per il controllo dell’operazione d’interrupt e sono:
• RCON
• INTCON
• INTCON2
• INTCON3
• PIR1, PIR2
• PIE1, PIE2
• IPR1, IPR2
Ogni sorgente d’interrupt,
tranne INTO, prevede l’uso di tre bit per il controllo, ognuno dei quali ha una
specifica funzione:
• Flag bit per indicare il
verificarsi di un evento
d' interrupt
• Enable bit che consente
all’esecuzione del programma
di saltare all’indirizzo del vettore d’interrupt quando è
stato settato il Flag bit
• Priority bit per
selezionare un livello di priorità alto
o basso
Il livello di priorità viene
abilitato settando il bit IPEN ( bit 7 di RCON). Quando il livello di priorità
è abilitato, ci sono due bit che abilitano gli interrupt globalmente. Settando
il bit GEH ( bit 7 di INTCON) si abilitano tutti gli interrupt che hanno il bit
di priorità fissato, mentre settando il bit GIEL ( bit 6 di INTCON ) si
abilitano gli interrupt che non hanno priorità fissata.
Quando sono settati il Flag
bit, l’Enable bit e uno dei bit d’abilitazione globale degli interrupt, il
vettore d’interrupt viene direttamente indirizzato all’indirizzo ‘000008h’
oppure ‘000018h’ in base al livello di priorità. Gli interrupt singoli possono
essere disabilitati mediante il loro corrispondente bit d’abilitazione.
Quando viene accolta una
richiesta d'interrupt, il bit di abilitazione globale viene cancellato per
disabilitare ulteriori interrupt. Il valore di ritorno viene memorizzato nello
stack e l’indirizzo del vettore d'interrupt ( ‘000008h’ oppure ‘000018h’ ) è
caricato nel PC ( Program Counter ).
Una volta entrati nella
routine di servizio dell’interrupt, le sorgenti dell’interrupt possono essere
determinate interrogando i flag bit. I flag bit dell’interrupt devono essere
cancellati prima di riabilitare gli interrupt per evitare interrupt ricorsivi.
L’istruzione di ritorno
dell’interrupt, ”RETFIE”, esce dalla routine d’interrupt e setta il bit GIE (
GIEH o GIEL se sono usati i livelli di priorità ), che riabilita gli interrupt.
Viene di seguito riportata
una figura relativa alla logica degli interrupt:
Fig. 3.8: Logica degli Interrupt.
Porte di I/O
Consideriamo le interfacce
di I/O del PIC. Innanzi tutto le considereremo per comodità come semplici porte
logiche in cui i valori a cui si possono portare sono 0 e 1 logici. In realtà
il valore logico 1 è relativo alla tensione +5V mentre lo 0 ai 0V. Sapendo
questo si può pensare di collegare opportunamente ai piedini di output un led
che si accenderà quando ai piedini arriva un 1 logico, oppure un interruttore
ai piedini di input che comunicheranno uno 0 logico quando si chiuderà il
contatto.
In funzione del dispositivo
scelto il numero delle porte disponibili varierà; per i PIC della famiglia
18FXXX si va da un massimo di cinque ad un minimo di tre. Alcuni pin delle
porte di I/O sono multiplexati con varie funzioni dalle varie funzionalità
periferiche presenti nel dispositivo.
Ogni porta possiede tre
registri per gestire le sue funzionamento:
• TRIS register (data
direction register)
• PORT register (reads the
levels on the pins of the
device)
• LAT register (output
latch)
Il TRIS register serve per
tenere le informazioni sullo stato d’utilizzo della porta, cioè se i singoli
piedini sono usati come Input (indicati nel registro attraverso un 1) o come
Output (indicati con uno 0); il PORT register mantiene traccia del dato
presente nella porta, leggendo il suo contenuto, infatti, si legge lo stato del
pin ad esso associato, scrivendo in esso si setta lo stato alto o basso del pin
corrispondente. Il LAT register sono anche mappati in memoria per cui
operazioni di lettura, scrittura o cancellazione di tali registri equivale ad
operare direttamente con i pin ad essi associati.
Ad esempio, se il dato
presente nel registro TRISB risulta essere ' b.00001111', avremo che i piedini
della porta B saranno settati metà come Output (0) e metà come Input (1): nel
caso in esame, i piedini RB4, RB5, RB6, RB7 saranno output, mentre RB0, RB1,
RB2, RB3 saranno Input.
Considerando la stessa porta si può vedere che se il dato presente
nel registro PORTB fosse 'b.00001111' avremo che il PIC sta ricevendo, dai
piedini d’ingresso, degli “1” e sta trasmettendo degli“0”.
Di seguito viene riportata
una tabella riassuntiva con le principali caratteristiche delle porte presenti
su un PIC18F452 o simili:
Porta |
Numero piedini |
Registro definizione della direzione del dato
(I/O) |
Registro contenente il dato presente sulla porta |
LAT Register |
PORTA |
7 |
TRISA |
PORTA |
LATA |
PORTB |
8 |
TRISB |
PORTB |
LATB |
PORTC |
8 |
TRISC |
PORTC |
LATC |
PORTD |
8 |
TRISD |
PORTD |
LATD |
PORTE |
3 |
TRISE |
PORTE |
LATE |
Tabella 3.5: Porte di I/O e rispettivi registri.
Le cinque porte del PIC
rappresentano le uniche risorse che questo dispositivo ha a disposizione per
comunicare con il mondo esterno, cioè con tutti gli altri dispositivi
elettronici ad esso collegati. Ogni porta del dispositivo per funzionare ha
bisogno di componenti hardware abbastanza complessi; molto spesso i singoli pin
possono essere programmati per svolgere più funzionalità.
Vengono riportate di seguito
tutte e cinque le porte del dispositivo, ponendo l’attenzione su quelle che
sono le possibili funzionalità dei pin.
Porta A
Tabella 3.6: Funzionalità
della porta A.
Porta B
Tabella 3.7: Funzionalità
della porta B.
Porta C
Tabella 3.8: Funzionalità della porta C.
Porta D
Tabella 3.9: Funzionalità
della porta D.
Porta E
Tabella 3.10: Funzionalità
della porta E.
Convertitore A/D
Il convertitore Analogico/Digitale prevede cinque
ingressi per i PIC della famiglia 18F2X2 e otto per la famiglia 18F4X2. Questo
convertitore A/D a 10 bit consente di convertire un segnale analogico presente
su queste porte in un corrispondente valore digitale a 10 bit.
Di seguito viene riportato uno schema a blocchi del
convertitore:
Fig. 3.9: Schema a blocchi del convertitore A/D.
Come possiamo notare il
convertitore è unico, mentre a monte di esso è presente un MUX analogico
necessario per settare gli ingressi analogici opportuni (5 ingressi per il PIC
a 28 pin 8 ingressi per il PIC a 40 pin).
Il convertitore A/D per poter funzionare necessita
di quattro registri:
• A/D Result High Register
(ADRESH)
• A/D Result Low Register
(ADRESL)
• A/D Control Register 0
(ADCON0)
• A/D Control Register 1
(ADCON1)
Il registro ADCON0, mostrato sotto, controlla il
funzionamento del convertitore.
Fig. 3.10: Registro ADCON0.
I bit sette e sei,
denominati “ADCS1” e “ADCS0”, insieme al bit sei del registro ADCON1, servono a
selezionare una delle otto possibili sorgenti di clock da usare per la
conversione, secondo la tabella riportata sotto:
Tabella 3.11: Corrispondenza bit ADCS1&ADCS0_sorgente di clock.
I bit da cinque a tre ( “CHS2”, “CHS1” e “CHS0” )
servono a stabilire quali pin della porta debbano essere convertiti:
Fig. 3.11: Bit CHS2-CHS0
per la selezione dei canali analogici da convertire.
Il bit due di ADCON0 ( ‘GO/DONE’ ) indica lo stato
del convertitore A/D:
GO/DONE=1: la
conversione analogico/digitale e in fase
d’esecuzione (settando
a 1 questo bit parte la
conversione). Il bit
viene portato a zero
tramite hardware quando
la conversione
è finita.
GO/DONE=0: la
conversione non è in esecuzione.
Il bit zero ‘ADON’ se posto ad 1 accende il
convertitore A/D, se posto a zero lo spegne. Il pin uno non ha alcuna funzione.
Il registro ADCON1 configura le funzioni dei pin
della porta.
Fig. 3.12: Registro ADCON1.
Il bit sette ‘ADFM’ consente
di selezionare il formato del risultato della conversione:
ADFM=1: giustificato a desta. I sei bit meno
significativi di ADRESH
sono letti come ‘0’
ADFM=0:
giustificato a sinistra. I sei bit meno
significativi di
ADRESL sono letti come ‘0’
Il bit sei ‘ADCS2’, come gia
detto prima, insieme ai bit ‘ADCS1’ e ADCS0’ di ADCON0 servono a selezionare la
sorgente di clock per il convertitore.
I bit da tre a zero,
‘PCFG3’, ‘PCFG2’, ‘PCFG1’ e ‘PCFG0’, controllano la configurazione delle porte
connesse all’A/D converter secondo la seguente tabella:
Tabella 3.12: Bit PCFG3-PCFG0 per la configurazione dei pin d’ingresso.
I registri ADRESH e ADREL
contengono il risultato del processo di conversione.
Quando un processo di
conversione viene ultimato il risultato del processo viene caricato in ADRESH e
ADREL, il bit due di ADCON0 ( ‘GO/DONE’ ) si abbassa e il flag degli interrupt
generati dal convertitore A/D ( ADIF ) viene alzato.
Il convertitore A/D è
composto, internamente, da un sample&hold con in cascata un convertitore ad
approssimazioni successive, la cui risoluzione ottimale è di 10 bit. La
capacità del circuito di sample&hold è di 120pF. Nella figura seguente
abbiamo il modello analogico della sezione d’ingresso.
Fig. 3.13: Modello analogico
d’ingresso dell’A/D converter.
Affinché la conversione sia
fatta correttamente bisogna attendere che la capacità (CHOLD) venga caricata
fino al valore di tensione in ingresso. Il tempo di carica della capacità CHOLD
viene influenzato sia dalla resistenza della sorgente analogica ( Rs ) che
dall’impedenza interna del circuito di Sampling Switch ( Rss ). Quest’ultima
cambia in funzione della temperatura e della tensione Vdd. L’impedenza della
sorgente analogica influenza il valore della tensione di offset in ingresso, a
causa della corrente di Leakage.
Se si considera il massimo
valore della resistenza della sorgente analogica da convertire pari a 2,5
KΩ, si può calcolare il tempo minimo di conversione. Si assume che il
massimo errore accettabile affinché la risoluzione sia quella indicata, sia
pari a 1/2 LSB. In queste condizioni si ha che il tempo minimo d’acquisizione è
pari a 11,86 μs.
Il tempo necessario alla
conversione di un singolo bit viene definito come TAD; per eseguire
un’operazione di conversione a 10 bit sono necessari 12 TAD.
Sono previste sette sorgenti
di clock da utilizzare per la conversione:
• 2 TOSC
• 4 TOSC
• 8 TOSC
• 16 TOSC
• 32 TOSC
• 64 TOSC
• Internal A/D module RC
oscillator (2-6 μs)
Affinché l’operazione di
conversione avvenga in modo corretto è necessario selezionare il clock del
convertitore A/D in modo da assicurare un TAD ( tempo necessario
alla conversione di un bit) superiore a 1,6 μs.
La tabella seguente riassume
la corrispondenza tra una delle sette possibili sorgenti di clock selezionabili
e il corrispondente TAD:
Tabella 3.13: Corrispondenza tra le sorgenti di clock selezionate e TAD.
Il risultato dell’operazione
di conversione viene caricato nella coppia di registri ADRESH – ADRESL; ognuno
di questi registri ha otto bit per un totale di 2 X 8 = 16 bit.
I PIC consentono di
scegliere se il risultato debba essere caricato nella coppia di registri
giustificandolo a destra o a sinistra. Nella figura seguente sono riportati due
esempi, uno con giustificazione a destra e l’altro a sinistra. In entrambi i
casi tutti i bit non utilizzati per contenere il risultato dalla conversione
vengono posti a ‘0’.
Fig. 3.14: Risultato della
conversione con giustificazione a destra o a sinistra.
Comunicazione Seriale
I PIC della Microchip
appartenenti alla famiglia 18FXX2 contengono al loro interno un modulo
elettronico capace di implementare una comunicazione seriale. Tale modulo
prende il nome di Universal Synchronous Asynchronous Receiver Transmitter
(USART) e viene spesso indicato anche come Serial Communications Interface (
SCI ).
L’ USART può essere
configurata come un’interfaccia asincrona full-duplex o come un’interfaccia
sincrona half-duplex.
Quindi i tre possibili modi
di configurare l’USART sono i seguenti:
• Asynchronous (full-duplex)
• Synchronous - Master
(half-duplex)
• Synchronous - Slave
(half-duplex)
Se si configura come Asynchronous
(full-duplex) allora il PIC può usare l’USART per comunicare con un qualsiasi
device periferico che implementa tale standard, come ad esempio un comune PC.
Bisogna però ricordare che la porta RS232, che comunemente viene usata sui PC
per comunicazioni seriali, associa al livello logico alto il valore +12V e al
livello logico basso il valore 0V ( per maggiori dettagli si rimanda alle
specifiche dello standard), mentre le porte del pic, anche quelle utilizzate
per la comunicazione seriale, associano al livello logico alto il valore +5V e
al valore logico basso 0V.
Quindi risulta praticamente
impossibile collegare direttamente un PC tramite la propria RS232
all’interfaccia seriale implementata dal microcontrollore. Esistono in
commercio dei dispositivi integrati ( ad esempio il MAX232 ) che si occupano di
convertire i segnali RS232 di 12V in segnali di 5V, compatibili con le porte
logiche in tecnologia TTL che realizzano l’interfaccia seriale dei pic.
Per configurare il pin
RC6/TX/CK ed il pin RC7/RX/DT come USART bisogna seguire il seguente
procedimento:
• bit SPEN (RCSTA<7>)
deve essere settato (= 1)
• bit TRISC<6> deve
essere abbassato (= 0)
• bit TRISC<7> deve
essere settato (=1)
Il registro TXSTA serve per
controllare la trasmissione e per contenere informazioni sul suo stato.
Il registro RCSTA per controllare la ricezione e per
contenere informazioni sul suo stato.
Fig. 3.15: Registro TXSTA
per il controllo e la gestione della trasmissione.
Fig. 3.16: Registro RCSTA per
il controllo e la gestione della ricezione.
Low
Voltage Detect
Quando ci si trova a
progettare un’apparecchiatura elettronica si sente speso la necessità di avere
a disposizione un dispositivo che sia in grado di verificare se la tensione
d’alimentazione VDD sia scesa al di sotto di un valore prestabilito.
I PIC della famiglia 18FXX2 implementano al loro interno questa funzionalità
che può risultare molto utile; ad esempio quando ci si accorge che la tensione
d’alimentazione sta scendendo, prima che raggiunga un valore al di sotto del
quale il dispositivo non può più funzionare, è possibile settare il dispositivo
in modo che consumi il meno possibile in modo da prolungare il suo
funzionamento.
Il modulo Low Voltage Detect
dei pic e completamente programmabile via software quindi è molto flessibile.
Quando il valore della tensione d’alimentazione scende al di sotto del valore
impostato viene attivato un flag d’interrupt. Se gli interrupt sono abilitati
l’esecuzione del programma può saltare all’indirizzo del vettore degli
interrupt e servirla.
Nella figura seguente viene
riportata una situazione in cui è possibile utilizzare il Low Voltage Detect (
LVD ). Si presuppone che il dispositivo sia alimentato da delle batterie e che
la tensione d’alimentazione stia scendendo, cioè che le batterie si stiano
scaricando. Quando la tensione arriva al valore VA impostato, il LVD
se n’accorge e genera una richiesta d’interrupt; quest’interrupt può, ad
esempio, spegnere il dispositivo prima che la tensione raggiunga il valore VB
che è critico per il funzionamento dell’apparecchiatura.
Fig. 3.17: Esempio d’utilizzo del Low Voltage Detect.
Di seguito viene riportato
lo schema a blocchi del LVD. In esso si
possono riconoscere vari elementi:
un partitore resistivo con 16 livelli (i possibili
livelli impostabili per il LVD)
un comparatore
un riferimento di tensione interno (1,2 V)
un multiplexer a 16 ingressi
un registro di controllo per selezionare il livello
di soglia del LVD
Fig. 3.18: Schema a blocchi del Low Voltage Detect.
La tensione d’alimentazione
VDD viene mandata ad un partitore resistivo che genera a6 livelli di
tensione da inviare al multiplexer a 16 ingressi. Tramite il LVD Control
Register si può scegliere quale di questi 16 riferimenti debba essere inviato
al comparatore. Quando il riferimento scelto diventa più basso della tensione
di riferimento (1,2V) l’uscita del comparatore si alza (LVDIF) settando
l’opportuno flag d’interrupt.
Il LVD prevede anche la
possibilità di utilizzare come riferimento per il comparatore un ingresso
supplementare esterno. Risulta quindi possibile impostare il valore del LVD a
proprio piacimento.
Fig. 3.19: Schema a blocchi del Low Voltage Detect con riferimento
esterno.
Set d’Istruzioni
Nei precedenti paragrafi è
stata descritta la struttura hardware dei microcontrollori PIC appartenenti
alla famiglia 18FXX2; in questo paragrafo analizzeremo in dettaglio le
istruzioni disponibili per scrivere un programma in assembler per i PIC;
affronteremo quelli che sono i passi necessari per la stesura di un programma e
analizzeremo come il microcontrollore si comporta di fronte alle varie
istruzioni.
Il linguaggio che viene
normalmente utilizzato per i microcontrollori è l’assembler; tutti i
dispositivi elettronici digitali interpretano e lavorano tramite un linguaggio
proprio definito dallo standard binario.
I dispositivi elettronici
digitali sono progettati per riconoscere solamente due condizioni: “1”, ovvero
presenza di tensione e “0”, assenza di tensione. Nello specifico lo stato
logico alto on (‘1’) corrisponde nei PIC (che implementano una logica definita
positiva) al valore di + 5V e lo stato logico basso off (‘0’) al valore 0V.
Dovendo scrivere un
programma tramite questo tipo di linguaggio è facile immaginare a quale
difficoltà si va incontro nel compilarlo e nell’interpretarlo; ecco quindi che
viene in nostro soccorso un’interfaccia, il linguaggio assembler, che ci
semplifica di molto il lavoro di programmazione.
Un programma scritto in
assembler ( che varia a seconda del tipo di microcontrollore ) è costituito da
una serie di frasi, definite statement (dichiarazioni), ciascuna delle quali
può rappresentare una serie d’informazioni: etichette (Labels), codice
operativo (spesso denominato anche mnemonico), che rappresenta in pratica le
istruzioni che il PIC è in grado di eseguire, operandi, cioè gli elementi (
registri, locazioni di memoria ) su cui le istruzioni devono andare ad agire,
commenti, cioè indicazioni che non vengono eseguite dal micro, ma che aiutano
chi legge il programma ad interpretarne il significato.
Generalmente all’inizio di
ogni listato viene inserita una presentazione descrittiva contenente alcune
informazioni quali il nome del file, la data di realizzazione, una descrizione
sommaria del contenuto, l’autore eccetera.
Le labels sono delle parole
che vengono utilizzate come “rimandi” nel programma oppure delle costanti che
saranno sostituite dal compilatore nella generazione del codice macchina.
Generalmente, la prima parte
di un programma scritto in assembler contiene diverse labels che serviranno per
semplificare la scrittura del programma stesso.
La parola EQU non è
un’istruzione del PIC, ma una direttiva del compilatore, che dice appunto di
associare ad una label un certo valore.
Quando il programma viene
compilato dall’assemblatore, per generare il codice finale in linguaggio
macchina, ogni volta che il compilatore incontra la parola a cui è associato
EQU, sostituisce a questa il suo valore effettivo.
In pratica il dichiarare
delle costanti in questo modo, anziché scrivere direttamente il loro valore
all’interno del programma, ha due sostanziali vantaggi:
1.
risulta
molto più facile scrivere un programma, in quanto è più semplice utilizzare una
label che ricorda il significato di una certa costante piuttosto che il suo
valore numerico;
2.
diventa
più facile e veloce effettuare modifiche al programma.
Una parte importante del
programma è costituita dai commenti: per aggiungere dei commenti, è sufficiente
porre un punto e virgola prima del commento stesso; il compilatore
automaticamente ignorerà tutto ciò che è scritto dopo il punto e virgola.
I commenti, anche se non
servono direttamente al programma, sono tuttavia d’estrema importanza per la
comprensione del programma stesso.
E’ buona norma inserire
commenti frequenti, ad esempio per le costanti usate nel programma, per le
routine e così via. Dopo la prima parte relativa alla dichiarazione delle
costanti, vi è il programma vero e proprio, che comincia dalla label INIT.
La prima istruzione che si
trova è ORG 0000h. Questa, come la EQU già vista, non è un’istruzione del PIC
ma una direttiva dell’assembler; in pratica “dice” all’assemblatore che la
parte di programma che segue dovrà essere compilata in memoria a partire dalla
locazione 0000h ( in esadecimale ).
Questo perché quando il PIC
viene alimentato, o quando esce da una situazione di reset, il program Counter
parte dalla prima locazione di memoria, che nel 16F877 è rappresentata dalla
locazione di indirizzo 0.
In tale locazione è quindi
necessario inserire un rimando all’inizio, per così dire, vero, del programma.
A volte si fa riferimento a tale rimando parlando di vettore di reset del
micro.
Dopo la ORG inizia il programma vero e proprio, con
diverse istruzioni.
Quasi tutte le istruzioni
sono costituite da due parti: l’istruzione vera e propria, che dice al
microcontrollore il tipo d’operazione che deve essere eseguita, e gli operandi,
cioè in pratica ciò su cui l’istruzione deve andare ad agire.
Prima di scrivere la
sequenza d’istruzioni che compone un programma, si descrive il programma che il
micro dovrà eseguire attraverso un diagramma di flusso, o flow chart, per
esprimere il tipo di operazioni che il micro dovrà eseguire.
Vediamo adesso in maniera
più approfondita, il set d’istruzioni del PIC, che rappresenta l’insieme
d’istruzioni che il micro è in grado di eseguire e che è quindi possibile
scrivere in un programma assembler.
Il set d’istruzioni del
16FXX2 è costituito da 75 istruzioni che, anche se possono sembrare poche, sono
molte di più di quelle implementate dalle altre famiglie di microcontrollori
PIC.
Le istruzioni possono essere
così raggruppate:
• Byte-oriented operations
• Bit-oriented operations
• Literal operations
• Control operations
La maggior parte delle
istruzioni ha una lunghezza di una singola word di memoria ( 16-bits ), ma
esistono tre istruzioni speciali che richiedono due locazioni di memoria (due
word 32-bits).
Tutte le istruzioni che
hanno lunghezza pari ad una word sono eseguite in un solo ciclo d’istruzione
tranne nel caso in cui risulti vero un test condizionale o che il Program Counter
(PC) vari come conseguenza dell’istruzione stessa. In questi casi l’istruzione
per essere eseguita completamente richiede due cicli d’istruzione. Le tre
istruzioni speciali con lunghezza due word richiedono sempre due cicli
d’istruzione.
Ogni ciclo d’istruzione è
costituito da quatto periodi di clock. Se ad esempio abbiamo una frequenza di
clock pari a 4 MHz ( T = 250 ns ) il tempo di esecuzione di un’istruzione che
richiede un solo ciclo d’istruzione è pari a 1 μs ( 4 X 250 ns = 1
μs). Se risulta vera un test condizionale o il program counter viene
incrementato come risultato dell’istruzione, il tempo d’esecuzione
dell’istruzione diventa doppio, cioè 2
μs (8 X 250 ns = 2 μs).
Di seguito vengono riportate
due tabelle; la prima contiene una descrizione sintetica di tutti i campi che
si possono trovare nel formato generale di un’istruzione (opcode), il cui
schema viene riportato nella seconda tabella.
Tabella 3.14: Descrizione dei campi delle istruzioni.
Fig. 3.20: Formato generale delle istruzioni.
Byte-oriented
instruction
La maggior parte delle Byte-oriented instruction ha
tre operandi:
1.
file register ( identificato con ‘f’ )
2.
destination register ( identificato con ‘d’ )
3.
acceded memory( identificato con ‘a’ )
Il file register che, come
abbiamo detto sopra, viene segnalato con la lettera ‘f’ indica quale file
register deve essere utilizzato dall’istruzione; il destination register indica
il registro di destinazione, cioè dove deve essere posto il risultato
dell’istruzione. Se tale operando è lasciato vuoto il risultato dell’istruzione
viene salvato nel registro WREG, altrimenti, se posto ad uno, il risultato
viene collocato nel file register specificato nell’istruzione.
Di seguito viene riportata
una tabella con tutte le funzioni Byte-oriented:
Tabella 3.15: Byte-oriented
instruction.
Bit-oriented
instruction
Tutte le istruzioni bit-oriented hanno tre operandi:
1.
file
register ( identificato con ‘f’ )
2.
bit
nel file register ( indicato con ‘b’ )
3.
acceded
memory( identificato con ‘a’ )
Il secondo campo, bit nel file register, indica su
quanti bit indica il numero di bit su cui l’operazione avrà effetto, mente il
campo file register indica il numero del file in cui il bit si trova.
Tabella 3.16: Bit-oriented instruction.
Le funzioni bit-oriented sono:
Literal instruction
Le literal instruction possono far uso di alcuni dei
seguenti operandi:
1.
Un
valore letterale che deve essere caricato in un file register (indicato con ‘k’
)
2.
L’
FSR register in cui caricare il valore letterale ( indicato con ‘f’ )
3.
Nessun
operando richiesto (indicato con ‘−’ )
le literal instruction sono:
Tabella 3.17: Literal instruction.
Control
instruction
Le control instruction possono far uso di alcuni dei
seguenti operandi:
1.
Un
indirizzo della program memory ( indicato con ‘n’ ).
2.
La
modalità dell’istruzione di Call o Return ( indicato con ‘s’ ).
3.
La
modalità dell’istruzione di Table Read e Table Write ( indicato con ‘m’ ).
4.
Nessun
operando richiesto (indicato con ‘−’ ).
Le control operation sono:
Tabella 3.18: Control
instruction.