P I C 1 6 F 8 4   -   A P P U N T I    D I    U T I L I Z Z O

(avvertenze)

[Precedente]   [Indice principale]   [Seguente]

[Piedinatura e aree di memoria]   [Istruzioni]   [Note per la programmazione]


PIEDINATURA E AREE DI MEMORIA



Picture by Sergio Tanzilli

Il PIC 16F84 e' un microcontroller e puo' essere pensato come un piccolissimo computer completo realizzato in un unico integrato a 18 pin. E' dotato infatti di memoria programma, ram utente, periferiche interne e porte di ingresso/uscita per ricevere e trasmettere segnali da e verso l'esterno.  Puo' essere alimentato da 3 a 5,5V e assorbe poco piu' di 2 mA. Vss e' la massa (chiamata anche GND), Vdd e' il positivo di alimentazione (chiamato anche Vcc). OSC1 e OSC2 sono i pin a cui va collegato il quarzo per il clock, a questi vanno anche collegati due condensatori da 22pF verso massa come indicato nella figura di sotto. Il quarzo puo' arrivare fino a 20Mhz a seconda del tipo di PIC. Collegando a massa il pin MCLR si ottiene il reset del micro, normalmente questo pin va tenuto a 1 con una resistenza da qualche K collegata a Vdd. Gli altri 13 pin sono ingressi/uscite singolarmente programmabili e ciascuno puo' pilotare almeno 20mA. Il pin RB0 puo' essere programmato come ingresso di interrupt. I pin da RB4 a RB7 possono generare un interrupt di gruppo. Tutti i pin della porta B (RB0..RB7) se configurati come ingressi possono disporre di una resistenza di pull-up interna. Il pin RA4 in uscita e' un open collector,  e in ingresso puo' essere usato come clock di conteggio per il timer interno. Lo schema seguente  mostra il collegamento base del 16f84. Anche se nello schema non e' indicato, e' sempre consigliabile collegare un condensatore da 100nF tra i pin Vdd e Vss per filtrare i possibili disturbi sull'alimentazione.

Il PIC 16F84 dispone di una memoria programma separata dalla memoria dati. La memoria programma e' lunga 1024 locazioni  (1kwords) con indirizzi da 0 a 1023. Il PIC all'accensione (o dopo un reset) inizia a leggere il programma dall'indirizzo 0. L'indirizzo 4 e' il punto di partenza dell' interrupt handler, la discriminazione della sorgente dell'interrupt va effettuata via software.

La memoria dati e' lunga 80 locazioni (indirizzi da 0 a 79) e prende il nome di register file in quanto ogni locazione puo' essere considerata come un registro a 8 bit. I primi 12 indirizzi (0..11) servono per il controllo dell'hardware del PIC, i seguenti 68 indirizzi (12..79) sono usabili dall'utente per memorizzare i propri dati di lavoro. Inoltre i primi 12 indirizzi dispongono di due banchi di registri, alcuni dei quali sono visibili in entrambi i banchi, mentre altri sono presenti solo in un banco. Il registro STATUS per esempio e' visibile in entrambi i banchi, puo' cioe' essere letto o scritto sia se il banco attivo e' lo 0, sia se e' l' 1. La commutazione da un banco all'altro avviene settando il bit 5 di STATUS (bit RP0), se vale 0 e' attivo il banco 0, se vale 1 e' attivo il banco 1. I 68 registri utente dall'indirizzo 12 (0CH) in poi sono invece sempre visibili e non sono influenzati dal banco attivo. Il registro STATUS contiene anche i flags, il bit 0 e' il flag C, il bit 2 e' il flag Z.
 



Picture by Microchip



ISTRUZIONI


[Caricamento dati]   [Aritmetiche]   [Logiche]   [Rotazioni e set/reset]
[Salti e subroutine]   [Controllo sistema]   [Riepilogo]

