home | area personale         schemi | tutorial | robotica | pic micro | recensioni         forum | chat irc         faq | contatti         store | Ordina PCB
username
password
cerca
 
LA MASCHERATURA tipo: livello:
Una tecnica per la manipolazione dei dati, largamente usata nella programmazione
 
 



La Mascheratura

 


Introduzione

Questo tutorial è dedicato ad una tecnica molto usata nella programmazione, che permette di settare (porre al valore di 1), resettare (porre al valore di 0) o invertire i bit di un qualunque dato binario.
Solo pochi microprocessori/microcontrollori dispongono di istruzioni per fare direttamente queste operazioni che sono molto comuni nella programmazione di basso livello (basso nel senso che è vicino all'hardware non che sia di poco conto). 
Visto che in alcuni ambienti di programmazione è indispensabile saperla utilizzare, per essere in grado di fare queste operazioni e per capire come le fanno gli altri, ci tocca studiare questa tecnica.
Nella spiegazione partiremo dall'algebra di Boole.
Chi già la conosce può saltare qualche paragrafo.


Algebra di Boole

Per capire l'argomento dobbiamo fare un passo indietro: andiamo a vedere alcuni elementi fondamentali dell'algebra di Boole: le tabelle di verità di quattro operatori fondamentali, vale a dire AND, OR, NOT e XOR, che indicheremo come “Logici”.

AND
Ingressi Uscita
A B Y
Falso  Falso  Falso
 Falso  Vero  Falso
 Vero Falso   Falso
 Vero Vero  Vero 

Quella precedente, e' la tabella di verità dell'operatore AND (che significa qualcosa come “e  anche”). 

Si legge per righe.

Il risultato Y sarà vero solo quando lo saranno contemporaneamente sia l'ingresso A che quello B.
Un sistema che si comporta cosi' e' per esempio un sistema idraulico con due rubinetti in serie. Ipotizzando la corrispondenza
A= “il primo rubinetto e' aperto”
B=“il secondo rubinetto e' aperto”
Y=”esce acqua dal sistema”

AND "idraulico"


Normalmente, nei sistemi digitali, visto che si maneggiano grandezze booleane che possono essere cioè vere oppure false e numeri binari che possono valere 0 oppure 1, per comodita' si pone Vero=1; Falso=0.
Fatta questa posizione, la tabella di verità dell'AND diventa la seguente:
 

AND
A B Y
0 0 0
0 1 0
1 0 0
1 1 1

Analogamente la tabella di verità dell'OR (che significa qualcosa come “oppure”)
è la seguente:
 

OR
Ingressi Uscita
A B Y
Falso Falso Falso
Falso Vero Vero
Vero Falso Vero
Vero Vero Vero

 Rifatta con 0 e 1, diventa:

OR
A B Y
0 0 0
0 1 1
1 0 1
1 1 1

Un sistema idraulico che si comporta da OR, ipotizzando sempre la corrispondenza di significati:
A= “il primo rubinetto e' aperto”
B=“il secondo rubinetto e' aperto”
Y=”esce acqua dal sistema”
e' quello che si ottiene mettendo in parallelo due rubinetti.


Lo XOR, o Or Esclusivo, non corrisponde a nessuna espressione usata comunemente. E' definito dalla tabella di verità seguente che vi fornisco direttamente con zeri e uni:

XOR
Ingressi Uscita
A B Y
0 0 0
0 1 1
1 0 1
1 1 0

 


 Altro operatore booleano fondamentale è il NOT, che ha un solo ingresso:

NOT
Ingresso Uscita
A Y
Vero Falso
Falso Vero

 

o, in alternativa:

NOT
Ingresso Uscita
A Y
0 1
1 0

 

Il NOT è l'operatore “Bastian Contrario”. Quando gli dai un valore in ingresso, lui produce un'uscita che e' sempre l'opposto.


A proposito degli operatori dell'algebra di Boole e dei sistemi che hanno un comportamento analogo, vi suggerisco qualche domanda-riflessione:

  • pensate ad una porta con due serrature: quando potremo aprirla in relazione all'avere le due chiavi A e B ? (provate a formulare la cosa con uno degli operatori booleani) 
  • pensate ad una stanza con due porte, ognuna con una sola serratura: quando potremo entrarci in relazione all'avere le chiavi delle due porte A e B ?
  • pensate ad un sistema elettrico con due interruttori in serie, a monte di una lampadina: quando si accenderà in relazione all'avere attivato i due interruttori A e B ?
  • pensate all'altalena illustrata nel disegno precedente. Quando si trova in alto la bambina in relazione a quando si trova in alto il bambino ?

 

 

Tre Proprietà che ci fanno comodo

Se andiamo a vedere la tabella di verità dell'AND, troviamo che nella prima e terza riga, dove B vale 0, l'uscita Y vale anche 0, nelle altre 2 righe, dove B vale invece 1, l'uscita Y ha lo stesso valore di B.
Possiamo scrivere questo fatto cosi':

A AND 0 = 0  
e
A AND 1 = A

 

Facendo lo stesso discorso con la prima e la terza riga della tabella di verita' dell'OR, ci accorgiamo che quando B vale 0, Y = A mentre quando B vale 1, Y =1. Le due leggi corrispondenti si scrivono:

A OR 0 = A  
e
A OR 1 = 1

 

Infine andiamo a vedere come si comporta l'operatore XOR.
Quando B vale 0, troviamo che Y=A, quando B vale 1, Y=NOT A. In conclusione:
 

A XOR 0 = A
e
A XOR 1 = NOT A

 

 

 

Le Operazioni Bit a Bit

Solo pochi microprocessori consentono di fare le operazioni booleane fra numeri grandi una sola cifra binaria 0/1.
Ritenendo “troppo banale” fare una sola operazione alla volta, ne fanno un gruppo intero per volta.

Questo modo di operare si dice “bit a bit” (in inglese bitwise).

Mettiamo di avere 2 dati binari della stessa grandezza:

un primo numero a caso -> 1 1 0 0 0 1 0 1
un secondo numero a caso -> 0 1 0 1 0 1 1 0

 

Se facciamo l'AND bit a bit fra i due dati, produciamo un risultato della stessa grandezza in cui ogni bit del risultato si ottiene facendo l'AND fra i 2 bit che stanno nella stessa posizione dei due operandi:

primo numero -> 1 1 0 0 0 1 0 1
secondo numero -> 0 1 0 1 0 1 1 0
risultato -> 0 1 0 0 0 1 0 0

 

Se facessimo, invece, l'OR bit a bit, sugli stessi dati otterremmo:

primo numero -> 1 1 0 0 0 1 0 1
secondo numero -> 0 1 0 1 0 1 1 0
risultato -> 1 1 0 1 0 1 1 1

 

Se facessimo, lo XOR bit a bit, sugli stessi dati otterremmo invece:
 

primo numero -> 1 1 0 0 0 1 0 1
secondo numero -> 0 1 0 1 0 1 1 0
risultato -> 1 0 0 1 0 0 1 1

 

Se infine facessimo, il NOT bit a bit, sugli stessi dati otterremmo:
 

numero -> 1 1 0 0 0 1 0 1
risultato -> 0 0 1 1 1 0 1 0
 

 

 

 

La Mascheratura
1: Azzeramento selettivo di bit

Se vogliamo azzerare alcuni bit di un dato lasciando inalterati gli altri bit, utilizziamo l'operatore And.
Per fare un esempio, immaginiamo che il dato abbia 8 bit (non si usano quasi mai dati piu' piccoli). In genere i bit si numerano da 0 in avanti partendo dall'ultima cifra a destra e procedendo verso sinistra:

Numero del bit 7 6 5 4 3 2 1 0
Un dato a caso 1 1 0 0 0 1 0 1
 
Nella tabella precedente, in alto è indicato il numero del bit, in basso un valore scelto a caso, per provare.
Supponiamo che ci serva di azzerare i bit numero 0, 2, 4 e 5.
Ragioniamo cosi:
creiamo un secondo dato della stessa grandezza, detto maschera (in inglese mask); per ogni bit di questo secondo dato sfruttiamo le due leggi trovate per l'And:

A AND 0 = 0  ; A AND 1 = A.
 
Se il bit in una posizione va azzerato, nella stessa posizione nella maschera metteremo uno 0, se va lasciato inalterato metteremo un 1.
Numero del bit 7 6 5 4 3 2 1 0
Maschera 1 1 0 0 1 0 1 0
 
 

 
Numero del bit 7 6 5 4 3 2 1 0
dato a caso 1 1 0 0 0 1 0 1
Maschera 1 1 0 0 1 0 1 0
Risultato 1 1 0 0 0 1 0 0
 
 

 

 

Abbiamo ottenuto quello che volevamo!
Andiamo adesso ad effettuare l'AND bit a bit fra i due dati:
La Mascheratura
2: Settaggio selettivo di bit
 

Se vogliamo settare alcuni bit di un dato lasciando inalterati gli altri bit, dobbiamo utilizzare l'operatore OR.
Ricordiamo le due leggi trovate prima:

A OR 0 = A   ;     A OR 1 = 1.

Ci costruiamo, anche qui', una maschera che avra' uno 0, dove vorremo lasciare il bit inalterato, ed un 1, dove vorremo settare il bit. 

Esempio:
Numero del bit 7 6 5 4 3 2 1 0
Un dato a caso 0 0 1 0 0 1 1

 
Mettiamo di voler settare i bit numero 1, 2 e 3.
Creiamo la maschera seguente:
 
Numero del bit 7 6 5 4 3 2 1 0
Maschera 0 0 0 0 1 1 1 0
 
 
 
Numero del bit 7 6 5 4 3 2 1 0
dato a caso 0 0 1 1 0 0 1 1
Maschera 0 0 0 0 1 1 1 0
Risultato 0 0 1 1 1 1 1 1
 
Combinando i due numeri otteniamo:
 
 

 

 
La Mascheratura
3: Inversione selettiva di bit
 
Per fare questa operazione dobbiamo utilizzare l'operatore XOR.
Le leggi da cui partiamo questa volta sono: 
A XOR 0 = A   ;   A XOR 1 = NOT A

Nella maschera si mettera' uno 0, per i bit da lasciare immutati, ed un 1, per quelli da invertire.

Esempio:

Numero del bit 7 6 5 4 3 2 1 0
Un dato di partenza a caso 1 0 1 0 1 0 1 0

 
Mettiamo di voler invertire i bit numero 3, 4 e 7.
Creiamo la maschera seguente:
 
Numero del bit 7 6 5 4 3 2 1 0
Maschera 1 0 0 1 1 0 0 0
 
Combinando i due numeri otteniamo:
 
Numero del bit 7 6 5 4 3 2 1 0
dato di partenza 1 0 1 0 1 0 1 0
Maschera 1 0 0 1 1 0 0 0
Risultato 0 0 1 1 0 0 1 0
 
Per prenderci la mano vi consiglio di farci qualche esercizio di prova.
 
 
 
 
Ultimissimo concetto

Se devo andare a controllare che un dato abbia certi bit uguali a un valore prefissato, ignorando gli altri, faccio così:

- azzero i bit che non interessano nel confronto, in entrambi i dati,

- quindi faccio il confronto

(l'operazione funziona anche se setto i bit che non interessano in entrambi i dati).

 

Esempio:
Supponiamo che devo andare a vedere se una variabile x, grande un byte, ha i bit 6,4 e 2 che valgono rispettivamente 1,0 e 1.

Opero cosi':
1- copio x in una variabile della stessa grandezza y, senza perdere il valore del dato di partenza: 
  y=x
2- sulla copia azzero i bit che non contano con una mascheratura:   y=y&0b01010100
3- creo un dato di confronto che ha i 3 bit come servono (1,0,1), mentre gli altri li azzero allo stesso modo di y:            z=0b01000100
4- faccio il confronto:
  if(y = = z){
    //quì si fa quello che mi serve
    };


Si capisce? Cercate di fare qualche prova!

 

 

Alcune applicazioni pratiche

A me, in genere, capita di utilizzare la mascheratura, quando lavoro in linguaggio C/C++ oppure in assembler.
Un contesto abbastanza tipico potrebbe essere quello di un microcontrollore PIC dove, come sappiamo, il programmatore deve gestire le cose meticolosamente: passo passo, bit per bit.

Simbolo degli operatori nel linguaggio C/C++
  AND OR NOT XOR
Bit a Bit & | ~ ^
Logico && || !  

Nella tabella precedente ho riepilogato i simboli degli operatori booleani logici e bit a bit usati nel linguaggio C/C++: attenzione a non confonderli fra loro!
In C++ manca un simbolo per l'operatore XOR logico (si puo' sostituire con ! = ).

Se, ad esempio, vogliamo andare a vedere se il PORT B (che è grande 8 bit) di un 16F876 ha i 4 bit meno significativi che valgono 0101 binario, un modo per farlo in linguaggio C/C++ potrebbe essere:

unsigned char dato;//l'unsigned char occupa 8 bit quanto è grande il PORT B
…..
dato=PORTB & 0b00001111;
if (dato==0b00000101){
    //fai qualche cosa<;br />     };

come si vede abbiamo fatto la mascheratura utilizzando l'And bit a bit, azzerando i 4 bit che non ci interessavano e visto se il risultato aveva il valore che cercavamo.

 

 

Esempio2:

1) unsigned char nuovo_dato,vecchio_dato,bit_cambiati,bit_settati;
2) unsigned int contatick;
3) void Intr(void) __interrupt
  { 
  ..............
4) if(RBIF){//cambio qualche bit port B
5)   vecchio_dato=nuovo_dato; //valore precedente 
6)   nuovo_dato=PORTB&0b11110000;//contano solo i bit  7,6,5 e 4
7)   bit_cambiati=(nuovo_dato^vecchio_dato);//bit cambiati: ottenuti con XOR
8)   bit_settati=nuovo_dato&(~vecchio_dato);//bit settati= passati da 0 a 1
     ..............
