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]

[Confronto tra numeri a 8 bit]   [Ricezione seriale]   [Loop lunghi]


CONFRONTO TRA NUMERI A 8 BIT


In un programma puo' essere necessario confrontare due valori per stabilire quale dei due e' maggiore (o minore) dell'altro , o se sono uguali, o tutte le altre combinazioni possibili (che in tutto sono 6). Il confronto viene effettuato facendone la sottrazione e verificando poi lo stato dei flags C e Z.

Infatti durante una sottrazione viene settato il flag Z nel caso in cui il risultato sia 0, e resettato il flag C nel caso in cui si verifichi un prestito. Esistono due istruzioni di sottrazione, la prima e' sublw (dal valore specificato viene sottratto l'accumulatore), la seconda e' subwf (dalla variabile specificata viene sottratto l'accumulatore):
 

   SUBLW 45       =    W = 45 - W
   SUBWF var,W    =    W = var - W
   SUBWF var,F    =    var = var - W
 

Facendo la sottrazione si puo' pensare nei termini di:  confronto il valore con quello dell'accumulatore, per vedere se l'accumulatore e' maggiore, minore, uguale ecc...  

Condizioni Impostazione dei flags
W = var  (uguale) 
W <> var (diverso)
W > var  (maggiore) 
W < var  (minore) 
W >= var (maggiore o uguale) 
W <= var (minore o uguale) 
Z=1
Z=0
        C=0
Z=0 and C=1 
Z=1 or  C=0
        C=1 

