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
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 ...