9)   if((bit_settati&0b00010000)==0b00010000){//settato bit 4 = FTA0 0->1
10)              contatick++;
         ..............
        };
     ..............
     };
  };

Nell'esempio, vengono dichiarate 4 variabili unsigned char, grandi 8 bit ciascuna, quanto e' grande il PORTB, ed una, contatick, grande 16 bit.
In questo microcontrollore, quando si verifica un cambiamento sui 4 bit piu' significativi (vale a dire 7,6,5  e 4), viene settato il flag RBIF e chiamata la routine di interrupt che costituisce l'esempio precedente.
Noi vogliamo monitorare i cambiamenti di questi 4 bit.


Ogni volta che RBIF vale 1 si entra nel blocco della IF.
Per prima cosa, il vecchio valore della variabile nuovo_dato viene copiato in vecchio_dato (5).
Subito dopo viene calcolata la variabile bit_cambiati, ottenuta per XOR bit a bit, fra nuovo_dato e vecchio_dato. Il risultato e' un dato che puo' avere solo i 4 bit 7,6,5,4 che valgono 1 (nuovo_dato viene mascherato in (6) in modo da azzerare gli altri bit e vecchio_dato e' uguale al vecchio valore di nuovo_dato ).
Per le caratteristiche dello XOR, ognuno dei 4 bit varra' 1 solo se i corrispondenti bit di nuovo_dato e vecchio_dato avranno valori diversi.


Invece bit_settati è dato dall'AND fra nuovo_dato e il NOT di vecchio_dato. Ognuno dei 4 bit varra' 1 solo se valeva 0 in vecchio_dato ed 1 in nuovo_dato.
In (9) se il bit 4 di bit settati vale 1 viene incrementato un contatore.

Una routine di gestione degli interrupt come la precedente e' abbastanza comune, ad esempio quando si gestisce un encoder incrementale.

 

Concludo qui'  o non mi fermo  piu' e finisco per tirarla troppo lunga.

Vi fornisco solo la traduzione assembler del segmento di programma precedente. Guardatela e cercate di ricostruire come si comporta facendo un po' di prove con carta e penna.

UserFiles/febia001/File/mascheratura.asm


Spero di essere stato chiaro ed avervi spiegato qualcosa di utile che non conoscevate.

 

Se qualcuno e' interessato ad approfondire questi argomenti di programmazione assembler e fondamenti dei sistemi digitali, vi consiglio questo mio libro.

Se non riuscite a trovarlo, contattatemi e (eccezionalmente per i membri di GRIX) ve lo mandero' con un forte sconto.

 

 

Ciao a tutti!

 



  il parere della community
esprimi il tuo voto approvi questa pagina? promo


  non sei autenticato, per questo non puoi visualizzare i commenti sulla pagina. Se sei registrato accedi oppure registrati.


difficoltà
costo
informazioni
Questa pagina è stata creata da febia001
il 12/04/2009 ore 22:43
ultima modifica del 13/04/2009 ore 21:51
la pagina è stata visitata 5026 volte




Lo staff di www.grix.it non si assume responsabilità sul contenuto di questa pagina.
Se tu sei l'autore originale degli schemi o progetti proposti in questo articolo, e ritieni che siano stati violati i tuoi diritti, contatta lo staff di www.grix.it per segnalarlo.

   
 







 
 
indietro | homepage | torna su copyright © 2004/2025 GRIX.IT - La community dell'elettronica Amatoriale