Elettronica
|
|
Micropic.
Nozioni basilari di Hardware e programmazione.
Nota preliminare: Sono in commercio oltre 50 versioni di micropic con diverse potenzialità, inizieremo l'approccio con il modello 16F84, esso non è il modello base ma è il più idoneo all'approccio da parte di un principiante. Questo PIC rappresenta uno dei modelli più comuni e più venduti. Essendo uno dei più semplici in esso sono implementate solo le istruzioni basilari.
Definizione: Si definisce Microcontrollore un circuito integrato che contiene un uP (leggasi microprocessore), e un certo numero di periferiche di I/O (leggasi input, output), quali gates configurabili sia come ingressi che come uscite, contatori hardware, convertitori analogici/digitali, line di comunicazione seriale e parallela, nonchè una certa quantità di memoria di tipo RAM (per i dati volatili), ROM (per il programma), EPROM (per dati statici e programma), EEPROM Flasch (per le versioni di PIC programmabili più volte). Le versioni UV sono riprogrammabili dopo la cancellatura con raggi ultravioletti.
I microcontrollori
PIC dispongono di un numero ridotto di istruzioni e quindi sono dei dispositivi
di tipo RISC e si programmano in assembly ovvero in codice macchina, ma
il codice può essere ottenuto con aplicativi di tipo visual che semplificano la
stesura del programma.
In commercio si trovano diversi modelli di PIC a seconda della complessità e
delle funzioni implementate, alcuni dispositivi si differenziano anche per la
quantità di memoria disponibile e per la quantità di Timer a disposizione.
Nota: Con il termine OTP (one time programming) indichiamo quella tipologia di PIC che potrà essere scritta una sola volta, serve per la produzione di serie quando siamo certi che il programma è funzionate e nella sua versione definitiva.
Struttura Software del PIC 16F84
Concettualmente il principio di funzionamento di
un PIC è molto semplice:
Lo stack (una locazione di memoria) mantiene l'indice dell'istruzione da
eseguire, ogni ciclo di clock viene eseguita l'istruzione indicata dallo stack
seguendo riga per riga il programma memorizzato nella EEPROM accedendo ad
una memoria unica chiamata accumulatore. Nella RAM vengono
salvati i dati temporanei e una volta spento il PIC vengono persi. Per
memorizzare invece dei dati in modo permanete (tipo Hard Disk per capirci) c'è a
disposizione una EEPROM. Esistono alcune locazioni di memoria prefissate e
chiamate Register che contengono tutti i dati di configurazione
e permettono di definire ad esempio quali linee sono di ingresso e quali di
uscita, se si usano interrupt, se si usa il timer ecc... Tutti i
PIC hanno grosso modo la stessa configurazione di memoria ma cambia la quantità
disponibile.
Differenze tra le versioni dello stesso PIC.
PIC 16C84 versione base dei PIC con 36
byte di memoria RAM.
PIC 16F84 come 16C84 ma con 68 byte di memoria RAM e clock a 10MHz.
PIC 16F84A come 16F84 ma con clock a 20MHz.
Struttura Hardware del PIC 16F84.
Descrizione pin:
RA0-RA4 sono le linee della porta A
configurabili separatamente come IN o OUT.
RB0-RB7 sono le linee della porta B configurabili separatamente come
IN o OUT.
MCLR è il master reset utile per resettare il PIC a livello hardware
(normalmente a livello +Vcc, si porta a livello 0 per il reset).
Vss alimentazione positiva da 2 a 5,5 volt.
Vdd massa.
RB0 è il pin che in programmazione può essere usato per gestire interrupt
esterni.
OSC1 e OSC2 pin utilizzati per il clock tramite quarzo oppure con
rete RC, CLKIN può essere usato per inviare un clock esterno.
RB6 e RB7 vengono usati in programmazione rispettivamente come
DATA e come CLOCK.
Descrizione potenzialità dispositivo:
13 IN/OUT (quantità ingressi e uscite
denominatio genericamente gates).
Corrente nei gates: ogni uscita gestisce 25mA (sink quindi verso
dentro e source quindi verso fuori).
Clock max 20MHz: solo la versione 16F84A.
1024 istruzioni di programma dimensione massima del programma.
64 Byte RAM dimensione allocazione dati volatili.
64 byte EEPROM dimensione allocazione dati statici.
alimentazione 2-5,5V range (campo) della tensione di alimentazione.
1 Timer a 8 bit tipo e quantità dei timer interni.
WatchDog Timer (WDT) è un temporizzatore che se abilitato permette di
resettare il PIC se si blocca il programma
Interrupt se opportunamente programmato permette a particolari eventi di
fermare il programma principale per eseguirne una routine indipendente
detta di servizio.
Programmazione in Circuit funzionalità utile per programmare il dispositivo
anche se collegato al circuito di funzionamento.
Set di istruzioni: comprende 36 codici mnemonici in codice assembly.
Prima di procedere alla programmazione è necessario sapere come viene suddivisa la memoria interna al micropic perchè molte istruzioni fanno riferimento a locazioni (leggasi indirizzi) di memoria:
Il PIC 16F84 ha la memoria configurata come nella tabella che segue:
In modo particolare la memoria EEPROM di programma è cosi strutturata:
La memoria RAM dei dati è cosi strutturata:
Prime impostazioni sul software di programmazione:
Quando si seleziona il PIC 16F84 / 16F84A la
parola di configurazione consente le seguenti selezioni:
Oscillatore:
LP Quarzo bassa frequenza (ad esempio 32KHz).
XT Quarzo (ad esempio 4MHz).
HS Quarzo alta velocità (ad esempio 20MHz).
RC Clock tramite rete resistiva esterna.
Switch di configurazione:
WDT Watch Dog Timer spuntarlo se lo si utilizza.
PWRT Power-up Timer spuntarlo per attivare un ritardo nello Start-up.
CP Code Protection spuntarlo per attivare la
protezione del sorgente interno.
Per programmi basilari non spuntare alcuna voce. Selezionare XT se si usa
un quarzo a 4MHz.
Il PIC 16F628
Il PIC 16F628 ha lo stesso formato e la stessa piedinatura (e circa lo stesso costo 4-5 euro) del PIC 16F84, dispone però di alcune funzioni aggiuntive di alto livello. Può essere programmato esattamente con le stesse modalità del PIC 16F84.
Descrizione potenzialità del PIC16F628:
16 IN/OUT Pin (quantità ingressi e uscite
denominatio genericamente gates).
Corrente nei gates: ogni uscita gestisce 25mA (sink quindi verso
dentro e source quindi verso fuori).
Clock max 20MHz: solo la versione 16F84A.
2048 istruzioni di programma dimensione massima del programma.
224 Byte RAM dimensione allocazione dati volatili.
128 byte EEPROM dimensione allocazione dati statici.
alimentazione 2-5,5V range (campo) della tensione di alimentazione.
2 Timer a 8 bit tipo e quantità dei timer interni.
1 Timer a 16 bit
WatchDog Timer (WDT) è un temporizzatore che se abilitato permette di
resettare il PIC se si blocca il programma
Interrupt se opportunamente programmato permette a particolari eventi di
fermare il programma principale per eseguirne una routine indipendente
detta di servizio.
Programmazione in Circuit funzionalità utile per programmare il dispositivo
anche se collegato al circuito di funzionamento.
Set di istruzioni: comprende 36 codici mnemonici in codice assembly.
2 Comparatori analogici e uscita per tensione di riferimento
Funzione Capture per la misura precisa di intervalli di tempo
Funzione Compare per comparare due conteggi
Uscita in PWM con risoluzione sino a 10bit
Modulo USART (Universal Synchronous/Asynchronous Receiver
Transmitter) per gestire facilmente comunicazioni seriali
Funzioni aggiuntive:
Questo PIC consente una programmazione a bassa tensione con soli segnali 0÷5 V
senza la necessità del livello di programmazione a +12V (questa modalità viene
attivata tramite un apposito bit della parola di configurazione).
Descrizione
RA0-RA7 sono le linee della porta A configurabili separatamente come IN o
OUT.
RB0-RB7 sono le linee della porta B configurabili separatamente come IN o
OUT.
MCLR è il master reset utile per resettare il PIC a livello hardware
(normalmente a livello +Vdd, si porta a livello 0 per il reset).
Vdd alimentazione positiva da 3 a 5,5 volt.
Vss massa.
OSC1 e OSC2 pin utilizzati per il clock tramite quarzo oppure con
rete RC, CLKIN può essere usato per inviare un clock esterno.
RB6 e RB7 vengono usati in programmazione rispettivamente come
DATA e come CLOCK, vedi programmatore.
AN0÷AN3 ingresso comparatori analogici
Vref Uscita per tensione di riferimento generata internamente
CMP1, CMP2 uscita per i due comparatori di tensione
INT ingresso per interrupt esterno
RX/DT, TX/CK in out per modulo USART
CCP1 capture/compare/PWM Pin
Descrizione dimensione
memoria tra le due versioni analoghe di PIC
PIC 16F627 versione base del PIC con 1024 istruzioni
PIC 16F628 2048 istruzioni (anche versione a 20MHz)
Uso e descrizione della
parola di stato.
Quando si seleziona il PIC 16F628 in IC-PROG la parola di configurazione
è più complessa:
WDT Watch Dog Timer spuntarlo se lo si utilizza.
PWRT Power-up Timer spuntarlo per attivare un ritardo nello Start-up.
BODEN Brown-out Detect spuntarlo per attivare il reset in caso di
tensione bassa (un apposito circuito BOD rileva se la tensione di alimentazione
scende sotto il valore minimo di funzionamento).
MCLR MCLR=selzionato: Master-clear function. MCLR=deselezionato:
RA5 I/O MCLR connesso internamente a VDD.
LVP Low Level Program programmazione senza necessità dei +12V (utile per
la programmazione con soli segnali 0-5V, possibile la programmazione su BUS
I2C).
CPD Code Protection spuntarlo per attivare la protezione del sorgente
interno.
Il Clock interno
Il PIC 16F628 dispone di un generatore di clock
interno configurabile. Impostando con Ic-Prog Oscillator su IntRC/IO
viene selezionato come clock di sistema il generatore interno
preimpostato sul valore 4 MHz (bit0,1,4 della Configuration word). E'
possibile agendo sul bit3 (R/W-1) del registro PCON selezionare il valore di
37KHz al posto di 4MHz. Impostando con Ic-Prog Oscillator su ER I/O
viene selezionato come clock di sistema il generatore interno, programmabile con
una sola resistenza esterna, si possono ottenere tutte le frequenze tra
200KHz e 10MHz.
Queste modalità ovviamente permettono di liberare i due pin (non vengono
utilizzati il quarzo e i due condensatori ceramici) relativi al clock e di
poterli usare con funzioni di I/O.
Il PIC 12F629
Il PIC 12F629 ha un formato ad 8 pin sempre con memoria flash (cioè riprogrammabile) e costa circa 2 euro. La programmazione avviene con le stesse modalità del PIC 16F84 considerando che si dispone di meno linee di in/out.
Descrizione potenzialità del PIC16F629:
8
Pin complessivi
6 IN/OUT Pin (quantità ingressi e uscite
denominatio genericamente gates).
Corrente nei gates: ogni uscita gestisce 25mA (sink quindi verso
dentro e source quindi verso fuori).
Clock max 20MHz: solo la versione 16F629.
1024 istruzioni di programma dimensione massima del programma.
64 Byte RAM dimensione allocazione dati volatili.
128 byte EEPROM dimensione allocazione dati statici
ma riprogrammabili.
alimentazione 2-5,5V range (campo) della tensione di alimentazione.
1 Timer a 8 bit tipo e quantità dei timer interni.
1 Timer a 16 bit
WatchDog Timer (WDT) è un temporizzatore che se abilitato permette di
resettare il PIC se si blocca il programma
Interrupt se opportunamente programmato permette a particolari eventi di
fermare il programma principale per eseguirne una routine indipendente
detta di servizio.
Programmazione in Circuit funzionalità utile per programmare il dispositivo
anche se collegato al circuito di funzionamento.
Set di istruzioni: comprende 36 codici mnemonici in codice assembly.
2 Comparatori analogici e uscita per tensione di riferimento
1 comparatore analogico con
tensione di riferimento.
Clock interno 4Mhz.
Descrizione
GP0-GP5 sono le linee
configurabili separatamente come IN o OUT.
MCLR è il master reset utile per resettare il PIC a livello hardware
(normalmente a livello +Vdd, si porta a livello 0 per il reset) in fase di
programmazione si può impostare MCLR interno cosi da poter utilizzare il pin GP3
come ingresso.
Vdd alimentazione positiva da 2 a 5,5 volt.
Vss massa.
OSC1 e OSC2 pin utilizzati per il clock tramite quarzo oppure con
rete RC, CLKIN può essere usato per inviare un clock esterno. Se si imposta il
clock interno i pin GP4 e GP5 sono pin di I/O normale.
ICSPDAT e ICSPCLK vengono usati in programmazione rispettivamente
come DATA e come CLOCK
Uso e descrizione della parola di stato del PIC 12F629 in IC-PROG:
Oscillatore:
LP Quarzo
bassa frequenza (pin GP4 e GP5 occupati).
XT
Quarzo (pin GP4 e GP5 occupati).
HS Quarzo
alta velocità (GP4 e GP5 occupati).
EC GP4 Ingresso clock esterno in GP5 (GP4 I/O function).
INT OSC GP4 Oscillatore interno (4MHz) (GP4 e GP5 I/O function).
INT OSC ClkOut Oscillatore interno (4MHz) e segnale disponibile in GP4
(GP5 I/O function).
RC GP4 Oscillatore esterno con rete RC su pin GP5 (GP4
I/O function).
RC ClkOut Oscillatore esterno con rete RC su pin GP5 (GP4
Clock Out)
BandGap: Seleziona il livello di tensione per la funzione
POR e BOD.
WDT Watch
Dog Timer spuntarlo se lo si utilizza.
PWRTE Power-up Timer spuntarlo per attivare un ritardo nello Start-up.
MCLR MCLR=1: Master-clear function. MCLR=0: GP3 I/O MCLR connesso
internamente a VDD.
BODEN rown-out Detect spuntarlo per attivare il reset in caso di
tensione bassa.
CP Code Protection
spuntarlo per attivare la protezione del sorgente interno.
CPD Data Code Protection spuntarlo per
attivare la protezione dell'area dati.
Se si usa MPLAB IDE per la simulazione è
importante specificare la parola di programmazione in modo che il Debug
possa identificare i pin effettivamente disponibili.
Il Clock interno.
Il PIC 12F629 dispone di un generatore di clock interno configurabile.
Impostando con Ic-Prog Oscillator su IntRC/IO viene selezionato come clock di
sistema il generatore interno preimpostato sul valore 4 MHz. Il clock può essere
calibrato.
Durante la programmazione con IC-Prog, può comparire un messaggio relativo alla
mancata calibrazione, si può rispondere NO e lasciare la calibrazione
preimpostata.
Il PIC 12F675
Il PIC 12F675 ha un formato ad 8 pin sempre con memoria flash (cioè
riprogrammabile) e costa circa 2 euro. La programmazione avviene con le stesse
modalità del PIC 16F84 considerando che si dispone di meno linee di in/out.
E' lo stesso componente del 12F629 ma dispone anche di un modulo di conversione
A/D a 4 canali con risoluzione di 10bit.
8
Pin complessivi
6 IN/OUT Pin (quantità ingressi e uscite
denominatio genericamente gates).
Corrente nei gates: ogni uscita gestisce 25mA (sink quindi verso
dentro e source quindi verso fuori).
Clock max 20MHz: versione 16F675.
1024 istruzioni di programma dimensione massima del programma.
64 Byte RAM dimensione allocazione dati volatili.
128 byte EEPROM dimensione allocazione dati statici
ma riprogrammabili.
alimentazione 2-5,5V range (campo) della tensione di alimentazione.
1 Timer a 8 bit tipo e quantità dei timer interni.
1 Timer a 16 bit
WatchDog Timer (WDT) è un temporizzatore che se abilitato permette di
resettare il PIC se si blocca il programma
Interrupt se opportunamente programmato permette a particolari eventi di
fermare il programma principale per eseguirne una routine indipendente
detta di servizio.
Programmazione in Circuit funzionalità utile per programmare il dispositivo
anche se collegato al circuito di funzionamento.
Set di istruzioni: comprende 36 codici mnemonici in codice assembly.
1 Comparatori analogici e uscita per tensione di
riferimento
1 comparatore analogico con
tensione di riferimento.
Clock interno 4Mhz.
MCLR interno o esterno
Convertitore A/D 4canali con risoluzione 10bit
Descrizione:
GP0-GP5 sono le linee configurabili separatamente come IN o OUT.
MCLR è il master reset utile per resettare il PIC a livello hardware
(normalmente a livello +Vdd, si porta a livello 0 per il reset) in fase di
programmazione si può impostare MCLR interno cosi da poter utilizzare il pin GP3
come ingresso.
AN0-AN3 sono i pin configurabili come ingressi per il convertitore A/D.
Vdd alimentazione positiva da 2 a 5,5 volt.
Vss massa.
OSC1 e OSC2 pin utilizzati per il clock tramite quarzo oppure con
rete RC, CLKIN può essere usato per inviare un clock esterno. Se si imposta il
clock interno i pin GP4 e GP5 sono pin di I/O normale.
ICSPDAT e ICSPCLK vengono usati in programmazione rispettivamente
come DATA e come CLOCK
Note sulla programmazione
Quando si seleziona il PIC 12F675 in IC-PROG la parola di configurazione è:
Oscillatore:
LP Quarzo
bassa frequenza (pin GP4 e GP5 occupati).
XT Quarzo
(pin GP4 e GP5 occupati).
HS Quarzo alta
velocità (GP4 e GP5 occupati).
EC GP4 Ingresso clock esterno
in GP5 (GP4 I/O function).
INT OSC GP4 Oscillatore interno (4MHz) (GP4 e GP5 I/O function).
INT OSC ClkOut Oscillatore interno (4MHz) e segnale disponibile in GP4
(GP5 I/O function).
RC GP4 Oscillatore esterno con rete RC su pin GP5 (GP4
I/O function).
RC ClkOut Oscillatore esterno con rete RC su pin GP5 (GP4
Clock Out)
BandGap: Seleziona il livello di tensione per la funzione
POR e BOD.
WDT Watch Dog Timer spuntarlo se lo
si utilizza.
PWRTE Power-up Timer spuntarlo per attivare un ritardo nello Start-up.
MCLR MCLR=1: Master-clear function. MCLR=0: GP3 I/O MCLR connesso
internamente a VDD.
BODEN Brown-out Detect spuntarlo per attivare il reset in caso di
tensione bassa.
CP Code Protection
spuntarlo per attivare la protezione del sorgente interno.
CPD Data Code Protection spuntarlo
per attivare la protezione dell'area dati.
Il Clock interno.
Il PIC 12F675 dispone di un generatore di clock interno configurabile.
Impostando con Ic-Prog Oscillator su IntRC/IO viene selezionato come clock di
sistema il generatore interno preimpostato sul valore 4 MHz. Il clock può essere
calibrato.
Durante la programmazione con IC-Prog, può comparire un messaggio relativo alla
mancata calibrazione, si può rispondere NO e lasciare la calibrazione
preimpostata.
Il PIC 16F818
Il PIC 16F818 ha lo stesso formato e la stessa piedinatura del PIC 16F84 e PIC16F628, dispone però di alcune funzioni aggiuntive di alto livello. Il suo costo è decisamente contenuto, circa 2-3 euro. E' di nuova generazione in tecnologia NanoWatt, dispone di tutte le funzionalità già descritte nel PIC 16F84 e in più comprende un convertitore A/D a 5 canali con una risoluzione di 10bit. Può essere programmato esattamente con le stesse modalità del PIC 16F84 e 16F628.
16 IN/OUT Pin
Corrente nei gates: ogni uscita gestisce 25mA (sink quindi verso
dentro e source quindi verso fuori).
Clock max 20MHz: versione 16F818.
1024 istruzioni di programma dimensione massima del programma.
128 Byte RAM dimensione allocazione dati volatili.
128 byte EEPROM dimensione allocazione dati statici
ma riprogrammabili.
alimentazione 2-5,5V range (campo) della tensione di alimentazione.
2 Timer a 8 bit tipo e quantità dei timer interni.
1 Timer a 16 bit
WatchDog Timer (WDT) è un temporizzatore che se abilitato permette di
resettare il PIC se si blocca il programma
Interrupt se opportunamente programmato permette a particolari eventi di
fermare il programma principale per eseguirne una routine indipendente
detta di servizio.
Programmazione in Circuit funzionalità utile per programmare il
dispositivo anche se collegato al circuito di funzionamento.
Set di istruzioni: comprende 36 codici mnemonici in codice assembly.
Convertitore A/D 5 canali 10 bit.
1 Comparatore analogici e uscita per tensione di
riferimento.
Funzione Capture per la misura precisa di intervalli di tempo.
Funzione Compare per comparare due conteggi.
Uscita in PWM con risoluzione sino a 10bit.
Gestione di una porta seriale sincrona e del BUS I2C.
Clock interno programmabile con 8 frequenze.
Programmazione a bassa tensione con soli segnali 0÷5 V.
Descrizione:
RA0-RA7 sono le linee della porta A configurabili separatamente come IN o
OUT.
RB0-RB7 sono le linee della porta B configurabili separatamente come IN o
OUT.
MCLR è il master reset utile per resettare il PIC a livello hardware
(normalmente a livello +Vcc, si porta a livello 0 per il reset). Si può
configurare MCLR gestito internamente in modo da utilizzare il pin con funzioni
di I/O.
Vdd alimentazione positiva da 3 a 5,5 volt.
Vss massa.
OSC1 e OSC2 pin utilizzati per il clock tramite quarzo oppure con
rete RC, CLKIN può essere usato per inviare un clock esterno. E' possibile usare
il clock interno e usare i pin come normali I/O.
RB6 e RB7 vengono usati in programmazione rispettivamente come
DATA e come CLOCK, vedi programmatore.
AN0÷AN3 ingresso comparatori analogici o convertitore ADC.
Vref Uscita per tensione di riferimento generata internamente.
Descrizione dimensione
memoria tra le due versioni analoghe di PIC
PIC 16F818 versione base del PIC con
1024 istruzioni
PIC 16F819 2048 istruzioni, 256 byte RAM
Note sulla programmazione
Quando si seleziona il PIC 16F818 in IC-PROG la parola di configurazione è più
complessa:
Oscillatore:
LP Quarzo bassa frequenza (pin RA6 e RA7 occupati).
XT Quarzo (pin RA6 e RA7 occupati).
HS Quarzo alta velocità (pin RA6 e RA7 occupati).
ExtCLK Ingresso clock esterno in RA7 (RA6 I/O function).
IntRC Oscillatore interno (frequenza configurabile) (RA6 e RA7 I/O
function).
IntRC ClkOut Oscillatore interno (frequenza configurabile) e
segnale disponibile in RA6 (RA7 I/O function).
ExtRC Oscillatore esterno con rete RC su pin RA7 (RA6 I/O function).
ExtRC ClkOut Oscillatore esterno con rete RC su pin RA7 (RA6 Clock Out)
BandGap: Seleziona il livello di tensione per la funzione POR e BOD.
Write Enable: Indica la parte di memoria Flash protetta la scrittura
WRT 0000h-05FF
WRT 0000h-03FF
WRT 0000h-01FF
WRT OFF
Fuses:
WDT Watch Dog Timer spuntarlo se lo si utilizza.
PWRT Power-up Timer spuntarlo per attivare un ritardo nello Start-up.
MCLR MCLR=selzionato: Master-clear function. MCLR=deselezionato: RA5
funzione di I/O e MCLR connesso internamente a VDD.
BODEN Brown-out Detect spuntarlo per attivare il reset in caso di
tensione bassa (un apposito circuito BOD rileva se la tensione di alimentazione
scende sotto il valore minimo di funzionamento).
LVP Low Level Program programmazione senza necessità dei +12V (utile per
la programmazione con soli segnali 0-5V, possibile la programmazione su BUS
I2C).
CPD Code Protection spuntarlo per attivare la protezione del sorgente
interno.
DEBUGGER Attiva il Debugger mode (RB6 e RB7 sono usati per il debug).
CCPMX CCP1 pin selection bit (non selezionato CCP1 assegnato a RB3,
selezionato CCP1 assegnato a RB2).
Impostazione del Clock.
Il clock può essere impostato in 8 modalità differenti durante la fase di
programmazione (tramite la configurazione di IcProg alla voce Oscillatore). Se
viene impostata una modalità di clock interno (ovviamente non servono componenti
aggiuntivi esterni per generare il clock) è possibile selezionare la frequenza
interna tramite il valore scritto sul registro OSCCON.
Per i normali programmi la impostiamo a 4 MHz scrivendo su OSCCON il valore 60H
(B'01100000'). Per selezionare altre frequenza si rimanda ai datasheet.
Utilizzando il clock interno RA6 e RA7 possono essere usati come normali pin
digitali.
Se in fase di programmazione non selezioniamo MCLR possiamo omettere la
resistenza tra il pin 4 (MCLR) e il positivo di alimentazione e possiamo
utilizzarlo normalmente.
Basi di
programmazione e configurazione hardware.
i PICmicro (in questo caso un PIC16F84A) si presentano esternamente come dei normali circuiti integrati TTL o CMOS, ma internamente dispongono di tutti dispositivi tipici di un sistema a microprocessore, ovvero:
Una CPU (Central Processor Unit) ovvero una unità centrale di elaborazione il cui scopo è interpretare le istruzioni di programma.
Una memoria FLASH in cui sono memorizzare in maniera permanente le istruzioni del programma da eseguire.
U
Una serie di LINEE DI I/O (Input/Output) ovvero linee di ingresso e uscita per pilotare dispositivi esterni o ricevere impulsi da sensori, pulsanti, ecc.
Una serie di dispositivi ausiliari al funzionamento quali generatori di clock, bus, contatori, ecc.
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.
I PICmicro sono disponibili in un'ampia gamma di modelli per meglio adattarsi alle esigenze di progetto specifiche, differenziandosi per numero di linee di I/O e per dotazione di dispositivi. Si parte dai modelli più piccoli identificati dalla sigla PIC12C5xx dotati di soli 8 pin, fino ad arrivare ai modelli più grandi con sigla PIC18Cxx dotati di 40 e più pin.
il PIC16F84A dispone di una memoria per contenere il programma di tipo FLASH che può essere riscritta quante volte vogliamo e quindi ideale per i nostri esperimenti.
Il circuito "Hello World"
ovvero il passo obbligato da fare per iniziare. Un "LED lampeggiante"
Nella figura seguente viene presentato il progetto basilare che consente il
collegamento del PIC16F84A ad un clock esterno a 4Mhz, a una fonte di
alimentazione a +5V compatibile TTL, e a un LED con la sua resistenza di
limitazione alla prima porta di uscita.
Data la semplicità del circuito si potrà realizzarlo anche su basetta sperimentale breadboard.
La tensione di alimentazione
di 5 volt viene inviata ai pin Vdd (pin 14) e Vss (pin 5) collegati
rispettivamente al positivo ed alla massa.
Il pin MCLR (pin 4) serve per poter effettuare il reset del PICmicro.
Normalmente viene mantenuto a 5 volt tramite la resistenza di pull up R1 e messo
a zero quando si desidera resettare il PICmicro.
Grazie alla circuiteria interna di reset di cui il PICmicro è dotato, non è
necessario collegare al pin MCLR pulsanti o circuiti RC per ottenere il reset
all'accensione.
I pin OSC1/CLKIN (pin 16) e OSC2/CLKOUT (pin 15) sono collegati internamente al circuito per la generazione della frequenza di clock utilizzata per temporizzare tutti i cicli di funzionamento interni al chip.
Da questa frequenza dipende la quasi
totalità delle operazioni interne ed in particolare la velocità con cui il
PICmicro esegue le istruzioni del programma.
Nel caso del PIC16F84A-04/P tale frequenza può raggiungere un massimo di
4Mhz (anche se in realtà è pratica comune spingere tale frequenza a
valori molto superiori, operazione chiamata overclocking) da cui si ottiene una
velocità di esecuzione delle istruzioni pari a 1 milione di istruzioni al
secondo. Nel nostro caso per la generazione del clock viene utilizzato un quarzo
esterno da 4 MHz e due condensatori da 22pF.
Il pin RB0 (pin 6) è una delle linee di I/O disponibili sul PICmicro per i
nostri scopi. In questo caso questa linea è stata collegata ad un led tramite
una resistenza di limitazione.
Scrittura e compilazione del programma Assembly.
Ogni istruzione è rappresentata da un codice operativo (in inglese operation code o più brevemente opcode) composto da 14 bit ed è memorizzata in una locazione di memoria dell'area programma. Tale memoria nel PIC16F84A è di tipo FLASH e dispone di 1024 locazioni ognuna delle quali è in grado di contenere una sola istruzione oppure una coppia istruzione/dato.
Un esempio di opcode in notazione binaria viene riportato di seguito:
00 0001 0000 0000
ma è più probabile che un opcode venga rappresentato in notazione esadecimale ovvero:
0x100
che rappresenta esattamente lo stesso valore ma in forma più breve. La 0x davanti al valore indica che si tratta di una notazione esadecimale. Lo stesso valore può essere rappresentato in assembler con la notazione H'0100'.
Questi codici, completamente privi di senso per un essere umano, sono gli unici che il PICmicro è in grado di capire. Per fortuna esistono alcuni strumenti che consentono di facilitare il compito al programmatore rendendo le istruzioni più comprensibili.
Per convenzione si associa, ad ogni opcode, una breve sigla detta mnemonica, ovvero una sigla che aiuti a ricordare la funzione svolta da ogni istruzione.
L'opcode 0x100 dell'esempio precedente, effettua l'azzeramento del registro W (vedremo meglio di seguito che cosa significa) che in inglese viene indicato con la frase CLEA
R W REGISTER, ovvero "AZZERA IL REGISTRO W" che nella forma abbreviata diventa CLRW.Altre sigle mnemoniche consentono di definire tutte le istruzioni che il PICmicro è in grado di eseguire ma anche variabili, costanti ed etichette (label). L'insieme di queste sigle e le regole per ordinarle per formare un programma completo viene chiamato LINGUAGGIO ASSEMBLY.
Per scrivere un programma in linguaggio assembly
occorre conoscere le istruzioni disponibili sul micro che
si intende usare (in questo caso il PICmicro), le regole sintattiche per
definire variabili,
parametri, ecc e disporre di un editor di testo con cui digitare il nostro
programma.
Il file di testo così ottenuto viene denominato source o
sorgente assembler.
Il passo successivo consiste nel tradurre il nostro sorgente
assembler nella giusta sequenza di istruzioni in formato
binario che il PICmicro è in grado di capire. Questo tipo di programma si
chiama compilatore assembler o assemblatore.
Nella figura seguente viene schematizzato il flusso di operazioni ed i file generati necessari per ottenere un PICmicro programmato.
La prima operazione da effettuare è
la scrittura del source assembler e la sua memorizzazione in un file di testo.
L'estensione di questo file deve essere .ASM.
Possiamo usare allo scopo un semplice editor ASCII quale, ad esempio NOTEPAD di
Windows anche se è vivamente consigliabile un edit ascii pensato appositamente
per sviluppare sorgenti. Un ottimo programma da utilizzare sotto windows è
Ultraedit32.
;**************************************************
; Programma di esempio "lampeggiatore led"
; LED.ASM
;**************************************************
PROCESSOR 16F84
RADIX
DEC
INCLUDE
"P16F84.INC"
ERRORLEVEL -302
;Setup of PIC configuration flags
;XT oscillator
;Disable watch dog timer
;Enable power up timer
;Disable code protect
__CONFIG 0x3FF1
LED EQU
0
ORG 0x0C
Count RES
2
;Reset Vector
;Start point at CPU reset
ORG 0x00
bsf
STATUS,RP0
movlw B'00011111'
movwf TRISA
movlw B'11111110'
movwf TRISB
bcf
STATUS,RP0
bsf
PORTB,LED
MainLoop
call
Delay
btfsc PORTB,LED
goto SetToZero
bsf
PORTB,LED
goto MainLoop
SetToZero
bcf
PORTB,LED
goto
MainLoop
;Subroutines
;Software delay
Delay
clrf
Count
clrf
Count+1
DelayLoop
decfsz Count,1
goto DelayLoop
decfsz Count+1,1
goto DelayLoop
return
END
Il passo successivo è la compilazione
del source, ovvero la trasformazione in opcode dei codici mnemonici o istruzioni
assembler in esso contenute.
Il compilatore assembler che utilizzeremo è l'MPASM.EXE prodotto dalla
Microchip.
Come è possibile vedere nella figura precedente, oltre al nostro source con
estensione .ASM è necessario fornire al compilatore un secondo file prodotto
dalla Microchip con estensione .INC, differente a seconda del tipo di PICmicro
che stiamo utilizzando. Nel nostro caso il file è il P16F84.INC. Questo source
contiene alcune definizioni dipendenti dal chip utilizzato che vedremo più
avanti.
Durante la compilazione, l'assemblatore genera una serie di file con il nome
identico al source da cui derivano, ma con estensione diversa. Vediamo quali
sono e cosa contengono:
.HEX è il file contenete gli
opcode da inserire nella memoria programma del PICmicro.
.LST è un file di testo in cui
viene riportato l'intero source assembler e la corrispondente traduzione in
opcode. Non è utilizzabile per la programmazione del PICmicro ma è estremamente
utile per verificare i processi di compilazione che ha eseguito l'assemblatore.
.ERR contiene la lista
degli errori di compilazione riscontrati ed il numero di linea all'interno del
source assembler in cui sono stati rilevati.
I file .LST e .ERR vengono utilizzati
per il controllo di quanto effettuato in compilazione. Solo il file .HEX viene
utilizzato realmente per programmare il PICmicro.
Il file .HEX non è un file in formato binario ma un file codificato in un
formato inventato dalla Intel per la descrizione dei file binari in formato
ASCII. Senza entrare troppo nei dettagli è utile sapere che tale formato è
direttamente riconoscibile da qualsiasi programmatore di PICmicro il quale
provvederà a leggere da questo formato gli opcode ed a trasferirli nella memoria
del PICmicro.
Analizziamo il programma Assembly riga per riga.
Analizziamo ora linea per linea il contenuto del nostro source
LED.ASM. Per chi dispone di unastampante è utile effettuare una stampa del source per poter meglio seguire la nostra descrizione.
Altrimenti è preferibile visualizzare il source in una finestra separata in modo da seguire
simultaneamente il source e la relativa spiegazione.
Partiamo dalla prima linea di codice:
PROCESSOR 16F84
PROCESSOR è una direttiva del compilatore assembler che consente di definire per quale
microprocessore è stato scritto il nostro source. Le direttive non sono delle istruzioni mnemoniche
che il compilatore traduce nel rispettivo opcode, ma delle semplici indicazioni rivolte al compilatore
per determinarne il funzionamento durante la compilazione. In questo caso informiamo il
compilatore che le istruzioni che abbiamo inserito nel nostro source sono relative ad un PIC16F84.
RADIX DEC
La direttiva
RADIX serve ad informare il compilatore che i numeri riportati senza notazione, sonoda intendersi come numeri decimali. Ovvero se intendiamo specificare, ad esempio il numero
esadecimale 10 (16 decimale) non possiamo scrivere solamente 10 perché verrebbe interpretato
come 10 decimale, ma 0x10 oppure H'10'.
ERRORLEVEL -302
La direttiva ERRORLEVEL serve ad escludere la segnalazione di alcuni errori di compilazione. Nel
nostro caso viene utilizzata per evitare che il compilatore ci segnali questi due errori:
Message[302] C:\EPIC\LED.ASM 37 :
Register in operand not in bank 0.
Ensure that bank bits are correct.
Message[302] C:\EPIC\LED.ASM 40 :
Register in operand not in bank 0.
Ensure that bank bits are correct.
I quali ci avvertono che alla linea 37 e 40 del nostro sorgente vengono usati dei registri che non
si trovano sul banco 1 e ci ricordano di commutare banco. Vedremo in seguito il significato reale
di
questi errori. Per ora limitiamoci a filtrarli.
INCLUDE "P16F84.INC"
Ancora un'altra direttiva per dire al compilatore la nostra intenzione di includere nel source un
secondo file denominato
P16F84.INC. Il compilatore si limiterà a sostituire la linea contenente ladirettiva INCLUDE con il contenuto del file indicato e ad effettuare quindi la compilazione come se
fosse anch'esso parte del nostro source.
LED EQU 0
La direttiva
EQU è molto importante in quanto ci consente di definire delle costanti simbolicheall'interno del nostro source. In particolare la parola
LED da questo punto in poi del source saràequivalente al valore 0. Lo scopo principale dell'esistenza della direttiva EQU è quindi rendere i
source più leggibili e consentire di cambiare i valori costanti in un unico punto del source.
E' importante notare che la parola LED non identifica una variabile ma semplicemente un nome
simbolico valido durante la compilazione. Non sarà quindi possibile inserire instruzioni tipo LED = 3
all'interno del source in quanto l'assegnazione dinamica di un valore ad una variabile è
un'operazione che richiede l'intervento della CPU del PICmicro e che quindi deve essere espressa
con istruzioni e non con direttive.
Le direttive hanno senso solo durante la compilazione del source quindi un PICmicro non potrà mai
eseguire una direttiva.
Vediamo ora la linea seguente:
ORG 0x0C
Anche
ORG è una direttiva e ci consente di definire l'indirizzo da cui vogliamo che il compilatoreinizi ad allocare i dati o le istruzioni seguenti. In questo caso stiamo per definire un'area dati
all'interno del PICmicro ovvero un'area in cui memorizzare variabili e contatori durante
l'esecuzione del nostro programma. Quest'area coincide con l'area RAM del PICmicro definita dalla
Microchip come area dei
FILE REGISTER.I file register altro non sono che locazioni RAM disponibili per l'utente a partire dall'indirizzo 0x0C.
Questo indirizzo di inizio è fisso e non può essere cambiato in quanto le locazioni precedenti sono
occupate da altri registri specializzati per uso interno.
Count RES 2
In questa linea incontriamo una label:
Count e una direttiva: RES.La direttiva RES indica al compilatore che intendiamo riservare un certo numero di byte o meglio di
file register all'interno dell'area dati; in questo caso 2 byte. La label Count, dove Count è un nome
scelto da noi, è un marcatore che nel resto del source assumerà il valore dell'indirizzo in cui è stato
inserito. Dato che precedentemente avevamo definito l'indirizzo di partenza a 0x0C con la direttiva
ORG, Count varrà 0x0C. Se ad esempio inseriamo una label anche alla linea successiva essa varrà
0x0C + 2 (due sono i byte che abbiamo riservato) ovvero 0x0E. I nomi delle label possono essere
qualsiasi ad eccezione delle parole riservate al compilatore quali sono le istruzioni mnemoniche e le
direttive).
Una label si distingue da una costante simbolica perchè il suo valore viene calcolato in fase di
compilazione e non assegnato da noi staticamente.
ORG 0x00
Questa seconda direttiva ORG fà riferimento ad un indirizzo in area programma (nella FLASH)
anzichè in area dati. Da questo punto in poi andremo infatti ad inserire le istruzioni mnemoniche
che il compilatore dovrà convertire negli opportuni opcode per il PICmicro.
Il primo opcode eseguito dal PICmicro dopo il reset è quello memorizzato nella locazione 0, da qui
il valore 0x00 inserito nella ORG.
bsf STATUS,RP0
Ecco finalmente la prima istruzione mnemonica completa di parametri. I PICmicro hanno una CPU
interna di tipo
RISC per cui ogni istruzione occupa una sola locazione di memoria, opcode eparametri inclusi. In questo caso l'istruzione mnemonica
bsf sta per BIT SET FILE REGISTERovvero metti a uno (condizione logica alta) uno dei bit contenuti nella locazione di ram specificata.
Il parametro STATUS viene definito nel file
P16F84.INC tramite una direttiva EQU. Il valoreassegnato in questo file è 0x03 e corrisponde ad un file register (ovvero una locazione ram
nell'area dati) riservato.
Anche il parametro RP0 viene definito nel file P16F84.INC con valore 0x05H e corrisponde al
numero del bit che si vuole mettere a uno. Ogni file register è lungo 8 bit e la numerazione di
ciascuno parte da 0 (bit meno significativo) fino ad arrivare a 7 (bit più significativo)
Questa istruzione in pratica mette a 1 il quinto bit del file register STATUS. Questa operazione è
necessaria, come vedremo nelle lezioni successive, per accedere ai file register TRISA e TRISB
come vedremo ora.
movlw B'00011111'
Questa istruzione sta a significare:
MOVE LITERAL TO W REGISTER ovvero muovi un valorecostante nell'accumulatore. Come avremo modo di vedere più avanti, l'accumulatore è un
particolare registro utilizzato dalla CPU in tutte quelle situazioni in cui vengono effettuate
operazioni tra due valori oppure in operazioni di spostamento tra locazioni di memoria. In pratica è
un registro di appoggio utilizzato dalla CPU per memorizzare temporaneamente un byte ogni volta
che se ne presenta la necessità.
Il valore costante da memorizzare nell'accumulatore è
00011111 ovvero un valore binario a 8 bitdove il bit più a destra rappresenta il bit 0 o bit meno significativo.
Nell'istruzione successiva:
movwf TRISA
il valore 00011111 viene memorizzato nel registro TRISA (come per il registro STATUS anche
TRISA è definito tramite una direttiva EQU) la cui funzione è quella di definire il funzionamento di
ogni linea di I/O della porta A. In particolare ogni bit ad uno del registro TRISA determina un
ingresso sulla rispettiva linea della porta A mentre ogni 0 determina un'uscita.
Nella seguente tabella viene riportata la configurazione che assumeranno i pin del PICmicro dopo
l'esecuzione di questa istruzione:
Come è possibile vedere i bit 5, 6 e 7 non corrispondono a nessuna linea di I/O e quindi il loro
valore non ha alcuna influenza.
Le due istruzioni successive svolgono le stesse funzioni per la porta B del PICmicro:
movlw B'11111110'
movwf TRISB
in questo caso la definizione delle linee sarà la seguente:
Notate come il valore 0 nel bit 0 del registro TRISB determini la configurazione in uscita della
rispettiva linea del PICmicro. Nella nostra applicazione infatti questa linea viene utilizzata per
pilotare il LED da far lampeggiare.
Abbiamo visto che l'istruzione
movwf TRISB trasferisce il valore contenuto nell'accumulatore(inizializzato opportunamente con l'istruzione
movlw B'11111110') nel registro TRISB. Ilsignificato di movwf è infatti
MOVE W TO FILE REGISTER.bcf STATUS,RP0
Questa istruzione è simile alla
bsf vista in precedenza, con la sola differenza che azzera il bitanzichè metterlo a uno. La sigla un questo caso è
BIT CLEAR FILE REGISTER.Dal punto di vista funzionale questa istruzione è stata inserita per consentire l'accesso ai registri
interni del banco 0 anzichè ai registri interni del banco 1 di cui fanno parte TRISA e TRISB. Una
descrizione più dettagliata verrà data più avanti in questo corso.
bsf PORTB,LED
Con questa istruzione viene effettuata la prima operazione che ha qualche riscontro all'esterno del
PICmicro. In particolare viene acceso il led collegato alla linea RB0.
PORTB è una costante definitain P16F84.INC e consente di referenziare il file register corrispondente alle linee di I/O della porta
B mentre
LED è il numero della linea da mettere a 1. Se ben ricordate, all'inizio del source lacostante LED è stata definita pari a 0, quindi la linea interessata sarà RB0.
MainLoop
Questa linea contiene una
label ovvero un riferimento simbolico ad un indirizzo di memoria. Ilvalore della label, come detto in precedenza, viene calcolato in fase di compilazione in base al
numero di istruzioni, alle direttive ORG e alle altre istruzione che in qualche modo allocano spazio
nella memoria del PICmicro. In questo caso, se contiamo le istruzioni inserite a partire dall'ultima
direttiva ORG possiamo calcolare il valore che verrà assegnato a MainLoop ovvero
0x07.In realtà il valore che assumono le label non ha molta importanza in quanto il loro scopo è proprio
quello di evitare di dover conoscere la posizione precisa degli opcode nella memoria del PICmicro
permettendo comunque di referenziare una determinata locazione di memoria.
In questo caso la label MainLoop viene utilizzata come punto di ingresso di un ciclo (dall'inglese
Loop) di accensione e spegnimento del led, ovvero una parte di codice che verrà ripetuta
ciclicamente all'infinito. Incontreremo più avanti un riferimento a questa label.
call Delay
Questa istruzione determina una chiamata (dall'inglese
call) ad una subroutine che inizia incorrispondenza della label
Delay.Le subroutine sono delle parti di programma specializzare ad effettuare una funzione specifica.
Ogni qualvolta è necessaria quella funzione è sufficiente richiamarla con una sola istruzione,
anzichè ripetere ogni volta tutte le istruzioni necessarie ad effettuarla. In questo caso la subroutine
inserisce un ritardo pari al tempo di accensione e spegnimento del led.
Le istruzioni che compongono la subroutine
Delay sono inserite più avanti in questo stesso source.btfsc PORTB,LED
Il significato di questa istruzione è
BIT TEST FLAG, SKIP IF CLEAR ovvero controlla lo stato di unbit all'interno di un registro e salta l'istruzione successiva se il valore di tale bit è zero. Il bit da
controllare corrisponde alla linea di uscita cui è collegato il diodo led, tramite questo test potremo
determinare quindi se il led è acceso o spento e quindi agire di conseguenza, ovvero se il led è gia
acceso lo spegneremo, se il led è spento lo accenderemo.
goto SetToZero
Questa istruzione è un salto incondizionato (dall'inglese
GO TO, vai a)alla label SetToZero dovetroveremo le istruzioni per spegnere il led. Questa istruzione verrà saltata dall'istruzione
successiva se il led è gia spento.
bsf PORTB,LED
goto MainLoop
Queste due istruzioni semplicemente
accendono il led e rimandano il programma all'ingresso delciclo di lampeggiamento.
SetToZero
bcf PORTB,LED
goto MainLoop
Queste due istruzioni semplicemente
spengono il led e rimandano il programma all'ingresso delciclo di lampeggiamento.
La subroutine Delay
Come descritto in precedenza questa subroutine inserisce un ritardo di circa un secondo e può
essere chiamata più volte nel source tramite l'istruzione
call Delay.Vediamo come funziona:
Delay
clrf Count
clrf Count+1
DelayLoop
decfsz Count,1
goto DelayLoop
decfsz Count+1,1
goto DelayLoop
retlw 0
Delay e
DelayLoop sono due label. Delay identifica l'indirizzo di inizio della subroutine e vieneutilizzato per le chiamate dal corpo principale del programma.
DelayLoop viene chiamatointernamente dalla subrountine e serve come punto di ingresso per il ciclo (dall'inglese loop) di
ritardo.
In pratica il ritardo viene ottenuto eseguendo migliaia di istruzioni che non fanno nulla !
Questo tipo di ritardo si chiama ritardo software o ritardo a programma. E' il tipo di ritardo più
semplice da implementare e può essere utilizzato quando non è richiesto che il PICmicro esegua
altri compiti mentre esegue il ritardo.
Le istruzioni:
clrf Count
clrf Count+1
CLEA
R FILE REGISTER azzerano le due locazioni di ram riservate precedentemente conl'istruzione:
Count RES 2
Queste due locazioni sono adiacenti a partire dall'indirizzo referenziato dalla label Count.
decfsz Count,1
L'istruzione significa
DECREMENT FILE REGISTER, SKIP IF ZERO ovvero decrementa il contenutodi un registro (in questo caso Count e salta l'istruzione successiva se il valore raggiunto è zero). Se
il valore raggiunto non è zero viene eseguita l'istruzione successiva:
goto DelayLoop
Che rimanda rimanda l'esecuzione all'inizio del ciclo di ritardo. Una volta raggiunto lo zero con il
contatore Count vengono eseguite le istruzioni:
decfsz Count+1,1
goto DelayLoop
Che decremetano il registro seguente fino a che anche questo raggiunge lo zero. Il registro
Count+1 in particolare verrà decrementato di uno ogni 256 decrementi di Count.
Quando anche Count+1 avrà raggiunto lo zero l'istruzione:
return
il cui significato è
RETURN FROM SUBROUTINE determinerà l'uscita dalla routine di ritardo ed ilproseguimento dell'esecuzione dall'istruzione successiva la call Delay.
Per finire
END è una direttiva che indica al compilatore la fine del source assembler.compilazione del programma Assembly.
Vediamo ora come è possibile effettuare in pratica la compilazione di un source assembler.
Per prima cosa creiamo sul nostro disco fisso una directory di lavoro in cui da ora in poi
memorizzeremo tutti i file sorgenti del nostro corso. Scegliamo un nome quale ad esempio:
C:\PBE
(Qualsiasi altro nome di directory o drive è ovviamente valido. Basterà sostituire nel resto del
corso tutti i riferimento a C:\PBE con il nome del drive e della directory scelti).
Copiamo ora nella nostra directory di lavoro C:\PBE il file
LED.ASM. Per far questo basta cliccarecon il tasto destro del mouse sul nome e richiedere di salvare il file nella nostra directory di lavoro.
Scarichiamo ora da internet il compilatore MPASM disponibile gratuitamente dal sito Microchip al
seguente indirizzo:
http://www.microchip.com/1010/pline/tools/archive/other/61/index.htm
Il file da scaricare è
asm21500.zip (579K) e contiene l'assembler MPASM sia in versioneWindows (MPASMWIN.EXE) che
MS/DOS (MPASM.EXE) oltre ad una serie di utility e tutti file .INCper i vari microprocessori prodotti da Microchip .
Una volta espanso il contenuto dei file asm21500.zip nella nostra directory di lavoro possiamo
lanciare il file MPASMWIN.EXE.
La schermata che apparirà sarà la seguente:
Premiamo il tasto "Browse..." e selezioniamo il sorgente LED.ASM. Quindi premiamo il tasto
"Assemble". L'assemblatore inizierà a compilare.
Al termine della compilazione otterremo la seguente schermata:
Se andiamo ora a vedere nella directory C:\PBE nuovi file creati, troveremo il file LED.HEX
contenente il codice oggetto da utilizzare per programmare il PICmicro ed i file di supporto
LED.ERR e LED.LST spiegati precedentemente.
Siamo ora pronti per programmare il PIC16F74A con il programma appena compilato.
Che programmatore usare?
Qualsiasi programmatore commerciale o autocostruito in grado di programmare PIC16F84 può
essere ovviamente usato con successo per seguire il corso.
In questo caso per le modalità di programmazione dei PICmicro di prega di seguire le istruzioni di corredo al
programmatore stesso.
I Flags di configurazione dei PIC.
Il PICmicro dispone di una serie di flag di configurazione contenuti nella cosidetta configuration
word. Questi flag determinano alcune modalità di funzionamento del PICmicro quando esso
esegue un programma. La configurazione dei flag è indicata nei source d'esempio con la
direttiva __CONFIG e dovrebbe essere letta correttamente da quasi tutti i programmatori di
PICmicro. Alcuni di questi però non lo fanno
per cui i flag vanno settati manualmente prima di iniziare la programmazione.
Tutti gli esercizi riportati in questo corso, salvo quando esplicitamente indicato usano la seguente configurazione:
Oscillatore in modalità XT. In questa modalità il PICmicro funziona correttamente con un quarzo collegato ai pin OSC1 e OSC2 come indicato in ogni scahema proposto.
Esistono altri flag di configurazione il cui settaggio non determina cambiamenti sull'esito degli
esercizi.
Inserimento del programma nel PIC.
Assicuriamoci di aver installato correttamente sia l'hardware che il software del nostro
programmatore di PICmicro (per l'installazione hardware e software del programmatore EPIC fare
riferimento a questo articolo).
Lanciamo quindi il software di gestione del programmatore (nel caso dell'EPIC il programma da
lanciare in ambiente Windows è EPICWIN.EXE.
Selezioniamo il tipo di PICmicro da programmare, un PIC16F84A (in molti casi va bene anche la
selezione del PIC16F84).
Inseriamo il PICmicro da programmare nella zoccolo del programmatore facendo attenzione che la
disposizione del PICmicro sia corretta (Nel caso dell'EPIC bisogna far corrispondere il pin 1 del
PICmicro con l'indicazione "Pin 1" riportata sulla serigrafia del circuito stampato.
Carichiamo ora il file LED.HEX dalla directory di lavoro C:\PBE (Su EPICWin si seleziona la voce
"Menu File" seguita da "Open").
Assicuriamoci che il software del programmatore abbia interpretato correttamente la
configurazione della configuration word.
con particolare attenzione al tipo di oscillatore che deve essere settato su XT. E sulla
disabilitazione del watch dog timer. L'errata interpretazione di questi due parametri da parte del
software del programmatore potrebbe portare al mancato funzionamento dei nostri esempi.
Avviamo la programmazione (Menu "Run" --> "Program"). Se non ci sono segnalazioni d'errore da
parte del software del programmatore possiamo togliere il PICmicro programmato ed inserirlo nel
circuito d'esempio.
Fornendo l'alimentazione dovremmo vedere il led lampeggiare.
Files di configurazione e heder files per la corretta configurazioen del PIC.
LIST
; P16F84.INC Standard Header File, Version 2.00 Microchip Technology, Inc. NOLIST
; This header file defines configurations, registers, and other useful bits of
; information for the PIC16F84 microcontroller. These names are taken to match
; the data sheets as closely as possible.
; Note that the processor must be selected before this file is
; included. The processor may be selected the following ways:
; 1. Command line switch:
; C:\ MPASM MYFILE.ASM /PIC16F84
; 2. LIST directive in the source file
; LIST P=PIC16F84
; 3. Processor Type entry in the MPASM full-screen interface
;==========================================================================
;
; Revision History
;
;==========================================================================
;Rev: Date: Reason:
;2.00 07/24/96 Renamed to reflect the name change to PIC16F84.
;1.01 05/17/96 Corrected BADRAM map
;1.00 10/31/95 Initial Release
;==========================================================================
;
; Verify Processor
;
;==========================================================================
IFNDEF __16F84
MESSG "Processor-header file mismatch. Verify selected processor."
ENDIF
;==========================================================================
;
; Register Definitions
;
;==========================================================================
W EQU H'0000'
F EQU H'0001'
;----- Register Files------------------------------------------------------
INDF EQU H'0000'
TMR0 EQU H'0001'
PCL EQU H'0002'
STATUS EQU H'0003'
FSR EQU H'0004'
PORTA EQU H'0005'
PORTB EQU H'0006'
EEDATA EQU H'0008'
EEADR EQU H'0009'
PCLATH EQU H'000A'
INTCON EQU H'000B'
OPTION_REG EQU H'0081'
TRISA EQU H'0085'
TRISB EQU H'0086'
EECON1 EQU H'0088'
EECON2 EQU H'0089'
;----- STATUS Bits --------------------------------------------------------
IRP EQU H'0007'
RP1 EQU H'0006'
RP0 EQU H'0005'
NOT_TO EQU H'0004'
NOT_PD EQU H'0003'
Z EQU H'0002'
DC EQU H'0001'
C EQU H'0000'
;----- INTCON Bits --------------------------------------------------------
GIE EQU H'0007'
EEIE EQU H'0006'
T0IE EQU H'0005'
INTE EQU H'0004'
RBIE EQU H'0003'
T0IF EQU H'0002'
INTF EQU H'0001'
RBIF EQU H'0000'
;----- OPTION Bits --------------------------------------------------------
NOT_RBPU EQU H'0007'
INTEDG EQU H'0006'
T0CS EQU H'0005'
T0SE EQU H'0004'
PSA EQU H'0003'
PS2 EQU H'0002'
PS1 EQU H'0001'
PS0 EQU H'0000'
;----- EECON1 Bits --------------------------------------------------------
EEIF EQU H'0004'
WRERR EQU H'0003'
WREN EQU H'0002'
WR EQU H'0001'
RD EQU H'0000'
;==========================================================================
;
; RAM Definition
;
;==========================================================================
__MAXRAM H'CF'
__BADRAM H'07', H'50'-H'7F', H'87'
;==========================================================================
;
; Configuration Bits
;
;==========================================================================
_CP_ON EQU H'000F'
_CP_OFF EQU H'3FFF'
_PWRTE_ON EQU H'3FF7'
_PWRTE_OFF EQU H'3FFF'
_WDT_ON EQU H'3FFF'
_WDT_OFF EQU H'3FFB'
_LP_OSC EQU H'3FFC'
_XT_OSC EQU H'3FFD'
_HS_OSC EQU H'3FFE'
_RC_OSC EQU H'3FFF'
LIST
Architettura interna dei PIC16F84A.
Dopo aver fatto un pò di pratica nella lezione precedente, passiamo ora alla teoria. Iniziamo a vedere com'è
fatto internamente un PICmicro, quali dispositivi contiene e come interagiscono tra loro.
Nella figura seguente viene riprodotto lo schema a blocchi semplificato dell'architettura interna del
PIC16F84A che ci aiuterà a seguire meglio quanto verrà spiegato di seguito. Le parti evidenziate in giallo,
sono le componenti che di volta in volta andremo ad analizzare.
Iniziamo dalla memoria programma o PROGRAM MEMORY e dalla memoria dati o REGISTER FILE.
La Program Memory
La PROGRAM MEMORY è una memoria speciale di tipo FLASH, non cancellabile elettricamente, ed utilizzata
nel PICmicro per tenere memorizzato il programma da eseguire.
La sua capacità di memorizzazione è di 1024 locazioni ognuna in grado di contenere un opcode a 14 bit
ovvero una istruzione base del PICmicro. Il programma più complesso che potremo realizzare non potrà
essere quindi più lungo di 1024 istruzioni.
Gli indirizzi riservati alla PROGRAM MEMORY vanno da 0x000 a 0x3FF (0x3FF esadecimale = 1023
decimale).
Il PICmicro può solamente eseguire le istruzioni memorizzate in queste locazioni. Non può in alcun modo
leggere, scrivere o cancellare quanto in esse contenuto. Questo vale in particolar modo per i PIC16F84A
mentre su altri modelli quali i PIC16F87x è possibile anche aggiornare la memoria programma a run time
ovvero a programma in esecuzione.
Per scrivere, leggere e cancellare queste locazioni è necessario un dispositivo esterno denominato
programmatore. Un esempio di programmatore è l'EPIC Plus il o PICSTART prodotto dalla Microchip o
molti altri ancora disponibili in commercio.
La prima locazione di memoria, all'indirizzo zero, deve contenere la prima istruzione che il PICmicro dovrà
eseguire al reset e per questo viene nominata Reset Vector.
Come ricorderete, nel source LED.ASM presentato più in alto in questa pagina web era stata inserita la direttiva:
ORG 0x00
per segnare l'inizio del programma. Questa direttiva tiene conto del fatto che l'esecuzione del programma
al reset parte dall'indirizzo 0x000 dell'area programma.
L'istruzione che segue immediatamente la direttiva ORG 0x00:
bsf STATUS,RP0
sarà quindi la prima istruzione ad essere eseguita.
Il Register File
Il REGISTER FILE è un'insieme di locazioni di memoria RAM ovvero memorie con cui è possibile leggere e
modificare il contenuto senza l'ausilio di programmatori esterni e direttamente dal programma in
esecuzione sul PICmicro.
Date le sue caratteristiche il REGISTER FILE è la memoria normalmente utilizzata per memorizzare le
variabili di programma, ovvero tutti quei valori il cui contenuto varia durante l'esecuzione.
Contrariamente alla PROGRAM MEMORY il REGISTER FILE perde il suo contenuto quando il PICmicro viene
spento per cui è necessario reinizializzare i valori di tutte le sue locazioni prima di poterla usare.
Alcune locazioni del REGISTER FILE ed in particolare quelle che si trovano agli indirizzi più bassi vengono
usate per il controllo dell'hardware del PICmicro secondo quanto illustrato di seguito.
Le locazioni di memoria presenti nel REGISTER FILE sono indirizzabili direttamente in uno spazio di memoria che va da 0x00 a 0x2F per un totale di 48 byte, denominato pagina 0. Un secondo spazio di indirizzamento denominato pagina 1 va da 0x80 a 0xAF. Per accedere a questo secondo spazio è necessario ricorrere ai due bit ausiliari RP0 e RP1 secondo le modalità che andremo a spiegare più avanti.
Le prime 12 locazioni della pagina 0 (da 0x00 a 0x0B) e della pagina 1 (da 0x80 a 0x8B) sono quelle riservate alle funzioni speciali per il funzionamento del PICmicro e non possono essere utilizzate per altri scopi.
Le 36 locazioni in pagina 0 indirizzate da 0x0C a 0x2F possono essere utilizzate liberamente dai nostri programmi per memorizzare variabili, contatori, ecc.
Nel nostro esempio LED.ASM la direttiva:
ORG 0x0C
indica proprio l'indirizzo di inizio dell'area dati utilizzabile dal nostro programma.
La direttiva che segue:
Count RES 2
riserva uno spazio di due locazioni, che il programma utilizzerà per memorizzare i contatori di ritardo della subroutine Delay.
I registri specializzati del PIC vengono utilizzati molto di frequente nei programmi.
Ad esempio, si ricorre alla coppia di registri specializzati TRISA (0x85) e TRISB (0x86), per definire quali
linee di I/O sono in ingresso e quali in uscita. Lo stesso stato logico delle linee di I/O dipende dal valore dei due registri PORTA (0x05) e PORTB (0x06).
Alcuni registri riportano lo stato di funzionamento dei dispositivi interni al PICmicro o il risultato di operazioni aritmetiche e logiche.
E' necessario conoscere esattamente quale funzione svolge ciascun registro specializzato e quali effetti si ottengono nel manipolarne il contenuto.
Per facilitare le operazioni sui registri specializzati, nel file P16F84.INC (che come ricorderete era stato incluso nel source LED.ASM con la direttiva INCLUDE) la Microchip ha inserito una lista di nomi che identificano univocamente ciascun registro specializzato e a cui sono associati gli indirizzi corrispondenti nell'area dei REGISTER FILE.
Se, ad esempio, volessimo definire tutte le linee della porta B del PIC in uscita agendo sul registro TRISB, potremmo scegliere di referenziare direttamente il registro con il suo indirizzo:
movlw B'00000000'
movwf 0x86
oppure, referenziare lo stesso registro con il suo nome simbolico:
movlw B'00000000'
movwf TRISB
avendo però l'accortezza di inserire la direttiva INCLUDE "P16F84.INC" nel nostro source.
La ALU
La ALU (acronimo di Arithmetic and Logic Unit ovvero unità aritmetica e logica) è la componente più
complessa del PICmicro in quanto contiene tutta la circuiteria delegata a svolgere le funzioni di calcolo e
manipolazione dei dati durante l'esecuzione di un programma.
La ALU è una componente presente in tutti i microprocessori e da essa dipende direttamente la potenza di
calcolo del micro stesso.
La ALU del PIC16F84A è in grado di operare su valori ad 8 bit, ovvero valori numerici non più grandi di
255. Esistono microprocessori con ALU a 16, 32, 64 bit e oltre. La famiglia Intel© 80386©, 486© e
Pentium© ad esempio dispone di una ALU a 32 bit. Le potenze di calcolo raggiunte da questi micro sono
notevolmente superiori a scapito della complessità della circuiteria interna ed accessoria e
conseguentemente dello spazio occupato.
L'Accumulatore o registro W
Direttamente connesso con la ALU c'è il registro W denominato anche accumulatore. Questo registro
consiste di una semplice locazione di memoria in grado di contenere un solo valore a 8 bit.
La differenza sostanziale tra il registro W e le altre locazioni di memoria consiste proprio nel fatto che, per
referenziare ill registro W, la ALU non deve fornire nessun indirizzo di memoria, ma può accedere
direttamente.
Il registro W viene utilizzato molto spesso nei programmi per PICmicro.
Facciamo un esempio pratico. Supponiamo di voler inserire nella locazione di memoria 0xC del REGISTER
FILE il valore 0x01. Cercando tra le istruzioni del PICmicro ci accorgiamo subito che non esiste un'unica
istruzione in grado di effettuare questa operazione ma dobbiamo necessariamente ricorrere
all'accumulatore ed usare due istruzioni in sequenza.
Vediamo perché:
Come detto nei passi precedenti, l'opcode di una istruzione non può essere più grande di 14 bit mentre a
noi ne servirebbero:
8 bit per specificare il valore che intendiamo inserire nella locazione di memoria,
7 bit per specificare in quale locazione di memoria vogliamo inserire il nostro valore,
6 bit per spcificare quale istruzione intendiamo utilizzare.
per un totale di 8 + 7 + 6 = 21 bit.
Dobbiamo quindi ricorrere a due istruzioni, ovvero:
movlw 0x01
movwf 0x0C
che prima inseriscono nel registro W il valore 0x01H con l'istruzione MOVe Literal to W e poi lo
"muovono" nella locazione 0x0C con l'istruzione MOVe W to F.
Il Program Counter (PC)
Come abbiamo già visto nei passi precedenti, il PIC16F84A inizia l'esecuzione del programma a partire dal
vettore di reset (Reset Vector) ovvero dall'istruzione memorizzata nella prima locazione di memoria
(indirizzo 0x000).
Dopo aver eseguito questa prima istruzione passa quindi all'istruzione successiva memorizzata nella
locazione 0x001 e così via. Se non esistesse nessuna istruzione in grado di influenzare in qualche modo
l'esecuzione del programma, il PICmicro arriverebbe presto ad eseguire tutte le istruzione presenti nella
sua memoria fino all'ultima locazione disponibile.
Sappiamo ovviamente che non è così e che qualsiasi microprocessore o linguaggio di programmazione
dispone di istruzioni di salto, ovvero di istruzioni in grado di modificare il flusso di esecuzione del
programma in base alle esigenze del programmatore.
Una di queste istruzioni è la GOTO (dall'inglese GO TO, vai a) che ci permette di cambiare la sequenza di
esecuzione e di "saltare" direttamente ad un qualsiasi punto, all'interno della memoria programma, e di
continuare quindi l'esecuzione a partire da quel punto.
Facciamo un esempio:
ORG 0x00
Point1
movlw
10goto
Point1Al reset il PICmicro eseguirà l'istruzione MOVLW 10 memorizzata alla locazione 0x000, la quale inserirà
nell'accumulatore il valore decimale 10, quindi passerà ad eseguire l'istruzione successiva GOTO Point1.
Questa istruzione determinerà un salto incondizionato alla locazione di memoria puntata dalla label Point1
ovvero di nuovo alla locazione 0x000. Nel suo insieme quindi, questo programma non farà altro che
eseguire continuamente le due istruzioni elencate.
Durante questo ciclo (o loop), per determinare quale sarà l'istruzione successiva da eseguire, il PIC utilizza
uno speciale registro denominato PROGRAM COUNTER (dall'inglese contatore di programma) la cui
funzione è proprio quella di mantenere traccia dell'indirizzo che contiene la prossima istruzione da
eseguire.
Questo registro viene incrementato automaticamente ad ogni istruzione eseguita per determinare il
passaggio all'istruzione successiva. Al momento del RESET del PIC il PROGRAM COUNTER viene azzerato,
determinando così l'inizio dell'esecuzione a partire dall'indirizzo 0x000.
L'istruzione GOTO consente l'inserimento a programma di un nuovo valore nel PROGRAM COUNTER ed il di
conseguente salto ad una locazione qualsiasi dell'area programma del PIC.
Lo Stack Pointer
Un'altra istruzione molto utile, che influenza il valore del PROGRAM COUNTER è la CALL (dall'inglese
chiamata) con la quale è possibile effettuare delle CHIAMATE A SUBROUTINE.
Questa istruzione funziona in maniera molto simile alla GOTO. Come la GOTO infatti permette di scrivere
nel PROGRAM COUNTER un nuovo indirizzo di esecuzione del programma. La differenza sostanziale
consiste però nel fatto che prima di eseguire il salto,. il PIC memorizza, in un altro registro speciale,
denominato STACK, l'indirizzo di quella che sarebbe dovuta essere la successiva istruzione da eseguire se
non si fosse incontrata la CALL.
Vediamo meglio con un esempio:
ORG 0x00
Point1
movlw
10call
Point2goto
Point1Point2
movlw
11return
In questo caso il PICmicro, dopo aver eseguito la MOVLW 10 passa ad eseguire listruzione CALL Point2.
Prima di saltare però, memorizza nello STACK l'indirizzo 0x002, ovvero l'indirizzo della locazione
successiva alla CALL. L'esecuzione passa quindi all'istruzione MOVLW 11 e quindi alla istruzione RETURN
(dall'inglese ritorno). Questa istruzione, come dice il suo nome, consente di "ritornare", ovvero di
riprendere l'esecuzione a partire dall'istruzione successiva alla CALL che aveva determinato l'abbandono
del flusso principale del programma utilizzando il valore memorizzato nel registro di STACK.
Come detto l'operazione appena effettuata viene denominata CHIAMATA A SUBROUTINE, ovvero una
interruzione momentanea del normale flusso di programma per "chiamare" in esecuzione una serie di
istruzioni per poi ritornare al normale flusso di esecuzione.
La parola STACK in inglese significa "catasta o pila" ed infatti su questa catasta è possibile depositare, uno
sull'altro, più indirizzi per recuperarli quando servono. Questo tipo di memorizzazione viene anche
denominata LIFO dall'inglese Last In First Out, in cui l'ultimo elemento inserito (last in) deve
necessariamente essere il primo ad uscire (last out). Grazie a questa caratteristica è possibile effettuare
più CALL annidate ovvero l'una nell'altra e mantenere sempre traccia del punto in cui riprendere il flusso al
momento che si incontra una istruzione RETURN.
Vediamo un altro esempio:
ORG 0x00
Point1
movlw
10call
Point2goto
Point1Point2
movlw
11call
Point3return
Point3
movlw
12return
In questo caso nella subroutine Point2 viene effettuata un'ulteriore CALL alla subroutine Point3. Al ritorno
da quest'ultima il programma dovrà rientrare nella subroutine Point2 eseguire la RETURN e quindi tornare
nel flusso principale.
Gli indirizzi da memorizzare nello stack sono due in quanto viene incontrata una seconda CALL prima
ancora di incontrare la RETURN corrispondente alla prima.
Il PIC16F84A dispone di uno stack a 8 livelli, ovvero uno stack che consente fino ad 8 chiamate annidate..
E' importante assicurasi, durante la stesura di un programma, che ci sia sempre una istruzione RETURN
per ogni CALL per evitare pericolosi disallineamenti dello stack che in esecuzione possono dar adito a errori
difficilmente rilevabili.
Realizziamo le "luci in sequenza"
Proviamo ora a fissare i concetti finora appresi rielaborando il source LED.ASM presentato nella prima
lezione per realizzare un lampeggiatore sequenziale a quattro led. Il nuovo source modificato si chiamerà
SEQ.ASM
.Nella figura seguente viene riportato lo schema elettrico del nuovo circuito, sostanzialmente equivalente al
circuito presentato nella prima lezione, con l'unica variante che ora i led collegati sono quattro anziché
uno.
Le linee di I/O utilizzate sono RB0 per primo led, RB1 per il secondo, RB2 per il terzo ed RB3 per il
quarto. Esse vanno quindi configurate tutte in uscita all'inizio del programma cambianto le istruzioni:
movlw
B'11111110'movwf
TRISBin
movlw
B'11110000'movwf
TRISBin cui i quattro bit meno significativi, corrispondenti alle linee RB0,1,2,3 vengono messi a zero per definire
tali linee in uscita.
Nell'area di memoria del REGISTER FILE (che nel source inizia con la direttiva ORG 0x0C) oltre ai due byte
referenziati dalla label Count, riserviamo un ulteriore byte con label Shift che utilizzeremo per determinare
la sequenza di accensione dei led. La direttiva da inserire è:
Shift RES 1
Prima di eseguire il ciclo principale (label MainLoop) inizializiamo il nuovo registro Shift a 00000001B con le
seguenti istruzioni istruzioni:
movlw
B'00000001'movwf
ShiftA questo punto, nel ciclo principale del nostro programma, ci occuperemo di trasferire il valore
memorizzato nel registro Shift sulla Porta B ottenendo quindi l'accensione del primo led, con le seguenti
istruzioni:
movf
Shift,Wmovwf
PORTBquindi di effettuare lo shift a sinistra del valore contenuto in Shift di un bit, con le seguenti istruzioni:
bcf
STATUS,Crlf
Shift,Fla prima istruzione serve ad azzerare il bit CARRY del registro di stato STATUS che verrà analizzato nelle
lezioni successive. L'istruzione RLF Rotate Left F through Carry (ruota a sinistra attraverso il bit di carry)
sposta di un bit verso sinistra il valore memorizzato nel registro Shift inserendo nella posizione occupata
dal bit 0 il valore del bit di Carry (che come già detto andremo a vedere in seguito). Per far si che il bit
inserito sia sempre zero viene eseguita prima della RLF l'istruzione BCF STATUS,C per azzerare questo bit.
A questo punto il registro Shift varrà 00000010, quindi, al ciclo successivo, una volta trasferito tale valore
sulla port B si otterrà lo spegnimento del LED1 e l'accensione del LED2 e così via per i cicli successivi.
Quando il bit 4 di Shift varrà 1, vorrà dire che tutti e quattro i led sono stati accesi almeno una volta e
occorre quindi ripartire dal led 1. Le istruzioni seguenti svolgono questo tipo di controllo:
btfsc
Shift,4swapf
Shift,FL'istruzione BTFSC Shift,4 controlla appunto se il bit 4 del registro Shift vale 1. Se si esegue l'istruzione
successiva SWAPF Shift,F altrimenti la salta.
L'istruzione SWAP (dall'inglese "scambia") in pratica scambia i quattro bit più significativi contenuti nel
registro Shift con i quattro meno significativi. Dal valore iniziale del registro Shift pari a 00010000 ottenuto
dopo alcune ripetizioni del ciclo MainLoop si ottiene il valore 00000001 ed in pratica alla riaccensione del
primo led.
;**************************************************
; Programma accensione sequenza di led
; SEQ.ASM
;**************************************************
PROCESSOR 16F84
RADIX DEC
INCLUDE "P16F84.INC"
ERRORLEVEL -302
;Setup of PIC configuration flags
;XT oscillator
;Disable watch dog timer
;Enable power up timer
;Disable code protect
__CONFIG 0x3FF1
ORG 0x0C
Count RES 2
Shift RES 1
;Reset Vector
;Program start point at CPU reset
ORG 0x00
bsf STATUS,RP0
movlw B'00011111'
movwf TRISA
movlw B'11110000'
movwf TRISB
bcf STATUS,RP0
movlw B'00000001'
movwf Shift
MainLoop
movf Shift,W
movwf PORTB
bcf STATUS,C
rlf Shift,F
btfsc Shift,4
swapf Shift,F
call Delay
goto MainLoop
; Subroutines
Delay
clrf Count
clrf Count+1
DelayLoop
decfsz Count,1
goto DelayLoop
decfsz Count+1,1
goto DelayLoop
return
END
visualizza il programma in un'altra pagina
download il file .ASM "accende luci in sequenza"
Le porte A e B
Il PIC16F84A dispone di un totale di 13 linee di I/O organizzate in due porte denominate
PORTA A e
PORTA B.La PORTA A dispone di 5 linee configurabili sia in ingresso che in uscita identificate dalle
sigle RA0, RA1, RA2, RA3 ed RA4.
La PORTA B dispone di 8 linee anch'esse configurabili sia in ingresso che in uscita
identificate dalle sigle RB0, RB1, RB2, RB3, RB4, RB5, RB6 ed RB7.
La suddivisione delle linee in due porte distinte è dettata dai vincoli dell'architettura
interna del PIC16F84A che prevede la gestione di dati di lunghezza massima pari a 8 bit.
Per la gestione delle linee di I/O da programma, il PIC dispone di due registri interni per
ogni porta denominati TRISA e PORTA per la porta A e TRISB e PORTB per la porta B.
I registri TRIS A e B, determinano il funzionamento in ingresso o in uscita di ogni singola
linea, i registri PORT A e B determinano lo stato delle linee in uscita o riportano lo lo stato
delle linee in ingresso.
Ognuno dei bit contenuti nei registri menzionati corrisponde univocamente ad una linea di
I/O.
Ad esempio il bit 0 del registro PORTA e del registro TRIS A corrispondono alla linea RA0 ,
il bit 1 alla linea RA1 e così via.
Se il bit 0 del registro TRISA viene messo a zero, la linea RA0 verrà configurata come linea
in uscita, quindi il valore a cui verrà messo il bit 0 del registro PORTA determinerà lo stato
logico di tale linea (0 = 0 volt, 1 = 5 volt).
Se il bit 0 del registro TRISA viene messo a uno, la linea RA0 verrà configurata come linea
in ingresso, quindi lo stato logico in cui verrà posta dalla circuiteria esterna la linea RA0 si
rifletterà sullo stato del bit 0 del registro PORTA.
Facciamo un esempio pratico, ipotizziamo di voler collegare un led sulla linea RB0 ed uno
switch sulla linea RB4, il codice da scrivere sarà il seguente:
movlw 00010000B
tris B
in cui viene messo a 0 il bit 0 (linea RB0 in uscita) e a 1 il bit 4 (linea RB4) in ingresso. Si
ricorda a tale proposito che nella notazione binaria dell'assembler il bit più a destra
corrisponde con il bit meno significativo quindi il bit 0.
Per accendere il led dovremo scrivere il seguente codice:
bsf PORTB,0
Per spegnerlo:
bcf PORTB,0
Per leggere lo stato dello switch collegato alla linea RB4, il codice sarà:
btfss PORTB,4
goto SwitchAMassa
goto SwitchAlPositivo
Stadi d'uscita delle linee di I/O
Per rendere più adattabili i PICmicro alle diverse esigenze di utilizzo, la Microchip ha
implementato diverse tipologie di stati d'uscita per le linee di I/O. Esistono quindi dei
gruppi di pin il cui comportamento è leggermente differenziato da altri gruppi. Conoscendo
meglio il funzionamento dei diversi stadi d'uscita potremo sfruttare al meglio le loro
caratteristiche ed ottimizzare il loro uso nei nostri progetti.
Stadio d'uscita delle linee RA0, RA1, RA2 e RA3
Iniziamo dal gruppo di linee RA0, RA1, RA2 ed RA3 per le quali riproduciamo, nella figura
seguente, lo schema dello stadio d'uscita estratto dal data sheet della Microchip:
Come accennato al passo precedente, la configurazione di una linea come ingresso o
uscita dipende dallo stato dei bit nel registro TRIS (TRISA per la porta A e TRISB per la
porta B).
Prendiamo come esempio la linea RA0 ed analizziamo il funzionamento dello stadio
d'uscita sia quando la linea funziona in ingresso, che quando funziona in uscita.
Funzionamento in ingresso
Per configurare la linea RA0 in ingresso, dobbiamo mettere a 1 il bit 0 del registro TRISA
con l'istruzione:
bsf TRISA,0
Questo determina una commutazione ad 1 dello stato logico del flip-flop di tipo D-latch
indicato nel blocco con il nome TRIS latch. Per ogni linea di I/O esiste uno di questi flipflop
e lo stato logico in cui si trova dipende strettamente dallo stato logico del relativo bit
nel registro TRIS (anzi per meglio dire ogni bit del registro TRIS è fisicamente
implementato con un TRIS latch).
L'uscita Q del TRIS latch è collegata all'ingresso di una porta logica di tipo OR. Questo
significa che, indipendentemente dal valore presente all'altro ingresso, l'uscita della porta
OR varrà sempre 1 in quanto uno dei suoi ingressi vale 1 (vedi tavola della verità). In
questa condizione il transistor P non conduce e mantiene la linea RA0 scollegata dal
positivo d'alimentazione.
Allo stesso modo l'uscita negata del TRIS latch è collegata all'ingresso di una porta AND
quindi l'uscita di questa varrà sempre 0 in quanto uno dei suoi ingressi vale 0 (vedi
tavola). In questa condizione anche il transistor N non conduce mantenendo la linea RA0
scollegata anche dalla massa. Lo stato logico della linea RA0 dipenderà esclusivamente
dalla circuiteria esterna a cui la collegheremo.
Applicando 0 o 5 volt al pin RA0, sarà possibile leggerne lo stato sfruttando la circuiteria
d'ingresso del blocco rappresentata dal TTL input buffer e dal latch d'ingresso.
Funzionamento in uscita
Per configurare la linea RA0 in uscita, dobbiamo mettere a 0 il bit 0 del registro TRISA con
l'istruzione:
bcf TRISA,0
Questo determina la commutazione a 0 dell'uscita Q del TRIS latch (ed a 1 dell'uscita Q
negata). In questo stato il valore in uscita dalle porte OR e AND dipende esclusivamente
dallo stato dell'uscita Q negata del Data Latch. Come per il TRIS latch, anche il Data Latch
dipende dallo stato di un bit in un registro, in particolare del registro PORTA. La sua uscita
negata viene inviata all'ingresso delle due porte logiche OR e AND e quindi direttamente
sulla base dei transistor P ed N.
Se mettiamo a 0 il bit 0 del registro PORTA con l'istruzione:
bcf PORTA,0
otterremo la conduzione del transistor N con conseguente messa a 0 della linea RA0. Se
invece mettiamo a 1 il bit 0 con l'istruzione:
bsf PORTA,0
otterremo la conduzione del transistor P con conseguenza messa a +5 volt della linea RA0.
In questa condizione è sempre possibile rileggere il valore inviato sulla linea tramite la
circuiteria d'ingresso.
Stadio d'uscita della linea RA4
Analizziamo ora il funzionamento dello stadio d'uscita della linea RA4 che si differenzia da
tutte le altre linee di I/O in quanto condivide lo stesso pin del PIC16F84 con il TOCKI.
Nella figura seguente viene riprodotto lo schema a blocchi dello stadio d'uscita estratto dal
data sheet Microchip:
La logica di commutazione è sostanzialmente identica al gruppo di linee RA0-3 ad
eccezione dell'assenza della porta OR e del transistor P, ovvero di tutta la catena che
consente di collegare al positivo la linea RA4. Questo significa, in termini pratici, che
quando la linea RA4 viene programmata in uscita e messa a 1 in realtà non viene
connessa al positivo ma rimane scollegata. Tale tipo di circuiteria d'uscita viene
denominata a "collettore aperto" ed è utile per applicazioni in cui sia necessario
condividere uno stesso collegamento con più pin d'uscita e ci sia quindi la necessità di
mettere in alta impedenza una linea d'uscita senza doverla riprogrammare come linea
d'ingresso.
Se vogliamo essere sicuri che la linea RA4 vada a 1 dovremo collegare esternamente una
resistenza di pull-up, ovvero una resistenza collegata al positivo di alimentazione.
Vedremo in seguito l'utilizzo della linea indicata sullo schema TMR0 clock input.
Stadio d'uscita delle linee RB0, RB1, RB2 ed RB3
Anche per questo gruppo di linee rimane sostanzialmente invariata la logica di
commutazione. Esse dispongono in aggiunta una circuiteria di weak pull-up attivabile
quando le linee sono programmate in ingresso.
In ingresso infatti, come spiegato precedentemente, le linee vengono completamente
scollegate dal PIC in quanto sia il transitor P che il transistor N sono aperti. Lo stato delle
linee dipende quindi esclusivamente dalla circuiteria esterna. Se tale circuiteria è di tipo a
collettore aperto o più semplicemente è costituita da un semplice pulsante che, quando
premuto, collega a massa la linea di I/O, è necessario inserire una resistenza di pull-up
verso il positivo per essere sicuri che quando il pulsante è rilasciato ci sia una condizione
logica a 1 stabile sulla linea d'ingresso. La circuiteria di weak pull-up consente di evitare
l'uso di resistenze di pull-up e può essere attivata o disattivata agendo sul bit RBPU del
registro OPTION .
Nella figura seguente viene riprodotto lo schema a blocchi dello stadio d'uscita estratto dal
data sheet Microchip:
La sola linea RB0 inoltre, presenta una caratteristica molto particolare. Essa, quando viene
configurata come linea di ingresso, può generare, in corrispondenza di un cambio di stato
logico, un interrupt, ovvero una interruzione immediata del programma in esecuzione ed
una chiamata ad una subroutine speciale denominata interrupt handler. Ma di questo
parleremo in seguito.
Stadio d'uscita delle linee RB4, RB5, RB6 e RB7
La circuiteria di commutazione di questo gruppo di linee è identica al gruppo RB0-3.
Queste linee dispongono anche della circuiteria di weak pull-up. In più rispetto alle linee
RB0-3 hanno uno stadio in grado di rilevare variazioni di stato su una quansiasi linea e di
generare un interrupt di cui parleremo nelle prossime lezioni.
Nella figura seguente viene riprodotto lo schema a blocchi dello stadio d'uscita estratto dal
data sheet Microchip:
Input da tastiera
Dopo aver realizzato, nella lezione precedente, le luci in sequenza sfruttando le linee da
RB0 a RB3 come linee di output, vediamo ora come si può realizzare un input da tastiera
configurando le linee da RB4 a RB7 come linee di input.
Per far questo ampliamo il circuito presentato nella lezione 2 con quattro pulsanti da
stampato denominati SW1, SW2, SW3 ed SW4 e collegati secondo lo schema elettrico
riportato di seguito:
;**************************************************
; Acquisizione segnali in input
; INPUT.ASM
;***************************************************
PROCESSOR 16F84
RADIX DEC
INCLUDE "P16F84.INC"
;Setup of PIC configuration flags
;XT oscillator
;Disable watch dog timer
;Enable power up timer
;Disable code protect
__CONFIG 3FF1H
LED1 EQU 0
LED2 EQU 1
LED3 EQU 2
LED4 EQU 3
SW1 EQU 4
SW2 EQU 5
SW3 EQU 6
SW4 EQU 7
ORG 0CH
;Reset Vector
;Punto di inizio del programma al reset della CPU
ORG 00H
;Commuta sul secondo banco dei registri per accedere ai registri TRISA e TRISB
bsf STATUS,RP0
;Definizione delle linee di I/O (0=Uscita, 1=Ingresso)
;Definizione della porta A
movlw 00011111B
movwf TRISA & 7FH
;Definizione della porta B
;Le linee da RB0 a RB3 vengono programmate in uscita per essere collegate ai quattro led
;Le linee da RB4 a RB7 vengono programmate in ingresso per essere collegate ai quattro pulsanti
movlw 11110000B
movwf TRISB & 7FH
;Commuta sul primo banco dei registri
bcf STATUS,RP0
MainLoop
;Spegne tutti i led
clrf PORTB
;Se e' premuto il pulsante SW1 accende il LED1
btfss PORTB,SW1
bsf PORTB,LED1
;Se e' premuto il pulsante SW2 accende il LED2
btfss PORTB,SW2
bsf PORTB,LED2
;Se e' premuto il pulsante SW3 accende il LED3
btfss PORTB,SW3
bsf PORTB,LED3
;Se e' premuto il pulsante SW4 accende il LED4
btfss PORTB,SW4
bsf PORTB,LED4
goto MainLoop
END
Il contatore TMR0 ed il PRESCALER
Il registro contatore TMR0
Vediamo ora cosa è e come funziona il registro TMR0.
Il registro TMR0 è un contatore, ovvero un particolare tipo di registro il cui contenuto viene
incrementato con cadenza regolare e programmabile direttamente dall'hardware del PIC. In
pratica, a differenza di altri registri, il TMR0 non mantiene inalterato il valore che gli viene
memorizzato, ma lo incrementa continuamente, se ad esempio scriviamo in esso il valore 10
con le seguenti istruzioni:
movlw 10
movwf TMR0
dopo un tempo pari a quattro cicli macchina, il contenuto del registro comincia ad essere
incrementato a 11, 12, 13 e così via con cadenza costante e del tutto indipendente
dall'esecuzione del resto del programma.
Se, ad esempio, dopo aver inserito un valore nel registro TMR0, eseguiamo un loop infinito
movlw 10
movwf TMR0
loop
goto loop
il registro TMR0 viene comunque incrementato dall'hardware interno al PIC contemporaneamente all'esecuzione del loop.
Una volta raggiunto il valore 255 il registro TMR0 viene azzerato automaticamente riprendendo quindi il conteggio non dal valore originariamente impostato ma da zero.
La frequenza di conteggio è direttamente proporzionale alla frequenza di clock applicata al chip e può essere modificata programmando opportunamente alcuni bit di configurazione.
Nella figura seguente viene riportata la catena di blocchi interni al PIC che determinano il funzionamento del registro TMR0.
I blocchi Fosc/4 e T0CKI riportati in blu rappresentano le due possibili sorgenti di segnale per il contatore TMR0.
Fosc/4 è un segnale generato internamente al PIC dal circuito di clock ed è pari alla frequenza di clock divisa per quattro.
T0CKI è un segnale generato da un eventuale circuito esterno ed applicato al pin T0CKI corrispondente al pin 3 nel PIC16F84A.
I blocchi T0CS e PSA riportati in verde sono due commutatori di segnale sulla cui uscita viene presentato uno dei due segnali in ingresso in base al valore dei bit T0CS e PSA del registro OPTION.
Il blocco PRESCALER è un divisore programmabile il cui funzionamento verrà spiegato nel prossimo passo.
Vediamo in pratica come è possibile agire su questi blocchi per ottenere differenti modalità di conteggio per il registro TMR0.
Iniziamo programmando i bit T0CS a 0 e PSA a 1. La configurazione di funzionamento che otterremo è rappresentata nella seguente figura:
Le parti in rosso evidenziano il percorso che effettua il segnale prima di arrivare al contatore TMR0.
Come abbiamo già detto in precedenza, la frequenza Fosc/4 è pari ad un quarto della frequenza di clock. Utilizzando un quarzo da 4Mhz avremo una Fosc/4 pari ad 1 MHz. Tale
frequenza viene inviata direttamente al registro TMR0 senza subire nessun cambiamento. La cadenza di conteggio che se ne ottiene è quindi pari ad 1 milione di incrementi al secondo del valore presente in TMR0.
Ipotizziamo ora di cambiare lo stato del bit T0CS da 0 a 1 la configurazione che otteniamo è la seguente:
Questa volta sarà il segnale applicato al pin TOCKI del PIC ad essere inviato direttamente al contatore TMR0 determinandone la frequenza di conteggio. Applicando ad esempio a questo pin una frequenza pari ad 100Hz otterremo una frequenza di conteggio pari a cento incrementi al secondo.
La presenza della porta logica XOR (exclusive OR) all'ingresso TOCKI del PIC consente di determinare tramite il bit T0SE del registro OPTION se il contatore TMR0 deve essere incrementato in corrispondenza del fronte di discesa (T0SE=1) o del fronte di salita (T0SE=0) del segnale applicato dall'esterno.
Nella figura seguente viene rappresentata la corrispondenza tra l'andamento del segnale esterno ed il valore assunto dal contatore TMR0 in entrambe i casi:
Il Prescaler
L'ultimo blocco rimasto da analizzare per poter utilizzare completamente il registro TMR0 è il PRESCALER.
Se configuriamo il bit PSA del registro OPTION a 0 inviamo al registro TMR0 il segnale in uscita dal PRESCALER come visibile nella seguente figura:
Il PRESCALER consiste in pratica in un divisore programmabile a 8 bit da utilizzare nel caso la frequenza di conteggio inviata al contatore TMR0 sia troppo elevata per i nostri scopi.
Nell'esempio riportato al passo precedente abbiamo visto che utilizzando un quarzo da 4Mhz otteniamo una frequenza di conteggio pari ad 1Mhz che per molte applicazioni potrebbe risultare troppo elevata.
Con l'uso del PRESCALER possiamo dividere ulteriormente la frequenza Fosc/4 configurando opportunamente i bit PS0, PS1 e PS2 del registro OPTION secondo la seguente tabella.
Proviamo ora ad effettuare un esperimento sul campo per verificare quanto finora appreso. Nella lezione 2 avevamo realizzato un lampeggiatore a quattro led la cui sequenza di lampeggio era determinata da una subroutine che introduceva un ritardo software, ovvero un ritardo basato sul tempo di esecuzione di un ciclo continuo di istruzioni.
Proviamo ora a riscrivere la stessa subroutine per introdurre un ritardo pari ad un secondo utilizzando il registro TMR0.
Ecco il programma modificato.
;**************************************************
; Luci sequenziali con temporizzazione via TIMER 0
;Programmazione di specifici ritardi
;**************************************************
PROCESSOR 16F84
RADIX DEC
INCLUDE "P16F84.INC"
;Setup of PIC configuration flags
;XT oscillator
;Disable watch dog timer
;Enable power up timer
;Disable code protect
__CONFIG 3FF1H
ORG 0CH
Count RES 1
Shift RES 1
;Reset Vector - Punto di inizio del programma al reset della CPU
ORG 00H
;Commuta sul secondo banco dei registri
bsf STATUS,RP0
;Definizione delle linee di I/O (0=Uscita, 1=Ingresso)
movlw 00011111B
movwf TRISA & 7FH
movlw 11110000B
movwf TRISB & 7FH
;Assegna il PRESCALER a TMR0 e lo configura a 1:32
;Vedi subroutine Delay per maggiori chiarimenti
movlw 00000100B
movwf OPTION_REG & 0x7F
;Commuta sul primo banco dei registri
bcf STATUS,RP0
;Il registro Shift viene utilizzato per rappresentare internamente
;lo stato delle linee di uscita della porta B dove sono collegati i led.
;Il bit 0 del registro Shift viene settato ad uno per iniziare il ciclo
;dal primo led.
movlw 00000001B
movwf Shift
;Loop di scorrimento
MainLoop
;Invia sulla porta B il registro Shift cosi che ogni bit settato ad uno in Shift
;fara' accendere il led relativo
movf Shift,W
movwf PORTB
;Per ruotare le luci usa l'istruzione rlf che effettua lo shift a sinistra dei bit
;contenuti nel registro ed inserisce nel bit 0 lo stato del bit di carry. Per
;questo motivo prima di effettuare l'istruzione rlf azzera il bit di carry con l'istruzione
;bcf STATUS,C.
bcf STATUS,C
rlf Shift,F
;Quando lo shift raggiunge il bit 4 vengono invertiti i primi quattro bit del registro
;Shift con i secondi quattro bit in modo da ricominciare il ciclo dal bit 0.
;
; Ecco cosa succede ai bit del registro Shift durante l'esecuzione di questo loop:
;
; 00000001 <--- Valore iniziale (primo led acceso)
; 00000010 rlf
; 00000100 rlf
; 00001000 rlf
; 00010000 rlf a questo punto viene eseguita l'istruzione swapf ottenendo:
; 00000001 ...e cosi' via
btfsc Shift,4
swapf Shift,F
;Inserisce un ritardo tra una accensione e l'altra
call Delay
;Torna ad eseguire nuovamente il loop
goto MainLoop
;**************
; Subroutines
;**************
; Inserimento di un ritardo pari ad un secondo
; utilizzando il registro TMR0
;
; Il ritardo viene ottenuto dalla frequenza in uscita al PRESCALER pari a:
; 4Mhz / 4 / 32 = 31.250 Hz
; ... divisa per 250 dal TMR0 32.250 / 250 = 125 Hz
; ... e per 125 dal contatore Count 125 / 125 = 1Hz
Delay
; Inizializza TMR0 per ottenere 250 conteggi prima di arrivare a zero.
; Il registro TMR0 e' un registro ad 8 bit quindi se viene incrementato
; nuovamentre quando arriva a 255 ricomincia a contare da zero.
; Se lo si inizializza a 6 dovra' essere incrementato 256 - 6 = 250 volte
; prima passare per lo zero.
movlw 6
movwf TMR0
; Il registro Count viene inizializzato a 125 in quanto il suo scopo e' far
; uscire il loop
movlw 125
movwf Count
;Loop di conteggio
DelayLoop
;TMR0 vale 0 ?
movf TMR0,W
btfss STATUS,Z
goto DelayLoop ;No, aspetta...
movlw 6 ;Si, reimposta TMR0 e controlla se
movwf TMR0 ;e' passato per 125 volte per lo zero
decfsz Count,1
goto DelayLoop
return
END
Gli interrupt
L'interrupt è una particolare caratteristica dei PICmicro (e dei microprocessori in generale) che consente di intercettare un evento esterno, interrompere momentaneamente il programma in corso, eseguire una porzione di programma specializzata per la gestione dell'evento verificatosi e riprendere l'esecuzione del programma principale.
Volendo fare un paragone con il mondo reale possiamo dire che l'interrupt rappresenta per il PIC quello che per noi rappresenta ad esempio la suoneria del telefono.
Per poter ricevere telefonate non dobbiamo preoccuparci di alzare continuamente la cornetta per vedere se c'é qualcuno che vuol parlare con noi, ma, grazie alla suoneria, possiamo continuare tranquillamente a fare le nostre faccende in quanto saremo avvisati dà questa ogni volta che qualcuno ci sta chiamando.
Appena sentiamo lo squillo, possiamo decidere di interrompere momentaneamente le nostre faccende, rispondere al telefono e, una volta terminata la conversazione, riprendere dal punto in cui avevamo interrotto.
Riportando i termini di questo paragone al PIC abbiamo che:
le nostre faccende corrispondono al programma in esecuzione;
la chiamata da parte di qualcuno corrisponde all'evento da gestire;
lo squillo del telefono corrisponde alla richiesta di interrupt;
la nostra risposta al telefono corrisponde alla subroutine di gestione dell'interrupt.
E' evidente quanto sia più efficiente gestire un evento con un interrupt anzichè controllare ciclicamente il verificarsi dell'evento con il programma principale.
Gran parte degli aspetti legati alla gestione dell'interrupt vengono inoltre trattati direttamente dall'hardware interno del PIC per cui il tempo di risposta all'evento è praticamente immediato.
Tipi di evento e bit di abilitazione
Il PIC16F84A è in grado di gestire in interrupt quattro eventi diversi, vediamo quali sono:
1. Il cambiamento di stato sulla linea RB0 (External interrupt RB0/INT pin).
2. La fine del conteggio del registro TMR0 (TMR0 overflow interrupt).
3. Il cambiamento di stato su una delle linee da RB4 ad RB7 (PORTB change interrupts).
4. La fine della scrittura su una locazione EEPROM (EEPROM write complete interrupt).
L'interrupt su ognuno di questi eventi può essere abilitato o disabilitato indipendentemente dagli altri agendo sui seguenti bit del registro INTCON:
INTE (bit 4) se questo bit viene messo a 1 viene abilitato l'interrupt sul cambiamento di stato sulla linea RB0
T0IE (bit 5) se questo bit viene messo a 1 viene abilitato l'interrupt sulla fine del conteggio del registro TMR0
RBIE (bit 3) se questo bit viene messo a 1 viene abilitato l'interrupt sul cambiamento di stato su una delle linee da RB4 ad RB7
EEIE (bit 6) se questo bit viene messo a 1 viene abilitato l'interrupt sulla fine della scrittura su una locazione EEPROM
Esiste inoltre un bit di abilitazione generale degli interrupt che deve essere settato anch'esso ad uno ovvero il bit GIE (Global Interrupt Enable bit) posto sul bit 7 del registro INTCON.
Interrupt vector ed Interrupt handler
Qualunque sia l'evento abilitato, al suo manifestarsi il PIC interrompe l'esecuzione del programma in corso, memorizza automaticamente nello STACK il valore corrente del PROGRAM COUNTER e salta all'istruzione presente nella locazione di memoria 0004H denominata Interrupt vector (vettore di interrupt).
E' da questo punto che dobbiamo inserire la nostra subroutine di gestione dell'interrupt denominata Interrupt Handler (gestore di interrupt).
Potendo abilitare più interrupt, tra i primi compiti dell'interrupt handler è la verifica di quale, tra gli eventi abilitati, ha generato l'interrupt e l'esecuzione della parte di programma relativo.
Questo controllo può essere effettuato utilizzando gli Interrupt flag.
Interrupt flag
Dato che qualunque interrupt genera una chiamata alla locazione 04H, nel registro INTCON sono presenti dei flag che indicano quale è l'evento che ha generato l'interrupt, vediamoli:
INTF (bit 1) Se vale 1 l'interrupt è stato generato dal cambiamento di stato sulla linea RB0.
T0IF (bit 2) Se vale 1 l'interrupt è stato generato al termine del conteggio del timer TMR0.
RBIF (bit 0) Se vale 1 l'interrupt è stato generato dal cambiamento di stato di una delle linee da RB4 a RB7.
Come si vede per l'interrupt sul fine scrittura in EEPROM non è previsto alcun flag di segnalazione per cui l'interrupt handler dovrà considerare che l'interrupt è stato generato da questo evento quando tutti e tre i flag sopra citati valgono 0.
Importante: Una volta rilevato quale flag è attivo, l'interrupt handler deve azzerarlo altrimenti non verrà più generato l'interrupt corrispondente.
Ritorno da un interrupt handler
Quando viene generato un interrupt il PIC disabilita automaticamente il bit GIE (Global Interrupt Enable) del registro INTCON in modo da disabilitare tutti gli interrupt mentre è già in esecuzione un interrupt handler. Per poter ritornare al programma principale e reinizializzare a 1 questo bit occorre utilizzare l'istruzione:
RETFIE
Esempio pratico di gestione di un interrupt
Vediamo ora un esempio pratico di gestione degli interrupt. Prendiamo come base di partenza il source LED.ASM usato nella lezione 1 per realizzare il lampeggiatore a led.
Come ricorderete questo programma fa semplicemente lampeggiare il LED1 a ciclo continuo utilizzando un ritardo software introdotto dalla subroutine Delay.
Vediamo ora come è possibile fargli rilevare la pressione di un tasto ed accendere il LED 2 contemporaneamente all'esecuzione del programma principale.
Il source d'esempio che andremo ad analizzare è disponibile nel file INTRB.ASM
;**************************************************
; gestione di compiti multipli con interrupt
; INTRB.ASM
;**************************************************
PROCESSOR 16F84
RADIX DEC
INCLUDE "P16F84.INC"
;Setup of PIC configuration flags
;XT oscillator
;Disable watch dog timer
;Enable power up timer
;Disable code protect
__CONFIG 3FF1H
LED1 EQU 0
LED2 EQU 1
LED3 EQU 2
LED4 EQU 3
ORG 0CH
Count RES 2
nTick RES 1 ;Registro utilizzato per contare il numero di
;lampeggi del LED 1
;Reset Vector
;Punto di inizio del programma al reset della CPU
ORG 00H
;Salta al corpo principale del programma. Questo jump Š necessario
;per evitare tutta la parte di codice per la gestione degli
;interrupt.
goto Start
;Interrupt vector
;Punto di inizio per tutte le subroutine di gestione degli interrupt
ORG 04H
;**********************************************************************
; Interrupt handler
;**********************************************************************
;Accende il led 2 per segnalare che c'e' stato un interrupt
bsf PORTB,LED2
;Inizializza il contatore di lampeggi del LED1
movlw 3
movwf nTick
;Azzera nuovamente il flag RBIF per consentire all'interrupt di
;ripetersi
bcf INTCON,RBIF
;Ritorna al programma principale
retfie
;**********************************************************************
; Programma principale
;**********************************************************************
Start:
;Commuta sul secondo banco dei registri per accedere ai registri TRISA e TRISB
bsf STATUS,RP0
;Definizione delle linee di I/O (0=Uscita, 1=Ingresso)
;Definizione della porta A
movlw 00011111B
movwf TRISA & 7FH
;Definizione della porta B
;Le linee da RB0 a RB3 vengono programmate in uscita per essere collegate ai quattro
led
;Le linee da RB4 a RB7 vengono programmate in ingresso per essere collegate ai quattro
pulsanti
movlw 11110000B
movwf TRISB & 7FH
;Commuta sul primo banco dei registri
bcf STATUS,RP0
;Spegne tutti i led collegati sulla porta B
bcf PORTB,LED1
bcf PORTB,LED2
bcf PORTB,LED3
bcf PORTB,LED4
;Abilita l'interrupt sul cambiamento di stato delle linee RB4,5,6,7
movlw 10001000B
movwf INTCON
;**********************************************************************
; Loop principale
;**********************************************************************
MainLoop
call Delay ;Ritardo software
btfss PORTB,LED1 ;Led acceso ?
goto TurnOnLed1 ;No, lo accende
goto TurnOffLed1 ;Si, lo spegne
;Accensione led e decremento del contatore di lampeggi
TurnOnLed1
bsf PORTB,LED1
;Controlla se LED 2 di segnalazione dell'interrupt e' gia acceso.
;Se e' acceso decrementa il contatore nTick ad ogni lampeggio di
;LED1. Quando nTick vale 0 spegne LED 2
btfss PORTB,LED2 ;LED2 acceso ?
goto MainLoop ;No, continua a lampeggiare
decf nTick,1 ;Si, decrementa nTick
btfss STATUS,Z ;nTick = 0 ?
goto MainLoop ;No, continua a lampeggiare
bcf PORTB,LED2 ;Si, spegne LED2
goto MainLoop ;Continua a lampeggiare
;Spegnimento led
TurnOffLed1
bcf PORTB,LED1 ;Spegne LED 1
goto MainLoop ;Continua a lampeggiare
;**********************************************************************
; Subroutine
;**********************************************************************
;Subroutine di ritardo software
Delay
clrf Count
clrf Count+1
DelayLoop
decfsz Count,1
goto DelayLoop
decfsz Count+1,1
goto DelayLoop
return
END
vedi il programma di gestione interrupt scarica il programma INTERB.ASM
Proviamo a compilarlo ed a eseguirlo utilizzando lo stesso schema elettrico realizzato in precedenza per la gestione della tastiera.
Una volta scaricato il programma INTRB.ASM nella scheda PicTech noteremo che il LED 1 lampeggia esattamente come avveniva con il programma LED.ASM. Proviamo ora a premere uno qualsiasi dei tasti da SW1 a SW4 e vedremo che il LED 2 si accende immediatamente e rimane acceso per un tempo pari a 3 lampeggi del LED 1.
In pratica mentre il loop principale, derivato dal vecchio LED.ASM, continua a far lampeggiare il LED 1 utilizzando un ritardo software introdotto dalla subroutine Delay, il PIC è in grado di accorgersi della pressione di un tasto e di segnalarlo immediatamente sul LED 2 senza influenzare in maniera evidente la frequenza di lampeggio di LED1.
Prima di analizzare il source INTRB.ASM vediamo la differenza di comportamento con un altro source che effettua le stesse operazioni ma senza ricorrere agli interrupt.
A questo proposito compiliamo ed inseriamo nel PICmicro il programma NOINTRB.ASM.
Noteremo che l'accensione del LED 2, in corrispondenza alla pressione di un tasto, è leggermente ritardata in quanto la lettura dello stato delle linee RB4-7 non viene effettuata dall'hardware di gestione dell'interrupt ma direttamente dal programma principale ad ogni ciclo di loop. Il leggero ritardo è quindi dovuto alla presenza della subroutine Delay all'interno del loop principale.
Analizziamo ora il source INTRB.ASM
Partiamo dalla direttiva ORG 00H che, come sappiamo serve a posizionare il nostro programma a partire dalla locazione di reset, ovvero dalla locazione con indirizzo 0.
Notiamo subito che la prima istruzione che incontra il PIC è un salto incondizionato alla label Start:
ORG 0x00
goto Start
seguito da un'altra direttiva:
ORG 0x04
e quindi dal codice della subroutine di gestione dell'interrupt:
bsf PORTB,LED2
movlw 3
movwf nTick
bcf INTCON,RBIF
retfie
Come abbiamo detto nella lezione precedente, l'interrupt handler deve necessariamente essere allocato a partire dall'indirizzo 0x04, quindi per evitare che venga eseguito al reset dobbiamo necessariamente saltarlo con una istruzione di salto incondizionato.
Il codice dell'interrupt handler, in questo caso, è molto semplice e si limita ad accendere il LED 2, quindi inserire nel registro utente nTick il numero di lampeggi raggiunto il quale il LED 2 deve spegnersi e quindi azzerare il flag RBIF per consentire alla circuiteria di generazione dell'interrupt di continuare a funzionare.
L'istruzione RETFIE consente al PIC di tornare ad eseguire il programma interrotto dall'interrupt.
Ma perchè viene generato un interrupt quando premiamo un tasto qualsiasi ?
Tra le prime istruzioni che esegue il nostro PIC al reset troviamo le seguenti:
movlw 10001000B
movwf INTCON
dove in pratica viene messo ad uno il bit GIE (bit 7) che abilita in generale la circuiteria di generazione degli interrupt e quindi il bit RBIE (bit 3) che abilita, in particolare, l'interrupt su cambiamento di stato delle linee RB4-7.
In pratica, avendo collegato i pulsanti PU1, PU2, PU3 e PU4 proprio sulle linee di I/O RB4, RB5, RB6 ed RB7, con la pressione di uno di questi otteniamo un cambiamento di stato e quindi un interrupt.
Nel loop principale, oltre alle operazioni di accensione e spegnimento del LED 1, viene decrementato il contatore nTick fino al raggiungimento dello zero. In corrispondenza di questo viene spento il LED 2.
Esempio pratico di gestione di più interrupt
Vediamo ora come gestire più interrupt contemporaneamente.
Utilizzando sempre come base il source precedente INTRB.ASM proviamo a gestire anche l'interrupt sulla fine conteggio del registro TMR0. Ovvero facciamo lampeggiare il LED 3 in corrispondenza di ogni fine conteggio di TMR0.
Il source da utilizzare è DBLINT.ASM.
Compiliamo e scarichiamo il programma DBLINT.ASM nella scheda PicTech e vediamo che oltre a LED 1 che lampeggia con la solita frequenza, c'é il LED 3 che lampeggia contemporaneamente con una frequenza più elevata.
Premendo un tasto qualsiasi, inoltre, otteniamo la solita accensione per tre cicli del LED 2.
L'effetto finale che otteniamo è l'esecuzione di tre compiti ad una velocità tale da sembrare in esecuzione parallela.
Analizziamo ora il source DBLINT.ASM
Le modifiche maggiori riguardano l'interrupt handler all'inizio del quale viene effettuato un controllo su quale evento abbia generato l'interrupt. Con le istruzioni:
btfsc INTCON,T0IF
goto IntT0IF
btfsc INTCON,RBIF
goto IntRBIF
viene controllato il flag T0IF e RBIF per vedere rispettivamente se l'evento che ha scatenato l'interrupt proviene dal registro TMR0 o dalle porta RB4-RB7.
Quindi vengono lanciate in esecuzione le relative subroutine di gestione a partire dalle label IntT0IF e IntRBIF.
Prima di ridare il controllo al programma principale vengono azzerati i flag T0IF e RBIF assicurarsi che i successivi eventi possano scaturire nuovamente gli interrupt.
visualizza il programma in un'altra pagina scarica il programma
collegamento da togliere http://digilander.libero.it/mircose/pic/pic.htm
nota importante: Dal link sottostante potrai scaricare il PCB per realizzare il circuito, esso è realizzato con FidoCad, se quando lo apri vedi solo una lista di numeri (netlist), significa che non hai installato il Fidocad nel tuo PC, questo software è gratuito, è totalmente sicuro per il tuo PC e richiede solo un minuto per il download da questo sito. Se ancora non lo hai scaricato lo puoi ottenere cliccando qui -> FidoCad.