Microcontrollori PIC

Transcript

Microcontrollori PIC
Microcontrollori PIC
Teoria, Esperimenti, Esercizi
HARDWARE DEL PIC
SOFTWARE DEL PIC
MPLAB
MEMORIA
PORTE-IO
TIMER
DISPLAY
AUDIO
ADC
INTERRUPT
EEPROM
HARDWARE DEL PIC
Il PIC16F684 (PIC=Peripheral Interface Controller=Controllore di interfaccia periferica) è un microcontrollore
RISC (Reduced Instruction Set Computer = Computer con Set di Istruzioni Ridotto) con un set di sole 35
istruzioni. La sua memoria programma è separata dalla memoria dati, che ha estensione 8 bit. Questa
separazione permette l’utilizzo di una memoria programma con word a 14 bit. Grazie a ciò tutte le istruzioni
sono codificate con una sola word e quindi vengono eseguite in un solo ciclo. Di conseguenza le dimensioni dei
programmi risultano ridotte e la velocità esaltata rispetto ad altre famiglie di microchip.
Il contenitore ha 14 pin:
VDD
1
14
VSS
RA5/T1CKI/OSC1/CLKIN
2
13
RA0/AN0/C1IN+/ICSPDAT/ULPWU
RA4/AN3/T1G/OSC2/CLKOUT
3
12
RA1/AN1/C1IN-/VREF/ICSPCLK
RA3/MCLR/VPP
4
11
RA2/AN2/T0CKI/INT/C1OUT
RC5/CCP1/P1A
RC4/C2OUT/P1B
5
10
RC0/AN4/C2IN+
6
9
RC1/AN5/C2IN-
RC3/AN7/P1C
7
8
RC2/AN6/P1D
Il significato dei pin è descritto nella seguente tabella:
NOME
FUNZIONE
DESCRIZIONE
NOME
VDD
VDD
RA5/T1CKI/
OSC1/CLKIN
RA5
Alimentazione
Porta I/O con pull-up
programmabile e interrupt per
transizione
clock Timer 1
oscillatore al quarzo
ingresso clock esterno,
connessione oscillatore RC
Porta I/O con pull-up
programmabile e interrupt per
transizione
VSS
RA0/AN0/C1IN+/I
CSPDAT
/ULPWU
T1CKI
OSC1
CLKIN
RA4/AN3/T1G/
OSC2/CLKOUT
RA4
FUNZIONE
VSS
C1IN+
massa
Porta I/O con pull-up
programmabile e interrupt per
transizione
input canale 0 A/D
ingresso comparatore 1
ICSPDAT
I/O dati programmazione seriale
ULPWU
input potenza ultra-bassa wakeup
RA0
AN0
RA1/AN1/C1IN/VREF/ICSPCLK
RA1
AN3
input canale 3 A/D
T1G
OSC2
porta Timer 1
oscillatore al quarzo
AN1
C1IN-
CLKOUT
uscita fOSC/4
VREF
RA3
input PortA con interrupt per
transizione
ICSPCLK
MCLR
clear principale con pull-up interno
VPP
RC5
CCP1
P1A
tensione di programmazione
I/O PORTC
ingresso cattura/uscita confronto
uscita PWM
RC4/C2OUT/
P1B
RC4
I/O PORTC
RC3/AN7/P1C
C2OUT
P1B
RC3
AN7
P1C
uscita comparatore 2
uscita PWM
I/O PORTC
input canale 7 A/D
uscita PWM
RA3/MCLR/VPP
RC5/CCP1/P1A
RA2/AN2/T0CKI/I
NT/C1OUT
RC0/AN4/C2IN+
RC1/AN5/C2IN-
RC2/AN6/P1D
DESCRIZIONE
Porta I/O con pull-up
programmabile e interrupt per
transizione
input canale 1 A/D
input comparatore 1
tensione di riderimento estena
A/D
clock programmazione seriale
AN2
T0CKI
INT
C1OUT
Porta I/O con pull-up
programmabile e interrupt per
transizione
input canale 2 A/D
input clock Timer 0
interrupt esterno
output comparatore 1
RC0
I/O PORTC
AN4
C2IN+
RC1
AN5
C2INRC2
input canale 4 A/D
input comparatore 2
I/O PORTC
input canale 5 A/D
input comparatore 2
I/O PORTC
input canale 6 A/D
uscita PWM
RA2
AN6
P1D
Si riporta di seguito lo schema a blocchi, con indicazione dei pin.
La CPU (Central Processing Unit = Unità Centrale di Elaborazione) è il cervello del microcontrollore, riceve le
istruzioni dalla memoria flash, attraverso il Bus Programma. Le istruzioni sono selezionate dal Program Counter
PC.
La CPU decodifica l’istruzione, ovvero interpreta il suo significato e impartisce i comandi per eseguirla.
In questo compito è supportata dal registro Accumulatore WREG, centro nevralgico per la circolazione dei dati e
dalla ALU (Arithmetic and Logic Unit = Unità Aritmetico Logica), centralina di calcolo matematico.
1
La RAM contiene i File Registers (Registri Archivio), che conservano l’”impronta” del sistema. Se la CPU è il
cervello del sistema, i fili register ne sono il cuore. I file register di tipo “core” contengono informazioni che
disciplinano il comportamento del sistema nel suo insieme. I file register di tipo “periferica” mantengono
memorizzate le informazioni di configurazione delle periferiche.
Questi registri sono volatili, quindi vengono programmati di volta in volta. I dati di configurazione delle
periferiche sono trasmessi attraverso il Bus Dati, così come i dati utili manipolati.
I dati da conservare possono essere salvati sulla EEPROM.
Non esiste un vero e proprio Bus Indirizzi. La RAM riceve l’indirizzo di registro dalla CPU e la Flash dal PC. La
EEPROM riceve l’indirizzo dal bus dati e lo salva entro un registro dedicato, prima di ricevere il dato.
Come tradizione la CPU gestisce l’istruzione di programma in due fasi: la fase di Fetch e quella di Execute.
Nella fase di fetch avviene il prelievo dell’istruzione dalla memoria (fetch=ricerca), in quella di execute ha luogo
l’esecuzione vera e propria del comando impartito dall’istruzione. Nel PIC è possibile una parziale
sovrapposizione delle due fasi (Pipeline), con risparmio di tempo e conseguente aumento della velocità. Grazie
alla separazione tra Bus Programma e Bus Dati, mentre è ancora in corso l’esecuzione, la quale coinvolge il
bus dati, la CPU può iniziare la lettura dell’istruzione successiva, che coinvolge il bus programma.
14
OSC1/CLKIN
OSC2/CLKOUT
Bus Programma
CPU
13
PC
flash
2K14
memoria
programma
INT
RAM
128 bytes
file registers
T0CKI
T1CKI
T1G
CCP1/P1A
P1B
P1C
P1D
C1INC1IN+
C1OUT
C2INC2IN+
C2OUT
Timer 0
Timer 1
Timer 2
ECCP
EEPROM
256 bytes
dati
B
U
S
PORTA
D
A
T
I
PORTC
2 comparatori
analogici e
riferimento
Cat / Comp / PWM
Progr Seriale IC
8
Convertitore
Analogico
Digitale
RA0
RA1
RA2
RA3
RA4
RA5
RC0
RC1
RC2
RC3
RC4
RC5
AN0
AN1
AN2
AN3
AN4
AN5
AN6
AN7
VREF
Il chip incorpora le seguenti periferiche:
•
Due porte di I/O per un totale di 12 pin con controllo individuale della direzione del dato.
Le porte assicurano connessioni fisiche tra microprocessore e dispositivi esterni ad esso.
Entrambe le porte dispongono di 6 terminali digitali, nella PORTC sono tutti bidirezionali, nella PORTA il
terminale RA3 è solo di input.
•
Timer0, Timer1 e Timer2 per la generazione di intervalli temporali. Il timer è un dispositivo basato su un
registro contatore. Ad ogni quarto di periodo del clock esso incrementa il suo valore. La misurazione del
contenuto del registro riflette allora una misutazione temporale utile in molte applicazioni.
•
Convertitore Analogico Digitale A/D di risoluzione 10 bit a 8 canali di input per il dato analogico.
Consente di tradurre segnali presenti sugli input analogici in formato digitale, adeguato all’elaborazione
matematica.
•
Modulo con comparatori analogici. Contiene due comparatori analogici a due ingressi e una tensione
nota di riferimento. Un comparatore stabilisce un confronto tra due segnali di tipo analogico, fornendo in
uscita livello alto o basso, come risultato del confronto.
•
Modulo Cattura, Compara, PWM
Fornisce su quattro uscite impulsi digitali con periodo e duty cycle stabiliti programmaticamente (PWM =
Pulse Width Modulation = Modulazione della Durata di Impulso).
•
Programmazione seriale In-Circuit per la scrittura del programma con il chip nel circuito finale
2
Il PIC16F684 dispone di tre memorie:
•
•
•
memoria di Programma
memoria Register File
memoria EEPROM
MEMORIA EEPROM
byte 0
byte 1
byte 2
00h
01h
10h
byte 254
byte 255
FEh
FFh
MEMORIA DI PROGRAMMA
PC<12:0>
MEMORIA REGISTER FILE
Livello 1 Stack
Livello 2 Stack
.
.
Livello 8 Stack
Vettore di Reset
0000h
indirizz indiretto
TMR0
PCL
STATUS
FSR
PORTA
PORTC
Vettore di Interrupt
0004h
0005h
Memoria
programma
07FFh
0800h
1FFF
• Organizzazione memoria di programma
La memoria di programma è di tipo flash, una
memoria non volatile programmabile e
cancellabile elettricamente fino a 100000 volte.
Nella memoria di programma viene riversato, al
momento della programmazione, il codice
macchina a 14 bit.
Il PIC dispone di un Program Counter PC<12:0>
di 13bit, in grado di scandire una istruzione dopo
l’altra, puntando di volta in volta alla istruzione da
eseguire.
Il PC è virtualmente in grado di indirizzare
13
2 =4098byte=4k, dall’indirizzo 0000h all’indirizzo
1FFFh. Tuttavia, di questi, solo i primi 2k, da
0000h a 07FFh sono implementati.
All’indirizzo 0000h è collocato il vettore di reset. A
questa locazione si dispone il PC al momento del
reset; da qui inizia l’esecuzione del programma.
L’indirizzo 0004h è riservato ai vettori di interrupt
(vedi capitolo). E’ necessario mantenere vuoto
questo spazio e collocare la prima istruzione del
programma all’indirizzo 005h.
PCLATH
INTCON
PIR1
TMR1L
TMR1H
T1CON
TMR2
T2CON
CCPR1L
CCPR1H
CCP1CON
PWM1CON
ECCPAS
WDTCON
CMCON0
CMCON1
ADRESH
ADCON0
00h
01h
02h
03h
04h
05h
06h
07h
08h
09h
0Ah
0Bh
0Ch
0Dh
0Eh
0Fh
10h
11h
12h
13h
14h
15h
16h
17h
18h
19h
1Ah
1Bh
1Ch
1Dh
1Eh
1Fh
20h
indirizz indiretto
OPTION_REG
PCL
STATUS
FSR
TRISA
TRISC
PCLATH
INTCON
PIE1
PCON
OSCCON
OSCTUNE
ANSEL
PR2
WPUA
IOCA
VRCON
EEDAT
EEADR
EECON1
EECON2
ADRESL
ADCON1
General
Purpose
Registers
32 Bytes
80h
81h
82h
83h
84h
85h
86h
87h
88h
89h
8Ah
8Bh
8Ch
8Dh
8Eh
8Fh
90h
91h
92h
93h
94h
95h
96h
97h
98h
99h
9Ah
9Bh
9Ch
9Dh
9Eh
9Fh
A0h
BFh
Registri
uso
Generale
96 Bytes
7Fh
BANCO 0
ACCESSO
70h-7Fh
F0h
FFh
BANCO 1
Per questo si deve far precedere le istruzioni del programma dalla direttiva per il compilatore:
org
0x005
e collocare all’indirizzo 0x000 l’istruzione di salto all’indirizzo 0x005:
org
0x000
goto 0x005
La direttiva org ha il significato di ORiGin (origine) per il programma.
Sono presenti infine 8 livelli di stack (catasta) entro i quali il programma salva (push) l’indirizzo di ritorno da
sottoprogramma e lo ripristina (pop) all’uscita dal sottoprogramma.
3
• Organizzazione memoria Register File
Register File significa Archivio Registri. E’ una memoria di 128 bytes 2 banchi di tipo RAM, quindi veloce ma
volatile, necessaria per registrare, nel corso del programma, i dati di gestione dei dispositivi del microcontrollore
e i dati manipolati dal programma. E’ divisa in due banchi:
banco 0: spazio indirizzi 00h – 7Fh
banco 1: spazio indirizzi 80h – FFh
Entrambi sono selezionati dagli indirizzi base a 7 bit 00 – 7F. L’indirizzo reale si ottiene completando l’indirizzo
base con il contenuto dei bit RP1, RP0 del registro STATUS secondo le combinazioni:
RP1RP0 = 00 selezione banco 0
RP1RP0 = 01 selezione banco 1
I primi 32 byte dei banchi sono Special Function Registers (Registri Funzione Speciale) SFR.
I rimanenti 96 bytes del banco 0 e solo 32 bytes del banco 1 sono General Purpose Registers (Registri di
Impiego Generale) GPR.
Ogni File Register (Registro Archivio) dello spazio SFR controlla il comportamento di uno o più dispostivi del
microcontrollore. Ci sono registri per la gestione del Timer, delle porte di I/O ecc. Questi saranno approfonditi
ognuno in un proprio capitolo.
Ogni registro dello spazio GPR può essere utilizzato liberamente per la registrazione di dati manipolati dal
programma. Qui si possono memorizzare quelle che anche nei linguaggi ad alto livello sono note come
“variabili”.
• Organizzazione memoria EEPROM
La sigla EEPROM è l’acronimo di Electrically Erasable Programmable Read Only Memory (Memoria di sola
Lettura Cancellabile e Programmabile Elettricamente).
E’ una memoria di tipo non volatile, impiegata per la conservazione di dati importanti per il processo gestito dal
microcontrollore. Il suo contenuto permane anche a microcontrollore spento, pertanto può essere programmata
una sola volta. Se necessario comunque è possibile cancellarla e riprogrammarla con opportune istruzioni, che
agiscono elettricamente nei suoi circuiti interni, senza la necessità, come nelle EPROM, di esposizione a raggi
ultravioletti per la cancellazione. La memoria è riprogrammabile 1000000 di volte. Il tempo di conservazione del
dato oltrepassa 40 anni.
4
SOFTWARE DEL PIC
• Set di istruzioni
E’ composto dalle 35 istruzioni qui riportate:
Bit registro
STATUS
influenzati
Codice operativo di 14 bit
Mnemonico,
operandi
Descrizione
Cicli
MSB
LSB
ISTRUZIONI SU FILE REGISTER ORIENTATE AL BYTE
f, d
f, d
f
f, d
f, d
f, d
f, d
f, d
f, d
f, d
f
f, d
f, d
f, d
f, d
f, d
ADDWF
ANDWF
CLRF
CLRW
COMF
DECF
DECFSZ
INCF
INCFSZ
IORWF
MOVF
MOVWF
NOP
RLF
RRF
SUBWF
SWAPF
XORWF
Add W and f
AND W with f
Clear f
Clear W
Complement f
Decrement f
Decrement f, Skip if 0
Increment f
Increment f, Skip if 0
Inclusive OR W with f
Move f
Move W to f
No Operazione
Rotate Left f through Carry
Rotate Right f through Carry
Subtract W from f
Swap nibbles in f
Exclusive OR W with f
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
1
1
1
1
1
1
1(2)
1
1(2)
1
1
1
1
1
1
1
1
1
0111
0101
0001
0001
1001
0011
1011
1010
1111
0100
1000
0000
0000
1101
1100
0010
1110
0110
dfff
dfff
lfff
0xxx
dfff
dfff
dfff
dfff
dfff
dfff
dfff
lfff
0xx0
dfff
dfff
dfff
dfff
dfff
ffff
ffff
ffff
xxxx
ffff
ffff
ffff
ffff
ffff
ffff
ffff
ffff
0000
ffff
ffff
ffff
ffff
ffff
C, DC, Z
Z
Z
Z
Z
Z
Z
Z
Z
C
C
C, DC, Z
Z
ISTRUZIONI SU FILE REGISTER ORIENTATE AL BIT
f, b
f, b
f, b
f, b
BCF
BSF
BTFSC
BTFSS
Bit Clear f
Bit Set f
Bit Test f, Skip if Clear
Bit Test f, Skip if Set
01
01
01
01
1
1
1 (2)
1 (2)
00bb
01bb
10bb
11bb
bfff
bfff
bfff
bfff
ffff
ffff
ffff
ffff
ISTRUZIONI CON LETTERALI E OPERAZIONI DI CONTROLLO
ADDLW
ANDLW
CALL
CLRWDT
GOTO
IORLW
MOVLW
RETFIE
RETLW
RETURN
SLEEP
SUBLW
XORLW
•
k
k
k
k
k
k
k
k
k
Add literal and W
AND literal with W
Call subroutine
Clear Watchdog Timer
Go to address
Inclusive OR literal with W
Move literal to W
Return from interrupt
Return with literal in W
Return from Subroutine
Go into Standby mode
Subtract W from literal
Exclusive OR literal with W
1
1
2
1
2
1
1
2
2
2
1
1
1
11
11
10
00
10
11
11
00
11
00
00
11
11
111x
1001
0kkk
0000
1kkk
1000
00xx
0000
01xx
0000
0000
110x
1010
kkkk
kkkk
kkkk
0110
kkkk
kkkk
kkkk
0000
kkkk
0000
0110
kkkk
kkkk
kkkk
kkkk
kkkk
0100
kkkk
kkkk
kkkk
1001
kkkk
1000
0011
kkkk
kkkk
C, DC, Z
Z
TO, PD
Z
TO, PD
C, DC, Z
Z
Campi codice operativo
Campo Descrizione
f
indirizzo numerico o simbolico di un registro del register file (da 0x00 a 0x7F)
W
registro accumulatore
b
disposizione del bit entro un file register di 8 bit
k
campo letterale, dato costante o etichetta
d
selezione destinazione risultato;
d=0 destinazione=W; d=1 destinazione= il file register f specificato nell’istruzione
5
Il set di istruzioni del PIC16F684 è suddiviso nelle seguenti categorie:
• istruzioni orientate al byte
• istruzioni orientate al bit
• istruzioni letterali e di controllo
Ogni istruzione, codificata con 14 bit, è ripartita in un campo codice operativo, che specifica il tipo di istruzione
e un campo operando, che specifica ulteriormente il/i dati sui quali l’istruzione opera.
Istruzioni orientate al byte
•
Per le istruzioni orientate al byte, ‘f’ designa il nome di un operando di tipo file register, ‘d’ specifica se la
destinazione del risultato è W (d=0) oppure il file register stesso (d=1).
esempio
movwf f
STATUS
83h
significa “copia il contenuto del registro W entro il registro f ”.
FSR
84h
WREG
Nella specifica istruzione, al posto dell’identificatore
TRISA
85h
3F
generico f, ci sarà il nome di un qualsiasi file register.
86h
Ad esempio, ipotizzando WREG=0x3F, l’istruzione:
TRISC
87h
movwf
TRISA
copia il valore esadecimale 3F entro il registro TRISA.
Si noti una importante caratteristica comune a tutte le istruzioni: gli operandi coinvolti formano parte
dell’istruzione, il sorgente a sinistra e la destinazione a destra.
esempio
incf f,d
Il contenuto del registro ‘f’ viene incrementato. Se ‘d’ è 0 il
+1
ADCON0
1Fh
risultato viene posto nel registro W. Se ’d’ è 1 il risultato
0
viene posto in ‘f’.
20h
Ad esempio, ipotizzando la variabile UNITA inizializzata a 0,
General
21h
Pur pose
l’istruzione:
22h
Registers
incf UNITA,1
incrementa di 1 il valore di UNITA.
Una variabile è un registro utente dello spazio di memoria General Purpose Register. Per accedere a questo
spazio mediante simboli anziché mediante indicazione dell’indirizzo, si deve dichiarare un blocco di variabile
all’inizio del programma. I nomi di variabile vengono associati, nell’ordine di dichiarazione, con i registri a partire
dall’indirizzo indicato. Ad esempio il seguente segmento:
cblock 0x20
UNITA
DECINE
endc
associa la variabile UNITA al registro 20h e la variabile DECINE all’indirizzo 21h.
esempio
xorwf f,d
Il contenuto del registro W è posto in OR esclusivo con il registro ‘f’. Se ‘d’ è 0 il risultato viene posto nel registro
W. Se ’d’ è 1 il risultato viene posto in ‘f’.
L’utilità dell’istruzione risiede nella possibilità di verificare l’uguaglianza di due registri, testando il valore del flag
di zero del registro STATUS. L’operazione infatti influenza il flag di zero in questo modo:
risultato operazione=0 Flag di zero settato Z=1
1
risultato operazione=1 Flag di zero resettato Z=0
Ad esempio, ipotizzando WREG=10, UNITA=10, l’istruzione:
xorwf UNITA,0
IRP RP1 RP0 TO PD Z DC C
imposta Z=1.
Per completezza si riportano di seguito le specifiche del registro STATUS.
STATUS - REGISTRO DI STATO (INDIRIZZO: 03h O 83h)
riservato
riservato
5
4
3
2
1
0
IRP
RP1
RP0
TO
PD
Z
DC
C
bit 7-6
sono riservati e devono essere mantenuti a ‘0’
bit 5
RP0: Register bank select bit (Bit di selezione del banco registri)
1 = Banco 1 (80h – FFh)
0 = Banco 0 (00h – 7Fh)
bit 4
TO: Time Out bit (Bit di Time-out)
è posto a 1 dopo l’accensione o un’istruzione CLRWDT o SLEEP
è posto a 0 quando il Watchdog Timer va in Time-out
6
bit 3
PD: Power Down bit (Bit di Power Down)
è posto a 1 dopo un’istruzione CLRWDT
è posto a 0 all’esecuzione dell’istruzione SLEEP
bit 2
Z: Zero bi (Flag di Zero)
è posto a 1 quando il risultato di una operazione logica o aritmetica è zero
è posto a 0 quando il risultato di una operazione logica o aritmetica è diverso da zero
bit 1
DC: Digital Carry/borrow bit (Bit di Riporto/prestito di una cifra)
è posto a 1 se è presente un riporto dal quarto bit della cifra meno significativa del risultato
è posto a 0 se non è presente un riporto dal quarto bit della cifra meno significativa del risultato
bit 0
C: Carry/borrow bi (Bit di Riporto/prestito)
è posto a 1 se è presente un riporto dal bit più significativo del risultato
è posto a 0 se non è presente un riporto dal bit più significativo del risultato
•
Istruzioni orientate al bit
Per le istruzioni orientate al bit, ‘b’ designa il numero del bit influenzato dall’operazione, mentre ‘f’ rappresenta il
file register nel quale il bit è collocato.
esempio
btfss f,b
Se il bit ‘b’ del registro ‘f’ è 0 viene eseguita l’istruzione successiva. Se il bit ‘b’ del registro ‘f’ è 1 l’istruzione
successiva viene annullata e al suo posto viene eseguita una istruzione NOP. In altri termini in questo ultimo
caso l’istruzione successiva viene saltata. Questo è appunto il significato dell’acronimo:
btfss = Bit Test File Register Skip Set = Esegui il test del bit del file register e salta se è settato
Ad esempio l’istruzione:
btfss STATUS,Z
testa il flag di zero e salta l’istruzione successiva se è settato. Si tratta di un cosiddetto salto condizionato,
ovvero l’inibizione del normale avanzamento all’istruzione successiva di esecuzione sostituita dal salto
all’istruzione susseguente.
Questo tipo di istruzione è fondamentale per effettuare test
sul valore delle variabili.
Sostituisce in pratica il costrutto if…else dei linguaggi di
programmazione ad alto livello, come evidenziato a fianco.
Nel seguente segmento di programma ad esempio, viene
effettuato l’XOR tra WREG e UNITA. Se sono uguali il flag di
zero risulta settato e l’istruzione btfss rinvia al corpo delle
istruzione relative all’if. Se il flag di zero è resettato invece
vengono eseguite le istruzioni relative all’else. Si noti la
presenza dell’istruzione goto finetest, senza la quale
verrebbe eseguito sia il corpo dell’if che quello dell’else.
xorwf UNITA,0
btfss STATUS,Z
goto else
; corpo istruzioni if
…………………
…………………
goto finetest
else ; corpo istruzioni else
…………………
…………………
finetest
…………………
•
SI
NO
WREG=UNITA?
if
else
corpo
istruzioni if
corpo
istruzioni else
………..
Istruzioni letterali e di controllo
Nelle istruzioni letterali e di controllo ‘k’ rappresenta un dato immediato come un numero o una lettera, oppure
una etichetta di salto o una costante dichiarata. Le costanti vengono dichiarate all’inizio del programma con la
clausola #define. Ad esempio;
#define PortA_input
B'00111111'
dichiara una costante di nome PortA_input alla quale viene assegnato il valore binario 00111111.
Per dichiarare un valore in formato esadecimale si deve utilizzare il modificatore 0x e in decimale il punto.
Ad esempio le due seguenti dichiarazioni sono equivalenti alla precedente:
#define PortA_input
0x3F
#define PortA_input
.63
Il vantaggio nell’uso delle costanti è dovuto alla possibilità di utilizzare simboli al posto di sequenze complesse
di numeri.
esempio
movlw k
7
Il letterale ‘k’ viene copiato nel registro W.
Ad esempio:
movlw .10
copia in WREG il numero 10
movlw PortA_input
copia in WREG il numero rappresentato dalla costante PortA_input
movlw ‘a’
copia in WREG la lettera ‘a’, memorizzata come carattere ASCII numero ….61H.
Tra le istruzioni di controllo si annoverano le istruzioni di salto e di chiamata a sottoprogramma.
esempio
goto k
Il GOTO è un salto incondizionato. ‘k’ viene posto in modo immediato nei primi undici bit <10:0> della parte
bassa del Program Counter PCL. I bit alti vengono copiati dal PCLATH<4:3> nella parte alta PCH.
Il Program Counter, ovvero contatore di programma, è
un registro di 13 bit che conserva l’indirizzo
dell’istruzione in corso di esecuzione. Mantenere
PC
memorizzata questa informazione è fondamentale per
PC+1
tenere traccia delle istruzioni eseguite e poter avanzare
regolarmente nella sequenza di esecuzione. Il PC
“punta” dunque all’istruzione corrente; dopo la sua
esecuzione, il PC viene automaticamente incrementato
per puntare all’istruzione successiva, come descritto a
fianco.
Spesso serve saltare ad una locazione del programma
PC
diversa da quella successiva, per questo è necessario
introdurre un salto incondizionato con una istruzione goto.
Incondizionato significa che il salto viene fatto in tutti i casi,
indipendentemente dallo stato del microcontrollore.
Quando incontra una istruzione goto k il sistema sostituisce k
al posto dei primi 11 bit del PC, alterando il suo valore. Come
conseguenza diretta si ha l’esecuzione al passo successivo
dell’istruzione di indirizzo k, come descritto a fianco.
000017
000018
000019
00001A
00001B
281C
3000
0A0
3000
0A1
00001C
008
GOTO 0x1c
MOVLW 0
MOVWF 0x20
MOVLW 0
MOVWF 0x21
goto
movlw
movwf
movlw
movwf
memoria programma
0005
0005h
0006h
0007h
0008h
0006
0009h
memoria programma
0005
0005h
0006h
0007h
0008h
0009h
000Ah
000Bh
0006B
000Ch
fine
.0
UNITA
.0
DECINE
fine
RETURN
return
Nel segmento di programma sopra riportato, nel quale è presente a sinistra la versione disassemblata, cioè con
i veri codici di memoria al posto dei simboli, si vede che l’istruzione goto fine, codificata come GOTO 0x1c,
determina il salto all’indirizzo 001C.
esempio
call k
Chiamata di sottoprogramma. L’indirizzo di ritorno (PC+1) viene inserito nello stack. Il valore di k viene posto in
modo immediato negli undici bit <10:0> del PC. I bit alti del PC vengono caricati dal PCLATH.
La chiamata a sottoprogramma determina il salto incondizionato alla locazione della prima istruzione del
sottoprogramma. Un sottoprogramma è una sezione di programma separata dal programma principale. Lo
scopo di questa divisione è di razionalizzare la scrittura dei programmi, affidando compiti diversi a sezioni
distinte di programma, richiamabili anche ripetutamente.
programma principale
PC=5
………
5 call sottoprogramma1
……………..
……………..
……………..
sottoprogramma1
100 call sottoprogramma2
……………..
……………..
……………..
return
sottoprogramma2
200
……………..
……………..
……………..
return
8
Come si vede nella figura sopra, a differenza dell’istruzione goto, che prevede solo il salto iniziale, l’istruzione
call deve assicurare il ritorno al programma principale e la prosecuzione all’istruzione successiva alla call
stessa.
Per questo è necessario che il sistema, all’atto della chiamata di sottoprogramma, registri il valore corrente del
PC, in quanto il PC viene caricato con l’indirizzo della prima istruzione del sottoprogramma. A conclusione del
sottoprogramma il sistema recupera il vecchio valore di PC e lo incrementa per puntare alla successiva
istruzione.
Il salvataggio degli indirizzi di ritorno viene fatto nello stack. Nel PIC lo stack è una catasta di 8 parole di 13 bit
(13=numero di bit del PC). Come descritto dalla figura seguente, gli indirizzi, man mano che vengono salvati,
risultano impilati uno sopra l’altro, con una organizzazione di tipo LIFO Last In First Out, ovvero l’ultimo a
entrare è anche il primo a uscire.
Ad ogni salto a sottoprogramma, anche nel caso di sottoprogrammi che richiamano altri sottoprogrammi,
l’indirizzo di ritorno viene salvato sopra la pila. Per percorrere a ritroso il ritorno al programma principale, gli
indirizzi di ritorno vengono prelevati uno ad uno fino a svuotare la catasta.
PC=PC+1
PC=5
PC=PC+1
PC=100
PC=100
PC=5
100
5
prima di call
sottoprogramma1
call sottoprogramma1
5
call sottoprogramma2
return
return
Ad ogni nuovo salvataggio un registro stack pointer viene incrementato, per puntare alla nuova locazione vuota
disponibile per il salvataggio.
9
•
Descrizione delle istruzioni
ADDLW
Add Literal and W
Sintassi: [label] ADDLW k
Operandi: 0 ≤ k ≤ 255
Operazione: (W) + k → (W)
Bit STATUS influenzati: C, DC, Z
Descrizione: Il contenuto del registro W è
sommato al letterale ‘k’ e il risultato è posto
in W
BCF Bit Clear f
Sintassi: [label] BCF f,b
Operandi: 0 ≤ f ≤ 127
0≤b≤7
Operazione: 0 → (f<b>)
Bit STATUS influenzati: None
Descrizione: Il bit 'b' del registro 'f' viene
impostato a 0.
ADDWF Add W and f
Sintassi: [label] ADDWF f,d
Operandi: 0 ≤ f ≤ 127
d ∈ [0,1]
Operazione: (W) + (f) → (Destinazione)
Bit STATUS influenzati: C, DC, Z
Descrizione: Il contenuto del registro W viene
sommato al file register ‘f’. Se ‘d’ è 0 il risultato
viene posto nel registro W. Se’d’ è 1 il risultato
viene posto in ‘f’.
BSF Bit Set f
Sintassi: [label] BSF f,b
Operandi: 0 ≤ f ≤ 127
0≤b≤7
Operazione: 1 → (f<b>)
Bit STATUS influenzati: None
Descrizione: Il bit 'b' del registro 'f' viene
impostato a 1.
ANDLW AND Literal with W
Sintassi: [label] ANDLW k
Operandi: 0 ≤ k ≤ 255
Operazione: (W) .AND. (k) → (W)
Bit STATUS influenzati: Z
Descrizione: Il contenuto del registro W è
posto in AND con il letterale ‘k’. Il risultato è
posto in W.
BTFSS Bit Test f, Skip if Set
Sintassi: [label] BTFSS f,b
Operandi: 0 ≤ f ≤ 127
0≤b<7
Operazione: skip if (f<b>) = 1
Bit STATUS influenzati: None
Descrizione: Se il bit ‘b’ del registro ‘f’ è 0 viene
eseguita l’istruzione successiva. Se il bit ‘b’ del
registro ‘f’ è 1 l’istruzione successiva viene
annullata e al suo posto viene eseguita una
istruzione NOP.
ANDWF AND W with f
Sintassi: [label] ANDWF f,d
Operandi: 0 ≤ f ≤ 127
d [0,1]
Operazione: (W) .AND. (f) → (Destinazione)
Bit STATUS influenzati: Z
Descrizione: Il contenuto del registro W è
posto in AND con il file register ‘f’. Se ‘d’ è 0
il risultato viene posto nel registro W. Se ’d’’
è 1 il risultato viene posto in ‘f’.
BTFSC Bit Test, Skip if Clear
Sintassi: [label] BTFSC f,b
Operandi: 0 ≤ f ≤ 127
0≤b≤7
Operazione: skip if (f<b>) = 0
Bit STATUS influenzati: None
Descrizione: Se il bit ‘b’ del registro ‘f’ è 1
viene eseguita l’istruzione successiva. Se il
bit ‘b’ del registro ‘f’ è 0 l’istruzione
successiva viene annullata e al suo posto
viene eseguita una istruzione NOP.
CALL Call Subroutine
Sintassi: [ label ] CALL k
Operandi: 0 ≤ k ≤ 2047
Operazione: (PC)+ 1→ TOS,
k → PC<10:0>,
(PCLATH<4:3>) → PC<12:11>
Bit STATUS influenzati: None
Descrizione: Chiamata di sottoprogramma.
L’indirizzo di ritorno (PC+1) viene inserito nello
stack. Il valore di k viene posto in modo
immediato negli undici bit <10:0> del PC. I bit
alti del PC vengono caricati dal PCLATH.
CLRWDT Clear Watchdog Timer
Sintassi: [ label ] CLRWDT
Operandi: None
Operazione: 00h → WDT
0 → WDT prescaler,
1 → TO
1 → PD
Bit STATUS influenzati: TO, PD
Descrizione: Resetta il Watchdog Timer. Il
prescaler del WDT e il bit TO del registro
STATUS vengono impostati a 1.
CLRF Clear f
Sintassi: [label] CLRF f
Operandi: 0 ≤ f ≤ 127
Operazione: 00h → (f)
1→Z
Bit STATUS influenzati: Z
Descrizione: Il contenuto del registro ‘f’
viene cancellato e il bit Z viene posto a 1.
COMF Complement f
Sintassi: [ label ] COMF f,d
Operandi: 0 ≤ f ≤ 127
d ∈ [0,1]
Operazione: (f) → (Destinazione)
Bit STATUS influenzati: Z
Descrizione: Il contenuto del registro ‘f’ viene
complementato. Il risultato viene posto nel
registro W. Se ’d’ è 1 il risultato viene posto in
‘f’.
CLRW Clear W
Sintassi: [ label ] CLRW
Operandi: None
Operazione: 00h → (W)
1→Z
Bit STATUS influenzati: Z
Descrizione: Il contenuto del registro W
viene cancellato e il bit Z viene posto a 1.
DECF Decrement f
Sintassi: [label] DECF f,d
Operandi: 0 ≤ f ≤ 127
d ∈ [0,1]
Operazione: (f) - 1 → (Destinazione)
Bit STATUS influenzati: Z
Descrizione: Il contenuto del registro ‘f’
viene decrementato. Se ‘d’ è 0 il risultato
viene posto nel registro W. Se ’d’ è 1 il
risultato viene posto in ‘f’.
DECFSZ Decrement f, Skip if 0
Sintassi: [ label ] DECFSZ f,d
Operandi: 0 ≤ f ≤ 127
d ∈ [0,1]
Operazione: (f) - 1 → (Destinazione);
skip if result = 0
Bit STATUS influenzati: None
Descrizione: Il contenuto del registro ‘f’ viene
decrementato. Se ‘d’ è 0 il risultato viene posto
nel registro W,. Se ’d’ è 1 il risultato viene
posto in ‘f’.
Se il risultato è 1 viene eseguita l’istruzione
successiva. Se il risultato è 0 viene eseguita
l’istruzione NOP.
INCFSZ Increment f, Skip if 0
Sintassi: [ label ] INCFSZ f,d
Operandi: 0 ≤ f ≤ 127
d ∈ [0,1]
Operazione: (f) + 1 → (Destinazione),
skip if result = 0
Bit STATUS influenzati: None
Descrizione: Il contenuto del registro ‘f’
viene incrementato. Se ‘d’ è 0 il risultato
viene posto nel registro W,. Se ’d’ è 1 il
risultato viene posto in ‘f’.
Se il risultato è 1 viene eseguita l’istruzione
successiva. Se il risultato è 0 viene
eseguita l’istruzione NOP.
GOTO Unconditional Branch
Sintassi: [ label ] GOTO k
Operandi: 0 ≤ k ≤ 2047
Operazione: k → PC<10:0>
PCLATH<4:3> → PC<12:11>
Bit STATUS influenzati: None
Descrizione: Il GOTO è un salto
incondizionato. ‘k’ viene posto in modo
immediato nei primi undici bit <10:0> del
PC. I bit alti vengono copiati dal
PCLATH<4:3>.
IORLW Inclusive OR Literal with W
Sintassi: [ label ] IORLW k
Operandi: 0 ≤ k ≤ 255
Operazione: (W) .OR. k → (W)
Bit STATUS influenzati: Z
Descrizione: Il contenuto del registro W è posto
in OR con il letterale ‘k’. Il risultato viene posto
nel registro W.
10
INCF Increment f
Sintassi: [ label ] INCF f,d
Operandi: 0 ≤ f ≤ 127
d ∈ [0,1]
Operazione: (f) + 1 → (Destinazione)
Bit STATUS influenzati: Z
Descrizione: Il contenuto del registro ‘f’
viene incrementato. Se ‘d’ è 0 il risultato
viene posto nel registro W. Se ’d’ è 1 il
risultato viene posto in ‘f’.
IORWF Inclusive OR W with f
Sintassi: [ label ] IORWF f,d
Operandi: 0 ≤ f ≤ 127
d ∈ [0,1]
Operazione: (W) .OR. (f) → (Destinazione)
Bit STATUS influenzati: Z
Descrizione: Il contenuto del registro W è
posto in OR con il registro ‘f’. Se ‘d’ è 0 il
risultato viene posto nel registro W. Se ’d’ è
1 il risultato viene posto in ‘f’.
MOVF Move f
Sintassi: [ label ] MOVF f,d
Operandi: 0 ≤ f ≤ 127
d ∈ [0,1]
Operazione: (f) → (Destinazione)
Bit STATUS influenzati: Z
Il contenuto del registro ‘f’ viene copiato entro
un registro di destinazione. Se ‘d’ è 0 la
destinazione è il registro W. Se ’d’ è 1 la
destinazione è ‘f’.
Il caso d=1 è utile per testare un file register,
poiché viene influenzato il flag Z.
NOP No Operation
Sintassi: [ label ] NOP
Operandi: None
Operazione: No Operazione
Bit STATUS influenzati: None
Descrizione: Nessuna operazione.
MOVLW Move Literal to W
Sintassi: [ label ] MOVLW k
Operandi: 0 ≤ k ≤ 255
Operazione: k → (W)
Bit STATUS influenzati: None
Descrizione: Il letterale ‘k’ viene copiato nel
registro W.
RETFIE Return from Interrupt
Sintassi: [ label ] RETFIE
Operandi: None
Operazione: TOS → PC,
1 → GIE
Bit STATUS influenzati: Nessuno
MOVWF Move W to f
Sintassi: [ label ] MOVWF f
Operandi: 0 ≤ f ≤ 127
Operazione: (W) → (f)
Bit STATUS influenzati: None
Descrizione: Copia il contenuto del registro
W nel registro ‘f’.
RETLW Return with Literal in W
Sintassi: [ label ] RETLW k
Operandi: 0 ≤ k ≤ 255
Operazione: k → (W);
TOS → PC
Bit STATUS influenzati: None
Descrizione: Il registro W viene caricato
con il letterale ‘k’. Il program counter viene
aggiornato con il byte alto dello stack
(indirizzo di ritorno). E’ una istruzione a due
cicli.
RLF Rotate Left f through Carry
Sintassi: [ label ] RLF f,d
Operandi: 0 ≤ f ≤ 127
d ∈ [0,1]
Operazione: Vedi descrizione sotto
Bit STATUS influenzati: C
Descrizione: Il contenuto del registro ‘f’ viene
fatto ruotare di un bit a sinistra attraverso il
Carry. Se ‘d’ è 0 il risultato viene posto nel
registro W. Se ’d’ è 1 il risultato viene posto in
‘f’.
SLEEP
Sintassi: [ label ] SLEEP
Operandi: None
Operazione: 00h → WDT,
0 → WDT prescaler,
1 → TO,
0 → PD
Bit STATUS influenzati: TO, PD
Descrizione: Il bit PD di power-down del
registro STATUS, il Watchdog Timer e il
prescaler vengono cancellati. Il bit di timeout TO del registro STATUS viene settato.
Il processore viene posto in stato di SLEEP
con l’oscillatore fermo.
RETURN Return from Subroutine
Sintassi: [ label ] RETURN
Operandi: None
Operazione: TOS → PC
Bit STATUS influenzati: None
Descrizione: Ritorno da sottoprogramma. Il
byte in cima allo stack viene estratto e
caricato nel program counter.
SUBLW Subtract W from Literal
Sintassi: [ label ] SUBLW k
Operandi: 0 ≤ k ≤ 255
Operazione: k - (W) → (W)
Bit STATUS influenzati: C, DC, Z
Descrizione: Il contenuto del registro W viene
sottratto dal letterale ‘k’ (metodo complemento a
due). Il risultato viene posto nel registro W.
RRF Rotate Right f through Carry
Sintassi: [ label ] RRF f,d
Operandi: 0 ≤ f ≤ 127
d ∈ [0,1]
Operazione: Vedi descrizione sotto
Bit STATUS influenzati: C
Descrizione: Il contenuto del registro ‘f’
viene fatto ruotare di un bit a destra
attraverso il Carry. Se ‘d’ è 0 il risultato
viene posto nel registro W. Se ’d’ è 1 il
risultato viene posto in ‘f’.
SUBWF Subtract W from f
Sintassi: [ label ] SUBWF f,d
Operandi: 0 ≤ f ≤ 127
d ∈ [0,1]
Operazione: (f) - (W) → (Destinazione)
Bit STATUS influenzati: C, DC, Z
Descrizione: Il contenuto del registro W
viene sottratto a ‘f’ (metodo complemento a
due). Se ‘d’ è 0 il risultato viene posto nel
registro W. Se ’d’ è 1 il risultato viene posto
in ‘f’.
SWAPF Swap Nibbles in f
Sintassi: [ label ] SWAPF f,d
Operandi: 0 ≤ f ≤ 127
d ∈ [0,1]
Operazione: (f<3:0>) → (Destinazione<7:4>),
(f<7:4>) → (Destinazione<3:0>)
Bit STATUS influenzati: None
Descrizione: Vengono scambiati il nibble basso
e alto del registro ‘f’. Se ‘d’ è 0 il risultato viene
posto nel registro W. Se ’d’ è 1 il risultato viene
posto in ‘f’.
XORWF Exclusive OR W with f
Sintassi: [label] XORWF f,d
Operandi: 0 ≤ f ≤ 127
d ∈ [0,1]
Operazione: (W) .XOR. (f) →
(Destinazione)
Bit STATUS influenzati: Z
Descrizione: Il contenuto del registro W è
posto in OR esclusivo con il registro ‘f’. Se
‘d’ è 0 il risultato viene posto nel registro W.
Se ’d’ è 1 il risultato viene posto in ‘f’.
XORLW Exclusive OR Literal with W
Sintassi: [label] XORLW k
Operandi: 0 ≤ k ≤ 255
Operazione: (W) .XOR. k → (W)
Bit STATUS influenzati: Z
Descrizione: Il contenuto del registro W è
posto in OR con il letterale ‘k’. il risultato
viene posto in W.
11
IDE MPLAB
MPLAB (MicrochiP LABoratory) è un ambiente di sviluppo integrato, o IDE (Integrated Development
Environment), che incorpora tutti gli strumenti utili per la programmazione dei microcontrollori PIC:
• editor: per la scrittura del programma; automaticamente colora il codice sorgente per assicurarne la
correttezza
• compilatore: per convertire il codice simbolico assembler in codice macchina ‘1’, ‘0’
• debugger: per la simulazione del programma: consente, osservando registri e simboli, di identificare i “bug”,
cioè i quasi inevitabili errori
• programmatore: per trasferire il programma sviluppato “on board” nel microcontrollore, scrivendolo (burn)
nella sua memoria di programma.
1) Inserire il CD Blu/Rosso, attendere l’autocaricamento e cliccare sul punto indicato per avviare l’installazione
2) Dopo l’installazione fare doppio click sull’icona nel
desktop. Compare la schermata del MPLAB IDE.
3) Selezionare Configure Select Device.
Selezionare il PIC16F684. I led verdi indicano i
componenti supportati dall’MPLAB IDE.
4) Iniziare a creare un nuovo progetto. Predisporre una cartella con il nome del progetto e entro essa un file con
estensione asm di un precedente lavoro, per disporre di una base di partenza dalla quale iniziare il lavoro. In
questo capitolo è utilizzato il file esempio.asm della cartella Applicazioni\MPLAB\esempio.
Si consiglia di utilizzare Esplora Risorse e lavorare per trascinamento.
5) Selezionare nel menu Project Project Wizard
Nella finestra che si apre selezionare AVANTI
6) Selezionare il dispositivo
12
7) Selezionare il linguaggio
8) immettere il nome del progetto e selezionare, con
l’ausilio del pulsante browse, la cartella predisposta.
Cliccare su AVANTI.
9) Aggiungere al progetto il file con estensione .asm
premento ADD>> Cliccare su AVANTI.
10) Nella finestra che si apre selezionare Fine
11) Fare doppio click sul nome del file
sotto la voce Source Files, per aprire la
finestra con il listato del programma.
if
SI
UNITA
=10 ?
NO
UNITA=0
INCREMENTA
DECINE
if
SI
DECINE
=6 ?
NO
Il programma di esempio è un contatore da 0 a 59.
Esso risponde al diagramma di flusso riportato a fianco.
Viene confrontato il valore delle unità con 10: se risulta
uguale vuole dire che il 9 è stato superato, quindi
UNITA deve essere azzerato e si deve far progredire la
cifra delle DECINE.
Un controllo simile viene eseguito sulle decine: se
risulta DECINE=6 vuol dire che il 5 è stato superato,
pertanto si deve forzare DECINE=0.
Ad ogni ciclo l’istruzione call reset? chiama il
sottoprogramma reset?. Questo controlla se il bit 3
della porta A è settato; in caso affermativo resetta sia
UNITA che DECINE.
Si riporta di seguito il listato completo.
DECINE=0
13
goto Inizio
;DIRETTIVE
list
p=16f684
; direttiva list per definizione del processore
#include <p16f684.inc>
; definizione variabili specifiche processore
errorlevel -302
;
;bit di configurazione che specificano modalità operative del PIC: Code protect off, Watchdog
;timer off, Power-up timer on …………
__CONFIG
_CP_OFF & _CPD_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT
;DEFINIZIONE COSTANTI E VARIABILI
#define PortA_input
B'00111111'
cblock 0x20
UNITA
DECINE
endc
;INIZIALIZZAZIONE
org
0x000
; vettore di reset del processore
goto
Initialize
org
0x005
; vettore di inizio del programma
Initialize
bsf
STATUS, RP0
; selezione banco 1
movlw PortA_input
movwf TRISA
; imposta alti tutti bit porta A
bcf
STATUS, RP0
; selezione banco 0
;PROGRAMMA
Inizio
call
reset?
incf
UNITA,1
; incrementa numero
movlw .10
xorwf UNITA,0
; se UNITA=10 riprende il conteggio da 0
btfss STATUS,Z
; salta se Z=0
goto
controllodecine
clrf
UNITA
; azzera UNITA
incf
DECINE,1
; incrementa DECINE
controllodecine
movlw .6
; se DECINE=6 pone DECINE=0
xorwf DECINE,0
btfsc STATUS,Z
clrf
DECINE
goto
Inizio
;SOTTOPROGRAMMA
reset?
btfss PORTA,3
goto
fine
movlw .0
movwf UNITA
movlw .0
movwf DECINE
fine
return
end
; testa se Switch premuto
; azzera unità e decine
Ora si passa alla fase di analisi/debugging del programma. Analizzeremo una ad una le istruzioni più
significative, osservandone gli effetti sui registri e le variabili. Le istruzioni analizzate sono le stesse all’uopo
enucleate e spiegate nel capitolo precedente.
12) Per avviare lo strumento debugger selezionare Debugger Select Tool MPLAB SIM. Di seguito si
riportano le opzioni di debugging con le relative spiegazioni.
Animate
Run
Halt
Step Into
Step Over
Reset
Step Out
AZIONE
Run
Halt
DESCRIZIONE
Il programma viene eseguito in tempo reale, in pratica alla massima velocità consentita dal PC
Il programma viene arrestato
Animate
Step Into
Step Out
Il programma viene eseguito passo passo con avanzamento automatico
Il programma viene eseguito passo passo con avanzamento manuale; se sono presenti
sottoprogrammi, anche questi vengono percorsi passo passo
Il programma viene eseguito passo passo con avanzamento manuale; se sono presenti
sottoprogrammi, non vengono mostrate passo passo le istruzioni interne
Il sottoprogramma corrente viene abbandonato
Resest
L’esecuzione viene riportata all’inizio del programma; i registri vengono reinizializzati
Step Over
14
13) Compilare il programma selezionando Project Build All; chiudere la finestra Output dei risultati di
compilazione.
14) Impostare la velocità di animazione selezionando Debugger Settings…
In modalità Animate il programma viene eseguito
Digitare 50 nel campo Animate step time della
scheda Animation/Realtime Updates. Questo è il automaticamente come nella modalità Run, ma in modo
rallentato. Questo permette di osservare la progressione
tempo di scansione automatica delle istruzioni.
dei dati coinvolti nell’algoritmo.
15) Ridurre la finestra del programma premendo
sull’icona di ripristino (due quadrati sovrapposti); invocare
la finestra Watch selezionando View Watch e
accostarla a fianco della finestra di programma, come
sotto mostrato.
Per visualizzare i numeri d’ordine delle istruzioni cliccare
con il tasto destro sulla banda grigia a sinistra e
selezionare Properties… Nella scheda “Editor” spuntare
la casella “Line Numbers”.
La finestra Watch permette di osservare in tempo reale i valori degli elementi coinvolti nel programma. Un menu
a sinistra permette di selezionare un file register; premendo Add SFR esso viene aggiunto all’elenco di
visualizzazione. Nel menu a destra sono selezionabili i singoli bit dei registri o simboli vari, come le variabili
dichiarate, premendo Add Symbol essi vengono aggiunti all’elenco di visualizzazione.
16) Selezionare le due variabili UNITA e DECINE e aggiungerle alla visualizzazione.
17) Eseguire il programma in modalità Animate. Si può osservare il conteggio effettuato sulla variabile unità e
l’incremento delle decine. Il programma effettua un conteggio da 0 a 59 e riprende da zero.
Di seguito eseguiremo istruzioni singole passo passo, per verificare quanto descritto nel capitolo precedente,
valutando di volta in volta l’effetto dell’istruzione su registri e simboli.
18) Aggiungere alla finestra Watch il registro TRISA. Portarsi in modalità Step Over all’istruzione numero 19 del
programma ed eseguirla:
19
movwf TRISA
Il dato 0x3F presente in W viene copiato nel file register TRISA
15
0X3F
19) Portarsi in modalità Step Over all’istruzione numero 24 del programma:
24
incf UNITA,1
Il dato presente nella variabile UNITA viene incrementato di 1; il risultato viene riversato nella variabile stessa.
0X01
20) Aggiungere alla finestra Watch il registro
STATUS. Eseguire continuamente il
programma in modalità Step Over per far
avanzare il valore di UNITA.
0X1F
Quando si verifica l’uguaglianza UNITA=0x0A, la coppia di istruzioni:
xorwf UNITA,0; btfss STATUS,Z; cambia STATUS da: STATUS=0x18=00011000 a:
STATUS=0x1C=00001100 ovvero setta il flag di zero.
21) Aggiungere alla finestra Watch il simbolo WREG. Resettare il programma e portarsi in modalità Step Over
all’istruzione numero 18 del programma:
movlw . PortA_input
Il valore della costante PortA_input, prefissato a B’00111111’=0x3F viene copiato nell’accumulatore WREG.
0X3F
22) Questo programma è in grado di interagire con un input, il pin3 della porta A. Per impostare un dato, o
“stimulus”, su una linea di input, si deve abbinare ad essa un pulsante virtuale. Per questo selezionare
Debugger Stimulus Controller New Scenario; compare la seguente finestra:
Nella colonna Pin selezionare il pin RA3.
La colonna Action offre quattro modalità di
azione del pulsante:
Set High: sempre premuto
Set Low: sempre non premuto
Pulse High: premuto per una istruzione
Pulse Low: non premuto per una istruzione
Toggle: inversione stato pulsante ad ogni
istruzione.
Selezionare Set High e premere Fire per
innescare l’azione. Eseguendo il programma
in modalità Step Into si può osservare che il
conteggio viene resettato. Se invece si
imposta Set Low il conteggio procede
regolarmente.
16
23) Per osservare gli elementi di interesse nel caso di istruzioni di salto conviene invocare la finestra del listato
disassemblato, selezionando View Disassembling Listing. Disassemblare significa convertire il listato
assembler simbolico nei codici macchina di codifica delle istruzione, con indicazione degli indirizzi delle word
dove le istruzioni sono collocate. Disporre le finestre in modo tale da poter osservare il programma, il listato
disassemblato e la finestra Watch.
Portarsi all’istruzione 28 goto controllodecine, che come si può vedere nella finestra del disassemblato, è
codificata all’indirizzo 0x000E.
Aggiungere il registro PCL alla finestra Watch. Il PCL segna giustamente 0x0E.
Avanzare di un passo: viene eseguito il salto all’istruzione movlw .6, che è collocata all’indirizzo 0x0011.
La finestra Watch mostra il valore PCL=0X11.
0X11
24) Per osservare il comportamento dello stack nel caso di una istruzione call visualizzare la finestra Hardware
Stack selezionando View Hardware Stack.
Portarsi all’istruzione numero 23 call reset?. Come si può vedere dal disassemblato essa è codificata
all’indirizzo 0x0009; la successiva al 0x000A.
Proseguire in modalità Step
Into: in questo modo si entra
nel sottoprogramma. Il valore
0x0A dell’indirizzo di ritorno,
cioè dell’istruzione successiva
a call reset?, viene subito
salvato nello stack, come si può
osservare dalla finestra
Hardware Stack.
All’esecuzione dell’istruzione return, lo stack viene svuotato, il PCL riacquista l’indirizzo di ritorno e il programma
riprende dall’istruzione successiva alla call.
25) Il programma di esempio è un contatore da 0 a 59, con due variabili UNITA e DECINE.
Per osservare l’incremento delle decine passo passo è necessario ogni volta scandire tutte le unità da 0 a 9.
Questo comporta uno spreco di tempo e richiede una grande dose di pazienza.
Si ricorre in questo e in numerosi altri casi simili e più complessi al Breakpoint. Il Breakpoint (punto di arresto)
introduce, come suggerisce il termine inglese, un punto di arresto nella sequenza delle istruzioni.
In questo caso conviene introdurlo in
coincidenza con l’istruzione
movlw .6. Per questo si fa doppio
click in un punto qualsiasi
dell’istruzione, appare di
conseguenza una B circondata da
un cerchio rosso.
Si può ora agire sul tasto Run anziché Step Over, in quanto il programma comunque si arresta al Breakpoint.
Se c’è aperta la finestra Watch con l’indicazione di UNITA e DECINE, si potrà osservare l’avanzamento delle
UNITA’ ad ogni passaggio per il breakpoint.
17
Esercizi
es1
Scrivere un programma che effettui, con una variabile UNITA, il conteggio da 0 a 9. Confrontare UNITA con 10, quando
sono uguali forzare UNITA=0. Per il test sul valore di UNITA utilizzare l'istruzione btfsc anzichè btfss.
es2
Scrivere un programma che effettui, con una variabile UNITA, il conteggio da un valore MIN compreso a un valore MAX
escluso. Dichiarare MIN e MAX come costanti e assegnarvi il valore desiderato.
Confrontare UNITA con MAX, quando sono uguali forzare UNITA=MIN.
es3
Scrivere un programma che effettui, con una variabile UNITA, il conteggio da 0 a 9 in avanti oppure all'indietro da 9 a 0.
La direzione del conteggio viene imposta dal valore della costante DIREZIONE dichiarata nel programma.
Se DIREZIONE=1 conteggio avanti, se DIREZIONE=0 conteggio indietro.
Per controllare il valore di DIREZIONE immettere .1 in WREG con l'istruzione movlw .1 e far seguire l'istruzione xorlw
DIREZIONE, la quale confronta WREG con il letterale DIREZIONE.
Nel conteggio avanti confrontare UNITA con 10, quando sono uguali forzare UNITA=0.
Nel conteggio indietro confrontare UNITA con 255, quando sono uguali forzare UNITA=9.
es4
Scrivere un programma che effettui, con una variabile UNITA, il conteggio da 0 a 9 in avanti oppure all'indietro da 9 a 0.
La direzione del conteggio viene imposta dal livello RA3 del bit3 della Porta A.
Se RA3=1 conteggio avanti, se RA3=0 conteggio indietro.
Nel conteggio avanti confrontare UNITA con 10, quando sono uguali forzare UNITA=0.
Nel conteggio indietro confrontare UNITA con 255, quando sono uguali forzare UNITA=9.
Provare il programma con un pulsante virtuale.
18
MEMORIA
Tra le principali attività di un microprocessore ci sono le operazioni di lettura e scrittura entro la memoria dati.
Nel PIC sono presenti tre diverse sezioni di memoria:
• memoria di PROGRAMMA – dove viene scritto il programma che il microcontrollore deve eseguire
• memoria REGISTER FILE – dove sono presenti i registri Special Function Register SFR e General Pur
pose Register GPR.
• memoria EEPROM – dove possono essere salvati i dati permanentemente.
Nei registri SFR sono presenti i dati di configurazione dei vari dispositivi che corredano il PIC.
Nei registri GPR sono presenti i dati utente, ovvero i dati che il programma manipola. Un gruppo di registri GPR
può contenere i numeri di un calcolo matematico, oppure le lettere di un brano testuale. Ancora: può registrare i
byte di configurazione dei pixel di una immagine o i campioni di un brano musicale.
Il capitolo ha lo scopo di descrivere come questi dati possano essere gestiti, con una panoramica su algoritmi
base di gestione della memoria.
Nel PIC lo spazio GPR del banco 0 è compreso tra gli indirizzi 20h e 7Fh. Le modalità di accesso ai 96 bytes di
questo spazio sono due:
• indirizzamento diretto
• indirizzamento indiretto.
•
Indirizzamento Diretto
Nelle istruzioni con indirizzamento diretto l’indirizzo del byte GPR da manipolare è specificato direttamente
nell’istruzione.
WREG
Ad esempio nell’istruzione movwf 0x0020 è
specificato in esadecimale l’indirizzo 20h. Il
significato dell’istruzione è: “copia il valore
dell’accumulatore ‘w’ nel byte di indirizzo 20h”.
5
5
20h
L’istruzione duale movfw 0x0020 copia invece il valore del byte di indirizzo 20h nell’accumulatore.
Esperimento …\Memoria\diretto
Scrivere un programma che inizializzi il blocco dei registri GPR dall’indirizzo 20h all’indirizzo 24h con i numeri 0, 1, 2, 3, 4.
;DIRETTIVE
list
p=16f684
; direttiva list per definizione del processore
#include <p16f684.inc>
; definizione variabili specifiche processore
errorlevel -302
;INIZIALIZZAZIONE
org
0x000
; vettore di reset del processore
goto
Initialize
org
0x005
; vettore di inizio del programma
Initialize
bcf
STATUS, RP0
; selezione banco 0
movlw .0
; carica 0 in w
movwf 0x0020
; copia w nel File Register di indirizzo 20h
movlw .1
movwf 0x0021
movlw .2
movwf 0x0022
movlw .3
movwf 0x0023
movlw .4
movwf 0x0024
end
Ogni coppia di istruzioni mov è costituita da una prima istruzione di tipo letterale che carica un numero in w e
una seconda istruzione che copia w nel File Register, di indirizzo specificato in modo diretto.
Selezionare View File Registers per visualizzare la finestra File Registers. In essa è visualizzato tutto lo
spazio Register File.
Ogni riga visualizza 16 registri, dislocati in altrettante colonne. Si può vedere che all’indirizzo 0020di riga, nelle
prime quattro colonne, ovvero agli indirizzi 20h, 21h, 22h, 23h, 24h il programma ha registrato i rispettivi numeri
0, 1, 2, 3, 4.
19
•
Indirizzamento Indiretto
Nelle istruzioni di implementazione dell’indirizzamento indiretto l’indirizzo del byte GPR da manipolare è
specificato nel registro FSR (File Select Register = Registro di Selezione Archivio).
La lettura e la scrittura del byte GPR prevede che l’indirizzo venga scritto nel registro FSR. Per indicare che
l’operazione avviene in modo indiretto si utilizza poi la parola chiave INDF (Indirect File).
Ad esempio nel seguente gruppo di istruzioni:
movlw 0x0020
movwf FSR
movfw INDF
la prima carica in w l’indirizzo 20h, la seconda lo copia in FSR, la terza sposta nell’accumulatore il contenuto del
registro, il cui indirizzo è presente in FSR. In questa ottica FSR assume il ruolo di un “puntatore”, ovvero di un
registro che con il suo contenuto punta alla locazione da leggere. INDF complica un po’ il meccanismo, esso ha
il ruolo di “alias” del registro FSR.
WREG
5
FSR
20h
5
20h
Esperimento …\Memoria\indiret
Scrivere un programma che sposti un blocco di 5 byte dall'indirizzo iniziale 20h all'indirizzo 30h, mediante
indirizzamento indiretto.
20h
blocco sorgente
30h
blocco destinazione
Come descritto dalla figura a fianco, la prima
istruzione copia il byte di indirizzo 20h in
WREG e la seconda copia WREG in 30h. Si
noti che la copia diretta da 20h a 30h senza
WREG è impossibile, in quanto tutte le
istruzioni sono implementate da WREG, che è
il solo registro che ha “nervature” con tutto il
resto dell’architettura.
Lo spostamento di blocchi di memoria avviene byte per
byte: si deve copiare il byte di indirizzo 20h all’indirizzo
30h, quello di indirizzo 21h all’indirizzo 31h etc.
Per comprendere a pieno il concetto di indirizzamento
indiretto studiamo prima la soluzione con indirizzamento
diretto. Essa comporta l’utilizzo di una coppia di
istruzioni, una per spostare il byte sorgente in WREG e
una per spostare WREG nel byte destinazione.
Per il primo byte ad esempio, si ha:
movfw 0x0020
movwf 0x0030
byte sorgente
WREG
20h
byte destinazione
30h
Questo è un evidente esempio dove l’utilizzo dell’indirizzamento indiretto è indispensabile: per la copia di un
blocco ad esempio di 100 byte verrebbero impiegate 200 istruzioni; per la copia (ipotetica) di un blocco di
100000 bytes, il programmatore dovrebbe scrivere (!) 200000 istruzioni. In questo e in tutti i casi analoghi, si
procede in modo iterativo con indirizzamento indiretto, collocando un ridotto numero di istruzioni con
indirizzamento diretto entro un ciclo.
PUNTATORE1
20h
byte sorgente
20h
APPOGGIO
0
1
2
3
4
PUNTATORE2
30h
byte destinazione
30h
0
1
2
3
4
20
L’algoritmo utilizza 4 variabili: due puntatori PUNTATORE1 e PUNTATORE2 per puntare alla coppia di byte
corrente, APPOGGIO per la copia temporanea di un byte e CICLI per il numero di iterazioni.
I due puntatori vengono inizializzati all’indirizzo iniziale dei due blocchi, rispettivamente 20h e 30h.
L’operazione di trasferimento del byte sorgente entro APPOGGIO è implementata dalle seguenti istruzioni:
movfw
movwf
movfw
movwf
PUNTATORE1
FSR
INDF
APPOGGIO
;
;
;
;
copia
copia
copia
copia
il contenuto di PUNTATORE1 in WREG
WREG in FSR
il byte puntato da FSR in WREG
WREG in APPOGGIO
Il contenuto di PUNTATORE1, che inizialmente è l’indirizzo 20h viene copiato in WREG e da qui in FSR.
FSR “punta” quindi al primo byte. La terza istruzione copia il contenuto del primo byte in WREG e la quarta lo
salva in APPOGGIO.
La seconda quaterna di istruzioni agisce in modo speculare, copiando APPOGGIO nel primo byte del secondo
blocco:
movfw
movwf
movfw
movwf
PUNTATORE2
FSR
APPOGGIO
INDF
;
;
;
;
copia
copia
copia
copia
il contenuto di PUNTATORE2 in WREG
WREG in FSR
APPOGGIO in WREG
WREG nel byte puntato da FSR
Successivamente i due puntatori vengono incrementati per puntare ai byte successivi dei blocchi e viene
decrementato CICLI.
Infine viene eseguito un test su CICLI. Se CICLI è diverso da zero l’algoritmo viene iterato, altrimenti il
programma termina.
Esperimento …\Memoria\indiret
;DIRETTIVE
list
p=16f684
; direttiva list per definizione del processore
#include <p16f684.inc>
; definizione variabili specifiche processore
errorlevel -302
;DEFINIZIONE COSTANTI E VARIABILI
cblock 0x50
PUNTATORE1
PUNTATORE2
APPOGGIO
CICLI
endc
;INIZIALIZZAZIONE
org
0x000
; vettore di reset del processore
goto
Initialize
org
0x005
; vettore di inizio del programma
Initialize
bcf
STATUS, RP0
; selezione banco 0
movlw .0
; carica 0 in w
movwf 0x0020
; copia w nel File Register di indirizzo 20h
movlw .1
movwf 0x0021
movlw .2
movwf 0x0022
movlw .3
movwf 0x0023
movlw .4
movwf 0x0024
movlw 0x0020
; inizializza puntatori
movwf PUNTATORE1
movlw 0x0030
movwf PUNTATORE2
;PROGRAMMA
movlw .5
movwf CICLI
Inizio
movfw PUNTATORE1
; copia il contenuto di PUNTATORE1 in WREG
movwf FSR
; copia WREG in FSR
movfw INDF
; copia il byte puntato da FSR in WREG
movwf APPOGGIO
; copia WREG in APPOGGIO
movfw
movwf
movfw
movwf
PUNTATORE2
FSR
APPOGGIO
INDF
;
;
;
;
copia
copia
copia
copia
il contenuto di PUNTATORE2 in WREG
WREG in FSR
APPOGGIO in WREG
WREG nel byte puntato da FSR
incf
incf
decfsz
goto
end
PUNTATORE1,1
PUNTATORE2,1
CICLI,1
Inizio
; punta alle successive locazioni
; se CICLI<>0 itera
21
Per analizzare l’algoritmo passo-passo conviene invocare in
MPLAB le finestre File Registers e Watch.
Nella Watch aggiungere i seguenti simboli e variabili:
WREG, FSR, PUNTATORE1, PUNTATORE2, APPOGGIO,
CICLI, Osservarne l’evoluzione in modalità di debugging.
A fianco è rappresentata Watch in corrispondenza della
quarta passata del ciclo.
La tabella che segue riporta i valori assunti da simboli e variabili di interesse in corrispondenza di ciascuna
istruzione.
ISTRUZIONE
movlw .0
movwf 0x0020
movlw .1
movwf 0x0021
movlw .2
movwf 0x0022
movlw .3
movwf 0x0023
movlw .4
movwf 0x0024
movlw 0x0020
movwf PUNTATORE1
movlw 0x0030
movwf PUNTATORE2
;PROGRAMMA
movlw .5
movwf CICLI
Inizio
movfw PUNTATORE1
movwf FSR
movfw INDF
movwf APPOGGIO
movfw PUNTATORE2
movwf FSR
movfw APPOGGIO
ISTRUZIONE
movwf INDF
incf PUNTATORE1,1
incf PUNTATORE2,1
decfsz
CICLI,1
goto Inizio
W
REG
0
FSR
PUNTA
TORE1
PUNTA
TORE2
APPOG
GIO
CICLI 20h
21h
22h
23h
24h
0
1
1
2
2
3
3
4
4
20
20
30
30
5
5
20
20
0
0
30
30
0
W
REG
FSR
PUNTA
TORE1
PUNTA
TORE2
APPOG
GIO
CICLI 30h
31h
32h
33h
34h
0
21
31
4
Esperimento …\Memoria\somma
Scrivere un programma che sommi i bytes da 20h al 24h e depositi il risultato in 25h.
byte0 + byte1 + byte2 + byte3 + byte4
20h
21h
22h
23h
24h
25h
byte 0
byte 1
byte 2
byte 3
byte 4
Risultato
22
;DIRETTIVE
list
p=16f684
; direttiva list per definizione del processore
#include <p16f684.inc>
; definizione variabili specifiche processore
errorlevel -302
__CONFIG
_CP_OFF & _CPD_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT
;DEFINIZIONE COSTANTI E VARIABILI
cblock 0x50
CICLI
PUNTATORE1
SOMMA
endc
;INIZIALIZZAZIONE
org
0x000
; vettore di reset del processore
goto
Initialize
org
0x005
; vettore di inizio del programma
Initialize
bcf
STATUS, RP0
; selezione banco 0
movlw .0
; carica 0 in w
movwf 0x0020
; copia w nel File Register di indirizzo 20
movlw .1
movwf 0x0021
movlw .2
movwf 0x0022
movlw .3
movwf 0x0023
movlw .4
movwf 0x0024
movlw 0x0020
; inizializza puntatore
movwf PUNTATORE1
;PROGRAMMA
movlw .5
movwf CICLI
Inizio
movfw PUNTATORE1
; copia contenuto di PUNTATORE1 in WREG
movwf FSR
; copia WREG in FSR
movfw INDF
; copia il byte puntato da FSR in WREG
addwf SOMMA,1
; somma WREG alla variabile SOMMA
; il risultato viene depositato in somma
incf
PUNTATORE1,1
; punta alla successiva locazione
decfsz CICLI,1
goto
Inizio
; se CICLI<>0 itera
movfw
movwf
movfw
movwf
end
;
;
;
;
PUNTATORE1
FSR
SOMMA
INDF
copia
copia
copia
copia
contenuto di PUNTATORE1 in WREG
WREG in FSR
SOMMA in WREG
SOMMA nel byte puntato da FSR (25h)
Il grafico seguente descrive l’effetto delle istruzioni movfw INDF; addwf SOMMA,1 che sono le istruzioni chiave.
La prima carica nell’accumulatore WREG il byte il cui indirizzo è contenuto nel registro INDF. In altre parole
INDF “punta” al byte di memoria da spostare; l’indirizzo a cui puntare è contenuto in FSR.
La seconda somma WREG al risultato preesistente contenuto in SOMMA; il risultato viene sovrascritto in
SOMMA.
La figura mostra l’ultimo ciclo, nel quale il valore 6 accumulato in SOMMA viene sommato al byte di valore 4
puntato da FSR. Il risultato 0Ah viene depositato in SOMMA.
FSR
24h
20h
21h
22h
23h
24h
0
1
2
3
4
movfw INDF
SOMMA
WREG
+
25h
6
0A
L’ultima quaterna di istruzioni pone in FSR l’indirizzo del byte 25h e vi copia SOMMA.
FSR
25h
movwf INDF
25h
0A
WREG
0A
23
Esperimento …\Memoria\selez
Scrivere un programma che copi un byte dall'indirizzo 20h al 21h, solo se il byte è inferiore a 6.
Per implementare confronti tra numeri si impiega l’istruzione sublw (oppure subwf), osservando il valore del flag di carry, che
è il bit 0 del registro STATUS. Il flag C viene influenzato in questo modo:
risultato sottrazione >0
risultato sottrazione <0
movfw APPOGGIO
sublw .6
C=1
C=0
.Testando il C mediante una istruzione btfss è possibile percorrere uno
di due rami, come descritto nel diagramma di flusso e di conseguenza
eseguire le operazioni opportune.
L’algoritmo, mediante l’istruzione movfw APPOGGIO carica in WREG il
valore della variabile da confrontare con il numero. In questo caso
questa variabile è contenuta in APPOGGIO e il numero è 6.
L’istruzione sublw .6 ha effetto sul flag C, che viene successivamente
testato dalla btfss STATUS,C.
Se C=1 il valore della variabile APPOGGIO, mediante le istruzioni
movfw APPOGGIO e movwf 0x0021, viene depositata all’indirizzo 21h.
;DIRETTIVE
list
p=16f684
#include <p16f684.inc>
errorlevel -302
;DEFINIZIONE COSTANTI E VARIABILI
cblock 0x50
APPOGGIO
endc
;INIZIALIZZAZIONE
org
0x000
goto
Initialize
org
0x005
Initialize
bcf
STATUS, RP0
movlw .3
movwf 0x0020
;PROGRAMMA
movfw 0x0020
movwf APPOGGIO
movfw
sublw
btfss
goto
movfw
movwf
APPOGGIO
.6
STATUS,C
none
APPOGGIO
0x0021
SI
NO
C=1 ?
if
movfw
movwf
APPOGGIO
0x0021
; direttiva list per definizione del processore
; definizione variabili specifiche processore
; vettore di reset del processore
; vettore di inizio del programma
; selezione banco 0
; carica 3 in w
; copia w nel File Register di indirizzo 20h
; copia WREG in APPOGGIO
; flag C settato se 6-APPOGGIO>0
; se APPOGGIO non è inferiore a 6 non fare nulla
none
end
Esercizi
es1
Scrivere un
programma che
copi in ordine
inverso un blocco
di 5 byte
dall'indirizzo
iniziale 20h
all'indirizzo 30h.
Il byte di indirizzo
20h deve essere
collocato in 34h, il
21h in 33h ecc.
20h
22h
0
1
2
23h
24h
3
4
30h
32h
4
3
2
33h
34h
1
0
21h
31h
es2
Scrivere un
programma che
sommi 5 coppie
adiacenti di byte e
depositi il risultato
nella terza
posizione.
Il byte di indirizzo
20h viene
sommato al 21h e
il risultato viene
depositato in 22h
ecc.
20h
21h
22h
3
1
4
2Ch
2
4
6
2
2
4
5
4
9
7
2Dh
2Eh
2
9
23h
24h
25h
26h
27h
28h
29h
2Ah
2Bh
24
20h
3
1
2
4
2
21h
22h
es3
Scrivere un programma che sommi,
byte per byte, i blocchi di 5 bytes con
indirizzo di partenza 20h e 30h
e depositi i risultati a partire da 40h.
Il byte di indirizzo 20h viene sommato
al 30h e depositato in 40h ecc.
23h
24h
30h
31h
33h
34h
20h
22h
3
1
7
23h
24h
9
2
30h
3
1
2
21h
31h
32h
20h
21h
es5
Scrivere un programma
che confronti il byte 20h
con il 30h e depositi in 40h
il minore, poi confronti il
21h con il 31h e depositi il
minore in 41h ecc. Iterare
per 5 bytes.
es6
Scrivere un programma
che determini il numero
minimo nel blocco di 5
bytes di indirizzo 20h e lo
depositi in 25h.
22h
23h
24h
30h
3
1
2
4
2
32h
2
5
4
33h
34h
7
2
20h
22h
3
1
7
23h
24h
25h
9
2
1
31h
21h
42h
43h
44h
40h
<
5
6
6
B
4
41h
+
2
5
4
7
2
32h
es4
Scrivere un
programma che
sposti solo i
bytes <6 dal
blocco di 5 byte
collocato da 20h
al blocco di 5
bytes collocato
da 30h.
40h
42h
2
1
2
43h
44h
4
2
41h
25
PORTE-IO
L’integrato PIC16F684 dispone di due porte di nome porta A e Porta C. Una porta, ad esempio la porta A,
dispone di due registri:
• registro dati PORTA
• registro di configurazione TRISA
Il termine “Porta” nel linguaggio dei microprocessori designa un gruppo di pin fisicamente esistenti all’esterno
dell’integrato, collegati internamente a un registro. Ogni pin corrisponde a un bit del registro e può essere
configurato come input o come output. Se è configurato come output, l’impostazione, mediante il software, di un
valore ‘0’ o ‘1’, si riflette nella presenza o assenza di tensione sul corrispondente pin.
7 6
TRISA
5
4
3
2
1
0
7 6 5
PORTA
4
3
2
1
0
RA5
RA0
RA4
RA1
RA3
RA2
La figura a fianco descrive appunto il
collegamento dei bit del registro PORTA
con i terminali dell’integrato; si noti che
solo 6 degli otto bit del registro sono
collegati ai pin, denominati RA0, RA1,
RA2, RA3, RA4, RA5. Se un bit di
PORTA viene programmato come ‘1’ il
corrispondente pin si trova a livello alto
e viceversa.
Il registro TRISA non è collegato ai pin
bensì è diretto verso PORTA a scopo di
configurazione. Se un suo bit si trova a
livello alto il corrispondente pin è
configurato come input e viceversa.
Si riporta di seguito il dettaglio dei
registri con la descrizione di ciascun bit.
PORTA - REGISTRO PORTA A (INDIRIZZO: 05h)
7
6
5
4
3
2
1
0
------
------
RA5
RA4
RA3
RA2
RA1
RA0
bit 7-6
non implementati: vengono letti come ‘0’
bit 5-0
RA<5:0>: poRtA I/O pin bit (Pin corrispondenti ai bit della porta A)
1 = il pin è a livello alto
0 = il pin è a livello basso
TRISA - REGISTRO DELLA PORTA A TRI-STATE (INDIRIZZO: 85h)
7
6
5
4
3 sola lett.
2
1
0
------
------
TRISA5
TRISA4
TRISA3
TRISA2
TRISA1
TRISA0
bit 7-6
non implementati: vengono letti come ‘0’
bit 5-0
TRISA<5:0>: port A TRI-State pin bit (Bit di controllo tri-state della porta A)
1 = il pin della porta A è configurato come input (tri-stated)
0 = il pin della porta A è configurato come output
PORTC - REGISTRO PORTA C (INDIRIZZO: 07h)
7
------
6
5
4
3
2
1
0
------
RC5
RC4
RC3
RC2
RC1
RC0
bit 7-6
non implementati: vengono letti come ‘0’
bit 5-0
RA<5:0>: poRtA I/O pin bit (Pin corrispondenti ai bit della porta C)
1 = il pin è a livello alto
0 = il pin è a livello basso
TRISC - REGISTRO DELLA PORTA C TRI-STATE (INDIRIZZO: 87h)
7
6
5
4
3
2
1
0
------
------
TRISC5
TRISC4
TRISC3
TRISC2
TRISC1
TRISC0
bit 7-6
non implementati: vengono letti come ‘0’
bit 5-0
TRISC<5:0>: port A TRI-State pin bit (Bit di controllo tri-state della porta C)
1 = il pin della porta C è configurato come input (tri-stated)
0 = il pin della porta C è configurato come output
26
Si noti che i registri PORTA, PORTC sono inscritti al banco 0 e il TRISA, TRISC al banco 1.
L’esempio seguente configura in output la porta A e scrive su essa il numero 7.
bsf
movlw
movwf
bcf
movlw
movwf
STATUS,RP0
B'00000000'
TRISA
STATUS, RP0
B'00000111'
PORTA
;
;
;
;
;
;
banco 1
pone 0 i w
pone w in TRISA
banco 0
pone 7 in w
pone w in PORTA
R5
RA4
150
D0
RED
D1
RED
D4
RED
D5
RED
D6
RED
D7
RED
D2
RED
D3
RED
R6
RA5
150
R7
RA2
150
R8
RA1
150
Per la sperimentazione delle porte di I/O il PICKit1 dispone
di 8 led designati come D0, D1, D2, D3, D4, D5, D6, D7.
A essi fa capo la porta A. Poiché questa dispone solo di 6
uscite, delle quali RA3 abilitata solo per l’input, non è
possibile associare un led a ogni pin. Il collegamento dei led
è strutturato in modo che l’accensione individuale avvenga
per mezzo di combinazioni di RA5, RA4, RA2, RA1 del
registro PORTA e programmando in modo opportuno il
registro TRISA.
Ad esempio per causare l’accensione del diodo D0 è
necessario portare RA4=1 e RA5=0 in PORTA. E’
necessario inoltre programmare RA2 e RA1 in TRISA come
input tri-state, in modo che non si accendano altri led.
Per accendere D1 si può mantenere la medesima
programmazione di TRISA, mentre vanno invertiti i livelli di
RA4 e RA5 in PORTA.
Generalizzando il concetto per tutti i led, risultano le seguenti tabelle:
•
programmazione TRISA
IMPOSTA OUT
OUT_D0_D1
OUT_D2_D3
OUT_D4_D5
OUT_D6_D7
•
----------0
0
0
0
---------0
0
0
0
TRISA5
0
1
0
1
TRISA4
0
0
1
1
TRISA3
1
1
1
1
TRISA2
1
0
0
0
TRISA1
1
1
1
0
TRISA0
1
1
1
1
programmazione PORTA
ATTIVAZIONE
D0_ON
D1_ON
D2_ON
D3_ON
D4_ON
D5_ON
D6_ON
D7_ON
----0
0
0
0
0
0
0
0
----0
0
0
0
0
0
0
0
RA5
0
1
0
0
1
0
0
0
RA4
1
0
1
0
0
0
0
0
RA3
0
0
0
0
0
0
0
0
RA2
0
0
0
1
0
1
1
0
RA1
0
0
0
0
0
0
0
1
RA0
0
0
0
0
0
0
0
0
Alle due tabelle corrispondono le seguenti definizioni di costante da inserire nel segmento di inizializzazione del
programma.
•
programmazione TRISA
#define TRIS_D0_D1 B'00001111'
#define TRIS_D2_D3 B'00101011'
#define TRIS_D4_D5 B'00011011'
#define TRIS_D6_D7 B'00111001'
•
programmazione PORTA
#define D0_ON
B'00010000'
#define D1_ON
B'00100000'
#define D2_ON
B'00010000'
#define D3_ON
B'00000100'
#define D4_ON
B'00100000'
#define D5_ON
B'00000100'
#define D6_ON
B'00000100'
#define D7_ON
B'00000010'
;
;
;
;
impostazione
impostazione
impostazione
impostazione
;
;
;
;
;
;
;
;
D0
D1
D2
D3
D4
D5
D6
D7
TRISIO
TRISIO
TRISIO
TRISIO
per
per
per
per
D0
D2
D4
D6
and
and
and
and
D1
D3
D5
D7
LED
LED
LED
LED
LED
LED
LED
LED
27
Esperimento …\PorteIO\switch
Scrivere un programma che accenda il led D0 se viene premuto lo switch SW1.
;DIRETTIVE
list
p=16f684
; direttiva list per definizione del processore
#include <p16f684.inc>
; definizione variabili specifiche processore
errorlevel -302
__CONFIG
_CP_OFF & _CPD_OFF & _MCLRE_OFF & _
WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT
;DEFINIZIONE COSTANTI E VARIABILI
#define TRIS_D0
B'00001111'
; impostazione TRISA per D0
#define D0_ON
B'00010000'
; output per D0 ON
#define D0_OFF
B'00000000'
; output per D0 OFF
;INIZIALIZZAZIONE
org
0x000
; vettore di reset del processore
goto
Initialize
org
0x005
; vettore di inizio del programma
Initialize
bsf
STATUS,RP0
; banco 1
movlw TRIS_D0
movwf TRISA
; programma porta IO per D0
;PROGRAMMA
bcf
STATUS, RP0
Inizio
btfsc PORTA,3
; testa il bit 3 della porta A
goto
Switch_OFF
movlw D0_ON
; switch premuto quindi accendi led
goto
Fine
Switch_OFF
movlw D0_OFF
; switch rilasciato quindi spegni led
Fine
movwf PORTA
; invia dato su PORTA
goto
Inizio
end
In questo esempio l’istruzione btfsc implementa un costrutto if –
else. Se il bit 3 della porta A vale 0 (pulsante premuto mette a
massa) viene saltata l’istruzione goto Switch_OFF quindi viene
eseguita la movlw D0_ON che predispone il led all’accensione. In
caso contrario viene eseguita la movlw D0_OFF, che predispone il
led allo spegnimento. In entrambi i casi si confluisce all’istruzione
movwf PORTA, che perfeziona la scrittura sulla porta.
Il diagramma di flusso a fianco illustra il concetto.
Esercizi
es1
Scrivere un programma che accenda i Led D0 e D1. Data la struttura circuitale
l'accensione non può essere contemporanea. Il programma prevede pertanto un ciclo
continuo entro il quale si alterna continuativamente l'accensione di D0 a quella di D1.
E' sufficiente una sola programmazione della porta TRISA, valida per entrambi i diodi.
SI
bit 3 PORTA
=0 ?
if
NO
else
W=D0_ON
W=D0_OFF
WPORTA
es2
Scrivere un programma che accenda i Led D0 e D1 se premuto lo switch. Seguire la traccia dell'esempio, integrando quanto
visto nell'es.1 per ciò che attiene il comando di due diodi.
es3
Scrivere un programma che accenda i Led D4 e D5 se premuto lo switch, altrimenti accenda i led D0 e D1.
Il codice alterna la programmazione del registro TRISA per la coppia D0_D1 a quella per la coppia D4_D5.
La programmazione del TRISA non avviene pertanto in un'unica soluzione all'inizio del programma, ma è presente nel corpo
del ciclo. Data la presenza di accessi al TRISA seguiti da accessi al PORTA, viene effettuata la commutazione continua tra
banco 0 e banco 1.
es4
Scrivere un programma che commuti tra Led0 e Led1 ad ogni pressione del tasto.
E' presente la dichiarazione di un blocco di memoria RAM con la variabile CONTATORE. Contatore funge da variabile di
stato, mantenendo in memoria lo stato acceso o spento del diodo. Alla pressione del tasto se CONTATORE=0 il
programma, tramite le istruzioni incf CONTATORE,1 e movlw D0_ON incrementa il contatore e accende D0. Se
CONTATORE=1 esso viene decrementato e viene acceso D1.
Il controllo del valore di CONTATORE viene attuato dalle istruzioni movlw .1
xorwf CONTATORE,0 btfsc
STATUS,Z. L'istruzione xorwf esegue l'EX_OR tra W, che è posto a 1 nell'istruzione precedente e CONTATORE.
Se CONTATORE è pari a 1 il flag di zero viene settato; questa condizione viene testata dall'istruzione btfsc.
28
TIMER
Il timer è un dispositivo dedicato utilissimo per la temporizzazione delle funzioni del microcontrollore. Esso
affianca il microprocessore e opera facendosi carico di gestire i ritardi temporali, senza appesantire il carico del
microprocessore.
Il PIC16F684 dispone di tre timer; Timer0, Timer1 e Timer2; nelle nostre applicazioni utilizzeremo quasi sempre
il Timer0.
L’unità base del Timer0 è il registro TMR0 (TiMeR0) a 8 bit. Esso ha funzione di contatore: viene infatti
incrementato ad ogni periodo del clock interno (è possibile anche impostare un clock esterno), assumendo i
valori 0, 1, 2, 3, …, fino a 255. Questo è il valore di saturazione per un registro a 8 bit, al clock successivo il
registro effettua un overflow e riprende il suo conteggio da 0.
T0IF
7
6
5
4
3
2
1
0
7
6
5
4
3
2 1 0
fOSC/4
INTCON
TMR0 0, 1, 2, …, 255 0
prescaler 1/2
prescaler 1/4
prescaler 1/8
L’evento di overflow influisce su un bit del registro INTCON, il bit T0IF (Timer 0 Interrupt Flag) il quale subisce
una transizione da 0 a 1. Il flag T0IF funge quindi da spia, segnalando (flag significa appunto bandiera,
segnalatore) l’avvenuto overflow. Il programmatore, per avvalersi del timer, nota la frequenza del clock fosc/4,
imposta il valore del registro TMR0 per un ritardo base. Farà poi incrementare una variabile di conteggio ad
ogni overflow. Il prodotto di questa variabile per il tempo richiesto per ciascun overflow fornirà il tempo di ritardo
totale.
Il tempo di ritardo può essere eventualmente amplificato mediante il prescaler. Il prescaler è un divisore di
frequenza, esso riceve in ingresso la frequenza fosc/4 e la restituisce divisa per 2, 4, 8…, fino a 256. Il fattore di
divisione può essere programmato tramite la combinazione di tre bit PS2, PS1, PS0 del registro OPTION_REG.
Si riporta di seguito questo registro con la specifica del significato dei bit e la tabella del fattore di divisione del
prescaler.
OPTION_REG - REGISTRO OPZIONI (INDIRIZZO: 81h)
7
RAPU
6
5
4
3
2
1
0
INTEGD
TOCS
TOSE
PSA
PS2
PS1
PS0
bit 7
RAPU: PORTA PUll-up enable bit (bit abilitazione pull-up porta A)
1 = PORTA pull-ups disabilitati
0 = PORTA pull-ups abilitati dai valori di latch individuali presenti nel registro WPUA
bit 6
INTEDG: INTerrupt EDGe select bit (bit selezione fronte interrupt)
1 = Interrupt sul fronte di salita del pin RA2/INT
0 = Interrupt sul fronte di discesa del pin RA2/INT
bit 5
T0CS: TMR0 Clock Source select bit (bit selezione sorgente del clock)
1 = Transizione sul pin RA2/TOCKI
0 = Clock del ciclo istruzioni interne
bit 4
T0SE: TMR0 Source Edge select bit (bit selezione fronte sorgente TMR0)
1 = Incremento sul fronte di discesa del pin RA2/TOCKI
0 = Incremento sul fronte di salita del pin RA2/TOCKI
bit 3
PSA: PreScaler Assignment bit (bit assegnamento prescaler)
1= Il prescaler è assegnato al WDT
0 = Il precaler è assegnato al modulo Timer0
bit 2-0
PS<2-0>: bits di selezione del fattore di divisione
Valore Bit
000
001
010
011
100
101
110
111
Periodo TMR0
1:2
1:4
1:8
1 : 16
1 : 32
1 : 64
1 : 128
1 : 256
Compreso il funzionamento di principio del timer dedichiamoci ora ad approfondire l’aspetto matematico del
calcolo dei tempi di ritardo.
Il clock del PIC16F684 può essere programmato fino a un massimo di 8MHz, ma è impostato di default a 4MHz,
risulta pertanto:
6
f osc / 4 =
4 ⋅ 10
= 1MHz
4
periodo base =
1
= 10 − 6 = 1µ sec
6
1 ⋅ 10
29
Il tempo impiegato per raggiungere l’overflow dipende dal valore di TMR0 impostato. Quanto maggiore è TMR0
tanto minore è il numero di cicli necessari per giungere a 255. Si ha dunque:
tempo ritardo base = 1µsec ⋅ (256 - TMR0)
Per TMR0=0, impostando il prescaler a 32, si verifica un ritardo massimo di: 1µsec⋅256 ⋅ 32 = 8,192msec
Per ritardi maggiori si deve ripetere il conteggio più volte, impostando un ciclo mediante una variabile di tipo
contatore.
Ad esempio per il ritardo di 1 secondo deve essere:
CONTATORE =
1sec
= 122
8,192msec
Si riporta ora il programma per il ritardo di 1 secondo.
ritardo
movlw
movwf
loopesterno
clrf
bcf
loopinterno
btfss
goto
decfsz
goto
return
end
.122
CONTATORE
; ritardo di 1 secondo
TMR0
INTCON,T0IF
; resetta registro timer
; resetta flag timer
INTCON,T0IF
loopinterno
CONTATORE,1
loopesterno
; attendi se flag timer non settato
; decrementa contatore ritardo
Il programma inizializza CONTATORE a 122, cancella TMR0 e T0IF che potrebbe risultare settato da un
precedente overflow e rimane in attesa entro un ciclo di nome loopinterno. L’attesa finisce quando giunge
l’overflow, in questo caso infatti l’istruzione btfss (Bit Test File Skip Set) provoca il salto dell’istruzione goto
loopinterno e l’esecuzione di decfsz (Decrement File Skip Zero). Questa decrementa la variabile contatore; se
essa è maggiore di zero si verifica un salto indietro a loopesterno e si ripete un nuovo ciclo del timer, altrimenti
si esce dalla subroutine di ritardo.
Di seguito è riportato lo schema reale del timer.
Bus Dati
CLKOUT
(=FOSC/4)
8
0
1
1
TOCKI
pin
0
TOSE
1
0
SYNC 2
Cycles
TMR0
Prescaler
8-bit
Imposta a 1 il flag bit
TOCS
PSA
8
PSA
dal WDT
T0IF
quando si verifica
OVERFLOW
dal WDT
PS<2:0>
Si nota la presenza di TMR0 e T0IF. Inoltre è presente il bit PSA, che come visto in precedenza appartiene al
registro OPTION_REG. Il PSA deve essere impostato a 0 affinchè il prescaler venga assegnato al modulo
Timer0 e non al modulo WDT Watchdog Timer (linee tratteggiate che vanno alla parte di schema mancante). Il
termine PS<2:0> indica i tre bit PS2, PS1, PS0 di OPTION_REG, per la selezione di una tra le 8 uscite del
prescaler.
Infine compaiono i bit T0CS e T0SE del registro OPTION_REG. Il T0CS (TMR0 Clock Source select Bit) se
programmato a 0 specifica che la sorgente del clock è interna, in tal caso si verifica il normale funzionamento da
timer. Se invece il T0CS viene programmato a 1 il clock viene prelevato dal pin T0CKI (Timer 0 ClocK Input).
In questo caso il dispositivo funge da contatore e può essere utile per registrare in TMR0 un certo numero di
eventi esterni, come i fronti d’onda di una cellula fotoelettrica adibita al conteggio di pezzi. Il bit T0SE definisce
se il conteggio debba avere luogo sul fronte di discesa o di salita di questa onda.
30
Esperimento …\Timer\Ledonoff
Scrivere un programma che accenda il Led D0 ad intermittenza, ad intervalli di 1 secondo.
;DIRETTIVE
list
p=16f684
; direttiva list per definizione del processore
#include <p16f684.inc>
; definizione variabili specifiche processore
errorlevel -302
__CONFIG
_CP_OFF & _CPD_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON &
_INTRC_OSC_NOCLKOUT
;DEFINIZIONE COSTANTI E VARIABILI
#define TRIS_D0
B'00001111' ; impostazione TRISA per D0
#define D0_ON
B'00010000' ; output per D0 ON
#define D0_OFF
B'00000000' ; output per D0 OFF
cblock 0x20
CONTATORE
; contatore per ritardo
endc
;INIZIALIZZAZIONE
org
0x000
; vettore di reset del processore
goto
Initialize
org
0x005
; vettore di inizio del programma
Initialize
bsf
STATUS,RP0
; banco 1
movlw B'10000100'
; clock timer interno, prescaler 1/32
movwf OPTION_REG
; overflow in 8.2ms
movlw TRIS_D0
movwf TRISA
; programma porta IO
;PROGRAMMA
bcf
STATUS, RP0
Inizio
movlw D0_ON
movwf PORTA
; accendi led
call
ritardo
movlw D0_OFF
movwf PORTA
; spegni led
call
ritardo
goto
Inizio
;SOTTOPROGRAMMA
ritardo
movlw .122
movwf CONTATORE
loopesterno
clrf
TMR0
bcf
INTCON,T0IF
loopinterno
btfss INTCON,T0IF
goto
loopinterno
decfsz CONTATORE,1
goto
loopesterno
return
end
; ritardo di 1 secondo
; resetta registro timer
; resetta flag timer
; attendi se flag timer non settato
; decrementa contatore ritardo
Esercizi
es1
Scrivere un programma che accenda i Led D0 e D1 a intermittenza, a intervalli di 1 secondo.
Programmare TRISA una sola volta per entrambi i diodi.
es2
Scrivere un programma che accenda i Led D0, D1, D2, D3, D4, D5, D6, D7 in sequenza, ad intervalli di 1 secondo.
I diodi vanno programmati a coppie, ovvero D0_D1, D2_D3, D4_D5, D6_D7, mediante 4 istruzioni TRISA.
A ciascuna di queste seguono due istruzioni su PORTA per l'accensione di un singolo led della coppia.
es3
Scrivere un programma che accenda i Led D0, D5, D2, D7, D3, D6, D1, D4 in sequenza, ad intervalli di 1 secondo. Per
ciascun led è necessario in questo caso programmare diversamente TRISA, in quanto le coppie di led adiacenti nella
sequenza appartengono a sezioni diverse nel circuito.
es4
Scrivere un programma che accenda in sequenza D4, D5, D6, D7 se lo Switch è premuto, altrimenti accenda in sequenza
D0, D1, D2, D3. Impiegare l'istruzione btfsc PORTA,3 per l'implementazione dell'if.
31
DISPLAY
Il Laboratorio ha in dotazione una scheda di espansione, da innestare nella schedina del PICKit1,
comprendente due display a 7 segmenti a catodo comune e due integrati 9368 per il loro pilotaggio.
Ogni integrato riceve sui suoi quattro ingressi DCBA la combinazione binaria del numero da visualizzare.
La sezione delle unità riceve i bit dalla Porta C, quella delle decine dalla porta A. Tuttavia poichè l’uscita RA3
non può fungere da output, la sezione delle decine si collega solo a tre pin, il quarto più significativo, cioè D, è
collegato permanentemente a massa. Il numero massimo configurabile sulle decine è pertanto 7 (111 binario).
Si veda la tabella che segue per una indicazione esaustiva dei collegamenti.
decine
C
B
RA2 RA1
4
5
6
7
8
9
10
11
12
13
DECINE
UNITA’
A
RC0
RA5
RA4
RA3
RC5
RC4
RC3
RA0
+5 f g a b c d
RA1
RA2
B C LT
D A
e
Vcc f g a b c d
B C LT
D A
e
GND
3
unità
C
B
RC2 RC1
RBO
RBI
2
D
RC3
GND
1
A
RA0
RBO
RBI
D
0
RC0
RC1
+5
+5
RC2
+5
13
Esperimento …\Display\contat
Scrivere un programma che effettui un conteggio da 0 a 7 sul display delle unità.
Il programma dichiara una variabile NUMERO per la conservazione dello stato del conteggio. NUMERO viene incrementato
ogni secondo e azzerato quando vale 8 mediante le istruzioni movlw .8; xorwf NUMERO,0; btfsc STATUS,Z e clrf NUMERO.
L'istruzione xorwf confronta NUMERO con 0: se sono uguali pone il flag Z a zero. L'istruzione btfsc testa Z: se esso risulta
settato viene cancellato NUMERO con l'istruzione clrf.
DIRETTIVE
list
p=16f684
; direttiva list per definizione del processore
#include <p16f684.inc>
; definizione variabili specifiche processore
errorlevel -302
__CONFIG
_CP_OFF & _CPD_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON &
_INTRC_OSC_NOCLKOUT
;DEFINIZIONE COSTANTI E VARIABILI
cblock 0x20
CONTATORE
; contatore per ritardo
NUMERO
; variabile di conteggio
endc
;INIZIALIZZAZIONE
org
0x000
; vettore di reset del processore
goto
Initialize
org
0x005
; vettore di inizio del programma
Initialize
bsf
STATUS, RP0
; banco 1
movlw B'10000100'
; clock timer interno, prescaler 1/32
movwf OPTION_REG
; overflow in 8.2ms
clrf
ANSEL
; I/O digitale
movlw 0x00
movwf TRISC
; programma porta C per tutti i pin output
bcf
STATUS, RP0
; banco 0
movlw .0
; inizializza conteggio
movwf NUMERO
;PROGRAMMA
Inizio
movfw NUMERO
movwf PORTC
; numero in output su unità
32
call
incf
movlw
xorwf
btfsc
clrf
goto
ritardo
NUMERO,1
.8
NUMERO,0
STATUS,Z
NUMERO
Inizio
; incrementa numero
; se numero=8 riprende il conteggio da 0
; salta se Z=0
; azzera numero
;SOTTOPROGRAMMA
ritardo
movlw .122
movwf CONTATORE
loopesterno
clrf
TMR0
bcf
INTCON,T0IF
loopinterno
btfss INTCON,T0IF
goto
loopinterno
incfsz CONTATORE,1
goto
loopesterno
return
end
; ritardo di 1 secondo
; resetta registro timer
; resetta flag timer
; attendi se flag timer non settato
; incrementa contatore ritardo
Esercizi
es1
Scrivere un programma che effettui un conteggio da 0 a 7 contemporaneamente sul display delle unità e delle decine.
Procedere come nell’esperimento.
es2
Scrivere un programma che effettui un conteggio da 4 a 8 sul display delle unità.
Per bloccare il conteggio a 8 verificare quando NUMERO vale 9 mediante l'istruzione xorwf NUMERO,
che setta il flag Z nel caso di uguaglianza. Con l'istruzione btfss STATUS,Z effettuare il test;
nel caso Z=1 si deve porre NUMERO=4 per riprendere il conteggio da capo.
L’algoritmo risponde al seguente diagramma di flusso di tipo “if”. a fianco è riportato lo stralcio di programma riguardante il
test su NUMERO.
if
SI
NUMERO
=9 ?
NUMERO=4
NO
movlw
.9
xorwf
NUMERO,0
btfss
STATUS,Z
goto notnove
movlw
.4
movwf
NUMERO
notnove
goto
Inizio
; confronta NUMERO con 9
; salta se Z=0
goto Inizio
es3
Scrivere un programma che effettui un conteggio da 0 a 59. Il programma testa
la cifra delle unità; quando questa raggiunge dieci viene forzata a 0. Parimenti
quando la cifra delle decine raggiunge sei viene forzata a zero.
I test sui valori delle cifre vengono condotti con l'abbinamento tra l'istruzione
xorwf e btfss.
L’algoritmo risponde al diagramma di flusso a fianco.
es4
Scrivere un programma che effettui il conteggio a singola cifra dei numeri pari
alternati a quelli dispari.
Per generare queste sequenze il programma incrementa due volte NUMERO.
Vengono effettuati due test su NUMERO. Nel primo, durante il conteggio
dispari, quando NUMERO raggiunge 11 viene forzato a zero.
Nel secondo, durante il conteggio pari, se raggiunge 10 viene forzato a uno.
if
SI
UNITA
=9 ?
NO
UNITA=0
if
SI
DECINE
=6 ?
NO
DECINE=0
goto Inizio
33
AUDIO
L’onda audio è una variazione di pressione prodotta
generalmente dall’oscillazione di una membrana che
sposta all’unisono le particelle di aria che la
circondano. Nel caso di un sistema digitale come il
microprocessore è possibile generare onde quadre,
ovvero onde costituite da una alternanza di ‘0’ e ‘1’. Il
dispositivo più economico per la riproduzione, che
non necessita di amplificazione è il buzzer.
GND
PIC
RA0
BUZZER
call ritardo
bsf PORTA,0
Variando la frequenza dell’onda quadra varierà il tono del
bcf PORTA,0
segnale audio prodotto. Verrà utilizzato come uscita il pin 0 della
porta A, cioè RA0. Un programma per la generazione di onde
quadre deve prevedere una sezione di base in grado di
call ritardo
generare un singolo periodo di onda quadra. E’ sufficiente per
questo utilizzare due istruzioni, la bcf PORTA,0 per impostare
RA0=0 e la bsf PORTA,0 per impostare RA=1 e interporre tra
queste dei ritardi di durata opportuna, come descritto dalla figura
a fianco.
Il ritardo si ottiene con il Timer. Per il calcolo del tempo di ritardo si ricorre alla formula del Timer, che qui
riportiamo:
tempo ritardo base = 1µsec ⋅ (256 - TMR0)
Studiamo il problema del calcolo con riferimento a due casi concreti: una frequenza f1=320Hz e una f2=480Hz
Risulta:
periodo del segnale di 320Hz = T1=1/320 = 3125 µsec
T1/2=1562 µsec
periodo del segnale di 480Hz = T2=1/480 = 2083 µsec
T2/2=1041 µsec
Impostando il prescaler a 1/8 il tempo di ritardo base viene amplificato di 8 volte; si può ora calcolare i valore da
impostare in TMR0 nei due casi:
8 ⋅ ( 256 – TMR0 ) = 1562
8 ⋅ ( 256 – TMR0 ) = 1041
256 – TMR0 = 195
256 – TMR0 = 130
TMR0 = 61
TMR0 = 126
Inserendo la sezione del programma che genera un singolo periodo entro un ciclo, si produce un’onda
continuativa.
Esperimento …\Audio\tono
Scrivere un programma che generi sul pin RA0 numero 0 di PORTA un tono fisso di 320Hz oppure di 480Hz.
Per impostare la durata del ritardo (semiperiodo) si devono assegnare a TMR0 rispettivamente i valori 61 oppure 126.
;DIRETTIVE
list
p=16f684
; direttiva list per definizione del processore
#include <p16f684.inc>
; definizione variabili specifiche processore
errorlevel -302
__CONFIG _CP_OFF & _CPD_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON &
_INTRC_OSC_NOCLKOUT
;INIZIALIZZAZIONE
org
0x000
; vettore di reset del processore
goto
Initialize
org
0x005
; vettore di inizio del programma
Initialize
bsf
STATUS,RP0
; banco 1
movlw B'10000010'
; clock timer interno, prescaler 1/8
movwf OPTION_REG
movlw .0
movwf TRISA
; tutti i pin di output
;PROGRAMMA
bcf
STATUS, RP0
Inizio
bcf
PORTA,0
; imposta RA0=0
call
ritardo
bsf
PORTA,0
; imposta RA0=1
call
ritardo
goto
Inizio
;SOTTOPROGRAMMA
ritardo
movlw .126
movwf TMR0
bcf
INTCON,T0IF
; imposta registro timer
; resetta flag timer
34
loopinterno
btfss
goto
return
end
INTCON,T0IF
loopinterno
; attendi se flag timer non settato
Per generare suoni più ricchi di sfumature rispetto al semplice tono continuo di frequenza fissa è necessario
intervallare onde di diversa frequenza, quindi utilizzare differenti tempi di ritardo. In questo casi si lavora con un
singolo sottoprogramma di ritardo che può essere reso variabile modificando il o i suoi registri di conteggio.
Questi vengono spostati dal corpo del sottoprogramma entro il programma principale, dove diventano parametri
che possono essere impostati di volta in volta per programmare il ritardo desiderato. Questi tipi di
sottoprogrammi si chiamano sottoprogrammi di ritardo parametrici. Il vantaggio del loro impiego è dato dalla
possibilità di impostare tempi di ritardo diversi in diverse sezioni del programma principale, sfruttando un solo
sottoprogramma di ritardo.
Di seguito sono riportati due programmi: nel primo il registro TMR0 è impostato nel corpo del sottoprogramma,
pertanto il ritardo è prefissato e non modificabile. Nel secondo TMR0 è impostato nel programma principale,
pertanto il medesimo sottoprogramma produce ritardi diversi in funzione del valore di TMR0 impostato nel
programma principale. In grassetto sono indicate le istruzioni modificate nei due casi.
Programma principale che richiama un
sottoprogramma di ritardo parametrico
Programma principale che richiama un
sottoprogramma di ritardo fisso
……………………
……………………
call ritardo
……………………
ritardo
movlw. 125
movwf TMR0
bcf
INTCON,T0IF ; resetta flag timer
loopinterno
btfss
INTCON,T0IF ; attendi se flag
timer non settato
goto
loopinterno
return
……………………
……………………
movlw. 125
movwf TMR0
call ritardo
……………………
ritardo
bcf
INTCON,T0IF ; resetta flag timer
loopinterno
btfss
INTCON,T0IF ; attendi se flag
timer non settato
goto
loopinterno
return
Esercizi
es1
L’onda del tono di chiamata telefonica è un’onda composita, di durata 1 secondo, seguita da due secondi di sospensione.
Essa risponde quindi al seguente grafico:
1sec
2 sec silenzio
Magnificando la parte composita, riportata di seguito, si possono evidenziare alcune caratteristiche importanti.
T1
12 impulsi
25msec
T2
8 impulsi
12 impulsi
8 impulsi
25msec
35
L’onda è composta da una successione di 20 treni di onde di durata 25msec, caratterizzate da due frequenze diverse:
320Hz e 480Hz.
I periodi delle due onde li conosciamo già, ne riportiamo qui il calcolo:
inizializza
TMR0=126
CICLI=12
periodo del segnale di 480Hz = T1=1/480 = 2083 µsec
T1/2=1041 µsec
TMR0 = 126
periodo del segnale di 320Hz = T2=1/320 = 3125 µsec
TMR0 = 61
T2/2=1562 µsec
movlw
movwf
movlw
movwf
.126
TMR0
.12
CICLI
bcf PORTA,0
RA0=0
Possiamo allora ricavare il numero di impulsi replicati in 25msec:
n° impulsi onda 480Hz:
n° impulsi onda 320Hz:
call ritardo
25msec / 2083µsec = 12
25msec / 3125µsec = 8
bsf PORTA,0
RA0=1
Scrivere un programma che generi continuativamente sul pin RA0 12 cicli di 480Hz
seguiti da 8 cicli di 320Hz.
call ritardo
A fianco come ausilio è riportata la struttura del programma; parallelamente al
diagramma di flusso sono specificate le istruzioni di implementazione.
Per impostare la durata del ritardo (semiperiodo) vengono assegnati a TMR0
rispettivamente i valori 126 oppure 61.
Il programma utilizza una variabile CICLI per conservare il numero delle ripetizioni.
Il controllo del numero di ripetizioni è affidato all'istruzione decfsz.
TMR0 deve essere inizializzato prima di ogni chiamata a "ritardo", in quando questa
subroutine lo altera.
decrementa
CICLI
NO
CICLI=0 ?
decfsz
CICLI
goto
periodoT1
………………..
………………..
es2
SI
Estendere il programma di generazione del tono telefonico in modo che produca 1
secondo di segnale seguito da 2 secondi di silenzio.
Il conteggio dei 2 secondi è effettuato dal Timer1, in quanto il Timer 0 è impegnato
nella generazione delle onde sonore.
Il programma, dopo aver prodotto un ciclo d'onda, la itera per 20 volte. Il numero di
iterazioni è conservato nella variabile RIPETIZIONI.
L'istruzione decfsz RIPETIZIONI seguita da goto ripetizioni provvede a rinviare il
flusso all'inizio se RIPETIZIONI>0.
Segue l'istruzione call ritardotimer2 che invoca il ritardo di 2 secondi.
Il Timer1 dispone di un registro a 16 bit formato da una parte alta TMR1H e una
bassa TMR0L.
L'overflow viene raggiunto al valore 65536, pertanto la formula del Timer1, sulla
base delle considerazioni fatte per Timer0 è:
inizializza
TMR0=61
CICLI=8
RA0=0
call ritardo
RA0=1
1 microsec ( 65536 - TMR1H_TMR1L )
call ritardo
Se decidiamo di impostare TMR1H_TMR1L=0 risulta un ritardo a ciclo di
65,325msec.
Per un ritardo di 2 secondi sono quindi richiesti 2 / 65,326msec = 30 cicli.
L'overflow viene segnalato dal bit TMR1IF (Timer 1 Interrupt Flag) del registro PIR1.
Il programma lo testa con l'istruzione btfss PIR1,TMR1IF.
Finchè TMR1IF non è settato effettua un salto indietro e riazzera TMR1H, TMR1L,
altrimenti incrementa il contatore CONTATORE del ciclo esterno e itera tutte le volte
che CONTATORE<30.
es3
decrementa
CICLI
NO
CICLI=0 ?
SI
La frequenza della nota LA della ottava centrale è convenzionalmente fissata a 440Hz.
Noto che il rapporto tra le frequenze della stessa nota nella ottava superiore è 1:2,
possiamo calcolare le frequenze di tutte le note.
Le note base sono 7, questo è noto a tutti, ma se si considerano i diesis diventano 12,
intervallate dallo stesso semitono.
Considerata la divisione dell’ottava in 12 intervalli e il rapporto 1:2 si avrà che tra una
qualsiasi nota e la sua successiva esiste la relazione:
f ( nota sup) = f ( nota inf) ⋅ 2
1
12
= f ( nota inf) ⋅ 2 0 , 083 = 1,059
Ad esempio: rispetto al LA a 440 Hz, la frequenza del LA# (LA diesis) è:
440 ⋅ 1,059 = 466 Hz
quella de Si è:
466 ⋅ 1,059 = 494 Hz
Si riporta la tabella completa delle frequenze.
36
NOTA
FREQ
NOTA
FREQ
NOTA
FREQ
NOTA
FREQ
NOTA
FREQ
NOTA
FREQ
DO2
66 Hz
DO3
131 Hz
DO4
262 Hz
DO5
523 Hz
DO6
1046 Hz
DO7
2093 Hz
DO#2
70 Hz
DO#3
139 Hz
DO#4
277 Hz
DO#5
554 Hz
DO#6
1109 Hz
DO#7
2217 Hz
RE2
74 Hz
RE3
147 Hz
RE4
294 Hz
RE5
587 Hz
RE6
1175 Hz
RE7
2349 Hz
RE#2
78 Hz
RE#3
156 Hz
RE#4
311 Hz
RE#5
622 Hz
RE#6
1245 Hz
RE#7
2489 Hz
MI2
83 Hz
MI3
165 Hz
MI4
330 Hz
MI5
659 Hz
MI6
1319 Hz
MI7
2637 Hz
FA2
88 Hz
FA3
175 Hz
FA4
349 Hz
FA5
698 Hz
FA6
1397 Hz
FA7
2794 Hz
FA#2
93 Hz
FA#3
185 Hz
FA#4
370 Hz
FA#5
740 Hz
FA#6
1480 Hz
FA#7
2960 Hz
SOL2
98 Hz
SOL3
196 Hz
SOL4
392 Hz
SOL5
784 Hz
SOL6
1568 Hz
SOL7
3136 Hz
3322 Hz
SOL#2
104 Hz SOL#3
208 Hz
SOL#4
415 Hz
SOL#5
831 Hz
SOL#6
1661 Hz
SOL#7
LA2
110 Hz
LA3
220 Hz
LA4
440 Hz
LA5
880 Hz
LA6
1760 Hz
LA7
3520 Hz
LA#2
117 Hz
LA#3
233 Hz
LA#4
466 Hz
LA#5
932 Hz
LA#6
1865 Hz
LA#7
3729 Hz
SI2
124 Hz
SI3
247 Hz
SI4
494 Hz
SI5
988 Hz
SI6
1976 Hz
SI7
3951 Hz
DO8
4186 Hz
Per far suonare il microprocessore si deve generare, per ogni nota, un insieme di periodi di onda quadra, avvalendosi di un
tempo di ritardo di un semiperiodo. All’aumentare della frequenza dell’onda, aumenta il numero di cicli necessari per una
nota di durata prefissata. Nell’ipotesi di una durata di 1 secondo, per il DO3 risulta:
fDO3 = 131Hz
TDO3 = 7634 µsec
Cicli = 1 / 7634 µsec = 130
TDO3/2 = 3817
Con un prescaler di 1/16 si ha:
16 ⋅ ( 256 – TMR0 ) = 3817
NOTA
FREQ
DO3
DO#3
RE3
RE#3
MI3
FA3
FA#3
SOL3
SOL#3
LA3
LA#3
SI3
131
139
147
156
165
175
185
196
208
220
233
247
Hz
Hz
Hz
Hz
Hz
Hz
Hz
Hz
Hz
Hz
Hz
Hz
PERIODO T
7634 µsec
7194 µsec
6803 µsec
6410 µsec
6061 µsec
5714 µsec
5405 µsec
5102 µsec
4808 µsec
4545 µsec
4292 µsec
4049 µsec
256 – TMR0 = 239
CICLI
131
139
147
156
165
175
185
196
208
220
233
247
TMR0 = 17
T/2
3817
3597
3401
3205
3030
2857
2702
2551
2404
2272
2146
2024
TMR0
17
31
43
56
67
77
87
96
105
114
121
129
Scrivere un programma che generi una nota di 131Hz alternata a una di 247Hz, entrambe di durata 1 secondo.
Il segmento di programma che genera una singola nota deve prevedere l'inizializzazione del numero di cicli e della durata
dei semiperiodi.
Questa viene impostata in TMR0, il quale va inizializzato prima di ogni istruzione call ritardo, in quanto il sottoprogramma
ritardo ne altera il valore. I due segmenti per le due note sono strutturalmente uguali fra loro; il diagramma di flusso è lo
stesso dell’esercizio 1.
es4
Scrivere lo stesso programma dell’esercizio 3 utilizzando un solo ciclo di generazione del treno di onde per entrambe le
frequenze.
Si deve ricorrere all’utilizzo di sottoprogrammi, uno per la generazione del ritardo e uno per la generazione di un treno di
onde. Quest’ultimo deve essere parametrico, cioè deve ricevere dall’esterno, in forma di parametri, gli elementi per la
specificazione della frequenza e del numero di cicli, che sono rispettivamente TMR0 e CICLI.
Si riporta di seguito il sottoprogramma:
nota
movfw
movwf
bcf
call
movfw
movwf
bsf
call
decfsz
goto
return
MEMREG
TMR0
PORTA,0
ritardo
MEMREG
TMR0
PORTA,0
ritardo
CICLI,1
nota
;Ripristina TMR0 con il contenuto di MEMREG
; imposta RA0=0
;Ripristina TMR0 con il contenuto di MEMREG
; imposta RA0=1
;salta a nota se CICLI>0
37
In esso il registro TMR0 viene utilizzato due volte e la seconda volta risulta alterato. E’ necessario allora disporre il suo
valore entro una variabile di nome MEMREG, che viene inizializzata nel programma principale e permette di ripristinare ogni
volta il corretto valore di TMR0, mediante le istruzioni movfw MEMREG e movwf TMR0.
es5
In base alla struttura dell’esercizio 5, scrivere un programma che sintetizzi una breve melodia.
Si provi ad esempio con la seguente sequenza:
MI
MI
MI
FA
FA
MI
SOL
MI
MI
SOL
FA
MI
RE
MI
MI
DO
FA
MI
RE
RE
MI
MI
RE
Copiare le seguenti costanti nel programma, per sveltirne lo sviluppo:
#define DO3_CICLI
#define DO#3_CICLI
#define RE3_CICLI
#define RE#3_CICLI
#define MI3_CICLI
#define FA3_CICLI
#define FA#3_CICLI
#define SOL3_CICLI
#define SOL#3_CICLI
#define LA3_CICLI
#define LA#3_CICLI
#define SI3_CICLI
#define DO3_TMR0
#define DO#3_TMR0
#define RE3_TMR0
#define RE#3_TMR0
#define MI3_TMR0
#define FA3_TMR0
#define FA#3_TMR0
#define SOL3_TMR0
#define SOL#3_TMR0
#define LA3_TMR0
#define LA#3_TMR0
#define SI3_TMR0
.131
.149
.167
.156
.195
.175
.185
.196
.208
.220
.233
.247
.17
.31
.43
.56
.67
.77
.87
.96
.105
.114
.121
.129
38
ADC
Il convertitore Analogico Digitale A/D implementa la conversione di un segnale analogico nella sua
rappresentazione binaria a 10 bit. La funzionalità del dispositivo è controllata dai tre registri ANSEL, ADCON0,
ADCON1, riportati più avanti. Di seguito è riportato lo schema interno del dispositivo.
VCFG=0
VDD
VREF
VCFG=1
RA0/AN0
RA1/AN1/VREF
RA2/AN2
RA4/AN3
RC0/AN4
RC1/AN5
RC2/AN6
RC3/AN7
10
A/D
GO/DONE
ADFM
ADON
10
VSS
ADRESH ADRESL
CHS<2:0>
In esso si distinguono otto ingressi analogici, multiplexati con i pin di PORTA. Per abilitare un pin al
funzionamento come input analogico si deve settare il corrispondente bit del registro ANSEL (ANalogic
SELect=Selezione Analogica). Occorre inoltre impostare il pin come input, tramite il registro TRISA.
La selezione dell’ingresso analogico avviene mediante i tre bit ADCON0<4:2>.
Il bit VCFG (ADCON0<6>) permette di selezionare una tensione di riferimento esterna (input RA1/AN1/VREF ) o
interna (VDD).
Il bit ADON <ADCON0<0> abilita il funzionamento dell’AD.
La conversione viene avviata portando alto il pin GO/DONE. Il ritorno di questo al livello basso segnala la fine
della conversione.
Il risultato della conversione impegna 10 bit dei due registri di 8 bit ADRESH e ADRESL. Sono disponibili due
formati per il dato convertito: giustificato a sinistra e giustificato a destra, come descritto nelle rispettive figure.
La selezione del formato è data dal bit ADFM (ADCON0<7>).
ADRESL
ADRESH
LSB
MSB
bit 7
bit 7
bit 0
bit 0
risultato giustificato a sinistra
non implementato: letto come ‘0’
ADRESL
ADRESH
LSB
MSB
bit 7
bit 7
bit 0
bit 0
risultato giustificato a destra
non implementato: letto come ‘0’
ANSEL – REGISTRO SELEZIONE ANALOGICA (INDIRIZZO: 91h)
riservato
riservato
5
4
3
2
1
0
ANS7
ANS6
ANS5
ANS4
ANS3
ANS2
ANS1
ANS0
bit 7-0
ANS<7:0>: ANalog Select bits (Bit di selezione analogica)
Selezione tra funzione analogica e digitale sui rispettivi pin AN<7:0>
1 = Input analogico. Il pin è assegnato all’input analogico
0 = I/O digitale. Il pin è assegnato alla porta digitale o a una funzione speciale
ADCON0 – REGISTRO DI CONTROLLO A/D (INDIRIZZO: 1Fh)
7
6
5
4
3
2
1
0
ADFM
VCFG
-----
CHS2
CHS1
CHS0
GO/DONE
ADON
bit 7-0
ADFM: A/D result ForMed Select bit (Bit di selezione formato risultato A/D)
1 = giustificato a destra
0 = giustificato a sinistra
bit 6
VCFG: Voltage Reference bit (bit tensione di riferimento)
1 = pin VREF
39
0 = VDD
bit 5
Non implementato (letto come ‘0’)
bit 4-2
CHS<2:0>: analog CHannel select bits (bits selezione canale analogico)
000 = Canale 00 (AN0)
001 = Canale 01 (AN1)
010 = Canale 02 (AN2)
011 = Canale 03 (AN3)
100 = Canale 04 (AN4)
101 = Canale 05 (AN5)
110 = Canale 06 (AN6)
111 = Canale 07 (AN7)
bit 1
GO/DONE: A/D convertion status bit (bit di stato della conversione)
1 = Conversione A/D in corso. Portando a 1 questo bit ha inizio la conversione.
Questo bit è automaticamente cancellato via hardware a completamento della conversione
0 = Conversione A/D non in corso/completata
bit 0
ADON: bit di avvio della conversione
1 = modulo convertitore A/D in funzione
0 = modulo convertitore A/D spento senza assorbimento di corrente
Esperimento …\ADC\convers
Scrivere un programma che accenda i Led D0 e D1 ad intermittenza, a intervalli regolabili tramite il trimmer RP1.
Il formato deve essere giustificato a sinistra per poter utilizzare solo gli 8 bit più significativi della conversione, presenti nel
registro ADRESH. I due meno significativi di ADRESL possono essere ignorati senza alcun errore, con la sola conseguenza
trascurabile di un minore grado di risoluzione.
Il valore di ADRESH, memorizzato nella variabile RESULTHI, viene passato entro il sottoprogramma di ritardo a
CONTATORE. Un alto valore del registro, conseguente a una ampia rotazione de trimmer, comporta un alto tempo di ritardo
e viceversa.
In fase di inizializzazione le istruzioni bsf TRISA,0 e bsf ANSEL,0 impostano AN0 come input analogico.
Le istruzioni movlw B'00000001' e movwf ADCON0 programmano il formato giustificato a sinistra, l’abilitazione del modulo
A/D e dell’ingresso AN0.
L’avvio della conversione è dato dall’istruzione bsf ADCON0,GO. L’istruzione btfsc ADCON0,GO mantiene in ciclo fino al
raggiungimento della fine conversione. A questo punto il risultato della conversione, presente in ADRESH, viene caricato
entro RESULTHI.
Il programma invia sulla PORTC il valore RESULTH, che può essere così monitorato.
;DIRETTIVE
list
p=16f684
; direttiva list per definizione del processore
#include <p16f684.inc>
; definizione variabili specifiche processore
errorlevel -302
__CONFIG
_CP_OFF & _CPD_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT
;DEFINIZIONE COSTANTI E VARIABILI
#define TRIS_D0_D1
B'00001111'
; impostazione TRISA per D0
#define D0_ON
B'00010000'
; output per D0 ON
#define D1_ON
B'00100000'
; output per D1 ON
cblock 0x20
CONTATORE
; contatore per ritardo
RESULTHI
; bit alto conversione
endc
;INIZIALIZZAZIONE
org
0x000
; vettore di reset del processore
goto
Initialize
org
0x005
; vettore di inizio del programma
Initialize
bsf
STATUS,RP0
; banco 1
movlw B'10000100'
; clock timer interno, prescaler 1/32
movwf OPTION_REG
; overflow in 8.2ms
movlw TRIS_D0_D1
movwf TRISA
; programma porta IO per D0_D1
bsf
TRISA,0
; programma RA0 come input
bsf
ANSEL,0
; imposta RA0 analogico
movlw 0x00
movwf TRISC
; programma porta C per tutti i pin output
bcf
STATUS, RP0
movlw B'00000001'
movwf ADCON0
; Vref=Vdd ADON
;PROGRAMMA
Inizio
conv
movlw
movwf
call
movlw
movwf
call
D0_ON
PORTA
ritardo
D1_ON
PORTA
ritardo
bsf
ADCON0,GO
; accendi led D0
; accendi led D1
; avvia conversione
40
btfsc
goto
movf
movwf
movf
movwf
ADCON0,GO
conv
ADRESH,0
RESULTHI
ADRESH
PORTC
goto
Inizio
;SOTTOPROGRAMMA
ritardo
movf
RESULTHI,0
movwf CONTATORE
loopesterno
clrf
TMR0
bcf
INTCON,T0IF
loopinterno
btfss INTCON,T0IF
goto
loopinterno
decfsz CONTATORE,1
goto
loopesterno
return
end
; attesa fine conversione
; poni parte significativa in WREG
; numero in output su unità
; ritardo funzione di RESULTHI
; resetta registro timer
; resetta flag timer
; attendi se flag timer non settato
; incrementa contatore ritardo
Esercizi
es1
Scrivere un programma che accenda i Led in sequenza a intervalli regolabili tramite il trimmer RP1.
Disporre le istruzioni di conversione entro un sottoprogramma. Questo deve essere richiamato per ogni led,
per tenere sempre aggiornato il ritardo dosato con RP1.
es2
Scrivere un programma che mostri sul display delle unità i numeri da 0 a F, proporzionatamente al grado di rotazione del
trimmer RP1.
Programmare il dispositivo ADC per il formato giustificato a sinistra, affinchè il risultato a 8 bit della conversione
si trovi nel registro ADRESH.
L'intervallo del risultato varia da 0 a 255, perciò prevede 256 scaglioni. Se lo si divide per 16 il numero di scaglioni si riduce
a 16. La divisione per 16 viene implementata mediante quattro istruzioni rrf, che fanno ruotare i bit di 4 posizioni a destra. In
tal modo il valore massimo 11111111 diventa 00001111, ovvero F, come richiesto dal problema. Tutti gli scaglioni si
contraggono proporzionatamente.
Inserire un piccolo ritardo prima della conversione per la stabilizzazione del convertitore.
41
INTERRUPT
Un microcontrollore che ha in carico l’esecuzione di un programma, svolge in sequenza le istruzioni
programmate, secondo un ordine predeterminato. Oltre ad assolvere a un flusso di lavoro “determinato”, il
microprocessore deve anche rispondere a richieste che gli giungono in modo casuale dai dispositivi con i quali
interagisce. Una periferica o un dispositivo facente parte del sistema coordinato dal microcontrollore possono
lanciare a esso una richiesta di servizio. Ad esempio, in un sistema di controllo della temperatura, un dispositivo
può comunicare una sopravvenuta condizione di allarme.
A fronte di una richiesta di servizio casuale, il microprocessore deve abbandonare il regime corrente e avviare
una procedura di gestione della richiesta di servizio.
Due sono le modalità con le quali il microcontrollore si dispone ad accogliere le richieste di servizio: il Polling e
l’Interrupt.
Con il Polling, che significa interrogazione, il controllo delle richieste segue uno schema prefissato: è lo stesso
programma in esecuzione sul microprocessore a prevedere una ricognizione periodica delle periferiche per
intercettare quelle con richieste di servizio pendenti. Il Polling è quindi un metodo software, il controllo è tutto a
carico del programma che periodicamente deve sospendere la sua normale esecuzione, per interrogare le
periferiche, dilatando i tempi di esecuzione.
è presente una
richiesta di servizio ?
Microcontrollore
Periferica
POLLING
????
Con l’Interrupt è il dispositivo a lanciare la richiesta di servizio. Questa viene ricevuta dall’hardware del
microcontrollore; il software non ha il compito di sondare le richieste di servizio, come nel Polling.
richiesta di servizio
Microcontrollore
Periferica
INTERRUPT
!!!!
Descriviamo il processo di interrupt:
1) Un dispositivo lancia sulla linea di interrupt, mediante un opportuno segnale, una richiesta di servizio
2) Il microcontrollore sospende il programma corrente e passa a eseguire la cosiddetta routine di gestione
dell’interrupt
3) Il microcontrollore ritorna a eseguire il programma corrente dal punto dove era stato interrotto
INTERRUPT
programma
POLLING
programma
è presente
una richiesta
di servizio ??
SI
routine di gestione
dell’interrupt
routine di gestione
della richiesta
NO
Il programma di gestione dell’interrupt individua il dispositivo che ha lanciato la richiesta, leggendo opportuni
registri che vengono alterati in caso di interrupt, e passa a soddisfare le richieste di servizio.
Il programma di gestione dell’interrupt si configura come una specie di salto a sottoprogramma. In effetti il
microcontrollore sospende un flusso di programmazione principale per passare a eseguire una routine
straordinaria. Ma c’è una importante differenza: il salto a sottoprogramma è un passaggio predeterminato a
livello software, collocato in una ben determinata sezione del programma. L’interrupt è invece un evento
casuale, hardware, che può essere sollevato in qualsiasi sezione del programma in esecuzione.
Per comprendere totalmente i concetti ora espressi conviene riferirsi a due esempi, uno “domestico” e uno
tecnico.
Supponiamo di attendere un amico e avere il citofono non funzionante. Dobbiamo periodicamente sospendere
la nostra attività per andare a controllare il cancello di casa. Questo metodo è assimilabile al polling, in quanto è
necessario un controllo costante che comporta uno spreco di tempo. Se invece contattiamo l’amico
chiedendogli di segnalare il suo arrivo con una breve telefonata, siamo in regime di Interrupt. Lo squillo del
telefono ci farà sospendere la nostra attività una sola volta per passare a gestire la richiesta di servizio, che in
questo caso sarà l’apertura del cancello.
Riferiamoci ora al computer: la gestione delle sue periferiche, tastiera, mouse ecc. è fatta con la tecnica
dell’interrupt. Quando viene premuto un tasto sulla testiera, il microprocessore sospende il suo lavoro, passa a
leggere il codice del tasto premuto, lo memorizza e infine ritorna sul lavoro interrotto. Sarebbe molto
42
dispendioso e irrazionale sondare di continuo la testiera per verificare la pressione di un tasto, considerate
soprattutto le differenti tempistiche di microprocessore e tastiera.
Il PIC16F684 ha 11 sorgenti di interrupt:
Interrupt esterno RA2/INT; Interrupt overflow Timer0 TMR0; Interrut per transizione su porta A; Interrupt da due
comparatori;Interrupt convertitore A/D; Interrupt overflow Timer1; Interrupt Timer 2; Interrupt per scrittura su
EEPROM; Interrupt monitor controllo clock; Interrupt CCP avanzato.
Il registro INTCON contiene bit di controllo e flag relativi a interrupt Timer0 e per transizione su porta A, che
sono le modalità approfondite in questo capitolo. Contiene inoltre bit per l’interrupt esterno e bit di abilitazione
globale degli interrupt.
INTCON - INTERRUPT CONTROL REGISTER (INDIRIZZO: 0Bh o 8Bh)
7
6
5
4
3
2
1
0
GIE
PEIE
T0IE
INTE
RAIE
T0IF
INTF
RAIF
bit 7
GIE: Global Interrupt Enable bit (bit di abilitazione globale interrupt)
1 = Abilita tutti gli interrupt non mascherati
0 = Disabilita tutti gli interrupt
bit 6
PEIE: Peripheral Interrupt Enable bit (bit di abilitazione periferiche)
1 = Abilita tutti gli interrupt periferica non mascherati
0 = Disabilita tutti gli interrupt periferica
bit 5
T0IE: TMR0 overflow Interrupt Enable bit (bit abilitazione interrupt overflow TMR0)
1 = Abilita l’interrupt TMR0
0 = Disabilita interrupt TMR0
bit 4
INTE: RA2/INT external INTerrupt Enable bit (bit di abilitazione interrupt esterno RA2/INT)
1 = Abilita interrupt esterno RA2/INT
0 = Disbilita interrupt esterno RA2/INT
bit 3
RAIE: poRtA change Interrupt Enable bit (bit abilitazione interrupt per transizione su porta A)
1 = Abilita interrupt per transizione porta A
0 = Disabilita interrupt per transizione porta A
bit 2
T0IF: TMR0 overflow Interrupt Flag (bit flag interrupt overflow TMR0)
1 = E’ avvenuto l’overflow di TMR0 (deve essere cancellato in software)
0 = Non è avvenuto l’overflow di TMR0
bit 1
INTF: RA2/INT external INTerrupt Flag bit (flag interrupt esterno RA2/INT)
1 = E’ avvenuto interrupt esterno RA2/INT (deve essere cancellato in software)
0 = Non è avvenuto interrupt esterno RA2/INT
bit 0
RAIF: poRtA change Interrupt Flag bit (flag interrupt per transizione su porta A)
1 = Almeno uno dei bit <5:0> di PORTA ha cambiato stato (deve essere cancellato in software)
0 = Nessuno dei bit <5:0> di PORTA ha cambiato stato
All’occorrenza di un evento di interrupt il microcontrollore provvede a sospendere il programma in corso di
esecuzione e esegue un salto a una locazione fissa, dove deve essere collocata la routine di gestione
dell’interrupt. Questa locazione, detta Vettore di Interrupt, si trova all’indirizzo 0004h.
Vettore di Reset
0000h
Vettore di Interrupt
Memoria
Programma
0004h
Dato che lo spazio è di una sola word, qui il programmatore deve
collocare una istruzione di salto ad altra etichetta di programma, dove
collocare l’effettiva routine di gestione, chiusa dall’istruzione RETFIE
(Return From IntErrupt).
Al ritorno il programma proseguirà dall’istruzione successiva, la 0005.
Qui il programmatore disporrà un salto al punto più logicamente
corretto di prosecuzione del programma.
Nella routine di interrupt il programmatore deve disabilitare ulteriori
interrupt, per evitare pericolose chiamate nidificate e cancellare
eventuali flag influenzati.
L’istruzione retfie riabilita automaticamente gli interrupt. Si noti che il programma deve essere collocato a partire
da 0006h, in quanto 0005h è ora impegnata per il salto.
Interrupt Timer0
Il Timer0 è dotato del registro contatore TMR0. Quando esso raggiunge l’overflow setta il flag T0IF del registro
INTCON. Se l’interrupt del Timer0 è abilitato si verifica un evento di interrupt.
Per l’abilitazione si devono abilitare gli interrupt globali ponendo a 1 i bit GIE e PEIE dell’INTCON e lo specifico
interrupt del Timer0 ponendo a 1 il bit T0IE di INTCON. Un interrupt abilitato globalmente ma non
specificamente dal proprio bit si dice “mascherato”.
43
Esperimento …\Interrupt\Timer
Scrivere un programma che effettui un conteggio da 0 a 7 sul display delle unità utilizzando l'interrupt del Timer0.
Il processo deve essere gestito interamente dalla routine di gestione dell'interrupt.
Questa deve incrementare una variabile CONTATORE ad ogni overflow di TMR0.
TMR0 non deve essere impostato, pertanto deve svolgere tutto il conteggio da 00h a FFh.
Non appena si ha CONTATORE=122, ovvero dopo 1 secondo, la routine di gestione deve azzerare CONTATORE e
incrementare NUMERO, che non deve superare 7. In fase di inizializzazione, tramite INTCON, si devono abilitare
globalmente gli interrupt e l'interrupt del Timer0. Si noti nella routine di gestione dell’interrupt l’istruzione bcf INTCON,T0IF,
che predispone TMR0, azzerandolo, a generare il successivo interrupt.
;DIRETTIVE
list
p=16f684
; direttiva list per definizione del processore
#include <p16f684.inc>
; definizione variabili specifiche processore
errorlevel -302
__CONFIG
_CP_OFF & _CPD_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT
;DEFINIZIONE COSTANTI E VARIABILI
cblock 0x20
CONTATORE
; contatore per ritardo
NUMERO
; numero da visualizzare su display unità
endc
;INIZIALIZZAZIONE
org
0x000
; vettore di reset del processore
goto
Initialize
org
0x004
goto
gestore_int_timer
goto
Inizio
; locazione dove saltare al ritorno da routine interrupt
org
0x006
; vettore di inizio del programma
Initialize
bsf
STATUS, RP0
; banco 1
movlw B'10000100'
; clock timer interno, prescaler 1/32
movwf OPTION_REG
; overflow in 8.2ms
clrf
ANSEL
; I/O digitale
movlw 0x00
movwf TRISC
; programma porta C per tutti i pin output
bcf
STATUS, RP0
; banco 0
movlw B'11100000'
movwf INTCON
; abilitazione interrupt timer0 e abilitazione globale interrupt
movlw .0
movwf NUMERO
;PROGRAMMA
Inizio
goto
Inizio
;ROUTINE DI GESTIONE DELL'INTERRUPT TIMER
gestore_int_timer
bcf
INTCON,T0IF
; resetta flag overflow timer0
movlw .122
; ritardo di 1 secondo
xorwf CONTATORE,0
btfss STATUS,Z
goto
noazioni
; attendere il completamento del ritardo
movlw .0
movwf CONTATORE
; reinizializza CONTATORE
movfw NUMERO
movwf PORTC
; numero in output su unità
incf
NUMERO,1
; incrementa numero
movlw .8
xorwf NUMERO,0
; se numero=8 riprende il conteggio da 0
btfsc STATUS,Z
; salta se Z=0
clrf
NUMERO
; azzera numero
retfie
noazioni
incf
CONTATORE,1
retfie
end
Questo programma ha scopo di studio, perciò è stato creato nell’ottica della massima semplicità. In esso il
programma principale non svolge alcun compito, ma questo contrasta con lo scopo dell’interrupt, che è di
liberare il programma principale dal controllo puntuale delle richieste di servizio, in questo caso lanciate dal
Timer0.
Il programma successivo è arricchito da una nuova funzione. Il Timer0 provvede ancora a visualizzare il
conteggio in avanti da 0 a 7 su un display, il programma principale comanda su un altro display il conteggio da 7
a 0 all’indietro, a diversa velocità.
I due processi sono completamente indipendenti e asincroni. Il programma principale gestisce la
temporizzazione del conteggio all’indietro con il timer1. Il timer 0 comanda in autonomia le temporizzazioni per il
conteggio in avanti.
44
Esperimento …\Interrupt\DueTim
Scrivere un programma che effettui un conteggio da 0 a 7 in avanti sul display delle unità e all'indietro su quello delle decine,
a velocità diverse desincronizzate.
;DIRETTIVE
list
p=16f684
; direttiva list per definizione del processore
#include <p16f684.inc>
; definizione variabili specifiche processore
errorlevel -302
__CONFIG
_CP_OFF & _CPD_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT
;DEFINIZIONE COSTANTI E VARIABILI
cblock 0x20
CONTATORE
; contatore per ritardo
CONTAT
NUM_UNITA
NUM_DECINE
endc
;INIZIALIZZAZIONE
org
0x000
; vettore di reset del processore
goto
Initialize
org
0x004
goto
gestore_int_timer
goto
Inizio
org
0x006
; vettore di inizio del programma
Initialize
bsf
STATUS, RP0
; banco 1
movlw B'10000100'
; clock timer interno, prescaler 1/32
movwf OPTION_REG
; overflow in 8.2ms
clrf
ANSEL
; I/O digitale
movlw 0x00
movwf TRISC
; programma porta C per tutti i pin output
movlw 0x00
movwf TRISA
; programma porta A per tutti i pin output
bcf
STATUS, RP0
; banco 0
movlw B'11100000'
movwf INTCON
; abilitazione interrupt timer0 e abilitazione globale interrupt
bsf
T1CON,TMR1ON
; attiva Timer1
movlw .0
; inizializza conteggio
movwf NUM_UNITA
movlw .0
movwf NUM_DECINE
;PROGRAMMA
Inizio
movfw NUM_DECINE
movwf PORTA
; visualizza NUM_DECINE
decf
NUM_DECINE,1
; decrementa NUM_DECINE
call
ritardotimer1
goto
Inizio
;ROUTINE DI GESTIONE DELL'INTERRUPT TIMER
gestore_int_timer
bcf
INTCON,T0IF
movlw .122
; ritardo di 1 secondo
xorwf CONTATORE,0
btfss STATUS,Z
goto
noazioni
; attendere il completamento del ritardo
movlw .0
movwf CONTATORE
movfw NUM_UNITA
movwf PORTC
; numero in output su unità
incf
NUM_UNITA,1
; incrementa numero
movlw .8
xorwf NUM_UNITA,0
; se numero=8 riprende il conteggio da 0
btfsc STATUS,Z
; salta se Z=0
clrf
NUM_UNITA
; azzera numero
retfie
noazioni
incf
CONTATORE,1
retfie
;SOTTOPROGRAMMA
ritardotimer1
movlw .4
movwf CONTAT
loopesterno
clrf
TMR1H
clrf
TMR1L
bcf
PIR1,TMR1IF
loopinternoTMR1
btfss PIR1,TMR1IF
goto
loopinternoTMR1
decfsz CONTAT,1
goto
loopesterno
return
end
; ritardo breve
; resetta registri timer
; resetta flag timer 1
; attendi se flag timer non settato
; decrementa contatore ritardo
45
Interrupt per transizione su PORTA
•
Questo interrupt viene lanciato se almeno uno dei sei bit <5:0> della PORTA subisce una transizione, cioè un
passaggio da basso a alto o da alto a basso. In questo modo il microcontrollore può rispondere a richieste di
servizio causate da segnali esterni, come ad esempio il segnale prodotto da una cellula fotoelettrica che
intercetta il passaggio di un oggetto sulla sua direttrice.
Per l’abilitazione dell’interrupt si devono abilitare gli interrupt globali ponendo a 1 i bit GIE e PEIE dell’INTCON e
lo specifico bit RAIE di abilitazione interrupt per transizione su porta A.
Ogni pin della PORTA è inoltre configurabile singolarmente come pin di interrupt per transizione. Il registro
IOCA permette di specificare i pin abilitati con i corrispondenti bit.
IOCA - INTERRUPT-ON-CHANGE PORTA REGISTER (INDIRIZZO: 96h)
7
6
5
4
3
2
1
0
------
-------
IOCA5
IOCA4
IOCA3
IOCA2
IOCA1
IOCA0
bit 7-6
Non implementati
bit 5-0
IOCA<5:0> bit di controllo interrupt di transizione su PORTA
1 = Interrupt su transizione abilitato
0 = Interrupt su transizione non abilitato
Nella routine di gestione dell’interrupt è necessario disabilitare ulteriori interrupt e azzerare il flag interrupt per transizione su
porta A. E’ inoltre necessario attendere alcuni istanti prima di uscire dall’interrupt, richiamando un ritardo (può andare bene 1
secondo). In questo modo si attende che i rimbalzi meccanici cessino e si evita che possano causare interrupt spuri.
Esperimento …\Interrupt\Change
Scrivere un programma che effettui un conteggio da 0 a 7 sul display delle unità in avanti o all'indietro.
La direzione di conteggio deve invertirsi ogni volta che si preme il pulsante SW1.
La pressione del pulsante deve invocare un interrupt.
La routine di gestione dell'interrupt interroga il valore di DIREZIONE.
Se DIREZIONE=0 pone DIREZIONE =1 e viceversa. Il programma principale esegue il conteggio nella direzione indicata
appunto da DIREZIONE.
;DIRETTIVE
list
p=16f684
; direttiva list per definizione del processore
#include <p16f684.inc>
; definizione variabili specifiche processore
errorlevel -302
__CONFIG
_CP_OFF & _CPD_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_OFF & _INTRC_OSC_NOCLKOUT
;DEFINIZIONE COSTANTI E VARIABILI
cblock 0x20
CONTATORE
; contatore per ritardo
NUMERO
; numero da visualizzare
DIREZIONE
; direzione del conteggio
endc
;INIZIALIZZAZIONE
org
0x000
; vettore di reset del processore
goto
Initialize
org
0x004
call
gestore
goto
Inizio
org
0x006
; vettore di inizio del programma
Initialize
bsf
STATUS, RP0
; banco 1
movlw B'10000100'
; clock timer interno, prescaler 1/32
movwf OPTION_REG
; overflow in 8.2ms
movlw B'11001000'
; RAIE=1;
movwf INTCON
; abilitazione interrupt cambiamento su Porta A
; e abilitazione globale interrupt
clrf
ANSEL
; I/O digitale
movlw B'00000000'
movwf TRISC
bsf
IOCA,3
; abilitazione interrupt cambiamento su bit 3 porta A
bcf
INTCON,0
; resetta flag overflow timer 0
bcf
STATUS, RP0
; banco 0
movlw .0
; inizializza conteggio
movwf NUMERO
;PROGRAMMA
Inizio
movfw NUMERO
movwf PORTC
; numero in output su unità
call
ritardo
movlw .1
xorwf DIREZIONE,0
btfsc STATUS,Z
; se DIREZIONE=1 il conteggio procede in avanti
goto
avanti
decf
NUMERO,1
goto
Inizio
avanti
incf
NUMERO,1
goto
Inizio
46
;ROUTINE DI GESTIONE DELL'INTERRUPT DOVUTO A CAMBIAMENTO SU PORTA
gestore
bcf
INTCON,RAIE
; disabilita ulteriori interrupt cambiamento su porta A
call
ritardo
; attende cessazione impulsi di SW1 per rimbalzi meccanici
bcf
INTCON,RAIF
; resetta flag overflow timer0
movlw .1
xorwf DIREZIONE,0
btfss STATUS,Z
; se DIREZIONE=1 pone DIREZIONE=0 e viceversa
goto
setta
movlw .0
movwf DIREZIONE
goto
fine
setta
movlw .1
movwf DIREZIONE
fine
bsf
INTCON,RAIE
; riabilita interrupt cambiamento su porta A
retfie
;SOTTOPROGRAMMA
ritardo
movlw .122
movwf CONTATORE
loopesterno
clrf
TMR0
bcf
INTCON,T0IF
loopinterno
btfss INTCON,T0IF
goto
loopinterno
decfsz CONTATORE,1
goto
loopesterno
return
end
; ritardo di 1 secondo
; resetta registro timer
; resetta flag timer
; attendi se flag timer non settato
; incrementa contatore ritardo
Esercizi
es1
Scrivere un programma che effettui un conteggio in avanti sul display delle unità.
Il conteggio deve essere resettato ogni volta che si preme il pulsante SW1.
La pressione del pulsante deve invocare un interrupt.
La routine di gestione dell'interrupt provvede a forzare NUMERO a 0.
L’istruzione bsf IOCA,3 provvede ad abilitare l’interrupt del pin 3 di PORTA, al quale è collegato il pulsante SW1,
es2
Scrivere un programma che effettui un conteggio in avanti a due velocità sul display delle unità.
La velocità deve essere commutata ogni volta che si preme il pulsante SW1.
Il valore della velocità impostata viene conservato da una variabile RICARICA_VELOCITA.
Questa deve essere caricata entro CONTATORE all'interno del sottoprogramma di ritardo.
La pressione del pulsante deve invocare un interrupt.
La routine di gestione dell'interrupt provvede a commutare RICARICA_VELOCITA.
Se RICARICA_VELOCITA=122 (conteggio lento) pone RICARICA_VELOCITA=20 (conteggio veloce) e viceversa.
es3
Scrivere un programma che effettui un conteggio in avanti sul display delle unità, a due velocità, commutate ogni 16
secondi.
Ad ogni overflow di TMR0 Timer0 deve lanciare un interrupt. In risposta la routine di gestione provvede a incrementare di
una quota fissa il registro CONTATORE. Con il prescaler a 1/16, con il test CONTATORE=244, il tempo di attesa diventa di
16 secondi. Trascorsi questi la routine provvede a commutare la velocità di conteggio.
Per implementare la doppia velocità si devono impiegare due variabili. Una variabile CONTAT_TIMER1 funge da contatore
per il ciclo esterno del Timer1. Una seconda variabile RICARICA_TIMER1 serve da ricarica per CONTAT_TIMER1 e viene
impostata alternativamente a 1 e a 4 dalla routine di interrupt per dosare la velocità.
47
EEPROM
La memoria EEPROM (Electrically Erasable Programmable Read Only Memory=Memoria di sola Lettura
Programmabile e Cancellabile Elettricamente) è una memoria permanente, che mantiene il proprio contenuto
anche ad alimentazione spenta.
E’ possibile sia leggere che scrivere sulla EEPROM; la scrittura ha luogo mediante una cancellazione che
avviene con modalità elettriche.
I registri associati sono:
EEDAT: in esso viene posto il dato a 8 bit da scrivere o leggere
EEADR: in esso viene posto l’indirizzo di una delle 256 locazioni
EECON1: contiene bit di controllo
EECON2: non fisicamente implementato
EEDAT - EEPROM DATA REGISTER (INDIRIZZO: 9Ah)
7
6
5
4
3
2
1
0
EEDAT7
EEDAT6
EEDAT5
EEDAT4
EEDAT3
EEDAT2
EEDAT1
EEDAT0
bit 7-0
EEDATn: byte value to write or read from DATa EEPROM (bits del byte da leggere o scrivere nella EEPROM)
EEADR - EEPROM ADDRESS REGISTER (INDIRIZZO: 9Bh)
7
6
5
4
3
2
1
0
EEADR7
EEADR6
EEADR5
EEADR4
EEADR3
EEADR2
EEADR1
EEADR0
bit 7-0 EEADRn: specifies the ADdRess of one of 256 locations for EEPROM read/write operation bits (specifica una delle
256 locazioni per lettura/scrittura su EEPROM)
EECON1 - EEPROM CONTROL REGISTER (INDIRIZZO: 9Ch)
7
6
5
4
3
2
1
0
------
------
------
------
WRERR
WREN
WR
RD
bit 7-4
non implementati
bit 3
WRERR: EEPROM WRite ERRor flag bit (flag segnalazione errore EEPROM)
1=operazione di scrittura terminata prematuramente
0=operazione di scrittura completata
bit 2
WREN: EEPROM WRite ENable bi (bit abilitazione scrittura su EEPROM)
1=consente cicli di scrittura
0=inibisce scrittura su EEPROM
bit1
WR: WRite control bit (bit di controllo scrittura)
1=inizia un ciclo di scrittura della EEPROM (il bit è cancellato dall’hardware a completamento della scrittura.
Il bit WR può solo essere settato, non cancellato, con il software)
bit0
RD: ReaD control bit (bit di controllo lettura)
1=inizia un ciclo di lettura della EEPROM (La lettura richiede un ciclo. RD è cancellato in dall’hardware.
Il bit WR può solo essere settato, non cancellato, dal software)
0=Non ha inizio la lettura della EEPROM
La lettura della EEPROM prevede le seguenti fasi:
1) scrittura indirizzo in EEADR
2) comando lettura mediante settaggio bit RD di EECON1
3) lettura dato entro registro EEDAT
La scrittura della EEPROM prevede le seguenti fasi:
1) scrittura indirizzo in EEADR
2) scrittura dato entro registro EEDAT
3) abilitazione scrittura mediante settaggio bit WREN di EECON1
4) disabilitazione interrupt bit GIE di INTCON1
5) sequenza obbligata: movlw 0x55; movwf EECON2; movlw 0xAA; movwf EECON2
6) comando scrittura mediante settaggio bit WR di EECON1
7) riabilitazione interrupt bit GIE di INTCON1
Il programma che segue implementa entrambe le operazioni di scrittura e lettura.
48
Esperimento …\EEPROM
Scrivere un programma che incida nella locazione di indirizzo 0 della EEPROM il numero 5, poi lo legga e lo visualizzi su
display.
;DIRETTIVE
list
p=16f684
; direttiva list per definizione del processore
#include <p16f684.inc>
; definizione variabili specifiche processore
errorlevel -302
__CONFIG
_CP_OFF & _CPD_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT
;DEFINIZIONE COSTANTI E VARIABILI
cblock 0x20
CONTATORE
; contatore per ritardo
endc
;INIZIALIZZAZIONE
org
0x000
; vettore di reset del processore
goto
Initialize
org
0x005
; vettore di inizio del programma
Initialize
bsf
STATUS, RP0
; banco 1
movlw B'10000100'
; clock timer interno, prescaler 1/32
movwf OPTION_REG
; overflow in 8.2ms
clrf
ANSEL
; I/O digitale
movlw 0x00
movwf TRISC
; programma porta C per tutti i pin output
;PROGRAMMA
scrittura
movlw .10
movwf EEADR
; indirizzo
movlw .5
movwf EEDAT
; dato
bsf
EECON1,WREN
; abilita scrittura
bcf
INTCON,GIE
; disabilita interrupt
movlw 0x55
movwf EECON2
movlw 0xAA
movwf EECON2
bsf
EECON1,WR
; comando scrittura
bsf
INTCON,GIE
; riabilita interrupt
call
ritardo
lettura
movlw .10
movwf EEADR
; indirizzo
bsf
EECON1,RD
; comando lettura
movf
bcf
movwf
EEDAT,W
STATUS, RP0
PORTC
call
goto
ritardo
loop
; copia dato in W
; banco 0
loop
;SOTTOPROGRAMMA
ritardo
movlw .122
movwf CONTATORE
loopesterno
clrf
TMR0
bcf
INTCON,T0IF
loopinterno
btfss INTCON,T0IF
goto
loopinterno
incfsz CONTATORE,1
goto
loopesterno
return
; ritardo di 1 secondo
; resetta registro timer
; resetta flag timer
; attendi se flag timer non settato
; incrementa contatore ritardo
end
49