Esistono poi le macro che non sono altro che degli insiemi di istruzioni,
anche esse concorrono fortemente all'incremento dell'astrazione.
................
read macro
; in questo caso non passiamo parametri
In questo caso innvocando la macro read dal programma principale vengono
eseguite tutte le istruzione in essa contenute. La macro e' riusabile lungo tutta la
durata del programma.
Dentro ad una macro e' possibile definire delle label ad uso locale per la funzionalita'
della macro. Una macro puo' inoltre restituire un risultato in uscita, per fare questo,
all'interno della macro, il risultato andra' caricato in un registro il quale verra' poi
letto dal programma principale.
write macro data
; passiamo il parametro data, che puo' essere
una costante o anche un registro
Vediamo ora una macro che puo' configurare i bit di porta in input o in
output, a seconda di come sono i corrispondenti bit del parametro IN_OUT, dinamicamente
lugno il programma.
............
..........
.........
.........
La potenzialita' della macro rispetto alla subroutine sta nel fatto che
alla macro e' possibile passare dei parametri.
IN_DEC macro data, rout, adr ;
rout e' il nome di una subroutine !!!!!!
local salta
; salta viene vista solo dentro la macro, e' una label locale
goto salta
; salta dentro la macro a salta
goto adr
; salta alla label adr del prg principale
................
................
...............
............
...........
...........
............
...........
Nel Pic16F84 le sorgenti di interrupt possono essere 4, di queste 2 sono
esterne e 2 interne.
Interrupt esterno generato da lcambiamento di stato della linea RB0/INT o sul fronte di
discesa o sul fronte di salita. La scelta del tipo di fronte viene effettuata andando ad
agire sul bit 6 INTEDG dell' OPTION_REG.
Interrupt esterno associato al cambiamento di stato di uno dei pin
RB4, RB5, Rb6 e RB7. Queste linee devono tutte essere state definite come input.
Interrupt interno : overflow di TMR), ogni volta che esso passa da ffH a
00H.
Interrupt interno : ciclo di scrittura completo du EEPROM.
Quando viene effettuata una INTR (Interrupt Request) da qualsiasi dei
4 casi precedenti il Program Counter (PC) viene caricato con l'indirizzo 04H al quale si
trova la routine di gestione dell'interrupt. La gestione dell'area di Stack e' automatica,
non vi e' bisogno di fare PUSH in entrata e POP in uscita. Viene automaticamente caricato
nell'area di Stack l'indirizzo di ritorno dall'interrupt al main. Abbiamo a
discposizione un registro apposito per la gestione degli interrupt denominato INTCON. Esso
e' costituito da alcuni bit di controllo dell'abilitazione del tipo di interrrupt e di
alcuni Flag di controllo. I flag sono :
TOIF : si porta a 1 ogni volta che TMR0 va in overflow, indica un
intr proveniente da TMR0
INTF : si porta a 1 quando avviene un intr su RB0/INT anche se
l'interrupt in questione non e' stato abilitato
RBIF : si porta a 1 quando avviene un intr su una delle linee da RB4
a RB7
Invece i segnali di controllo delle abilitazioni sono :
GIE : consente o meno di abilitare i vari interrupt (usato per
mascherare tutti gli interrupt)
TOIE : abilita l'intr su TMR0
INTE : abilita l'intr su RB0/INT
RBIE : abilita l'intr su RB4--RB7
EEIE : abilita l'intr su termine scrittura completa in EEPROM
Il flag EEIF non e' compreso in questoregistro ma si trova nel registro
EEICON1.
I flag servono perche' ad ogni intr, se GIE e' abilitato, il PC viene
caricato con 04h, a questo punto ho bisogno di sapere chi mi ha rischiesto l'intr
altrimenti non so come comportarmi. Ecco l'importanza di avere dei flag da interrogare per
sapere quale sorgente fra le 4 a disposizione ha richiesto l'interrupt. Posso avere la
necessita' di dover mascherare solo alcuni tipi di interrupt, per questo agiro' sui bit di
controllo TOIE, INTE, RBIE, EEIE.
Appena il PC salta a 04h automaticamente GIE viene reserrato per
mascherare, ad eventuali ulteriori intr, la routine di gestione dell'intr appena ricevuto.
Quando si esce dalla routine bisogna assolutamente resettare il flag della sorgente di
interrupt che mi ha fatto l'intr. Questo perche' diversamente, al ritorno al main, con il
settaggio automatio di GIE, e quindi trovando ancora quel flag alzato il PC verrebbe
nuovamente ricaricato con il vettore 04H e si formerebbe un loop fra il main e la routine
dell'interrupt.
Posso avere la necessita', una volta che sto gia' gestendo un primo
intr e quindi una volta che sono dentro alla routine di gestione, di dover gestire altri
interrupt provenienti da sorgenti diverse. A questo punto appena entrato nella routine di
gestione devo settare GIE che era stato automaticamente resettato. Poi, nel caso arrivasee
un nuovo intr, il PC punterrebbe nuovamente a 04H dove ci dovra' essere una routine di
riconoscimento della sorgente di generazione dell'interrupt ed un conseguente salto alla
relativa subroutine Si possono annidare fino a 8 intr.
Quando si entra in una routine di gestione di interrupt occorre :
salvare W
salvare STATUS
gestire l'interrupt
resettare il flag della sorgente di intr
ripristinare STATUS
ripristinare W
retfie
Dall'intr al momento in cui effettivamente il PC passa a 04H trascorrono
circa 3-4 cicli macchina per le intr esterne e 2 cicli macchina per le intr interne.
Dallo stato di sleep ci si esce solo con un interrupt o con un reset.
Per sapere effettivamente quale delle linee RB4--RB7 ha richiesto l'inter occorre
tenre in memoria uno storico dello stato di portb e fare un contronto fra il portb attuale
e quello precedente ogni volta che si trova il flag RBIF a 1.
*****************************************************************
Lettura e scrittura su EEPROM
Il PIC16F84 ha una EEPROM di 64 byte, da 00h a 3fh) che puo' essere utilizzata in
operazioni di lettura e scrittura durante il funzionamento del programma. Per utilizzare
la E2PROM devono essere utilizzati quattro registri specifici :
EECON1 bank1
EECON2 bank1
EEADR bank0
EEDATA bank0
Il registro EEDATA contiene il dato da scrivere o appena letto dalla EEPROM, in lettura
il dato verra' trasferito dalla memoria a EEDATA, in scirttura da EEDATA alla memoria.
Per quanto rigurda la lettura si tratta di una operazione semplice e veloce, la scrittura
invece e' piu' complessa e meno veloce.
Il ritardo e' dovuto al fatto che prima di scrivere effettivamente in EEPROM il pic
cancella quella locazione per evitare eventuali errori. Lettura e scrittura avvengono per
indirizzamento indiretto.
Il registro EEADR viene utilizzato per l'indirizzamento indiretto dell'area EEPROM, e' un
registro a 8 bit ma di questi ne vengono utilizzati solo 6 per il fatto che 64 byte sono
indirizzabili da 6 bit. (64 = 2^6). Occorrera' quindi prestare la massima attenzione
quando si scrive un byte in questo registro, i due bit piu' significativi andranno quindi
resettati.
EECON1 e' il vero e proprio resgistro di controllo delle operazioni di lettura e di
scrittura sulla e2prom. Vediamo come e' strutturato :
- - -
EEIF WERR WREN WR
RD
7 6 5
4
3
2
1
0
Il bit RD posto ad 1 abilita la lettura della locazione e2prom puntata da EEADR, alla
fine della lettura viene automaticamente resettato dal pic.
Per quanto rigurda la scrittura in e2prom c'e' bisogno di agire su 2 bit , WREN e WR. WREN
deve essere posto ad 1 per abilitare la scrittura, pero' al fine di evitare scritture
accidentali, per dare il via alla scrittura vera e propria bisogna settare anche il bit
WR. WR poi resetta automaticamente alla fine del ciclo di scrittura, WREN no, andra'
resettato via software.
Il bit WERR ad 0 ci indica che la scrittura non e' avvenuta correttamente, se e' ad 1 c'e'
stato qualche problema. Ovviamente dovrermo essere noi a gestire via software questa
eventuaita'. Un caso di errore puo' essere che mentre si scrive in e2prom avviene un reset
del pic oppure un reset generato dal watchdog. Siccome in caso di errore EEADR e EEDATA
non vengono modificati, si potra' procedere alla riscrittura della loicazione interessata.
EEIF e' il flag di interrupt di fine scrittura, esso va resettato da programma alla fine
del ciclo.
EECON2 non e' un registro vero e proprio ed e' utilizzato solo nelle fasi di scrittura
della e2prom.
Vediamo ora alcuni esempi :
esempio 1 : lettura di un byte dall locazione e2prom 10h
bcf STATUS,RP0 ;bank0 (e2data e2adr)
movlw 10h
;
movwf EEADR ;10h in EEADR
bsf STATUS,RP0 ;bank1 (e2con1)
bsf EECON1,RD ;abilita la lettura
bcf STATUS,RP0 ;bank0
movwf EEDATA,W ;in W il dato letto da 10h
esempio 2 : scrittura del contenuto di porta in 10h e2prom
bcf INTCON,GIE ;disabilita ogni interrupt
bcf STATUS,RP0 ;bank0
movf PORTA,W
movwf EEDATA ;PORTA in EEDATA
movlw 10h
movwf EEADR
bsf STATUS,RP1 ;bank1
bsf EECON1,WREN ;scrittura abilitata
movlw 55h
; operazioni fisse
movwf EECON2 ;
"
movlw aah
; "
movwf EECON2 ;
"
bsf EECON1,WR ;inizio scrittura
LOOP
btfsc EECON1,WR
goto LOOP
;attende che WR torni a 0 (fine scrittura)
bcf EECON1,WREN ;disabilita scrittura
bcf EECON1,EEIF ;disabilita flag di
interrupt, operazione fondamentale se non mi interessa gestire EEIF ma ho altri tipi di
interrupt da gestire
bsf INTCON,GIE ;riabilita gli
interrupt
esempio 3 : scrittura in 10h e2prom di PORTA e controllo del dato scitto con gestione
di EEIF
FLAG equ 0ch
S_DATO equ 0dh
bcf STATUS,RP0 ;
bank0
bsf FLAG,1
; flag=0 scrittuara termintata, =1 no
movlw 10h
movwf EEADR
movf PORTA
movwf EEDATA
movwf S_DATO ;una copia
del dato in S_DATO per il successivo confronto.
bsf STATUS,RP0
bcf INTCON,GIE
bsf EECON1,WREN
movlw 55h
movwf EECON2
movlw aah
movwf EECON2
bsf EECON,WR
bsf INTCON,GIE
...............................................................................
routine di gestione dell'interrupt da EEIF
org 04h
salva STATUS e W
bsf STATUS,RP0
bcf EECON1,EEIF
bcf FLAG,1 ;scrittura
terminata
ripristina STATUE e W
retfie
................................................................................
WAIT
btfsc FLAG,1 ; attende che la routine di intr, cioe'
la scittura, sia terminata
goto WAIT
bsf FLAG,0 ;1 lettura
ok, 0 non ok
call lettura
movwf EEDATA,W
xorwf S_DATO,W ;confronto
btfss STATUS,Z
goto ERRORE!!!
.....................
.....................
; OK