Il PIC dispone di un set di 35 istruzioni elementari, e ogni istruzione occupa una sola locazione della memoria programma. Quasi tutte le istruzioni vengono eseguite in 4 cicli di clock, un PIC cloccato a 4Mhz e' percio' in grado di eseguire 1milione di istruzioni al secondo (1 mips) e ogni istruzione dura 1µS. Le istruzioni di branch (salto) possono richiedere 8 cicli di clock anziche' 4. Nella terminologia Microchip un gruppo di 4 cicli di clock e' detto "ciclo", per cui le istruzioni vengono eseguite in uno o due cicli.

Le aree di memoria su cui si puo' agire sono i registri della memoria dati e il registro accumulatore W (che non fa parte dell'area dati, ma e' un ulteriore registro hardware interno al PIC utilizzato nelle operazioni aritmetico logiche).

Nelle seguenti liste delle istruzioni si deve considerare n come un valore (literal) a 8 bit, addr come un valore che indica una locazione di memoria (di programma o dati a seconda dell'istruzione) e b come un valore compreso tra 0 e 7 che indica il bit all'interno di un byte. Inoltre sono riportati gli effetti sui flags, una X indica che il valore finale del flag dipende dal risultato dell'operazione. Molte istruzioni che operano su registri permettono di trasferire il risultato dell'operazione o nel registro W o nel registro stesso chiamato in causa dall'istruzione, queste due possibilita' si specificano scrivendo ,w o ,f alla fine dell'istruzione.
 

ISTRUZIONI DI CARICAMENTO DATI A 8 BIT
movlw n    n -> W
movwf addr    W -> (addr)
movf  addr,w   Z=X   (addr) -> W
movf  addr,f  Z=X   (addr) -> (addr)
swapf addr,w    swap(addr) -> W
swapf addr,f    swap(addr) -> (addr)
clrf  addr  Z=1  (addr) = 0
clrw  Z=1  W = 0

Le istruzioni movlw e movwf non alterano i flags. L'istruzione movf invece modifica il flag Z, che risulta settato (s=set) se il valore caricato e' 0, e resettato (c=clear) se il valore caricato e' diverso da 0. Nell' ultima movf il valore viene trasferito nella stessa locazione da cui viene preso, il suo valore percio' non cambia, ma, visto che il flag Z viene modificato, e' un modo rapido per verificare se contiene zero.

L' istruzione swapf scambia i nibbles (i 4 bit superiori e i 4 bit inferiori) della locazione addr, e deposita il risultato nell'accumulatore o nella locazione stessa. In alcuni casi puo' essere vantaggioso usarla, oltre che per swappare i nibble, anche come spostamento perche' non altera i flags (per esempio e' usata per salvare il registro STATUS durante un interrupt).

Le istruzioni clrf e clrw sono un caricamento diretto del valore 0 in una locazione dati o nell'accumulatore. Entrambe impostano il flag Z a 1.
 

ISTRUZIONI ARITMETICHE
addlw n  C=X Z=X   W = W + n
addwf addr,w   C=X Z=X  W = W + (addr)
addwf addr,f  C=X Z=X  (addr) = W + (addr)
sublw n  C=X Z=X  W = n - W
subwf addr,w  C=X Z=X  W = (addr) - W
subwf addr,f  C=X Z=X  (addr) = (addr) - W
incf  addr,w      Z=X  W = (addr) + 1
incf  addr,f      Z=X  (addr) = (addr) + 1
decf  addr,w      Z=X  W = (addr) - 1
decf  addr,f      Z=X  (addr) = (addr) - 1

Le istruzioni di somma e sottrazione alterano entrambi i flags C e Z. Il flag Z e' sempre clear, viene settato solo quando il risultato dell'operazione e' 0, Durante una somma il flag C e' sempre resettato, viene settato solo se l'operazione causa un overflow. Durante una sottrazione il flag C e' sempre settato, viene resettato solo se l'operazione causa un prestito. Controllando lo stato di questi flags dopo una sottrazione e' possibile stabilire se un numero e' maggiore, minore o uguale a un'altro.

Le istruzioni di incremento decremento settano il flag Z se il risultato dell'operazione e' 0.
 

ISTRUZIONI LOGICHE
andlw n  Z=X   W = W AND n
andwf addr,w   Z=X   W = W AND (addr)
andwf addr,f  Z=X   (addr) = W AND (addr)
iorlw n  Z=X   W = W OR n
iorwf addr,w  Z=X   W = W OR (addr)
iorwf addr,f  Z=X  (addr) = W OR (addr)
xorlw n  Z=X   W = W XOR n
xorwf addr,w  Z=X  W = W XOR (addr)
xorwf addr,f  Z=X  (addr) = W XOR (addr)
comf  addr,w  Z=X  W = NOT(addr)
comf  addr,f  Z=X  (addr) = NOT(addr)

Tutte le istruzioni logiche settano il flag Z nel caso che il risultato dell'operazione sia 0.
 

ROTAZIONI E SET/RESET DI SINGOLI BIT
rlf   addr,w   C=X   W = rlf(addr)
rlf   addr,f  C=X  (addr) = rlf(addr)
rrf   addr,w  C=X   W = rrf(addr)
rrf   addr,f  C=X   (addr) = rrf(addr)
bcf   addr,b    Bit b di (addr) = 0
bsf   addr,b    Bit b di (addr) = 1

Le istruzioni rlf e rrf ruotano rispettivamente a sinistra o a destra il contenuto di un registro. Il   risultato e' depositato nell'accumulatore o nella locazione di memoria stessa e la rotazione avviene sempre attraverso il flag C.
 

SALTI E SUBROUTINE
btfsc  addr,b    Skip se bit b di (addr) = 0
btfss  addr,b    Skip se bit b di (addr) = 1
incfsz addr,w    W = (addr)+1  Skip se W = 0
incfsz addr,f    (addr) = (addr)+1  Skip se (addr) = 0
decfsz addr,w    W = (addr)-1  Skip se W = 0
decfsz addr,f    (addr) = (addr)-1  Skip se (addr) = 0
goto   addr    Salto a addr
call   addr    Chiamata di subroutine 
return    Ritorno da subroutine
retlw  n    Ritorno da subr. con valore in W
retfie    Ritorno da interrupt

Le istruzioni per il salto incondizionato (goto, call, return, retlw, retfie) richiedono sempre 2 cicli macchina, mentre i salti condizionati (skip) ne richiedono 2 solo se la condizione e' verificata.
 

ISTRUZIONI DI CONTROLLO SISTEMA
nop    Nessuna operazione
clrwdt     Azzera watch dog timer
sleep    Standby mode

 
 

RIEPILOGO ISTRUZIONI
Il valore di d puo' valere 0 o 1 (o, rispettivamente, W o F),  addr indica un registro dati oppure un indirizzo di programma nelle istruzioni goto e call, b indica un bit all'interno di un byte, n e' un valore costante (literal) a 8 bit.
 
Mnemonic operands Cyc. Flag Description

Byte oriented file register operations
addwf   addr,d 1 Z  C d = W + (addr)
andwf   addr,d 1 Z d = W AND (addr)
clrf    addr 1 Z (addr) = 0
clrw 1 Z W = 0
comf    addr,d 1 Z d = NOT(addr)
decf    addr,d 1 Z d = (addr) - 1
decfsz  addr,d 1(2)   d = (addr)-1  Skip se d = 0
incf    addr,d 1 Z d = (addr) + 1
incfsz  addr,d 1(2)   d = (addr)+1  Skip se d = 0
iorwf   addr,d 1 Z d = W OR (addr)
movf    addr,d 1 Z (addr) -> d
movwf   addr 1   W -> (addr)
rlf     addr,d 1    C d = rlf(addr)
rrf     addr,d 1    C d = rrf(addr)
subwf   addr,d 1 Z  C d = (addr) - W
swapf   addr,d 1   swap(addr) -> d
xorwf   addr,d 1 Z d = W XOR (addr)

Bit oriented file register operations
bcf     addr,b 1   Bit b di (addr) = 0
bsf     addr,b 1   Bit b di (addr) = 1
btfsc   addr,b 1(2)   Skip se bit b di (addr) = 0
btfss   addr,b 1(2)   Skip se bit b di (addr) = 1

Literal and control operations
addlw   n 1 Z  C W = W + n
andlw   n 1 Z W = W AND n
call    addr 2   Chiamata di subroutine
clrwdt 1   Azzera watch dog timer
goto    addr 2   Salto a addr
iorlw   n 1 Z W = W OR n
movlw   n 1   n -> W
nop 1   Nessuna operazione
retfie 2   Ritorno da interrupt
retlw   n 2   Ritorno da subr. con valore in W
return 2   Ritorno da subroutine
sleep 1   Standby mode
sublw   n 1 Z  C W = n - W
xorlw   n 1 Z W = W XOR n

 

NOTE PER LA PROGRAMMAZIONE


[Generalità]   [Configurazione hardware]   [Esempio di programma]   [Loop]  [Tabelle dati]  [Ritardi software]
 
 

GENERALITA'
Le istruzioni dei PIC sono molto veloci ma anche molto elementari. Questo significa che e' necessario un certo studio e una certa quantita' di istruzioni anche per realizzare le piu' semplici strutture software (come ad esempio i loop). Solo alcune operazioni alterano i flags, e i salti  condizionati sono dei semplici skip dell'istruzione successiva. Questo obbliga a pensare alle condizioni in negativo, nel senso che invece del consueto "salta a se si verifica che" si deve ragionare come "skip se non si verifica che" seguito da un salto incondizionato (goto).
 
 

EQU
Le 68 locazioni della memoria dati utente, e le 12 per il controllo hardware del PIC, possono essere indirizzate scrivendo direttamente il loro indirizzo nelle istruzioni (gli addr nella lista istruzioni precedente) o usando la direttiva EQU per specificarne un nome simbolico. Il registro di stato all'indirizzo 3 puo' essere  infatti definito con una EQU:
 

   STATUS   EQU  3
 

E quindi ci si puo' riferire a lui indifferentemente come STATUS o come indirizzo 3:
 

   btfss   STATUS,2    ;Skip se bit 2 di status = 1
   btfss   3,2         ;Skip se bit 2 di status = 1
 

In realta' anche i flags possono essere definiti con una EQU:
 

   Z        EQU  2
 

...e quindi ci si puo' riferire al flag Z nel seguente modo:
 

   btfss   STATUS,Z    ;Skip se il flag Z e' settato
 

Anche alle locazioni utente puo' essere assegnato un nome, e quindi possono essere usate come se fossero 68 registri ciascuno col suo nome:
 

   var1     EQU  12
   var2     EQU  13
   contat   EQU  14
   ...
 
 

INCLUDE
Per ogni tipo di pic esiste un file gia' pronto (fornito assieme all'assemblatore) che contiene tutte le definizioni standard. Per esempio in un programma scritto per il pic 16F84A andra' incluso il file P16F84a.INC con la direttiva:
 

   INCLUDE         "P16F84a.INC"
 

La direttiva INCLUDE puo' servire anche per incorporare nel proprio programma degli altri pezzi di programma scritti in uno o piu' files esterni.
 
 

ORG
La direttiva di compilazione ORG (origine) che serve per due scopi differenti, a seconda che si applichi al programma o all'area dati. Nel primo caso serve per indicare all'assemblatore l'indirizzo fisico dove dovranno essere caricate le istruzioni successive (generalmente un programma inizia sempre all' ORG 0). Nel secondo caso invece permette di definire l'indirizzo fisico di partenza di un'area dati, e di definirne poi l'occupazione tramite nomi simbolici e la direttiva RES (riserva). Le nostre 3 variabili dell'esempio precedente potrebbero per esempio essere dichiarate con:
 

            ORG  0CH
   var1     RES  1
   var2     RES  1
   contat   RES  3
   ...
 

