PICmicro. PICmicro Cult 2

Il Register File

Il REGISTER FILE è un'insieme di locazioni di memoria RAM ovvero memorie con cui è possibile leggere e modificare il contenuto senza l'ausilio di programmatori esterni e direttamente dal programma in esecuzione sul PICmicro.
Date le sue caratteristiche il REGISTER FILE è la memoria normalmente utilizzata per memorizzare le variabili di programma, ovvero tutti quei valori il cui contenuto varia durante l'esecuzione.
Contrariamente alla PROGRAM MEMORY il REGISTER FILE perde il suo contenuto quando il PICmicro viene spento per cui è necessario reinizializzare i valori di tutte le sue locazioni prima di poterla usare.
Alcune locazioni del REGISTER FILE ed in particolare quelle che si trovano agli indirizzi più bassi vengono usate per il controllo dell'hardware del PICmicro secondo quanto illustrato di seguito.

Le locazioni di memoria presenti nel REGISTER FILE sono indirizzabili direttamente in uno spazio di memoria che va da 0x00 a 0x2F per un totale di 48 byte, denominato pagina 0. Un secondo spazio di indirizzamento denominato pagina 1 va da 0x80 a 0xAF. Per accedere a questo secondo spazio e' necessario ricorrere ai due bit ausiliari RP0 e RP1 secondo le modalità che andremo a spiegare più avanti.

Le prime 12 locazioni della pagina 0 (da 0x00 a 0x0B) e della pagina 1 (da 0x80 a 0x8B) sono quelle riservate alle funzioni speciali per il funzionamento del PICmicro e non possono essere utilizzate per altri scopi.
Le 36 locazioni in pagina 0 indirizzate da 0x0C a 0x2F possono essere utilizzate liberamente dai nostri programmi per memorizzare variabili, contatori, ecc.

Nel nostro esempio LED.ASM la direttiva:

ORG  0x0C

indica proprio l'indirizzo di inizio dell'area dati utilizzabile dal nostro programma.
La direttiva che segue:

Count    RES 2 

riserva uno spazio di due locazioni, che il programma utilizzerà per memorizzare i contatori di ritardo della subroutine Delay.

I registri specializzati del PIC vengono utilizzati molto di frequente nei programmi.

Ad esempio, si ricorre alla coppia di registri specializzati TRISA (0x85) e TRISB (0x86), per definire quali linee di I/O sono in ingresso e quali in uscita. Lo stesso stato logico delle linee di I/O dipende dal valore dei due registri PORTA (0x05) e PORTB (0x06).
Alcuni registri riportano lo stato di funzionamento dei dispositivi interni al PICmicro o il risultato di operazioni aritmetiche e logiche.

E' necessario conoscere esattamente quale funzione svolge ciascun registro specializzato e quali effetti si ottengono nel manipolarne il contenuto.
Per facilitare le operazioni sui registri specializzati, nel file P16F84A.INC (che come ricorderete era stato incluso nel source LED.ASM con la direttiva INCLUDE) la Microchip ha inserito una lista di nomi che identificano univocamente ciascun registro specializzato e a cui sono associati gli indirizzi corrispondenti nell'area dei REGISTER FILE.
Se, ad esempio, volessimo definire tutte le linee della porta B del PIC in uscita agendo sul registro TRISB, potremmo scegliere di referenziare direttamente il registro con il suo indirizzo:


        movlw  B'00000000'
	movwf  0x86

oppure, referenziare lo stesso registro con il suo nome simbolico:


        movlw  B'00000000'
	movwf TRISB

avendo pero l'accortezza di inserire la direttiva INCLUDE "P16F84A.INC" nel nostro source.

La ALU

La ALU (acronimo di Arithmetic and Logic Unit ovvero unita aritmetica e logica) è la componente più complessa del PICmicro in quanto contiene tutta la circuiteria delegata a svolgere le funzioni di calcolo e manipolazione dei dati durante l'esecuzione di un programma.

La ALU è una componente presente in tutti i microprocessori e da essa dipende direttamente la potenza di calcolo del micro stesso.
La ALU del PIC16F84A è in grado di operare su valori ad 8 bit, ovvero valori numerici non più grandi di 255. Esistono microprocessori con ALU a 16, 32, 64 bit e oltre. La famiglia Intel 80386 486 e Pentium ad esempio dispone di una ALU a 32 bit. Le potenze di calcolo raggiunte da questi micro sono notevolmente superiori a scapito della complessità della circuiteria interna ed accessoria e conseguentemente dello spazio occupato.

