509 lines
25 KiB
Plaintext
509 lines
25 KiB
Plaintext
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 bytes 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 bytes 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
|
|
|
|
|
|
|