PICmicro. PICMICRO advanced 3

Vediamo ora come possiamo utilizzare le istruzioni per creare le strutture base di tutti i linguaggi ad alto livello: selezioni e iterazioni.
Gli esempi proposti sono da considerarsi più che altro dei modelli, che verranno
poi adattati in base alla situazione.

Selezione Semplice (If - Then)

	btfsc	STATUS,C	; carry = 1 ??
	istruzione		; sì
	btfss	STATUS,C	; carry = 1 ??
	goto	EndIf	; no
	istruzione1		; sì
	istruzione2
	istruzione3
EndIf
	....                        

Selezione Doppia (If - Then - Else)

	btfss	STATUS,C	; carry = 1 ??
	goto	Else	; no
	istruzione1		; sì
	istruzione2
	istruzione3
	goto	EndIf	
Else
	istruzione4
	istruzione5
	istruzione6
EndIf
	...

Iterazione a cicli fissi

	movlw	10	; 10 cicli
	movwf	0x0C	; usiamo il registro 0x0C come contatore
Loop
	istruzione1
	istruzione2
	....
	decfsz	0x0C,F	; decrementa 0x0C, se 0 salta l'struzione successiva
	goto	Loop	; altrimenti torna a "Loop"
	....                                        	
  
In questi esempi, si nota che ad alcuni numeri sono state sostituite delle lettere:
- STATUS = 0x03
- C = 0x00
- F = 0x01
Questo può essere fatto, in MPLab, con la direttiva EQU:
STATUS	EQU	0x03
C	EQU	0x00
F	EQU	0x01

Allo stesso modo possiamo dare ai nostri registri un nome; nell'ultimo esempio potremmo chiamare "Contatore"
il registro 0x0C.

Forti di queste conoscenze, possiamo vedere il primo esempio completo:
Il PIC non è in grado di eseguire moltiplicazioni: questo programma esegue la moltiplicazione
5x3 sommando tre volte cinque => 5x3 = 5+5+5

	include	"P16F84.INC"	; include il file che contiene tutte le EQU del PIC 16F84

DatoA	EQU	0x0C	; primo operando nel registro 0x0C
DatoB	EQU	0x0D	; il secondo in 0x0D
Ris	EQU	0x0E	; mettiamo il risultato in 0x0E

	ORG	0x00	; indica che ci troviamo all'indirizzo 0
			; della memoria programma

; il programma esegue la moltiplicazione 5x3
	movlw	0x05
	movwf	DatoA	; DatoA = 5

	movlw	0x03
	movwf	DatoB	; DatoB = 3

	clrf	Ris	; Ris = 0

Loop
	movf	DatoA,W	; W = DatoA = 5
	addwf	Ris,F	; Ris = Ris + W

	decfsz	DatoB,F	; decrementa DatoB (esegue il ciclo DatoB volte)
	goto	Loop	; torna a Loop

	END		; tutti i programmi devono terminare con END

Putroppo il risultato non può essere visto, se non con il debugger, perchè effettivamente questo
non viene comunicato all'esterno del chip; ma scopriremo come farlo nella prossima lezione.

Come già visto, possiamo usare i registri PORTA e PORTB per modificare lo stato
dei pin o per leggerne il valore; prima, però, bisogna definire quali sono gli ingressi
e le uscite, dobbiamo quindi modificare i registri TRISA e TRISB.
Quest'ultimi si trovano nel banco 1 e per accedervi agiremo sul registro di STATUS:

	bsf	STATUS,RP0	; mette a uno il bit RP0, viene selezionato il banco 1

A questo punto è possibilie modificare i due registri: metteremo le due porte tutte
come ingresso, tranne il primo piedino della porta B.

	movlw	B'11111111'
	movwf	TRISA
	movlw	B'11111110'
	movwf	TRISB

Quindi si torna al banco 0:

	bcf	STATUS,RP0	; mette a zero il bit RP0, viene selezionato il banco 0

Ora, agendo sul primo bit di PORTB, con le istruzioni bsf e bcf, cambierà lo stato dell'uscita:

	bsf	PORTB,0		; il pin RB0 è a 5V
	bcf	PORTB,0		; il pin RB0 è a 0V

Esempio pratico
Come primo esempio pratico, realizziamo il programma che fa lampeggiare un LED.
Il codice sorgente completo è disponibile qui, ma vediamolo in dettaglio:
la testata del programma e la configurazione delle porte è già stata illustrata,
quindi esaminiamo il resto del programma.

