Risorse per il Lab. Elettronica |
|
Home Page
CAD/CAE • LTspice • PSpice Sistemi • Arduino • AVR • Raspberry Pi • National Instruments Risorse • Datasheet • Link • Hardware e Software • Misc |
*** IL DOWNLOAD DEI SEGUENTI FILE COMPORTA L'IMPLICITA ACCETTAZIONE DELLE SEGUENTI CONDIZIONI **** I seguenti Documenti, ove non diversamente specificato, sono distribuiti con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported. E' dunque escluso l'utilizzo per scopi di lucro . Il materiale viene fornito AS-IS senza alcuna garanzia di assenza di errori e/o imprecisioni e senza alcuna forma di supporto. L'Autore è sollevato da ogni responsabilità per qualsiasi utilizzo dei seguenti file. Autore: Francesco Parisi fparisi gmail com « IndiceAVR ATmega8 con libC - Gli operatori bit a bi u.r. 17/04/16 OPERATORI BIT A BITPrima di iniziare la programmazione in C dei mcu AVR, è bene soffermarsi sugli operatori bit a bit del linguaggio C essendo questi molto usati nella scrittura/lettura dei registriSi ricorda che le variabili associate ai registri dei mcu AVR a 8 bit sono ovviamente del tipo char senza segno (0...255) Gli esempi sottoriportati possono essere eseguiti con qualsiasi compilatore C (es. gcc) su qualsiasi sistema operativo (Windows, Linux ecc.). La notazione 0b non è standardizzata nel linguaggio (il compilatore lcc-win32 sembra essere l'unico ad accettarla); qui è utilizzata solo come convenzione di rappresentazione del numero in formato binario. Il linguaggio C, per la manipolazione dei bit, mette a disposizione del programmatore sei operatori bit a bit, che possono essere applicati soltanto ad operandi interi ovvero di tipo char, short, int e long, con o senza segno.
& AND bit a bit E’ necessario distinguere gli operatori bit a bit & e | dagli operatori logici && e ||, che implicano la valutazione da sinistra a destra di un valore di verità. Per esempio, se x vale 1 e y vale 2, allora x&y vale 0, mentre x&&y vale 1”, p.59, B.W. KERNIGHAN e D.M. RITCHIE, Linguaggio C, II edizione, Jackson Libri, Milano 1989.Gli operatori che vengono correntemente applicati sono: Operatore NOT ~E’ un operatore unario che produce il complemento ad uno dell’operando; converte dunque un bit 1 in bit 0 e, viceversa, un bit 0 in bit 1. Esempio:unsigned char portb = 0x00 /* portb vale 0b00000000 */ portb = ~portb /* portb ora vale 0b11111111 */vengono negati tutti i bit della variabile registro portb, indistintamente. Operatori di SHIFT << e >>Gli operatori di shift << e >> spostano, rispettivamente, verso sinistra e verso destra il loro operando sinistra di un numero di bit pari al valore del loro operando destro, che deve essere positivo. Per esempio x << 3 sposta a sinistra di tre posizioni il valore di x, riempiendo con degli zeri le posizioni così liberatesi. Esempio:unsigned char portc = 0x01; /* portc = 0b00000001 */ portc = portc << 3; /* portc ora vale 0b00001000 */Creiamo una tabella, in cui shiftiamo a sinistra il bit 0x01 (ovvero 1 in decimale) di k posizioni, per k che va da 0 a 7. Otteniamo così tanti byte che hanno attivo solo il bit in corrispondenza della posizione k, mentre i restanti risultano azzerati: Da questa tabella, guardando la colonna dei risultati in formato decimale o esadecimale, è facile verificare che lo shift a sinistra corrisponde ad una moltiplicazione per due; analogamente lo shift a destra corrisponde a una divisione per due. Gli 1 "shiftati" di k posizioni ci torneranno utili più avanti. Operatore OR bit a bit |Se a un bit aggiungiamo 1, qualunque sia il suo valore, il risultato sarà sempre 1: se è 0 abbiamo che 0 | 1 = 1, se è 1 abbiamo comunque che 1 | 1 = 1. Dunque, quando vogliamo attivare (set) un determinato bit di un byte, non dobbiamo fare altro che sottoporre questo a un’operazione OR bit a bit con un altro byte, che abbia tutti i bit azzerati tranne quello della posizione (ovvero delle posizioni) che vogliamo attivare. Questo secondo byte prende il nome di maschera ("mask") Quindi l’operatore OR bit a bit | viene usato per attivare uno o più bit, lasciando inalterati gli altri.Esempio: Attivare i soli bit 0 3 della variabile ddrc, lasciando inalterati i restanti bit: unsigned char ddrc = 0x98; /* 0b10011000 */ unsigned char mask = 0x09; /* 0b00001001 */ ddrc = ddrc | mask; /* ora ddrc vale 0b10011001 */Un byte che abbia attivo un solo bit (e tutti gli altri azzerati) altro non è che il risultato di uno shift a sinistra del numero 1, di un numero di posizioni corrispondente alla posizione del bit attivo. Nell’esempio appena fatto, la variabile maschera altro non era che l’OR bit a bit di due “sottomaschere”: 0b00000001 (per attivare il bit 0) e 0b00001000 (per attivare il bit 3). Queste due sottomaschere altro non sono che, rispettivamente, il numero 1 shiftato di 0 posizioni e il numero 1 shiftato di 3 posizioni (vedi tabella precedente). Riscriviamo dunque l’esempio, in una forma più leggibile: unsigned char ddrc = 0x98; /* 0b10011000 */ unsigned char mask = (1 << 0) | (1 << 3); /* 0b00000001 | 0b00001000 */ ddrc |= mask;Questa seconda notazione, del tutto equivalente alla precedente, è sicuramente preferibile, in quanto ci consente subito di sapere quali bit della variabile verranno "attivati" (ovvero "settati"). Infine, l’istruzione usata: ddrc |= maskadopera l’operatore di assegnamento messo a disposizione dal C ed è del tutto equivalente, ma sintatticamente più compatta, a quella precedemente usata: ddrc = ddrc | mask Operatore AND bit a bit &Facciamo subito un esempio. Fare l’AND bit a bit di due operandi ddrb e mask e riporre il risultato nella variabile ddrb:unsigned char ddrb = 0xFF; /* ddrb = 0b11111111 */ unsigned char mask = 0xFA; /* mask = 0b11111010 */ ddrb = ddrb & mask; /* ddrb ora vale 0b11111010 */Nell’esempio l’operatore AND ha quindi azzerato solo alcuni bit della variabile registro ddrb secondo una maschera; nell’esempio, la variabile mask ha azzerati i soli bit di posizione 0 e 2 e dunque anche i soli bit di posizione 0 e 2 della variabile ddrb verranno azzerati, mentre i restanti rimarranno invariati, avendo subito un’operazione AND bit a bit con un bit 1. Quindi l’operatore AND bit a bit & viene usato per azzerare uno o più bit, lasciando inalterati i restanti. Per dare una maggiore leggibilità e immediatezza al codice, la maschera viene creata attraverso una operazione di AND bit a bit con il complemento del solo bit a 1 che vogliamo azzerare: unsigned char ddrb = 0b11111111; unsigned char mask = (1 << 0) | (1 << 2); /* 0b00000001 | 0b00000100 */ ddrb &= ~mask; /* ddrb ora vale 0b11111010 */L’inizializzazione della variabile mask è del tutto equivalente a quella dell’esempio precedente, ma in questo caso si legge immediatamente quale bit verrà azzerato; inoltre, volendo, è possibile aggiungere, semplicemente con un’operazione di OR bit a bit, altri bit da resettare; definendo la posizione del bit con una variabile è infine possibile creare delle strutture iterative. Infine l’istruzione usata ddrb &= ~maskè la forma compatta e del tutto equivalente alla seguente: ddrb = ddrb & ~maskdove si è fatto uso di un operatore di assegnamento Operatore X OR bit a bit ^L’ex-or serve a fare il toogle di un determinato bit ovvero la sua commutazione, lasciando inalterati gli altri bit: se il bit è 0, lo attiva; viceversa, se è 1, lo azzera. L’operatore X-OR serve, dunque, a commutare uno o più bit, restando inalterati gli altriDalla tabella di verità si vede che se il bit è a 0, facendone l’X-OR con una maschera di valore 1, diventa 1; viceversa se è a 1, facendone l’X-OR sempre con una maschera di valore 1 diventa 0. Se, invece, la maschera è 0 per quel bit, lo stesso non viene commutato cioè resta inalterato. Quindi se vogliamo far commutare un bit alla posizione k, dobbiamo sottoporlo a una operazione di EX-OR con una maschera che abbia un bit 1 alla posizione k e tutti bit 0 nelle restanti posizioni. Esempio: Commutare il bit 1 e il bit 0 della variabile portb unsigned char portb=0x01; /* portb vale 0b00000001 */ unsigned char mask = (1 << 1) | (1 << 0); /* commuta i soli bit di posizione 0 e 1 */ portb ^= mask /* ora portb vale 0x00000010; */Alcune applicazioni degli operatori bit a bit: Lettura del singolo bit di una variabile registroPer leggere il singolo bit di una variabile registro, bisogna fare prima un AND bit a bit con una maschera che ha il bit 1 solo nella posizione relativa al bit di cui vogliamo conoscere lo stato; questa maschera, quindi, altro non è che il solito 1 shiftato a sinistra di k posti, ove k è proprio la posizione del singolo bit che vogliamo leggere.Successivamente si fa un AND logico Esempio: leggere il bit 7 della variabile pinb e stamparne a video lo stato: alto (1) o basso (0) #include <stdio.h> int main(void) { unsigned char pinb =0x81; /* assegnamo pinb il valore 0b10000001 */ if ( pinb && (1 << 7) ) { /* 0b10000001 && 0b1000000 = 1 */ printf("pb7 livello H\n"); } else { printf("pb7 livello L\n"); } }Il risultato dell’operazione di AND logico può essere o 1 (livello H) oppure 0 (livello L); per quanto citato all'inizio, in questo caso, vale 1 perché il bit 7 di pinb vale 1. Ripetere l'esercizio assegnando un valore di pinb che comporti il bit di posizione 7 a 0 (es. 0x62) Esercizi
|
|
Informativa estesa sui Cookie
|
|
Realizzazione a cura di Francesco Parisi (2002 ÷ 2024) | Contatti