Rétro-ingénierie de MCU

Déverrouillage de microcontrôleur - MikaTech

Nos valeurs et objectifs

À propos de MikaTech

Le temps a passé vite, depuis le jour où nous avons réalisé notre premier projet de rétro-ingénierie sur MCU 8051 en 1998, jusqu'à la mise en place de notre laboratoire de rétro-ingénierie d'un million de dollars en 2012, 14 années se sont écoulées. Aujourd'hui, nous lançons notre nouvelle activité de développement de systèmes visuels embarqués, avec l'espoir de servir encore 10 ans.

signature Peter Lee Co-fondateur et PDG

Architecture et programmation des MCU 8051 pour le rétro-ingénierie 3

Chapitre 5 : Le langage d'assemblage

Introduction

Les ingénieurs spécialisés en matériel ont dû faire des compromis pour rester compétitifs dans le développement embarqué. Contrairement aux circuits électroniques ordinaires qui ne nécessitent que le câblage et l'alimentation pour fonctionner, les microcontrôleurs exigent en plus une programmation personnalisée pour exécuter des tâches définies. Heureusement, les architectures des microcontrôleurs n'ont pas évolué au point de nécessiter des langages de haut niveau variés ; presque toutes les familles de microcontrôleurs ne comprennent nativement que le langage machine. Cette standardisation apporte des avantages majeurs. L'inconvénient est que le langage machine, composé uniquement de 0 et de 1 binaires, est inintelligible pour les développeurs humains et ne peut être déchiffré que par des experts en conception matérielle. Pour combler le fossé de communication entre le matériel du microcontrôleur et les programmeurs humains, le langage d'assemblage — le premier langage de programmation bas niveau lisible par l'homme — a été créé.

L'assemblage a résolu le problème de la mémorisation des opcodes binaires bruts pour les instructions matérielles, mais il a introduit une nouvelle barrière qui a compliqué le travail des développeurs et du matériel des microcontrôleurs. Ce nouvel obstacle a été résolu à l'aide de deux outils clés : un logiciel assembleur basé sur PC et un dispositif de programmation matériel dédié appelé programmateur de puces.

Le logiciel assembleur accepte les mnémoniques d'assemblage lisibles par l'homme et les traduit de manière fiable en un fichier binaire exécutable. L'étape de compilation qui convertit le code source assembleur en code machine est critique, car le fichier HEX résultant est un flux de valeurs binaires que seul le matériel du microcontrôleur peut interpréter. Le code source assembleur brut ne peut pas s'exécuter directement sur un microcontrôleur à moins que ce fichier HEX compilé ne soit programmé dans la mémoire programme du dispositif. C'est là qu'intervient le dernier composant du flux de développement, le programmateur de puces. Il s'agit d'un dispositif matériel compact qui se connecte à un PC via un port de communication standard et qui dispose d'un support pour monter la puce du microcontrôleur cible afin de programmer le firmware.

5.1 Éléments du langage d'assemblage

Le langage d'assemblage suit des règles structurelles similaires aux langues naturelles, avec des mots réservés, des règles de formatage strictes et une syntaxe standardisée. Les quatre blocs de base fondamentaux du code source assembleur sont listés ci-dessous :

  • Étiquettes (labels)
  • Mnémoniques d'instructions
  • Directives de l'assembleur
  • Lignes de commentaires
Éléments de l'assembleur

Syntaxe du langage d'assemblage

Des règles de formatage strictes (collectivement appelées syntaxe) doivent être respectées lors de l'écriture du code source assembleur pour garantir une compilation sans erreur en code machine HEX exécutable. Les règles de syntaxe obligatoires se limitent aux exigences suivantes :

  • Une seule ligne de code source assembleur peut contenir un maximum de 255 caractères ASCII ;
  • Chaque ligne compilable doit commencer par une étiquette, un mnémonique d'instruction ou une directive d'assembleur ;
  • Tout texte apparaissant après un point-virgule ";" sur une ligne est traité comme un commentaire lisible par l'homme et est complètement ignoré par l'assembleur lors de la compilation ;
  • Tous les composants distincts sur une même ligne (étiquettes, instructions, opérandes, directives) doivent être séparés par au moins un espace. La touche TAB du clavier est largement utilisée à la place des espaces simples pour aligner proprement les étiquettes, les mnémoniques et les directives en colonnes verticales cohérentes afin d'améliorer la lisibilité du code.

Constantes numériques

À l'exception du système octal obsolète, le langage d'assemblage prend en charge les valeurs numériques écrites dans trois formats de base distincts :

Nombres décimaux

Si aucun suffixe de base n'est spécifié, l'assembleur interprète toutes les constantes numériques comme des valeurs décimales. La notation décimale utilise les chiffres 0 à 9. Étant donné que le stockage du microcontrôleur alloue un maximum de deux octets pour le stockage numérique général, la plus grande valeur décimale représentable dans le code assembleur est 65535. La lettre "D" peut être ajoutée pour marquer explicitement une valeur comme décimale, par exemple : 1234D.

Nombres hexadécimaux

La notation hexadécimale est le format le plus couramment utilisé pour la programmation embarquée. Le système hexadécimal utilise seize symboles uniques : les chiffres 0 à 9 et les lettres A à F. La valeur hexadécimale maximale sur deux octets est FFFF, ce qui équivaut à la valeur décimale 65535. Pour différencier les constantes hexadécimales des valeurs décimales, la lettre "h" (minuscule ou majuscule) est ajoutée au nombre, comme 54h.

Nombres binaires

Les constantes binaires sont fréquemment utilisées lorsque les états de bits individuels des registres du CPU doivent être définis explicitement, car chaque chiffre binaire correspond directement à une position de bit matérielle. La notation binaire n'utilise que les chiffres 0 et 1. La constante binaire maximale sur deux octets est 1111111111111111. La lettre "b" (minuscule ou majuscule) est ajoutée pour distinguer les valeurs binaires des autres formats numériques, par exemple : 01100101B.

Opérateurs

De nombreuses directives conditionnelles de l'assembleur et opérandes d'instructions acceptent des expressions mathématiques et logiques au lieu de valeurs statiques fixes. Un exemple de bloc conditionnel est présenté ci-dessous :

IF (VERSION>1)
   LCALL Table_2
   USING VERSION+1
ENDIF
   ...

L'assembleur peut évaluer des expressions mathématiques et logiques constantes lors de la compilation et intégrer les valeurs calculées résultantes dans le code machine final. L'ensemble complet des opérateurs pris en charge est listé dans le tableau ci-dessous :

Symbole Opération Exemple Résultat
+ Addition 10+5 15
- Soustraction 25-17 8
* Multiplication 7*4 28
/ Division entière (troncature) 7/4 1
MOD Modulo (reste de division) 7 MOD 4 3
SHR Décalage à droite bit à bit 1000B SHR 2 0010B
SHL Décalage à gauche bit à bit 1010B SHL 2 101000B
NOT NON logique bit à bit (complément à 1) NOT 1 1111111111111110B
AND ET logique bit à bit 1101B AND 0101B 0101B
OR OU logique bit à bit 1101B OR 0101B 1101B
XOR OU exclusif bit à bit 1101B XOR 0101B 1000B
LOW Extraire les 8 bits de poids faible d'une valeur 16 bits LOW(0AADDH) 0DDH
HIGH Extraire les 8 bits de poids fort d'une valeur 16 bits HIGH(0AADDH) 0AAH
EQ, = Comparaison d'égalité 7 EQ 4 ou 7=4 0 (Faux)
NE,<> Comparaison d'inégalité 7 NE 4 ou 7<>4 0FFFFH (Vrai)
GT, > Supérieur à 7 GT 4 ou 7>4 0FFFFH (Vrai)
GE, >= Supérieur ou égal 7 GE 4 ou 7>=4 0FFFFH (Vrai)
LT, < Inférieur à 7 LT 4 ou 7<4 0 (Faux)
LE,<= Inférieur ou égal 7 LE 4 ou 7<=4 0 (Faux)

Symboles définis par l'utilisateur

Des noms symboliques personnalisés peuvent être attribués aux registres du CPU, aux valeurs constantes, aux adresses mémoire et aux points d'entrée de sous-routines dans le code assembleur, améliorant considérablement la lisibilité et la maintenabilité du code source. Par exemple, si la broche GPIO P0.3 est connectée à un bouton-poussoir qui déclenche un arrêt complet du processus (bouton STOP), la logique du code devient beaucoup plus intuitive si l'adresse bit P0.3 est aliasée par le symbole descriptif "pushbutton_STOP". Comme dans d'autres langages de programmation, des règles de dénomination strictes régissent les symboles personnalisés valides :

  • Les caractères valides pour les symboles incluent les lettres latines majuscules et minuscules (A-Z, a-z), les chiffres décimaux (0-9) et deux symboles spéciaux : le trait de soulignement "_" et le point d'interrogation "?". Le langage d'assemblage est insensible à la casse pour les noms de symboles.

