PIC Esempi

Transcript

PIC Esempi
PIC Esempi - LED
Per i primi esempi viene utilizzato soltanto un LED sulla porta B (PortB), successivamente
si utilizzano più LED.
1.1
Questo semplice programma esegue uno switch ripetutamente su tutti i pin di uscita tra i
due livelli alto e basso.
; 1.1
LIST
p=16F628
include "P16F628.inc"
__config 0x3D18
;tell assembler what chip we are using
;include the defaults for the chip
;sets the configuration settings
;(oscillator type etc.)
org
;org sets the origin, 0x0000 for the 16F628,
;this is where the program starts running
0x0000
;-------------------------------------------------------movlw
0x07
;assegna al registro W generico (accumulatore) il
;valore 0x07il quale servirà a settare un determinato
;comportamento del comparatore
movwf
CMCON
;turn comparators off (make it like a 16F84)
;CMCON identifica un registro (Comparator Control
;Register)
; Writing a value of 7 (binary 00000111) to
;CMCON turns OFF the comparators
;--------------------------------------------------bsf
STATUS, RP0
movlw
b'00000000'
movwf
TRISB
movwf
TRISA
bcf
STATUS, RP0
movlw
movwf
0xff
PORTA
;select bank 1
;pone a 1 il bit relativo al valore contenuto in RP0
;nel registro STATUS
;RP0 è un bit che se vero seleziona il banco 1
;altrimenti il banco 0
;Banking requires the use of control bits for bank
;selection.
;These control bits are located in the STATUS Register.
;set PortB all outputs
;pone il valore 0 nel registro W
;sposta il valore in W (0) nel registro TRISB
;in tal modo setta tutta la porta B come
; uscita
;set PortA all outputs
;come per la porta B
;NB. PORTA è formata solo da 5 bit
;select bank 0
; l’istruzione riporta a 0 il bit nel registro STATUS
;------------------------------------------------------------------------------Loop
;set all bits on
movwf
nop
nop
PORTB
movlw
movwf
movwf
0x00
PORTA
PORTB
;set all bits off
goto
Loop
;go back and do it again
;the nop's make up the time taken by the goto
;giving a square wave output
end
Le prime tre righe sono istruzioni per l’assemblatore, non sono parte integrante del
programma, lasciamole come sono in questi esempi senza farci troppe domande sul
perchè ci sono. La __Config setta le varie configurazioni possibili del chip, in questo caso
viene selezionato l’oscillatore interno a 4MHz. La riga successiva “org 0x0000” setta
l’indirizzo iniziale, questo può variare a seconda del PIC usato ma i più moderni utilizzano
l’indirizzo più basso (zero).
Le righe 5 e 6:
“movlw 0x07” significa “MOVe the Literal value 7 into the W register”, il registro W è il
registro di lavoro principale,
“movwf CMCON” significa “MOV the value in W to File CMCON”, CMCON è un registro
utilizzato per selezionare l’uso del comparatore hardware. Pertanto le due righe settano
CMCON al valore 7, questo disabilita il comparatore, e rende le relative linee di I/O
disponibili per uso generale.
Le cinque righe successive settano la direzione delle linee di I/O, inizialmente dobbiamo
selezionare il “bank 1”, alcuni registri sono in “bank 0” ed altri in “bank 1”, per selezionare
“bank 1” abbiamo bisogno di settare il bit RP0 nello STATUS register a “1” – il comando
“bsf” (Bit Set File) setta un bit a uno. Il “bcf” (Bit Clear File) alla fine delle cinque righe,
setta RP0 di nuovo a “0” e ritorna al “bank 0”.
Il “movlw”, come prima, muove un valore nel registro W, questa volta però il valore
passato è un valore binario (anzichè esadecimale 0x00), questo è indicato dalla “b” prima
del valore stesso, in questo caso è semplicemente zero, e questo valore è poi trasferito ai
due registri TRIS (TRIState) A e B. Questo setta la direzione dei pin, un valore “0” setta
un pin come Uscita, mentre un “1” lo setta come Ingresso – pertanto il valore b'00000000'
(otto zero) setta tutti i pin come Uscita, b'10000000' setterà il pin 7 come un ingresso, e
tutti gli altri come uscite – utilizzando un balore binario risulta semplice vedere quale quali
pin soni ingressi (1) e quali uscite (0).
Questo completa il set up del chip, adesso discutiamo la vera parte del programma che
produrrà delle azioni, si inizia con l’etichetta “Loop”, l’ultimo comando “goto Loop' fa si che
il programma ritorni al punto relativo all’etichetta, e esegue un loop infinito.
La prima istruzione di questa sezione è “movlw 0xff” questa muove il numero esadecimale
0xff (255 decimale, 11111111 binario) nel registro W, la seconda e la terza in seguito
trasferiscono questo valore alla PortA e alla PortB di I/O – questo “prova” a settare tutti i
16 pin (approfondiremo in seguito!).
Le due istruzioni seguenti sono “nop” “NO Operation”, questa istruzione richiede 1uS per
essere eseguita e non fa niente, vengono utilizzate solo per mantenere le uscite alte per
un extra time di 2uS.
Poi abbiamo “movlw 0x00” la quale muove 0x00 (0 decimale, 00000000 binario) nel
registro W, poi verrà trasferito alle porte come visto prima, questo setta tutti e 16 le uscite
al livello basso. L’ultimo “goto Loop” ritorna all’inizio e permette di rieseguire la sezione
all’infinito, continuerà switchando le porte al valore alto e basso.
1.2
Come avete potuto notare nella prima parte (implementando il codice di cui sopra), i LED's
non lampeggiano!. In realtà i LED lampeggiano ma lo fanno troppo velocemente
affinchè sia visibile. Il PIC esegue ciascuna istruzione a 4MHz, pertanto impiega 1uS per
completare (ad eccezione del “jump”, che impiega 2uS), questo fa si che i LED
lampeggino migliaia di volte al secondo – troppo veloce per i nostri occhi!. Questo è un
problema comune nella programmazione di microcontrollori che interagiscono con
ambienti fisici esterni, girano troppo velocemente rispetto al mondo esterno, spesso
abbiamo bisogno di rallentare l’esecuzione!.
Anche questo secondo esempio cambia lo stato delle porte di uscita da alto a basso e
viceversa, ma questa volta utilizziamo un delay fra i due cambi di stato.
; 1.2
LIST
p=16F628
include "P16F628.inc"
__config 0x3D18
cblock
;tell assembler what chip we are using
;include the defaults for the chip
;sets the configuration settings (oscillator type etc.)
0x20
;direttiva del compilatore
;start of general purpose registers
;used in delay routine
;used in delay routine
;used in delay routine
;fine direttiva
count1
counta
countb
endc
org
0x0000
movlw
movwf
0x07
CMCON
bsf
movlw
movwf
movwf
bcf
STATUS,
b'00000000'
TRISB
TRISA
STATUS,
;org sets the origin, 0x0000 for the 16F628,
;this is where the program starts running
;turn comparators off (make it like a 16F84)
RP0
;select bank 1
RP0
;set PortB all outputs
;set PortA all outputs
;select bank 0
Loop
movlw
0xff
movwf
PORTA
;set all bits on
movwf
PORTB
nop
;the nop's make up the time taken by the goto
nop
;giving a square wave output
;---------------------------------------------------------------------------------call
Delay
;this waits for a while!
;viene richiamata la routine di nome Delay
movlw
0x00
movwf
PORTA
movwf
PORTB
;set all bits off
call
Delay
;ritardo
goto
Loop
;go back and do it again
;acceso wait spento wait acceso wait spento wait ...................
;--------------------------------------------------------------------------------; di seguito abbiamo la routine in grado di contare 250ms
Delay
d1
movlw
d'250'
;delay 250 ms (4 MHz clock)
;nel registro W si inserisce il valore 250
movwf
count1
; tale valore (250) viene passato al registro
;countl
movlw
movwf
movlw
movwf
0xC7
counta
0x05
countb
;199 volte
;assegna 199 al registro conta
;5 volte
assegna 5 al registo contb
decfsz
counta, f
goto
decfsz
goto
$+2
countb, f
Delay_0
;decrementa il registro conta e se zero passa
;alla riga successiva
;passa 2 istruzioni in avanti (ne salta una)
decfsz
goto
count1
d1
retlw
0x00
Delay_0
,f
;ritorno dalla chiamata di subroutine
;inoltre in grado di restituire un valore
;nel registro accumulatore (non interessa)
end
Questo non fa altro che introdurre due righe di codice in più nel main, “call Delay”, questa
è una chiamata ad una subroutine, una parte del programma che esegue e poi ritorna
dove è stata chiamata. La routine è richiamata due volte, una dopo che i LED sono
diventati accesi, e nuovamente dopo il loro spegnimento. Tutta la routine “Delay” è tempo
perso, cicla continuamente fino a quando non termina.
La parte aggiunta all’inizio del programma (cblock to endc) alloca una coppia di variabili
(count1 and count2) a due dei registri “general purpose file registers”, questi iniziano alla
locazione 0x20 – la direttiva cblock alloca la prima variabile a 0x20, e seguenti.
The cblock directive allows you to define several bytes together. For example:
cblock 0x70
temp
x, y
endc
This bit of assembler defines 3 bytes that will be at locations 0x70 (temp), 0x71 (x), and
0x72 (y). Note that if you put multiple items on the same line, you need a comma between
them.
La routine “Delay” realizza un ritardo di 250mS, settato nella sua prima riga (movlw d'250')
– la “d” indica che si tratta di un numero decimale, per facilitarne la comprensione –
pertanto si accenono i LED, si aspettano 250mS, si spengono i LED, si attendono altri
250mS, e poi si ripete. Questo fa si che i LED lampeggino 2 volte al secondo, adesso sarà
certamente visibile il lampeggiamento. Alterando il valore d'250' si può modificare il flash
rate, comunque poichè al massimo disponiamo di 8 bit il valore non potrà essere più di
d'255' (0xff esadecimale).
Figura 1 – Registri speciali
Figura 2 – Registri Generici
Questa routine introduce un nuovo comando “decfsz” “Decrement File and Skip on Zero”,
questo decrementa il file register specificato (in questo caso count2, o count1) e se il
risultato è uguale a zero passa oltre la riga successiva. Pertanto questa prima sezione
utilizzando il seguente,
d2
decfsz count2 ,f
goto
d2
decrementa count2, controlla se è uguale a zero, e altrimenti continua verso il “goto d2”, il
quale risalta indietro e decrementa count2 nuovamente, continua fino a quando count2 è
uguale a zero, poi “goto d2” viene ignorato e count1 viene decrementato nello stesso
modo, questa volta tornando all’inizio del loop count2, e così via. Questo è detto “nested
loop”, il ciclo interno impiega 1mS per eseguire, e quello esterno chiama quello interno un
numero di volte specificato in count1 –
così se carichiamo 0x01 in count1 la routine Delay impiegherà 1mS, nell’esempio utilizzato
noi carichiamo d'250' (hex 0xfa) in count1, così impiegherà 250mS (1/4 di secondo).
L’altro comando nuovo è “retlw” “RETurn from subroutine with Literal in W”, ritorna dove è
stata chiamata la subroutine, e restituisce un valore opzionale nel registro W (non è però
utilizzato per restituire tale valore in questo esempio, pertanto gli assegnamo 0x00).
Dicevamo che le routine al max possono dare un ritardo massimo di 255mS, se volessimo
un tempo maggiore dovremmo introdurre un altro ciclo esterno che richiama la routine
“Delay” in numero di volte che ci serve, se vogliamo far lampeggiare i LED una volta al
secondo (anziché due) possiamo semplicemente duplicare la riga “call Delay”,
nop
call
call
movlw
;giving a square wave output
;this waits for a while!
;second delay call added
Delay
Delay
0x00
questo dà un ritardo di 500mS, mantenendo il LED acceso per 1/2 secondo, aggiungendo
una seconda chiamata “call Delay” al “off time” il LED starà spento per 1/2 secondi. Non
c’è inoltre bisogno di questa simmetria, usando una chiamata “call Delay” per il “on time”,
e tre per il “off time” il LED continuerà a lampeggiare una volta al secondo ma sarà acceso
per 1/4 del tempo (25/75) – utilizzerà solo il 50% dell’energia rispetto a un 50/50.
Ci sono interessanti vantaggi nell’usare subroutine, una routine come quella del ritardi
può essere usata in molte parti del codice ripetutamente, quindi salvandola una volta
si risparmia spazio. Inoltre modifiche non richiederanno di modificare in più parti il codice
ma solo la subroutine, il cambiamento si ripercuoterà a tutte le chiamate alla subroutine.
1.3
I due esempi precedenti accendevano semplicemente i LED ponendo i pin alti o bassi,
spesso vogliamo agire su un solo pin, questo è facilmente realizzabile con il comando
“bcf” e “bsf”, “bcf” “Bit Clear File” pone un bit a zero, e “bsf” “Bit Set File” pone un bit a 1, il
range dei bit va da 0 (LSB) a 7 (MSB). Il seguente esempio fa lampeggiare il bit 7 (RB7)
della PortB, mentre gli altri bit resteranno a zero.
; 1.3
LIST
p=16F628
;tell assembler what chip we are using
include "P16F628.inc"
;include the defaults for the chip
__config 0x3D18
;sets the configuration settings (oscillator
type etc.)
cblock
0x20
count1
counta
countb
;start of general purpose registers
;used in delay routine
;used in delay routine
;used in delay routine
org
0x0000
;org sets the origin, 0x0000 for the 16F628,
;this is where the program starts running
movlw
movwf
0x07
CMCON
bsf
movlw
movwf
movwf
bcf
clrf
clrf
STATUS,
b'00000000'
TRISB
TRISA
STATUS,
PORTA
PORTB
bsf
call
PORTB,
Delay
endc
;turn comparators off (make it like a 16F84)
RP0
RP0
;select bank 1
;set PortB all outputs
;set PortA all outputs
;select bank 0
;set all outputs low
Loop
7
;turn on RB7 only!
;this waits for a while!
Delay
d1
bcf
call
goto
PORTB,
Delay
Loop
7
movlw
movwf
movlw
movwf
movlw
movwf
d'3'
count1
0x17
counta
0x01
countb
decfsz
goto
decfsz
goto
counta, f
$+2
countb, f
Delay_0
decfsz
goto
retlw
count1
d1
0x00
;turn off RB7 only!.
;go back and do it again
;delay 250 ms (4 MHz clock) 250=FA
;delay 1mS C7=199
Delay_0
,f
end
Il “movwf PORTA” e il “movwf PORTB” sono state rimpiazzate da una singola riga
“bsf PORTB, 7” (per accendere il LED), e “bcf PORTB, 7” (per spegnere il LED). Le
righe associate “movlw 0xff” e “movlw 0x00” sono state eliminate, poichè non servono più,
i due “nop” sono stati rimossi, sono superflui – non ci interessa aggiungere 2uS ad una
routine che dura 250mS.
1.4
Se vogliamo utilizzare un pin diverso rispetto all’RB7, basterà cambiare il “7” nelle due
righe prima viste. Questo esempio (funzionalmente identico al precedente) assegna due
costanti all’inizio del programma, LED, e LEDPORT – a questi vengono assegnati i valori
“7” e “PORTB”, e questi nomi di costanti sono utilizzati in “bsf” e “bcf”. L’uso delle costanti
facilita così eventuali cambiamenti alle assegnazioni dei pin.
; 1.4
LIST
p=16F628
include "P16F628.inc"
__config 0x3D18
type etc.)
cblock
;tell assembler what chip we are using
;include the defaults for the chip
;sets the configuration settings (oscillator
0x20
count1
counta
countb
;start of general purpose registers
;used in delay routine
;used in delay routine
;used in delay routine
endc
LED
Equ
LEDPORT Equ
7
PORTB
org
0x0000
movlw
movwf
0x07
CMCON
bsf
movlw
movwf
movwf
bcf
clrf
STATUS,
b'00000000'
TRISB
TRISA
STATUS,
PORTA
;set constant LED = 7 dichiara una costante
;set constant LEDPORT = 'PORTB'
;org sets the origin, 0x0000 for the 16F628,
;this is where the program starts running
;turn comparators off (make it like a 16F84)
RP0
RP0
;select bank 1
;set PortB all outputs
;set PortA all outputs
;select bank 0
clrf
PORTB
;set all outputs low
bsf
call
bcf
call
goto
LEDPORT, LED
Delay
LEDPORT, LED
Delay
Loop
movlw
movwf
movlw
movwf
movlw
movwf
d'250'
count1
0xC7
counta
0x01
countb
decfsz
goto
decfsz
goto
counta, f
$+2
countb, f
Delay_0
decfsz
goto
retlw
count1
d1
0x00
Loop
Delay
d1
;turn on RB7 only!
;this waits for a while!
;turn off RB7 only!.
;go back and do it again
;delay 250 ms (4 MHz clock)
;delay 1mS
Delay_0
,f
end
Questo lavora esattamente come la versione precedente infatti comparando i relativi file
HEX questi risulteranno identici.
Esercizi
•
•
•
Alterare il numero delle chiamate della Delay in modo tale da produrre
lampeggiamenti asimmetrici.
Cambiare l’assegnamento dei pin.
Far lampeggiare più di un LED ma meno di 8 contemporaneamente - TIP:
aggiungere extra comandi del tipo “bsf” e “bcf”. Aggiungere altri LED lampeggianti
utilizzando diversi rate -TIP: far lampeggiare uno on/off, poi un altro on/off,
aggiungendo diverse chiamate a Delay.
Gli esempi successivi usano più LED (LED board)
1.5
Usando la LED board si fa girare un LED all’interno della riga.
; 1.5
LIST
p=16F628
include "P16F628.inc"
__config 0x3D18
cblock
;tell assembler what chip we are using
;include the defaults for the chip
;sets the configuration settings (oscillator
; type etc.)
0x20
count1
counta
countb
;start of general purpose registers
;used in delay routine
;used in delay routine
;used in delay routine
endc
LEDPORT Equ
LEDTRIS Equ
org
PORTB
TRISB
;set constant LEDPORT = 'PORTB'
;set constant for TRIS register
0x0000
:-------------------
;org sets the origin, 0x0000 for the 16F628,
this is where the program starts running
movlw
0x07
;il valore 7 al registro del comparatore
;esclude il comparatore hw
;turn comparators off (make it like a 16F84)
movwf
CMCON
bsf
movlw
movwf
bcf
clrf
STATUS,
b'00000000'
LEDTRIS
STATUS,
LEDPORT
movlw
movwf
call
b'10000000'
LEDPORT
Delay
;this waits for a while!
movlw
movwf
call
b'01000000'
LEDPORT
Delay
;this waits for a while!
movlw
movwf
call
b'00100000'
LEDPORT
Delay
;this waits for a while!
movlw
movwf
call
b'00010000'
LEDPORT
Delay
;this waits for a while!
movlw
movwf
call
b'00001000'
LEDPORT
Delay
;this waits for a while!
movlw
movwf
call
b'00000100'
LEDPORT
Delay
;this waits for a while!
movlw
movwf
call
b'00000010'
LEDPORT
Delay
;this waits for a while!
movlw
movwf
call
b'00000001'
LEDPORT
Delay
;this waits for a while!
goto
Loop
;go back and do it again
RP0
;select bank 1
;set PortB all outputs
RP0
;select bank 0
;set all outputs low
Loop
Delay
d1
movlw
movwf
movlw
movwf
movlw
movwf
d'250'
count1
0xC7
counta
0x01
countb
;delay 250 ms (4 MHz clock)
decfsz
goto
decfsz
goto
counta, f
$+2
countb, f
Delay_0
decfsz
goto
retlw
count1
d1
0x00
Delay_0
,f
end
1.6
Possiamo facilmente modificare la routine sopra in modo tale che il LED rimbalzi da una
parte all’altre, semplicemente aggiungendo altre “movlw” e “movwf” più la riga “call
Delay”.
; 1.6
LIST
p=16F628
include "P16F628.inc"
__config 0x3D18
;tell assembler what chip we are using
;include the defaults for the chip
;sets the configuration settings (oscillator
;type etc.)
cblock
;start of general purpose registers
;used in delay routine
;used in delay routine
;used in delay routine
0x20
count1
counta
countb
endc
LEDPORT Equ
LEDTRIS Equ
org
PORTB
TRISB
;set constant LEDPORT = 'PORTB'
;set constant for TRIS register
0x0000
;---------------------------
;org sets the origin, 0x0000 for the 16F628,
;this is where the program starts running
movlw
movwf
0x07
CMCON
bsf
movlw
movwf
bcf
clrf
STATUS,
b'00000000'
LEDTRIS
STATUS,
LEDPORT
movlw
movwf
call
b'10000000'
LEDPORT
Delay
;this waits for a while!
movlw
movwf
call
b'01000000'
LEDPORT
Delay
;this waits for a while!
movlw
movwf
call
b'00100000'
LEDPORT
Delay
;this waits for a while!
;turn comparators off (make it like a 16F84)
RP0
;select bank 1
;set PortB all outputs
RP0
;select bank 0
;set all outputs low
Loop
Delay
d1
movlw
movwf
call
b'00010000'
LEDPORT
Delay
;this waits for a while!
movlw
movwf
call
b'00001000'
LEDPORT
Delay
;this waits for a while!
movlw
movwf
call
b'00000100'
LEDPORT
Delay
;this waits for a while!
movlw
movwf
call
b'00000010'
LEDPORT
Delay
;this waits for a while!
movlw
movwf
call
b'00000001'
LEDPORT
Delay
;this waits for a while!
movlw
movwf
call
b'00000010'
LEDPORT
Delay
;this waits for a while!
movlw
movwf
call
b'00000100'
LEDPORT
Delay
;this waits for a while!
movlw
movwf
call
b'00001000'
LEDPORT
Delay
;this waits for a while!
movlw
movwf
call
b'00010000'
LEDPORT
Delay
;this waits for a while!
movlw
movwf
call
b'00100000'
LEDPORT
Delay
;this waits for a while!
movlw
movwf
call
b'01000000'
LEDPORT
Delay
;this waits for a while!
goto
Loop
;go back and do it again
movlw
movwf
movlw
movwf
movlw
movwf
d'250'
count1
0xC7
counta
0x01
countb
;delay 250 ms (4 MHz clock)
decfsz
goto
decfsz
goto
counta, f
$+2
countb, f
Delay_0
decfsz
goto
retlw
count1
d1
0x00
Delay_0
end
1.7
,f
Nonostante le due precedenti routine siano funzionanti, sono però rudimentali. .5 usa 24
righe all’interno del loop, utilizzando un altro comando del PIC si può ridurre il numero di
righe di codice.
; 1.7
LIST
p=16F628
include "P16F628.inc"
__config 0x3D18
type etc.)
cblock
;tell assembler what chip we are using
;include the defaults for the chip
;sets the configuration settings (oscillator
0x20
count1
counta
countb
;start of general purpose registers
;used in delay routine
;used in delay routine
;used in delay routine
endc
LEDPORT Equ
LEDTRIS Equ
PORTB
TRISB
org
0x0000
;-------------------
;set constant LEDPORT = 'PORTB'
;set constant for TRIS register
;org sets the origin, 0x0000 for the 16F628,
this is where the program starts running
movlw
movwf
0x07
CMCON
bsf
movlw
movwf
bcf
clrf
STATUS,
b'00000000'
LEDTRIS
STATUS,
LEDPORT
Start
movlw
movwf
b'10000000'
LEDPORT
;set first LED lit
Loop
bcf
call
rrf
STATUS, C
Delay
LEDPORT, f
;clear carry bit
;this waits for a while!
;ruota il contenuto del registro LEDPORT
;un bit a destra attraverso il riporto
;il valore di f è 1 pertanto il
;risultato viene rimesso nel registro
;se fosse 0 il risultato andrebbe in W
btfss
STATUS, C
;check if last bit (1 rotated into Carry)
;se il bit del riporto nel registro STATUS
;è 0 allora esegue l’istruzione successiva,
;altrimenti la salta e sostituisce con NOP
goto
goto
Loop
Start
;go back and do it again
movlw
movwf
movlw
movwf
movlw
movwf
d'250'
count1
0xC7
counta
0x01
countb
;delay 250 ms (4 MHz clock)
decfsz
goto
decfsz
goto
counta, f
$+2
countb, f
Delay_0
decfsz
goto
retlw
count1
d1
0x00
Delay
d1
;turn comparators off (make it like a 16F84)
Delay_0
end
,f
RP0
;select bank 1
;set PortB all outputs
RP0
;select bank 0
;set all outputs low
Questo esempio introduce il comando 'rrf” “Rotate Right File”, ruota il contenuto del file
register verso destra (divide il valore per 2). Poichè il comando “rrf” ruota passando dal
“carry” bit occorre essere sicuri questo sia svuotato con il comando “bcf STATUS, C”. Per
verificare il raggiungimento della fine utilizziamo la riga “btfss STATUS, C” per verificare
quando il CARRY bit è settato, questo restart la sequenza di bit dal 7.
1.8
Possiamo applicare questo metodo anche al 1.6, in questo caso aggiungendo il comando
“rlf” “Rotate Left File”, questo shifta il contenuto del registro a sinistra (moltiplicando per 2).
; 1.8
LIST
p=16F628
include "P16F628.inc"
__config 0x3D18
type etc.)
cblock
;tell assembler what chip we are using
;include the defaults for the chip
;sets the configuration settings (oscillator
0x20
count1
counta
countb
;start of general purpose registers
;used in delay routine
;used in delay routine
;used in delay routine
endc
LEDPORT Equ
LEDTRIS Equ
org
PORTB
TRISB
0x0000
;------------------
Start
movlw
movwf
0x07
CMCON
bsf
movlw
movwf
bcf
clrf
STATUS,
b'00000000'
LEDTRIS
STATUS,
LEDPORT
movlw
movwf
b'10000000'
LEDPORT
;org sets the origin, 0x0000 for the 16F628,
this is where the program starts running
;------------Loop
bcf
call
rrf
btfss
goto
movlw
movwf
sposta a destra
STATUS, C
Delay
LEDPORT, f
STATUS, C
Loop
b'00000001'
LEDPORT
;------------Loop2
bcf
call
rlf
btfss
goto
goto
sposta a sinistra
STATUS, C
Delay
LEDPORT, f
STATUS, C
Loop2
Start
Delay
d1
movlw
movwf
movlw
movwf
movlw
;set constant LEDPORT = 'PORTB'
;set constant for TRIS register
d'250'
count1
0xC7
counta
0x01
;turn comparators off (make it like a 16F84)
RP0
;select bank 1
;set PortB all outputs
RP0
;select bank 0
;set all outputs low
;set first LED lit
;clear carry bit
;this waits for a while!
;check if last bit (1 rotated into Carry)
;go back and do it again
;set last LED lit
;clear carry bit
;this waits for a while!
;ruota verso sinistra
;check if last bit (1 rotated into Carry)
;go back and do it again
;finished, back to first loop
;delay 250 ms (4 MHz clock)
movwf
countb
decfsz
goto
decfsz
goto
counta, f
$+2
countb, f
Delay_0
decfsz
goto
retlw
count1
d1
0x00
Delay_0
,f
end
1.9
Fino ad ora abbiamo utilizzato due metodi per creare il LED rimbalzante, adesso creiamo
un’altra versione ancora, utilizzando un lookup table.
; 1.9
LIST
p=16F628
include "P16F628.inc"
__config 0x3D18
type etc.)
cblock
;tell assembler what chip we are using
;include the defaults for the chip
;sets the configuration settings (oscillator
0x20
count
count1
counta
countb
;start of general purpose registers
;used in table read routine
;used in delay routine
;used in delay routine
;used in delay routine
endc
LEDPORT Equ
LEDTRIS Equ
PORTB
TRISB
org
0x0000
;----------------------movlw
0x07
movwf
CMCON
;set constant LEDPORT = 'PORTB'
;set constant for TRIS register
;org sets the origin, 0x0000 for the 16F628,
this is where the program starts running
;turn comparators off (make it like a 16F84)
bsf
movlw
movwf
bcf
clrf
STATUS,
b'00000000'
LEDTRIS
STATUS,
LEDPORT
Start
clrf
count
;set counter register “count” to zero
Read
movf
count, w
;put counter value in W
call
movwf
call
incf
Table
LEDPORT
Delay
count, w
;chiama la sub “Table”
;sposta il contenuto di W alla porta B
;chiama la sub delay
;incrementa di 1 il valore del registro count
;e copia il valore in W
xorlw
d'14'
btfsc
STATUS, Z
;check for last (14th) entry
;verifica se W contiene il valore 14
;se uguali setta il flag Z
;se Z è settato andiamo alla riga successiva
;altrimenti saltiamo una riga
goto
incf
goto
Start
count,
Read
f
RP0
;select bank 1
;set PortB all outputs
RP0
;select bank 0
;set all outputs low
;if start from beginning
;else do next incrementa il valore count
Table
Delay
d1
ADDWF
PCL, f
;data table for bit pattern
;aggiunge al program counter il valore
;contenuto in W
;in base al contenuto di W si salta infatti sommando al PC il valore di W
;il PC si sposta a PC+W
retlw
retlw
retlw
retlw
retlw
retlw
retlw
retlw
retlw
retlw
retlw
retlw
retlw
retlw
b'10000000'
b'01000000'
b'00100000'
b'00010000'
b'00001000'
b'00000100'
b'00000010'
b'00000001'
b'00000010'
b'00000100'
b'00001000'
b'00010000'
b'00100000'
b'01000000'
;inserisce il valore in W
movlw
movwf
movlw
movwf
movlw
movwf
d'250'
count1
0xC7
counta
0x01
countb
;delay 250 ms (4 MHz clock)
decfsz
goto
decfsz
goto
counta, f
$+2
countb, f
Delay_0
decfsz
goto
retlw
count1
d1
0x00
Delay_0
,f
end
Introduce un altro nuovo comando, il 'addwf” “ADD W to File”, è un comando di somma,
infatti essendo il PIC con architettura RISC ha solo 35 comandi, pertanto alcuni
comandi apparentemente semplici come la lettura dei dati di una tabella non sono
presenti.
Nel 1.2 abbiamo usato il comando “retlw”, senza usarne il valore restituito, adesso per
creare la data table facciamo uso del valore restituito.
Alla etichetta “Start” prima poniamo a zero un contatore che sarà poi utilizzato, il “clrf
Count”, questo verrà poi spostato nel registro W mediante “movf Count, w”, e la subroutine
Table verrà chiamata.
La prima riga della subroutine è “addwf PCL, f”, la quale somma il contenuto di W (che è
stato appena settato a zero) con il registro PCL, il PCL è il Program Counter, conta
esattamente dove si trova l’esecuzione del programma, perciò aggiungendovi zero ci si
sposta alla riga successiva “retlw b’10000000' che restituisce b'10000000' nel registro W,
Questo è poi spostato ai LED.
l conteggio viene poi incrementato e il programma cicla richiamando nuovamente la Table,
questa volta W contiene il valore 1, poi sommato a PCL il quale fa un salto di una riga e
restituisce la seguente riga della Table – si continua per il resto della table. Non è però
una buona cosa superare la lunghezza della tabella, causando un salto del PCL ad una
riga dopo alla tabella, la quale in questo caso è la Delay. Per evitarlo si controlla il valore
di count, usando “xorlw d14” “eXclusive Or Literal with W”, il quale implementa un
“exclusive or” con il registro W (dove si trova il valore di count) e il valore 14, e setta il flag
“Z” “Zero” se sono uguali, poi controlliamo il flag Z, e se è settato facciamo un salto
indietro all’inizio e resettiamo count a zero e così via.
Il vantaggio di questo sistema è la possibilità di avere qualsiasi pattern nella tabella e la
facilità di modifica della stessa.

Documenti analoghi

Lezione n° 3 - mrscuole.net

Lezione n° 3 - mrscuole.net Il Compilatore può essere • in linguaggio BASIC ( ad esempio il PicBasic) • in linguaggio C • di tipo grafico, ossia che usa simboli grafici al posto delle istruzioni. Ad esempio usa il simbolo di ...

Dettagli