Main
	bsf	PORTB,0		; LED acceso
	call	Delay

	bcf	PORTB,0		; LED spento
	call	Delay

	goto	Main		; torna a Main

Questo è il corpo principale del programma: è costituito da un ciclo infinito:
una volta eseguite le quattro istruzioni, attraverso il goto, ritorna all'inizio e così via in eterno.
Come suggeriscono i commenti, le due istruzioni bsf e bcf accendono e spengono alternativamente il LED,
ma essendo la frequenza di lavoro molto elevata, ai nostri occhi il LED sembrerebbe sempre acceso;
per questo motivo è stata introdotta una routine di ritardo, chiamata Delay.
Si fa uso dell'istruzione call perchè, una volta eseguito il ritardo, si ritorna al corpo principale
del programma.

Vediamo dunque come viene fatto questo ritardo:

Delay
	clrf	Count1		; azzera i contatori
	clrf	Count2		;
Loop
	decfsz	Count2,F
	goto	Loop

	decfsz	Count1,F
	goto	Loop

	return			; ritorna al programma principale

Si tratta di due iterazioni a cicli fissi (viste nella lezione precedente) innestate una nell'altra; azzerando i contantori si ottiene
il numero massimo di iterazioni, ovvero 256 ciascuno, per un totale di 256*256 = 65536 cicli.
Il blocco di istruzioni:

	decfsz	Count2,F
	goto	Loop

decrementa Count2 per 256 volte, finchè non raggiunge lo zero: a questo punto si passa al secondo blocco
che decrementa il registro Count1 una volta, per poi tornare a "Loop" dove il registro Count2 verrà nuovamente
decrementato per 256 volte. Infine quando anche il Count1 raggiunge lo zero, la routine finisce con l'istruzione return.

Mettendo a zero i contatori non si ottiene il minor numero di iterazioni come si potrebbe
pensare bensì il massimo, infatti l'istruzione decfsz prima decrementa e solo poi esegue il controllo sullo zero,
perciò al primo decremento il contatore varrà 255, saranno quindi 256 le iterazioni totali.
Sappiamo che con un clock a 4Mhz, un ciclo istruzione è di un microsecondo,
perciò è possibile calcolare l'entità del ritardo:
- 2 per la call
- 1 per clrf
- 1 per decfsz
- 2 per goto, tranne quando viene fatto saltare da decfsz
- 2 per il return
quindi : 2 + 2 + ((3*256 - 1) + 3)*256 - 1 + 2  = 200ms circa

Lo scopo del programma è quello di riprodurre l'effetto supercar o, se si preferisce,
effetto luci scorrevoli avanti/indietro. In pratica si vuole ottenere la sequenza:


Gli approci per arrivare a questo risultato sono molti e diversi, ma ne esamineremo soltanto uno.
Il sorgente completo è qui.
Il programma consiste in una routine che esegue degli shift verso destra e verso sinistra in modo da creare la sequenza;
un registro tiene traccia della direzione in cui ci stiamo muovendo, quando il primo o l'ultimo LED si
accendono, la direzione viene invertita.

Schema elettrico

Il programma
L'intestazione contiene una piccola novità, che riguarda la direttiva ORG:

	ORG	0x0C		; indirizzo 0x0C della RAM

Count	RES	2		; riserva 2 byte per il contatore
Dir	RES	1		; riserva 1 byte per la direzione

In questo caso, infatti, la direttiva non si riferisce alla memoria programma, ma alla RAM;
poi, attraverso la direttiva RES si possono allocare gli spazi per i nostri registri, indicando il
numero di byte utilizzati. Nel nostro caso il registro Count occuperà i registri 0x0C e 0x0D, mentre a
Dir corrisponderà 0x0E.

Il programma inizia con la classica configurazione delle porte: semplicemente la porta A
viene settata come ingresso (non ci interessa), mentre la porta B è un'uscita. Il blocco di istruzioni
che seguono inizializzano l'uscita e la direzione:

	movlw	B'00000001'
	movwf	PORTB		; accende solo il primo LED

	clrf	Dir		; Dir = 0 = sinistra

Come sempre, il programma presenta un ciclo infito, rappresentato nel nostro caso dalla label Main:

Main
	call	Delay		; chiama il ritardo

	bcf	STATUS,C	; azzera il carry

	btfss	Dir,0		; se direzione
	goto	GoLeft		; = 0 va a sinistra

