Sei sulla pagina 1di 16

Il PIC 16F84

Caratteristiche

Architettura Harvard: il PIC possiede memorie separate per i dati e le istruzioni. Memoria FLASH per le istruzioni da 1 K (1024 istruzioni) programmabile con l'ausilio di un computer esterno. Questa memoria supporta fino ad un massimo di 1000 cicli di cancellazione/scrittura. Memoria RAM dei dati da 90 bytes, dei quali 22 utilizzati per i registri interni di sistema (SFR = Special Function Registers) e i restanti 68 come registri utente liberi (GPR = General Purpose Register) Frequenza di clock massima: 10MHz (20MHz per la versione 16F84A) Set istruzioni RISC: Un set di appena 35 istruzioni. Grazie al sistema di pipelining ogni istruzione viene eseguita in un singolo ciclo macchina (4 colpi di clock) eccetto le istruzioni di salto che richiedono 2 cicli macchina (8 colpi di clock). Ad esempio, con un oscillatore esterno da 4MHz richiesto 1 microsecondo per l'esecuzione di una istruzione non di salto e 2 microsecondi per quelle di salto (condizionato o non). Memoria EEPROM interna da 64 bytes. Questa memoria pu essere programmata via software dal PIC stesso e sopporta fino ad un massimo di 1 milione di cicli di cancellazione/scrittura. Tale memoria non pu essere utilizzata come RAM aggiuntiva per via della sua lentezza (20 ms in scrittura) e l'accesso seriale (non e' mappata nello spazio degli indirizzi direttamente raggiungibili dalla CPU e viene letta/scritta solo tramite l'ausiliio di alcuni dei registri speciali SFR) Stack a 8 livelli (Lo stack implementato in una memoria a parte non visibile da programma e quindi non occupa lo spazio della RAM) Timer interno a 8 bit Watch-dog interno 2 porte di I/O (porta A a 5 bit e porta B a 8 bit) per un totale di 13 piedini di ingresso/uscita. Ogni linea pu essere programmata indipendentemente dalle altre come linea di ingresso o linea di uscita. Possono sembrare poche ma va sempre ricordato che il microcontrollore alloggiato in un DIL a soli 18 piedini! 4 diverse possibilit di interrupt (esterno tramite piedino apposito, del timer, esterno dovuto al cambio di stato dei piedini di I/O, interno di completamento della fase di scrittura della EEPROM) Opzione di protezione del codice. Settando questa opzione viene impedito ogni tentativo di lettura della memoria FLASH d programma. Tensione di alimentazione da 2 a 6 volt. Tensione di programmazione da 12 a 14 volt. Nella sigla la f sta per flash (memoria programma flash)

NOTE Architettura Harvard Architettura Von Neumann

Come strutturata una memoria

Memoria 2M x 2N bit

Normalmente non si accede al singolo bit (cella) di memoria ma viene letta/scritta lintera riga selezionata dallindirizzo di riga.

Classifica memorie (RAM EEPROM)

Piedinatura
Come detto prima il PIC possiede 18 piedini. 13 di questi sono adibiti all'I/O in logica TTL: questo significa che i valori booleani sono rappresentati dalle tensioni 0V e +5V rispettivamente per lo 0 e 1 logico. I rimanenti piedini vengono impiegati per il reset, l'alimentazione e per l'oscillatore esterno che fornisce il clock al PIC stesso. Come si vede in figura alcuni piedini hanno una duplice funzione (ad esempio il piedino numero 3 porta la dicitura RA4 e T0CKl) anche se di default vale la prima (il piedino numero 3 e' di default RA4). Le funzioni secondarie verranno spiegate piu' avanti.

