Tutoriel · Débutant · 28 min de lecture
GPIO 8051 et interfaçage des ports : puisez, ne sourcez pas
Broche 8051 : elle puise dix milliampères et n'en source presque aucun. D'où le câblage de LED inversé, le 1 écrit avant de lire, et les limites d'un port.
Introduction
Le premier programme 8051 que tous écrivent fait clignoter une LED, et un nombre surprenant d’entre eux ne clignotent pas. Le câblage semble bon, le code semble bon, et la broche mesure un 5 V assuré qui ne fait rien d’utile.
La cause est presque toujours la même, et elle est architecturale plutôt qu’une erreur : une broche 8051 tire bien vers le bas et mal vers le haut. Tout le reste de ce tutoriel en découle — pourquoi les LED se câblent à l’opposé d’un Arduino, pourquoi lire un interrupteur exige d’abord une écriture, et pourquoi un port ne peut pas piloter huit quoi que ce soit.
Un port est juste un octet
Il n’y a pas d’API GPIO. Les quatre ports sont des registres spéciaux à adresses fixes, et en écrire un change les broches :
#include <reg52.h>
void main(void) {
P1 = 0x00; // all eight P1 pins low
P1 = 0xFF; // all eight high
P1 = 0b10101010; // alternating
}
Les bits individuels se nomment avec sbit, la forme vue dans presque tout le matériel de cours :
sbit LED = P1^0; // Keil C51 syntax
sbit BUTTON = P1^1;
LED = 0; // one instruction — the 8051 has real bit operations
Ce ^ n’est pas un ou-exclusif. C’est la notation Keil pour « bit 0 de P1 ». Sous SDCC, l’équivalent vient de <8051.h> comme P1_0, et le reste du code est inchangé.
De quoi est faite une broche
Chaque broche de port possède un faible rappel interne vers l’alimentation et un fort transistor de tirage vers la masse, avec le verrou de port pilotant la grille du transistor. Les deux n’ont rien à voir en force.
Écrivez 0 et le transistor s’allume, bloquant la broche près de la masse et absorbant volontiers le courant venu de l’extérieur. Écrivez 1 et le transistor s’éteint, ne laissant que ce faible rappel — des dizaines de microampères — pour tenir la ligne haute. Assez pour présenter un 1 logique à une autre entrée CMOS, et loin d’assez pour allumer quoi que ce soit.
Cet arrangement s’appelle quasi bidirectionnel : la même broche est sortie et entrée, sans registre de direction à configurer, car une broche tenant un 1 est déjà assez relâchée pour être pilotée par autre chose.
Les LED vont donc dans l’autre sens
Sur Arduino, on câble une LED de la broche via une résistance à la masse et on pilote la broche haute. Faites cela sur 8051 et vous obtenez au mieux une faible lueur, car 60 µA n’est pas une source de lumière.
Le câblage 8051 est inversé : anode vers +5 V via la résistance, cathode vers la broche. La broche puise le courant, et un 0 allume la LED.
sbit LED = P1^0;
LED = 0; // ON — the pin sinks current from the supply
LED = 1; // OFF — the pin releases the line
Dimensionnez la résistance pour le courant voulu, en rappelant que la broche elle-même chute d’environ un demi-volt en puisant :
R = (Vsupply − Vf(LED) − Vpin) / I
red LED at 5 mA : (5 − 2.0 − 0.5) / 0.005 = 500 Ω → use 470 Ω
red LED at 10 mA: (5 − 2.0 − 0.5) / 0.010 = 250 Ω → use 270 Ω
Le budget de courant de port que personne ne mentionne
Les limites par broche ne sont que la moitié de l’histoire. La fiche technique de l’AT89S52 spécifie les deux, et la seconde est bien plus restrictive :
| Limite | Valeur |
|---|---|
| Courant puisé maximal par broche | 10 mA |
| Total maximal pour tout le port 1, 2 ou 3 | 15 mA |
| Total maximal pour tout le port 0 | 26 mA |
| Total maximal sur toute la puce | 71 mA |
Relisez cette ligne du milieu. Une seule broche peut puiser 10 mA, mais tout le port 1 ne peut puiser que 15 mA entre ses huit broches. L’exercice classique de câbler huit LED à un port et d’exécuter un chenillard convient — une LED à la fois. Allumez les huit à 10 mA chacune et vous demandez 80 mA à un port calibré pour 15.
Les pièces hors spéc n’explosent généralement pas ; elles s’affaissent. Vos niveaux logiques dérivent, la puce chauffe, et le comportement devient intermittent de façons qui ressemblent à des bogues logiciels. Pour huit LED brillantes et simultanées, le correctif est un pilote : un réseau Darlington ULN2803 puise un demi-ampère par canal, et le 8051 se contente de commander.
À la limite propre du port, huit LED simultanées reçoivent environ 1,9 mA chacune. Une LED moderne à haut rendement est parfaitement visible à cela, donc un chenillard ou un bargraphe convient — faites juste l’arithmétique avant de supposer la brillance.
Lire une entrée : écrire 1 d’abord
Comme le même transistor sert les deux sens, une broche 8051 ne peut être lue en entrée que si son verrou contient un 1. Avec un 0 verrouillé, le transistor bloque la broche à la masse et chaque lecture rend 0 quoi que soit connecté.
sbit BUTTON = P1^1;
void main(void) {
BUTTON = 1; // release the pin — REQUIRED before reading
while (1) {
if (BUTTON == 0) { // switch wired to ground: pressed reads 0
// handle press
}
}
}
Sauter cette première ligne est le bogue d’entrée 8051 le plus courant. Ce n’est pas une erreur possible sur une puce à registre de direction, d’où elle piège les arrivants d’AVR ou PIC.
Les interrupteurs se câblent vers la masse, pas vers l’alimentation, pour la même raison que les LED étaient inversées : le faible rappel est l’état de repos, et le travail de l’interrupteur est de le dominer en court-circuitant la broche vers le bas.
Le port 0 est l’exception
Le port 0 n’a aucun rappel interne. Il est à drain ouvert, car il double le bus multiplexé d’adresse et données pour la mémoire externe. Utilisé en E/S généralistes, il peut tirer une broche vers le bas et sinon seulement flotter.
Corrigez avec un rappel externe sur chaque broche P0 utilisée — 10 kΩ vers +5 V, ou un réseau de résistances pour les huit. Sans eux, les sorties P0 n’atteignent jamais le haut et les entrées P0 lisent du bruit. Les ports 1, 2 et 3 n’ont besoin de rien.
Anti-rebond, car un interrupteur n’est pas un interrupteur
Un contact mécanique rebondit quelques millisecondes, et une boucle de scrutation 8051 est assez rapide pour voir chaque rebond comme un appui séparé. Le correctif bon marché est de confirmer la lecture après un délai :
sbit BUTTON = P1^1;
bit pressed(void) {
if (BUTTON != 0) return 0; // not pressed
delay_ms(20); // let the contact settle
return (BUTTON == 0); // still down? real press
}
Vingt millisecondes survivent largement au rebond d’un bouton tactile et restent loin du perceptible humain. Un délai bloquant convient en apprentissage ; une fois une interruption de minuterie en route, échantillonnez l’interrupteur depuis elle pour que le délai cesse de tout caler.
Quand ça tourne mal
- La LED luit très faiblement. Elle est câblée façon Arduino, de broche à masse. Retournez-la : anode vers +5 V via la résistance, cathode vers la broche, et pilotez la broche basse.
- Une entrée lit toujours 0. Le verrou de la broche tient 0. Écrivez-y 1 avant de lire.
- Le port 0 ne fait rien. Pas de rappels externes. Ajoutez 10 kΩ vers +5 V sur chaque broche P0 utilisée.
- Un appui s’enregistre triple. Rebond de contact. Confirmez la lecture après ~20 ms.
- Tout marche jusqu’à plusieurs sorties actives à la fois. Vous dépassez le budget 15 mA du port. Déplacez la charge vers un ULN2803 ou réduisez le courant par LED.
- Les broches se comportent bizarrement seulement quand le port série tourne. Vous utilisez P3.0 ou P3.1, qui sont RXD et TXD. Les fonctions alternées du port 3 priment sur vos projets pour elles.
Explorer le graphe
Fait partie de ces réalisations
Les projets et parcours d'apprentissage qui incluent ce tutoriel.
Pour aller plus loin