Ad ogni iterazione viene chiamato un piccolo ritardo e viene azzerato il carry: dobbiamo infatti ricordarci
che le istruzioni di rotazione prevedono il passaggio per il carry, è perciò consigliato settarlo secondo
le proprie esigenze prima di eseguire uno shift (nel nostro caso va azzerato).
Successivamente viene eseguito un controllo sul registro Dir per decidere in quale direzione ruotare.

;GoRight			; = 1 va a destra
	rrf	PORTB,F
	goto	Check

GoLeft
	rlf	PORTB,F

Questo sono le istruzioni che vengono chiamate per ruotare il contenuto della porta B.

Inifine, attraverso il blocco Check, controlliamo se siamo ad inizio o fine sequenza, in caso affermativo
viene invertita la direzione:

Check	
	btfss	PORTB,0		; se il primo bit
	btfsc	PORTB,7		; o l'ultimo bit sono settati
	comf	Dir,F		; inverte la direzione

Propongo un altro esempio, forse più semplice, di effetto supercar: supercar2.asm

Abbiamo già visto che esistono due registri (PCL e PCLATH) attraverso i quali è possibile
interagire con il Program Counter; uno dei loro utilizzi è la creazione di
tabelle di dati, o meglio array, e strutture di tipo switch (o case..of).

Tabelle Dati
Sfruttando l'istruzione retlw, possiamo realizzare degli array di costanti: tale istruzione
funziona come return ovvero permette di tornare dopo una chiamata
e, in più, mette una costante in w.
L'istruzione call:

In questo spezzone di codice, quando si giunge alla call, viene effettuato un salto a Label,
le istruzioni vengono eseguite normalmente, infine arrivati a return, si ritorna alla call o
meglio, all'istruzione che la segue.

Andiamo ora a creare la nostra tabella:

	retlw	B'00000000'
	retlw	B'10000001'
	retlw	B'01000010'
	retlw	B'00100100'
	retlw	B'00011000'

A questo punto interviene il registro PCL attraverso il quale potremo ottenere il valore che
desideriamo dalla tabella:

Tabella
	addwf	PCL,F		; aggiunge W a PCL
	retlw	B'00000000'
	retlw	B'10000001'
	retlw	B'01000010'
	retlw	B'00100100'
	retlw	B'00011000'

Mettendo in W l'indice dell'elemento voluto e aggiungendolo poi a PCL (con addwf), verrà eseguito un salto
quindi retlw ci restituirà il valore; essendo quest'ultima una funzione di ritorno, è indispensabile
utilizzare una chiamata per accedere alla tabella:

	....
	movlw	3
	call	Tabella
	....

In questo caso verrà restituito il quarto elemento (il n° 3), ovvero B'00100100'.

PCLATH
Come già visto, il Program Counter è un registro di 13bit, perciò PCL (8 bit) non è sufficiente per
accedervi, ma viene impiegato anche il registro PCLATH (5 bit).
Quando si crea una tabella, bisogna tenere conto di questo fatto, ovvero dobbiamo considerare
che andando a modificare il registro PCL, possiamo accedere soltanto a 256 indirizzi di memoria, perciò
è fondamentale che la tabella non si trovi "a cavallo" tra due pagine di, appunto, 256 word.
Lo stesso accorgimento dev'essere fatto nel caso di istruzioni di salto, dove però l'indirizzo è espresso nell'opcode
con 11 bit, perciò vengono utilizzati solo i bit 3 e 4 di PCLATH; in questo caso le pagine sono di 2048 word.

A differenza di PCL, il quale accede direttamente al PC, il registro PCLATH non modifica direttamente
il contatore e non è mai scritto dal micro; viene copiato nel PC soltanto quando PCL viene modificato direttamente o indirettamente.


Scrittura diretta di PCL (movwf, addwf, ecc.)

Scrittura indiretta di PCL (call, goto)

Struttura Switch
Sfruttando lo stesso principio delle tabelle dati, possiamo realizzare delle strutture di questo tipo:

switch(w) {
	case 0 : caso0();
	         break;
	case 1 : case1();
	         break;
	case ... ;
}

semplicemente sostituendo ai retlw dei goto:

Tabella
	addwf	PCL,F
	goto	case0
	goto	case1
	....
break

.... ....

caso0 .... goto break caso1 .... goto break caso.. .... ....

dove il break costituisce la fine della struttura (la parte in rosso è codice al di fuori della struttura).
Questo spezzone può essere inserito all'interno del codice, senza l'utilizzo di call; se però la struttura
viene impiegata in più parti del programma, sarebbe bene utilizzare una chiamata, quindi sostituire i goto break
con dei return.

