Basi · 19 min di lettura

Porte logiche: AND, OR, NOT, XOR, tabelle di verità e Arduino

Cosa sono le porte logiche? AND, OR, NOT, NAND, NOR e XOR: simboli, tabelle di verità, integrati 74HC08 e 74HC00, semisommatore e codice Arduino ed ESP32.

Le porte logiche sono i mattoni fondamentali dei circuiti digitali: ognuna osserva uno o più ingressi digitali e produce un'unica uscita digitale secondo una regola fissa. Gli ingressi possono valere solo 0 (LOW) o 1 (HIGH), e lo stesso vale per l'uscita. Le porte di base sono sette: AND, OR, NOT, NAND, NOR, XOR e XNOR. Dal processore del tuo smartphone alla scheda di una lavatrice, dall'ATmega328P di un Arduino a una calcolatrice tascabile, ogni dispositivo digitale funziona combinando milioni di minuscole porte logiche.

In questa guida imparerai il simbolo e la tabella di verità di ogni porta, integrati reali come il 74HC08, il 74HC32 e il 74HC00, un esperimento con due pulsanti sulla breadboard, come costruire tutte le altre porte usando solo NAND e il circuito semisommatore che somma due bit. Nelle ultime sezioni tradurremo la stessa logica in codice su Arduino con gli operatori &&, || e ! e con le operazioni bit a bit, per poi proseguire con esempi per ESP32 e Raspberry Pi Pico (MicroPython).

Breadboard per gli esperimenti con le porte logiche
Puoi provare gli integrati delle porte logiche senza saldare, posizionandoli a cavallo del canale centrale della breadboard.

Cos'è una porta logica e come funziona?

Nell'elettronica digitale ogni segnale si trova in uno di due stati: 1 (HIGH, vero) o 0 (LOW, falso). La matematica che lavora con questi due valori si chiama algebra di Boole; in un libro pubblicato nel 1854, George Boole espresse proprio così il ragionamento logico sotto forma di algebra. Nel 1937 Claude Shannon dimostrò che questa algebra corrisponde esattamente ai circuiti di commutazione a relè, gettando le basi della progettazione dei circuiti digitali. Oggi una porta logica contiene solo pochi transistor: in tecnologia CMOS una porta NOT è formata da 2 MOSFET e una NAND da 4. Spieghiamo come funziona un transistor usato come interruttore in Cos'è un transistor?.

Ma quale tensione il circuito considera 1 e quale 0? Dipende dalla tensione di alimentazione della scheda e dalla famiglia dell'integrato. La tabella qui sotto mostra le soglie oltre le quali un ingresso viene riconosciuto con certezza come 1 o come 0. La zona tra le due soglie è la zona indefinita; se un ingresso resta lì, l'uscita può comportarsi in modo casuale. Un ingresso non collegato a nulla, cioè un ingresso flottante, vaga proprio in questa zona. Per questo ogni ingresso deve essere collegato a un segnale, oppure a GND o VCC tramite una resistenza.

Scheda / famigliaAlimentazioneIngresso riconosciuto come 1Ingresso riconosciuto come 0
Arduino Uno (ATmega328P)5 V≥ 3,0 V≤ 1,5 V
ESP323,3 V≥ 2,5 V≤ 0,8 V
Raspberry Pi Pico (RP2040)3,3 V≥ 2,0 V≤ 0,8 V
Integrato 74HC5 V≥ 3,5 V≤ 1,5 V
Integrato 74HCT5 V≥ 2,0 V≤ 0,8 V
Integrato CD40005 V≥ 3,5 V≤ 1,5 V

Le 7 porte logiche fondamentali e i loro simboli

Negli schemi le porte vengono disegnate secondo due norme diverse. Nella norma americana (ANSI/IEEE) ogni porta ha una forma propria: AND assomiglia a una lettera D, OR a uno scudo appuntito e NOT a un triangolo. Il piccolo cerchio sull'uscita significa "inverti"; una NAND è quindi una AND con un cerchio sulla punta. A distinguere la XOR dalla OR è la seconda linea curva sul lato degli ingressi. Nella norma europea (IEC) tutte le porte sono rettangoli e si riconoscono dal simbolo scritto all'interno: & per AND, ≥1 per OR, =1 per XOR e 1 per NOT. Nei libri di testo troverai anche XOR chiamata OR esclusivo e XNOR chiamata NOR esclusivo.

PortaNome italianoSimbolo ANSISegno IECEspressione booleanaQuando l'uscita vale 1?
ANDE (prodotto logico)Forma a D&Y = A · BEntrambi gli ingressi valgono 1
ORO (somma logica)Scudo appuntito≥1Y = A + BAlmeno un ingresso vale 1
NOTNegazione (invertitore)Triangolo + cerchio1 (cerchio in uscita)Y = A'L'ingresso vale 0
NANDAND negataForma a D + cerchio& (cerchio in uscita)Y = (A · B)'Almeno un ingresso vale 0
NOROR negataScudo + cerchio≥1 (cerchio in uscita)Y = (A + B)'Entrambi gli ingressi valgono 0
XOROR esclusivoScudo a doppia curva=1Y = A ⊕ BGli ingressi sono diversi
XNORNOR esclusivoDoppia curva + cerchio=1 (cerchio in uscita)Y = (A ⊕ B)'Gli ingressi sono uguali

Tabelle di verità delle porte logiche

Una tabella di verità elenca l'uscita di una porta per ogni combinazione dei suoi ingressi. Una porta con n ingressi ha 2ⁿ righe: 4 righe con due ingressi, 8 con tre e 16 con quattro. Se scrivi le righe nell'ordine del conteggio binario (00, 01, 10, 11), non salterai mai una combinazione. Ecco tutte e sei le porte a due ingressi in un'unica tabella:

ABANDORNANDNORXORXNOR
00001101
01011010
10011010
11110001

