Bases · 21 min de lecture

Portes logiques : ET, OU, NON, XOR, table de vérité et Arduino

Les portes logiques ET, OU, NON, NAND, NOR et XOR : symboles, tables de vérité, circuits 74HC08 et 74HC00, demi-additionneur et code Arduino, ESP32 et Pico.

Les portes logiques sont les briques de base des circuits numériques : chacune observe une ou plusieurs entrées numériques et produit une seule sortie numérique selon une règle fixe. Les entrées ne peuvent valoir que 0 (LOW) ou 1 (HIGH), et la sortie aussi. Il existe sept portes de base : ET (AND), OU (OR), NON (NOT), NON-ET (NAND), NON-OU (NOR), OU exclusif (XOR) et XNOR. Du processeur de ton téléphone à la carte d'un lave-linge, de l'ATmega328P d'un Arduino à une calculatrice de poche, tous les appareils numériques fonctionnent en combinant des millions de minuscules portes logiques.

Dans ce guide, tu vas découvrir le symbole et la table de vérité de chaque porte, de vrais circuits intégrés comme les 74HC08, 74HC32 et 74HC00, une expérience à deux boutons-poussoirs sur plaque d'essai, comment construire toutes les autres portes uniquement avec des NAND, et le demi-additionneur qui additionne deux bits. Dans les dernières parties, nous traduirons la même logique en code sur Arduino avec les opérateurs &&, || et ! et avec les opérations bit à bit, puis nous continuerons avec des exemples pour l'ESP32 et le Raspberry Pi Pico (MicroPython).

Plaque d'essai pour les expériences de portes logiques
Tu peux essayer les circuits de portes logiques sans soudure en les plaçant à cheval sur la rainure centrale de la plaque d'essai.

Qu'est-ce qu'une porte logique et comment fonctionne-t-elle ?

En électronique numérique, chaque signal se trouve dans l'un de deux états : 1 (HIGH, vrai) ou 0 (LOW, faux). Les mathématiques qui manipulent ces deux valeurs s'appellent l'algèbre de Boole ; dans un livre publié en 1854, George Boole a exprimé le raisonnement logique sous forme d'algèbre de cette manière. En 1937, Claude Shannon a montré que cette algèbre correspond exactement aux circuits de commutation à relais, posant ainsi les bases de la conception des circuits numériques. Aujourd'hui, une porte logique ne contient que quelques transistors : en technologie CMOS, une porte NON compte 2 MOSFET et une NAND en compte 4. Nous expliquons comment un transistor fonctionne en interrupteur dans Qu'est-ce qu'un transistor ?.

Mais quelle tension le circuit considère-t-il comme un 1, et laquelle comme un 0 ? Cela dépend de la tension d'alimentation de la carte et de la famille du circuit. Le tableau ci-dessous indique les seuils à partir desquels une entrée est reconnue à coup sûr comme 1 ou comme 0. La zone entre les deux seuils est la zone indéterminée ; si une entrée y reste, la sortie peut se comporter au hasard. Une entrée reliée à rien, dite entrée flottante, erre justement dans cette zone. C'est pourquoi chaque entrée doit être reliée à un signal, ou à GND ou VCC à travers une résistance.

Carte / familleAlimentationEntrée reconnue comme 1Entrée reconnue comme 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
Circuit 74HC5 V≥ 3,5 V≤ 1,5 V
Circuit 74HCT5 V≥ 2,0 V≤ 0,8 V
Circuit CD40005 V≥ 3,5 V≤ 1,5 V

Les 7 portes logiques de base et leurs symboles

Sur les schémas, les portes sont dessinées selon deux normes différentes. Dans la norme américaine (ANSI/IEEE), chaque porte a sa propre forme : ET ressemble à la lettre D, OU à un bouclier pointu et NON à un triangle. Le petit rond en sortie signifie "inverser" ; une NAND est donc une porte ET avec un rond au bout. Ce qui distingue le OU exclusif du OU, c'est la deuxième ligne courbe côté entrées. Dans la norme européenne (CEI), utilisée dans beaucoup de manuels, toutes les portes sont des rectangles qui se distinguent par le signe inscrit à l'intérieur : & pour ET, ≥1 pour OU, =1 pour XOR et 1 pour NON.

PorteNom en françaisSymbole ANSISigne CEIExpression booléenneQuand la sortie vaut-elle 1 ?
ANDETForme de D&Y = A · BLes deux entrées valent 1
OROUBouclier pointu≥1Y = A + BAu moins une entrée vaut 1
NOTNON (inverseur)Triangle + rond1 (rond en sortie)Y = A'L'entrée vaut 0
NANDNON-ETForme de D + rond& (rond en sortie)Y = (A · B)'Au moins une entrée vaut 0
NORNON-OUBouclier + rond≥1 (rond en sortie)Y = (A + B)'Les deux entrées valent 0
XOROU exclusifBouclier à double courbe=1Y = A ⊕ BLes entrées sont différentes
XNORNON-OU exclusifDouble courbe + rond=1 (rond en sortie)Y = (A ⊕ B)'Les entrées sont identiques