Ecco l'elenco dei piedini e delle loro funzioni: RA0, RA1, RA2, RA3, RA4 - Sono i 5 piedini della porta A (tale porta e' a 5 bit). I piedini possono essere configurati indipendentemente come linee di ingresso o di uscita. Quando un piedino e' impostato come linea di uscita, presentera' una tensione di 0V o 5V a seconda che il PIC abbia associato uno 0 o 1 logico al piedino stesso, tramite apposite istruzioni. Quando e' impostato come ingresso, il PIC potra' ricevere un valore booleano leggendo il livello di tensione fornito al piedino in questione. Se il livello e' maggiore di 2V verra' letto un 1 logico, se inferiore a 0.8V verra' letto lo 0 logico. Applicando una tensione compresa tra 0.8 e 2V il risultato e' impredicibile. RB0, RB1, RB2, RB3, RB4, RB5, RB6, RB7 - Sono gli 8 piedini della porta B. Valgono le considerazioni viste per quelli della porta A. GND - Riferimento di massa VDD - Tensione di alimentazione. Deve essere compresa tra 2 e 6V. Di norma e' 5V. OSC1 e OSC2 - A questi piedini deve essere collegato l'oscillatore che fornisce il clock al sistema. Per alcuni tipi di oscillatori sono necessari tutti e due i piedini, per altri serve solo OSC1 e quindi OSC2 puo' essere lasciato scollegato. #MCLR - Piedino di reset, detto anche MasterCLeaR. L'attivazione del piedino produce un reset del PIC, cioe' il sistema riparte da capo con l'esecuzione del programma interno, come quando viene appena acceso. Questo piedino e' l'unico ad essere attivo basso, cio' significa che solo portandolo a massa si provoca il reset del PIC; durante il funzionamento normale il piedino deve essere mantenuto a livello logico alto tramite apposita resistenza limitatrice di corrente.

Il piedino #MCLR Oscillatore esterno Struttura interna


In figura viene riportata a grandi linee la struttura interna del PIC. In alto a sinistra e' la memoria delle istruzioni da 1024 posizioni. In alto al centro la RAM principale, chiamata anche RAM File Register da 68 byte (cioe' 68 registri). A destra di questa e' la memoria EEPROM da 64 byte. La memoria delle istruzioni viene indirizzata da uno specifico puntatore detto Program Counter. Tale registro permette di recuperare in sequenza le istruzioni del programma e di portarle nell'Instruction register. Sebbene bastino 10 bit per indirizzare la memoria istruzioni (2^10 = 1024) il Program Counter e' a 13 bit perche' il modello 16F84 (come il 16F84A) fa parte di una famiglia di PIC piu' estesa che