L'Accumulatore o registro W

Direttamente connesso con la ALU c'è il registro W denominato anche accumulatore. Questo registro consiste di una semplice locazione di memoria in grado di contenere un solo valore a 8 bit.
La differenza sostanziale tra il registro W e le altre locazioni di memoria consiste proprio nel fatto che, per referenziare ill registro W, la ALU non deve fornire nessun indirizzo di memoria, ma puo' accedere direttamente.
Il registro W viene utilizzato molto spesso nei programmi per PICmicro.
Facciamo un esempio pratico. Supponiamo di voler inserire nella locazione di memoria 0xC del REGISTER FILE il valore 0x01. Cercando tra le istruzioni del PICmicro ci accorgiamo subito che non esiste un'unica istruzione in grado di effettuare questa operazione ma dobbiamo necessariamente ricorrere all'accumulatore ed usare due istruzioni in sequenza.
Vediamo perché:

Come detto nei passi precedenti, l'opcode di una istruzione non può essere più grande di 14 bit mentre a noi ne servirebbero:

8 bit per specificare il valore che intendiamo inserire nella locazione di memoria,
7 bit per specificare in quale locazione di memoria vogliamo inserire il nostro valore,
6 bit per specificare quale istruzione intendiamo utilizzare.
per un totale di 8 + 7 + 6 = 21 bit.

Dobbiamo quindi ricorrere a due istruzioni, ovvero:


        movlw	0x01
	movwf   0x0C

che prima inseriscono nel registro W il valore 0x01H con l'istruzione MOVe Literal to W e poi lo "muovono" nella locazione 0x0C con l'istruzione MOVe W to F.

Il Program Counter (PC)

Come abbiamo già visto nei passi precedenti, il PIC16F84A inizia l'esecuzione del programma a partire dal vettore di reset (Reset Vector) ovvero dall'istruzione memorizzata nella prima locazione di memoria (indirizzo 0x000).
Dopo aver eseguito questa prima istruzione passa quindi all'istruzione successiva memorizzata nella locazione 0x001 e così via. Se non esistesse nessuna istruzione in grado di influenzare in qualche modo l'esecuzione del programma, il PICmicro arriverebbe presto ad eseguire tutte le istruzione presenti nella sua memoria fino all'ultima locazione disponibile.
Sappiamo ovviamente che non è così e che qualsiasi microprocessore o linguaggio di programmazione dispone di istruzioni di salto, ovvero di istruzioni in grado di modificare il flusso di esecuzione del programma in base alle esigenze del programmatore.
Una di queste istruzioni e' la GOTO (dall'inglese GO TO, vai a) che ci permette di cambiare la sequenza di esecuzione e di "saltare" direttamente ad un qualsiasi punto, all'interno della memoria programma, e di continuare quindi l'esecuzione a partire da quel punto.

Facciamo un esempio:


             ORG	0x00

Point1
	     movlw     10
	     goto       Point1