Les deux symboles ci-dessous sont traités comme identiques par l'assembleur :

Serial_Port_Buffer
SERIAL_PORT_BUFFER
  • Pour éviter toute ambiguïté avec les constantes numériques, chaque symbole valide doit commencer par une lettre alphabétique, un trait de soulignement ou un point d'interrogation ; les chiffres ne peuvent pas être utilisés comme premier caractère.
  • Un nom de symbole peut contenir jusqu'à 255 caractères, mais l'assembleur n'évalue que les 32 premiers caractères pour distinguer les identifiants uniques. L'exemple ci-dessous illustre ce comportement : les deux premiers symboles sont signalés comme des définitions en double (erreur de compilation), tandis que les troisième et quatrième sont reconnus comme des identifiants distincts :
START_ADDRESS_OF_TABLE_AND_CONSTANTS_1
START_ADDRESS_OF_TABLE_AND_CONSTANTS_2
TABLE_OF_CONSTANTS_1_START_ADDRESS
TABLE_OF_CONSTANTC_2_START_ADDRESS
  • Certains mots-clés réservés ne peuvent pas être utilisés comme noms de symboles personnalisés, car ce sont des mnémoniques d'instructions prédéfinis, des directives d'assembleur ou des identifiants de registres matériels intégrés. Par exemple, un utilisateur ne peut pas définir un symbole nommé "A" ou "DPTR", car ces noms correspondent à des registres CPU natifs.

La liste complète des mots-clés réservés interdits comme symboles personnalisés est fournie dans le tableau ci-dessous :

A AB ACALL ADD
ADDC AJMP AND ANL
AR0 AR1 AR2 AR3
AR4 AR5 AR6 AR7
BIT BSEG C CALL
CJNE CLR CODE CPL
CSEG DA DATA DB
DBIT DEC DIV DJNZ
DPTR DS DSEG DW
END EQ EQU GE
GT HIGH IDATA INC
ISEG JB JBC JC
JMP JNB JNC JNZ
JZ LCALL LE LJMP
LOW LT MOD MOV
MOVC MOVX MUL NE
NOP NOT OR ORG
ORL PC POP PUSH
R0 R1 R2 R3
R4 R5 R6 R7
RET RETI RL RLC
RR RRC SET SETB
SHL SHR SJMP SUBB
SWAP USING XCH XCHD
XDATA XOR XRL XSEG

Étiquettes (Labels)

Une étiquette est un type spécialisé de symbole qui représente un alias lisible pour une adresse mémoire physique dans la ROM programme ou la RAM de données. Les étiquettes sont toujours placées au tout début d'une ligne de code source. Les instructions de saut, de branchement et d'appel de sous-routine seraient extrêmement fastidieuses à écrire et à maintenir sans les étiquettes. Le flux de travail standard pour l'utilisation des étiquettes est simple :

  • Attribuer un nom d'étiquette descriptif à la première ligne d'une sous-routine ou à la destination cible d'une instruction de saut ;
  • Référencer le nom de l'étiquette directement dans les instructions de saut et d'appel de sous-routine au lieu de saisir manuellement des adresses mémoire numériques brutes sur 16 bits.

Lors de la compilation, l'assembleur résout automatiquement chaque étiquette en son adresse mémoire absolue correspondante et substitue la valeur numérique dans le code machine compilé.

Directives de l'assembleur

Contrairement aux mnémoniques d'instructions CPU qui sont compilés en code machine exécutable stocké dans la mémoire programme du microcontrôleur, les directives de l'assembleur sont des commandes natives interprétées uniquement par le logiciel assembleur et n'ont aucun impact sur le comportement à l'exécution du matériel du microcontrôleur. Certaines directives sont obligatoires pour tout projet d'assemblage valide, tandis que d'autres existent uniquement pour simplifier les flux de travail de développement ou accélérer les processus de compilation.
Les directives occupent la même colonne verticale réservée aux mnémoniques d'instructions dans le code source, et une seule ligne source ne peut contenir qu'une seule directive d'assembleur.

Directive EQU

La directive EQU lie une valeur numérique constante fixe à un nom de symbole personnalisé pour une réutilisation dans tout le fichier source. Exemple d'utilisation :

MAXIMUM EQU 99

Après cette définition, chaque occurrence du symbole "MAXIMUM" dans le code source sera remplacée par la valeur littérale 99 lors de la compilation. Chaque symbole ne peut être défini qu'une seule fois avec EQU, c'est pourquoi les déclarations EQU sont presque toujours placées en haut du fichier assembleur pour la configuration des constantes globales.

Directive SET

La directive SET associe également une valeur numérique à un alias symbolique. Sa principale différence avec EQU est que SET permet de redéfinir plusieurs fois le même symbole tout au long du fichier source :

SPEED SET 45
SPEED SET 46
SPEED SET 57

Directive BIT

La directive BIT attribue un nom de symbole personnalisé à un emplacement mémoire adressable par bit spécifique, l'adresse du bit cible devant être comprise entre 0 et 255. Exemples de définitions :

TRANSMIT BIT PSW.7 ;Alias "TRANSMIT" pour le bit 7 du registre d'état PSW
OUTPUT BIT 6 ;Alias "OUTPUT" pour l'adresse bit 06h
RELAY BIT 81 ;Alias "RELAY" pour l'adresse bit 81h (correspond à la broche 1 du port 0)

Directive CODE

La directive CODE lie un symbole personnalisé à une adresse mémoire programme fixe. Étant donné que l'espace d'adressage maximal de la mémoire programme 8051 standard est de 64 Ko, les adresses valides vont de 0 à 65535. Exemple :

RESET CODE 0 ;Alias "RESET" pour l'emplacement mémoire programme 00h
TABLE CODE 1024 ;Alias "TABLE" pour l'adresse mémoire programme 1024 décimal (0400h)

Directive DATA

La directive DATA attache un alias symbolique à une adresse dans la RAM interne directement accessible du microcontrôleur, avec des valeurs d'adresse valides de 0 à 255. Elle peut réaffecter des noms lisibles à n'importe quel SFR standard ou registre RAM général :

TEMP12 DATA 32 ;Nommer l'adresse RAM 32 comme "TEMP12"
STATUS_R DATA 0D0h ;Renommer le SFR PSW en "STATUS_R"

Directive IDATA

La directive IDATA crée des alias symboliques pour des emplacements RAM accessibles via adressage indirect par les registres pointeurs R0 ou R1 :

TEMP22 IDATA 32 ;Alias pour l'emplacement RAM pointé par le registre à l'adresse 32 comme "TEMP22"
TEMP33 IDATA T_ADR ;Alias pour l'emplacement RAM pointé par le registre T_ADR comme "TEMP33"

Directive XDATA

La directive XDATA attribue des noms symboliques à des emplacements mémoire dans la RAM de données externe, qui prend en charge l'adressage 16 bits complet jusqu'à 65535. Exemple :

TABLE_1 XDATA 2048 ;Alias pour l'adresse RAM externe 2048 décimal comme "TABLE_1"

Directive ORG

La directive ORG définit le décalage mémoire de départ pour tout le code compilé ultérieur ou les définitions de données dans le segment actif. Exemple :

BEGINNING ORG 100
          ...
          ...
          ORG 1000h
TABLE     ...
          ...

Cet extrait de code place le programme principal à partir du décalage mémoire 100 décimal, tandis que le bloc de données de la table de correspondance est ancré à l'adresse 1000 hexadécimale.

Directive USING

La directive USING sélectionne laquelle des quatre banques de registres généraux du CPU (R0–R7) sera utilisée pour la logique de code ultérieure :

USING 0 ;Sélectionner la banque de registres 0 (R0-R7 mappés aux adresses RAM 0–7)
USING 1 ;Sélectionner la banque de registres 1 (R0-R7 mappés aux adresses RAM 8–15)
USING 2 ;Sélectionner la banque de registres 2 (R0-R7 mappés aux adresses RAM 16–23)
USING 3 ;Sélectionner la banque de registres 3 (R0-R7 mappés aux adresses RAM 24–31)

Directive END

La directive END marque la terminaison absolue du fichier source assembleur. L'assembleur arrête tout traitement de compilation dès qu'il rencontre ce jeton. Exemple :

...
END ;Marque la fin de l'ensemble du programme source assembleur

Directives de sélection de segment

Cinq directives dédiées contrôlent la sélection entre les cinq types de segments mémoire distincts disponibles sur les microcontrôleurs 8051 standard :

CSEG ;Active le segment de mémoire programme pour les instructions exécutables
BSEG ;Active le segment de RAM interne adressable par bit
DSEG ;Active le segment de RAM interne général à adressage direct
ISEG ;Active le segment de RAM interne à adressage indirect (accessible via R0/R1)
XSEG ;Active le segment de RAM de données externe