Queste righe indicano al compilatore di riservare 1 byte all'indirizzo 12 (0CH) e chiamarlo var1, un altro byte all'indirizzo 13 con il nome var2 ecc... Questo puo' essere comodo ad esempio per spostare un programma da un tipo di pic all'altro, in quanto basta cambiare l'org dell'area dati senza dover riscrivere tutti gli indirizzi fisici associati a ciascun nome simbolico. Come si vede nell'esempio, con res si puo' riservare anche piu' di un byte, la variabile contat e' a 24 bit, e possiamo riferirci ai suoi tre byte come contat, contat+1 e contat+2.
 
 

#DEFINE
Esiste poi la possibilita' di ridefinire dei comandi comuni usati spesso assegnando loro un nome piu' comodo. Per esempio per impostare il banco attivo nella prima parte dell'area dati (quella che controlla l'hardware) si deve settare o resettare il bit RP0 del registro status:
 

   bsf  STATUS,RP0     ;attiva banco 1
   bcf  STATUS,RP0     ;attiva banco 0
 

Per evitare di scrivere ogni volta queste istruzioni le possiamo ridefinire con le parole Bank1 e Bank0:
 

   #define    Bank0    bcf STATUS,RP0
   #define    Bank1    bsf STATUS,RP0
 

A questo punto nel programma possiamo semplicemente scrivere Bank0 o Bank1
 
 
 