Questo circuito simula il comportamento di un normale decoder per display a 7 segmenti a catodo comune.
Mettendo in ingresso un numero binario di 4 bit (PORTA), si può visualizzarne il valore tramite un display
connesso alla PORTB. Nel collegare il display, si tenga conto che RB0 è il segmento "a" ed in ordine gli altri
fino al segmento "g" in RB6.
Per avere un decoder che funzioni su un display ad anodo comune, è sufficiente invertire tutti gli uni e gli zeri che compaiono
in tabella.

	include	"P16F84A.INC"
	RADIX	DEC

	ORG	0x00

	bsf	STATUS,RP0
	clrf	TRISB
	movlw	0xFF
	movwf	TRISA
	bcf	STATUS,RP0

Main
	movf	PORTA,W
	call	Tabella
	movwf	PORTB

	goto	Main

Tabella
	addwf	PCL,F
		; gfedcba
	retlw	B'0111111'	; 0
	retlw	B'0000110'	; 1
	retlw	B'1011011'	; 2
	retlw	B'1001111'	; 3
	retlw	B'1100110'	; 4
	retlw	B'1101101'	; 5
	retlw	B'1111101'	; 6
	retlw	B'0000111'	; 7
	retlw	B'1111111'	; 8
	retlw	B'1101111'	; 9
	retlw	B'0110111'	; A
	retlw	B'1111100'	; b
	retlw	B'0111001'	; C
	retlw	B'1011110'	; d
	retlw	B'1111001'	; E
	retlw	B'1110001'	; F

	END

Normalmente, per scrivere in un registro usiamo l'istruzione:

	movwf	0x0C

questo si chiama indirizzamento diretto perchè l'indirizzo a cui ci riferiamo è espresso
direttamente nell'istruzione; esiste, però, un altro metodo di accesso alla RAM, chiamato
"indirizzamento indiretto": questo fa uso di due registri, ovvero FSR e INDF.
Nel primo viene specificato l'indirizzo al quale si vuole accedere; il secondo, invece, non è un vero
e proprio registro, perchè fisicamente non è implementato, ma serve per leggere o scrivere nella locazione di
memoria specificata in FSR.

Vediamo un esempio di come scrivere 0xA3 nel registro 0x0C con entrambi i metodi:

	;Indirizzamento Diretto
	movlw	0xA3
	movwf	0x0C
	
	
	;Indirizzamento Indiretto
	movlw	0x0C
	movwf	FSR
	movlw	0xA3
	movwf	INDF

Per un'operazione così banale si ricorre, ovviamente, all'indirizzamento diretto, ma ci sono
situazioni nelle quali l'indirizzamento indiretto è l'unica soluzione.

Array
Una semplice applicazione dell'indirizzamento indiretto, è quello di creare un array di variabili nella
memoria RAM:


Array è una costante e corrisponde all'indirizzo del primo elemento dell'array (in questo caso 0x0C);
aggiungendo poi a questa costante, l'indice dell'elemento che desideriamo, otteniamo il suo indirizzo.
Detto questo, la procedura per leggere/scrivere un elemento dell'array è il seguente:
- w = indice; l'indice deve essere >= 0;
- aggiungere w all'indirizzo dell'array e mettere il risultato in FSR;
- leggere/scrivere l'elemento attraverso INDF;

Per concludere ecco il codice:

Dato	EQU	0x0C
Array	EQU	0x0D	; indirizzo base dell'array

Esempio
	; esegue array[5] = array[2] + 7
	movlw	2
	call	LeggiArray
	movlw	7
	addwf	Dato,F
	movlw	5
	call	ScriviArray

LeggiArray		; funzione per leggere Array[w]
	addlw	Array
	movwf	FSR
	movf	INDF,W
	movwf	Dato
	return
	
ScriviArray	; funzione per scrivere in Array[w]
	addlw	Array
	movwf	FSR
	movf	Dato,W
	movwf	INDF
	return

Alcuni PIC, come il nostro 16F84A, contengono una memoria EEPROM supplementare, la quale ci permette
di salvare dei dati in modo permanente, che non vanno quindi persi quando si toglie l'alimtentazione.
Tale memoria può essere letta o scritta sia in fase di programmazione, sia dal PIC stesso; nel 16F84A è di 64 byte
e per accedervi si usano i quattro registri EEDATA, EEADR, EECON1 ed EECON2.
E' bene tenere a mente che questi quattro registri si trovano in due banchi diversi: i primi due nel banco 0, gli altri due nel banco 1.