Le segment de code CSEG est activé par défaut lorsque l'assembleur s'initialise et reste actif jusqu'à ce qu'une directive de segment alternative soit déclarée. Chaque segment mémoire maintient son propre compteur d'adresses indépendant, qui se réinitialise à zéro chaque fois que l'assembleur redémarre la compilation. Le décalage de départ du compteur d'adresses d'un segment peut être défini manuellement en ajoutant un spécificateur AT suivi d'une valeur numérique, d'une expression arithmétique ou d'un symbole prédéfini. Exemple :

DSEG       ;Basculer vers le segment RAM interne à adressage direct
BSEG AT 32 ;Sélectionner la RAM adressable par bit avec un compteur de segment commençant au bit 32

Le symbole dollar "$" représente la valeur actuelle du compteur d'adresses pour le segment actif. Deux exemples d'utilisation pratique sont fournis ci-dessous :

Exemple 1 :

JNB FLAG,$ ;Boucle infinie qui répète cette instruction de saut jusqu'à ce que le bit FLAG soit effacé

Exemple 2 :

MESSAGE DB 'ALARM turn off engine'
LENGTH EQU $-MESSAGE-1

Ces deux lignes calculent le nombre exact de caractères de la chaîne ASCII "ALARM turn off engine" stockée à l'adresse étiquetée MESSAGE.

Directive DS

La directive DS réserve un bloc contigu d'octets de mémoire dans le segment de données DSEG, ISEG ou XSEG actif. Deux exemples d'utilisation sont présentés ci-dessous :

Exemple 1 :

DSEG     ;Sélectionner le segment RAM à accès direct
DS 32         ;Avancer le compteur d'adresses du segment de 32 octets
SP_BUFF DS 16 ;Réserver un bloc contigu de 16 octets pour le tampon de réception du port série
IO_BUFF DS 8  ;Réserver un bloc contigu de 8 octets pour le tampon de données E/S générales

Exemple 2 :

ORG 100       ;Définir le décalage d'adresse de départ à 100 décimal
DS 8          ;Réserver 8 octets vides consécutifs
LAB ......... ;La logique du programme commence à l'adresse mémoire 108

Directive DBIT

La directive DBIT alloue un bloc de stockage de bits contigu dans le segment BSEG de RAM adressable par bit actif, la taille de l'allocation étant spécifiée en nombre de bits :

BSEG ;Activer le segment de RAM adressable par bit
IO_MAP DBIT 32 ;Réserver les 32 premières positions de bit pour les indicateurs d'état E/S

Directive DB

La directive DB stocke des valeurs d'octets statiques ou des chaînes de caractères ASCII directement dans le segment de mémoire programme CSEG actif. Plusieurs constantes numériques sont séparées par des virgules, et les chaînes de texte ASCII doivent être placées entre guillemets simples. Cette directive ne peut être utilisée que lorsque le segment CSEG est actif :

CSEG
DB 22,33,'Alarm',44

Si une étiquette précède une instruction DB, l'adresse de l'étiquette pointera vers le premier élément de données défini (la valeur 22 dans cet exemple).

Directive DW

La directive DW fonctionne de manière similaire à DB, mais elle stocke des mots complets de 16 bits (deux octets) dans la mémoire programme. L'octet de poids fort de chaque valeur est écrit en premier, suivi de l'octet de poids faible.

Directives conditionnelles IF, ELSE, ENDIF

Ces trois directives créent des blocs de compilation conditionnelle dans le code source assembleur. Chaque bloc conditionnel s'ouvre par une instruction IF et se termine par ENDIF, avec une logique ELSE facultative séparant les chemins de code mutuellement exclusifs. L'expression mathématique/logique entre parenthèses après IF détermine quelles sections du code source sont compilées dans le binaire final :

  • Si l'expression conditionnelle est vraie (valeur non nulle), toutes les lignes source entre IF et la prochaine directive ELSE ou ENDIF sont compilées en code machine ;
  • Si l'expression conditionnelle est fausse (valeur nulle), toutes les lignes entre IF et ELSE sont ignorées lors de la compilation, et l'assemblage reprend le traitement des lignes après ELSE ou ENDIF.

Exemple 1 :

IF (VERSION>3)
   LCALL Table_2
   LCALL Addition
ENDIF
   ...

Si la valeur constante VERSION est supérieure à 3 (condition vraie), les deux appels de sous-routine à Table_2 et Addition sont compilés dans l'image firmware finale. Si VERSION est inférieur ou égal à 3 (condition fausse), ces deux instructions sont entièrement ignorées lors de la compilation.

Exemple 2 :

Si le symbole Model est égal à 1, les deux instructions suivant immédiatement IF sont compilées, et tout le code entre ELSE et ENDIF est ignoré. Si Model est égal à 0, les instructions du bloc IF sont ignorées et seul le code sous ELSE est assemblé en code machine.

IF (Model)
   MOV R0,#BUFFER
   MOV A,@R0
ELSE
   MOV R0,#EXT_BUFFER
   MOVX A,@R0
ENDIF
   ...

Directives de contrôle de l'assembleur

Les directives de contrôle commencent par un signe dollar "$". Elles configurent le comportement de l'assembleur lors de la compilation, y compris l'inclusion de fichiers source externes, les chemins de destination du fichier HEX de sortie et les règles de formatage du fichier de liste de compilation lisible par l'homme. Il existe de nombreuses directives de contrôle, mais seules les plus couramment utilisées sont présentées ci-dessous :

Directive $INCLUDE

Cette directive ordonne à l'assembleur de charger et d'analyser un fichier source assembleur externe pendant le processus de compilation :

$INCLUDE(TABLE.ASM)

Directive $MOD8253

La directive $MOD8253 référence un fichier d'en-tête prédéfini contenant tous les noms de registres de fonctions spéciales (SFR) et leurs adresses mémoire correspondantes pour la variante de microcontrôleur 8253. Avec cette directive activée, les développeurs peuvent référencer les registres par leurs noms lisibles plutôt que par des adresses numériques brutes. Si cette directive est omise, chaque SFR utilisé dans le projet doit être déclaré manuellement avec son adresse mémoire exacte en début de fichier source.

 

Chapitre 6 : Exemples pratiques

Vue d'ensemble

Ce chapitre livre les connaissances fondamentales du matériel des microcontrôleurs nécessaires à une mise en œuvre pratique. Les lecteurs ne trouveront pas ici de logique de programme trop complexe ni de schémas de circuits avancés avec des conceptions optimisées de pointe. Au lieu de cela, les exemples pratiques suivants démontrent que la programmation embarquée n'est ni un privilège ni une compétence dépendante du talent — c'est simplement le processus d'assemblage d'une logique fonctionnelle modulaire via une syntaxe d'instructions standardisée. Rassurez-vous, la conception et le développement itératif du matériel s'articulent autour d'un flux de travail cohérent : « tester, ajuster, itérer ». Naturellement, la complexité des projets augmente avec l'expérience ; la même logique de composants modulaires s'applique aussi bien aux prototypes de bricoleurs qu'aux architectures professionnelles de qualité industrielle...