CONFIGURAZIONE HARDWARE
I pic dispongono di un registro di configurazione hardware, che viene scritto una sola volta al momento della programmazione, e che stabilisce il funzionamento di alcuni circuiti interni, come il watch dog timer (wdt) e l'oscillatore di clock. Questa operazione e' conosciuta anche con il nome di "settaggio dei fuses". Nei micro dotati di memoria flash non si parla naturalmente di fusibili e questi settaggi possono essere cambiati semplicemente riprogrammandoli. Ogni programma per pic inizia con una intestazione in cui si dichiara, oltre al tipo di micro usato e al formato di default dei numeri (decimale, esadecimale ecc...), anche la configuration word che ne determinera' il funzionamento (specificata con __CONFIG):
 

   PROCESSOR       16F84a
   RADIX           DEC
   INCLUDE         "P16F84a.INC"
   __CONFIG        1111111110001b
 

Il significato completo dei singoli bit della configuration word e' scritto nel datasheet, e varia per ogni tipo di micro. Quella qui riportata significa: oscillatore al quarzo, wtd disabilitato, power up timer abilitato, protezione programma disabilitata. Se si vuole abilitare il wdt si deve mettere a 1 il bit 2 (ricordandosi sempre che il bit 2 e' il terzo bit a partire da destra!).
 
 