Poiché la porta NOT ha un solo ingresso, la sua tabella ha due righe: con A = 0 l'uscita è 1, con A = 1 l'uscita è 0. Osservando bene la tabella noterai uno schema: la colonna NAND è esattamente l'opposto di AND, NOR l'opposto di OR e XNOR l'opposto di XOR. Per memorizzarle usa queste regole brevi: AND chiede "sono tutti 1?", OR "ce n'è almeno uno a 1?" e XOR "gli ingressi sono diversi?"; la porta il cui nome inizia con N dà la risposta opposta alla stessa domanda. Per provare le porte da solo e vedere i simboli dal vivo, basta toccare gli ingressi A e B nello strumento Porte logiche.

  • AND: Due interruttori in serie. La lampada si accende solo quando entrambi sono chiusi; anche una cassaforte di banca che si apre con due chiavi diverse segue la regola AND.
  • OR: Due pulsanti in parallelo. Suona lo stesso campanello sia che si prema il pulsante della porta d'ingresso sia quello della porta sul retro.
  • NOT: La luce del frigorifero. Con la porta chiusa l'interruttore è premuto e la luce spenta; quando la porta si apre l'interruttore viene rilasciato e la luce si accende.
  • NAND: La regola "avvisa se non è tutto a posto". Se anche solo una delle due protezioni di una macchina è aperta, si accende la spia di allarme.
  • NOR: La regola "non è successo niente". Una spia verde di "tutto in ordine" che si accende solo se non viene rilevato né fumo né gas.
  • XOR: L'impianto con deviatori di una scala. Azionando il deviatore in basso o quello in alto cambia lo stato della lampada; la lampada è accesa quando i due deviatori sono in posizioni diverse e spenta quando coincidono.
  • XNOR: Un controllo di uguaglianza. Dà 1 quando due bit sono uguali; si usa nei comparatori digitali e nei circuiti di rilevamento degli errori.

Integrati di porte logiche: 74HC08, 74HC32, 74HC00

Invece di costruire le porte logiche transistor per transistor, si usano integrati già pronti. La famiglia più diffusa nell'elettronica hobbistica è la serie 74HC: un contenitore DIP a 14 piedini contiene quattro porte a due ingressi, l'alimentazione va sempre al piedino 14 (VCC) e la massa al piedino 7 (GND). I 74HC funzionano da 2 a 6 V, i loro ingressi non assorbono quasi corrente e a 5 V una porta ha un ritardo di circa 10 nanosecondi, centinaia di volte più veloce di una singola chiamata digitalWrite su Arduino. Ogni uscita mantiene i livelli di tensione garantiti con un carico di 4 mA; il limite assoluto è di 25 mA per uscita e 50 mA per l'intero integrato.

IntegratoPortaContenutoPiedinaturaEquivalente CMOS 4000
74HC08AND4 × 2 ingressiStandard (tabella sotto)CD4081
74HC32OR4 × 2 ingressiStandardCD4071
74HC00NAND4 × 2 ingressiStandardCD4011
74HC86XOR4 × 2 ingressiStandardCD4070
74HC02NOR4 × 2 ingressiDiversa: uscite su 1, 4, 10, 13CD4001
74HC04NOT6 × 1 ingressoIngressi su 1, 3, 5, 9, 11, 13CD4069
74HC14NOT (trigger di Schmitt)6 × 1 ingressoUguale al 74HC04CD40106
CD4077 / 74HCS7266XNOR4 × 2 ingressiRaro; di solito 74HC86 + 74HC04CD4077

74HC08, 74HC32, 74HC00 e 74HC86 hanno esattamente la stessa piedinatura; cambia solo il tipo di porta all'interno. La tacca o il puntino sulla parte superiore indica il piedino 1. Guardando l'integrato dall'alto con la tacca a sinistra, i piedini sono numerati in senso antiorario: la fila inferiore da sinistra a destra da 1 a 7, quella superiore da destra a sinistra da 8 a 14. A e B sono gli ingressi, Y l'uscita, e la cifra davanti indica il numero della porta.

PiedinoFunzionePiedinoFunzione
11A (ingresso porta 1)14VCC (+2…6 V)
21B (ingresso porta 1)134B (ingresso porta 4)
31Y (uscita porta 1)124A (ingresso porta 4)
42A (ingresso porta 2)114Y (uscita porta 4)
52B (ingresso porta 2)103B (ingresso porta 3)
62Y (uscita porta 2)93A (ingresso porta 3)
7GND83Y (uscita porta 3)
Non lasciare mai flottanti gli ingressi CMOS. Collega a GND (o a VCC) gli ingressi delle porte che non usi; un ingresso flottante cambia continuamente stato a causa dei disturbi, aumenta l'assorbimento dell'integrato e può persino disturbare le porte vicine. Le uscite inutilizzate, invece, possono restare libere. Non dimenticare un condensatore ceramico di disaccoppiamento da 100 nF tra VCC e GND, il più vicino possibile all'integrato.

Gli integrati che svolgono la stessa funzione esistono in diverse famiglie. La serie 74LS è la vecchia tecnologia TTL: funziona solo tra 4,75 e 5,25 V, assorbe più corrente e di solito legge come 1 un ingresso flottante. La serie 74HCT è un 74HC con ingressi compatibili TTL; si alimenta a 5 V ma riconosce come 1 sicuro già 2 V, quindi legge senza problemi i segnali a 3,3 V di un ESP32 o di un Pico. La serie CD4000 (CD4081, CD4011 e così via) lavora in un ampio intervallo di 3–18 V, ma è più lenta e ha una piedinatura diversa dai 74HC: un CD4011 non può sostituire direttamente un 74HC00.

Esperimento con pulsanti sulla breadboard: porta AND con il 74HC08

Il modo migliore per capire una porta logica è provarla di persona con due pulsanti. In questo esperimento non c'è nessun microcontrollore; ti servono solo un 74HC08, due pulsanti, due resistenze da 10 kΩ, una da 1 kΩ, un LED e un condensatore da 100 nF. Per l'alimentazione vanno bene i pin 5V e GND di un Arduino, un modulo di alimentazione per breadboard o tre pile AA (4,5 V). Se non sei sicuro dei collegamenti interni della breadboard, leggi prima Cos'è una breadboard?.