Tables de vérité des portes logiques

Une table de vérité indique la sortie d'une porte pour chaque combinaison de ses entrées. Une porte à n entrées a 2ⁿ lignes : 4 lignes pour deux entrées, 8 pour trois et 16 pour quatre. Si tu écris les lignes dans l'ordre du comptage binaire (00, 01, 10, 11), tu n'oublieras aucune combinaison. Voici les six portes à deux entrées dans un seul tableau :

ABETOUNANDNORXORXNOR
00001101
01011010
10011010
11110001

Comme la porte NON n'a qu'une entrée, sa table compte deux lignes : quand A = 0 la sortie vaut 1, et quand A = 1 elle vaut 0. En regardant le tableau de près, tu remarques une logique : la colonne NAND est exactement l'inverse de ET, NOR l'inverse de OU et XNOR l'inverse de XOR. Pour les retenir, utilise ces règles courtes : ET demande "sont-elles toutes à 1 ?", OU "y en a-t-il au moins une à 1 ?" et XOR "les entrées sont-elles différentes ?" ; la porte dont le nom commence par N (ou NON) donne la réponse inverse à la même question. Pour essayer les portes toi-même et voir les symboles en direct, touche simplement les entrées A et B dans l'outil Portes logiques.

  • ET : Deux interrupteurs en série. La lampe ne s'allume que si les deux sont fermés ; un coffre de banque qui s'ouvre avec deux clés différentes suit aussi la règle ET.
  • OU : Deux boutons-poussoirs en parallèle. La même sonnette retentit, qu'on appuie sur le bouton de la porte d'entrée ou sur celui de la porte arrière.
  • NON : La lampe du réfrigérateur. Porte fermée, l'interrupteur est enfoncé et la lampe éteinte ; quand la porte s'ouvre, l'interrupteur est relâché et la lampe s'allume.
  • NAND : La règle "alerter si tout n'est pas en ordre". Si un seul des deux carters de sécurité d'une machine est ouvert, le voyant d'alarme s'allume.
  • NOR : La règle "rien ne s'est produit". Un voyant vert "tout va bien" qui ne s'allume que si ni fumée ni gaz ne sont détectés.
  • XOR : Le montage va-et-vient d'un escalier. Basculer l'interrupteur du bas ou celui du haut change l'état de la lampe ; elle est allumée quand les deux interrupteurs sont dans des positions différentes et éteinte quand ils sont identiques.
  • XNOR : Un test d'égalité. Il donne 1 quand deux bits sont identiques ; on le trouve dans les comparateurs numériques et les circuits de détection d'erreurs.

Circuits intégrés de portes logiques : 74HC08, 74HC32, 74HC00

Plutôt que de construire les portes logiques transistor par transistor, on utilise des circuits intégrés tout faits. La famille la plus répandue en électronique de loisir est la série 74HC : un boîtier DIP à 14 broches contient quatre portes à deux entrées, l'alimentation va toujours sur la broche 14 (VCC) et la masse sur la broche 7 (GND). Les 74HC fonctionnent de 2 à 6 V, leurs entrées ne consomment presque aucun courant et, à 5 V, une porte a un temps de propagation d'environ 10 nanosecondes, des centaines de fois plus rapide qu'un simple digitalWrite sur Arduino. Chaque sortie garde ses niveaux de tension garantis sous une charge de 4 mA ; la limite absolue est de 25 mA par sortie et 50 mA pour tout le circuit.

CircuitPorteContenuBrochageÉquivalent CMOS 4000
74HC08ET4 × 2 entréesStandard (tableau ci-dessous)CD4081
74HC32OU4 × 2 entréesStandardCD4071
74HC00NAND4 × 2 entréesStandardCD4011
74HC86XOR4 × 2 entréesStandardCD4070
74HC02NOR4 × 2 entréesDifférent : sorties sur 1, 4, 10, 13CD4001
74HC04NON6 × 1 entréeEntrées sur 1, 3, 5, 9, 11, 13CD4069
74HC14NON (trigger de Schmitt)6 × 1 entréeIdentique au 74HC04CD40106
CD4077 / 74HCS7266XNOR4 × 2 entréesRare ; en général 74HC86 + 74HC04CD4077

