P I C 1 6 F 8 4   -   A P P U N T I    D I    U T I L I Z Z O

(avvertenze)

[Precedente]   [Indice principale]   [Seguente]

[Porte di ingresso/uscita]   [Trasmissione seriale]   [Potenziamento assembler]



PORTE DI INGRESSO/USCITA



Picture by Sergio Tanzilli

Il PIC 16F84 ha 13 pin usabili come ingressi o uscite singolarmente programmabili. La scelta se rendere un pin un ingresso o un' uscita viene effettuata scrivendo un valore nei registri TRISA e TRISB presenti nel banco1. TRISA controlla i pin della porta A (RA0..RA4), il bit 0 e' associato al pin RA0, il bit 4 e' associato al pin RA4. Uno 0 in questi bit rende i pin delle uscite (0=out), un 1 invece li rende degli ingressi (1=in). TRISB e' il registro che controlla invece i pin della porta B (RB0..RB7). All'accensione, o dopo un reset, TRISA e TRISB contengono tutti i bit a 1, pertanto i pin sono programmati automaticamente come ingressi. E' possibile cambiare la configurazione dei pin in ogni momento durante il programma, le uscite possono cioe' essere trasformate in ingressi e viceversa. Una volta scelto quali pin devono essere delle uscite e quali degli ingressi, si puo' accedere al loro valore tramite i registri PORTA e PORTB presenti nel banco0.

I pin configurati come uscite sono di tipo push-pull, sono cioe' in grado sia di assorbire corrente dal positivo dell'alimentazione (25mA), sia di fornirla verso massa (20mA), ad eccezione di RA4 che in uscita e' di tipo open-collector (che quindi la puo' solo assorbire come se fosse un interruttore che si chiude verso massa). I pin configurati come ingressi sono in alta impedenza e quindi bisogna ricordarsi di non lasciare mai scollegati quelli inutilizzati, ma di collegarli a +Vcc con una resistenza da 10K. Lo stesso discorso vale per i pin della porta B, a meno che non si attivino le resistenze interne di pull-up con le istruzioni:
 

   BANK1
   BCF    OPTION_REG,7   ;Attiva pull-ups su porta B
 

Se vengono attivate le resistenze di pull-up della porta B e' possibile collegare direttamente ai suoi pin interruttori, commutatori e pulsanti (che chiudono verso massa) senza bisogno di nessun altro componente esterno (i rimbalzi meccanici di questi componenti vanno pero' eliminati scrivendo apposite routines software).

Va ricordato che ha senso leggere (dalla porta o dalla portb) i pin programmati come ingressi, ma non ne ha invece leggere quelli programmati come uscite, il loro valore va semplicemente ignorato. Allo stesso modo ha senso scrivere in quelli programmati come uscite ma non ne ha in quelli programmati come ingressi, a meno che non si preveda di trasformarli in uscite, in questo caso infatti l'uscita assume subito l'ultimo valore che e' stato scritto in quel bit della porta mentre il pin era ancora un ingresso.

L'esempio seguente mostra come configurare PORTA come uscita e scriverci un valore (ricordando che per comodita' abbiamo ridefinito le istruzioni di scambio banco: #DEFINE  BANK0  BCF STATUS,RP0   e  #DEFINE  BANK1  BSF STATUS,RP0):
 

   BANK1               ;attiva banco 1
   CLRF      TRISA     ;azzera bit di TRISA (tutte uscite)
   BANK0               ;ritorna al banco 0
   MOVLW     11000B
   MOVWF     PORTA     ;scrittura sulla porta
 

Usando le istruzioni BCF e BSF e' possibile resettare o settare un singolo bit di una qualsiasi cella di memoria o di un pin di ingresso/uscita. Il seguente esempio mostra come generare un breve impulso di 1µS (con clock 4Mhz) dal pin di uscita RA2 (naturalmente deve essere attivo il banco0):
 

   BSF       PORTA,2   ;manda a 1 il pin di uscita
   BCF       PORTA,2   ;lo riporta a 0
 

La ridefinizione (#DEFINE) puo' essere usata anche per assegnare un nome simbolico (alias) a un qualsiasi pin di ingresso/uscita, e anzi questa e' una pratica corretta di programmazione, perche' permette modifiche piu' semplici al software e una maggiore portabilita'. Per esempio potrebbe essere comodo dare il nome "SEGNALE" al pin RA2:
 

   #DEFINE   SEGNALE   PORTA,2
 

A questo punto il nostro impulso lo possiamo anche generare scrivendo:
 

   BSF       SEGNALE   ;manda a 1 il pin di uscita
   BCF       SEGNALE   ;lo riporta a 0
 

Detto questo sappiamo come configurare i pin delle porte, come scrivere o leggere su di essi (e anche su uno singolo), sappiamo quanta corrente ci puo' passare e che RA4 e' un open-collector (o meglio open-drain), e abbiamo visto come attivare le resistenze di pull-up della porta B.
 
 

TRASMISSIONE SERIALE SOFTWARE


Per mettere in pratica quanto, visto sia riguardo alla parte software che hardware, possiamo realizzare un semplice trasmettitore seriale che invia continuamente dal pin RA4 i bit letti dalla porta B. Questo sistema puo' essere utile per il debug dei programmi, infatti permette di inviare verso un PC il contenuto di qualsiasi cella di memoria per verificarne il contenuto. Il programma sul PIC trasmette un byte ogni 10 ms circa nel classico formato asincrono start-stop 9600 8-N-1. Per poter leggere i dati in arrivo sul PC ho scritto un semplicissimo visualizzatore binario-esadecimale-decimale (provato su W95/98):

[Download visualizzatore txser.zip (87K)]
(Scompattarlo e lanciare txser.exe, riceve solo da COM1)

Lo schema del circuito e' riportato nella figura seguente. I pin RB0..RB7 sono gli ingressi, il pin RA4 e' l'uscita che comanda un transistor adattatore di livello TTL/EIA, in modo da inviare verso il PC le tensioni corrette sia in ampiezza che in polarita'. La tensione negativa richiesta dalla seriale del PC e' presa dal pin TX della seriale stessa, infatti, visto che il PC non deve trasmettere nulla, su questo pin sono sempre presenti  -12V. Il terminale chiamato RX e' la ricezione del PC, quello chiamato TX e' la sua trasmissione (e' evidente che il nostro PIC deve trasmettere verso la ricezione del PC, in caso di dubbi sulla piedinatura della porta seriale o sul formato dei dati vedere l'apposita pagina).
  

Il programma del PIC: txser.asm
Include per pic16f84a: P16F84a.INC
L'eseguibile: TXSER.HEX


Foto del prototipo montato su bredboard.


POTENZIAMENTO ASSEMBLER


Si e' visto che usando la direttiva di ridefinizione #DEFINE e' possibile condensare un'intera istruzione in un nome simbolico, piu' comodo da ricordare e piu' semplice da scrivere. Per esempio i comandi BANK0 e BANK1 usati precedentemente sono ridefinizioni delle istruzioni complete "BCF STATUS,RP0" e "BSF STATUS,RP0".

Il compilatore mette anche a disposizione la direttiva macro che permette di racchiudere con un nome unico un gruppo di istruzioni, e consente anche di usare degli argomenti, cioe' dei parametri che assumono di volta in volta il valore necessario.

Per comprendere l'utilita' di una macro vediamo un semplicissimo esempio. Possiamo pensare alle seguenti due istruzioni che servono per caricare 44 nella variabile contatore (che naturalmente va definita prima con una equ o una res):
 

   MOVLW   44
   MOVWF   CONTATORE
 

Non esiste nessun modo per caricare direttamente 44 nella variabile, pero' possiamo scrivere una macro che racchiuda queste due istruzioni e usarla come se fosse una nuova istruzione singola (macroistruzione), per esempio:
 

   LDF     CONTATORE,44
 

...che vorrebbe dire: carica nella variabile contatore il valore 44... la macro da usare per "creare" questa nuova istruzione e':
 

   LDF     MACRO arg1,arg2
           MOVLW arg2
           MOVWF arg1
           ENDM
 

Il nome della macro e' LDF, arg1 e arg2 sono gli argomenti, in pratica i nomi e i valori che noi scriveremo quando useremo l'istruzione LDF e che il compilatore pensera' poi a sostituire automaticamente nelle istruzioni all'interno della macro..

Usando ridefinizioni e macro e' quindi in un certo modo possibile "costruire" delle nuove istruzioni, se non fisicamente per il processore, almeno idealmente per il programmatore. Per prova ho voluto aggiungere nuove istruzioni come i salti condizionati dai flag (Jc Jnc Jz Jnz) che sui pic mancano.

Nel file pwrasm.inc sono contenute le ridefinizioni e le macro necessarie per implementare le nuove istruzioni (e un breve riepilogo), questo file puo' essere copiato in ogni programma con un copia/incolla (sconsigliato) o incluso come le altre definizioni per il pic (metodo corretto).

Le nuove istruzioni comprendono la serie completa di salti (J..) e skip (SK) condizionati dal valore dei flags (Z  C),  Abbiamo anche il salto condizionato dal valore di un bit, per esempio JNB effettua un salto se il bit testato vale 0 (clear). Oltre al caricamento diretto in una variabile (LDF) abbiamo anche lo spostamento da una variabile a un'altra: MOVFF var1,var2 che trasferisce var1 in var2. Molte istruzioni lavorano su 16, 24 e 32 bit, comprese rotazioni, shift, operazioni logiche e aritmetiche.  I singoli bit possono essere anche mossi da un registro all'altro (MOVB) o cambiati di stato (BTG). Ci sono poi le istruzioni di attesa condizionata sul valore di un bit (WAITB WAITNB) e di ritardo (DELAY). E per finire la comodissima DJNZ che permette di decrementare una variabile e saltare se non e' arrivata a zero. Le macroistruzioni per il cambio banco sono 4 per usare anche i pic 16F628 e la serie 16F87x.
 


[Precedente]   [Indice principale]   [Seguente]


By Claudio Fin 2001 - Ultimo aggiornamento pagina 11-4-2004