Pulsante per l'esperimento sulla breadboard
Un pulsante collega i suoi due lati finché è premuto. Nei modelli a quattro piedini i piedini sono collegati internamente a coppie; la soluzione più sicura è posizionarlo a cavallo del canale centrale.
  1. Posiziona il 74HC08 a cavallo del canale centrale della breadboard, con i piedini sui due lati e la tacca rivolta a sinistra.
  2. Collega il piedino 14 alla linea + (5 V) e il piedino 7 alla linea − (GND), poi metti il condensatore da 100 nF tra questi due piedini.
  3. Collega un lato del pulsante A alla linea + e l'altro al piedino 1. Aggiungi una resistenza da 10 kΩ dallo stesso piedino verso GND: questa resistenza di pull-down tiene l'ingresso saldamente a 0 finché il pulsante non è premuto.
  4. Collega il pulsante B al piedino 2 nello stesso modo e dagli la sua resistenza di pull-down da 10 kΩ.
  5. Dal piedino 3, l'uscita, passa attraverso una resistenza da 1 kΩ fino al piedino lungo del LED (anodo); collega il piedino corto (catodo) a GND.
  6. Collega a GND gli ingressi inutilizzati, i piedini 4, 5, 9, 10, 12 e 13; lascia libere le uscite 6, 8 e 11.
  7. Dai alimentazione e prova le quattro combinazioni una dopo l'altra: il LED deve accendersi solo quando premi entrambi i pulsanti insieme. Confronta i risultati con la tabella di verità.
CollegamentoPiedino del 74HC08Da collegare a
Alimentazione14 (VCC)Linea +, 5 V
Massa7 (GND)Linea −
Condensatore di disaccoppiamentoTra 14 e 7100 nF ceramico, vicino all'integrato
Ingresso A1Pulsante A → 5 V, 10 kΩ → GND
Ingresso B2Pulsante B → 5 V, 10 kΩ → GND
Uscita31 kΩ → anodo del LED, catodo → GND
Ingressi inutilizzati4, 5, 9, 10, 12, 13GND
Uscite inutilizzate6, 8, 11Libere
Quando il circuito funziona inizia la parte divertente: se togli il 74HC08 e inserisci un 74HC32 con la stessa piedinatura, il LED si accende premendo uno qualsiasi dei pulsanti (OR). Con un 74HC00 resta acceso finché non premi entrambi i pulsanti (NAND), e con un 74HC86 si accende solo quando ne premi uno solo (XOR). Con 1 kΩ un LED rosso assorbe circa 3 mA, un valore sicuro per un'uscita 74HC. Per un LED di un altro colore puoi calcolare la resistenza con lo strumento Resistenza per LED.

Costruire ogni porta con le NAND: la porta universale

La NAND è chiamata porta universale perché con sole porte NAND puoi costruire qualsiasi altra porta. C'è anche un motivo pratico: in tecnologia CMOS la NAND è una delle porte più semplici, con soli 4 transistor, mentre una AND è in realtà una NAND seguita da una NOT e ne richiede 6. Ecco perché i progettisti di chip amano la NAND. Anche la memoria NAND flash delle chiavette USB deve il suo nome al fatto che le sue celle sono collegate in serie, come i transistor di una porta NAND. Anche la NOR è universale: l'Apollo Guidance Computer che volò verso la Luna fu costruito con circa 2.800 integrati, ognuno con due porte NOR a tre ingressi.

Porta da ottenereCome con le NAND?NAND necessarie
NOTA NAND A (unisci i due ingressi)1
ANDFai passare l'uscita di (A NAND B) in una NOT2
OR(A NAND A) NAND (B NAND B)3
NOROR + NOT4
XORN1 = A NAND B; (A NAND N1) NAND (B NAND N1)4
XNORXOR + NOT5

La riga OR della tabella si basa sulla legge di De Morgan: (A' · B')' = A + B. In altre parole, se prima inverti ciascun ingresso e poi li mandi in una NAND, ottieni una OR. La seconda legge di De Morgan è (A + B)' = A' · B'. Entrambe ti aiutano anche a semplificare le condizioni nel codice: su Arduino, !(a && b) dà sempre lo stesso risultato di (!a || !b), e !(a || b) lo stesso di (!a && !b).

Costruire una XOR con quattro porte NAND è un classico esercizio d'esame e di laboratorio, e le quattro porte di un solo 74HC00 bastano esattamente. Prima si calcola N1 = A NAND B. Poi si ricavano N2 = A NAND N1 e N3 = B NAND N1, e l'uscita dell'ultima porta, Y = N2 NAND N3, dà la XOR. Con il cablaggio qui sotto puoi trasformare l'esperimento sulla breadboard in una XOR a quattro NAND:

Piedino del 74HC00CollegamentoFunzione
1 e 4Pulsante AIngresso A (porte 1 e 2)
2 e 10Pulsante BIngresso B (porte 1 e 3)
3 → 5 e 9CavettoN1 = A NAND B
6 → 12CavettoN2 = A NAND N1
8 → 13CavettoN3 = B NAND N1
111 kΩ + LEDY = A XOR B
14 / 75 V / GNDAlimentazione

Facciamo un passo in più: se colleghi in modo incrociato le uscite di due porte NAND all'ingresso dell'altra, ottieni una memoria da 1 bit chiamata latch SR. Questo circuito ricorda il suo ultimo stato anche quando rilasci il pulsante. I registri dei processori, i contatori e integrati come lo shift register 74HC595 nascono mettendo in fila celle di memoria di questo tipo, costruite con le porte.

Il semisommatore (half adder): sommare due bit con le porte

La cosa più sorprendente che sanno fare le porte logiche è sommare. In binario 0 + 0 = 0, 0 + 1 = 1, 1 + 0 = 1 e 1 + 1 = 10 (2 in decimale). La cifra destra del risultato si chiama somma e quella che trabocca verso sinistra riporto (carry). Guardando la tabella qui sotto vedrai che la somma è esattamente una XOR e il riporto esattamente una AND. Quindi una porta XOR e una AND affiancate formano un semisommatore che somma due numeri da un bit.

ABRiporto (C = A AND B)Somma (S = A XOR B)Risultato decimale
00000
01011
10011
11102 (binario 10)

Per montarlo sulla breadboard, collega i pulsanti A e B ai piedini 1 e 2 sia di un 74HC86 sia di un 74HC08. Il piedino 3 del 74HC86 pilota il LED della somma, il piedino 3 del 74HC08 quello del riporto. Premendo entrambi i pulsanti, il LED della somma si spegne e quello del riporto si accende: i LED mostrano il binario 10, cioè 2. Se vuoi usare solo un 74HC00, ti servono quattro NAND per la XOR e una quinta NAND che inverta N1 per ottenere il riporto; un semisommatore si costruisce quindi con 5 porte NAND.