EECON1


EEIF : indica che la scrittura della EEPROM è avvenuta (per interrupt); resettato dal software
WRERR : settato quando si è verificato un errore durante la scrittura
WREN : settato per abilitare la scrittura nella EEPROM
WR : inizia la scrittura; resettato dall'hardware
RD : inizia la lettura; resettato dall'hardware

Leggere la EEPROM
Leggere un dato dalla memoria EEPROM è molto semplice: innanzi tutto si scrive l'indirizzo a cui accedere
in EEADR, successivamente si setta il bit RD (EECON1[0]) ed il dato è già disponibile in EEDATA:

	; mette in W il contenuto dell'indirizzo 0x1E
	movlw	0x1E
	movwf	EEADR
	bsf	STATUS,RP0	; banco 1
	bsf	EECON1,RD
	bcf	STATUS,RP0	; banco 0
	movf	EEDATA,W

Scrivere nella EEPROM
La scrittura della EEPROM è un'operazione un po' più complessa, infatti è presente un sistema di protezione
contro le scritture accidentali.
Il registro EECON2 in realtà non è un registro, viene soltanto impiegato per verificare che la scrittura non sia accidentale;
in particolare bisogna seguire un'essatta sequenza:
- mettere il dato in EEDATA
- scrivere l'indirizzo in EEADR
(queste due operazioni possono essere fatte in un qualunque momento)
- settare il bit WREN
- scrivere 0x55 in EECON2
- scrivere 0xAA in EECON2
- settare il bit WR per iniziare la scrittura
Inoltre la scrittura impiega più cicli istruzione, perciò prima di iniziare una nuova scrittura è indispensabile
controllare che il bit WR sia stato resettato dall'hardware.

	; esempio : scrive 0x3A all'indirizzo 0x10
	movlw	0x3A
	movwf	EEDATA
	movlw	0x10
	movwf	EEADR
	bsf	STATUS,RP0
	bsf	EECON1,WREN
	movlw	0x55
	movwf	EECON2
	movlw	0xAA
	movwf	EECON2
	bsf	EECON1,WR
	bcf	STATUS,RP0

Gli interrupt (o interruzioni) sono un'importante carratteristica dei microprocessori
che permettono la gestione degli eventi esterni.
Un evento può essere moltissime cose, come la pressione di un tasto, la fine di una trasmissione, il cambiamento di
stato di una linea, ecc.; per ricollegarci alla lezione precedente, un evento potrebbe essere
l'avvenuta scrittura della EEPROM.
Normalmente per verificare, ad esempio, il cambiamento di stato di un ingresso (cioè il passaggio da 1 a 0 o viceversa)
dovremmo continuamente controllare quell'ingresso, aspettando che cambi; con le interruzioni, invece, possiamo
eseguire altre operazioni e sarà il PIC a segnalarci che lo stato della linea è cambiato.
Gli interrupt gestibili dal PIC16F84A sono :
- fronte di salita o discesa sul pin RB0
- cambiamento di stato sui pin RB4-RB7
- overflow del timer TMR0 (nella prossima lezione)
- scrittura avvenuta della EEPROM

Interrupt Vector
La routine che gestisce gli interrupt (Interrupt Handler) deve trovarsi all'indirizzo 0x04 (Interrupt Vector), perciò generalmente si usa questo codice:

	ORG	0x00

	goto	Start
	
	ORG	0x04
	; istruzioni di gestione interrupt
	....
	....
	retfie
	
Start
	; inizio programma
	....
	.... 

Il registro INTCON
Il registro che gestisce gli interrupt è INTCON, al suo interno sono presenti i bit di abilitazione delle varie fonti
di interruzione e relativi flag.


GIE : abilitazione generale degli interrupt
EEIE : abilita l'interrupt sulla scrittura completata della EEPROM
T0IE : abilita l'interrupt sull'overflow del TMR0
INTE : abilita l'interrupt sul fronte di salita/discesa del pin RB0
RBIE : abilita l'interrupt sul cambiamento di stato dei pin RB4-RB7
T0IF : indica se l'interrupt è dovuto al T0IE
INTF : indica se l'interrupt è dovuto all' INTE
RBIF : indica se l'interrupt è dovuto all' RBIF