Bien que ces démonstrations introductives se concentrent purement sur le fonctionnement fonctionnel de base, chaque plateforme matérielle embarquée comporte un niveau de risque de sécurité sous-jacent souvent sous-estimé et rarement abordé dans les tutoriels pour débutants. Le microcontrôleur central (MCU) exécutant ces routines de contrôle simples peut ensuite être intégré dans des produits commerciaux finis, où la protection du code source exécutable contre tout accès non autorisé devient une priorité de conception essentielle. De nombreux ingénieurs novices croient à tort que le mécanisme de fusible de verrouillage intégré peut bloquer complètement tout accès en lecture externe à la mémoire flash interne, mais cette hypothèse n'est pas universellement fiable. Dans des scénarios de menace réels, des acteurs malveillants peuvent utiliser des workflows de décapage de puces pour exposer les couches de silicium nues et effectuer une micro-sondage direct des fusibles matériels contrôlant la sécurité. Une fois le boîtier retiré, les adversaires peuvent extraire un vidage complet de toutes les zones de stockage du programme, réalisant ainsi une extraction complète du firmware sans identifiants d'authentification valides. Le jeu de puces EEPROM embarqué, qui stocke couramment les paramètres d'étalonnage d'usine et les clés cryptographiques, est exposé à des vulnérabilités identiques face à ces intrusions matérielles physiques. Certains attaquants utilisent des équipements de laboratoire à faisceau d'ions focalisé (FIB) pour modifier sélectivement des circuits de fusibles individuels et forcer un déverrouillage permanent des zones mémoire marquées comme protégées. D'autres attaquants exploitent des méthodologies d'analyse par canaux auxiliaires pour lire progressivement les binaires complets du programme sans déclencher de circuits de détection d'effraction matérielle. Dans le pire des cas d'exploitation, un vidage complet des partitions flash et EEPROM permet aux attaquants de fabriquer des répliques matérielles identiques, produisant des clones de dispositifs entièrement fonctionnels qui érodent complètement la valeur de la propriété intellectuelle. Pour cette raison, même lors de l'apprentissage de la logique d'entrée/sortie numérique de base et des sous-routines de contrôle de temporisation, les développeurs doivent reconnaître que les mêmes broches et registres peuvent être exploités lors de campagnes de rétro-ingénierie malveillantes. La récupération d'un dispositif embarqué brické non fonctionnel nécessite parfois de contourner les protections de verrouillage de sécurité via une injection de glitch de tension — une technique de réparation matérielle légitime qui crée simultanément un point d'entrée d'attaque viable. La maîtrise de la logique de fonctionnement sous-jacente du verrouillage est une compétence obligatoire pour les développeurs de firmware embarqué et les analystes de sécurité matérielle dédiés. Un grand nombre de dispositifs embarqués commerciaux ont subi des violations complètes de propriété intellectuelle en raison de fusibles de sécurité mal configurés, laissant le code exécutable entièrement exposé à une récupération externe. Une simple lecture des octets de configuration de la mémoire de la puce peut exposer tous les paramètres de la politique de sécurité, guidant les acteurs malveillants directement vers le vecteur d'exploitation le plus faible. Même la simple démonstration du temporisateur de surveillance (watchdog) présentée plus tard peut être réutilisée pour implémenter une logique de détection d'effraction matérielle. Dans la pratique de l'ingénierie, les concepteurs doivent trouver un équilibre entre la fonctionnalité matérielle et les protections anti-intrusion, en s'assurant que l'extraction non autorisée du firmware reste techniquement et financièrement irréalisable. Les démos pratiques qui suivent illustrent des flux de travail de base sur le matériel, mais elles montrent implicitement comment les périphériques centraux du MCU, y compris les temporisateurs, les contrôleurs d'interruptions et les interfaces de communication série, peuvent être réutilisés pour implémenter des contre-mesures de renforcement de sécurité robustes. Par exemple, l'utilisation de modules temporisateurs pour générer des décalages de temporisation aléatoires peut atténuer les attaques par canaux auxiliaires basées sur le timing ciblant le vidage de données secrètes confidentielles. De plus, la logique de transmission série UART peut être encapsulée avec des protocoles de chiffrement légers pour bloquer l'écoute brute des données lors de tentatives de lecture non autorisées. Les circuits d'affichage à LED multiplexées, bien que semblant triviaux, construisent une conscience critique de la sensibilité temporelle — une compétence fondamentale requise pour implémenter des séquences de démarrage sécurisées authentifiées. L'exemple de stockage de données EEPROM aborde directement les workflows de récupération de données persistantes, un concept technique qui s'étend à la conservation sécurisée à long terme des clés cryptographiques. En fin de compte, chaque ligne de code firmware embarqué doit être écrite en partant du principe que des acteurs hostiles pourraient éventuellement obtenir un accès physique complet au matériel cible. Le mécanisme de fusible de verrouillage de sécurité ne sert que de barrière défensive primaire ; une protection matérielle complète repose sur des mesures de sécurité multicouches qui rendent le décapage de puces et la sonde du silicium économiquement irréalisables pour les attaquants. Ce chapitre établit une sensibilisation de base à la sécurité bien qu'il n'approfondisse pas les tactiques spécialisées d'exploitation par rétro-ingénierie. Avec ce double objectif de fonctionnement fonctionnel et de sécurité embarquée, nous passons à l'examen des schémas de câblage fondamentaux du microcontrôleur et des composants périphériques de support.

6.1 Câblage matériel de base

Schéma de câblage de base - Circuit d'alimentation

Comme le montre le schéma ci-dessus, trois domaines de signal obligatoires doivent être câblés correctement pour garantir un fonctionnement stable du microcontrôleur :

  • Alimentation régulée ;
  • Signal de réinitialisation matérielle ; et
  • Signal d'horloge de référence externe.

Ce sont des topologies de circuits extrêmement minimales, mais la complexité matérielle augmente considérablement pour les équipements chargés de réguler des machines industrielles coûteuses ou de soutenir des flux de travail critiques pour la sécurité. Néanmoins, ce schéma simplifié suffit pour des besoins d'apprentissage introductifs...

Circuit d'alimentation régulée

Bien que ce microcontrôleur supporte plusieurs niveaux de tension d'alimentation, il n'y a aucune raison pratique d'introduire des risques de défauts inutiles en testant des conditions de tension marginales. Une alimentation 5V DC reste la norme industrielle la plus largement adoptée. Le schéma présenté implémente le régulateur linéaire positif à trois bornes LM7805, peu coûteux, délivrant une tension de sortie stable et une capacité de courant de crête suffisante (1A) pour alimenter le cœur du microcontrôleur ainsi que tous les périphériques auxiliaires connectés.

Circuit de réinitialisation matérielle

Pour une initialisation fiable du microcontrôleur, un signal bas (0V) doit être appliqué sur la broche RS de réinitialisation. Le bouton-poussoir reliant la broche RS à l'alimentation VCC n'est pas strictement obligatoire, mais il est inclus sur presque toutes les cartes de prototypage. Ce bouton permet une réinitialisation forcée contrôlée si l'exécution du firmware entre dans un état de défaut instable. Amener la broche RS à un niveau haut (5V) déclenche une réinitialisation complète de la puce, redémarrant l'exécution du programme à partir de l'adresse de vecteur de démarrage du firmware.

Circuit oscillateur

Bien que le microcontrôleur intègre un oscillateur RC interne, un fonctionnement stable et déterministe nécessite un cristal de quartz externe associé à deux condensateurs de charge pour fixer la fréquence d'horloge de fonctionnement, qui définit directement le débit d'exécution des instructions de la puce.

Schéma du circuit oscillateur

Naturellement, cette topologie à cristal n'est pas universellement applicable et il existe plusieurs solutions alternatives de génération d'horloge. Une configuration alternative consiste à fournir un signal d'horloge de référence à partir d'un module oscillateur externe dédié, acheminé via un buffer inverseur, comme illustré dans le schéma de gauche.

6.2 Composants périphériques auxiliaires

Malgré le fait qu'il représente un matériel informatique compact de pointe, un microcontrôleur autonome ne sert à aucune fonction pratique sans périphériques auxiliaires interfacés. En termes simples, les changements de niveau de tension sur les broches d'entrée/sortie de la puce n'ont aucune signification fonctionnelle à moins d'être utilisés pour piloter des opérations définies : commutation de charges, décalage de données, rendu d'affichage visuel, etc.

Interrupteurs et boutons-poussoirs tactiles

Aucun composant périphérique n'est plus simple que les interrupteurs mécaniques et les boutons-poussoirs momentanés ; ils constituent la méthode la plus directe pour détecter les transitions d'état de tension sur les broches d'entrée du microcontrôleur.

Interrupteurs mécaniques et boutons-poussoirs

La mise en œuvre réelle introduit une complexité imprévue due au rebond des contacts mécaniques, un défaut généralisé inhérent à tout matériel de commutation mécanique. Lorsque les surfaces de contact métalliques entrent en collision, l'élan physique et l'élasticité du matériau génèrent des impulsions électriques rapides et répétées au lieu d'une transition de tension unique entre 0V et la pleine alimentation. Ce comportement oscillatoire provient de petites imperfections de surface, de l'accumulation de poussière et des vibrations mécaniques. La durée du rebond — mesurée en microsecondes ou millisecondes — passe inaperçue pour la perception humaine mais est enregistrée de manière fiable comme de multiples événements d'entrée discrets par la logique numérique à grande vitesse du microcontrôleur. Si un signal de bouton brut alimente directement une routine de comptage d'impulsions, des taux d'erreur de comptage proches de 100 % se produiront sans conditionnement du signal.

Filtre anti-rebond RC

La stratégie d'atténuation la plus économique pour le rebond des contacts est un filtre passe-bas RC passif qui supprime les transitoires de tension rapides. Étant donné que les caractéristiques de rebond varient selon les modèles d'interrupteurs, les valeurs des résistances et des condensateurs ne sont pas strictement normalisées, mais les valeurs illustrées dans le diagramme offrent des performances cohérentes pour la plupart des cas d'usage courants.

Les applications nécessitant une stabilité absolue du signal d'entrée exigent des contre-mesures matérielles plus robustes. Un circuit bascule RS modifie l'état logique de sortie une seule fois lors de la transition de contact initiale, ignorant complètement les impulsions de rebond ultérieures. Bien que cette solution matérielle nécessite un composant d'interrupteur SPDT plus coûteux, elle élimine complètement les artéfacts de rebond et permet de détecter des impulsions d'entrée extrêmement courtes que les filtres RC passifs masqueraient, car aucun condensateur de stockage de charge n'est utilisé dans le chemin du signal.

Circuit anti-rebond à bascule RS