Les 74HC08, 74HC32, 74HC00 et 74HC86 ont exactement le même brochage ; seul le type de porte à l'intérieur change. L'encoche ou le point sur le dessus du boîtier repère la broche 1. En regardant le circuit de dessus, encoche à gauche, les broches sont numérotées dans le sens inverse des aiguilles d'une montre : la rangée du bas de gauche à droite de 1 à 7, la rangée du haut de droite à gauche de 8 à 14. A et B sont les entrées, Y la sortie, et le chiffre devant indique le numéro de la porte.

BrocheFonctionBrocheFonction
11A (entrée porte 1)14VCC (+2…6 V)
21B (entrée porte 1)134B (entrée porte 4)
31Y (sortie porte 1)124A (entrée porte 4)
42A (entrée porte 2)114Y (sortie porte 4)
52B (entrée porte 2)103B (entrée porte 3)
62Y (sortie porte 2)93A (entrée porte 3)
7GND83Y (sortie porte 3)
Ne laisse jamais une entrée CMOS en l'air. Relie les entrées des portes inutilisées à GND (ou à VCC) ; une entrée flottante bascule sans cesse avec le bruit, augmente la consommation du circuit et peut même perturber les portes voisines. Les sorties inutilisées, elles, peuvent rester libres. N'oublie pas un condensateur céramique de découplage de 100 nF entre VCC et GND, le plus près possible du circuit.

Les circuits qui font le même travail existent en plusieurs familles. La série 74LS est l'ancienne technologie TTL : elle ne fonctionne qu'entre 4,75 et 5,25 V, consomme davantage et lit généralement une entrée en l'air comme un 1. La série 74HCT est un 74HC à entrées compatibles TTL ; elle s'alimente en 5 V mais reconnaît déjà 2 V comme un 1 certain, ce qui lui permet de lire sans problème les signaux 3,3 V d'un ESP32 ou d'un Pico. La série CD4000 (CD4081, CD4011, etc.) fonctionne sur une large plage de 3 à 18 V, mais elle est plus lente et son brochage diffère de celui des 74HC : un CD4011 ne remplace pas directement un 74HC00.

Expérience à boutons-poussoirs sur plaque d'essai : porte ET avec le 74HC08

Le meilleur moyen de comprendre une porte logique est de l'essayer toi-même avec deux boutons-poussoirs. Pas de microcontrôleur ici : il te faut seulement un 74HC08, deux boutons-poussoirs, deux résistances de 10 kΩ, une résistance de 1 kΩ, une LED et un condensateur de 100 nF. Pour l'alimentation, les broches 5V et GND d'un Arduino, un module d'alimentation pour plaque d'essai ou trois piles AA (4,5 V) suffisent. Si tu n'es pas sûr des connexions internes de la plaque d'essai, lis d'abord Qu'est-ce qu'une breadboard ?.

Bouton-poussoir pour l'expérience sur plaque d'essai
Un bouton-poussoir relie ses deux côtés tant qu'il est enfoncé. Sur les modèles à quatre pattes, les pattes sont reliées deux à deux à l'intérieur ; le plus sûr est de placer le bouton à cheval sur la rainure centrale.
  1. Place le 74HC08 à cheval sur la rainure centrale de la plaque d'essai, les broches de part et d'autre, encoche vers la gauche.
  2. Relie la broche 14 à la ligne + (5 V) et la broche 7 à la ligne − (GND), puis place le condensateur de 100 nF entre ces deux broches.
  3. Relie un côté du bouton A à la ligne + et l'autre côté à la broche 1. Ajoute une résistance de 10 kΩ entre cette même broche et GND : cette résistance de pull-down (rappel au niveau bas) maintient l'entrée fermement à 0 tant que le bouton n'est pas enfoncé.
  4. Relie le bouton B à la broche 2 de la même façon et donne-lui aussi sa propre résistance de pull-down de 10 kΩ.
  5. Depuis la broche 3, la sortie, passe par une résistance de 1 kΩ jusqu'à la patte longue de la LED (anode) ; relie la patte courte (cathode) à GND.
  6. Relie à GND les entrées inutilisées, les broches 4, 5, 9, 10, 12 et 13 ; laisse libres les sorties 6, 8 et 11.
  7. Mets sous tension et essaie les quatre combinaisons l'une après l'autre : la LED ne doit s'allumer que lorsque tu appuies sur les deux boutons en même temps. Compare les résultats avec la table de vérité.