Un semisommatore non può tenere conto del riporto proveniente dalla cifra precedente; per questo serve un sommatore completo (full adder). Le sue formule sono S = A ⊕ B ⊕ Cin e Cout = (A · B) + (Cin · (A ⊕ B)), cioè due semisommatori e una porta OR. Collegando in catena quattro sommatori completi, in modo che ognuno passi il riporto al successivo, ottieni un sommatore a 4 bit; l'integrato 74HC283 esegue la stessa somma a 4 bit, ma calcola i riporti con un circuito interno veloce (carry look-ahead) invece di aspettare che si propaghino lungo la catena. L'unità aritmetica del processore del tuo computer è una versione a 64 bit, molto più veloce, della stessa idea.

Porte logiche su Arduino: &&, ||, ! e operazioni bit a bit

Nel codice Arduino ogni porta logica ha due equivalenti. Gli operatori logici (&&, ||, !) combinano le condizioni e restituiscono true o false; li usi nelle istruzioni if e while. Gli operatori bit a bit (&, |, ^, ~), invece, agiscono contemporaneamente su tutti i bit di un numero, colonna per colonna; lavorare su un byte è come far funzionare otto porte insieme. Gli esempi della tabella usano i numeri 0b1100 e 0b1010:

PortaLogico (bool)Bit a bitEsempioRisultato
ANDa && bx & y0b1100 & 0b10100b1000
ORa || bx | y0b1100 | 0b10100b1110
NOT!a~x~0b00001100 (byte)0b11110011
NAND!(a && b)~(x & y)~(0b1100 & 0b1010) & 0x0F0b0111
NOR!(a || b)~(x | y)~(0b1100 | 0b1010) & 0x0F0b0001
XORa != bx ^ y0b1100 ^ 0b10100b0110
XNORa == b~(x ^ y)~(0b1100 ^ 0b1010) & 0x0F0b1001

La differenza tra i due tipi sembra piccola ma porta a errori subdoli. && e || usano la valutazione in cortocircuito: in a && b, se a è falso, b non viene nemmeno valutato. & valuta sempre entrambi i lati e guarda i bit dei numeri: 2 && 1 vale true, ma 2 & 1 vale 0, perché 0b10 e 0b01 non hanno bit in comune. Il C++ non ha un operatore XOR logico a sé; per due bool, scrivere a != b è la forma più leggibile. Per approfondire le operazioni bit a bit, gli scorrimenti << e >> e il sistema binario, leggi Sistemi di numerazione e operazioni bit a bit.

Ora portiamo l'esperimento della breadboard su un Arduino Uno. Due pulsanti vanno ai pin 2 e 3, sette LED (ognuno con una resistenza da 330 Ω) ai pin 4–10. Ogni pulsante ha un lato sul pin e l'altro su GND; dato che la resistenza di pull-up interna è attiva, non serve nessuna resistenza aggiuntiva. Un solo sketch dà vita contemporaneamente a tutte e sette le porte:

Arduino (C++)
1// Mantık kapısı simülatörü: 2 buton, 7 LED / Logic gate simulator: 2 buttons, 7 LEDs
2const byte PIN_A = 2;   // A butonu, diğer ucu GND / button A, other leg to GND
3const byte PIN_B = 3;   // B butonu, diğer ucu GND / button B, other leg to GND
4
5// Sıra: AND, OR, NOT A, NAND, NOR, XOR, XNOR / Order: AND, OR, NOT A, NAND, NOR, XOR, XNOR
6const byte LED_PINS[7] = {4, 5, 6, 7, 8, 9, 10};
7const char* const GATE_NAMES[7] = {"AND", "OR", "NOT A", "NAND", "NOR", "XOR", "XNOR"};
8
9byte lastInputs = 0xFF;   // ilk turda yazdırmayı zorlar / forces a print on the first pass
10
11void setup() {
12  pinMode(PIN_A, INPUT_PULLUP);
13  pinMode(PIN_B, INPUT_PULLUP);
14  for (byte i = 0; i < 7; i++) {
15    pinMode(LED_PINS[i], OUTPUT);
16  }
17  Serial.begin(9600);
18}
19
20void loop() {
21  // Basılı buton LOW okunur, ! ile 1 yapılır / A pressed button reads LOW, ! turns it into 1
22  bool a = !digitalRead(PIN_A);
23  bool b = !digitalRead(PIN_B);
24
25  bool out[7];
26  out[0] = a && b;      // AND
27  out[1] = a || b;      // OR
28  out[2] = !a;          // NOT A
29  out[3] = !(a && b);   // NAND
30  out[4] = !(a || b);   // NOR
31  out[5] = a != b;      // XOR: girişler farklı mı? / are the inputs different?
32  out[6] = a == b;      // XNOR: girişler aynı mı? / are the inputs equal?
33
34  for (byte i = 0; i < 7; i++) {
35    digitalWrite(LED_PINS[i], out[i] ? HIGH : LOW);
36  }
37
38  // Yalnız girişler değişince yaz / Print only when the inputs change
39  byte inputs = (a << 1) | b;
40  if (inputs != lastInputs) {
41    Serial.print("A=");
42    Serial.print(a);
43    Serial.print(" B=");
44    Serial.print(b);
45    for (byte i = 0; i < 7; i++) {
46      Serial.print("  ");
47      Serial.print(GATE_NAMES[i]);
48      Serial.print('=');
49      Serial.print(out[i]);
50    }
51    Serial.println();
52    lastInputs = inputs;
53  }
54  delay(20);   // basit sıçrama önleme / simple debounce
55}

Con INPUT_PULLUP un pulsante premuto si legge LOW, quindi il codice inverte la lettura con ! e il pulsante premuto diventa 1. Ogni LED mostra poi il risultato della sua porta: 4 AND, 5 OR, 6 NOT A, 7 NAND, 8 NOR, 9 XOR e 10 XNOR. Se apri il Monitor seriale a 9600 baud, a ogni cambio di pulsante viene stampata l'intera riga; dopo aver provato tutte e quattro le combinazioni avrai ricavato la tabella di verità con le tue mani. I dettagli sulla logica pull-up sono in Come collegare un pulsante ad Arduino.