ESEMPIO DI PROGRAMMA
Il seguente e' un semplice esempio di programma completo. Funzionalmente non fa altro che leggere i 3 stati logici presenti sugli ingressi RB0..RB2 e  trasferirli pari pari sulle uscite RA0..RA2.

   ;-----------------------------------------------------------------------
   ; TEST1.ASM - Programma di test per PIC
   ;-----------------------------------------------------------------------
   ; RIEPILOGO USO PORTE:
   ;
   ; RA0 out       Uscita 0
   ; RA1 out       Uscita 1
   ; RA2 out       Uscita 2
   ; RA3 out       Non usato, sempre 0
   ; RA4 out(oc)   Non usato, sempre 0
   ;
   ; RB0 in(p-up)  Ingresso 0
   ; RB1 in(p-up)  Ingresso 1
   ; RB2 in(p-up)  Ingresso 2
   ; RB3 in(p-up)  Non usato
   ; RB4 in(p-up)  Non usato
   ; RB5 in(p-up)  Non usato
   ; RB6 in(p-up)  Non usato
   ; RB7 in(p-up)  Non usato
   ;-----------------------------------------------------------------------
   ; DEFINIZIONI
   ;-----------------------------------------------------------------------
              PROCESSOR       16F84a    ;clock  4 Mhz
              RADIX           DEC
              INCLUDE         "P16F84a.INC"
              __CONFIG        1111111110001b

   #define    Bank0   bcf STATUS,RP0
   #define    Bank1   bsf STATUS,RP0

   ;-----------------------------------------------------------------------
   ; PROGRAMMA
   ;-----------------------------------------------------------------------
              ORG     0
              goto inizio

   ;----------INTERRUPT HANDLER (se usato)
              ORG     4

              ...                     ;qui vanno le eventuali istruzioni
              ...                     ;per la gestione degli interrupt
 

   ;----------PREDISPOSIZIONE HARDWARE

   inizio     Bank1                   ;attiva il banco 1
              clrf TRISA              ;Predispone porta A come uscite
              bcf OPTION_REG,7        ;Attiva pull-ups su porta B
              Bank0                   ;attiva il banco 0
 

   ;----------CICLO PRINCIPALE DEL PROGRAMMA

   mainloop   movf PORTB,w            ;legge porta B
              andlw 00000111B         ;maschera i 3 bit inferiori
              movwf PORTA             ;li scrive sulla porta A
              goto mainloop           ;ripete il ciclo

   ;-----------------------------------------------------------------------
              END
 
 