ConnexionBroche du 74HC08À relier à
Alimentation14 (VCC)Ligne +, 5 V
Masse7 (GND)Ligne −
Condensateur de découplageEntre 14 et 7100 nF céramique, près du circuit
Entrée A1Bouton A → 5 V, 10 kΩ → GND
Entrée B2Bouton B → 5 V, 10 kΩ → GND
Sortie31 kΩ → anode de la LED, cathode → GND
Entrées inutilisées4, 5, 9, 10, 12, 13GND
Sorties inutilisées6, 8, 11Libres
Une fois le circuit fonctionnel, la partie amusante commence : retire le 74HC08 et mets à sa place un 74HC32 au même brochage, et la LED s'allume dès que tu appuies sur n'importe quel bouton (OU). Avec un 74HC00, elle reste allumée jusqu'à ce que tu appuies sur les deux boutons ensemble (NAND), et avec un 74HC86 elle ne s'allume que si un seul bouton est enfoncé (XOR). Avec 1 kΩ, une LED rouge consomme environ 3 mA, une valeur sûre pour une sortie 74HC. Pour une LED d'une autre couleur, tu peux calculer la résistance avec l'outil Résistance de LED.

Construire toutes les portes avec des NAND : la porte universelle

La NAND est appelée porte universelle car on peut construire toutes les autres portes uniquement avec des NAND. Cela a aussi un intérêt pratique : en technologie CMOS, la NAND est l'une des portes les plus simples, avec seulement 4 transistors, alors qu'une porte ET est en réalité une NAND suivie d'une NON et en demande 6. Voilà pourquoi les concepteurs de puces adorent la NAND. La mémoire flash NAND des clés USB doit d'ailleurs son nom au fait que ses cellules sont reliées en série, comme les transistors d'une porte NAND. La NOR est elle aussi universelle : l'ordinateur de guidage d'Apollo, parti vers la Lune, était construit avec environ 2 800 circuits contenant chacun deux portes NOR à trois entrées.

Porte à obtenirComment avec des NAND ?NAND nécessaires
NONA NAND A (relier les deux entrées)1
ETFaire passer la sortie de (A NAND B) dans une NON2
OU(A NAND A) NAND (B NAND B)3
NOROU + NON4
XORN1 = A NAND B ; (A NAND N1) NAND (B NAND N1)4
XNORXOR + NON5

La ligne OU du tableau repose sur la loi de De Morgan : (A' · B')' = A + B. Autrement dit, si tu inverses d'abord chaque entrée puis que tu les envoies dans une NAND, tu obtiens un OU. La seconde loi de De Morgan s'écrit (A + B)' = A' · B'. Ces deux lois t'aident aussi à simplifier les conditions dans le code : sur Arduino, !(a && b) donne toujours le même résultat que (!a || !b), et !(a || b) le même que (!a && !b).

Construire un XOR avec quatre portes NAND est un exercice classique d'examen et de TP, et les quatre portes d'un seul 74HC00 suffisent exactement. On calcule d'abord N1 = A NAND B. Puis on obtient N2 = A NAND N1 et N3 = B NAND N1, et la sortie de la dernière porte, Y = N2 NAND N3, donne le XOR. Avec le câblage ci-dessous, tu transformes ton expérience sur plaque d'essai en un XOR à quatre NAND :

Broche du 74HC00ConnexionRôle
1 et 4Bouton AEntrée A (portes 1 et 2)
2 et 10Bouton BEntrée B (portes 1 et 3)
3 → 5 et 9FilN1 = A NAND B
6 → 12FilN2 = A NAND N1
8 → 13FilN3 = B NAND N1
111 kΩ + LEDY = A XOR B
14 / 75 V / GNDAlimentation

Allons un peu plus loin : si tu relies en croix les sorties de deux portes NAND à l'entrée de l'autre, tu obtiens une mémoire de 1 bit appelée bascule RS (verrou SR). Ce circuit se souvient de son dernier état même quand tu relâches le bouton. Les registres des processeurs, les compteurs et des circuits comme le registre à décalage 74HC595 sont formés en enchaînant de telles cellules mémoire construites avec des portes.

Le demi-additionneur : additionner deux bits avec des portes

Ce que les portes logiques savent faire de plus impressionnant, c'est calculer. En binaire, 0 + 0 = 0, 0 + 1 = 1, 1 + 0 = 1 et 1 + 1 = 10 (2 en décimal). Le chiffre de droite du résultat s'appelle la somme et celui qui déborde vers la gauche la retenue (carry). En regardant le tableau ci-dessous, tu verras que la somme est exactement un XOR et la retenue exactement un ET. Une porte XOR et une porte ET côte à côte forment donc un demi-additionneur qui additionne deux nombres d'un bit.

ABRetenue (C = A ET B)Somme (S = A XOR B)Résultat décimal
00000
01011
10011
11102 (binaire 10)

Pour le monter sur la plaque d'essai, relie les boutons A et B aux broches 1 et 2 d'un 74HC86 et d'un 74HC08 à la fois. La broche 3 du 74HC86 commande la LED de somme, la broche 3 du 74HC08 la LED de retenue. Quand tu appuies sur les deux boutons, la LED de somme s'éteint et celle de retenue s'allume : les LED affichent le binaire 10, c'est-à-dire 2. Si tu veux n'utiliser qu'un 74HC00, il te faut quatre NAND pour le XOR et une cinquième NAND qui inverse N1 pour obtenir la retenue ; un demi-additionneur se construit donc avec 5 portes NAND.

Un demi-additionneur ne peut pas tenir compte de la retenue venant du rang inférieur ; pour cela, il faut un additionneur complet (full adder). Ses formules sont S = A ⊕ B ⊕ Cin et Cout = (A · B) + (Cin · (A ⊕ B)), soit deux demi-additionneurs et une porte OU. En chaînant quatre additionneurs complets pour que chacun transmette sa retenue au suivant, tu obtiens un additionneur 4 bits ; le circuit 74HC283 réalise la même addition 4 bits, mais calcule les retenues avec un circuit interne rapide (retenue anticipée, carry look-ahead) au lieu d'attendre qu'elles se propagent le long de la chaîne. L'unité arithmétique du processeur de ton ordinateur est une version 64 bits, bien plus rapide, de la même idée.

Les portes logiques sur Arduino : &&, ||, ! et opérations bit à bit

Dans le code Arduino, chaque porte logique a deux équivalents. Les opérateurs logiques (&&, ||, !) combinent des conditions et donnent un résultat true ou false ; tu les utilises dans les instructions if et while. Les opérateurs bit à bit (&, |, ^, ~) s'appliquent quant à eux à tous les bits d'un nombre en même temps, colonne par colonne ; travailler sur un octet revient à faire fonctionner huit portes à la fois. Les exemples du tableau utilisent les nombres 0b1100 et 0b1010 :

PorteLogique (bool)Bit à bitExempleRésultat
ETa && bx & y0b1100 & 0b10100b1000
OUa || bx | y0b1100 | 0b10100b1110
NON!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 différence entre les deux familles semble mince, mais elle provoque des bugs sournois. && et || utilisent l'évaluation en court-circuit : dans a && b, si a est faux, b n'est même pas évalué. & évalue toujours les deux côtés et regarde les bits des nombres : 2 && 1 vaut true, mais 2 & 1 vaut 0, car 0b10 et 0b01 n'ont aucun bit en commun. Le C++ n'a pas d'opérateur XOR logique à part ; pour deux bool, écrire a != b est le plus lisible. Pour aller plus loin sur les opérations bit à bit, les décalages << et >> et le système binaire, consulte Systèmes de numération et opérations bit à bit.

Passons maintenant l'expérience de la plaque d'essai sur un Arduino Uno. Deux boutons-poussoirs vont sur les broches 2 et 3, et sept LED (chacune avec une résistance de 330 Ω) sur les broches 4 à 10. Chaque bouton a un côté sur la broche et l'autre sur GND ; comme la résistance de pull-up interne est activée, aucune résistance supplémentaire n'est nécessaire. Un seul programme fait vivre les sept portes en même temps :

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}

Avec INPUT_PULLUP, un bouton enfoncé se lit LOW ; le code inverse donc la lecture avec ! et un bouton enfoncé devient 1. Chaque LED affiche ensuite le résultat de sa porte : 4 ET, 5 OU, 6 NON A, 7 NAND, 8 NOR, 9 XOR et 10 XNOR. Si tu ouvres le moniteur série à 9600 bauds, la ligne complète s'affiche à chaque changement de bouton ; après avoir essayé les quatre combinaisons, tu auras établi la table de vérité de tes propres mains. Les détails de la logique pull-up sont dans Comment brancher un bouton-poussoir sur Arduino.

Pour voir la puissance des opérations bit à bit, le deuxième exemple calcule toute la table de vérité en quelques lignes. L'astuce : si tu écris la colonne A sous la forme du nombre 0b1100 et la colonne B sous la forme 0b1010, chaque bit correspond à une ligne du tableau, et un seul & te donne d'un coup les quatre lignes de la colonne ET. La seconde moitié du programme additionne bit à bit deux nombres de 4 bits avec les formules de l'additionneur complet, imitant ainsi en logiciel le circuit additionneur d'un processeur. Ce programme ne demande aucun matériel ; ouvre simplement le moniteur série.

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}
N'utilise pas ~ avec des valeurs bool : ~ inverse tous les bits et transforme true (1) en -2, et comme -2 n'est pas nul, il compte toujours comme true. Pour un NON logique, utilise toujours !. Autre piège, la priorité des opérateurs : dans if (x & 1 == 0), c'est 1 == 0 qui est évalué en premier, la bonne écriture est donc if ((x & 1) == 0). Enfin, appliquer ~ à une variable byte transforme le résultat en int ; tronque-le avec un masque comme & 0x0F ou & 0xFF, comme le fait le code.

Un testeur de circuits 74HC avec Arduino

Si le marquage d'un circuit est effacé ou si tu veux savoir s'il fonctionne encore, tu peux transformer l'Arduino en testeur. Ce programme applique tour à tour les quatre combinaisons d'entrée aux quatre portes d'un 74HC00, 74HC08, 74HC32 ou 74HC86 (les circuits au brochage standard), lit les sorties et compare le résultat à des motifs connus. Relie la broche 14 du circuit au 5V, la broche 7 à GND et les autres broches aux broches de l'Arduino indiquées dans le tableau du code.

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}
Si tu te trompes de câblage, une sortie de l'Arduino peut se retrouver face à une sortie du circuit. Pour l'éviter, tu peux placer une résistance de 1 kΩ entre les sorties du circuit (3, 6, 8, 11) et les broches de l'Arduino ; le résultat du test ne change pas, mais les deux côtés sont protégés en cas d'erreur. Les 74HC02 et 74HC04 ont un autre brochage, ce programme ne peut donc pas les tester directement ; il faudrait adapter le tableau GATES d'après leur fiche technique.

Une porte logique programmable avec l'ESP32

Sur l'ESP32, les mêmes opérateurs fonctionnent sans changement. Dans cet exemple, un troisième bouton fait défiler les types de portes et une seule LED affiche la sortie de la porte choisie. Tu peux ainsi montrer six portes avec un seul circuit en classe ou lors d'une présentation. Les boutons vont sur GPIO 25, 26 et 27 (leur autre côté sur GND) et la LED sur GPIO 23 à travers une résistance de 220 Ω ; le nom de la porte choisie s'affiche dans le moniteur série à 115200 bauds.

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}
L'ESP32 et le Pico fonctionnent en 3,3 V et leurs broches ne tolèrent pas le 5 V. Si tu utilises un circuit 74HC avec ces cartes, alimente-le aussi en 3,3 V ; un 74HC fonctionne dès 2 V, ce n'est donc pas un problème. Si le circuit est alimenté en 5 V, les 5 V de sa sortie peuvent endommager l'entrée de la carte ; dans l'autre sens, un signal de 3,3 V reste sous 3,5 V, le seuil de 1 garanti d'un 74HC alimenté en 5 V. Si tu dois dialoguer avec un circuit 5 V, utilise un circuit 74HCT ou un convertisseur de niveau logique.

Portes logiques avec le Raspberry Pi Pico et MicroPython

En MicroPython, les opérateurs logiques s'écrivent avec des mots anglais : and, or, not. Les opérateurs bit à bit sont les mêmes qu'en C++ : &, |, ^ et ~. Le code ci-dessous lit deux boutons-poussoirs sur GP14 et GP15 et affiche les résultats de ET, OU, NAND, NOR, XOR et XNOR sur six LED reliées à GP16–GP21. L'autre côté de chaque bouton va à GND et chaque LED est reliée par une résistance de 220 à 330 Ω. Si tu enregistres le code dans Thonny sous le nom main.py, il s'exécute à chaque mise sous tension du Pico ; si tu débutes avec le Pico, commence par Qu'est-ce que le 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)

Python cache un piège semblable : ~True donne -2, car un bool est en réalité un entier. Pour inverser un bit, utilise not x, 1 - x ou x ^ 1. De plus, les opérateurs and et or de Python ne renvoient pas toujours True ou False, mais la dernière valeur évaluée : 0 or 5 donne 5. C'est pourquoi le code utilise des conversions int(), afin que les LED ne reçoivent jamais autre chose que 0 ou 1.

Idées de projets avec des portes logiques

  • Veilleuse intelligente (ET) : Allume la lumière quand il fait sombre ET qu'un mouvement est détecté ; combine une photorésistance LDR et un capteur PIR dans une seule condition &&.
  • Éclairage d'escalier (XOR) : Commande une lampe avec deux boutons en bas et en haut de l'escalier ; calcule l'état de la lampe avec un XOR et commute la lampe 230 V avec un module relais.
  • Alarme maison (ET + OU) : Quand le système est armé, déclenche la sirène si la porte OU la fenêtre s'ouvre. Détecte la porte et la fenêtre avec un interrupteur reed ; les détails sont dans le guide système d'alarme Arduino.
  • Coffre à deux clés (ET) : La serrure ne s'ouvre que si deux personnes différentes appuient en même temps sur leur bouton, ou une fois le code du clavier matriciel validé.
  • Calculatrice 4 bits : Additionne deux nombres saisis avec des interrupteurs grâce à la logique de l'additionneur complet et affiche le résultat sur un afficheur 7 segments.
  • Buzzer de quiz : Verrouille la LED du premier candidat qui appuie et bloque les autres ; c'est la version logicielle d'une bascule à base de NAND.
  • Contrôle de parité : Combine tous les bits d'un octet avec XOR ; si le résultat vaut 1, le nombre de 1 est impair. Le bit de parité des liaisons série est calculé exactement de cette façon.

Erreurs fréquentes et solutions

SymptômeCause probableSolution
La LED clignote toute seule et change quand tu approches la mainEntrée flottante, pas de résistance de pull-downAjoute une résistance de pull-down ou pull-up de 10 kΩ sur chaque entrée
Le circuit chauffeVCC et GND inversés ou deux sorties reliéesLa broche 14 va au VCC et la 7 à GND ; ne relie jamais des sorties
Aucune porte ne réagitPas d'alimentation ou circuit mal placé sur la rainureMesure entre les broches 14 et 7 au multimètre, place le circuit à cheval sur la rainure
Résultats faux avec un 74HC02 ou un CD4011Brochage différent de celui du 74HC08Câble selon le tableau des broches de la fiche technique
Le circuit consomme plus que prévuEntrées inutilisées en l'airRelie toutes les entrées libres à GND
Résultats instables avec un ESP32 ou un PicoUn signal 3,3 V ne suffit pas pour un 74HC en 5 VAlimente le 74HC en 3,3 V ou utilise un 74HCT
if (a & b) est faux de façon inattendue& travaille bit à bit ; 2 & 1 = 0Utilise && dans les conditions
if (x & 1 == 0) ne s'exécute jamais== est évalué avant &Ajoute des parenthèses : (x & 1) == 0
Un appui change la porte plusieurs foisRebonds du boutonAttends 20 à 50 ms en logiciel ou utilise un filtre RC + 74HC14
Avant de monter un circuit, écris sa table de vérité sur papier, puis teste chaque ligne une à une. La ligne où la LED ne correspond pas au résultat attendu t'indique que le problème vient de la porte utilisée par cette ligne ou de son câblage. Garde l'outil Portes logiques ouvert pour vérifier rapidement la table, et tu peux aussi essayer le circuit virtuellement dans Tinkercad avant de le monter.

Les portes logiques sont l'alphabet de tout le monde numérique, de l'allumage d'une LED jusqu'à l'addition dans un processeur. Une fois que tu maîtrises ET, OU et NON, lire une condition if, une règle d'alarme ou un registre à décalage devient beaucoup plus simple. Dans l'application BlueGrays, tu trouveras des projets pour allumer une LED avec un bouton, des projets à boutons pour ESP32 et Raspberry Pi Pico, un éclairage d'escalier intelligent et un éclairage intelligent qui combine PIR et LDR, chacun avec schémas et code pas à pas, pour mettre en pratique dans de vrais projets la logique des portes vue dans cet article.

Questions fréquentes

Quelles sont les portes logiques et à quoi servent-elles ?

Il existe sept portes logiques de base : ET, OU, NON, NAND (NON-ET), NOR (NON-OU), XOR (OU exclusif) et XNOR. Chacune observe des entrées valant 0 ou 1 et produit une seule sortie selon sa propre règle. Tous les circuits numériques, comme les processeurs, les mémoires, les compteurs et les calculatrices, sont formés en combinant ces portes.

Comment faire une table de vérité ?

Détermine d'abord le nombre de lignes à partir du nombre d'entrées : n entrées demandent 2ⁿ lignes. Écris les entrées dans l'ordre du comptage binaire (00, 01, 10, 11), puis applique la règle de la porte à chaque ligne pour remplir la colonne de sortie. Pour un circuit à plusieurs portes, ajouter une colonne par sortie intermédiaire facilite le calcul.

Pourquoi la porte NAND est-elle universelle ?

Parce qu'avec uniquement des portes NAND, tu peux construire NON, ET, OU, NOR, XOR et XNOR. Par exemple, relier les deux entrées d'une NAND donne un NON, deux NAND à la suite donnent un ET et quatre NAND donnent un XOR. La porte NOR possède la même propriété et est donc elle aussi universelle.

Quelle est la différence entre XOR et XNOR ?

XOR donne 1 quand les entrées sont différentes, alors que XNOR donne 1 quand elles sont identiques. XNOR est l'inverse de XOR et sert à vérifier si deux bits sont égaux. XOR est utilisé dans les additionneurs, le contrôle de parité et pour inverser un bit.

Quelle est la différence entre le 74HC08 et le 74LS08 ?

Les deux contiennent quatre portes ET à deux entrées et ont le même brochage. Le 74HC08 est en technologie CMOS, fonctionne de 2 à 6 V et consomme très peu ; le 74LS08 est en TTL, ne fonctionne qu'autour de 5 V et consomme davantage. Pour un nouveau projet, choisis le 74HC, et le 74HCT pour relier des signaux 3,3 V à un circuit 5 V.

Quelle est la différence entre && et & sur Arduino ?

&& est l'opérateur ET logique : il vérifie si les deux conditions sont vraies et renvoie true ou false. & est le ET bit à bit et compare séparément chaque bit de deux nombres. C'est pourquoi 2 && 1 vaut true mais 2 & 1 vaut 0 ; dans les conditions if, utilise &&.

Voir tous les projets
Allumer une LED avec un bouton-poussoir (Push)
#9Débutant

Allumer une LED avec un bouton-poussoir (Push)

Comme une sonnette : la lumière reste allumée tant que tu appuies et s'éteint quand tu relâches. L'Arduino surveille le bouton en permanence ; tant qu'il est enfoncé la LED est allumée, et dès que tu

4.9(112)
198
Allumer et éteindre une LED avec un bouton
#10Débutant

Allumer et éteindre une LED avec un bouton

Un appui et la lumière s'allume, un deuxième et elle s'éteint, exactement comme l'interrupteur de ta chambre. L'Arduino remarque chaque appui et fait passer la LED à l'état inverse, en attendant un co

4.8(100)
162
ESP32 Contrôle de LED avec bouton poussoir (Push)
#104Débutant

ESP32 Contrôle de LED avec bouton poussoir (Push)

La LED s'allume lorsque le bouton est enfoncé et s'éteint lorsqu'il est relâché. Montre comment la broche d'entrée numérique de l'ESP32 et la résistance pull-up interne sont utilisées. Grâce au mode INPUT_PULLUP, aucune résistance externe n'est nécessaire.

4.6(36)
55
ESP32 Contrôle de LED avec bouton (Toggle)
#105Débutant

ESP32 Contrôle de LED avec bouton (Toggle)

Chaque fois que l'on appuie sur le bouton, la LED change d'état : si elle est allumée, elle s'éteint, si elle est éteinte, elle s'allume. Modèle classique de basculement. Avec le debounce, nous nettoyons le bruit mécanique du bouton-poussoir pour garantir un seul basculement avec une seule pression.

4.6(39)
57
Raspberry Pi Pico LED Contrôlée par Bouton (Push, GP14 + GP2)
#155Débutant
Premium

Raspberry Pi Pico LED Contrôlée par Bouton (Push, GP14 + GP2)

Premier projet **entrée** avec Pico — lecture bouton ! 🔘 LED s'allume tant que le bouton est pressé. Apprends `Pin.IN`, `Pin.PULL_UP` et `button.value()`. GP14 LED, GP2 bouton avec PULL_UP interne. Pressé = 0, relâché = 1 — standard.

0.0(0)
11
Raspberry Pi Pico : commande indépendante de 2 LED à l'aide de 2 boutons (GP12-13 + GP4-5)
#157Débutant
Premium

Raspberry Pi Pico : commande indépendante de 2 LED à l'aide de 2 boutons (GP12-13 + GP4-5)

2 boutons, 2 LED — totalement indépendants l'un de l'autre ! 🔴🟢 Chaque bouton contrôle sa propre LED : lorsque BTN1 est enfoncé, la LED rouge s'allume ; lorsque BTN2 est enfoncé, la LED verte s'allume. Si vous appuyez sur les deux en même temps, les deux LED s'allument (fonctionnement en parallèle). Apprentissage : **gestion d'objets à broches multiples** (plusieurs entrées/sorties simultanées), **opérateur ternaire** (`1 if x else 0` — l'if-else compact de Python), **contrôle indépendant des E/

0.0(0)
7
Éclairage intelligent des escaliers et des couloirs
#82Intermédiaire
Premium

Éclairage intelligent des escaliers et des couloirs

Pose le pied dans l'escalier ou le couloir et les lumières s'allument marche après marche dans ton sens de passage. Un capteur de distance se trouve à chaque extrémité ; quel que soit celui devant leq

5.0(35)
51
Éclairage Intelligent ESP32 (PIR + LDR + Relais + OLED)
#141Avancé
Premium

Éclairage Intelligent ESP32 (PIR + LDR + Relais + OLED)

Transformez votre couloir, votre salle de bain ou votre garde-manger en éclairage intelligent avec l'ESP32 ! En utilisant un capteur de mouvement PIR, un capteur de lumière LDR et un module relais, nous construisons le scénario classique "la lumière s'allume lorsqu'un mouvement est détecté dans l'obscurité" — si l'environnement est déjà lumineux, le mouvement N'ACTIVE PAS la lumière, économisant ainsi de l'énergie pendant la journée. La lumière reste allumée pendant 30 secondes ; si le mouvement

4.3(6)
11