Per vedere la potenza delle operazioni bit a bit, il secondo esempio calcola tutta la tabella di verità in poche righe. Il trucco: se scrivi la colonna A come il numero 0b1100 e la colonna B come 0b1010, ogni bit corrisponde a una riga della tabella e un solo & ti dà in un colpo le quattro righe della colonna AND. La seconda metà dello sketch somma bit per bit due numeri a 4 bit con le formule del sommatore completo, imitando via software il circuito sommatore di un processore. Questo sketch non richiede hardware; basta aprire il Monitor seriale.

Arduino (C++)
1// Bit işlemleriyle doğruluk tablosu ve 4 bitlik toplayıcı / Truth tables with bitwise ops and a 4-bit adder
2// Her bit bir satırdır: bit 0 = (A=0, B=0) ... bit 3 = (A=1, B=1) / Each bit is one row: bit 0 = (A=0, B=0) ... bit 3 = (A=1, B=1)
3const byte COL_A = 0b1100;
4const byte COL_B = 0b1010;
5const byte MASK  = 0b1111;   // yalnız 4 satır / only 4 rows
6
7void printRow(const char* name, byte column) {
8  Serial.print(name);
9  Serial.print('\t');
10  for (byte row = 0; row < 4; row++) {
11    Serial.print(bitRead(column, row));   // satır satır yaz / print row by row
12    Serial.print("  ");
13  }
14  Serial.println();
15}
16
17// Tam toplayıcı: iki bit + gelen elde / Full adder: two bits + carry in
18void fullAdder(byte a, byte b, byte carryIn, byte &sum, byte &carryOut) {
19  sum = a ^ b ^ carryIn;                         // XOR'lar toplamı verir / XORs give the sum
20  carryOut = (a & b) | (carryIn & (a ^ b));      // AND + OR eldeyi verir / AND + OR give the carry
21}
22
23// 4 tam toplayıcı zincirlenir (ripple carry) / 4 full adders chained (ripple carry)
24byte add4(byte x, byte y, byte &carryOut) {
25  byte result = 0;
26  byte carry = 0;
27  for (byte i = 0; i < 4; i++) {
28    byte s, c;
29    fullAdder(bitRead(x, i), bitRead(y, i), carry, s, c);
30    bitWrite(result, i, s);
31    carry = c;
32  }
33  carryOut = carry;
34  return result;
35}
36
37void setup() {
38  Serial.begin(9600);
39  Serial.println(F("AB:\t00 01 10 11"));
40  printRow("AND",  COL_A & COL_B);
41  printRow("OR",   COL_A | COL_B);
42  printRow("NAND", ~(COL_A & COL_B) & MASK);   // ~ sonrası maske şart / mask is required after ~
43  printRow("NOR",  ~(COL_A | COL_B) & MASK);
44  printRow("XOR",  COL_A ^ COL_B);
45  printRow("XNOR", ~(COL_A ^ COL_B) & MASK);
46
47  byte carry;
48  byte s = add4(9, 12, carry);   // 1001 + 1100
49  Serial.print(F("9 + 12 = "));
50  Serial.print(s + carry * 16);  // elde 16'lar basamağıdır / the carry is the 16s place
51  Serial.print(F("  (toplam / sum = "));
52  Serial.print(s, BIN);
53  Serial.print(F(", elde / carry = "));
54  Serial.print(carry);
55  Serial.println(')');
56}
57
58void loop() {
59}
Non usare ~ con valori bool: ~ inverte tutti i bit e trasforma true (1) in -2, e dato che -2 non è zero conta ancora come true. Per una negazione logica usa sempre !. Un'altra trappola è la precedenza degli operatori: in if (x & 1 == 0) viene valutato prima 1 == 0, quindi la forma corretta è if ((x & 1) == 0). Inoltre, applicando ~ a una variabile byte il risultato diventa int; taglialo con una maschera come & 0x0F o & 0xFF, come fa il codice.

Un tester per integrati 74HC con Arduino

Se la sigla di un integrato si è cancellata o vuoi sapere se funziona ancora, puoi trasformare Arduino in un tester. Questo sketch applica a turno le quattro combinazioni di ingresso a tutte e quattro le porte di un 74HC00, 74HC08, 74HC32 o 74HC86 (gli integrati con piedinatura standard), legge le uscite e confronta il risultato con schemi noti. Collega il piedino 14 dell'integrato a 5V, il piedino 7 a GND e gli altri ai pin di Arduino indicati nella tabella del codice.