LOOP
Un loop (ciclo) puo' essere realizzato in modo semplice se il numero di iterazioni non e' maggiore di 256. In questo caso basta un registro a 8 bit come contatore (Impostando 0 in contat il si ottengono 256 iterazioni):
 

   contat   EQU  0CH

            movlw  30
            movwf  contat    ;predispone 30 iterazioni
   ciclo    ...
            ...
            ...
            decfsz contat,f  ;decrementa contat, skip se zero
            goto   ciclo     ;ritorna a ciclo se non zero
 

Se occorrono piu' di 256 iterazioni si devono usare piu' di registri. Per esempio con due registri (contenenti le parti alta e bassa di un numero a 16 bit) si possono realizzare fino a 65536 iterazioni:
 

   lcont    EQU  0CH
   hcont    EQU  0DH
 

            movlw  85
            movwf  lcont
            movlw  4
            movwf  hcont     ;predispone 1109 iterazioni
   ciclo    ...
            ...
            ...
            decf   lcont,f   ;dec parte bassa
            incf   lcont,w   ;incr. per controllare se torna a 0
            btfsc  STATUS,Z  ;skip se non tornato a zero
            decf   hcont,f   ;se tornato a zero decrementa hcont
            movf   lcont,w   ;carica lcont
            iorwf  hcont,w   ;mette in or con hcont
            btfss  STATUS,Z  ;se tutto zero termina
            goto   ciclo     ;altrimenti next
 

Impostando 0 sia in lcount che in hcount si ottengono 65536 iterazioni.
 
 