contempla anche memorie di dimensioni maggiori: i progettisti tendono a ridurre le differenze tra le varie versioni dei PIC per minimizzare i costi di produzione. L'istruzione viene poi inserita nell'Instruction register (di 14 bit) e poi decodificata ed eseguita. Il Program Counter viene incrementato di uno (oppure di una altra quantita' se e' previsto un salto). Il microcontrollore possiede un solo registro esterno alla memoria RAM, il registro W (Work). Questo registro entra in gioco durante le operazioni booleane, aritmetiche o di movimentazione dei dati. Ad esempio, per copiare un byte da una posizione di memoria ad un altra occorrono due istruzioni macchina: la prima legge la posizione di memoria desiderata e ne trasferisce il contenuto (il byte) nel registro W, la seconda trasferisce il contenuto di W nella posizione di memoria di destinazione. Le operazioni booleane o aritmetiche prevedono sempre e solo due operandi, il primo e' W, il secondo e' un locazione di memoria RAM (cioe' un registro del File Register); si puo' scegliere se piazzare il risultato dell'operazione in W (e quindi sovrascrivere il primo operando), o nella stessa locazione di memoria (sovrascrivendo il secondo operando). Le porte di I/O (porta A e porta B) sono mappate in RAM, cio' significa che si puo' leggere e scrivere nelle porte semplicemente leggendo e scrivendo nelle relative locazioni in RAM. Ad esempio, una scrittura di un byte nella locazione di memoria collegata alla porta B causa la configurazione opportuna dei segnali di tensione nei piedini della porta B (RB0,RB1,RB2 ... RB7), viceversa una lettura traduce in un byte la configurazione attuale delle tensioni applicate sui piedini di tale porta. Ovviamente un piedino di I/O non puo' essere simultaneamente di input e di output: occorre decidere all'inizio la "direzione" dei piedini per tutte e 13 le linee e cio' si risolve ancora una volta scrivendo in determinate posizioni di memoria RAM. Piu' avanti si chiariranno tutti questi meccanismi con esempi in assembler.

La memoria dati (memoria RAM)


La memoria RAM del PIC 16F84 ha una dimensione di 90 byte, 22 byte per i SFR (Special Function Register) e i restanti 68 byte per i 68 GPR (General Purpose Register). Ogni registro occupa sempre ed esattamente un byte. Gli SFR sono registri che controllano il funzionamento e le periferiche del microcontrollore (ad esempio, e' qui che sono mappate le porte A e B): tali registri non possono quindi essere utilizzati come memoria RAM per i programmi utente ma semplicemente fungono da pannello di controllo per l'intero microcontrollore. I GPR sono invece 68 registri liberi a disposizione dell'utente. Le aree di memoria colorate in azzurro non sono implementate; qualsiasi lettura in queste locazioni ritorna sempre con valore zero, mentre le scritture non hanno effetto.

La memoria RAM e' suddivisa in due banchi distinti (banco 0 e banco 1). Per poter accedere ad un registro e' quindi necessario specificare sia l'indirizzo di memoria che il banco. Ad esempio, all'indirizzo 01h e banco 0 abbiamo TMR0, mentre all'indirizzo 06h e banco 1 abbiamo TRIS B. Alcuni registri sono "copiati" in entrambi i banchi; cio' significa che per accede a quel registro e' sufficiente specificarne l'indirizzo di memoria, non importa quale banco sia abilitato in quel momento. Ad esempio, per accedere al registro PCL possiamo portarci all'indirizzo 02h e banco 0, ma anche all'indirizzo 02h e banco 1. I registri di questo tipo sono: Indirect addr., PCL, STATUS, FSR, PCLATH, INTCON e tutti e 68 i registri GPR.

Selezione del banco RAM (banco 0, banco 1)


Se, ad esempio, occorre modificare il registro TRIS_A e' necessario specificare il banco 1. Il banco RAM desiderato (0 o 1) viene selezionato impostando il sesto bit del registro STATUS. Se il bit vale zero e' abilitato il banco 0, se il bit vale uno e' abilitato il banco 1. All'accensione o al reset del PIC il banco 0 e' quello di default.

I registri SFR
Come appare poco evidente dalla composizione della memoria RAM, i registri SFR sono solo 16 (sembrerebbero 22 scartando le 2 sole aree in azzurro, ma ovviamente quelli mappati in ambedue i banchi contano sempre per uno solo, quindi sono effettivamente 16!): Registri SFR di controllo del PIC

INDF TMR0 OPTION_REG PCL

STATUS FSR PCLATH INTCON Registri SFR per le porte di I/O PORT_A TRIS_A PORT_B TRIS_B Registri SFR per l'utilizzo della memoria EEPROM interna EEDATA EECON1 EEADR EECON2

La memoria di programma (memoria FLASH)


I programmi inseriti nel PIC vengono registrati in questa memoria. La memoria contiene esattamente 1024 locazioni (da 0000h fino a 03FFh) ed ogni locazione puo' contenere una sola istruzione (le istruzioni del PIC 16F84 sono a 14 bit, quindi ogni locazione memorizza esattamente 14bit). Per questo motivo un programma deve necessariamente essere costituito da un massimo di 1024 istruzioni. La memoria istruzioni non e' accessibile da programma, cioe' non e' possibile indirizzarne lo spazio di memoria come per la memoria RAM; a livello utente (livello di programmazione) e' possibile dimenticarsi completamente dell'esistenza di questa memoria.

Una volta acceso (o resettato), il microcontrollore inizia ad eseguire il programma a partire dalla locazione 0000h, detta anche "vettore di reset", per poi proseguire con le istruzioni successive. Esiste pero' una locazione speciale, cioe' l'indirizzo 0004h, che assolve ad un compito speciale; ogni qualvolta si verifica un interrupt (secondo le modalita' descritte che si vedranno in seguito) il PIC salta immediatamente a questa locazione. In questo modo, se si desidera creare una routine di gestione delle interruzioni occorre farla cominciare da questa precisa locazione (0004h) in modo tale che essa verra' eseguita non appena si verifichera' un interrupt. Ovviamente prima della locazione 0004h occorrera' inserire un salto incondizionato per poter "oltrepassare" la routine di gestione delle interruzioni: di solito il salto e' inserito proprio in prima posizione, cioe' in 0000h, cosiche' il microcontrollore, una volta accesso o resettato, passera' immediatamente ad eseguire il salto e quindi si posizionera' alla locazione opportuna scelta dal programmatore. In figura si mostra graficamente il concetto di salto al vettore di interrupt:

Senza approfondire troppo, l'ultima istruzione della routine di gestione delle interruzioni dovra' essere un RETFIE per poter ritornare ad eseguire il programma da dove era stato interrotto, ma tutto questo verra' approfondito alla sezione relativa agli interrupt. Ovviamente se non e' prevista alcuna gestione di interrupt e quindi non c'e' alcuna routine di servizio delle interruzioni tutto il discorso puo' essere anche trascurato.

Il program counter
Il microcontrollore tiene traccia dello stato di avanzamento del programma grazie ad uno specifico puntatore, il program counter. Nel caso del 16F84, il program counter e' un puntatore a 13 bit che indica l'istruzione corrente da eseguire (solo i primi 10 bit dell program counter vengono utilizzati, per un totale di 2^10 = 1024 locazioni indirizzabili). Al reset del pic il program counter vale 0 (prima istruzione in cima alla memoria di programma), successivamente, per ogni istruzione eseguita, esso viene incrementato di uno. Le istruzioni di salto (condizionato o no) modificano esplicitamente il program counter quando sono eseguite, imponendo un salto opportuno nel normale flusso di esecuzione del programma. Gli 8 bit meno significativi del program counter sono accessibili in lettura e scrittura dal registro PCL, quindi da tale registro e' possibile sia modificare gli 8 bit meno significativi del program counter che leggerne lo stato. Il registro PCL viene costantemente aggiornato e rispecchia sempre lo stato dei 8 bit meno significativi del program counter. Per i restanti 2 bit del program counter il discorso e' differente: tali bit sono nascosti e non sono visibili all'utente, ma possono essere modificati andando a cambiare i due bit meno significativi del registro PCLATH. PCLATH non viene mai aggiornato e quindi il suo stato non corrisponde a quello dei 2 bit piu' significativi del program counter. La figura mostra come sono relazionati i registri PCL e PCLATH con il program counter:

In definitiva, durante il funzionamento normale del microcontrollore (esecuzione delle istruzioni, salti condizionati, salti incondizionati, chiamate a funzione etc..) il program counter viene aggiornato correttamente e non occorre preoccuparsi del suo stato. Occorre invece fare attenzione solo nel caso in cui una istruzione di programma modifichi esplicitamente il registro PCL: ogni volta che una qualche istruzione effettua una scrittura nel registro PCL, il contenuto di tale registro viene posto nei 8 bit meno significativi del program counter come detto in precedenza, ma anche i due bit meno significativi del registro PCLATH vengono copiati nei due bit piu' significativi del program counter (bit 8 e 9). Cio' significa che se una istruzione tenta di incrementare forzatamente il registro PCL di 10 unita' (al fine

di effettuare un salto in avanti nel programma di 10 istruzioni senza usare apposite istruzioni di salto) puo' farlo, ma occorre ricordarsi che i due bit meno significativi del registro PCLATH vengono automaticamente copiati nei due bit piu' significativi del program counter. Quindi, ogni volta che ci si appresta a scrivere in PCL, occorre far in modo che lo stato dei bit 0 e 1 di PCLATH corrisponda a quello dei bit 8 e 9 del program counter, pena un salto ad una locazione non desiderata.

