APPUNTI SUL PIC16F84 Gianluca 'gurutech' Mascolo v0.1 04/04/2004 mailto: gurutech_at_gurutech.it Hackit04 Il PIC16F84 è un microcontrollore a 8-bit dotato di due porte di I/O digitali, una da 5 bit e una da 8 bit. Pinout del PIC16F84 La memoria all'interno del PIC16F84 è organizzata in questo modo. addr BANK 0 BANK 1 addr Come si vede è divisa in due banchi: 00h BANK0 è utilizzato per le operazioni di I/O vere Indirect Addr. Indirect Addr. 80h e proprie 01h TMR0 OPTION_REG 81h BANK1 è utilizzato per controllare le modalità di 02h PCL PCL 82h funzionamento delle porte 03h STATUS STATUS 83h Tutta la memoria è divisa in registri da 8 bit. 04h Le zone di memoria da 0Ch a 4Fh sono mappate FSR FSR 84h su quelle da 8Ch a CFh (perciò 0Ch e 8Ch 05h PORTA TRISA 85h conterranno la stessa cosa), e sono lasciate a 06h 07h PORTB -- TRISB -- 86h 87h disposizione dei dati utente. Proviamo a capire come funziona con un esempio. 08h EEDATA EECON1 88h Vogliamo visualizzare un countdown da 9 a 0 su un display a led 7 segmenti collegato alla porta B. 09h EEADR EECON2 89h Segue il codice del programma 0Ah PCLATH PCLATH 8Ah 0Bh INTCON INTCON 8Bh 0Ch 4Fh 50h 68 General Purpose Register Mapped (accesses) in Bank 0 8Ch CFh D0h 7Fh FFh (Le zone in grigio non sono implementate e vengono lette come zero)
;led7dig.asm ;programma di countdown su un display a 7 segmenti PROCESSOR RADIX INCLUDE 16F84 DEC "P16F84.INC" ORG 0x0C ;Riservo dello spazio per alcune variabili CONTATORE RES 2 ;Contatore per un ciclo di ritardo CIFRA RES 10 ;Cifre da mettere sul display INDICE RES 1 ;Indice per puntare alle cifre ORG 0x00 movlw 11000000B movwf CIFRA+0 movlw 11111001B movwf CIFRA+1 movlw 10100100B movwf CIFRA+2 movlw 10110000B movwf CIFRA+3 movlw 10011001B movwf CIFRA+4 movlw 10010010B movwf CIFRA+5 movlw 10000010B movwf CIFRA+6 movlw 11111000B movwf CIFRA+7 movlw 10000000B movwf CIFRA+8 movlw 10010000B movwf CIFRA+9 ;Memorizzo l'impostazione dei segmenti per ; visualizzare ogni cifra in delle locazioni ; di memoria contigue, in modo da poterci ; accedere come con un array bsf STATUS,RP0 ;Passo al bank 1 movlw 00000000B movwf TRISB ;Imposto tutta la porta B come output bcf STATUS,RP0 ;Ritorno al bank 0 INFINITO movlw 0x9 ;punto l'indice sul 9 movwf INDICE COUNTD movlw 0x0E ;0x0E e' uno spiazzamento di memoria fisso addwf INDICE,0 ; che corrisponde alla cifra 0 movwf FSR ;Carico l'indice in un puntatore movf INDF,0 ;Metto nell'accumulatore la zona puntata movwf PORTB ;Pongo sulla porta B il dato call RITARDO ;zzzz... decfsz INDICE,1 ;Decremento l'indice e salto l'istruzione goto COUNTD ; successiva se questo è nullo goto INFINITO ;Ricominciamo! RITARDO clrf CONTATORE clrf CONTATORE+1 RLOOP decfsz CONTATORE,1 goto RLOOP decfsz CONTATORE+1,1 goto RLOOP return END
Analizziamo il programma: Innanzitutto le parti che ho evidenziato in blu sono direttive al compilatore e non istruzioni vere e proprie. Sono importantissime le tabulazioni di inizio riga: Se inseriamo una tabulazione stiamo immettendo un istruzione; Se non inseriamo una tabulazione stiamo assegnando un etichetta. PROCESSOR istruisce il compilatore sul tipo di CPU RADIX stabilisce che dove non specificato diversamente i numeri sono in DECimale INCLUDE copia il contenuto di un'altro file all'interno di un nostro programma, il file da noi incluso ci permette di utilizzare etichette, ad esempio TRISB, al posto dell'indirizzo del registro corrispondente. ORG specifica che le direttive successive saranno organizzate in celle di memoria dalla 0x0C (area dati). Successivamente ci riportiamo all'area per il programma 0x00. movlw mette nell'accumulatore W un numero. movwf mette nel registro indicato da un indirizzo il contenuto di W bsf setta (mette a uno) un bit di un registro indicato. bcf resetta (mette a zero) un bit di un registro indicato. f b a + f a g b e d c g d c e Il display a 7 segmenti a mia disposizione è del tipo ad anodo comune, per cui i segmenti si accendono quando ricevono uno 0. Ho collegato il display nel seguente modo: Bit RB7 RB6 RB5 RB4 RB3 RB2 RB1 RB0 Segmento // g f e d c b a Memorizzo perciò la configurazione dei segmenti per le 10 cifre in altrettanti registri di memoria. Agendo sul bit RP0 del registro STATUS possiamo passare dal bank0 al bank1 e viceversa. Ora passo al bank1 perchè devo impostare la porta B come uscita e non come ingresso. Ogni bit della porta può essere configurato indipendentemente in una delle due direzioni. Per stabilirlo carichiamo in TRISB un byte in cui ogni bit a 0 setta la corrispondente uscita come output e ogni bit a 1 come input Ad esempio, se caricassimo in TRISB 01001110 otterremmo RB7 RB6 RB5 RB4 RB3 RB2 RB1 RB0 Direz OUT IN OUT OUT IN IN IN OUT TRISB 0 1 0 0 1 1 1 0 Dopo aver configurato le porte torniamo al bank0. A questo punto siamo pronti per creare il codice di countdown, facendo muovere un puntatore da 9 a 0. All'indice che abbiamo creato dobbiamo aggiungere uno spiazzamento. Questo sarà 0x0E, perchè la memoria delle variabili parte da 0x0C, ma le prime due celle le abbiamo riservate per un contatore (vedi dopo), per cui le nostre cifre partono proprio da 0x0E. Faccio questo con addwf INDICE,0; questa istruzione dice: aggiungi il contenuto dell'accumulatore W al registro f=indice e metti il risultato nell'accumulatore (Il risultato dell'operazione potrebbe altrimenti essere rimesso nel registro se dopo la virgola avessimo messo 1). Ottenuto così l'indirizzo che contiene la cifra che ci interessa, lo mettiamo nel registro FSR, che è un registro per l'indirizzamento indiretto. Infatti successivamente mettiamo INDF nell'accumulatore. Tutte le volte che si legge INDF viene restituito il contenuto della cella il cui indirizzo è memorizzato in FSR. A questo punto possiamo semplicemente mettere l'accumulatore in uscita sulla porta B.
Ora creo un piccolo ritardo tramite una CALL a subroutine perchè altrimenti non vedrei scorrere le cifre sul display; per fare questo conto 255 per 255 volte, in questo modo: metto zero in due variabili CONTATORE al primo decremento di test queste variabili diventano 0xFF e da lì in avanti continua il decremento fino al raggiungimento dello 0. Tool per l'assemblaggio e la scrittura: Per assemblare il nostro programma utilizziamo MPASMWIN, distribuito dalla stessa MICROCHIP, produttrice del PIC16F84. MPASMWIN può girare su Linux tramite wine senza nessun accorgimento particolare. Selezioniamo il nostro codice con il tasto "Browse..." e poi clicchiamo su "Assemble". Dopo aver macinato un po', l'assemblatore mettera nella stessa directory del nostro programma altri file con estensione.cod,.err,.lst e.hex. I più importanti sono: led7dig.err, che contiene eventuali errori di compilazione led7dig.hex, che è il codice vero e proprio da passare al programmatore Abbiamo quasi finito, non ci resta che programmare il PIC16F84 e inserirlo nel circuito. Il programmatore che ho usato io si chiama PICALLW, reperibile su http://www.picallw.com e anch'esso installabile su Linux tramite wine. Per poterlo eseguire correttamente è essenziale avere il modulo del kernel chiamato ppdev.o, che permette a programmi in user-space di accedere allea porta parallela. Di conseguenza modificherò le sezioni del mio file config di wine in modo da includere:
[parallelports] "Lpt1" = "/dev/lp0" [ppdev] ;; key: io-base of the emulated port ;; value : parport-device{,timeout} ;; timeout for auto closing an open device ( not yet implemented) "378" = "/dev/parport0" ;"278" = "/dev/parport1" ;"3bc" = "/dev/parport2" [ports] "read" = "0x779,0x379,0x278-0x27a,0x280-0x2a0,0x378-0x37f" "write" = "0x779,0x379,0x278-0x27a,0x280-0x2a0,0x378-0x37f" Picallw in esecuzione con wine L'hardware di programmazione è un kit parallelo della Asamicros, http://www.asamicros.com, che corrisponde a un "P16PRO 74LS05,6 KIT96" nell voce Hardware setup di picallw. Apriamo led7dig.hex (tasto F2 o voce "Open Program"), e configuriamo l'oscillatore su XT (quarzo) con il tasto F3. E' importante scegliere correttamente l'oscillatore del proprio hardware, altrimenti il PIC16F84 non parte. Infine programmiamo la pic con il tasto F4. Spostiamo il PIC16F84 sulla development board... connettiamo il display... fatto! ora abbiamo anche noi il conto alla rovescia come alla NASA!.