LOOKUP TABLE (TABELLE DATI)
Usando le istruzioni addwf e retlw e' possibile creare delle tabelle dati nel programma leggibili con un indice. E' infatti permesso sommare un valore alla parte bassa del program counter (PCL), quindi basta impostare in W l'indice dell'elemento voluto e fare una call alla tabella. L' indice parte da 0 (per il primo elemento) e puo' andare fino a 254. Bisogna ricordare che l'istruzione addwf lavora solo su 8 bit e non e' in grado di aggiornare la parte alta del program counter, questo significa che la memoria programma puo' essere pensata come composta da 4 pagine da 256 byte ciascuna... le tabelle non devono percio' "sconfinare" dai bordi delle pagine. Inoltre va anche ricordato che ad ogni addwf la parte alta del prog.counter viene caricata con il valore del registro PCLATH (presente all'indirizzo dati 0AH), e pertanto prima di chiamare una tabella questo registro va impostato a seconda della pagina in cui risiede la tabella stessa.
 

   table1   addwf   PCL,f
            retlw   126
            retlw   0
            retlw   44
            retlw   255
            retlw   188
            ....
 

            movlw   ....     ;pagina della tabella
            movwf   PCLATH
            movlw   4        ;punta il 5° elemento
            call    table1   ;acquisisce in W il valore
                             ;letto dalla tabella (188)
 
 

Indirizzi PCLATH
000H - 0FFH 0
100H - 1FFH 1
200H - 2FFH 2
300H - 3FF 3

 

Se si vuole usare un registro come puntatore (per esempio PTAB) agli elementi della tabella possiamo generalizzare la chiamata includendo nella tabella stessa anche l'impostazione del PCLATH (in questo caso l'indice puo' arrivare al massimo a 251):
 

   PTAB     EQU     0CH
 

   table1   movlw   ....    ;pagina
            movwf   PCLATH
            movf    PTAB,w
            addwf   PCL,f
            retlw   126
            retlw   0
            retlw   44
            retlw   255
            retlw   188
            ....
 

            movlw   2        ;carica 2 nel registro puntatore
            movwf   PTAB
            call    table1   ;acquisisce in W il valore 44
 

RITARDI SOFTWARE
In alcuni programmi puo' essere necessario regolare con precisione la durata temporale di una routine software, inserendo qua e la delle apposite istruzioni che hanno l'unico scopo di creare un piccolo ritardo. Usando l'istruzione NOP e' possibile inserire un ritardo di 1µS (con clock di 4Mhz), se serve un ritardo di 2µS possono essere scritte due NOP una dietro l'altra, oppure, per risparmiare memoria programma, si puo' usare una goto fittizia che salta all'istruzione successiva (una goto infatti dura sempre 2µS e occupa una sola locazione della memoria programma... l'uso delle goto fittizie e' pero' uno stile di programmazione un po' scorretto, e va usato solo se e' assolutamente necessario risparmiare quelle poche locazioni di memoria, altrimenti e' sicuramente preferibile usare due NOP):
 

Ritardo 1µS:       nop
 

Ritardo 2µS:       nop
                   nop

oppure:            goto $+1
 

Ritardi maggiori possono essere ottenuti con combinazioni di NOP e goto fittizie. Quando si arriva ai 7µS di ritardo diventa conveniente usare un loop, con il quale si possono realizzare ritardi di centinaia di µS. Il ciclo formato dalle seguenti 4 istruzioni per esempio impiega 301µS per essere eseguito da un PIC cloccato a 4 Mhz:
 

            movlw  100
            movwf  contat    ;predispone 100 iterazioni
   ciclo    decfsz contat,f  ;decrementa contat, skip se zero
            goto   ciclo     ;prossimo ciclo se non zero
 

Da dove saltano fuori i 301µS? Le prime 2 istruzioni durano 1 µS ciascuna, poi il decremento e il goto vengono eseguiti 99 volte, e il decremento saltando il goto una sola volta all'ultimo ciclo. Quando il decremento non da risultato 0 dura 1 µS, seguito dal goto che dura 2 µS, quando invece il decremento da come risultato 0 dura 2 µS e il goto e' saltato... quindi:
 

    µS = 2 + 3*(n-1) + 2  =  2 + 3*99 + 2 = 301
 

Se vogliamo sapere che valore dobbiamo dare al registro contatore  per ottenere i µS desiderati basta fare:
 

    n = ( µS - 1 ) / 3
 

infatti se vogliamo 301 µS allora n = (301-1)/3 = 100

Si puo' notare che con il ciclo non e' possibile ottenere 302 e 303 µS in quanto dando il valore 101 al contatore otteniamo gia' 304µS. Nel caso si desiderassero i 302µS si scrive una NOP prima o dopo del ciclo, se si desiderassero i 303µS si puo' usare una goto fittizia:
 

            goto   $+1       ;goto fittizia 2 cicli
            movlw  100
            movwf  contat    ;predispone 100 iterazioni
   ciclo    decfsz contat,f  ;decrementa contat, skip se zero
            goto   ciclo     ;prossimo ciclo se non zero
 
 

[Precedente]   [Indice principale]   [Seguente]


By Claudio Fin - Ultimo aggiornamento pagina 4-2-2004