Arduino (C++)
1// 74HC00 / 08 / 32 / 86 tanıyıcı ve test cihazı / 74HC00 / 08 / 32 / 86 identifier and tester
2// Entegre: bacak 14 -> 5V, bacak 7 -> GND / Chip: pin 14 -> 5V, pin 7 -> GND
3// Her kapı: {A, B, Y} Arduino pinleri / Each gate: {A, B, Y} Arduino pins
4const byte GATES[4][3] = {
5  {2, 3, 4},      // kapı 1: entegre 1, 2 -> 3 / gate 1: chip 1, 2 -> 3
6  {5, 6, 7},      // kapı 2: entegre 4, 5 -> 6 / gate 2: chip 4, 5 -> 6
7  {8, 9, 10},     // kapı 3: entegre 9, 10 -> 8 / gate 3: chip 9, 10 -> 8
8  {11, 12, A0}    // kapı 4: entegre 12, 13 -> 11 / gate 4: chip 12, 13 -> 11
9};
10
11// Desenin bit sırası: bit 0 = (0,0), bit 3 = (1,1) / Pattern bit order: bit 0 = (0,0), bit 3 = (1,1)
12const char* nameOf(byte pattern) {
13  switch (pattern) {
14    case 0b1000: return "AND (74HC08)";
15    case 0b1110: return "OR (74HC32)";
16    case 0b0111: return "NAND (74HC00)";
17    case 0b0110: return "XOR (74HC86)";
18    default:     return "?";
19  }
20}
21
22byte testGate(byte g) {
23  byte pattern = 0;
24  for (byte row = 0; row < 4; row++) {
25    digitalWrite(GATES[g][0], bitRead(row, 1));   // A = satırın üst biti / A = high bit of the row
26    digitalWrite(GATES[g][1], bitRead(row, 0));   // B = satırın alt biti / B = low bit of the row
27    delayMicroseconds(10);                        // kapı ~10 ns gecikir, bol pay / the gate needs ~10 ns, plenty of margin
28    bitWrite(pattern, row, digitalRead(GATES[g][2]));
29  }
30  return pattern;
31}
32
33void setup() {
34  Serial.begin(9600);
35  for (byte g = 0; g < 4; g++) {
36    pinMode(GATES[g][0], OUTPUT);
37    pinMode(GATES[g][1], OUTPUT);
38    pinMode(GATES[g][2], INPUT);
39  }
40
41  byte first = testGate(0);
42  bool allSame = true;
43  for (byte g = 0; g < 4; g++) {
44    byte p = testGate(g);
45    Serial.print(F("Kapi / Gate "));
46    Serial.print(g + 1);
47    Serial.print(F(": "));
48    Serial.print(nameOf(p));
49    Serial.print(F("  desen / pattern 0b"));
50    Serial.println(p, BIN);
51    if (p != first) allSame = false;
52  }
53
54  if (allSame && nameOf(first)[0] != '?') {
55    Serial.println(F("Sonuc / Result: entegre saglam / chip OK"));
56  } else {
57    Serial.println(F("Sonuc / Result: bozuk kapi ya da baglanti hatasi / faulty gate or wiring error"));
58  }
59}
60
61void loop() {
62}
Se sbagli il cablaggio, un'uscita di Arduino può trovarsi in contrasto con un'uscita dell'integrato. Per evitarlo puoi mettere una resistenza da 1 kΩ tra le uscite dell'integrato (3, 6, 8, 11) e i pin di Arduino; il risultato del test non cambia, ma in caso di errore entrambi i lati sono protetti. Il 74HC02 e il 74HC04 hanno una piedinatura diversa, quindi questo sketch non può testarli direttamente; dovresti modificare la tabella GATES secondo il loro datasheet.

Una porta logica programmabile con l'ESP32

Sull'ESP32 gli stessi operatori funzionano senza modifiche. In questo esempio un terzo pulsante fa scorrere i tipi di porta e un solo LED mostra l'uscita della porta scelta. Così puoi mostrare sei porte con un unico circuito in classe o durante una presentazione. I pulsanti vanno su GPIO 25, 26 e 27 (l'altro lato su GND) e il LED su GPIO 23 tramite una resistenza da 220 Ω; il nome della porta scelta compare nel Monitor seriale a 115200 baud.

Arduino (C++)
1// ESP32 programlanabilir mantık kapısı / ESP32 programmable logic gate
2const int PIN_A = 25;      // A butonu, diğer ucu GND / button A, other leg to GND
3const int PIN_B = 26;      // B butonu / button B
4const int PIN_MODE = 27;   // kapı seçme butonu / gate select button
5const int PIN_LED = 23;    // çıkış LED'i (220 ohm) / output LED (220 ohm)
6
7const char* const NAMES[] = {"AND", "OR", "NAND", "NOR", "XOR", "XNOR"};
8const int GATE_COUNT = 6;
9const unsigned long DEBOUNCE_MS = 30;   // sıçrama süresi / bounce time
10
11int gate = 0;
12int modeStable = HIGH;            // kararlı buton durumu / stable button state
13int modeRaw = HIGH;               // son ham okuma / last raw reading
14unsigned long modeChangedAt = 0;  // ham değerin son değiştiği an / when the raw value last changed
15
16bool evaluate(int g, bool a, bool b) {
17  switch (g) {
18    case 0:  return a && b;
19    case 1:  return a || b;
20    case 2:  return !(a && b);
21    case 3:  return !(a || b);
22    case 4:  return a != b;     // XOR
23    default: return a == b;     // XNOR
24  }
25}
26
27void setup() {
28  Serial.begin(115200);
29  pinMode(PIN_A, INPUT_PULLUP);
30  pinMode(PIN_B, INPUT_PULLUP);
31  pinMode(PIN_MODE, INPUT_PULLUP);
32  pinMode(PIN_LED, OUTPUT);
33  Serial.printf("Kapi / Gate: %s\n", NAMES[gate]);
34}
35
36void loop() {
37  int reading = digitalRead(PIN_MODE);
38  if (reading != modeRaw) {          // ham değer değişti, süreyi yeniden başlat / raw value changed, restart the timer
39    modeRaw = reading;
40    modeChangedAt = millis();
41  }
42  // 30 ms boyunca sabit kaldıysa gerçek değişimdir / steady for 30 ms means a real change
43  if (millis() - modeChangedAt > DEBOUNCE_MS && reading != modeStable) {
44    modeStable = reading;
45    if (modeStable == LOW) {         // yeni basış (bırakma sayılmaz) / new press (release is ignored)
46      gate = (gate + 1) % GATE_COUNT;
47      Serial.printf("Kapi / Gate: %s\n", NAMES[gate]);
48    }
49  }
50
51  bool a = !digitalRead(PIN_A);   // basılı = 1 / pressed = 1
52  bool b = !digitalRead(PIN_B);
53  digitalWrite(PIN_LED, evaluate(gate, a, b) ? HIGH : LOW);
54}
ESP32 e Pico funzionano a 3,3 V e i loro pin non tollerano i 5 V. Se usi un integrato 74HC con queste schede, alimentalo anch'esso a 3,3 V; un 74HC funziona già da 2 V, quindi non c'è problema. Se l'integrato è alimentato a 5 V, i 5 V della sua uscita possono danneggiare l'ingresso della scheda; nella direzione opposta, un segnale a 3,3 V resta sotto i 3,5 V, la soglia di 1 sicuro di un 74HC a 5 V. Se devi comunicare con un circuito a 5 V, usa un integrato 74HCT o un convertitore di livello logico.

Porte logiche con Raspberry Pi Pico e MicroPython

In MicroPython gli operatori logici si scrivono con parole inglesi: and, or, not. Gli operatori bit a bit sono gli stessi del C++: &, |, ^ e ~. Il codice seguente legge due pulsanti su GP14 e GP15 e mostra i risultati di AND, OR, NAND, NOR, XOR e XNOR su sei LED collegati a GP16–GP21. L'altro lato di ogni pulsante va a GND e ogni LED è collegato tramite una resistenza da 220–330 Ω. Se salvi il codice in Thonny come main.py, viene eseguito a ogni accensione del Pico; se sei alle prime armi con il Pico, parti da Cos'è il Raspberry Pi Pico?.

MicroPython
1# Pico ile 6 mantık kapısı / 6 logic gates on the Pico
2from machine import Pin
3import time
4
5btn_a = Pin(14, Pin.IN, Pin.PULL_UP)   # A butonu, diğer ucu GND / button A, other leg to GND
6btn_b = Pin(15, Pin.IN, Pin.PULL_UP)   # B butonu / button B
7
8# GP16..GP21: AND, OR, NAND, NOR, XOR, XNOR
9leds = [Pin(n, Pin.OUT) for n in range(16, 22)]
10gates = [
11    ("AND",  lambda a, b: a and b),
12    ("OR",   lambda a, b: a or b),
13    ("NAND", lambda a, b: not (a and b)),
14    ("NOR",  lambda a, b: not (a or b)),
15    ("XOR",  lambda a, b: a != b),
16    ("XNOR", lambda a, b: a == b),
17]
18
19last = None
20while True:
21    a = int(not btn_a.value())   # basılı = 1 / pressed = 1
22    b = int(not btn_b.value())
23    results = [int(f(a, b)) for _, f in gates]
24    for led, r in zip(leds, results):
25        led.value(r)
26    if (a, b) != last:           # yalnız değişince yaz / print only on change
27        line = " ".join("%s=%d" % (g[0], r) for g, r in zip(gates, results))
28        print("A=%d B=%d  %s" % (a, b, line))
29        last = (a, b)
30    time.sleep_ms(20)

Anche Python ha una trappola simile: ~True dà -2, perché un bool è in realtà un intero. Per invertire un bit usa not x, 1 - x oppure x ^ 1. Inoltre gli operatori and e or di Python non restituiscono sempre True o False, ma l'ultimo valore valutato: 0 or 5 dà 5. Per questo il codice usa le conversioni int(), così i LED ricevono sempre e solo 0 o 1.

Idee di progetti con le porte logiche

  • Luce notturna intelligente (AND): Accendi la luce quando è buio E viene rilevato un movimento; combina un LDR e un sensore PIR in un'unica condizione &&.
  • Luce delle scale (XOR): Comanda una lampada con due pulsanti in fondo e in cima alla scala; calcola lo stato della lampada con XOR e accendi la lampada a 230 V con un modulo relè.
  • Allarme di casa (AND + OR): Con il sistema inserito, fai suonare la sirena se si apre la porta OPPURE la finestra. Rileva porta e finestra con un interruttore reed; trovi i dettagli nella guida sistema di allarme con Arduino.
  • Cassaforte a due chiavi (AND): La serratura si apre solo se due persone diverse premono il loro pulsante nello stesso momento, oppure dopo la verifica del codice sul tastierino.
  • Calcolatrice a 4 bit: Somma due numeri inseriti con degli interruttori usando la logica del sommatore completo e mostra il risultato su un display a 7 segmenti.
  • Pulsante da quiz: Blocca il LED del primo concorrente che preme e impedisci agli altri di farlo; è la versione software di un latch costruito con le NAND.
  • Controllo di parità: Applica la XOR a tutti i bit di un byte; se il risultato è 1, il numero di uni è dispari. Il bit di parità della comunicazione seriale si calcola esattamente così.

Errori comuni e soluzioni

SintomoCausa probabileSoluzione
Il LED lampeggia da solo e cambia quando avvicini la manoIngresso flottante, nessuna resistenza di pull-downMetti una resistenza di pull-down o pull-up da 10 kΩ su ogni ingresso
L'integrato si scaldaVCC e GND invertiti o due uscite collegate tra loroIl piedino 14 va a VCC e il 7 a GND; non unire mai le uscite
Nessuna porta rispondeManca l'alimentazione o l'integrato non è a cavallo del canaleMisura tra i piedini 14 e 7 con il multimetro e posiziona l'integrato sul canale
Risultati sbagliati con un 74HC02 o un CD4011Piedinatura diversa dal 74HC08Collega secondo la tabella dei piedini del datasheet
L'integrato assorbe più corrente del dovutoIngressi inutilizzati flottantiCollega a GND tutti gli ingressi liberi
Risultati instabili con ESP32 o PicoUn segnale a 3,3 V non basta per un 74HC a 5 VAlimenta il 74HC a 3,3 V o usa un 74HCT
if (a & b) è inaspettatamente false& lavora bit a bit; 2 & 1 = 0Usa && nelle condizioni
if (x & 1 == 0) non viene mai eseguito== viene valutato prima di &Usa le parentesi: (x & 1) == 0
Una pressione cambia la porta più volteRimbalzi del pulsanteAttendi 20–50 ms via software o usa un filtro RC + 74HC14
Prima di montare un circuito, scrivi la sua tabella di verità su carta e poi prova ogni riga una alla volta. La riga in cui il LED non corrisponde al risultato atteso ti dice che il problema sta nella porta usata da quella riga o nel suo cablaggio. Tieni aperto lo strumento Porte logiche per controllare velocemente la tabella, e prima di montarlo puoi anche provare il circuito in modo virtuale su Tinkercad.

Le porte logiche sono l'alfabeto di tutto il mondo digitale, dall'accensione di un LED alla somma eseguita da un processore. Una volta capiti AND, OR e NOT, leggere una condizione if, una regola di allarme o uno shift register diventa molto più semplice. Nell'app BlueGrays trovi progetti per accendere un LED con un pulsante, progetti con pulsanti per ESP32 e Raspberry Pi Pico, un'illuminazione intelligente delle scale e un'illuminazione intelligente che combina PIR e LDR, ognuno con schemi elettrici e codice passo passo, così puoi mettere in pratica in progetti reali la logica delle porte vista in questo articolo.

Domande frequenti

Quali sono le porte logiche e a cosa servono?

Le porte logiche fondamentali sono sette: AND, OR, NOT, NAND, NOR, XOR e XNOR. Ognuna osserva ingressi che valgono 0 o 1 e produce un'unica uscita secondo la propria regola. Tutti i circuiti digitali, come processori, memorie, contatori e calcolatrici, nascono dalla combinazione di queste porte.

Come si costruisce una tabella di verità?

Per prima cosa ricava il numero di righe dal numero di ingressi: n ingressi richiedono 2ⁿ righe. Scrivi gli ingressi nell'ordine del conteggio binario (00, 01, 10, 11), poi applica a ogni riga la regola della porta per riempire la colonna dell'uscita. Nei circuiti con più porte, aggiungere una colonna per ogni uscita intermedia semplifica il calcolo.

Perché la porta NAND è universale?

Perché usando solo porte NAND puoi costruire NOT, AND, OR, NOR, XOR e XNOR. Per esempio, unire i due ingressi di una NAND dà una NOT, due NAND in fila danno una AND e quattro NAND danno una XOR. Anche la porta NOR ha la stessa proprietà, quindi è considerata universale.

Qual è la differenza tra XOR e XNOR?

La XOR dà 1 quando gli ingressi sono diversi, mentre la XNOR dà 1 quando sono uguali. La XNOR è l'inversa della XOR e serve a verificare se due bit sono uguali. La XOR si usa nei circuiti sommatori, nel controllo di parità e per invertire un bit.

Qual è la differenza tra 74HC08 e 74LS08?

Entrambi contengono quattro porte AND a due ingressi e hanno la stessa piedinatura. Il 74HC08 è in tecnologia CMOS, funziona da 2 a 6 V e assorbe pochissima corrente; il 74LS08 è TTL, funziona solo intorno ai 5 V e consuma di più. Per i nuovi progetti scegli il 74HC, e il 74HCT quando colleghi segnali a 3,3 V a un circuito a 5 V.

Qual è la differenza tra && e & in Arduino?

&& è l'operatore AND logico: verifica se entrambe le condizioni sono vere e restituisce true o false. & è l'AND bit a bit e confronta separatamente ogni bit di due numeri. Per questo 2 && 1 vale true, mentre 2 & 1 vale 0; nelle condizioni if devi usare &&.

Vedi tutti i progetti
Accendere un LED con un pulsante (Push)
#9Principiante

Accendere un LED con un pulsante (Push)

Come un campanello: la luce resta accesa finché premi e si spegne quando lasci. L'Arduino ascolta il pulsante di continuo; mentre è premuto accende il LED, e appena togli il dito lo spegne. Con questo

4.9(112)
198
Accendere e spegnere un LED con un pulsante
#10Principiante

Accendere e spegnere un LED con un pulsante

Premi il pulsante una volta e la luce si accende, premilo di nuovo e si spegne, proprio come l'interruttore della tua stanza. L'Arduino si accorge di ogni pressione e porta il LED nello stato opposto,

4.8(100)
162
Controllo LED ESP32 con pulsante (Push)
#104Principiante

Controllo LED ESP32 con pulsante (Push)

Il LED si accende quando il pulsante viene premuto e si spegne quando viene rilasciato. Mostra come vengono utilizzati il pin di ingresso digitale dell'ESP32 e la resistenza di pull-up interna. Grazie alla modalità INPUT_PULLUP, non è necessaria alcuna resistenza esterna.

4.6(36)
55
Controllo LED ESP32 con pulsante (Toggle)
#105Principiante

Controllo LED ESP32 con pulsante (Toggle)

Ogni volta che si preme il pulsante, lo stato del LED cambia: se è acceso si spegne, se è spento si accende. Classico schema toggle. Con il debounce puliamo il rumore meccanico del pulsante per garantire una singola commutazione con una sola pressione.

4.6(39)
57
Raspberry Pi Pico LED Controllato da Pulsante (Push, GP14 + GP2)
#155Principiante
Premium

Raspberry Pi Pico LED Controllato da Pulsante (Push, GP14 + GP2)

Primo progetto di **input** con Pico — lettura pulsante! 🔘 LED si accende mentre il pulsante è premuto. Impara `Pin.IN`, `Pin.PULL_UP` e `button.value()`. GP14 LED, GP2 pulsante con PULL_UP interno. Premuto = 0, rilasciato = 1 — standard.

0.0(0)
11
Raspberry Pi Pico: controllo indipendente di 2 LED tramite 2 pulsanti (GP12-13 + GP4-5)
#157Principiante
Premium

Raspberry Pi Pico: controllo indipendente di 2 LED tramite 2 pulsanti (GP12-13 + GP4-5)

2 pulsanti, 2 LED — completamente indipendenti l'uno dall'altro! 🔴🟢 Ogni pulsante controlla il proprio LED: quando si preme BTN1 si accende il LED rosso, quando si preme BTN2 si accende il LED verde. Se si premono entrambi contemporaneamente, si accendono entrambi i LED (funzionamento in parallelo). Contenuti: **gestione di oggetti con più pin** (più ingressi/uscite contemporanei), **operatore ternario** (`1 if x else 0` — l’if-else compatto di Python), **controllo indipendente di I/O** (logica

0.0(0)
7
Illuminazione intelligente di scale e corridoi
#82Intermedio
Premium

Illuminazione intelligente di scale e corridoi

Metti piede sulle scale o nel corridoio e le luci si accendono gradino dopo gradino nella direzione in cui cammini. A ogni estremità c'è un sensore di distanza; davanti a qualunque dei due passi, gli

5.0(35)
51
Illuminazione Intelligente ESP32 (PIR + LDR + Relè + OLED)
#141Avanzato
Premium

Illuminazione Intelligente ESP32 (PIR + LDR + Relè + OLED)

Trasforma il tuo corridoio, bagno o dispensa in illuminazione intelligente con ESP32! Utilizzando un sensore di movimento PIR, un sensore di luce LDR e un modulo relè, costruiamo lo scenario classico "la luce si accende quando viene rilevato movimento al buio" — se l'ambiente è già luminoso, il movimento NON attiva la luce, risparmiando energia durante il giorno. La luce rimane accesa per 30 secondi; se il movimento continua, il timer si azzera e la luce rimane accesa più a lungo. Il display OLE

4.3(6)
11