La EEPROM
La EEPROM interna e' una memoria secondaria ad accesso relativamente lento (20ms per un cliclo di lettura o scrittura) di 64 bytes. La EEPROM puo' essere scritta e letta da programma attraverso gli appositi registri SFR ed il suo contenuto permane anche a microcontrollore spento; in effetti la durata massima di ritenzione dei dati puo' arrivare fino a 40 anni. La EEPROM verra' approfondita alla sezione "EEPROM interna".

Il registro STATUS

I bit 6 e 7 non sono utilizzati, il bit 5 usato per selezionare il blocco di memoria

Linguaggio assembly - parte I


Introduzione
Il PIC 16F84 ha un set di appena 35 istruzioni. Ogni istruzione e' una parola a 14 bit ed e' composta da un opcode che specifica l'istruzione stessa e da uno o due operandi (per alcune questi sono facoltativi o del tutto assenti) che specificano ulteriormente l'operazione da eseguire. Ogni istruzione viene eseguita in un ciclo macchina (4 colpi di clock) eccetto per le istruzioni di salto (ma solo quando il salto e' effettuato) e per le istruzioni che modificano il program counter; in questi due casi l'istruzione richiede 2 cicli macchina (8 colpi di clock). Le istruzioni sono variegate, ma possono essere raggruppate in tre categorie principali: le istruzioni di salto (condizionato o non), quelle aritmetiche/logiche e di movimentazione dei dati.
Molte istruzioni sono composte dallo mnemonico (il nome dell'istruzione stessa) e da uno o due parametri (a volte nessuno). I parametri possono essere di quattro tipi: parametro F, parametro D, B e K. F - Questo parametro rappresenta la locazione di memoria di un registro (SFR o GPR) della memoria dati. D - E' un singolo bit ed indica se il risultato dell'operazione andra' nel registro indicato da F (D=1) oppure nel registro di lavoro W (D=0). Se D viene omesso si ricade sempre nel caso D=1. B - E' un parametro a 3 bit (valori tra 0 e 7 inclusi) ed indica la posizione del bit prescelto all'interno di un registro puntato da F. Ad esempio, se B=2 indica il terzo bit meno significativo del registro indicato da F (il primo e' il bit numero zero, il secondo il numero uno ed il terzo il numero due). Alcune istruzioni necessitano di tale parametro per sapere quale bit deve essere controllato/modificato all'interno di un dato registro. K - Rappresenta un valore letterale, un byte, cioe' un valore tra 0 e 255. Alcune istruzioni hanno bisogno di un letterale come parametro per effettuare operazioni aritmetiche o logiche. Queste lettere vengono usate nelle descrizioni sintattiche delle varie istruzioni assembly. Eventuali commenti al codice sono preceduti dal punto e virgola e vengono inseriti a destra della istruzione commentata. Come si vedra' anche in seguito, in cima al listato del programma assembly e' possibile definire delle etichette da associare alle locazioni RAM del PIC. In questo modo ci si puo' riferire piu' facilmente a tali locazioni specificandone il nome scelto anziche' l'indirizzo in esadecimale. Per ora e' sufficiente sapere che scrivendo la seguente riga in cima al listato ILMIOREGISTRO EQU 0x25 e' possibile riferire la locazione 0x25 tramite il nome "ILMIOREGISTRO", esattamente come accade per le variabili nei linguaggi di programmazione di alto livello. ESEMPIO

Sintassi ADDLW k ADDWF f,d CLRF f CLRW BCF f, b

Descrizione Microchip Add Literal and W Add W and f Clear f Clear W Register Bit clear f

Operazione equivalente W=W+k d = W + f (dove d pu essere W o f) f=0 W=0 Fb = 0 (resetto il b-esimo bit di f)

14 bit opcode

Operazioni di base

Set e clear dei bit (BSF e BCF)


Sono le due istruzioni BSF e BCF. Vengono utilizzate per impostare a 0 o 1 i singoli bit dei registri. BSF setta a uno il bit in posizione B del registro F, mentre BCF setta a zero il bit in posizione B del registro F.

Sintassi delle istruzioni:

BSF F B BCF F B
Esempio: Settare ad uno il sesto bit meno significativo del registro alla locazione 0x13 BSF 0x13,5 NOTA: Il sesto bit e' il numero cinque, perche' il primo bit e' il numero zero! Esempio: Portare a zero il primo e l'ultimo bit del registro FSR BCF 0x04,0 BCF 0x04,7 oppure, utilizzando le etichette: FSR EQU 0x04 BCF FSR,0 BCF FSR,7 Esempio: Portare a zero il contenuto del registro in posizione 0x19 BCF BCF BCF BCF BCF BCF BCF BCF 0x19,0 0x19,1 0x19,2 0x19,3 0x19,4 0x19,5 0x19,6 0x19,7

NOTA: ovviamente l'azzeramento di un registro si puo' fare in modi piu' efficienti e veloci.

Selezione del banco RAM (banco 0, banco 1)


Per ora abbiamo toccato solo registri che non richiedevano la specifica di uno dei due banchi (il registro FSR e i registri GPR sono mappati in entrambi i banchi). Se pero', ad esempio, occorre modificare il registro TRIS_A e' necessario specificare il banco 1. Il banco RAM desiderato (0 o 1) viene selezionato impostando il sesto bit del registro STATUS. Se il bit vale zero e' abilitato il banco 0, se il bit vale uno e' abilitato il banco 1. All'accensione o al reset del PIC il banco 0 e' quello di default.

Esempio:

selezionare il banco 1 della RAM BSF 0x03,5 Esempio: selezionare il banco 0 della RAM BCF 0x03,5 Esempio: settare ad uno il terzo bit del registro TRIS_A supponendo che attualmente sia selezionato il banco 0. STATUS EQU 0x03 TRIS_A EQU 0x04 BSF STATUS,5 BSF TRIS_A,3 NOTA: Chiaramente l'accesso al registro STATUS (0x03) non richiede la selezione preventiva del banco in quanto e' mappato in entrambi.

Spostare i dati (MOVF, MOVWF e MOVLW)


Sono le tre istruzioni MOVLW, MOVF e MOVWF. Grazie a queste tre istruzioni e' possibile copiare un byte da un registro ram (GPR o SFR) al registro W e viceversa, oppure caricare W con un valore letterale compreso tra 0 e 255. MOVLW si usa tutte le volte in cui occorre inizializzare il registro W con un dato valore.

Sintassi delle istruzioni:


MOVLW K MOVLW inizializza il registro W con il valore K. K e' un valore compreso tra 0..255 inclusi (0x00..0xFF in esadecimale). MOVWF F MOVLW muove il contenuto del registro W alla locazione di memoria F. Il registro W non viene modificato. MOVF F,D MOVLW muove il contenuto del registro F nel registro W se D=0. Se invece D=1 il contenuto di F viene "copiato" su se stesso senza toccare W. L'istruzione modifica automaticamente anche un bit del registro STATUS, piu' precisamente il terzo bit, detto bit Z o ZERO_FLAG. Tale bit viene settato ad uno se e solo se il registro F (al momento dell'esecuzione dell'istruzione MOVF) vale zero, altrimenti viene impostato a zero. Ecco quindi che ha un senso anche copiare un registro su se stesso (con l'opzione D=1) perche' in questo caso l'unico effetto dell'istruzione e' la modifica opportuna del bit ZERO_FLAG, bit che viene controllato dal PIC per saltare o meno durante i salti condizionati.

Esempio: Caricare il registro W con il valore letterale 0x34 (52 in decimale) MOVLW 0x34 Esempio: Muovere il contenuto del registro W alla locazione di memoria 0x41 (in questo caso un registro GPR) MOVWF 0x41 Esempio: Muovere il contenuto del registro in posizione 0x32 nel registro W MOVF 0x32,0 Esempio: Copiare il contenuto della locazione di memoria 0x0F nella locazione 0x10. MOVF 0x0F,0 MOVWF 0x10

NOTA: In questi casi, siccome le locazioni 0x34,0x32,0x0F e 0x10 sono relative a registri GPR non e' mai necessario specificare il banco RAM (0 o 1). Esempio: Copiare il contenuto del registro TRIS_A nel registro W BSF 0x03,5 ;selezione del banco RAM 1 MOVF 0x05,0 NOTA: In questo caso e' necessario prima specificare il banco RAM per accedere a TRIS_A Esempio: Copiare il contenuto del registro OPTION_REG in PORT_A BSF 0x03,5 MOVF 0x01,0 BCF 0x03,5 MOVWF 0x05 ;selezione del banco RAM 1 ;selezione del banco RAM 0

Azzerare i registri (CLRF e CLRW) Vengono Sintassi utilizzate per azzerare delle i contenuti dei registri. istruzioni:

CLRF

Azzera il contenuto del registro puntato da F. Viene automaticamente settata a 1 la ZERO_FLAG del registro di stato.

CLRW
Azzera il contentuo del registro di lavoro W. Viene automaticamente settata a 1 la ZERO_FLAG del registro di stato. Esempio: Azzerare il contenuto di PORT_A CLRF 0x05 Esempio: Azzerare il contenuto di TRIS_B BSF 0x03,5 CLRF 0x05 ;selezione del banco RAM 1

Esempio: Azzerare il contenuto del registro W CLRW

No operation (NOP) Questa istruzione non produce alcun risultato. La sua "esecuzione" comporta solamente l'incremento del program counter alla prossima istruzione. L'istruzione di NOP viene utilizzata per effettuare dei ritardi nell'esecuzione dei programmi. Supponendo che l'oscillatore esterno sia di 4MHz, tutte le istruzioni non di salto (come NOP) verranno eseguite in 1us: se quindi e' necessario ritardare di 10us l'esecuzione in un punto di un programma, sara' sufficiente inserire in quel punto 10 NOP consecutivi. Ovviamente la risoluzione del tempo di ritardo sara' pari ad 1us. Ritardi piu' grandi possono essere effettuati tramite NOP

all'interno di cicli come si vedra' piu' avanti. L'istruzione NOP si rivela utilissima nei casi in cui si deve generare un segnale con tempistiche ben precise, ad esempio una comunicazione seriale RS232, oppure frequenze sonore. Sintassi della istruzione:

NOP
Esempio: Effettuare un ritardo di 3us supponendo un oscillatore da 8MHz. NOP NOP NOP NOP NOP NOP NOTA: Con un oscillatore da 8MHz ogni istruzione viene eseguta in 0,5us. Quindi per un ritardo di 3us occorrono 6 NOP.

Salto incondizionato (GOTO) Questa istruzione permette di saltare incondizionatamente alla linea di programma desiderata, qualunque essa sia. L'istruzione viene eseguita in due cicli macchina (8 colpi di clock). Sintassi della istruzione:

GOTO

addr

Salta ad eseguire l'istruzione posizionata all'indirizzo "addr". "addr" e' l'indirizzo di memoria di programma (memoria FLASH) alla quale si vuole saltare; percio' "addr" deve essere un valore compreso tra 0 e 1023. Spesso e' scomodo scrivere direttamente la locazione di memoria in forma numerica, percio' molti ambienti di sviluppo, come MPLAB, permettono di specificare delle label (da NON confondere con le etichette della direttiva EQU vista in precedenza!). La label e' semplicemente una stringa di testo arbitraria preceduta da ":" e la si posiziona all'interno del codice, tra una istruzione ed un altra. Quando si vuole saltare all'istruzione immediatamente successiva alla label, la si richiama nel goto scrivendo al posto di "addr" il nome dato alla label. Gli esempi successivi chiariscono ulteriormente il concetto: Esempio: Ripetere il caricamento del registro W con il valore 0x30 all'infinito. :loop ;label di nome "loop" MOVLW 0x30 ;caricamento di W con il valore 0x30 GOTO loop ;salto alla istruzione dopo "loop" Esempio: Saltare tre istruzioni BSF 0x03,5 MOVF 0x01,0 GOTO salto BCF 0x03,5 CLRW MOVLW 0x10 :salto BCF 0x03,5

;salto

;prima istruzione dopo il salto

MOVWF 0x05

Salti condizionati (BTFSC, BTFSS, DECFSZ e INCFSZ) Le quattro istruzioni di salto del microcontrollore sono BTFSC,BTFSS, DECFSZ e INCFSZ. Anche se i nomi di queste istruzioni possono apparire complicati, il loro funzionamento e' estremamente semplice. Quello che differenzia tra loro le istruzioni e' la politica di salto ed alcuni altri effetti collaterali specifici, ma in linea di massima si comportano in questo modo: se la condizione di salto e' FALSA si esegue l'istruzione successiva, altrimenti, se la condizione di salto e' VERA, si esegue quella immediatamente dopo a quella successiva. La figura spiega meglio il concetto:

In questo caso e' stata scelta BTFSC, ma poteva tranquillamente essere un'altra delle quattro. Se la condizione di salto (specifica per ognuna delle istruzioni) e' FALSA, allora si prosegue normalmente con l'esecuzione del programma, cioe' eseguendo l'istruzione 1, poi l'istruzione 2 e cosi' via come mostrato nella figura. Se la condizione e' VERA allora NON si esegue l'istruzione 1 ma si continua con l'esecuzione del programma dall'istruzione 2 in poi. Molto spesso l'istruzione 1 e' un salto incondizionato (GOTO); in questo modo e' possibile redirigere l'esecuzione del programma ad un altro punto. Le istruzioni di salto richiedono 2 cicli macchina quando la condizione e' VERA ed 1 solo ciclo macchina quando questa e' FALSA. Sintassi delle istruzioni:

BTFSC

F,B

Se il B-esimo bit del registro F e' settato a uno (condizione FALSA) viene eseguita l'istruzione immediatamente successiva; se vale zero (condizione VERA) l'istruzione immediatamente successiva viene saltata e si passa a quella dopo.

BTFSS

F,B

Se il B-esimo bit del registro F e' settato a zero (condizione FALSA) viene eseguita l'istruzione immediatamente successiva; se vale uno (condizione VERA) l'istruzione immediatamente successiva viene

saltata e si passa a quella dopo. Questa istruzione di salto e' simile alla precedente ma il controllo sul bit B-esimo e' invertito.

DECFSZ

F,D

Viene decrementato di una unita' il contenuto del registro F. Il risultato viene posto in W se D=0 (lasciando inalterato F), viene posto in F se D=1. Se inoltre tale risultato e' zero si salta l'istruzione successiva (condizione VERA), altrimenti (condizione FALSA) si prosegue normalmente. NOTA: Il decremento e' effettuato PRIMA del controllo della condizione!

INCFSZ

F,D

Viene incrementato di una unita' il contenuto del registro F. Il risultato viene posto in W se D=0 (lasciando inalterato F), viene posto in F se D=1. Se inoltre tale risultato e' zero (condzione VERA) si salta l'istruzione successiva, altrimenti (condizione FALSA) si prosegue normalmente. NOTA: L'incremento e' effettuato PRIMA del controllo! Esempio: Se il primo bit del registro 0x20 e' 1 caricare W con il valore 0x00, altrimenti caricare W con il valore 0xFF. REG EQU 0x20 BTFSC REG,0 GOTO yes MOVLW 0xFF GOTO end :yes MOVLW 0x00 :end ;controlla se il primo bit del registro 0x20 e' 1 ;se vale 1 vai a "yes" ;se vale 0 carica W con 0xFF e vai a "end" ;setta W con 0x00

Esempio: Scrivere nel registro 0x30 tutti i valori in successione da 0 a 255. Infine azzerare W. MOVLW 0x00 MOVWF 0x2F :loop MOVLW 0x2F,0 MOVWF 0x30 INCFSZ 0x2F,1 GOTO loop CLRW ;carico W con 0x00 ;scrivo W nel registro di appoggio 0x2F ;carico W con il contenuto di 0x2F ;scrivo il contenuto di W nel registro 0x30 ;incremento il registro 0x2F e controllo se vale zero ;non e' zero, vai a "loop" ;si e' zero, resetta W. Programma terminato.

Cicli di delay Abbiamo gia' visto come effettuare un ritardo tramite l'uso ripetuto dell'istruzione NOP. La tecnica non permette di generare grandi ritardi perche' occorrebbe inserire un gran numero di NOP in sequenza, occupando tutta la memoria di programma. Conviene invece scrivere un ciclo che itera per un determinato numero di volte, decrementando un registro GPR adibito a contatore; l'istruzione di decremento e' incorporata in quella di salto, quindi il sistema e' estremamente semplice da implementare. Piu' difficile e' stabilire il valore iniziale del contatore per ottere uno specifico tempo di ritardo: occorre infatti calcolare accuratamente tutte le durate di esecuzione delle istruzioni. Un tipico ciclo di delay e' quello riportato qui sotto: Ciclo di delay: Considerando un oscillatore a 4MHz si crea un ritardo di 500us (mezzo millisecondo)

COUNT EQU 0x30 :delay MOVLW 0xA7 MOVWF COUNT :loop DECFSZ COUNT,1 goto loop ;carico W con il valore 167 ;lo memorizzo nel registro COUNT ;decremento di uno, se non e' zero vai a "loop"

Il loop principale prevede una istruzione DECFSZ ed un GOTO. DECFSZ richiede 1us quando NON salta (cioe' nel caso in cui il registro non sia zero) e 2us quando salta (e quindi termina la routine di delay). Considerando N la nostra incognita (il valore di inzializzazione per count), DECFSZ richiede un tempo pari a: tempo_DEFSZ (N-1) volte L'istruzione In tempo_tot semplificando: tempo_tot semplificando tempo_tot risolvendo N rispetto = = a N 3N-1 si = 3(N-1)+2 us ancora: us ottiene: (tempo_tot+1)/3 richiede 1us GOTO viene = (quando non salta) e eseguita N-1 volte definitiva = (N-1)+2 all'ultimo giro richiede e quindi richiede si (N-1)+2+2(N-1) us 2us (salta). 2(N-1) us. ha: us

se "tempo_tot" e' appunto 500 come da richiesta, si ottiene N = 167 (0xA7 in esadecimale) Per avere ritardi maggiori occorre annidare piu' cicli uno dentro l'altro utilizzando quindi tanti registri contatori quanti sono i cicli annidati, ma il calcolo dei valori di inizializzazione si complica ancora di piu' ed e' necessario risolvere sistemi non lineari molto piu' complessi. Inoltre, spesso e volentieri le soluzioni prevedono valori non interi per cui o si sceglie di approssimare oppure si inseriscono NOP finali esterni ai cicli per compensare gli errori di approssimazione.

Potrebbero piacerti anche