Au-delà des topologies de filtrage matériel, il existe une implémentation logicielle légère de l'anti-rebond. Lorsque le firmware détecte une transition d'état sur une broche d'entrée, il revérifie le niveau logique de la broche après un délai fixe. Une lecture d'état cohérente confirme une action de commutation intentionnelle plutôt qu'un bruit de rebond transitoire. Cette approche logicielle n'entraîne aucun coût de composant supplémentaire, supprime les artéfacts d'interférence électromagnétique et fonctionne de manière fiable avec des contacts mécaniques usés de mauvaise qualité. Sa principale limitation, identique aux filtres RC, est que les impulsions d'entrée plus courtes que le délai programmé ne peuvent pas être capturées par la logique du firmware.

Modules optocoupleurs d'isolement

Circuits d'isolement par optocoupleur

Les optocoupleurs sont des composants d'isolement standard de l'industrie utilisés pour isoler galvaniquement les circuits du microcontrôleur des environnements électriques externes dangereux à haute intensité ou haute tension. Les boîtiers d'optocoupleurs typiques intègrent une, deux ou quatre sources lumineuses à LED côté entrée, associées à un nombre égal de dispositifs semi-conducteurs sensibles à la lumière côté sortie : phototransistors, photothyristors ou phototriacs. La fonctionnalité centrale repose sur un canal de transmission optique non conducteur pour transférer des signaux numériques entre des domaines de circuit isolés tout en maintenant une séparation électrique complète. Cette performance d'isolement n'est efficace que lorsque le côté LED d'entrée et le côté photodétecteur de sortie reçoivent des alimentations indépendantes. Cette séparation protège totalement le microcontrôleur et les périphériques de précision sensibles contre les transitoires haute tension destructeurs et les bruits électromagnétiques, deux causes principales de dommages matériels permanents et de comportement opérationnel instable dans les systèmes embarqués. Les optocoupleurs à sortie phototransistor sont la variante la plus largement déployée. Pour les optocoupleurs avec une broche de base exposée (broche 6), la base peut être laissée non connectée. Un réseau résistance-condensateur facultatif, représenté par un câblage en pointillés sur le schéma, atténue le bruit haute fréquence en filtrant les impulsions transitoires très courtes.

Relais électromécaniques

Schéma du circuit de commande de relais

Un relais constitue un interrupteur mécanique actionné électriquement, commandé par un circuit logique secondaire de faible puissance. Les relais s'interfacent avec les broches de sortie du microcontrôleur pour commuter des charges de forte puissance, notamment des moteurs DC, des transformateurs AC, des éléments chauffants, des lampes à incandescence et des réseaux d'antennes. Ces charges de forte puissance sont presque toujours physiquement séparées des composants logiques basse tension sensibles de la carte principale. Il existe plusieurs facteurs de forme de relais, mais tous fonctionnent selon des principes d'actionnement électromagnétique identiques : l'énergie d'une bobine de cuivre interne génère un champ magnétique qui bascule mécaniquement un ou plusieurs ensembles de paires de contacts conducteurs. Comme les optocoupleurs, les relais offrent un isolement galvanique complet sans chemin de conduction électrique direct entre la logique de commande d'entrée et les circuits de charge de sortie. La plupart des variantes de relais standard nécessitent une tension et un courant plus élevés pour alimenter la bobine, bien que les relais de signal miniatures puissent être pilotés directement par la capacité de courant de sortie des broches du microcontrôleur.

Le schéma illustré cible l'architecture du microcontrôleur 8051. Un transistor Darlington amplifie le courant de commande pour alimenter la bobine du relais, une solution de contournement obligatoire pour les états de sortie logique haute, où la broche du microcontrôleur fonctionne comme une entrée haute impédance avec une capacité de courant de sortie minimale, violant les directives de conception des circuits de commande standard, mais nécessaire pour les caractéristiques électriques spécifiques de cette architecture.

Schéma de câblage de base pour la commande de relais par microcontrôleur

Une diode de roue libre polarisée en inverse est câblée en parallèle avec la bobine du relais pour supprimer les transitoires de tension de retour inductifs destructeurs générés lorsque le courant de la bobine est brusquement interrompu. Cette diode d'écrêtage absorbe la pointe de tension inductive pour protéger les composants semi-conducteurs environnants contre les dommages par claquage.

Diodes électroluminescentes (LED)

Les diodes électroluminescentes servent de composants d'indicateurs visuels d'état dans les systèmes électroniques, fabriquées dans divers facteurs de forme, couleurs d'émission et tailles de boîtier. Leur coût unitaire ultra-bas, leur faible consommation et leur circuit de commande simplifié ont supplanté les lampes à incandescence classiques pour presque toutes les applications modernes. Le comportement électrique reflète celui des diodes à jonction PN standard, avec la propriété unique d'émettre de la lumière visible lorsqu'un courant direct traverse la jonction semi-conductrice.

Schéma de circuit de diode électroluminescente (LED)

La limitation du courant est une exigence de conception critique ; un courant direct non régulé dégradera et détruira définitivement la jonction de la LED. Une résistance série de limitation de courant doit être incluse dans chaque circuit de commande de LED. Le calcul de la valeur de résistance requise dépend de la chute de tension directe de la LED, un paramètre déterminé par le matériau semi-conducteur et la longueur d'onde/couleur d'émission cible. Les spécifications électriques standard pour les variantes de LED couramment déployées sont présentées dans le tableau ci-dessous. Trois classifications principales de LED existent : les LED standard atteignent une luminosité nominale à un courant direct de 20 mA ; les LED à faible courant offrent une luminosité équivalente à un dixième de ce courant ; les LED super brillantes produisent une intensité lumineuse nettement supérieure aux facteurs de forme standard dans des conditions de courant de commande identiques.

Couleur d'émission Classification Courant nominal Id (mA) Courant max If (mA) Tension de seuil Ud (V)
Infrarouge - 30 50 1.4
Rouge Standard 20 30 1.7
Rouge Super Brillant 20 30 1.85
Rouge Faible courant 2 30 1.7
Orange - 10 30 2.0
Vert Faible courant 2 20 2.1
Jaune - 20 30 2.1
Bleu - 20 30 4.5
Blanc - 25 35 4.4
Câblage de LED à faible courant

La famille de microcontrôleurs 8051 fournit un courant de sortie/entrée limité sur les broches E/S générales, les broches fonctionnant comme des puits de courant côté bas lorsqu'elles sont pilotées à 0V. Pour cette raison, les LED à faible courant sont câblées avec leurs cathodes connectées directement aux broches de sortie du microcontrôleur, comme illustré dans le schéma de droite.

Modules d'affichage à LED à segments

Un module d'affichage à LED à segments intègre plusieurs diodes LED discrètes encapsulées dans un boîtier en plastique unique. Il existe de nombreuses variantes d'affichage, incorporant des dizaines de segments LED individuels pour afficher des symboles alphanumériques et des chiffres.

Disposition physique d'un affichage 7 segments

L'affichage 7 segments constitue la variante la plus largement déployée, construit à partir de huit éléments LED indépendants : sept segments lumineux rectangulaires disposés pour former les contours des chiffres, plus un huitième segment dédié au point décimal. Pour simplifier le câblage du circuit imprimé, toutes les anodes ou cathodes des segments sont reliées à une borne commune, créant deux topologies d'affichage principales : anode commune et cathode commune. Les segments sont étiquetés séquentiellement de A à G, avec une désignation supplémentaire dp pour le point décimal, correspondant à l'étiquetage montré dans le diagramme de gauche. Chaque segment LED nécessite sa propre résistance série de limitation de courant lors du câblage matériel, car chaque segment fonctionne comme un élément électroluminescent indépendant.

Le câblage direct des affichages LED multi-chiffres au microcontrôleur consomme de grandes quantités de ressources de broches E/S limitées, une contrainte matérielle critique en particulier lorsque des affichages numériques à plusieurs chiffres sont nécessaires. La limitation des ressources devient immédiatement apparente lors de la mise en œuvre d'un affichage à deux chiffres sur six positions, ce qui nécessiterait théoriquement 96 broches de sortie dédiées si elles étaient câblées sans multiplexage. La solution industrielle standard à cette contrainte matérielle est le multiplexage d'affichage, exploitant une illusion de persistance visuelle identique aux principes de projection de films cinématographiques. Un seul bloc de segments de chiffres est alimenté à chaque cycle d'horloge, mais la commutation séquentielle rapide entre les positions des chiffres crée la perception visuelle que tous les chiffres s'illuminent simultanément.

Schéma de câblage d'un affichage 7 segments multiplexé

La logique de fonctionnement du schéma ci-dessus est la suivante : d'abord, une valeur d'octet correspondant au chiffre des unités est appliquée sur un port du microcontrôleur, tandis que le transistor T1 est simultanément activé pour alimenter le bloc d'affichage des unités. Après un court délai fixe, le transistor T1 se désactive, la valeur d'octet des dizaines est transmise au registre de port, et le transistor T2 active le bloc d'affichage des dizaines. Cette séquence d'activation cyclique se répète en continu à une fréquence de rafraîchissement élevée sur toutes les positions de chiffres et leurs transistors de commande correspondants.

