Questa pagina richiede il font 7Segments, scaricabile qui.
Le Tabelle RETLW
Nei PIC, il Program
Counter avanza a seconda dell' istruzione incontrata, scandendo la
lista del programma in modo automatico.
Però è possibile manipolarne il valore per far si che l' istruzione
successiva non sia quella prevista dall' automatismo, ma un' altra.
PC e PCLATH sono accessibili come normali SFR e quindi il loro
contenuto può essere letto e scritto, con istruzioni del genere movwf
PCL, addwf PCL, ecc.
Un uso pratico di questa possibilità è la creazione di tabelle che
possono essere scandite a seconda di un offset stabilito. La loro funzione è
quella di tradurre il valore indicato dall' offset in un numero binario
differente.
Più che le parole, un esempio chiarifica bene la questione.
|
Supponiamo di avere in display a 7 segmenti, a catodo comune, ognuno
dei quali è collegato ad un pin di un port del processore.
Ogni volta che noi portiamo a livello 1 un pin, il corrispondente
segmento del display si accenderà.
Certamente possiamo dire che ad ognuna delle 256 combinazioni
possibili dei valori 1 e 0 dei pin del port corrisponde una specifica
situazione di segmenti accesi e spenti. |
Ad esempio:
pin PORT |
|
Segmenti accesi |
|
Cifra |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
dp |
G |
F |
E |
D |
C |
B |
A |
|
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
|
|
|
|
|
|
|
|
|
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
|
|
|
|
|
|
|
X |
|
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
|
|
|
|
|
|
X |
|
|
0 |
0 |
0 |
0 |
0 |
0 |
1 |
1 |
|
|
|
|
|
|
X |
X |
|
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
|
|
|
|
|
X |
|
|
|
0 |
0 |
0 |
0 |
0 |
1 |
0 |
1 |
|
|
|
|
|
X |
|
X |
|
0 |
0 |
0 |
0 |
0 |
1 |
1 |
0 |
|
|
|
|
|
X |
X |
|
|
0 |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
|
|
|
|
|
X |
X |
X |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
che mette in rapporto i segmenti accesi e il livello logico dei pin del
port.
Ora, è chiaro che, tra tutte le possibili combinazioni, solo alcune
rappresentano una cifra numerica o una lettera. Nella tabella qui sopra,
soltanto la situazione presentata nella quarta riga è identificabile come un
1 e quella nell' ultima riga è identificabile come un 7. Le altre
combinazioni non hanno una corrispondenza con caratteri alfanumerici
Volendo usare il nostro display per rappresentare le cifre da 0 a 9 dobbiamo
restringere le possibili 256 combinazioni alle sole 10 utilizzabili.
Ne otteniamo la seguente tabella:
In questa tabella abbiamo associato tre elementi:
- la cifra che vogliamo rappresentare con i segmenti accesi
- i segmenti accesi necessari a rappresentare la cifra
- la parola di 8 bit necessaria da piazzare sul PORT per ottenere quei
determinati segmenti accesi
Dunque, nel momento in cui voglio accendere la cifra 8, dovrò porre sul
PORT il valore b'01111111' (che in esadecimale è 7Fh).
Così per visualizzare uno 0 dovrò caricare b'001111111' (che è 3Fh). E
così via.
Va notato che la corrispondenza tra il numero esadecimale-binario
del PORT e i segmenti accesi dipende da come sono collegati
fisicamente i pin e i segmenti.
Cambiando le connessioni, ovvero il rapporto tra pin e segmenti, il contenuto della tabella cambierà di
conseguenza. |
Due considerazioni:
- sicuramente è più semplice pensare alle cifre-numeri come tali e non
come corrispondenti esadecimali dipendenti dalle connessioni fisiche tra
in e segmenti. Ed in effetti anche il codice BCD o ASCII che
normalmente si usano per rappresentare cifre all' interno del programma
sono in relazione con i numeri reali che rappresentano (ad esempio, 0 in
ASCII è 30h, in BCD sarà 03h.
- possiamo pensare di usare la tabella "manualmente": ogni volta
che nel programma ci serve rappresentare un dato numero, caricheremo il
PORT con il valore opportuno.
Ma sarebbe più semplice se il programma facesse questa conversione per
noi.
Si tratta allora di inserire nel programma la nostra tabella in modo tale
che sia il programma stesso ad utilizzarla per noi, scegliendo la giusta
combinazione di bit da applicare a port per ottenere il display voluto.
Uno dei sistemi più semplici per ottenere questo è la creazione di una
Tabella RETLW, così chiamata dal fatto che è costituita da una serie di
istruzioni retlw numero, dove numero
è il valore binario (esadecimale) cercato.
La forma tipica di una tabella RETLW è questa:
;--------------------------------------------------------------
; 7 segments display code Table
;--------------------------------------------------------------
;**************************************************************
;* Table for 7 segment display
;* Displayport: 0 Segment A AAAAA
;*
1 Segment B F B
;*
2 Segment C F B
;*
3 Segment D GGGGG
;*
4 Segment E E C
;*
5 Segment F E C
;*
6 Segment G DDDDD
;*
7 Segment dp dp
GetDigitCode
addwf PCL,
f
; segments table for high level(common K) drive
; pin 76543210
; segment pGFEDCBA pos hex
retlw b'00111111'
; 0 - 0x3F
retlw b'00000110'
; 1 - 0x06
retlw b'01011011'
; 2 - 0x5B
retlw b'01001111'
; 3 - 0x4F
retlw b'01100110'
; 4 - 0x66
retlw b'01101101'
; 5 - 0x6D
retlw b'01111101'
; 6 - 0x7D
retlw b'00000111'
; 7 - 0x07
retlw b'01111111'
; 8 - 0x7F
retlw b'01101111'
; 9 - 0x6F |
La tabella viene "chiamata" semplicemente con un call,
avendo cura di caricare WREG con la cifra che si vuole rappresentare. Quindi,
ad esempio:
...
movlw
.3
; cifra 3
; display numero
call
GetDigitCode ; prendo dalla tabella
disp movwf
DisplayPort ; e copio sul
port di uscita
... |
La tabella ritorna con il codice corrispondente alla cifra in WREG.
Molto semplice ed efficace. Ma può ancora essere oscuro come il meccanismo
funzioni.
Ricordando quello
che conosciamo del funzionamento del Program Counter non è poi così
complicato. Vediamolo nei dettagli:
...
movlw
.3
; in WREG la
cifra 3
call
GetDigitCode ; l'
istruzione call
salva nello stack il valore corrente
; del prossimo passo (disp)
del PC e lo sostituisce con l'
; indirizzo di GetDigitCode prendo
dalla tabella
; il programma lascia la sequenza corrente e passa ad eseguire la GetDigitCode
...
...
;
Viene eseguita la prima
istruzione addwf PCL,
f, che modifica il
contenuto del PC
; sommando il valore
numerico contenuto in WREG, ovvero 3.
GetDigitCode
addwf PCL,
f
; Ora il PC contiene l'
indirizzo dell' istruzione prossima da eseguire, ma
; aumentato di tre. Di conseguenza sarà eseguita non la linea
;
retlw b'00111111' ; PC+0 - 0x3F
; ma la linea evidenziata, che ha indirizzo PC+3
retlw b'00111111'
; PC+0 - 0x3F
retlw b'00000110'
; PC+1 - 0x06
retlw b'01011011'
; PC+2 - 0x5B
retlw b'01001111'
; PC+3 - 0x4F
; retlw
scarica dallo stack l' indirizzo di ritorno salvato dalla call
e rientra
; alla label disp,
avendo in WREG il valore b'01001111'(4Fh).
...
...
; WREG contiene ora valore
4Fh, che, applicato al PORT da cui dipendo i segmenti
; provocherà l' accensione della cifra 3.
disp movwf
DisplayPort |
E così per ogni altro entri retlw
della tabella. Ovvero, in modo "meccanico", colleghiamo un indice
(offset) inviato attraverso WREG con uno dei valori contenuti nella tabella.
Il meccanismo sfrutta la modifica forzata del PC con la somma dell' offsset.
I limiti delle tabelle RETLW
Questo sistema può essere implementato su qualsiasi PIC 10/12/16/18
e le note seguenti valgono per tutti i PIC indicati (anche se nei PIC18F la
Tabella RETLW viene sostituita con grande vantaggio dalle istruzioni di
accesso alle tabelle, tipiche del set Enhanced).
Ma esistono alcuni limiti che vanno rispettati:
- WREG è un registro a 8 bit, quindi la tabella non può avere più di
255 entries.(1 spazio è occupato dalla addwf PCL,f
)
- Anche PCL è un registro a 8 bit, quindi il suo contenuto va da 00h a
FFh.
- Dato che l' istruzione addwf PCL,f
somma al PC corrente il contenuto di WREG, occorre che il risultato di
questa somma non sia superiore a FFh, altrimenti occorre modificare anche
il PCH.
- Se la tabella si trova in una pagina diversa da quella della chiamata,
occorre modificare il PCLATH di conseguenza
Dunque è necessario che:
- la tabella non sia più ampia di 256 linee
- che il suo indirizzo di inizio sia tale per cui la somma con il
contenuto di WREG non superi FFh
Ovvero, una tabella che inizia a 0x0FD potrà avere solo 3 linee.
Altrimenti la parte che sborda oltre 0x100F farà si che il PC venga a
contenere valori che nulla hanno a che fare con la tabella.
Questo perchè, ricordiamo, la scrittura di PCL provoca la copia di PCLATH in
PCH, ma l' incremento di PCL effettuato dalla addwf
NON aggiorna di conseguenza il PCLATH. Che dovrà essere aggiornato a aprte,
se necessario.
Cos' pure se la call genera
un salto di pagina, occorre che il PCLATH sia modificato opportunamente,
altrimenti il salto avverrà nella stessa pagina chiamante, con le relative
conseguenze..
Quindi le tabelle RETLW sono impiegabili senza alcuna manipolazione del
PCLATH se:
- sono situate nella pagina chiamante
- non sono a cavallo tra due pagine
Negli altri casi occorrerà manipolate il PCLATH.
Ed occorrerà una struttura diversa per tabelle più ampie di FFh.
Le tabelle RETLW nei PIC18F
Abbiamo detto che nulla osta all' utilizzo delle tabelle RETLW per i
PIC18F, anche se per questa famiglia il set di istruzioni offre una serie di
opcodes pensati proprio per la gestione delle tabelle e molto più pratici del
sistema fin qui dettagliato.
In ogni caso, ci si può trovare a dover inserire una brevissima tabella
oppure a dover convertire un sorgente scritto per PIC16 e trovare più comodo
mantenere la struttura RETLW.
In questo caso è necessaria una ulteriore considerazione:
Le istruzioni dei PIC Enhanced sono codificate su 2 o 4 bytes, ovvero
sempre su un numero pari di bytes.
Quindi l' accesso alla memoria programma attraverso il RETLW avviene sugli
indirizzi pari, dato che il bit 0 del Program Counter è sempre a 0 (e punta
quindi solo a indirizzi pari).
Ne risulta che la tabella RETLW vista in precedenza, in un PIC16 viene
assemblata come: (ved. Nota più avanti)
Indirizzo |
Contenuto |
Istruzione |
00000A |
0782 |
addwf PCL, f |
00000B |
34C0 |
retlw b'00111111' |
00000C |
34F9 |
retlw b'00000110' |
0000D |
34A4 |
retlw b'01011011' |
0000E |
34B0 |
retlw b'01001111' |
0000F |
3499 |
retlw b'01100110' |
000010 |
3492 |
retlw b'01101101' |
000011 |
3482 |
retlw b'01111101' |
000012 |
34F8 |
retlw b'00000111' |
000013 |
3480 |
retlw b'01111111' |
000014 |
3490 |
retlw b'01101111' |
Va notato che la memoria programma è organizzata in "bytes" da
12 o 14 bit per cui la cifra esadecimale dell'opcode (contenuto) è lunga al
massimo 12 o 14 bit e occupa una sola locazione.
Ma in un PIC18F la memoria programma è organizzata in bytes da 8 bit per
cui la cifra esadecimale dell'opcode (contenuto), che è lunga (al minimo) 16
bit, occupa DUE locazioni.
Quindi la tabella diventa: (ved. Nota più avanti)
Indirizzo |
Contenuto |
Istruzione |
00000A |
26F9 |
addwf PCL, f |
00000C |
0C3F |
retlw b'00111111' |
00000E |
0C06 |
retlw b'00000110' |
000010 |
0C5B |
retlw b'01011011' |
000012 |
0C4F |
retlw b'01001111' |
000014 |
0C66 |
retlw b'01100110' |
000016 |
0C6D |
retlw b'01101101' |
000018 |
0C7D |
retlw b'01111101' |
00001A |
0C07 |
retlw b'00000111' |
00001C |
0C7F |
retlw b'01111111' |
00001E |
0C6F |
retlw b'01101111' |
Ovvero ogni linea della tabella occupa 2 bytes e il passaggio da una linea
all' altra necessita di un incremento del PC non di una unità, ma di 2.
Ne deriva che l' entry per la tabella, per un PIC18F dovrà essere
modificata così::
GetDigitCode
rlncf
WREG, f ;<--
raddoppia il puntatore
addwf PCL,
f
; segments table for high level(common K) drive
; pin 76543210
; segment pGFEDCBA PC+ hex
retlw b'00111111'
; 0 - 0x3F
retlw b'00000110'
; 1 - 0x06
retlw b'01011011'
; 2 - 0x5B
retlw b'01001111'
; 3 - 0x4F
retlw b'01100110'
; 4 - 0x66
retlw b'01101101'
; 5 - 0x6D
retlw b'01111101'
; 6 - 0x7D
retlw b'00000111'
; 7 - 0x07
retlw b'01111111'
; 8 - 0x7F
retlw b'01101111'
; 9 - 0x6F |
Va da se che, essendo sempre il WREG a 8 bit, l' ampiezza possibile della
tabella sarà dimezzata (dato che le linee occupano il doppio di spazio).
E restano validi tutti i limiti descritti prima: anche se i PIC18F non
hanno paginazione della memoria programma, ugualmente il meccanismo del PC non
prevede un aggiornamento della parte alta dopo una somma sulla parte basse.
Va notato che l' ampiezza della memoria programma, così come
quella del codice di una istruzione dei PIC è differente a seconda
della famiglia.
I PIC16F hanno memoria programma e codice istruzioni a 14 bit
I PIC18F hanno memoria programma e codice istruzione a 16 bit
Questo vuol dire che il "byte" della memoria programma
dei PIC16 è ampio non 8, ma 14 (o12) bit. E questa è l' ampiezza del bus
istruzioni, in modo tale che l' intero opcode viene trattato in un
solo passaggio.
Potremmo dire che il "byte" istruzioni è di 14 (o12) bit.
Mentre il byte della memoria programma dei PIC18F è 8 bit,
configurati però come word da 16 bytes. E questa è l' ampiezza del bus
istruzioni, in modo tale che anche qui l' intero opcode viene trattato
in un solo passaggio, con una word da 16 bit.
Ne deriva che il codice di una istruzione (ampio 12 o 14 bit) nei PIC16F occupa una
cella di memoria programma (ampia 12 o 14 bit).
E, partendo il Vettore del Reset da 0000h, può collocarsi ad
indirizzi sia pari che dispari, a seconda della lunghezza dell' opcode,
dato che esistono anche istruzioni a due "bytes"
Mentre il codice di una istruzione nei PIC18F occupa due celle di
memoria da 1 byte ciascuna, per un totale di 16 bit. E, partendo il
Vettore del Reset da 0000h, può collocarsi solo ad indirizzi
pari.
E questo vale anche per le istruzioni lunghe 2 words, che, occupando
32 bit = 4 bytes, iniziano sempre ad indirizzi pari.
|
Argomenti collegati:
|