Al reset il PICmicro eseguirà l'istruzione MOVLW 10 memorizzata alla locazione 0x000, la quale inserirà nell'accumulatore il valore decimale 10, quindi passera' ad eseguire l'istruzione successiva GOTO Point1. Questa istruzione determinerà un salto incondizionato alla locazione di memoria puntata dalla label Point1 ovvero di nuovo alla locazione 0x000. Nel suo insieme quindi, questo programma non farà altro che eseguire continuamente le due istruzioni elencate.
Durante questo ciclo (o loop), per determinare quale sara' l'istruzione successiva da eseguire, il PIC utilizza uno speciale registro denominato PROGRAM COUNTER (dall'inglese contatore di programma) la cui funzione è proprio quella di mantenere traccia dell'indirizzo che contiene la prossima istruzione da eseguire.
Questo registro viene incrementato automaticamente ad ogni istruzione eseguita per determinare il passaggio all'istruzione successiva. Al momento del RESET del PIC il PROGRAM COUNTER viene azzerato, determinando così l'inizio dell'esecuzione a partire dall'indirizzo 0x000.
L'istruzione GOTO consente l'inserimento a programma di un nuovo valore nel PROGRAM COUNTER ed il di conseguente salto ad una locazione qualsiasi dell'area programma del PIC.

Lo Stack Pointer

Un'altra istruzione molto utile, che influenza il valore del PROGRAM COUNTER e' la CALL (dall'inglese chiamata) con la quale e' possibile effettuare delle CHIAMATE A SUBROUTINE.
Questa istruzione funziona in maniera molto simile alla GOTO. Come la GOTO infatti permette di scrivere nel PROGRAM COUNTER un nuovo indirizzo di esecuzione del programma. La differenza sostanziale consiste pero nel fatto che prima di eseguire il salto,. il PIC memorizza, in un altro registro speciale, denominato STACK, l'indirizzo di quella che sarebbe dovuta essere la successiva  istruzione da eseguire se non si fosse incontrata la CALL.
Vediamo meglio con un esempio:

ORG	0x00

Point1
	movlw	10
	call      Point2
	goto 	 Point1

Point2
	movlw	11
	return


In questo caso il PICmicro, dopo aver eseguito la MOVLW 10 passa ad eseguire listruzione CALL Point2. Prima di saltare pero, memorizza nello STACK l'indirizzo 0x002, ovvero l'indirizzo della locazione successiva alla CALL. L'esecuzione passa quindi all'istruzione MOVLW 11 e quindi alla istruzione RETURN (dall'inglese ritorno). Questa istruzione, come dice il suo nome, consente di "ritornare", ovvero di riprendere l'esecuzione a partire dall'istruzione successiva alla CALL che aveva determinato l'abbandono del flusso principale del programma utilizzando il valore memorizzato nel registro di STACK.
Come detto l'operazione appena effettuata viene denominata CHIAMATA A SUBROUTINE, ovvero una interruzione momentanea del normale flusso di programma per "chiamare" in esecuzione una serie di istruzioni per poi ritornare al normale flusso di esecuzione.
La parola STACK in inglese significa "catasta" ed infatti su questa catasta e' possibile depositare, uno sull'altro, piu' indirizzi per recuperarli quando servono. Questo tipo di memorizzazione viene anche denominata LIFO dall'inglese Last In First Out, in cui l'ultimo elemento inserito (last in) deve necessariamente essere il primo ad uscire (last out). Grazie a questa caratteristica è possibile effettuare più CALL annidate ovvero l'una nell'altra e mantenere sempre traccia del punto in cui riprendere il flusso al momento che si incontra una istruzione RETURN.
Vediamo un altro esempio:

	
            ORG	0x00

Point1
	movlw	10
	call	  Point2
	goto	Point1

Point2
	movlw	11
	call      Point3
	return

Point3
	movlw	12
	return

In questo caso nella subroutine Point2 viene effettuata un'ulteriore CALL alla subroutine Point3. Al ritorno da quest'ultima il programma dovrà rientrare nella subroutine Point2 eseguire la RETURN e quindi tornare nel flusso principale.
Gli indirizzi da memorizzare nello stack sono due in quanto viene incontrata una seconda CALL prima ancora di incontrare la RETURN corrispondente alla prima.
Il PIC16F84A dispone di uno stack a 8 livelli, ovvero uno stack che consente fino ad 8 chiamate annidate.
E' importante assicurasi, durante la stesura di un programma, che ci sia sempre una istruzione RETURN per ogni CALL per evitare pericolosi disallineamenti dello stack che in esecuzione possono dar adito a errori difficilmente rilevabili.

Realizziamo le "luci in sequenza"

Proviamo ora a fissare i concetti finora appresi rielaborando il source LED.ASM presentato nella prima lezione per realizzare un lampeggiatore sequenziale a quattro led. Il nuovo source modificato si chiamerà SEQ.ASM

Nella figura seguente viene riportato lo schema elettrico del nuovo circuito, sostanzialmente equivalente al circuito presentato nella prima lezione, con l'unica variante che ora i led collegati sono quattro anziché uno.

Le linee di I/O utilizzate sono RB0 per primo led, RB1 per il secondo, RB2 per il terzo ed RB3 per il quarto. Esse vanno quindi configurate tutte in uscita all'inizio del programma cambianto le istruzioni:


movlw B'11111110'
movwf TRISB

in


movlw B'11110000'
movwf TRISB

in cui i quattro bit meno significativi, corrispondenti alle linee RB0,1,2,3 vengono messi a zero per definire tali linee in uscita.
Nell'area di memoria del REGISTER FILE (che nel source inizia con la direttiva ORG 0x0C) oltre ai due byte referenziati dalla label Count, riserviamo un ulteriore byte con label Shift che utilizzeremo per determinare la sequenza di accensione dei led. La direttiva da inserire e':

Shift	RES	1

Prima di eseguire il ciclo principale (label MainLoop) inizializziamo il nuovo registro Shift a 00000001B con le seguenti istruzioni istruzioni:


movlw	B'00000001'
movwf	Shift

A questo punto, nel ciclo principale del nostro programma, ci occuperemo di trasferire il valore memorizzato nel registro Shift sulla Porta B ottenendo quindi l'accensione del primo led, con le seguenti istruzioni:


movf	Shift,W
movwf	PORTB

quindi di effettuare lo shift a sinistra del valore contenuto in Shift di un bit, con le seguenti istruzioni:


bcf	STATUS,C
rlf	Shift,F

la prima istruzione serve ad azzerare il bit CARRY del registro di stato STATUS che verrà analizzato nelle lezioni successive. L'istruzione RLF Rotate Left F through Carry (ruota a sinistra attraverso il bit di carry) sposta di un bit verso sinistra il valore memorizzato nel registro Shift inserendo nella posizione occupata dal bit 0 il valore del bit di Carry (che come già detto andremo a vedere in seguito). Per far si che il bit inserito sia sempre zero viene eseguita prima della RLF l'istruzione BCF STATUS,C per azzerare questo bit.

A questo punto il registro Shift varrà 00000010, quindi, al ciclo successivo, una volta trasferito tale valore sulla port B si otterrà lo spegnimento del LED1 e l'accensione del LED2 e così via per i cicli successivi.
Quando il bit 4 di Shift varrà 1, vorrà dire che tutti e quattro i led sono stati accesi almeno una volta e occorre quindi ripartire dal led 1. Le istruzioni seguenti svolgono questo tipo di controllo:


btfsc	Shift,4
swapf	Shift,F

L'istruzione BTFSC Shift,4 controlla appunto se il bit 4 del registro Shift vale 1. Se si esegue l'istruzione successiva SWAPF Shift,F altrimenti la salta.
L'istruzione SWAP (dall'inglese "scambia") in pratica scambia i quattro bit più significativi contenuti nel registro Shift con i quattro meno significativi. Dal valore iniziale del registro Shift pari a 00010000 ottenuto dopo alcune ripetizioni del ciclo MainLoop si ottiene il valore 00000001 ed in pratica alla riaccensione del primo led.

Esempio di LED in sequenza

Se vi volete divertire...

"

Introduzione alle periferiche

Le porte A e B, stadi d'uscita delle linee di input output, input da tastiera.

Il PIC16F84A dispone di un totale di 13 linee di I/O organizzate in due porte denominate PORTA A e PORTA B.
La PORTA A dispone di 5 linee configurabili sia in ingresso che in uscita identificate dalle sigle RA0, RA1, RA2, RA3 ed RA4.
La PORTA B dispone di 8 linee anch'esse configurabili sia in ingresso che in uscita identificate dalle sigle RB0, RB1, RB2, RB3, RB4, RB5, RB6 ed RB7.

La suddivisione delle linee in due porte distinte è dettata dai vincoli dell'architettura interna del PIC16F84A che prevede la gestione di dati di lunghezza massima pari a 8 bit.
Per la gestione delle linee di I/O da programma, il PIC dispone di due registri interni per ogni porta denominati TRISA e PORTA per la porta A e TRISB e PORTB per la porta B.
I registri TRIS A e B, determinano il funzionamento in ingresso o in uscita di ogni singola linea, i registri PORT A e B determinano lo stato delle linee in uscita o riportano lo lo stato delle linee in ingresso.
Ognuno dei bit contenuti nei registri menzionati corrisponde univocamente ad una linea di I/O.
Ad esempio il bit 0 del registro PORTA e del registro TRIS A corrispondono alla linea RA0 , il bit 1 alla linea RA1 e cosi' via.
Se il bit 0 del registro TRISA viene messo a zero, la linea RA0 verrà configurata come linea in uscita, quindi il valore a cui verrà messo il bit 0 del registro PORTA determinerà lo stato logico di tale linea (0 = 0 volt, 1 = 5 volt).
Se il bit 0 del registro TRISA viene messo a uno, la linea RA0 verrà configurata come linea in ingresso, quindi lo stato logico in cui verrà posta dalla circuiteria esterna la linea RA0 si rifletterà sullo stato del bit 0 del registro PORTA.
Facciamo un esempio pratico, ipotizziamo di voler collegare un led sulla linea RB0 ed uno switch sulla linea RB4, il codice da scrivere sarà il seguente:

movlw	00010000B
tris	B

in cui viene messo a 0 il bit 0 (linea RB0 in uscita) e a 1 il bit 4 (linea RB4) in ingresso. Si ricorda a tale proposito che nella notazione binaria dell'assembler il bit più a destra corrisponde con il bit meno significativo quindi il bit 0.
Per accendere il led dovremo scrivere il seguente codice:

bsf	PORTB,0

Per spegnerlo:

bcf	PORTB,0

Per leggere lo stato dello switch collegato alla linea RB4, il codice sarà:

btfss	PORTB,4
goto 	SwitchAMassa
goto 	SwitchAlPositivo

Stadi d'uscita delle linee di I/O

Per rendere più adattabili i PICmicro alle diverse esigenze di utilizzo, la Microchip ha implementato diverse tipologie di stati d'uscita per le linee di I/O. Esistono quindi dei gruppi di pin il cui comportamento è leggermente differenziato da altri gruppi. Conoscendo meglio il funzionamento dei diversi stadi d'uscita potremo sfruttare al meglio le loro caratteristiche ed ottimizzare il loro uso nei nostri progetti.

Stadio d'uscita delle linee RA0, RA1, RA2 e RA3

Iniziamo dal gruppo di linee RA0, RA1, RA2 ed RA3 per le quali riproduciamo, nella figura seguente, lo schema dello stadio d'uscita estratto dal data sheet della Microchip:

Come accennato al passo precedente, la configurazione di una linea come ingresso o uscita dipende dallo stato dei bit nel registro TRIS (TRISA per la porta A e TRISB per la porta B).
Prendiamo come esempio la linea RA0 ed analizziamo il funzionamento dello stadio d'uscita sia quando la linea funziona in ingresso, che quando funziona in uscita.

Funzionamento in ingresso

Per configurare la linea RA0 in ingresso, dobbiamo mettere a 1 il bit 0 del registro TRISA con l'istruzione:

bsf	TRISA,0

Questo determina una commutazione ad 1 dello stato logico del flip-flop di tipo D-latch indicato nel blocco con il nome TRIS latch. Per ogni linea di I/O esiste uno di questi flip-flop e lo stato logico in cui si trova dipende strettamente dallo stato logico del relativo bit nel registro TRIS (anzi per meglio dire ogni bit del registro TRIS è fisicamente implementato con un TRIS latch).
L'uscita Q del TRIS latch è collegata all'ingresso di una porta logica di tipo OR. Questo significa che, indipendentemente dal valore presente all'altro ingresso, l'uscita della porta OR varrà sempre 1 in quanto uno dei suoi ingressi vale 1 (vedi tavola della verità). In questa condizione il transistor P non conduce e mantiene la linea RA0 scollegata dal positivo d'alimentazione.
Allo stesso modo l'uscita negata del TRIS latch è collegata all'ingresso di una porta AND quindi l'uscita di questa varrà sempre 0 in quanto uno dei suoi ingressi vale 0 (vedi tavola). In questa condizione anche il transistor N non conduce mantenendo la linea RA0 scollegata anche dalla massa. Lo stato logico della linea RA0 dipenderà esclusivamente dalla circuiteria esterna a cui la collegheremo.

Applicando 0 o 5 volt al pin RA0, sarà possibile leggerne lo stato sfruttando la circuiteria d'ingresso del blocco rappresentata dal TTL input buffer e dal latch d'ingresso.

Scarica subito una copia gratis

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend