[Precedente] [Indice principale] [Seguente]
[Porte di ingresso/uscita] [Trasmissione seriale] [Potenziamento assembler]
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]
|
|