Come si puo' vedere la condizione di uguaglianza e' segnalata dal flag Z settato (il C in questo caso e' irrilevante) e quella di disuguaglianza dal flag Z resettato, pertanto puo' essere semplicemente testata con le istruzioni btfss o btfsc.  Le condizioni "minore" e  "maggiore o uguale" sono invece abbastanza complesse da codificare per il fatto che devono essere tenuti in considerazione entrambi i flags C e Z, ma il lavoro in pratica si semplifica scambiando l'ordine degli operandi nel seguente modo:

Se devo verificare se  A>B  faccio  B-A,  se C vale 0 la condizione e' vera.
Se devo verificare se  A<B  faccio  A-B,  se C vale 0 la condizione e' vera.
Se devo verificare se  A<=B  faccio B-A,  se C vale 1 la condizione e' vera.
Se devo verificare se  A>=B  faccio A-B,  se C vale 1 la condizione e' vera.

ESEMPI:

;IF pippo>26 THEN GOTO label

    MOVF     pippo,W
    SUBLW    26
    BTFSS    STATUS,C
    GOTO     label

;IF pippo<120 THEN GOTO label

    MOVLW    120
    SUBWF    pippo,W
    BTFSS    STATUS,C
    GOTO     label

;IF pippo<=pluto THEN GOTO label

    MOVF     pippo,W
    SUBWF    pluto,W
    BTFSC    STATUS,C
    GOTO     label

;IF pippo>=pluto THEN GOTO label

    MOVF     pluto,W
    SUBWF    pippo,W
    BTFSC    STATUS,C
    GOTO     label

 

RICEZIONE SERIALE


Similmente a quanto visto per la trasmissione seriale software e' possibile realizzare un ricevitore seriale che acquisisce un byte dal PC e lo presenta in formato binario sui pin RB0..RB7 (questa volta configurati come uscite). Questo circuito puo' essere utile a tutti coloro che hanno bisogno di un convertitore seriale/parallelo per comandare attraverso la porta seriale fino a 8 carichi indipendenti come ad esempio dei rele'.

Lo schema del circuito e' riportato nella figura seguente. I pin RB0..RB7 sono le uscite, il pin RA0 e' l'ingresso da cui si ricevono i dati attraverso un transistor adattatore di livello EIA/TTL. Il terminale chiamato TX e' la trasmissione del PC (in caso di dubbi sulla piedinatura della porta seriale o sul formato dei dati vedere l'apposita pagina).

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

Il programma provvede innanzitutto a configurare la porta B come uscita, avendo l'accortezza di precaricare 0 nel registro di uscita (portb) prima di renderla un'uscita. In questo modo all'istante dell'accensione questi pin sono in alta impedenza e subito dopo diventano delle uscite a zero senza glitch, cioe' senza stati incerti della durata di qualche microsecondo che potrebbero creare falsi comandi verso l'esterno, e questo permette di pilotare tranquillamente dei comuni transistor npn (o array di transistor integrati come gli ULN2003) come indicato nello schema seguente:

Il formato di ricezione e' asincrono start-stop 9600 8-N-1. Gli unici controlli effettuati sulla corretteza dei dati sono ll valore del bit di start (che deve essere 0) e quello del bit di stop (che deve essere 1). I byte non corretti vengono ignorati, quelli corretti vengono portati sull'uscita.

Togliendo il transistor adattatore di livello sia da questo circuito che da quello del trasmettitore e' possibile collegare tra loro due pic (uno trasmettitore e l'altro ricevitore) e fare in modo di portare sulle uscite dell'uno i valori in ingresso dell'altro (puo' servire per esempio per trasferire su due soli fili lo stato di 8 segnali digitali)... attenzione pero' che questo sistema non e' ad alta affidabilita', e percio' e' adatto solo per scopi didattici o dove la presenza di errori di trasmissione e' una cosa accettabile.




LOOP CON ALTO NUMERO DI CICLI


Come gia' detto nel paragrafo sui loop, con un registro a 8 bit si puo' realizzare un numero di cicli massimo di 256 iterazioni. Con combinazioni di registri, o con loop nidificati uno dentro l'altro, si puo' raggiungere un numero di iterazioni qualsiasi, con lo scotto pero' di dover scrivere una notevole quantita' di istruzioni solo per il controllo del ciclo (ben 8 per un ciclo da 65536 iterazioni massime, realizzato quindi con 2 registri da 8 bit). Ancora una volta ci vengono incontro le macro, infatti quelle 8 istruzioni possono essere racchiuse in un'unica macroistruzione chiamata per esempio Djnz16 (decrementa una variabile a 16 bit e salta se non e' arrivata a 0):
 

Djnz16      macro  var,addr
            decf   var,f     ;dec parte bassa
            incf   var,w     ;incr. per controllare se torna a 0
            btfsc  STATUS,Z  ;skip se non tornato a zero
            decf   var+1,f   ;altrimenti decrementa parte alta
            movf   var,w     ;carica parte bassa
            iorwf  var+1,w   ;mette in or con parte alta
            btfss  STATUS,Z  ;se tutto zero termina
            goto   addr      ;altrimenti next
            endm
 

Per realizzare un ciclo a 16 bit con questa macro dobbiamo riservare 2 byte per una variabile di conteggio, chiamata ad esempio cont:
 

            ORG    0CH
            cont   RES   2
 

Poi dobbiamo assegnare ai suoi 2 byte il valore che ci interessa, per esempio per 25000 iterazioni abbiamo 97 come parte alta e 168 come parte bassa (256*97+168=25000), possiamo percio' caricare i due valori in cont ricordandoci che all'indirizzo piu' basso va messa la parte bassa. L'esempio seguente mostra come realizzare questo loop a 16 bit:
 

            movlw  168
            movwf  cont
            movlw  97
            movwf  cont+1
label       .....
            .....
            Djnz16 cont,label
 

Allo stesso modo possiamo anche pensare ad una macro per un loop a 24 bit (che puo' eseguire fino a  16.777.216 iterazioni):
 

Djnz24      macro  var,addr
            decf   var,f     ;dec parte bassa
            incfsz var,w     ;incr. per controllare se torna a 0
            goto   $+5
            decf   var+1,f   ;decrementa parte media
            incf   var+1,w   ;incr. per controllare se torna a 0
            btfsc  STATUS,Z  ;skip se non tornato a zero
            decf   var+2,f   ;se tornato a zero decrementa parte alta
            movf   var,w     ;carica parte bassa
            iorwf  var+1,w   ;mette in or con parte media
            iorwf  var+2,w   ;mette in or con parte alta
            btfss  STATUS,Z  ;se tutto zero termina
            goto   addr      ;altrimenti next
            endm
 

L'esempio seguente realizza un ciclo di 900000 iterazioni usando la macroistruzione djnz24:
 

            ORG    0CH
            cont   RES   3       ;riserva 3 byte per il contatore

            movlw  160
            movwf  cont          ;carica parte bassa
            movlw  187
            movwf  cont+1        ;carica parte media
            movlw  13
            movwf  cont+2        ;carica parte alta
label       .....
            .....
            Djnz24 cont,label    ;decrementa e salta a label se non 0
 

Per quanto riguarda i tempi di esecuzione come gia' detto si calcolano considerando che al posto della macro ci siano scritte le istruzioni in essa contenute.

Per scrivere poi piu' comodamente le assegnazioni di valori a variabili a 8,16 e 24 bit possiamo scrivere altre tre macro:
 

Ldf         macro  var,n
            movlw  n
            movwf  var
            endm
 

Ldf16       macro  var,n2,n1
            movlw  n1
            movwf  var
            movlw  n2
            movwf  var+1
            endm
 

Ldf24       macro  var,n3,n2,n1
            movlw  n1
            movwf  var
            movlw  n2
            movwf  var+1
            movlw  n3
            movwf  var+2
            endm
 

Queste ci consentono di assegnare un valore a 8,16 o a 24 bit con un'unica istruzione. Per esempio, se nel nostro contatore a 16 bit vogliamo caricare 25000 e in quello a 24 bit 900000 possiamo scrivere:
 

            Ldf16  cont,97,168

            Ldf24  cont,13,187,160
 

I vari valori vanno scritti dal piu' significativo (parte alta) al meno significativo (parte bassa), in questo modo e' anche semplice determinarli scrivendone le doppiette esadecimali:
 

         25000 = 61A8      Ldf16 cont,61H,0A8H

        900000 = 0DBBA0    Ldf24 cont,0DH,0BBH,0A0H
 

...e la scrittura di un ciclo da 8, 16 o 24 bit richiede sempre solo due righe di programma:
 

            Ldf    cont,165     ;165 iterazioni
label       ....
            Djnz   cont,label
 
 

            Ldf16  cont,44,0    ;11264 iterazioni
label       ....
            Djnz16 cont,label
 
 

            Ldf24  cont,8,0,133  ;524421 iterazioni
label       ....
            Djnz24 cont,label
 
 

[Precedente]   [Indice principale]   [Seguente]


Pagina e disegni By Claudio Fin 2001
Ultimo aggiornamento 11-4-2004