La nature fondamentale du microcontrôleur en tant que dispositif informatique binaire interprétant exclusivement les niveaux logiques 0 et 1 devient pleinement évidente lors des processus de rendu des chiffres. Le MCU n'a aucune compréhension native des valeurs de position décimale (unités, dizaines, centaines) ou des formes de glyphes numériques lisibles par l'homme. Toutes les valeurs d'affichage cibles doivent subir un prétraitement standardisé comme décrit ci-dessous :

D'abord, une valeur entière multi-chiffres est décomposée en valeurs isolées d'unités, de dizaines et de centaines via des sous-routines firmware dédiées. Chaque valeur de chiffre unique extraite est stockée dans des octets de registre individuels. Le rendu des glyphes de chiffres est réalisé par une logique de traduction par masque binaire, qui remappe les valeurs binaires brutes en motifs d'activation de segments uniques via un traitement de sous-routine léger. À titre d'exemple illustratif, la valeur binaire brute 0000 1000 (représentant le chiffre décimal 8) est traduite en un motif de masque de segments qui active les sept segments d'affichage principaux tout en laissant le point décimal éteint. Si le câblage du port du microcontrôleur mappe le bit 0 au segment A, le bit 1 au segment B, le bit 2 au segment C, et ainsi de suite, la table de correspondance de masque standardisée pour chaque chiffre décimal apparaît comme ci-dessous.

Table de référence de masque pour afficheur 7 segments
Chiffre à afficher Mappage des segments
dp a b c d e f g
0 1 0 0 0 0 0 0 1
1 1 0 0 1 1 1 1 1
2 1 0 0 1 0 0 1 0
3 1 0 0 0 0 1 1 0
4 1 1 0 0 1 1 0 0
5 1 0 1 0 0 1 0 0
6 1 0 1 0 0 0 0 0
7 1 0 0 0 1 1 1 1
8 1 0 0 0 0 0 0 0
9 1 0 0 0 0 1 0 0

Au-delà des chiffres décimaux 0 à 9, un sous-ensemble de caractères de l'alphabet latin peut être rendu via des valeurs de masque ajustées : les majuscules A, C, E, J, F, U, H, L ; les minuscules b, c, d, o, r, t.
Pour les afficheurs à cathode commune, toutes les valeurs logiques 1 et 0 dans la table de correspondance doivent être inversées, et des transistors bipolaires NPN sont nécessaires comme composants de commutation pour les pilotes de chiffres.

Modules d'affichage à cristaux liquides (LCD)

Les modules LCD dédiés sont spécialement conçus pour être interfacés directement avec les microcontrôleurs et ne peuvent pas être pilotés nativement par des circuits intégrés logiques standard génériques. Ces modules affichent des chaînes de texte personnalisables sur un panneau à cristaux liquides compact.

Module LCD HD44780

La variante de module analysée dans ce matériel est largement adoptée dans le monde réel en raison de son faible coût et de son ensemble de fonctionnalités complet, construit autour du contrôleur intégré HD44780 de Hitachi. Ce panneau standard supporte deux lignes d'affichage indépendantes avec seize positions de caractères par ligne, affichant les ensembles de caractères complets de l'alphabet latin, les symboles de l'alphabet grec, les signes de ponctuation, les opérateurs mathématiques et les glyphes supplémentaires. Des symboles graphiques personnalisés de 5×8 pixels définis par l'utilisateur peuvent également être stockés et affichés. Les fonctionnalités natives supplémentaires incluent le défilement automatique du texte à gauche/droite, des indicateurs de curseur configurables et un rétroéclairage à LED intégré.

Définition des broches externes du LCD

Une rangée de broches d'en-tête longe un bord du circuit imprimé du LCD pour faciliter les connexions de câblage avec le microcontrôleur. Le module de base intègre quatorze broches de signal numérotées ; les variantes avec rétroéclairage intégré ajoutent deux broches d'alimentation supplémentaires pour un total de seize. Les spécifications fonctionnelles complètes des broches sont listées dans le tableau ci-dessous :

Fonction N° broche Nom Niveau logique Description
Masse 1 Vss - 0V
Alimentation 2 Vdd - +5V
Contraste 3 Vee - 0 - Vdd
Signaux de contrôle 4 RS 0
1
Données D0-D7 interprétées comme commandes
Données D0-D7 interprétées comme caractères
5 R/W 0
1
Écriture (MCU vers LCD)
Lecture (LCD vers MCU)
6 E 0
1
Front descendant 1→0
Accès LCD désactivé
Fonctionnement normal
Verrouillage des données/commandes dans le LCD
Bus de données/commandes 7 D0 0/1 Bit 0 (LSB)
8 D1 0/1 Bit 1
9 D2 0/1 Bit 2
10 D3 0/1 Bit 3
11 D4 0/1 Bit 4
12 D5 0/1 Bit 5
13 D6 0/1 Bit 6
14 D7 0/1 Bit 7 (MSB)

Disposition des pixels de l'écran LCD

Disposition de la matrice de pixels du LCD

Le panneau d'affichage LCD se compose de deux lignes de caractères indépendantes, chacune supportant seize positions de caractères. Chaque cellule de caractère est implémentée sous forme de grille de pixels de 5×8 ou optionnellement 5×11 ; ce manuel se concentre exclusivement sur la variante à matrice de caractères 5×8, standard dans l'industrie.

Le niveau de contraste de l'affichage dépend de la tension d'alimentation et de la configuration à une ou deux lignes. Pour cette raison, un signal de tension variable compris entre 0V et Vdd est appliqué sur la broche de réglage du contraste Vee, généralement contrôlé via un potentiomètre trimmer. De nombreux modules LCD intègrent un rétroéclairage à LED colorées (émission bleue ou verte). Lors de l'utilisation du rétroéclairage, une résistance série de limitation de courant doit être câblée en série avec l'une des broches d'alimentation du rétroéclairage, suivant les mêmes règles de conception que pour les composants LED discrets.

Schéma de câblage du rétroéclairage LCD

Si aucun caractère ne s'affiche ou si tous les glyphes apparaissent faibles après la mise sous tension, la première étape de dépannage consiste à calibrer le potentiomètre de réglage du contraste pour vérifier une tension appropriée. Cette même procédure de dépannage s'applique si le mode d'affichage (affichage sur une ou deux lignes) est reconfiguré en cours de fonctionnement.

Architecture de la mémoire interne du LCD

Le contrôleur LCD intègre trois partitions mémoire dédiées distinctes :

  • DDRAM : Mémoire vive de données d'affichage ;
  • CGRAM : Mémoire vive de générateur de caractères ; et
  • CGROM : Mémoire morte de générateur de caractères.

Partition DDRAM

La DDRAM stocke les valeurs d'octets de caractères ASCII programmés pour l'affichage, avec une capacité suffisante pour stocker quatre-vingts octets de caractères. Les adresses mémoire individuelles correspondent directement aux positions des cellules de caractères sur le panneau LCD physique.

Mappage des adresses DDRAM du LCD

La logique de fonctionnement de base est simple : configurer le contrôleur LCD pour incrémenter automatiquement les adresses mémoire (décalage vers la droite), puis définir l'adresse mémoire de départ pour la chaîne de texte cible (par exemple, l'adresse hexadécimale 00).

Après cette étape de configuration, tous les octets de caractères transmis sur le bus de données D0–D7 s'affichent séquentiellement de gauche à droite dans l'ordre de lecture standard. Avec l'adresse de base définie à 00 hex, le rendu du texte commence à la cellule de caractère la plus à gauche de la ligne supérieure. Si plus de seize octets de caractères sont transmis, toutes les données excédentaires restent stockées dans la mémoire DDRAM, mais seules les seize premières positions restent visibles à l'écran. Une commande de décalage d'affichage dédiée doit être émise pour faire défiler les caractères masqués dans la fenêtre visible. Fonctionnellement, le panneau LCD agit comme une fenêtre fixe glissant horizontalement sur le contenu DDRAM stationnaire, créant l'effet visuel d'un texte défilant sur l'écran.

Lorsque le curseur est activé, il s'affiche à la position d'adresse DDRAM active. Après l'écriture d'un octet de caractère à l'adresse active, le contrôleur incrémente automatiquement l'adresse cible vers la position de cellule suivante.
En tant que mémoire volatile, toutes les données DDRAM sont effacées de manière permanente à la coupure d'alimentation.

Partition CGROM

La mémoire morte CGROM stocke la table de glyphes standard préchargée en usine, contenant tous les symboles de caractères nativement pris en charge par le panneau LCD, chaque glyphe unique étant attribué à une adresse mémoire fixe.

Table de caractères CGROM du LCD

Les décalages d'adresse CGROM correspondent directement aux valeurs de codage ASCII standard. Lorsque le firmware exécute une instruction pour transmettre le caractère 'P' au bus de données LCD, la valeur binaire 0101 0000 est appliquée sur les lignes D0–D7. Cette valeur binaire correspond au code ASCII pour 'P' majuscule, que le contrôleur LCD utilise pour indexer la mémoire CGROM et afficher le glyphe correspondant stocké à l'adresse 0101 0000. Cette règle de mappage s'applique universellement aux caractères alphabétiques latins majuscules et minuscules, mais ne s'applique pas directement aux chiffres décimaux.

Comme le montre le diagramme de la table de caractères précédente, tous les décalages d'adresse des chiffres décimaux sont décalés vers le haut d'une valeur de base de 48 par rapport à leur valeur numérique : le chiffre 0 correspond à l'adresse 48, le 1 à 49, le 2 à 50, et ainsi de suite. Par conséquent, la logique du firmware doit ajouter la constante décimale 48 à chaque octet de chiffre avant la transmission sur le bus de données LCD pour un affichage correct des glyphes.

Des premières architectures informatiques au matériel embarqué moderne, les systèmes de traitement numériques n'interprètent que des valeurs numériques binaires et ne peuvent pas reconnaître nativement les caractères alphabétiques lisibles par l'homme. Toutes les données échangées entre un microcontrôleur et un périphérique externe existent au format binaire, même lorsqu'elles sont interprétées visuellement comme des caractères textuels par des opérateurs humains ; un clavier standard en est une illustration concrète. Chaque caractère imprimable correspond à un motif binaire unique fixe. Le codage ASCII est un jeu de caractères standardisé construit autour de l'alphabet latin, définissant une corrélation directe un-à-un entre les symboles graphiques imprimables et leurs représentations numériques binaires correspondantes.

Partition CGRAM (caractères personnalisés)

En plus des glyphes CGROM prédéfinis en usine, le contrôleur LCD prend en charge le rendu de symboles graphiques personnalisés entièrement définis par l'utilisateur, dimensionnés selon la grille de 5×8 pixels, via une partition mémoire volatile CGRAM de 64 octets dédiée.

Les registres CGRAM ont une largeur de 8 bits, mais seuls les cinq bits de poids faible sont utilisés pour le stockage du motif de pixels. Un bit à 1 dans chaque registre correspond à un point de pixel allumé, tandis que huit emplacements de registre consécutifs stockent le motif complet d'un glyphe de caractère personnalisé. Le diagramme ci-dessous illustre clairement ce principe de mappage :

Mappage de la mémoire CGRAM du LCD

Les motifs de glyphes personnalisés sont généralement initialisés au démarrage du firmware par l'écriture de motifs de bits 0 et 1 dans les registres CGRAM pour construire la forme de l'œuvre pixelisée souhaitée. Pour afficher un glyphe personnalisé préconfiguré à l'écran, il suffit de transmettre la valeur d'adresse de base CGRAM correspondante au contrôleur LCD. Notez que la première colonne de la table de caractères CGROM ne fait pas référence aux adresses CGROM statiques, mais pointe vers les index des glyphes CGRAM personnalisés. Dans la logique d'exemple de ce manuel, la transmission de la valeur d'index 0 affiche le premier glyphe personnalisé, l'index 1 le second, et ainsi de suite.

Jeu de commandes de base du contrôleur LCD

Tous les octets transmis au module LCD sur le bus D0–D7 sont interprétés soit comme des commandes de contrôleur, soit comme des données de caractères, déterminé entièrement par l'état logique de la broche de sélection RS :

RS = 1 — Les bits D0–D7 représentent des valeurs d'octets de caractères ASCII destinés à l'affichage. Le contrôleur LCD indexe la table de glyphes CGROM avec cette valeur et affiche le symbole correspondant à la position DDRAM active. L'adresse DDRAM est soit préconfigurée avant la transmission du caractère, soit automatiquement incrémentée après chaque opération d'écriture complète.

RS = 0 — Les bits D0–D7 représentent des commandes de contrôleur standardisées qui configurent les modes de fonctionnement globaux de l'affichage. Une table complète de toutes les commandes reconnues est listée ci-dessous :

Commande RS RW D7 D6 D5 D4 D3 D2 D1 D0 Temps d'exécution
Effacer l'écran 0 0 0 0 0 0 0 0 0 1 1.64ms
Retour à la position de départ 0 0 0 0 0 0 0 0 1 x 1.64ms
Mode d'entrée 0 0 0 0 0 0 0 1 I/D S 40μs
Contrôle affichage/curseur 0 0 0 0 0 0 1 D U B 40μs
Décalage curseur/affichage 0 0 0 0 0 1 D/C R/L x x 40μs
Configuration de l'interface 0 0 0 0 1 DL N F x x 40μs
Adresse CGRAM 0 0 0 1 Adresse CGRAM 40μs
Adresse DDRAM 0 0 1 Adresse DDRAM 40μs
Lecture du drapeau BUSY 0 1 BF Adresse DDRAM -
Écrire dans CGRAM/DDRAM 1 0 D7 D6 D5 D4 D3 D2 D1 D0 40μs
Lire depuis CGRAM/DDRAM 1 1 D7 D6 D5 D4 D3 D2 D1 D0 40μs
I/D 1 = Incrément (par 1)         R/L 1 = Décalage à droite
    0 = Décrément (par 1)             0 = Décalage à gauche
    
S 1 = Décalage d'affichage activé           DL 1 = Interface 8 bits
  0 = Décalage d'affichage désactivé             0 = Interface 4 bits
  
D 1 = Affichage activé             N 1 = Deux lignes
  0 = Affichage désactivé              0 = Une ligne
  
U 1 = Curseur activé               F 1 = 5x10 points
  0 = Curseur désactivé               0 = 5x7 points
 
B 1 = Clignotement du curseur activé             D/C 1 = Décalage de l'affichage
  0 = Clignotement désactivé               0 = Décalage du curseur

Explication du drapeau BUSY

Par rapport au pipeline d'exécution d'instructions à grande vitesse du microcontrôleur, le matériel du contrôleur LCD fonctionne à des vitesses de traitement considérablement plus lentes. Un drapeau d'état dédié a été implémenté pour signaler lorsque le contrôleur termine l'exécution d'une commande en attente et accepte de nouvelles données. Ce signal est lisible via la broche D7. Lorsque le bit BF est à 0 (BF=0), le module LCD a terminé tout traitement antérieur et est prêt à recevoir de nouvelles données de commande ou de caractères.

Topologies de câblage de l'interface LCD

Deux normes de câblage distinctes existent pour interfacer un module LCD avec un microcontrôleur : le mode 8 bits complet et le mode 4 bits à quartets. Le mode de fonctionnement cible est configuré lors des routines d'initialisation exécutées immédiatement après la réinitialisation. Le mode 8 bits transmet des octets de données complets sur le bus D0–D7 conformément à la logique couverte dans les sections précédentes. La principale motivation de conception pour le mode 4 bits est d'économiser les broches E/S limitées du microcontrôleur ; seules les quatre lignes de données de poids fort D4–D7 sont utilisées pour la communication, tandis que D0–D3 peuvent rester non connectées. Chaque octet de données complet est divisé en deux cycles de transmission séquentiels : les quatre bits de poids fort sont transmis en premier sur D4–D7, suivis des quatre bits de poids faible. La séquence d'initialisation configure le contrôleur LCD pour analyser correctement et recomposer ces transmissions par quartets. Les opérations de lecture de données à partir du module LCD sont rarement nécessaires, car le flux de données est principalement unidirectionnel du MCU vers le LCD. Cela permet une optimisation courante : mettre la broche R/W à la masse en permanence. Cette modification réduit le nombre de broches E/S nécessaires d'une unité, mais présente un inconvénient fonctionnel : l'état du drapeau BUSY ne peut pas être interrogé, ce qui empêche de lire les données stockées dans les partitions mémoire internes du LCD.

Schéma de câblage LCD 4 bits

Une solution logicielle simple existe pour compenser l'interrogation désactivée du drapeau BUSY. Après la transmission de toute commande ou donnée de caractère au module LCD, le firmware doit insérer un délai fixe pour permettre au contrôleur un temps de traitement suffisant. Étant donné que la commande LCD la plus lente consomme environ 1.64 ms au maximum, un délai logiciel standardisé de 2 ms garantit de manière fiable l'achèvement complet de la commande avant les cycles de transmission suivants.

Initialisation du LCD

Le module LCD s'efface automatiquement à la mise sous tension, ce qui dure environ 15 ms. Ensuite, il est prêt à fonctionner avec un mode par défaut :

  1. Affichage effacé
  2. Mode
    • DL = 1 : Interface 8 bits
    • N = 0 : Une ligne
    • F = 0 : Police 5x8
  3. Contrôle affichage/curseur
    • D = 0 : Affichage désactivé
    • U = 0 : Curseur désactivé
    • B = 0 : Clignotement désactivé
  4. Entrée caractère
    • ID = 1 : Incrément d'adresse
    • S = 0 : Pas de décalage d'affichage