Per utilizzare uno o più interrupt bisogna settare il bit GIE e settare i bit di abilitazione degli interrupt
che ci interessa utilizzare.
Quando si verifica una condizione tale da far scattare un'interruzione, il bit GIE viene automaticamente resettato
e viene effettuato il salto all'Interrupt Vector; la routine di gestione è la stessa per tutte le interruzioni
(cioè si trova sempre e solo all'indirizzo 0x04) perciò se sono abilitati più tipi di interruzioni, bisogna controllare
i flag per sapere di quale si tratta.
Il Flag della EEPROM risiede come visto nel registro EECON1.
Finito l'Interrupt Handling si può tornare al programma attraverso l'istruzione retfie che, inoltre, riabilita gli interrupt settando il bit
GIE.
Prima di chiamare questa istruzione, bisogna resettare i flag in modo da permettere all'interruzione di verificarsi nuovamente.

Interrupt su RB0
Questo interrupt permette di "catturare" un fronte di salita o discesa sul piedino RB0; per scegliere quale fronte
è sufficiente agire sul bit INTEDG del registro OPTION (OPTION_REG[6]):
- se 1 : fronte di salita
- se 0 : fronte di discesa

Vediamo ora un esempio completo di come usare un'interruzione per accendere un led alla pressione di un tasto NA, e poi
spegnerlo con un'altra pressione.
Ne approfitto per segnalare la possibilità di abilitare delle resistenze di pull-up interne;
basta resettare il bit NOT_RBPU del registro OPTION (OPTION_REG[7]) per avere un pull-up per ogni pin settato come ingresso della Porta B;
questo ci consente di collegare facilmente dei pulsanti al PIC senza componenti aggiuntivi.

	include	"P16F84A.INC"

	ORG	0x00

	goto	Start

	ORG	0x04

	comf	PORTB,F		; inverte lo stato del LED
	bcf	INTCON,INTF	; resetta il flag dell'interrupt
	retfie

Start

	bsf	STATUS,RP0	; banco 1
	movlw	B'11111101'	; RB0 ingresso, RB1 uscita
	movwf	TRISB
	bcf	OPTION_REG,NOT_RBPU ; attiva pull-up
	bcf	OPTION_REG,INTEDG ; fronte di discesa
	bcf	STATUS,RP0	; banco 0

	bsf	INTCON,INTE	; attiva interrupt su RB0
	bsf	INTCON,GIE	; abilita gli interrupt

Main
	goto	Main

	END
Se il pulsante non è anti-rimbalzo, il LED potrebbe accendersi o spegnersi in modo anomalo;
per ovviare tale problema si protrebbe introdurre un ritardo di qualche millisecondo prima di
uscire dall'Interrupt Handler.

Interrupt su RB4-RB7
In questo caso, l'interruzione viene generata ad ogni cambiamento di stato (sia fronte di salita che discesa)
su uno dei pin RB4-RB7; il flag settato è lo stesso per tutti i 4 pin, perciò è compito del programmatore verificare
quale sia il cambiamento avvenuto.

Preservare Status e W
Un interrupt può interrompere il programma principale in qualunque momento, per questo motivo la routine
di gestione delle interruzioni non deve in alcun modo influire sul comportamento del programma.
Qualunque operazione si effettui all'interno dell'Interrupt Handler, va inevitabilmente a modificare i
registri W e STATUS, perciò se questi vengono in qualche modo utilizzati nel software principale, risulta necessario
preservarne il contenuto:

	ORG	0x04
	movwf	W_TEMP
	swapf	STATUS, W
	movwf	STATUS_TEMP
	....
	....
	swapf	STATUS_TEMP, W
	movwf	STATUS
	swapf	W_TEMP, F
	swapf	W_TEMP, W
	retfie
In questo snippet viene impiegata l'istruzione swapf perchè non influenza lo STATUS

Sleep
Spesso il PIC si trova in situazioni nelle quali non deve fare nulla, se non attendere un evento esterno; per
questo motivo è stato progettato un sistema di risparmio d'energia che limita il consumo di corrente fino a qualche uA.
Per attivarlo è sufficiente usare l'istruzione sleep che manda il micro in stand-by.
Il PIC può esserere "risvegliato" con uno di questi eventi:
- Reset tramite il pin MCRL'
- Timeout del WDT
- Interrupt su RB0, RB4-RB7 o fine scrittura della EEPROM

Durante lo sleep le periferiche interne vengono disattivate.
Se il risveglio (wake-up) è causato da un interrupt, subito viene eseguita l'istruzione che segue sleep, e solo
poi si passa all'Interrupt Handler; se questa condizione è indesiderata, è sufficiente inserire dopo sleep un nop.

Scarica subito una copia gratis

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend