Gestione dei ritardi
Generatore di onde quadre





Il generatore di onde quadre consiste di un treno di onde luminose caratterizzate da un periodo il cui 50% il livello
logico è alto e il restante 50% è a livello logico basso.
Fare ciò, significa gestire il tempo e quindi i ritardi sui pic
Un metodo molto semplice e forse, un po’ banale, è quello di far lavorare la macchina avuoto senza far eseguire alcuna
operazione.
L’istruzione per non far eseguire operazioni è nop.
La routine è la seguente:
LIST p=16F628
include "P16F628.inc“ ; libreria dove sono definiti I registri del 16f628
org 0x0000
movlw 0x07
movwf CMCON
;tutti i comparatori sono disattivati. Le porte che sono multiplexate, fungono solo
;da I/O
bsf STATUS, RP0
; viene posto a 1 il bit RP0 del registro Staus per selezionare il bank1
movlw b'00000000'
movwf TRISB
;portb come output
movwf TRISA
;porta come output
bcf STATUS, RP0
; viene posto a 0 il bit RP0 del registro Staus per selezionare il bank0
Loop del programma
Loop
movlw 0xff
; viene caricato il numero
;255 in formato esadecimale che tradotto un binario è 11111111
movwf PORTA
;porta è a livello logico alto
movwf PORTB
;portb è a livello logico alto
nop
; viene inserito un ritardo di 1 microsecondo
;perchè ogni ciclo macchina ha frequenza 1 Mhz
nop
; per 1 us la macchina non esegue operazioni
movlw 0x00
; viene caricato lo zero
movwf PORTA
;porta e portb sono a livello logico basso
movwf PORTB
nop
nop
goto Loop
end
Nop
 Nop è l’istruzione che non fa eseguire alcuna operazione.
 A che cosa può servire?
 Fa lavorare il micro a vuoto per mantenere fisso lo stato di




un microcontrollore e non far cambiare stato.
Quanto può durare un ritardo?
Se la frequenza di clock è di 4 MHz, il periodo sarà di 0,25
us e il tempo macchina è 4*Tclock=1us
Ogni ciclo macchina dura quindi 1 us se la frequenza di
clock è 4 MHz.
Il ritardo ottenuto è quindi 2 us visto che sono state
introdotte due righe con l’istruzione nop
Senza libreria
 Se non avessimo inserito la libreria avremmo dovuto
dare delle direttive al compilatore:
PORTA EQU 0x05
PORTB EQU 0x06
TRISA EQU 0x05
TRISB EQU 0x06
STAUS EQU 0x03
RP0
EQU 0x05 ; bit 5 del registro status
CMCON EQU 0x1F
Riga programma
Registro interessato
Stato deI bit Registro
MOVLW 0X07
accumulatore
0
0
0
0
0
1 1
1
MOVWF cmcon
cmcon
0
0
0
0
0
1 1
1
Bsf status,rp0
5 bit registro status
0
0
1
0
0
0 0 0
Movlw 0x00
accumulatore
0
0
0
0
0
0 0 0
Movwf trisa
Trisa del bank1
0
0
0
0
0
0 0 0
Movwf trisb
Trisb del bank1
0
0
0
0
0
0 0 0
Bcf status, rp0
5 bit registro status
0
0
0 0
0
0 0 0
Movlw 0xff
accumulatore
1
1
1
1
1
1 1
1
Movwf porta
Porta del bank0
1
1
1
1
1
1 1
1
Movwf portb
Portb del bank0
1
1
1
1
1
1 1
1
nop
Nessun registro
Movlw 0x00
accumulatore
0
0
0
0
0
0 0 0
Movwf porta
Porta del bank0
0
0
0
0
0
0 0 0
Movwf portb
Portb del bank0
0
0
0
0
0
0 0 0
Ritardo con una routine di ritardo
• Con pochi microsecondi di ritardo non possiamo renderci conto della
differenza tra i due livelli logici e, gestire un ritardo più grande, comporterebbe
la scrittura di un numero enorme di istruzioni nop.
• Un metodo più efficace è quello di inserire un valore in un registro GFR e,
decrementarlo.
• La macchina rimane nel suo stato fino a quando il registro non è zero
• Si passa alla istruzione successiva se tutto è nullo.
• Useremo quindi decfsz
salta alla istruzione successiva se il risultato è nullo
• Il programma è il seguente:
LIST p=16F628
include "P16F628.inc“
count1 equ 0x0C ; registro generale
count2 equ 0x0D
org 0x00
Ritardo con una routine di ritardo
loop:
movlw
movwf
bsf
movlw
movwf
movwf
bcf
clrf
clrf
call
bsf
call
0x07
CMCON
;pone I comparatori a 1
STATUS, RP0
;seleziona bank1
b'00000000'
TRISB
TRISA
STATUS, RP0
;seleziona banco 0
PORTA
;porta non viene mai usata
PORTB
Delay
PORTB, 7 ;pone il bit 7 a livello logico alto
Delay
Ritardo con una routine di ritardo:
subroutine di ritardo
Spegni:
Delay:
Loop1:
Loop2:
bcf portb,7
;pone a livello logico basso il bit 7
goto loop
movlw 0x0f
movwf conta2
;pone il valore 15 in un GFR
movlw 0x0f
movwf conta1 ;pone il valore 15 in un GFR
decfsz conta1 ;decrementa il registro e salta se zero
goto
Loop1
decfsz conta2 ;decrementa il registro e salta se zero
goto
Loop2
return
end
Osservazioni
 Nel programma sono stati settati sia i registri porta e trisa
che non servono; non serve nemmeno il settaggio del
registro comcon che setta i comparatori. Se fosse stato
utilizzato tutto il registro trisa, sarebbe stato utile settare i
comparatori.
 Si noti che il ritardo sul cambio di stato di ogni porta è di
30 us perché il decremento di ciascun registro 0ch e 0dh
dura 15 cicli macchina e, ogni ciclo dura 1 us; 15 cicli durano
15 us. Siccome sono due registri da decrementare, il ritardo
sarà di 30 us
 Per fare un ritardo più grande, si possono settare a 1 al
massimo 8 bit di ciascun registro per un numero di cicli
massimi di decrementi pari a 255 us
esercizio
 Scrivere un programma che faccia accendere e
spegnere alternativamente 2 led e ciascuno con un
ritardo di 200 us
Osservazioni
 Quando si incontra l’istruzione goto oppure call
subroutine, si ha un salto e si interrompe il flusso del
programma per eseguire la linea programma o la
subroutine. Nella memoria programmi c’è una parte
riservata allo stack pointer in cui si inserisce l’indirizzo
in cui è stato interrotto il programma. Terminate le
istruzioni in cui il programma è saltato, lo stack
pointer fornisce l’indirizzo della memoria programma
dove ritornare
Registri
Riga programma
Registri
Bit
Movlw
0x07
w
0 0 0 0 0 1
1
1
Movwf
cmcon
Registro comparatore
0 0 0 0 0 1
1
1
Bit 5 di status
0 0 0 1
Bsf
status,rp0
0 0 0 0
Movlw
0x00
w
0 0 0 0 0 0 0 0
Movwf
trisb
trisb
0 0 0 0 0 0 0 0
Bcf
status,rp0
Bit 5 di status
0 0 0 0 0 0 0 0
Clrf
portb
portb
0 0 0 0 0 0 0 0
Bit 7 portb
1
Call delay
Bsf portb,7
Call delay
Goto loop
0 0 0 0 0 0 0
Delay
Supponiamo di inserire un ritardo molto più piccolo
Riga programmi
Registri
Bit
Movlw
0x02
w
0
0
0
0
0
0
1
0
Movwf
conta1
Registro 0x0c
0
0
0
0
0
0
1
0
Movlw
0x02
W
0
0
0
0
0
0
1
0
Movwf
conta2
Registro 0x0d
0
0
0
0
0
0
1
0
Decfsz
conta1
0x0c
0
0
0
0
0
0
0
1
Decfsz
conta1
0x0c
0
0
0
0
0
0
0
0
Decfsz
conta2
0x0d
0
0
0
0
0
0
0
1
Decfsz
conta2
0x0d
0
0
0
0
0
0
0
0
Goto loop1
Return
Ritorna all’ultima chiamata di subroutine.
Un tempo di ritardo più lungo
Delay:
Loop2:
Loop1:
movlw
movwf
movlw
movwf
decfsz
goto
decfsz
goto
return
end
0x0f
conta2
;pone il valore 15 in un GFR
0x0f
conta1 ;pone il valore 15 in un GFR
conta1 ;decrementa il registro e salta se zero
Loop1
conta2 ;decrementa il registro e salta se zero
Loop2
 Questa volta, per ogni decremento di conta2, si ritorna a
loop2
 Ogni decremento di conta2 genera 15 decrementi di conta1
 I decrementi terminano quando conta2 è zero
 Il tempo di ritardo è 255 us=15*15
Sorgenti di segnali
 Ogni microcontrollore lavora secondo un certo
sincronismo
 I segnali di sincronizzazione possono essere interni o
esterni
 Se esterni, viene applicato un generatore di impulsi ad
una certa frequenza su un determinato pin.
 Nel caso del pic16f628, il segnale viene applicato sul
pin 3
Prescaler e interrupt
Il pic 16f628 è dotato di un timer interno ad 8 bit.
Il registro timer0, registro del bank0 all’indirzzo 01h,
incrementa il proprio contenuto per ogni ciclo macchina
L’oscillatore interno del pic genera una frequenza f=4 MHz;
la frequenza di un qualsiasi segnale proveniente dal pic è
quindi di f/4=1 Mhz, frequenza macchina.
Il registro timer0 incrementa così il proprio contenuto con la
frequenza di 1 MHz
La frequenza di interruzione, frequenza di interrupt, si ha
quando il timer inizia a contare daccapo, cioè quando passa
da overflow a zero. Essendo il timer0 di 8 bit, l’interrupt si
ha ogni 28 -1 cicli macchina+1=256 contando anche il
passaggio da overflow a zero
Frequenza di interrupt
 La frequenza fi di interrupt si calcola dividendo la
frequenza macchina per 256: fi=f(osc)/(4*256)
 Si potrebbe cambiare la frequenza di interrupt con due
metodi:
 Inizializzando il timer con un valore Nt diverso da 0.
• È come accorciare la lunghezza del timer così impiegherà
meno tempo per andare in overflow
• La nuova frequenza fi di interrupt sarà: fi=f(osc)/4/(256-Nt)
 La frequenza di interrupt può cambiare se si inserisce un
prescaler, cioè un divisore di frequenza.
• Il prescaler è formato dai tre bit del registro option che si
trova all’indirizzo 81h, è cioè un registro di bank1
Esercizi per impostare l’interrupt
senza prescaler
Calcolare il periodo di interrupt se Nt=0
2. Calcolare il periodo e la frequenza di interrupt se
Nt=200
3. A quanto bisogna impostare Nt se si chiede che
fi=300 Hz
1.
Registro Option
Bit 0
Bit 1
Bit 2
Bit 3
Bit 4
RBPU
Disabilita o abilitai resistori interni di
pull up
0 disabilita
1 abilita
INTEDG Seleziona il fronte di salita di interrupt
su RB0/INT
0 fronte salita
TOCS
Seleziona il fronte di segnale di clock
del timer
0 clock interno
Seleziona il fronte del segnale per il
clock del timer su RA4/TOCKL
0 fronte di discesa
Assegna il prescaler l timer TMR0 o al
WDT
0 TMR0
TOSE
PSA
Bit 5
PS2
Bit 6
PS1
Bit 7
PS0
1 fronte discesa
1 clock esterno
1 fronte di salita
1 WDT
Selezione il fattore di divisione per il TMR0
Un piccolo schema
Prescaler
Ps2
Ps1
Ps0
Divisore
0
0
0
2
0
0
1
4
0
1
0
8
0
1
1
16
1
0
0
32
1
0
1
64
1
1
0
128
1
1
1
256
Se si vuole cambiare la frequenza fi
di interrupt con Np,
il fattore di divisione
di prescaler fi assumerà
la seguente formula matematica:
fi=fosc/4/Np
Prescaler
 La frequenza di interrupt può essere cambiata anche
utilizzando sia il prescaler che cambiando il punto di
partenza del timerO.
 La frequenza fi può cambiare nel seguente modo:
fi=fosc/4/Np*(256-Nt)
Esempio con il prescaler
•
•
•
•
•
•
•
Supponiamo di voler generare un interrupt ogni 3 ms
Ti=256*Tm=256*4*Tclock=256/fosc/4
Si inserisce il prescaler per cambiare Ti
Ti=256*Np/f/4
Imponendo Ti=3 Np=Ti/256*fosc/4=11.72
Questo valore non è nelle tabelle del prescaler
Si può far partire il conteggio del timer da un valore diverso da
zero
• Si deve allora calcolare il valore Nt da dove far partire il timer
• Si può utilizzare la seguente formula per calcolare il periodo di
interrupt Ti=Np*((256-Nt)/fosc/4
• Se si impone Ti=3 ms, Np=64, si calcola Nt=2563000/64=209,125=209
esempio
 Si vuole accendere e spegnere un led collegato su RA0
di un pic16f628 con periodo di 1 secondo. Si utilizza un
clock di 4 MHz.
 Se si impone un divisore di prescaler pari a 64, la
frequenza di interrupt diventa 15625
 Con un semplice conto, si calcola che per avere 1 Hz
basta far partire il timer da 125
Esercizi
 Se Nt=200 e Np=512, per un clock con frequenza 4
MHz, che valore assumeranno fi e ti?
 Se si vuole una frequenza fì pari a 300 con un clock di
4 MHz, come bisogna combinare Np ed Nt?
Registro INTCON
GIE
EEIE
TOIE
INTE
RBIE
TOIF
INTF
RBIF
Abilitazione di tutti gli interrupt
0
disabilitati
1
abilitati
Segnala il completamento nella memoria
EEPROM
0
Non completo
1
Completo
Abilita l’interrupt per il superamento di capacità
del timer0
0
Disabilitato
1
Abilitato
Abilita l’interrupt su RB0/INT
0
Disabilita
1
Abilita
Abilita l’interrupt per il cambio di livello su RB7RB4
0
Disabilita
1
abilita
Segnala overflow su timer0
0
No Overflow
1
Overflow avvenuto
0
Nessuna richiesta
1
Richiesta avvenuta
0
Nessun cambio livello
1
Cambio di più livelli
Segnala la richiesta di interrupt su RB0/INT
Segnale di cambio di livello su RB7-RB4
Routine di interrupt senza
prescaler
 La routine di interrupt va scritta a partire dalla locazione 004 della
memoria programma
 Se si vuole utilizzare il timer senza inserire il prescaler, bisogna seguire
questa sequenza di passaggi:
 Scrivere una routine di interrupt a partire dalla locazione 004. Nella
routine bisogna dare le seguenti informazioni:
• Si carica il valore dal quale bisogna far partire il timer
• Azzerare il flag di avvenuto interupt, bit 2 del registro INTCON
• Ritornare al programma principale tramite il comando RETFIE
 Nella routine principale bisogna scrivere:
• Porre a zero il bit 5 del registro OPTION, cioè porre in modalità timer
• Caricare il valore iniziale del timer
• Abilitare l’interrupt ponendo a 1 il bit 5 di INTCON
• Abilitare gli interrupt ponendo a 0 il bit 7 del registro INTCON
Routine di interrupt con prescaler
• Bisogna scrivere la routine di interrupt e partire dalla locazione
004 della memoria programma
o ricaricare il valore iniziale del timer
o azzerare il flag di avvenuto interrupt tramite il bit 2 del registro
INTCON
o terminare la routine di interrupt tramite l’istruzione RETFIE
• Nel programma principale si scrivono le seguenti istruzioni:
o assegnare il prescaler al timer ponendo a 0 il bit 3 del registro
OPTION
o selezionare il fattore di divisione del prescaler
o assegnare il valore di inizio del timer
o abilitare l’interrupt del timer ponendo a 1 il bit 5 di INTCON
o abilitare tutti gli interrupt ponendo a 1 il bit 7 di INTCON
Come settare il prescaler
esempio
 Si vuol far accendere e spegnere un led su RA1 con
frequenza 1 Hz. Si utilizzi un quarzo di 4 MHz
 f(clock)=4000000Hz; f(macchina)=1000000 Hz
 Si pone Np=(64) 10=combinazione prescaler 101
 256-Nt=125
Lampeggio di un led con frequenza
di 1 Hz
list p=16f628
radix
dec
porta equ 5
portb equ 6
Timer equ 1
intcon equ 0x0b
cont
equ 0x0c
flag
equ 0x0d
toif
equ 0x02
toie
equ 0x05
gie
equ 0x07
goto
start
Lampeggio led: routine interrupt
org
4
interrupt: incf
movlw
movwf
bcf
retfie
cont,1
0x00
timer
intcon, toif
;ritorno dall’interrupt
Lampeggio di un led:routine
principale
start:
movlw 0xd5 ; carica il valore 11010101
movwf option
RBPU
INTEDG
TOCS
TOSE
PSA
PS2
PS1
PS0
1
1
0
1
0
1
0
1
Divisore di prescaler=64
movlw 0xff
tris
portb
movlw 0x00
tris
porta
Clock interno
Prescaler al timer
Lampeggio di un led
movwf
timer
;l’accumulatore è ancora azzerato
movwf
cont
bsf
intcon, toie ;abilita l’interrupt timer
bsf
intcon, gie ;abilita gli interrupt
ancora: movlw
125
xorwf
cont,0 ;esegue l’operazione logica XOR tra cont e W e pone il risultato in W
skpz
; salta se il risultato è zero. Il conteggio si ferma a 125
goto
ancora
avanti:
movwf cont
comf
flag,1
;complementa flag e pone il risultatp in flag
btfsc
flag,0
;testa il bit 0 e salta se 0
goto accendi
bcf
porta,0
goto ancora
accendi: bsf
porta,0
goto ancora
end
Scarica

Diapositiva 1 - La scienza non è nient`altro che una perversione se