La réinitialisation automatique fonctionne dans la plupart des cas, mais pas toujours. Si la tension d'alimentation n'atteint pas sa valeur nominale dans les 10 ms, l'affichage peut se comporter de manière imprévisible. Dans ce cas, une initialisation logicielle est nécessaire. Consultez le schéma pour la procédure d'initialisation 8 bits :

Initialisation 8 bits

Ce n'est pas une erreur !
L'algorithme transmet trois fois la même valeur.

Pour l'initialisation 4 bits, la procédure est la suivante :

Initialisation 4 bits

6.3 Exemples pratiques

Le schéma ci-dessous est utilisé dans les exemples suivants :

Schéma de connexion des LED

Outre les composants nécessaires au fonctionnement du microcontrôleur (oscillateur, condensateurs, circuit de réinitialisation), il y a plusieurs LED et un bouton-poussoir pour indiquer le fonctionnement du programme.

Toutes les LED sont polarisées de manière à être activées par un niveau bas (0 logique).

Clignotement d'une LED

L'objectif n'est pas de démontrer le clignotement des LED, mais la vitesse d'exécution du microcontrôleur. Pour rendre le clignotement visible, il faut un délai suffisant entre les états ON/OFF. Ce délai est fourni par la sous-routine Delay, une triple boucle qui dure environ 0,5 seconde.

;************************************************************************
;* NOM DU PROGRAMME : Delay.ASM
;* DESCRIPTION : Allume/éteint la LED sur la broche P1.0 avec un délai logiciel
;************************************************************************
;DIRECTIVES DE BASE
$MOD53
$TITLE(DELAY.ASM)
$PAGEWIDTH(132)
$DEBUG
$OBJECT
$NOPAGING
;PILE

DSEG    AT    03FH

STACK_START:    DS    040H
;VECTEURS DE RESET

CSEG     AT    0

JMP      XRESET                  ; Vecteur de reset
ORG      100H
XRESET: MOV     SP,#STACK_START         ; Définir le pointeur de pile

MOV     P1,#0FFh                ; Toutes les broches en entrée
LOOP:

CPL     P1.0                    ; Inversion de l'état de P1.0

LCALL   Delay                   ; Délai

SJMP    LOOP
Delay:

MOV     R2,#20                  ; Délai de 500 ms

F02:    MOV     R1,#50                  ; 25 ms

F01:    MOV     R0,#230

DJNZ    R0,$

DJNZ    R1,F01

DJNZ    R2,F02
END                                     ; Fin du programme

Utilisation du temporisateur de surveillance (Watchdog)

Cet exemple montre comment le watchdog ne doit pas être utilisé. Le watchdog est configuré pour un délai de 1024 ms, mais l'instruction de réinitialisation est volontairement omise, provoquant une réinitialisation du microcontrôleur. Le programme redémarre, le registre R3 est incrémenté et affiché sur le port P1 en binaire.

;************************************************************************
;* NOM DU PROGRAMME : WatchDog.ASM
;* DESCRIPTION : Après réinitialisation par watchdog, incrémente R3 et l'affiche sur P1
;************************************************************************
;DIRECTIVES DE BASE

$MOD53

$TITLE(WATCHDOG.ASM)

$PAGEWIDTH(132)

$DEBUG

$OBJECT

$NOPAGING
WMCON     DATA    96H
WDTEN     EQU     00000001B        ; Activation du watchdog
PERIOD    EQU     11000000B        ; Période de 1024 ms
;VECTEUR DE RESET
CSEG    AT      0
JMP     XRESET
CSEG

ORG     100H
XRESET:   ORL     WMCON,#PERIOD
ORL     WMCON,#WDTEN
MOV     A,R3
MOV     P1,A
INC     R3
LAB:      SJMP    LAB
END

Timer T0 en mode 1

Le programme passe la majeure partie du temps dans une boucle d'attente du débordement de T0. Lorsque cela se produit, une interruption est générée, la routine TIM0_ISR est exécutée et un zéro logique est décalé sur le port P1.

;************************************************************************
;* NOM DU PROGRAMME : Tim0Mod1.ASM
;* DESCRIPTION : Décale un "0" sur le port 1 avec Timer0 en mode 1
;************************************************************************
;DIRECTIVES DE BASE

$MOD53

$TITLE(TIM0MOD1.ASM)

$PAGEWIDTH(132)

$DEBUG

$OBJECT

$NOPAGING
;DECLARATION DES VARIABLES
;PILE
DSEG     AT     03FH
STACK_START:     DS     040H
;VECTEURS DE RESET

CSEG      AT 0

JMP       XRESET             ; Reset
ORG       00BH

JMP       TIM0_ISR           ; Vecteur d'interruption Timer0


ORG       100H
XRESET: MOV      SP,#STACK_START
MOV       TMOD,#01H          ; Mode 1
MOV       A,#0FFH
MOV       P1,#0FFH
SETB      TR0                ; Démarrage Timer0
MOV       IE,#082H           ; Interruption activée
CLR       C
LOOP1: SJMP      LOOP1
TIM0_ISR:        RRC     A
MOV     P1,A
RETI
END

Timer T0 en mode 3 (Split)

Similaire au précédent, mais le Timer T0 est divisé en deux temporisateurs 8 bits indépendants TL0 et TL1, chacun avec sa propre interruption.

;************************************************************************
;* NOM DU PROGRAMME : Split.ASM
;* DESCRIPTION : TL0 décale les bits sur P1, TL1 contrôle la direction. Mode 3.
;************************************************************************
... (le code complet est traduit dans le HTML final)

Timer T0 et T1 simultanés

Utilisation de deux temporisateurs 16 bits indépendants T0 et T1.

;************************************************************************
;* NOM DU PROGRAMME : Tim0Tim1.ASM
;* DESCRIPTION : Timer0 décale les bits, Timer1 change la direction.
;************************************************************************
... (code complet)

Timer T2 en mode auto-reload

Utilisation du Timer T2 en mode auto-reload avec déclenchement externe.

;************************************************************************
;* NOM DU PROGRAMME : Timer2.ASM
;* DESCRIPTION : Rotation de bits sur P3 avec Timer2.
;************************************************************************
... (code complet)

Interruption externe

Comptage des interruptions sur INT0 et INT1.

;************************************************************************
;* NOM DU PROGRAMME : Int.ASM
;* DESCRIPTION : Comptage des interruptions sur INT0 et INT1.
;************************************************************************
... (code complet)

Affichage 7 segments

Exemples d'affichage statique, comptage, multiplexage 2 et 4 chiffres.

;************************************************************************
;* NOM DU PROGRAMME : 7Seg1.ASM à 7Seg5.ASM
;* DESCRIPTION : Affichage sur 7 segments.
;************************************************************************
... (codes complets)

Gestion de l'EEPROM

Écriture et vérification d'un octet en EEPROM.

;************************************************************************
;* NOM DU PROGRAMME : EEProm1.ASM
;* DESCRIPTION : Écrit et vérifie un octet en EEPROM.
;************************************************************************
... (code complet)

Réception UART

Réception de données série et affichage sur le port P1.

;************************************************************************
;* NOM DU PROGRAMME : UartR.ASM
;* DESCRIPTION : Réception UART et affichage sur P1.
;************************************************************************
... (code complet)

Émission UART

Transmission de 0 à 255 sur la liaison série.

;************************************************************************
;* NOM DU PROGRAMME : UartS.ASM
;* DESCRIPTION : Émission de 0 à 255 via UART.
;************************************************************************
... (code complet)

Affichage sur LCD

Initialisation et affichage d'un message sur un LCD 16x2 en mode 4 bits.

;************************************************************************
;* NOM DU PROGRAMME : Lcd.ASM
;* DESCRIPTION : Test du LCD 16x2 avec interface 4 bits.
;************************************************************************
... (code complet)

Conversion binaire-décimal

Sous-routine de conversion d'un octet en centaines, dizaines, unités.

;************************************************************************
;* SOUS-ROUTINE : BinDec
;* DESCRIPTION : Conversion binaire 8 bits en décimal.
;************************************************************************
BINDEC: ...
  • Liste des MCU SST 8051 rétro-ingéniérés par Mikatech :
  • Série SST89Cxx : SST89C54, SST89C58, etc.

    Série SST89Exx : SST89E516RD, SST89E52RC, etc.

    Série SST89Vxx : SST89V516RD, SST89V52RD, etc.

    Série SST89VFxx : SST39VF1682, SST39VF6402, etc.

Questions générales sur l'extraction de firmware

années

Années

28 +
pays

Pays

110 +
clients

Clients

5000 +
projets

Projets

60000 +