You are on page 1of 87

Institut Supèrieur des Etudes Technologiques de Sousse

Formation 21/21 sur le thème :

Microcontrôleurs
PIC16FXX

Assurée par : ZAIDI Abdelaziz et Hmidène Ali

2006/2007

1
Sommaire
A- Les microprocesseurs et les microcontrôleurs
1- Historique ………………………………………………………………………. 3
2- L’actualité………………………………………………………………………. 3
3- Architectures d'une Machine…………………………………………………… 3
4- Différence entre un microprocesseur et un microcontrôleur ………………….. 4
5- Quelques microcontrôleurs connus ……………………………………………. 4
6- Microcontrôleurs et applications ……………………………………………….. 9

B- Composition et fonctionnement des PICs


1- Qu’est-ce qu’un PIC ?........................................................................................... 1
2- Les différentes familles des PICs………………………………………………. 0
11
C- Le PIC 16F84
1- Caractéristiques générales du microcontrôleur…………………………………. 11
2- Architecture interne…………………………………………………………….. 1
3- Organisation du 16F84…………………………………………………………. 2
4- Les ports d’entrée/sortie…………..…………………………………………… 1
5- Les SFR (registres à fonction spéciale)……………………………………….. 3
6- Organisation des instructions……………………………….…………………… 1
7- Organisation d’un fichier « .asm »……………………………………………… 5
8- Les modes d’adressage…………………………………………………………. 1
9- Réalisation d’un programme embarqué ……………………………………….. 6
10- Les interruptions ……………………………………………………………… 1
11-Timer0 ………………………………………………………………………… 6
12- Les accès en mémoire « eeprom »……………………………………………. 2
13- Le watchdog (chien de garde)………………………………………………… 0
14- Le mode Sleep (veille)………………………………………………………… 2
7
2
9
3
6
4
1
4
5
4
7
4
8

2
D- Le PIC 16F877
1- Introduction ……………………………………………………………………. 5
2- Les Ports du 16F877 …………………………………………………………… 0
3- La mémoire du Pic ……………………………………………………………… 5
4- Les modules internes du 16F877……………………………………………….. 2
4.1. Les Trois timers / compteurs……………………………………………. 5
4.2. Un convertisseur analogique-numérique (CAN) 10 bits ………………. 4
4.3. Les deux modules CCP et la génération (PWM) ……………………… 5
4.4 Le module MSSP en mode SPI …………………………………………. 5
4.5. Le module USART …………………………………………………… 5
4.6. Port D en mode PSP…………………………………………………… 6
4.7. liaison I2C ……………………………………………………………… 6
5- Les Interruptions du 16F877 …………………………………………………… 0
6
8
7
2
7
3
7
9
8
0
8
5

A-Les microprocesseurs et les microcontrôleurs


1-Historique
Avant les années 50 John Mauchley et Prespert Eckert, construisent l'ENIAC : 18000 tubes,
1500 relais, consomme 140 kW. La mémoire de programme est un panneau de câblage. La
mémoire des données comporte 20 mots de 10 chiffres décimaux.
L'Eckert-Mauchly Corporation lance son premier ordinateur, l'UNIVAC, en 1951.
BULL lance son premier ordinateur, le Gamma 2, en 1951.
IBM lance son premier ordinateur, le 701, en 1953.
L'invention du transistor en 1948 marque le vrai départ de l’industrie informatique.
DEC lance le premier mini-ordinateur, le PDP-1 en 1961.
IBM lance le 7090 en 1961. Le plus gros du moment.
CDC lance le CDC 6600 en 1964. Le premier ordinateur parallèle (conçu par Seymour Cray)
restera longtemps le plus puissant.
IBM lance la même année la série 360. Le premier ordinateur doté d'une unité de commande
microprogrammée et d'un vrai système d'exploitation (la première catastrophe logicielle).
DEC invente le bus et lance le PDP-8 en 1965.
INTEL invente le microprocesseur en 1971.

3
2-L’actualité
Deux marques se partagent le marché des processeurs destinés aux ordinateurs :
• INTEL, grâce à IBM, ses PC et tous les compatibles qui sont apparus.
• MOTOROLA, grâce à Apple Computers et son Macintosh.

3-Architectures d'une Machine


3.1 Architecture de Von Neumann
John Von Neumann : Brillant mathématicien, il fixe pour jusqu'à présent l'architecture d'un
ordinateur (à son époque, le mot n'est pas encore inventé).
constitution : Mémoire, Unité centrale, Communications.
Dans ce cas, le traitement d’une instruction et son opérande nécessite donc la lecture d’au moins
deux cases mémoires (3 si l’opérande est codée sur deux octets).
Cela correspond à une durée de 2 ou 3 cycles machine.

3.2 Architecture de Harvard


Cette architecture repose sur le principe de séparation de la mémoire-données de la mémoire-
programme.
Dans ce cas, la lecture d’une seule case mémoire permet le traitement entier d’une instruction et
de son opérande.
Un seul cycle machine est donc nécessaire.

3.3 Architectures Parallèles


• Amélioration de l'unité centrale d'une architecture de Von Neumann ou de Harvard.
• Nouvelles architectures de machine.

4-Différence entre un microprocesseur et un microcontrôleur


Avec un microprocesseur d’usage général, pour réaliser une application bien déterminée, le
microprocesseur et ses composants annexes (mémoire RAM, ROM,) doivent être reliés à des
circuits périphériques spécialisés tels que des ports parallèles (entrées/sorties logiques),
des convertisseurs analogiques/numériques, des transmetteurs/récepteurs série (UART)…

Afin de répondre à ces besoins, les fabricants de semiconducteurs on eu l’idée de regrouper


toutes ces fonctions dans un seul circuit spécialisé : le microcontrôleur.
4
Microcontrôleur

5-Quelques microcontrôleurs connus


5.1 Le 80C552 de PHILIPS (noyau 8051 de Intel):

Le 80C552 est un microcontrôleur de 8bits. Il est fabriqué dans un processus supérieur de CMOS
et c'est un dérivé de la famille des microcontrôleurs 80C51. Il utilise les instructions mises pour
le 80C51 en addition des registres de la fonction spéciale qui sont incorporés pour contrôler les
périphériques.

5
Le schéma synoptique de la figure au dessous, présente les différents blocs internes du
microcontrôleur qui sont les suivants:
- 8 koctets de ROM interne (mémoire programme) extensible jusqu'à 64Koctets.
- 256 octets de RAM (mémoire données) interne extensible jusqu'à 64Koctets.
- 2 Timers 16 bits standard (T0 et Tl).
- Un troisième Timer de 16 bits (T2) couplé à quatre registres de capture et à trois
registres de comparaison.
- Convertisseur analogique numérique équipé de huit entrées dont la résolution est de 10
bits.
- 2 sorties (PWM) de résolution 8 bits.
- 5 ports bidirectionnels.
- Un port unidirectionnel.

-Un système de gestion d'interruption sur deux niveaux de priorité.


-Un port série du type USART.
-Un module watchdog.
La fréquence maximale d’horloge est de 24 MHz. Pour un quartz de 12 MHz, la durée d’un cycle
machine est d’une microseconde.

6
5.2 Le 68HC11 de Motorola :

• Structure interne
Le microcontrôleur Motorola 68HC11 peut fonctionner avec des horloges allant jusqu'a
12MHz. Tous les registres étant statiques, une coupure d'horloge n'entraîne pas de perte de
donnée. Le 68HC11 intègre de puissants périphériques :
• Jusqu'a 12KO de ROM ou d'EPROM (mémoire programme)
• Jusqu'a 1 KO de RAM (mémoire donnée)
• Jusqu'a 8KO d'EEPROM (mémoire donnée)
• Ports paralélles
• Port de communication série asynchrone
• Port de communication série synchrone
• Ports analogiques
• Timers
• Chien de garde
• Génération d'interruptions temps réel

7
Le 68HC11 est disponible suivant les versions en boîtier DIP ou PLCC. Le modèle
fonctionnel du 68HC11Ex est donné ci-dessus. Des blocs fonctionnels peuvent être
différents ou absents dans certaines versions.

• Modes de fonctionnement

- Single-Ship: Fonctionnement autonome, tous les ports du microcontrôleur sont


disponibles, par contre la memoire est limite à la capacité interne
- Expended multiplexed: Ce mode permet d'étendre la capacité mémoire ainsi que les
peripheriques. L'ensemble devient plus puissant mais le matériel est plus complexe et deux
ports 8 bits sont perdus sur Ie microcontrôleur
- Special Bootstrap : Lors du RESET un logiciel interne appelé BOOTLOADER
télécharge automatiquement en RAM un programme provenant de la liaison série
asynchrone (SCI) et exécute celui-ci. Ce mode est utilisé pour stocker à distance des valeurs
de consigne (pour une régulation par exemple) ou pour Ie développement .
- Special Test: Destiné au départ aux tests de production de Motorola, ce mode peut être
utilisé pour le développement, en particulier pour I'émulation, il permet entre autre de
modifier le registre CONFIG après le RESET

5.3 Le AT90S8535 de ATMEL

• Description :
Le microcontrôleur AT90S8535 est produit par ATMEL. Il s’agit d’un microcontrôleur 8 bits,
qui intègre de nombreux périphériques, ainsi que différents types de mémoire.
La figure suivante présente l’architecture interne du microcontrôleur.
• Constitution:
- CPU 8 Bits capable d’exécuter une instruction par cycle d’horloge.
- 8 Koctets de mémoire programme EEPROM FLASH programmable in situ.
- 512 Octets d’EEPROM (Stockage de données non volatiles)
- 512 Octets de RAM (données) statique.
- Convertisseur Analogique Numérique 10 bits à 8 entrées multiplexées.
- Liaisons séries synchrone (SPI) et asynchrone (SCI)
- 2 TIMERS 8 bits (dont 1 utilisable en RTC a l’aide d’un oscillateur externe)
- 1 TIMER 16 bits.
- 1 Comparateur de tensions analogiques.
- 2 entrées d’interruptions externes et une entrée de RESET.
- 4 Ports d’entrées/sorties 8 bits.
La fréquence maximale d’horloge est de 8MHz ce qui donne 8MIPS (8 Milliers d’Instructions
Par Seconde). Le boîtier peut être un boîtier DIL ou PLCC.

7
• Espace mémoire :
La taille du bus de données est de 8 bits, les mémoires de données (SRAM et EEPROM) sont
donc organisées en mot de 8 bits.
Les instructions exécutables par l’unité arithmétique et logique sont codées sur 16 bits, la
mémoire de programme (FLASH) est donc organisée en mots de 16 bits.

L’espace de données est complètement séparé de l’espace adressable de la mémoire


programme, ils possèdent chacun leur propre bus d’adresses et de données (Architecture de
HARVARD).

• Le CPU :
Le microprocesseur du AT90S8535 comporte :
- Un bloc de 32 registres, contenant les données à traiter,
- Une unité arithmétique et logique (ALU) rapide, qui est capable d’exécuter une instruction,
(de registre à registre) par cycle d’horloge,
- Un compteur programme,
- Un registre d’instruction et un décodeur d’instruction, et un cache d’instruction.

8
6- Microcontrôleurs et applications
D’autres fabricants proposent d’autres microcontrôleurs. Par exemple :
– Parallax (Série Basic Stamp)
– Arizona Microchip (Série PIC)
– Rabbit Semiconductor (Série Rabbit)

Il s’agit d’un marché gigantesque : Arizona Microchip déclare avoir vendu plus de 1,5
milliards d’unités (2001).
Les caractéristiques principales d’un microcontrôleur sont :
– De nombreux périphériques d’E/S
– Une mémoire de programme
– Une mémoire vive (en général de type SRAM)
– Eventuellement une mémoire EEPROM destinée à la sauvegarde par programme de
données à la coupure de l’alimentation.
– Un processeur 8 ou 16 bits.
– Faible consommation électrique
Les tailles mémoire sont en général réduites, de l’ordre de :
– 16 koctets pour la mémoire programme
– Quelques octets à 16 koctets pour la RAM
La puissance de calcul est aussi limitée :
– 0.012 MIPS pour les Basic Stamp
– 1 à 5 MIPS pour les PIC
– 20 MIPS pour les Rabbit
Pour référence, un 80286 à 6MHz permet d’atteindre 0.9 MIPS, alors que la puissance de
calcul d’un Pentium 4 est de l’ordre de 5000 MIPS. Les nouvelles gammes de
microcontrôleurs présentent des capacités importantes de calcul.
Les microcontrôleurs sont conçus pour l’usage dans plusieurs applications :
• Instrumentation

9
• Contrôle industriel
• Contrôle des automobiles
• Commande des machines
• Electroménager, Hi-Fi…
Nous allons durant ce cours étudier les microcontrôleurs PIC. Ces microcontrôleurs
présentent trois avantages majeurs : Le coût, le jeux d’instruction réduit et la facilité de
chargement du programme avec, bien sûr, toutes les fonctionnalités d’un microcontrôleur
moderne.

B- Composition et fonctionnement des PICs

Nous allons maintenant nous pencher sur un PIC, et en particulier sur le 16F84.
Rassurez-vous, tout ce que nous verrons sur le 16F84 pourra être directement utilisé sur les
PIC16F877, qui ne sont rien d’autre que des 16F84 améliorées. Chaque PIC dispose des
fonctionnalités des modèles inférieurs, augmentées de nouvelles fonctions.

Tout d’abord, vous devez télécharger le datasheet du 16F84, car c’est un document qui
facilite la compréhension de ce cours. Durant ce cours, on vous référe à des pages à voir sur le
datasheet, pour plus d’informations. Il est vivement conseillé de l’imprimer, car vous en aurez
toujours besoin quand vous vous lancerez dans la réalisation de vos propres programmes. Le
datasheet du 16F877 vous serais aussi utile dans le cas ou vous aimeriez approfondir vos
connaisances sur ce qui se passe rééllement à l’intérieur du PIC, pour les périphériques qui
sont intégrés dans le microcontrôleur évolué 16F877.

1- Qu’est-ce qu’un PIC ?

Un PIC n’est rien d’autre qu’un microcontrôleur, c’est à dire une unité de traitement
de l’information de type microprocesseur à laquelle on a ajouté des périphériques internes
permettant de réaliser des montages sans nécessiter l’ajout de composants externes.

La dénomination PIC est sous copyright de Microchip, donc les autres fabricants ont
été dans l’impossibilité d’utiliser ce terme pour leurs propres microcontrôleurs.

Les PICs sont des composants dits RISC (Reduce Instructions Construction Set), ou
encore composant à jeu d’instructions réduit. Pourquoi ? Et bien, sachez que plus on réduit le
nombre d’instructions, plus facile et plus rapide en est le décodage, et plus vite le composant
fonctionne.

Toutes les PICs Mid-Range ont un jeu de 35 instructions, stockent chaque instruction
dans un seul mot de programme, et exécutent chaque instruction (sauf les sauts) en 1 cycle.
On atteint donc des très grandes vitesses, et les instructions sont de plus très rapidement
assimilées.

L’horloge fournie au PIC est prédivisée par 4 au niveau de celui-ci. C’est cette base de
temps qui donne le temps d’un cycle.

10
Si on utilise par exemple un quartz de 4MHz, on obtient donc 1000000 de
cycles/seconde, or, comme le pic exécute pratiquement 1 instruction par cycle, hormis les
sauts, cela vous donne une puissance de l’ordre de 1MIPS (1 Million d’Instructions Par
Seconde).

Pensez que les pics peuvent monter à 20MHz. C’est donc une vitesse de traitement
plus qu’honorable.

2- Les différentes familles des PICs

La famille des PICs est subdivisée en 3 grandes familles : La famille Base-Line, qui
utilise des mots d’instructions de 12 bits, la famille Mid-Range, qui utilise des mots de 14
bits (et dont font partie le 16F84 et 16F877), et la famille High-End, qui utilise des mots de 16
bits.

Nous nous limiterons dans cet ouvrage à la famille Mid-Range, sachant que si vous
avez tout compris, vous passerez très facilement à une autre famille, et même à un autre
microcontrôleur.

Notez dès à présent que les datasheets du 16F84 et 16F877 n’est qu’une petite partie
de la documentation complète. Pour obtenir la documentation complète, vous ajoutez encore
plus de 600 pages en téléchargeant chez Microchip les datasheets pour la gamme Mid-Range.

Cependant, la documentation de base suffit pour 99,9% des applications, et, de plus,
les datasheets Mid-Range sont disponibles sous la forme d’un fichier par chapitre.

Notez dès à présent que les PICs sont des composants STATIQUES, c’est à dire que la
fréquence d’horloge peut être abaissée jusqu’à l’arrêt complet sans perte de données et sans
dysfonctionnement. Une version –10 peut donc toujours être employée sans problème en lieu
et place d’une –04. Pas l’inverse, naturellement.
Ceci par opposition aux composants DYNAMIQUES, donc la fréquence d’horloge
doit rester dans des limites précises. N’essayez donc pas de faire tourner votre PIII/500 à
166MHz, car c’est un composant dynamique.

Nous allons traiter dans ce cours le PIC16f84 qui est le microcontroleur de base de
cette famille. Par la suite, on étudiera le 16F877 en décrivant surtout ses périphériques.

C-Le PIC 16F84:

1-Caractéristiques générales du microcontrôleur:

- Microcontrôleur 8 bits.
- Unité centrale de traitement avec une architecture RISC (Reduced Instruction
Set Computer).
- 1024 mots mémoire programme (flash).

11
- 68 octets mémoire de donnée (RAM).
- 64 octets mémoire de donnée (EEPROM).
- Bus programme (mot d’instruction) ; 14 bits.
- Bus de donnée ; 8 bits.
- 15 registres à fonction spéciale (SFR).
- 35 instructions : toutes les instructions prennent un seul cycle sauf les
branchements, ils prennent deux cycles.
- Adressage direct, indirect et relatif.
- 4 sources d'interruptions.
- Fréquence maximum d'horloge : 10Mhz.
- Temps de cycle d'instruction : 200ns.
- 13 entrées/sorties avec contrôle individuel de direction.
- Courant maximum d'entrée (par broche) : 25mA.
- Courant maximum de sortie (par broche) : 20mA.
- TMR0:8 bits temporisateurs/compteur programmable.
- Chien de garde interne avec son propre oscillateur.
- Programmation en mode série à travers deux broches (RB7 et RB6).
- Plage de tension de Vdd entre 2V et 5.5V.
- Boîtier de 18 broches (PDIP) : voir figure 1.2.

Fig1.Brochage du 16f84

2-Architecture interne:

La famille des microcontrôleurs PIC 16F8X utilise l'architecture RISC, cette architecture
permet une accessibilité séparée de la mémoire programme et celle de donnée .Par
conséquent on à deux bus : bus pour la mémoire donnée et un autre pour la mémoire
programme. L'UAL (Unité Arithmétique et Logique) est de 8 bits, elle communique avec un

12
registre de travail (W). Elle peut affecter le contenu des bits ; carry (C), digit carry (DC) et
Zéro (Z) du registre d'état (status), tout cela dépend du type d'instruction.
La figure 2 montre la structure interne du 16f84 :

Fig2.Architecture interne du 16f84

3-Organisation du 16F84

La mémoire du 16F84 est divisée en 3 parties. Page 4 du datasheet, vous trouverez la


table 1-1 qui donne un aperçu de la famille 16F8X. Les numéros de pages peuvent varier en
fonction des mises à jour de Microchip. Vous devrez peut-être chercher un peu.

Pour ceux qui veulent tout comprendre, la figure 3-1 de la page 8 montre
l’organisation interne d’un 16F84.

3.1 La mémoire programme


A
La mémoire programme est constituée de 1K mots de 14 bits. C’est dans cette zone que
vous allez écrire votre programme. Ceci explique pourquoi vos fichiers sur PC font 2Kbytes.

13
En effet, il faut 2 octets pour coder 14 bits. Ceci explique également pourquoi, lorsque
vous lisez une PIC vierge, vous allez lire des 0x3FFF. Cela donne en binaire
B’11111111111111’, soit 14 bits.

Notez à ce point qu’une instruction est codée sur 1 mot. Donc, 1K donne 1 bon millier
d’instructions possibles (c’est déjà pas si mal). Quand vous en serez à écrire des programmes
de 1K, vous serez sans aucun doute autonome pour vos applications.

Fig3.Mémoire programme et pile

3.2 La mémoire Ram

La mémoire RAM est celle que nous allons sans cesse utiliser. Toutes les données qui y
sont stockées sont perdues lors d’une coupure de courant. La mémoire RAM est organisée en
2 banques pour la 16F84. La RAM est subdivisée de plus en deux parties. Dans chacune des
banques nous allons trouver des « cases mémoires spéciales » appelées REGISTRES
SPECIAUX et des cases mémoires « libres » dont vous pouvez vous servir à votre guise.

Pour le cas du 16F84, vous disposerez de 68 octets libres. L’organisation de la RAM est
montrée dans le tableau 4-2 page 13. Vous voyez la séparation verticale en 2 banques, et tout
en bas vous voyez deux banques de 68 octets de RAM.

Malheureusement, l’indication « mapped in bank 0) vous indique qu’accéder à ces 68


octets depuis la banque 0 ou la banque 1 donne en fait accès à la même case mémoire.

Chaque registre provoque un fonctionnement spécial du PIC ou la mise en service d’une


fonction particulière. Vous remarquerez enfin que certains registres sont identiques dans les 2

14
banques (FSR par exemple). Cela signifie qu’y accéder depuis la banque 0 ou 1 ne fait pas de
différence.

Remarquez que la banque 0 utilise les adresses de 0x00 à 0x7F, la banque 1 allant de
0x80 à 0xFF (voir Fig4). Les zones en grisé sont des emplacements non utilisés (et non
utilisables). L’emplacement 0x00 est un emplacement auquel on ne peut pas accéder.

Pour la grande majorité des registres, chaque bit a une fonction spéciale. Page 14, tableau
4-1, vous trouverez les noms des bits utilisés dans ces registres.

3.3 La mémoire eeprom

La mémoire eeprom (Electrical Erasable Programmable Read Only Memory), est


constituée de 64 octets que vous pouvez lire et écrire depuis votre programme. Ces octets sont
conservés après une coupure de courant et sont très utiles pour conserver des paramètres
semi-permanents. Leur utilisation implique une procédure spéciale que nous verrons par la
suite, car ce n’est pas de la RAM, mais bien une ROM de type spécial. Il est donc plus rapide
de la lire que d’y écrire. Si vous programmez souvent des eeproms (2416) vous aurez constaté
déjà ce phénomène.

4- Les ports d’entrée/sortie


Le pic 16F84 possède deux ports d’entré/sortie dont les broches sont bidirectionnelles et qu'ils
peuvent être programmées soit en entré soit en sortie.

4-1- Le PORTA :

Le PORTA est un port bidirectionnel et qu’il possède cinq pins dont la fonction de
chacune est :
RA0 (bit 0) : broche E/S.
RA1 (bit 1) : broche E/S.
RA2 (bit 2) : broche E/S.
RA3 (bit 3) : broche E/S.
RA4 (bit 4) : broche E/S et multiplexé avec une entrée d’horloge pour TMR0.

4-2- Le PORTB:

Le PORTB est un port bidirectionnel de huit broches dont la fonction de chacune est :
RB0 (bit 0) : broche E/S ou aussi une source d’interruption externe.
RB1 (bit 1) : broche E/S.
RB2 (bit2) : broche E/S.
RB3 (bit 3) : broche E/S.
RB4 ( bit 4 ) : broche E/S.
RB5 ( bit 5 ) : broche E/S.
RB6 (bit 6) : broche E/S et entrée horloge pour la programmation série du µC.
RB7 (bit 7) : broche E/S et entrée données pour la programmation série du µC.

15
Remarques :

- Toutes les broches du PORTB possèdent des résistances à + VDD (pullups). Ces résistances
sont mises en œuvre par programmation (le bit /RBPU du registre OPTION_REG), elles sont
automatiquement désactivées quand le port est en sortie..
- Les broches RB4:RB7 peuvent générer par programmation une interruption en cas de
changement d’état.

5- Les SFR (registres à fonction spéciale):

FiG4. Mémoire dedonnées RAM et


les SFR

Les registres à fonction spéciale ou les SFR sont contenus dans la mémoire de données.
Ils sont utilisés par l'unité centrale (CPU) .L’emplacement mémoire de ces registres est donné
Dans la figure 4.Ces registres seront étudiés ultérieurement.

6- Organisation des instructions


6.1 Généralités

16
Allez, courage, cela devient de plus en plus concret. On va faire un petit survol du jeu
d’instructions des PICs. On saute directement page 55 du datasheet, au chapitre 9. Et oui,
comme cet ouvrage n’est pas un manuel de référence technique, mais un apprentissage, il faut
voir les chapitres dans le désordre.

Sur cette page, vous trouvez un petit encadré grisé qui fait allusion à deux anciennes
instructions qui ne sont plus utilisées. Nous ne nous en servirons donc pas. Par contre, vous
trouvez un tableau 9-1 qui indique comment les instructions sont codées dans le PIC. Et la,
vous voyez enfin à quoi correspondent nos 14 bits de mémoire programme.

6.2 Les types d’instructions

Il existe 4 types d’instructions :

6.2.1 Les instructions « orientées octet »

Ce sont des instructions qui manipulent les données sous forme d’octets. Elles sont codées
de la manière suivante :

- 6 bits pour l’instruction : logique, car comme il y a 35 instructions, il faut 6 bits pour
pouvoir les coder toutes

- 1 bit (d) pour indiquer si le résultat obtenu doit être conservé dans le registre de travail de
l’unité de calcul (W pour Work) ou sauvé dans l’opérande (F pour File).

- Reste 7 bits pour encoder l’opérande (File)

Aie, premier problème, 7 bits ne donnent pas accès à la mémoire RAM totale, donc voici
ici l’explication de la division de la RAM en deux banques.

En effet, il faudra bien trouver une solution pour remplacer le bit manquant. Vous avez dit
« un bit d’un des registres ? « BRAVO, vous avez tout compris. Il s’agit en réalité du bit RP0
du registre STATUS.

Ah, vous avez remarqué qu’il y a un RP1 ? Et oui, le 16F877 a 4 banques. Vous veillerez
à laisser RP1 à 0 pour la 16F84, afin de pouvoir « porter » votre programme sans problème
vers une PIC supérieure.

6.2.2 Les instructions « orientées bits »

Ce sont des instructions destinées à manipuler directement des bits d’un registre
particulier. Elles sont codées de la manière suivante :

- 4 bits pour l’instruction (dans l’espace resté libre par les instructions précédentes)

- 3 bits pour indiquer le numéro du bit à manipuler (bit 0 à 7 possible), et de nouveau 7 bits
pour indiquer l’opérande.

17
6.2.3 Les instructions générales

Ce sont les instructions qui manipulent des données qui sont codées dans l’instruction
directement. Nous verrons ceci plus en détail lorsque nous parlerons des modes d’adressage.
Elles sont codées de la manière suivante :

- L’instruction est codée sur 6 bits

- Elle est suivie d’une valeur IMMEDIATE codée sur 8 bits (donc de 0 à 255).

6.2.4 Les sauts et appels de sous-routines

Ce sont les instructions qui provoquent une rupture dans la séquence de déroulement
du programme. Elles sont codées de la manière suivante :

- Les instructions sont codées sur 3 bits

- La destination codée sur 11 bits

Nous pouvons déjà en déduire que les sauts ne donnent accès qu’à 2K de mémoire
programme (211).

Rappelez-vous que l’espace mémoire programme est de 1Kmots. Pour coder une adresse
de saut à l’intérieur de la mémoire programme, il faut donc 10 bits (210 = 1024 = 1K).

Par convention, en effet, 1Kbytes correspond à 210 = 1024 octets. Ce qui explique que si
vous avez 16K de mémoire, en réalité vous avez 16*1024 = 16384 bytes. Par extension,
1Mbyte = 1024 Kbytes, donc 1048576 octets.

Maintenant vous voyez pourquoi vous voyez plus que votre mémoire théorique lors du
test mémoire au démarrage de votre ordinateur. Une petite parenthèse qui n’a rien à voir ici :
les fabricants de disques durs considèrent que 1Mbytes = 1000000 bytes. Comme Windows
indique la taille en Mbytes de 1048576 bytes, cela vous explique pourquoi la plupart de vos
disques durs semblent plus petits que prévus.
Le tableau suivant présente les instructions de la famille 16F(C)xxx :

18
Fig5.Le jeux d’instructions de la famille 16F8xx

6.3 Les indicateurs d’état

Ces indicateurs sont indispensables pour la programmation. Il est donc absolument


nécessaire d’avoir compris leur fonctionnement (du moins pour Z et C).

Lisez donc attentivement ce qui suit. Tous les indicateurs sont des bits du registre
STATUS. Voyez le tableau page 15. Nous aborderons ici les flags Z et C. Les autres seront
traités lors de l’étude des registres.

6.3.1 L’indicateur d’état « Z »

C’est l’indicateur Zero, il fonctionne de la manière suivante :

Si le résultat d’une opération POUR LEQUEL IL EST AFFECTE, donne un résultat


égal à 0, le flag Zero passe à 1.

Donc, ne vous mélangez pas les pinceaux. Dire « si Z = 1 » correspond à dire « si


résultat = 0 ». Le tableau de la figure 5, colonne 5 vous indique les instructions qui modifient
Z.

19
Donc, si vous faites une addition avec ADDWF et que le résultat obtenu est 0, le bit Z
sera à 1. Si le résultat est <>0 (différent de 0), le bit Z vaudra 0. Dans les 2 cas il est modifié.

Par contre, si vous stockez une valeur avec l’instruction MOVWF, le bit Z ne sera pas
modifié, même si la valeur vaut 0. Ces remarques sont valables pour les autres flags.

6.3.2 L’indicateur d’état « C »

C’est l’indicateur pour Carry (report). Si le résultat d’une opération entraîne un


débordement, le bit C sera positionné. Il s’agit en fait du 9ème bit de l’opération.

Petit exemple :

Si vous ajoutez B’11111110’ (254)


+ B’00000011’ (3)
Vous obtenez B’100000001’, (257) donc 9 bits.

Comme les registres de la PIC ne font que 8 bits, vous obtiendrez B’00000001’ (1) et
C positionné à 1 (en fait le 9ème bit, donc le bit 8, donc 28 = 256). Donc le résultat final est de
256 + 1 = 257.

Remarquez que si vous aviez ajouté B’11111110’ et B’00000010’, vous auriez obtenu
B’00000000’.

Dans ce cas, vous auriez eu C à 1 ET Z à 1, ce qui signifie résultat nul, mais avec
report (donc résultat = 256).

Les autres bits du registre d’état seront vus plus loin.

7- Organisation d’un fichier « .asm »

On utilisera pour l’édition d’un fichier « .asm » l’éditeur de MPLAB. MPLAB est
l’outil logiciel gratuit fournit par MICROCHIP pour l’édition, la compilation et la simulation
d’un programme en assembleur.
Tout d’abord, cliquez n’importe où à l’intérieur d’un fichier asm quelconque. Vous
êtes à l’intérieur d’un simple traitement de texte. Dans le coin inférieur gauche, vous verrez
un numéro de ligne et de colonne. C’est la position actuelle de votre curseur. Nous nous
servirons de cette position pour vous guider. N’ajoutez donc pas de lignes pour l’instant, pour
garder la correspondance correcte avec ce texte.

Si vous n’arrivez pas à effectuer des modifications dans votre fichier, et que votre
clavier semble inactif, c’est que vous avez utilisé un caractère étendu dans le nom de votre
fichier. MPLAB est allergique à certains caractères, comme le « ç ».

7.1 Les commentaires

Au début du fichier on trouve généralement un grand cadre. Si vous remarquez


attentivement le premier caractère de chaque ligne, vous verrez le symbole « ; ». Tout ce qui

20
suit étant considéré comme zone de commentaire, vous pouvez y mettre tout ce que vous
voudrez.

Prenez l’habitude de toujours commenter vos programmes. Soyez sûr que dans 6
mois, vous ne vous rappellerez plus ce que vous avez voulu faire, les commentaires vous
seront alors d’une grande utilité si vous décidez de modifier votre programme.On prendra
l’exemple du fichier <<Ledcli.asm>> qui fera le sujet de notre premier programme.

7.2 Les directives

A la ligne 8, nous trouvons une DIRECTIVE destinée à MPASM pour indiquer quel
type de processeur est utilisé dans ce programme.

Les DIRECTIVES ne font pas partie du programme, elles ne sont pas traduites en
OPCODE, elles servent à indiquer à l’assembleur de quelle manière il doit travailler. Ce sont
donc des COMMANDES destinées à l’assembleur en lui-même.

Au contraire, les INSTRUCTIONS seront traduites en OPCODE et chargées dans le


PIC. Il est donc impératif de bien faire la distinction.

7.3 les fichiers « include »

La ligne 9 signale à l’assembleur que les ASSIGNATIONS sont dans le fichier


P16F84.inc. Que contient ce fichier ? Et bien tout simplement la valeur de toutes les
CONSTANTES que nous allons utiliser. Pour voir ce qu’il contient, allez dans le menu
« file ->Open », choisissez « all files » dans le cadre inférieur, et ouvrez p16F84.inc. Une fois
dépassée la zone de commentaires, vous verrez des lignes du style :

FSR EQU H'0004'

Cette ligne signifie tout simplement que FSR EGAL 0x0004. Autrement dit, lorsque
vous utiliserez FSR dans une instruction, MPASM interprétera FSR comme étant 0x04. 0x04
étant tout simplement l’adresse de FSR dans la mémoire du PIC.

H’0004’ est une autre méthode autorisée pour exprimer un nombre hexadécimal, tout
comme 04h

Si vous prenez votre tableau 4-2 page 13, vous constaterez que c’est bien le cas. Ce
fichier est donc principalement destiné à vous éviter d’avoir à mémoriser toutes les adresses,
un nom est bien plus simple à utiliser. Fermez le fichier p16F84.inc pour ne pas encombrer
votre fenêtre.

7.4 La directive _CONFIG

La ligne suivante, commence par « __CONFIG ». Cette ligne contient les fameux
« fusibles » qui fixent le fonctionnement du PIC.

Les valeurs écrites ici seront intégrées dans le fichier « .hex » pour signaler au
programmateur les valeurs à encoder aux adresses spécifiques du PIC. Nous y reviendrons.

21
On trouve dans le fichier toutes les valeurs possibles de ces paramètres, avec les
explications correspondantes. Il suffit de remplacer une des valeurs par celle souhaitée.
Par exemple, activons le Code Protect (protection en lecture) :

On remplacera donc simplement la ligne :

__CONFIG _CP_OFF & _WDT_ON & _PWRTE_ON & _HS_OSC

Par

__CONFIG _CP_ON & _WDT_ON & _PWRTE_ON & _HS_OSC

Faites-le. Remarquez que les différentes valeurs sont liées par le symbole « & »
(AND). Ils fonctionnent donc en plaçant des bits à « 0 », si vous avez tout suivi. Les valeurs
exactes sont de nouveau dans le fichier « P16F84.INC ».

7.5 Les assignations

A la ligne 30, vous trouverez des ASSIGNATIONS personnelles qui fonctionnent


selon le même principe que dans le fichier « .inc ».

A quoi cela sert-il ? Et bien à faciliter la MAINTENANCE de votre programme. Il est


en effet plus simple de retenir dans votre programme la valeur « MASQUE » que de
manipuler la valeur 0x5B.

Les assignations se comportent comme une simple substitution. Au moment de


l’assemblage, chaque fois que l’assembleur va trouver une assignation, il la remplacera
automatiquement par sa valeur.

Un autre avantage est que si vous remplacez la valeur d’une assignation, le


changement sera effectif pour tout le programme. Vous ne risquez donc pas d’oublier des
valeurs en chemin.

Il est vivement conseillé d’utiliser les ASSIGNATIONS et autres méthodes que nous
allons voir plus bas. La syntaxe est simple puisqu’il s’agit de EQU (égal à)
Exemple d’assignation :

mavaleur EQU 0x05

7.6 Les définitions

Descendons encore un peu. Nous découvrons, lignes 38 et 39 des exemples de


DEFINE. Sachez que les « define » fonctionnent comme des ASSIGNATIONS. A ceci près
que nous réserverons les assignations pour les valeurs, et les définitions pour remplacer un
texte plus complexe.

Par exemple nous pourrons utiliser un PORT suivi d’un numéro de bit, ou bien
carrément une instruction avec ses paramètres.

22
Une définition est construite de la manière suivante : La directive #DEFINE, suivie
par le nom que l’on désire utiliser, puis la chaîne à substituer. Par exemple :

#DEFINE monbit PORTA, 1

7.7 Les macros

Plus bas, lignes 46 à 52, nous trouvons les MACRO.


La macro se compose d’un nom écrit en première colonne, suivi par la directive « macro ».
Commence alors à la ligne suivant la portion de code qui constitue la macro. La fin de la
macro est définie par la directice « endm) (end of macro).

Une macro remplace donc un morceau de code que nous utilisons souvent. La macro
fonctionne également uniquement comme un simple traitement de texte.

La macro simplifie donc l’écriture, mais ne raccourci pas la taille du fichier .hex
obtenu, puisque les 2 lignes seront écrites dans le PIC.

Notez que l’on peut utiliser des macros plus complexes, avec passage de paramètres,
mais nous n’entrerons pas dans ces fonctions particulières pour l’instant.

Notez également que vous disposez d’une aide dans le menu « help->MPASM Help ».
En effet, l’aide de MPLAB concerne l’utilisation du logiciel. Les aides concernant le langage
sont dans MPASM, puisque c’est ce langage que MPLAB utilise (revoyez l’édition des
nœuds).

7.8 La zone des variables

Toute zone définie par l’utilisateur commence avec la DIRECTIVE CBLOCK, suivie
par l’adresse du début de la zone.

Pour placer nos variables, qui sont des emplacements mémoires auxquels on a donné
un nom, nous consultons de nouveau le tableau 4-2. Nous voyons que la zone RAM librement
utilisable commence à l'adresse 0x0C. Notre zone de variable contiendra donc la directive

CBLOCK 0x00C ; début de la zone variables

Ensuite, vous pouvez utiliser 68 emplacements mémoire, qui répondront à la syntaxe


suivante : nom de la variable suivi du signe « : » suivi de la taille utilisée.
Par exemple :

w_temp :1 ; Zone de 1 byte


montableau : 8 ; zone de 8 bytes

Ensuite, vous devrez préciser la fin de la zone en cours à l’aide de la directive :

ENDC ; Fin de la zone

23
7.9 Les étiquettes

Vous trouverez dans les programmes en 1ere colonne ce que nous appellerons des
ETIQUETTES. Ce sont des noms que vous choisissez et qui sont des REPERES pour le
programme.

L’assembleur les remplacera par l’adresse du programme à l’endroit où elles sont


positionnées. Ceci vous évite de devoir calculer les emplacements programme. Nous en
verrons plus loin le principe.

7.10 La directive « ORG »

La directive ORG, suivie de l’adresse, précise à quelle adresse les instructions qui
suivent seront placées dans le PIC. Il est important de savoir 2 choses :

- Après un reset ou une mise sous tension, le PIC démarre toujours à l’adresse 0x00. Le
début de votre programme doit donc se situer là.

- L’adresse 0x04 est l’adresse utilisée par les interruptions (nous verrons le principe plus
tard). Il ne vous reste donc pas une grande place pour placer votre programme. Nous
commencerons donc par un saut vers l’emplacement du programme principal où nous
aurons plus de place. Allons donc voir ligne 70 comment tout ceci fonctionne :

org 0x000 ; Adresse de départ après reset


goto init ; Adresse 0: initialiser

La première ligne est une DIRECTIVE qui indique que la ligne suivante sera placée à
l’adresse 0x00.

La seconde ligne est une INSTRUCTION, expliquée page 62 du datasheet, qui indique
au PIC que le programme doit SAUTER à l’adresse « init ». « init » est une ETIQUETTE.

Après le reset, le PIC exécute donc l’instruction goto init qui se trouve à l’adresse
0x00, suivie par l’instruction qui se trouve à l’adresse init plus bas dans le programme (donc
juste en dessous de l’étiquette init).

7.11 La directive « END »

Cette directive précise l’endroit où doit cesser l’assemblage de votre programme. Elle
est obligatoire dans tout programme, sous peine d’une erreur qui vous signalera que la fin de
fichier (End Of File) a été atteinte avant de rencontrer la directive END.

Toutes les instructions situées après la directive END seront tout simplement ignorées.

7.12 Explication des registres fondamentaux

Vous voici prêt à lancer une simulation. Mais à quoi cela pourrait-il vous servir si vous
ne comprenez pas les changements qui vont s’opérer dans les registres spéciaux ? On va donc

24
commencer par vous expliquer les registres de base nécessaires à la compréhension du
processus.

7.12.1 Les registres « PCL » et « PCLATH »

Un processeur, quel qu’il soit est un composant qui exécute SEQUENTIELLEMENT une
série d’INSTRUCTIONS organisées selon un ensemble appelé PROGRAMME.

Il existe donc dans le processeur un SEQUENCEUR, c’est à dire un compteur qui permet
de pointer sur la PROCHAINE instruction à exécuter. Ce séquenceur est appelé suivant les
processeurs « compteur ordinal », « Pointeur de programme » etc. Dans le cas des PICs, il
s’appelle PC, pour Program Counter. Le PC n’est pas accessible directement par l’utilisateur.

Le principe de base est toujours le même. Dans les PICs, les registres ne font que 8 bits,
on ne peut donc stocker qu’une adresse maximale de 255. Il faudra donc 2 registres pour
accéder à une adresse. Les PICs ont un fonctionnement un peu particulier à ce sujet.

Nous trouvons tout d’abord un registre qui contient l’adresse basse du PC, c’est à dire les
8 bits de poids faibles. Ce registre est accessible en lecture et en écriture. Il est appelé PCL
(PC Low)

Il existe un autre registre de 5 bits qui participe au fonctionnement du séquenceur. Il


s’appelle PCLATH (PC LATch counter High). Il est accessible en lecture et en écriture par
l’utilisateur.

Le PC complet étant codé sur 13 bits, il faudra donc compléter PCL avec 5 bits
supplémentaires. Il existe deux cas possibles :

- Lors d’un saut, par exemple, le contenu du PC est chargé directement avec les 11 bits de
destination contenus dans l’instruction en elle-même. Les 2 bits manquants sont extraits
du registre PCLATH. Les bits 3 et 4, qui doivent être positionnés par l’utilisateur, sont
placés directement dans les bits 11 et 12 du PC afin de compléter l’adresse de destination.
Comme la 16F84 ne gère que 1K de mémoire programme, nous n’aurons pas besoin de ce
registre dans le cas des sauts. Le 16F84 ne gère que 10 des 13 bits du PC.

- En cas de modification du PCL directement par l’utilisateur, comme pour un registre


ordinaire, PCL est chargé dans PC et complétés par les 5 bits du registre PCLATH.
Comme le 16F84 ne traite que 1K de mémoire programme, les bits b2, b3 et b4 de
PCLATH seront inutilisés ici.

Remarquez que la limite du PC est de 13 bits, ce qui implique que les PICs de la
famille mid-range auront une capacité de mémoire programme de 8K mots maximum (soit
213).

Il est très important de se rappeler que le PC pointe toujours sur l’instruction suivante,
donc l’instruction qui n’est pas encore exécutée. C’est indispensable de bien comprendre ceci
pour analyser les programmes en cours de debbuggage.

25
7.12.2 Le registre « W »

Ce registre est un registre utilisé par les pics pour réaliser toutes sortes de calculs. Dans
une instruction la destination d’un résultat (d) peut en général être un emplacement RAM (f)
ou le registre de travail (w). C’est un donc un registre fondamental.

7.12.3 Le registre « STATUS »

C’est un registre dont chaque bit a une signification particulière. Il est principalement
utilisé pour tout ce qui concerne les tests. Il est donc également d’une importance
fondamentale. Il est décrit dans le tableau de la page 15 du datasheet..

Voici les différents bits qui le composent, en commençant par le bit0 (b0), donc le bit le
plus à droite, ou encore le moins significatif. Remarquez qu’on utilise le terme LSB, parfois
comme byte le moins significatif, parfois comme bit le moins significatif. C’est également un
abus de langage, mais le contexte permet très bien de les distinguer.

b0 : C Carry (report) Ce bit est en fait le 9ème bit d’une opération.


Par exemple, si une addition de 2 octets donne une valeur
>255 (0xFF), ce bit sera positionné.
b1 : DC Digit Carry Ce bit est utilisé principalement lorsque l’on travaille
avec nombres BCD : il indique un report du bit 3 vers le
bit 4. Pour info, un nombre BCD est un nombre dont
chaque quartet représente un chiffre décimal. Nous
n’aborderons pas ce principe ici.
b2 : Z Zero Ce bit est positionné à 1 si le résultat de la dernière
opération vaut 0. Rappelez-vous cependant que ces flags
ne sont positionnés que pour les instructions qui le
précisent (Status bit affected).
b3 : PD Power down Indique quel événement a entraîner le dernier arrêt du
PIC (instruction sleep ou dépassement du temps du
watchdog). Nous y reviendrons plus tard. En réalité, vous
verrez que PD est surmonté d’une petite barre qui
signifie : actif à l’état bas. Donc que 0 = bit validé.
Les inversions sont en italique
b4 : TO Time-Out bit Ce bit indique (si 0), que la mise en service suit un arrêt
provoqué par un dépassement de temps ou une mise en
sommeil. Dans ce cas, PD effectue la distinction.
b5 : RP0 Register Bank Select0 Permet d’indiquer dans quelle banque de RAM on
travaille.0 = banque 0.
b6 : RP1 Register Bank Select1 Permet la sélection des banques 2 et 3. Inutilisé pour la
16F84, doit être laissé à 0 pour garantir la compatibilité
ascendante (portabilité du programme).
B7 : IRP Indirect RP Permet de décider quelle banque on adresse dans le cas
de l’adressage indirect (que nous verrons plus tard).

26
8- Les modes d’adressage

Les instructions utilisent toutes une manière particulière d’accéder aux informations
qu’elles manipulent. Ces méthodes sont appelées « modes d’adressage ».

On va simplement donner un petit exemple concret de ce qu’est chaque mode


d’adressage. Supposons que vous vouliez mettre de l’argent dans votre poche :

8.1 L’adressage littéral ou immédiat

Avec l’ ADRESSAGE IMMEDIAT ou ADRESSAGE LITTERAL, vous pouvez dire : ‘on


mets 100D en poche’. La valeur fait IMMEDIATement partie de la phrase. Pas besoin d’un
autre renseignement.

Exemple

Movlw 0x55 ; charger la valeur 0x55 dans W

8.2 L’adressage direct

Avec l’ ADRESSAGE DIRECT, vous pouvez dire : on va mettre le contenu du coffre


numéro 10 dans notre poche. Ici, l’emplacement contenant la valeur utile est donné
DIRECTement dans la phrase. Mais il faut d’abord aller ouvrir le coffre pour savoir ce que
l’on va effectivement mettre en poche. On ne met donc pas en poche le numéro 10, mais ce
qu’il contient.

Exemple

Movf 0x10 , W ; charger le contenu de l’emplacement 0x10 dans W

8.3 L’adressage indirect

Avec l’ ADRESSAGE INDIRECT, vous pouvez dire :

Le préposé du guichet numéro 3 va me donner le numéro du coffre qui contient la


somme qu’on va mettre en poche.

Ici, vous obtenez le numéro du coffre INDIRECTement par le préposé au guichet.


Vous devez donc allez demander à ce préposé qu’il vous donne le numéro du coffre que vous
irez ouvrir pour prendre l’argent. On ne met donc en poche, ni le numéro du préposé, ni le
numéro du coffre que celui-ci va vous donner. Il y a donc 2 opérations préalables avant de
connaître la somme que vous empocherez.

Cet adressage fait appel à 2 registres, dont un est particulier, car il n’existe pas vraiment.
Examinons-les donc :

27
8.3.1 Les registres FSR et INDF

Ceux qui suivent sont déjà en train de chercher dans le tableau 4-2 après INDF.

INDF signifie INDirect File. Vous le voyez maintenant ? Et oui, c’est le fameux
registre de l’adresse 0x00. Ce registre n’existe pas vraiment, ce n’est qu’un procédé d’accès
particulier à FSR utilisé par le PIC pour des raisons de facilité de construction électronique
interne.

Le registre FSR est à l’adresse 0x04 dans les 2 banques. Il n’est donc pas nécessaire de
changer de banque pour y accéder, quelle que soit la banque en cours d’utilisation.

Dans l’exemple schématique précédent, le préposé au guichet, c’est le registre FSR.


L’adressage indirect est un peu particulier sur les PICS, puisque c’est toujours à la même
adresse que se trouvera l’adresse de destination. Comment cela se passe-t-il ?

- Premièrement, nous devons écrire l’adresse pointée dans le registre FSR.


- Ensuite, nous accédons à cette adresse pointée par le registre INDF.

On peut donc dire que INDF est en fait le registre FSR utilisé pour accéder à la case
mémoire. Donc, quand on veut modifier la case mémoire pointée, on modifie FSR, quand on
veut connaître l’adresse de la case pointée, on accède également à FSR. Si on veut accéder au
CONTENU de la case pointée, on accède via INDF. Nous allons voir tout ceci par un petit
exemple, mais avant,

ATTENTION

Le contenu du registre FSR pointe sur une adresse en 8 bits. Or, sur certaines PICs, la
zone RAM contient 4 banques (16F877). L’adresse complète est donc une adresse sur 9 bits.
L’adresse complète est obtenue, en adressage DIRECT, par l’ajout du bit 7 et 8 sous forme de
RP0¨et RP1 (RP1 est inutilisé pour le 16F84 car seulement 2 banques) et par l’ajout du bit
IRP dans le cas de l’adressage INDIRECT (inutilisé sur le 16F84). Veillez donc à toujours
laisser IRP (dans le registre STATUS) et RP1 à 0 pour assurer la portabilité de votre
programme.

Exemple

movlw 0x50 ; chargeons une valeur quelconque


movwf mavariable ; et plaçons-la dans la variable « mavariable »

movlw mavariable ; on charge l’ADRESSE de mavariable, par


; exemple, dans les leçons précédentes, c’était
; 0x0e. (W) = 0x0E
movwf FSR ; on place l’adresse de destination dans FSR.
; on dira que FSR POINTE sur mavariable
movf INDF,w ; charger le CONTENU de INDF dans W.

LE CONTENU DE INDF EST TRADUIT PAR LE PIC COMME ETANT LE


CONTENU DE L’EMPLACEMENT MEMOIRE POINTE PAR FSR (W) = 0X50

28
8.4 Quelques exemples

On va répéter, mais les modes d’adressages doivent impérativement être compris. Pour
les habitués des processeurs divers, excusez ces répétitions. Les registres sont intialisés avec
les valeurs précédentes.

movlw mavariable

C’est de l’adressage immédiat ou littéral ; donc on charge la VALEUR de mavariable,


ce qui correspond en réalité à son ADRESSE. Donc 0x0E est placé dans (W). Ceci se
reconnaît au « l » de l’instruction movlw

movf mavariable , w

Cette fois, c’est de l’adressage DIRECT, donc, on va à l’adresse mavariable voir ce


qu’il y a à l’intérieur. On y trouve le CONTENU de mavariable, donc (w) = 0x50 (dans notre
exemple).

movf INDF , w

Maintenant, c’est de l’adressage INDIRECT. Ce mode d’adressage se reconnaît


immédiatement par l’utilisation du registre INDF. Le PIC va voir dans le registre FSR, et lit
l’adresse contenue, dans ce cas 0X0E. Elle va ensuite dans l’emplacement visé, et lit le
CONTENU. Donc, dans (W) on aura le contenu de 0x0E, soit 0x50.

movf FSR , w

Ceci est un piège. C’est en effet de l’adressage DIRECT. On placera donc dans (W) le
CONTENU du registre FSR, donc 0X0E sera mis dans (W).

9- Réalisation d’un programme embarqué


9.1 Edition du fichier source

Complétez le cadre d’en-tête suivant votre désir. Vous trouverez ci-dessous un


exemple. Prenez l’habitude de toujours documenter vos programmes. Ce n’est pas un luxe,
c’est impératif pour une maintenance efficace dans le temps.

;*********************************************************************************
; PROGRAMME DE CLIGNOTEMENT D'UNE LED CONNECTEE SUR LE PORTA.2 *
; D'UN PIC16F84. PROGRAMME D'ENTRAINEMENT AU FONCTIONNEMENT *
; DES PICS.LA FREQUENCE DE CLIGNOTTEMENT EST DE 1 HZ (avec un quartz de 4MHz)*
;*********************************************************************************

9.2 Choix de la configuration

Plus bas dans le fichier, vous trouverez ceci :

__CONFIG _CP_OFF & _WDT_ON & _PWRTE_ON & _XT_OSC

29
; '__CONFIG' précise les paramètres encodés dans le processeur au moment de
; la programmation du processeur. Les définitions sont dans le fichier include.
; Voici les valeurs et leurs définitions :

; _CP_ON Code protection ON : impossible de relire


; _CP_OFF Code protection OFF
; _PWRTE_ON Timer reset sur power on en service
; _PWRTE_OFF Timer reset hors-service
; _WDT_ON Watch-dog en service
; _WDT_OFF Watch-dog hors service
; _LP_OSC Oscillateur quartz basse consommation
; _XT_OSC Oscillateur quartz moyenne vitesse ou externe
; _HS_OSC Oscillateur quartz grande vitesse
; _RC_OSC Oscillateur à réseau RC
On inclus les commentaires dans le fichier de façon à ce qu’il soit plus rapidement
modifiables sans devoir recourir au datasheet.

Remarquez qu’on effectue un AND (&) entre les différentes valeurs, les niveaux actifs
sont donc des niveaux 0

Le premier paramètre précise si votre PIC sera protégée ou non contre la lecture à la
fin de la programmation. Laissez ici ce paramètre sur « CP_OFF » = non protégée.

Le second paramètre précise si le « chien de garde » (watchdog) est mis ou non en


service. Dans un premier temps, remplacez WDT_ON par WDT_OFF pour le mettre hors-
service.

Ensuite, laissez PWRTE sur ON pour préciser que vous utilisez un reset « sécurisé »,
donc avec un allongement du temps avant démarrage. Ceci vous met à l’abri des alimentations
un peu lentes à démarrer.

Enfin, vient le fonctionnement de l’oscillateur que vous allez utiliser. Le tableau 8-1
page 40 donne les valeurs recommandées en fonction des fréquences utilisées pour un PIC de
10MHz. Retenez que la valeur _HS_OSC convient pour les fréquences élevées. Sinon utiliser
XT_OSC pour les fréquences ≤ 4MHz.
Il est important de ne pas utiliser _RC_OSC si on utilise un quartz. Ce paramètre est
réservé à un fonctionnement par réseau R/C tel que dessiné figure 8-7 page 41.

LE FAIT D’UTILISER LE PARAMETRE « RC » AVEC UNE HORLOGE


EXTERNE PEUT ENTRAINER LA DESTRUCTION DU PIC.

Même, si en pratique, les PICs sont des composants très solides, évitez de vous
tromper à ce niveau. Et voilà, vous connaissez parfaitement _Config. Vous avez maintenant la
ligne suivante :

__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC

30
9.3 Le registre OPTION

Si vous regardez le tableau 4-2, vous constaterez que ce registre se trouve à l’adresse
0x81, donc dans la banque1. Dans les fichiers include de MPLAB, ce registre est déclaré avec
le nom OPTION_REG.

C’est donc ce nom que vous devrez utiliser. Nous allons le détailler ici. Ce registre est un
registre de bits, c’est à dire que chaque bit a un rôle particulier :
Le tableau de la page 16 représente le contenu de ce registre :

b7 : RBPU

Quand ce bit est mis à 0 (actif niveau bas en italique), une résistance de rappel au +5
volt est placée sur chaque pin du PORTB.

b6 : INTEDG

Donne, dans le cas où on utilise les interruptions sur RB0, le sens de déclenchement de
l’interruption. Si b6 = 1, on a interruption si le niveau sur RB0 passe de 0 vers 1. Si b6 = 0,
l’interruption s’effectuera lors de la transition de 1 vers 0.

b5 : TOCS

Ce bit détermine le fonctionnement du timer0, que nous verrons bientôt. Retenez que
le timer0 est incrémenté soit en fonction de l’horloge interne (synchronisé au programme),
dans ce cas b5 = 0, soit il compte les impulsions reçues sur la pin RA4, dans ce cas b5=1.

Comme ce dernier mode nécessite un circuit de génération de pulses externe, nous


utiliserons pour le timer0 l’horloge interne, donc b5 = 0

b4 : TOSE

Donne, pour le cas ou le bit 5 serait 1, le sens de la transition qui détermine le


comptage de tmr0. Si b4 = 1, on a comptage si le signal passe de 5V à 0V sur RA4, si on a b4
= 0, ce sera le contraire.

Comme nous avons placé b5=0, b4 est alors inutilisé. Nous laisserons donc b4 = 0.

b3 : PSA

Nous avons dans le PIC un prédiviseur. Qu’est-ce que c’est ? Et bien tout simplement,
ceci indique le nombre de pulses qui devra être reçu pour provoquer une incrémentation de la
destination. Nous y reviendrons en détail avec le fonctionnement du tmr0.

A ce niveau, sachez simplement que ce prédiviseur peut servir à une des deux
fonctions suivantes (et pas les deux) : soit il effectue une prédivision au niveau du timer du
watchdog (b3 = 1), soit il effectue une prédivision au niveau du tmr0 (timer0) (b3=0). Dans
notre cas, mettez b3 = 1 (nous verrons ci-dessous pourquoi).

31
b2, b1,b0 : PS2,PS1,PS0

Ces trois bits déterminent la valeur de prédivision pour le registre déterminé ci-dessus. Il y
a donc 8 valeurs possibles, montrées dans le petit tableau de la page 16.

Remarquez que les valeurs sont différentes pour le watchdog et pour tmr0. En effet, il n’y
a pas de ‘division par 1’ pour ce dernier registre.

Si vous désirez ne pas utiliser de prédiviseur du tout, la seule méthode est de mettre b3=1
(prédiviseur sur watchdog) et PS2 à PS0 à 0. Dans ce cas : pas de prédiviseur sur tmr0, et
prédiviseur à 1 sur watchdog, ce qui correspond à pas de prédiviseur non plus. Nous mettrons
donc b2=b1=b0= 0.

9.4 Edition du programme

Nous utiliserons donc la valeur B’00001000’ pour notre programme d’essai, soit 0x08.
Il faut avoir l’habitude de ne pas traîner des valeurs fixes à travers mes programmes, afin d’en
faciliter la maintenance. On place ces valeurs en début de programme en utilisant des
assignations.

L’assignation est déjà créée plus bas dans le programme. On a créé une CONSTANTE
qu’on a appelé OPTIONVAL et qui contiendra la valeur à placer plus tard dans le registre
OPTION_REG. On rappelle que les CONSTANTES n’occupent pas de place dans le PIC,
elles sont simplement remplacées par l’assembleur au moment de la compilation. Elles
servent à faciliter la lecture du programme.

Cherchez donc plus bas dans le programme après les assignations, et remplacez la
valeur affectée à OPTIONVAL par celle que nous avons trouvée et ajoutez vos commentaires.
Supprimez l’assignation concernant INTERMASK, car nous ne nous servirons pas des
interruptions dans ce premier programme. Dans la zone des assignations, il vous reste donc
ceci :

;*********************************************************************
; ASSIGNATIONS *
;*********************************************************************

OPTIONVAL EQU H'0008 ; Valeur registre option


; Résistance pull-up ON
; Pas de préscaler

Descendons encore jusqu’à la zone des définitions. Nous allons donner un nom à notre
bouton-poussoir et à notre LED. Les instructions bcf et bsf que nous allons utiliser pour
mettre ou lire des 1 ou des 0 dans les registres ont la syntaxe suivante bsf f, n et comme le
registre d’accès s’appelant PORTA (pour le port A) et PORTB (pour le port B), nous
utiliserons des DEFINE permettant d’intégrer f et n en même temps.

32
Nous voyons sur le schéma que la LED est connectée sur le bit 2 du port A. Le
bouton-poussoir est connecté sur le bit 2 du port B. Nous effaçons donc les définitions de
l’exemple, et nous les remplaçons par les nôtres. Nous obtenons alors ceci :
;*********************************************************************
; DEFINE *
;*********************************************************************

#DEFINE LED PORTA,2 ; Led rouge


#DEFINE BOUTON PORTB,2 ; bouton-poussoir

Notez que LED et BOUTON sont des noms que nous avons librement choisis, à
condition qu’il ne s’agisse pas d’un mot-clé. Pas question par exemple d’utiliser STATUS ou
encore MOVLW, bien que ces exemples soient tirés par les cheveux, cela pourrait vous arriver
un jour d’utiliser un mot réservé par inadvertance.

A quoi servent les définitions ? Et bien supposons que vous décidez de connecter la
LED sur le PORTB bit 1 (RB1), par exemple. Et bien, nul besoin de rechercher partout dans
le programme, il suffira de changer dans la zone DEFINE.

On descend encore un peu, et on arrive dans la zone des macros. Nous n’en avons pas
vraiment besoin ici, mais nous allons quand même les utiliser à titre d’exemple.
Effacez la macro donnée à titre d’exemple et entrons celles-ci.

;*********************************************************************
; MACRO *
;*********************************************************************

LEDON macro
bsf LED
endm

LEDOFF macro
bcf LED
endm

La première colonne donne le nom de la macro (ici, 2 macros, une LEDON et une
LEDOFF). La directive macro signifie ‘début de la macro’ la directive endm signifie ‘fin de la
macro’. Notez que les macros peuvent évidemment comporter plusieurs lignes de code.

Prenons notre exemple : quand nous utiliserons la ligne suivante dans notre
programme (attention, ne pas mettre la macro en première colonne) :

LEDON

Au moment de la compilation, notre assembleur remplacera LEDON par :

bsf LED

Il remplacera également LED par PORTA,2. Ce qui fait qu’en réalité nous obtiendrons :

33
bsf PORTA , 2

Nous avons donc obtenu une facilité d’écriture et de maintenance. Gardez à l’esprit
que les macros sont des simples substitutions de traitement de texte. Si votre macro se
compose de 50 lignes de code, les 50 lignes seront copiées dans le PIC à chaque appel de la
macro.
Nous arrivons dans la zone des variables. Nous ajouterons celles-ci au fur et à mesure
de leur nécessité. Effacez donc les 2 variables présentes, car elles sont utilisées dans les
routines d’interruption que nous n’utiliserons pas ici.

;*********************************************************************
; DECLARATIONS DE VARIABLES *
;*********************************************************************

CBLOCK 0x00C ; début de la zone variables

ENDC ; Fin de la zone

A l’ORG 0x00, laissons l’appel vers la routine d’initialisation. Tout programme


comporte en effet une étape d’initialisation des variables et des registres. Prenez l’habitude de
séparer cette initialisation du reste du programme.

Comme nous n’utiliserons pas les interruptions, supprimez tout ce qui suit jusqu’à la routine
d’initialisation, vous obtenez :

**********************************************************************
; DEMARRAGE SUR RESET *
;**********************************************************************

org 0x000 ; Adresse de départ après reset


goto init ; Adresse 0: initialiser

;*********************************************************************
; INITIALISATIONS *
;*********************************************************************
suite du programme

A ce stade, avant de poursuivre, nous allons étudier les registres dont nous allons nous
servir, et tout d’abord :

9.5 Le registre PORTA

Ce registre est un peu particulier, puisqu’il donne directement accès au monde extérieur.
C’est en effet ce registre qui représente l’image des pins RA0 à RA4, soit 5 pins. Si vous
suivez toujours, c’est ce registre qui va servir à allumer la LED.

Ce registre se situe à l’adresse 05H, dans la banque0. Chaque bit de ce registre représente
un pin. Donc, seuls 5 bits sont utilisés. Pour écrire sur un pin en sortie, on place le bit
correspondant à 1 ou à 0, selon le niveau souhaité.

34
Par exemple :
bsf PORTA , 1 ; envoyer niveau 1 sur RA1

place un niveau +5V sur la pin RA1. Notez qu’il faut pour cela que cette pin soit
configurée en sortie (voir TRISA). Pour tester une entrée, on pourra par exemple utiliser

btfss PORTA,3 ; tester RA3 et sauter si vaut 5V

9.6 Le registre TRISA

Ce registre est situé à la même adresse que PORTA, mais dans la banque 1. Son adresse
complète sur 8 bits est donc 0x85.

Ce registre est d’un fonctionnement très simple et est lié au fonctionnement du PORTA.

Chaque bit positionné à 1 configure le pin correspondant en entrée. Chaque bit à 0


configure le pin en sortie.

Au reset du PIC, tous les pins sont mis en entrée, afin de ne pas envoyer des signaux non
désirés sur les pins. Les bits de TRISA seront donc mis à 1 lors de chaque reset.
Notez également que, comme il n’y a que 5 pins utilisées sur le PORTA, seuls 5 bits
(b0/b4) seront utilisés sur TRISA.

9.7 Les registres PORTB et TRISB

Ces registres fonctionnent exactement de la même manière que PORTA et TRISA, mais
concernent bien entendu les 8 pins RB. Tous les bits sont donc utilisés dans ce cas.

Voyons maintenant les particularités du PORTB. Nous en avons déjà vu une, puisque
les entrées du PORTB peuvent être connectées à une résistance de rappel au +5V de manière
interne.

La sélection s’effectuant par le bit 7 du registre OPTION. Le schéma interne visible


figures 5-3 et 5-4 page 23 (datasheet) vous montre que les bits b0 et b4/b7 peuvent être
utilisés comme source d’interruption, le bit 0 peut de plus être utilisé de manière autonome
pour générer un autre type d’interruption.

Note :

Après un reset, vous vous demandez peut-être quel est l’état de tel ou tel registre.
Vous trouverez ces explications dans le tableau de la page 14. Vous voyez qu’après un reset, le
registre OPTION_REG a tous ses bits à 1. Vous devez donc spécifier l’effacement du bit7
pour valider les résistances de rappel au +5V.

9.8 Finalisation du programme

Tout d’abord, il nous faut une routine de temporisation :

35
;*********************************************************************
; SOUS-ROUTINE DE TEMPORISATION *
;*********************************************************************
;---------------------------------------------------------------------
; Cette sous-routine introduit un retard de 500.000 µs.
; Elle ne reçoit aucun paramètre et n'en retourne aucun
;---------------------------------------------------------------------
tempo
movlw 2 ; pour 2 boucles
movwf cmpt3 ; initialiser compteur3
boucle3
clrf cmpt2 ; effacer compteur2
boucle2
clrf cmpt1 ; effacer compteur1

boucle1
nop ; perdre 1 cycle
decfsz cmpt1 , f ; décrémenter compteur1
goto boucle1 ; si pas 0, boucler
decfsz cmpt2 , f ; si 0, décrémenter compteur 2
goto boucle2 ; si cmpt2 pas 0, recommencer boucle1
decfsz cmpt3 , f ; si 0, décrémenter compteur 3
goto boucle3 ; si cmpt3 pas 0, recommencer boucle2
return ; retour de la sous-routine

Le programme principal est composé de 5 instructions seulement :

;*********************************************************************
; PROGRAMME PRINCIPAL *
;*********************************************************************

DEBUT
bsf STATUS,RP0
clrf TRISA ; port A en sortie
bcf STATUS,RP0
LEDON ; allumer la LED :
call tempo ; appeler la tempo de 0.5s
LEDOFF ; éteindre LED
call tempo ; appeler la tempor de 0.5s
goto DEBUT ; boucler
END ; directive fin de programme

10- Les interruptions

10.1 Qu’est-ce qu’une interruption ?

Imaginez une conversation normale. Chaque interlocuteur prend la parole quand vient son
tour de parler. Survient alors un événement extérieur dont le traitement est urgent. Par
exemple, un piano tombe du 3ème étage de l’immeuble au pied duquel vous discutez. Vous
imaginez bien que votre interlocuteur ne va pas attendre la fin de votre phrase pour vous

36
signaler le danger. Il va donc vous INTERROMPRE durant le cours normal de votre
conversation afin de pouvoir TRAITER IMMEDIATEMENT l’EVENEMENT extérieur.
Les interlocuteurs reprendront leur conversation où elle en était arrivée, sitôt le danger écarté.

Et bien, pour les programmes, c’est exactement le même principe. Votre programme se
déroule normalement. Survient un événement spécifique. Le programme principal est
interrompu (donc, subit une INTERRUPTION), et va traiter l’événement, avant de reprendre
le programme principal à l’endroit où il avait été interrompu.

L’interruption est donc une RUPTURE DE SEQUENCE ASYNCHRONE, c’est à dire


non synchronisée avec le déroulement normal du programme.

Vous voyez ici l’opposition avec les ruptures de séquences synchrones, provoquées par le
programme lui-même (goto, call, btfss…).

10.2 Mécanisme général d’une interruption

Nous pouvons dire, sans nous tromper de beaucoup, qu’une routine d’interruption est un
sous-programme particulier, déclenché par l’apparition d’un événement spécifique. Cela a
l’air un peu ardu, mais vous allez voir que c’est très simple.

Voici donc comment cela fonctionne :

- Le programme se déroule normalement


- L’événement survient
- Le programme achève l’instruction en cours de traitement
- Le programme saute à l’adresse de traitement de l’interruption
- Le programme traite l’interruption
- Le programme saute à l’instruction qui suit la dernière exécutée dans le programme
principal.

Il va bien sûr de soi que n’importe quel événement ne peut pas déclencher une
interruption. Il faut que 2 conditions principales soient remplies :

- L’événement en question doit figurer dans la liste des événements susceptibles de


provoquer une interruption pour le processeur sur lequel on travaille
- L’utilisateur doit avoir autoriser l’interruption, c’est à dire doit avoir signalé que
l’événement en question devait générer une interruption.

Organigramme général de l’exécution d’une interruption.

37
Fig 6. Méchanisme général d’une interruption

Que pouvons-nous dire en voyant cet ordinogramme ? Et bien, nous pouvons déjà nous
dire que le programme principal ne sait pas quand il est interrompu, il est donc crucial de lui
remettre ses registres dans l’état où ils étaient avant l’interruption.

En effet, supposons que l’instruction xxx ait positionné un flag (par exemple, le bit
d’indicateur Z). Si par malheur, la routine d’interruption a modifié ce bit, le programme ne
pourra pas se poursuivre normalement.

Nous voyons également que l’instruction xxx termine son exécution avant de se
brancher sur la routine d’interruption. Une instruction commencée n’est donc jamais
interrompue.

10.3 Mécanisme d’interruption sur les PICs

Bien entendu, les PICs répondent au fonctionnement général ci-dessus, mais elles ont
également leurs particularités. Voyons maintenant le principe des interruptions sur les PICs

- Tout d’abord, l’adresse de début de toute interruption est fixe. Il s’agit toujours de
l’adresse 0x04. Toute interruption provoquera le saut du programme vers cette adresse.

- Toutes les sources d’interruption arrivant à cette adresse, si le programmeur utilise


plusieurs sources d’interruptions, il lui faudra déterminer lui-même laquelle il est en
train de traiter.

- Les PICs en se connectant à cette adresse, ne sauvent rien automatiquement, hormis le


contenu du PC, qui servira à connaître l’adresse du retour de l’interruption. C’est donc
à l’utilisateur de se charger des sauvegardes.

38
- Le contenu du PC est sauvé sur la pile interne (8 niveaux). Donc, si vous utilisez des
interruptions, vous ne disposez plus que de 7 niveaux d’imbrication pour vos sous-
programmes. Moins si vous utilisez des sous-programmes dans vos interruption.

- Le temps de réaction d’une interruption est calculé de la manière suivante : le cycle


courant de l’instruction est terminé, le flag d’interruption est lu au début du cycle
suivant. Celui-ci est achevé, puis le processeur s’arrête un cycle pour charger l’adresse
0x04 dans PC. Le processeur se connecte alors à l’adresse 0x04 où il lui faudra un
cycle supplémentaire pour charger l’instruction à exécuter. Le temps mort total sera
donc compris entre 3 et 4 cycles.

- Une interruption ne peut pas être interrompue par une autre interruption. Les
interruptions sont donc invalidées automatiquement lors du saut à l’adresse 0x04 par
l’effacement du bit GIE (que nous allons voir).

- Les interruptions sont remises en service automatiquement lors du retour de


l’interruption. L’instruction RETFIE agit donc exactement comme l’instruction
RETURN, mais elle repositionne en même temps le bit GIE.

Fig7. Les interruptions sur les PICs

10.4 Les sources d’interruptions du 16F84

Le 16F84 est très pauvre à ce niveau, puisqu’elle ne dispose que de 4 sources


d’interruptions possibles (contre 14 pour le 16F877 par exemple). Les événements
susceptibles de déclencher une interruption sont les suivants :

- TMR0 : Débordement du timer0 (tmr0). Une fois que le contenu du tmr0 passe de 0xff
à 0x00, une interruption peut être générée.
- EEPROM : cette interruption peut être générée lorsque l’écriture dans une case
EEPROM interne est terminée.
- RB0/INT : Une interruption peut être générée lorsque, la pin RB0, encore appelée
INTerrupt pin, étant configurée en entrée, le niveau qui est appliqué est modifié.

39
- PORTB : De la même manière, une interruption peut être générée lors du changement
d’un niveau sur une des pins RB4 à RB7. Il n’est pas possible de limiter l’interruption
à une seule de ces pins. L’interruption sera effective pour les 4 pins ou pour aucune.

10.5 Le registre INTCON (INTerrupt CONtrol)

Ce registre se situe à l’adresse 0x0B, dans les 2 banques. Il est donc toujours accessible. Il est
détaillé figure 4-5 page 16. C’est un registre de bits, donc, chaque bit a une fonction
particulière. Voici le détail de ces bits :

b7 : GIE

Global Interrupt Enable bit. Il permet de valider ou d’invalider toutes les interruptions
d’une seule fois. Ce bit correspond donc à notre interrupteur de validation générale.

b6 : EEIE

Eeprom write complete Interrupt Enable bit. Ce bit permet de valider l’interruption de fin
d’écriture en eeprom (nous étudierons plus tard le mécanisme d’écriture eeprom).

b5 : T0IE

Tmr0 Interrupt Enable bit : Valide l’interruption générée par le débordement du timer0.

b4 : INTE

INTerrupt pin Enable bit : Valide l’interruption dans le cas d’une modification de niveau
de la pin RB0.

ATTENTION : rappelez-vous le bit 6 du registre OPTION, qui détermine quel est le sens
de transition qui provoque l’interruption. On pourra donc choisir si c’est une transition 0->1
ou 1->0 qui provoque l’interruption, mais pas les deux ensemble.

b3 : RBIE

RB port change Interrupt Enable bit : Valide les interruptions si on a changement de


niveau sur une des entrées RB4 à RB7.

b2 : T0IF

Tmr0 Interrupt Flag bit. C’est un Flag, donc il signale. Ici c’est le débordement du timer0

b1 : INTF

INTerrupt pin Flag bit : signale une transition sur la pin RB0 dans le sens déterminé par
INTEDG du registre OPTION (b6)

b0 : RBIF
Port Interrupt Flag bit : signale qu’une des entrées RB4 à RB7 a été modifiée.

40
Remarque

Rappelez-vous que les flags ne se remettent pas à 0 tout seuls. C’est votre
programme qui doit s’en charger, sous peine de rester indéfiniment bloqué dans
une routine d’interruption. Nous dirons que ces flags sont des FLAGS REMANENTS

10.6 Particulatité de l’instruction « RETFIE »

A ce niveau de l’exposé, une remarque pertinente serait la suivante :


Pourquoi existe-t-il une instruction RETFIE, alors qu’on pourrait utiliser RETURN ?
Et bien, vous ne pouvez pas interrompre une interruption par une autre. Si c’était le
cas, les sauvegardes des registres W et STATUS seraient « écrasé » par une seconde opération
(mais c’est possible sur d’autres processeurs). Donc, dès que le programme est branché sur
l’interruption, le bit GIE est mis à 0 automatiquement.

Pour qu’une nouvelle interruption puisse avoir lieu une fois celle en cours terminée, il
faut remettre GIE à 1. Ceci est exécuté automatiquement par RETFIE.

11-Timer0 :

11.1 Les différents modes de fonctionnement du timer0 :

Nous avons vu que le timer0 est en fait un compteur. Mais que compte-t-il ? Et bien, vous
avez deux possibilités.

- En premier lieu, vous pouvez compter les impulsions reçues sur le pin RA4/TOKI.
Nous dirons dans ce cas que nous sommes en mode compteur

- Vous pouvez aussi décider de compter les cycles d’horloge du PIC lui-même. Dans ce
cas, comme l’horloge est fixe, nous compterons donc en réalité du temps. Donc, nous
serons en mode « timer ».

La sélection d’un ou l’autre de ces deux modes de fonctionnement s’effectue par le bit
5 du registre OPTION : T0CS pour Tmr0 Clock Source select bit.

T0CS = 1 : Fonctionnement en mode compteur


T0CS = 0 : Fonctionnement en mode timer

Dans le cas où vous décidez de travailler en mode compteur, vous devez aussi préciser
lors de quelle transisition de niveau le comptage est effectué. Ceci est précisé grâce au bit 4
du registre OPTION : T0SE pour Timer0 Source Edge select bit.

T0SE = 0 : comptage si l’entrée RA4/TOKI passe de 0 à 1


T0SE = 1 : comptage si l’entrée RA4/TOKI passe de 1 à 0

41
11.2 Le registre tmr0

Ce registre, qui se localise à l’adresse 0x01 en banque0, contient tout simplement la valeur
actuelle du timer0. Vous pouvez écrire ou lire tmr0. Si par exemple vous avez configuré tmr0
en compteur, la lecture du registre tmr0 vous donnera le nombre d’événements survenus sur le
pin RA4/TOKI.

11.3 Les méthodes d’utilisation du timer0

Comment utiliser le timer0, et quelles sont les possibilités offertes à ce niveau, voilà de
quoi nous allons parler ici.

11.3.1 Le mode de lecture simple

La première méthode qui vient à l’esprit est la suivante : Nous lisons le registre tmr0
pour voir ce qu’il contient. La valeur lue est le reflet du nombre d’événements survenus, en
prenant garde au fait que le tmr0 ne peut compter que jusque 255. En cas de dépassement, le
tmr0 recommence à 0. C’est donc à vous de gérer cette possibilité.
Petit exemple :

Clrf tmr0 ; début du comptage


; ici un certain nombre d’instructions
movf tmr0 , w ; charger valeur de comptage
movwf mavariable ; sauver pour traitement ultérieur

11.3.2 Le mode de scrutation du flag

Nous devons savoir à ce niveau, que tout débordement du timer0 (passage de 0xFF à
0x00) entraîne le positionnement du flag T0IF du registre INTCON. Vous pouvez donc
utiliser ce flag pour déterminer si vous avez eu débordement du timer0, ou, en d’autres
termes, si le temps programmé est écoulé. Cette méthode à l’inconvénient de vous faire perdre
du temps inutilement

Petit exemple :

clrf tmr0 ; début du comptage


bcf INTCON , T0IF ; effacement du flag
loop
btfss INTCON , T0IF ; tester si compteur a débordé
goto loop ; non, attendre débordement
; suite du programme ; oui, poursuivre : 256 événements écoulés

Mais vous pourriez vous dire que vous ne désirez pas forcément attendre 256
incrémentations de tmr0. Supposons que vous désiriez attendre 100 incrémentations. Il suffit
dans ce cas de placer dans tmr0 une valeur telle que 100 incrémentations plus tard, tmr0
déborde.

exemple

42
movlw 256-100 ; charger 256 – 100
movwf tmr0 ; initialiser tmr0
bcf INTCON , T0IF ; effacement du flag
loop
btfss INTCON , T0IF ; tester si compteur a débordé
goto loop ; non, attendre débordement
; suite du programme ; oui, poursuivre : 100 événements écoulés

11.3.3 Le mode d’interruption

C’est évidemment le mode principal d’utilisation du timer0. En effet, lorsque T0IE est
positionné dans le registre INTCON, chaque fois que le flag T0IF passe à 1, une interruption
est généree.

11.3.4 Les méthodes combinées

Supposons que vous vouliez, par exemple, mesurer un temps entre 2 impulsions sur le
broche RB0. Supposons également que ce temps soit tel que plusieurs débordements du tmr0
puissent avoir lieu. Une méthode simple de mesure du temps serait la suivante :

1) A la première impulsion sur RB0, on lance le timer 0 en mode interruptions.


2) A chaque interruption de tmr0, on incrémente une variable
3) A la seconde interruption de RB0, on lit tmr0 et on arrête les interruptions
4) Le temps total sera donc (256*variable)+tmr0

On a donc utilisé les interruptions pour les multiples de 256, et la lecture directe de tmr0 pour
les « unités ».

11.4 Le prédiviseur

Supposons que nous travaillons avec un quartz de 4MHz. Nous avons donc dans ce cas
(4000000/4) = 1.000.000 de cycles par seconde. Chaque cycle d’horloge dure donc
1/1000000ème de seconde, soit 1µs.

Si nous décidons d’utiliser le timer0 dans sa fonction timer et en mode interruptions.


Nous aurons donc une interruption toutes les 256µs, soit à peut près toutes les quarts de
millième de seconde.

Si nous désirons réaliser une LED clignotante à une fréquence de +- 1Hz, nous aurons
besoin d’une temporisation de 500ms, soit 2000 fois plus. Ce n’est donc pas pratique.
Nous disposons pour améliorer ceci d’un PREDIVISEUR .
Qu’est-ce donc ? Et bien, tout simplement un diviseur d’événements situé AVANT
l’entrée de comptage du timer0. Nous pourrons donc décider d’avoir incrémentation de tmr0
tous les 2 événements par exemple, ou encore tous les 64 événements.

Regardez tableau de la page 16. Vous voyez en bas le tableau des bits PS0 à PS2 du
registre OPTION qui déterminent la valeur du prédiviseur.

43
Ces valeurs varient, pour le timer0, entre 2 et 256. Le bit PSA, quand à lui, détermine
si le prédiviseur est affecté au timer0 ou au watchdog. Voici un tableau exprimant toutes les
possibilités de ces bits :

PSA PS2 PS1 PS0 /tmr0 /WD Temps tmr0 Temps typique Watchdog
(minimal)
0 0 0 0 2 1 512 µs 18 ms (7ms)
0 0 0 1 4 1 1024 µs 18 ms (7ms)
0 0 1 0 8 1 2048 µs 18 ms (7ms)
0 0 1 1 16 1 4096 µs 18 ms (7ms)
0 1 0 0 32 1 8192 µs 18 ms (7ms)
0 1 0 1 64 1 16384 µs 18 ms (7ms)
0 1 1 0 128 1 32768 µs 18 ms (7ms)
0 1 1 1 256 1 65536 µs 18 ms (7ms)
1 0 0 0 1 1 256 µs 18 ms (7ms)
1 0 0 1 1 2 256 µs 36 ms (14 ms)
1 0 1 0 1 4 256 µs 72 ms (28 ms)
1 0 1 1 1 8 256 µs 144 ms (56 ms)
1 1 0 0 1 16 256 µs 288 ms (112 ms)
1 1 0 1 1 32 256 µs 576 ms (224 ms)
1 1 1 0 1 64 256 µs 1,152 Sec (448 ms)
1 1 1 1 1 128 256 µs 2,304 Sec (996 ms)

- PSA à PS0 sont les bits de configuration du prédiviseur


- /tmr0 indique la valeur du prédiviseur résultante sur le timer0
- /WD indique la valeur du prédiviseur résultante sur le Watchdog
- temps tmr0 indique le temps max entre 2 interruptions tmr0 avec quartz de 4MHz
- Temps watchdog indique le temps typique disponible entre 2 reset watchdog (indépendant
du quartz utilisé). La valeur entre parenthèses indique le temps minimal, qui est celui à
utiliser pour faire face à toutes les circonstances.

Remarques importantes :

- Il n’y a qu’un prédiviseur, qui peut être affecté au choix au timer du watchdog (que nous
verrons plus tard) ou au timer0. Il ne peut être affecté aux deux en même temps.

- Il n’existe pas de prédiviseur = 1 pour le timer0. Si vous ne voulez pas utiliser le


prédiviseur, vous devez donc impérativement le sélectionner sur le watchdog avec une valeur
de 1.

- La valeur contenue dans le prédiviseur n’est pas accessible. Par exemple, si vous décidez
d’utiliser un prédiviseur de 64, et qu’il y a un moment donné 30 événements déjà
survenus, vous n’avez aucun moyen de le savoir. Le prédiviseur limite donc la précision
en cas de lecture directe.

- L’écriture dans le registre tmr0 efface le contenu du prédiviseur. Les événements survenus
au niveau du prédiviseur sont donc perdus.

44
12- Les accès en mémoire « eeprom »

Ce paragraphe décrit l’accès dans l’eeprom interne du PIC. Il ne faut pas confondre
ceci avec l’écriture dans une eeprom externe type 2416. Pour ce type d’eeprom, il suffit de
suivre les directives du datasheet du composant concerné.

12.1 Taille et localisation de la mémoire « eeprom »

L’adresse physique de la zone eeprom commence, pour les PICs mid-range, à l’adresse
0x2100. Cette adresse se situe hors de l’espace d’adressage normal des PICs, donc nous
pouvons déjà en déduire qu’il nous faudra utiliser une procédure spéciale pour y accéder.

Notez déjà que si ces emplacements ne sont pas accessibles directement par le
programme, par contre ils le sont au moment de la programmation. Vous pourrez donc
initialiser votre zone eeprom au moment de programmer votre composant.

Ceci est également vrai pour des registres spéciaux des PICs. Par exemple, l’adresse
0x2007 contient les paramètres que vous écrivez dans _CONFIG. Vous pourriez donc
remplacer cette directive par une initialisation directe à l’adresse 0x2007. Nous vous le
déconseillons cependant pour des raisons de portabilité et d’évolution rapide vers une autre
famille de PICs.

De même, l’adresse 0x2006 contient l’identification du composant. C’est ainsi qu’un


programmateur évolué peut faire la distinction entre une 16F84 et une 16F84A, car leur
identification constructeur diffère.

La 16F84 dispose de 64 emplacements eeprom disponibles pour votre libre usage. Nous
allons voir comment les utiliser.

12.2 Le registre EEDATA

C’est dans ce registre que va transiter la donnée à écrire vers ou la donnée lue en
provenance de l’eeprom. Ce registre est situé à l’adresse 0x08 banque0.

12.3 Le registre EEADR

Dans ce registre, situé à l’adresse 0x09 banque0, nous allons préciser sur 8 bits l’adresse
concernée par l’opération de lecture ou d’écriture en eeprom. Nous voyons déjà que pour cette
famille de PICs, nous ne pourrons pas dépasser 256 emplacements d’eeprom. Pour la 16F84,
la zone admissible va de 0x00 à 0x3F, soit 64 emplacements.

12.4 Le registre EECON1

Ce registre, situé à l’adresse 0x88 en banque1, contient 5 bits qui définissent ou indiquent
le fonctionnement des cycles de lecture/écriture en eeprom. Voici son contenu :

bits 7/6/5

non utilisés

45
bit 4 : EEIF

Eeprom write operation Interrupt Flag bit. C’est le flag qui est en liaison avec
l’interruption EEPROM. Il passe à 1 une fois l’écriture en eeprom terminée. Si le bit EEIE du
registre INTCON est à 1, une interruption sera générée

bit 3 : WRERR

WRite Error. C’est un bit d’erreur. Il passe à 1 si une opération d’écriture en eeprom a été
interrompue, par exemple par un reset.

bit 2 : WREN

WRite ENable. Autorisation de démarrage du cycle d’écriture

bit 1 : WR

WRite. Démarrage du cycle d’écriture. Est remis à 0 automatiquement une fois l’écriture
terminée.

bit 0 : RD

ReaD. Démarrage d’un cycle de lecture. Reste à 1 durant un cycle, puis est remis à 0
automatiquement

12.5 Le registre EECON2

Nous revoici en présence d’un registre « fantôme », puisque ce registre n’existe pas. Il
s’agit tout simplement d’une adresse 0x89 banque1, qui sert à envoyer des commandes au PIC
concernant les procédures eeprom. Vous ne pouvez l’utiliser qu’en vous servant des
instructions expliquées plus bas.

12.6 Accès en lecture dans la mémoire « eeprom »

Pour lire une donnée en eeprom, il suffit de placer l’adresse concernée dans le registre
EEADR. Ensuite, vous positionnez le bit RD à 1. Vous pouvez ensuite récupérer la donnée lue
dans le registre EEDATA. Il ne faut pas bien sûr oublier les différents changements de
banques.

Comme cette procédure est courte et toujours la même, nous allons créer une macro à
cette intention. Comme la macro doit contenir l’adresse de lecture, nous réaliserons une macro
avec passage de paramètre. Voici la macro à ajouter. Vous devrez être dans la banque0 pour
appeler cette macro, et elle vous retourne la valeur lue dans le registre W.

READEE macro adeeprom ; macro avec 1 paramètre (argument)


movlw adeeprom ; charger adresse eeprom (argument reçu)
movwf EEADR ; adresse à lire dans registre EEADR
bsf STATUS , RP0 ; passer en banque1
bsf EECON1 , RD ; lancer la lecture EEPROM
bcf STATUS , RP0 ; repasser en banque0

46
movf EEDATA , w ; charger valeur lue dans W
endm ; fin de la macro

Vous remarquez que vous passez un argument à la macro. Vous désignez cet ou ces
arguments après la directive macro. Nous avons utilisé ici l’argument adeeprom pour indiquez
l’adresse eeprom. Chaque utilisation de adeeprom dans notre macro sera remplacée par
l’argument reçu au moment de l’appel de la macro.

Pour utiliser cette macro, nous devons donc lui passer un argument. Par exemple :

READEE eereload ; lecture de l’adresse eereload de l’eeprom

Lira l’eeprom à l’adresse eereload, c’est à dire l’adresse 0x00.

12.7 L’accès en écriture à la zone eeprom

Maintenant vous allez nous dire avec raison que cela ne sert à rien de lire en eeprom si
on n’arrive pas à y écrire. Notre programme ne présente donc rien de plus que ce que nous
avions auparavant. C’est tout à fait justifié. Aussi allons-nous étudier la méthode d’écriture.
Comme vous vous en doutez, cette méthode utilise les mêmes registres.

La procédure à suivre consiste d’abord à placer la donnée dans le registre EEDATA et


l’adresse dans EEADR. Ensuite une séquence spécifique (il n’y a rien à comprendre, c’est
imposé par le constructeur) doit être envoyée au PIC.

13- Le watchdog

Le watchdog, ou chien de garde est un mécanisme de protection de votre programme.


Il sert à surveiller si celui-ci s’exécute toujours dans l’espace et dans le temps que vous lui
avez attribués.

13.1 Le principe de fonctionnement

La mise en service ou l’arrêt du watchdog se décide au moment de la programmation de


votre PIC, à l’aide de la directive _CONFIG. Si vous précisez le paramètre « _WDT_OFF »
est précisé, le watchdog ne sera pas en service. Si au contraire vous précisez « _WDT_ON »,
le watchdog sera actif.

IL N’EST DONC PAS POSSIBLE DE METTRE EN OU HORS SERVICE LE


WATCHDOG DURANT L’EXECUTION DE VOTRE PROGRAMME.

Le fonctionnement du watchdog est lié à un timer interne spécifique, qui n’est pas
synchronisé au programme, ni à un événement extérieur. La durée spécifique de débordement
de ce timer est approximativement de 18ms. Cette valeur est à prendre avec précaution, car
elle varie en fonction de différents paramètres comme la tension d’alimentation ou la
température. La valeur minimale de 7ms est celle que vous devrez utiliser dans la pratique.

Chaque fois que l’instruction clrwdt est envoyée au PIC, le timer du watchdog est
remis à 0, ainsi que la valeur contenue dans son prédiviseur. Si par accident cette instruction
n’est pas reçue dans le délai prévu, le PIC est redémarrée à l’adresse 0x00 et le bit TO du

47
registre STATUS est mis à 0. En lisant ce bit au démarrage, vous avez donc la possibilité de
détecter si le PIC vient d’être mise sous tension, ou si ce démarrage est du à un « plantage »
de votre programme.

13.2 Le prédiviseur et le watchdog

Nous avons vu dans les leçons précédentes que le prédiviseur pouvait être affecté au tmr0
ou au watchdog, via le bit PSA du registre OPTION. Si nous décidons de mettre le prédiviseur
sur le watchdog (PSA = 1), le tableau de la page 16 nous donnera les valeurs du prédiviseur
obtenues suivant les bits PS0/PS2. En réalité, pour le watchdog, il s’agit d’un postdiviseur,
mais cela ne concerne que l’électronique interne du PIC. Vous n’avez pas à vous tracasser
pour cette différence.

Ce prédiviseur multiplie le temps de débordement du timer du watchdog. Par exemple,


avec un prédiviseur de 2, vous obtenez un temps minimal de 7ms*2 = 14ms. Donc, avec un
quartz de 4MHz, cela vous oblige à envoyer l’instruction clrwdt au moins une fois tous les
14.000 cycles d’instructions. Dans la plupart des cas, le reset s’effectuera en réalité après
18ms*2 = 36ms, soit 36.000 cycles d’instructions.

13.3 Les rôles du watchdog

Le watchdog est destiné à vérifier que votre programme ne s’est pas « égaré » dans une
zone non valide de votre programme (parasite sur l’alimentation par exemple), ou s’il n’est
pas bloqué dans une boucle sans fin (bug du programme). Il sert également à réveiller un PIC
placée en mode « sleep », ce que nous verrons plus tard.

13.4 Utilisation correcte du watchdog

La première chose à faire, si vous désirez profiter de cette protection intégrée, est de
paramètrer la _CONFIG pour la mise en service du watchdog. La première chose à constater,
c’est que si vous indiquez « _WDT_ON » pour un programme qui ne gère pas le watchdog,
celui-ci redémarrera sans arrêt, et donc ne fonctionnera pas, car il ne contiendra aucune
instruction « clrwdt ».

C’est une erreur fréquente pour ceux qui ne maîtrisent pas les bits de configuration de
leur programmateur. Les bits de configurations indiqués dans le fichier sont en effet
modifiables sur la plupart des softs de programmation, qui sont capables de forcer une valeur
de _CONFIG différente de celle prévue par le concepteur du logiciel.

Ensuite, vous devez placer une ou plusieurs instructions « clrwdt » dans votre
programme en vous arrangeant pour qu’une instruction « clrwdt » soit reçue dans les délais
requis par votre PIC. A ce propos, ne tenez pas compte du temps nominal de 18ms, mais
plutôt du temps de la situation la plus défavorable. Ce temps est de minimum 7ms. En prenant
ce temps comme temps maximum autorisé, vous êtes certain que votre programme
fonctionnera dans toutes les conditions.

14- Le mode Sleep

Nous allons étudier dans ce paragraphe un mode très particulier des PICs, qui leur
permet de se mettre en sommeil afin de limiter leur consommation.

48
14.1 Principe de fonctionnement

Le mode « sleep » ou « power down » est un mode particulier dans lequel vous pouvez
placer votre PIC grâce à l’instruction « sleep ». Une fois dans ce mode, le PIC est placée en
sommeil et cesse d’exécuter son programme. Dès réception de cette instruction, la séquence
suivante est exécutée :

- Le watchdog est remis à 0, exactement comme le ferait une instruction « clrwdt ».

- Le bit TO du registre STATUS est mis à 1.

- Le bit PD du registre STATUS est mis à 0.

- L’oscillateur est mis à l’arrêt, la PIC n’exécute plus aucune instruction.

Une fois dans cet état, le PIC est à l’arrêt. La consommation du circuit est réduite au
minimum. Si le tmr0 est synchronisé à l’horloge interne, il est également mis dans
l’incapacité de compter.

Par contre, il est très important de se rappeler que le timer du watchdog possède son
propre circuit d’horloge. Ce dernier continu à compter comme si de rien n’était.

Pour profiter au maximum de la chute de la consommation (montage sur piles par


exemple), Microchip recommande de veiller à ce que les pins d’entrées/sorties et
l’électronique connectée soient à des niveaux 0 ou 1 tels qu’il n’y ait aucun passage de
courant qui résulte du choix de ces niveaux.

14.2 La sortie du mode « sleep »

Le passage en mode « sleep » n’a réellement d’intérêt que s’il est possible d’en sortir. La
16F84 ne réagit dans ce mode qu’aux événements suivants, qui sont seuls susceptibles de
replacer la 16F84 en mode de fonctionnement normal. Ces événements sont les suivants :

- Application d’un niveau 0 sur le pin MCLR. Ceci provoquera un reset de la 16F84. La
PIC effectuera un reset classique à l’adresse 0x00. L’utilisateur pourra tester les bits
TO et PD lors du démarrage pour vérifier l’événement concerné (reset, watch-dog, ou
mise sous tension).

- Ecoulement du temps du timer du watchdog. Notez que pour que cet événement
réveille le PIC, il faut que le watchdog ait été mis en service dans les bits de
configuration.
Dans ce cas particulier, le débordement du watchdog ne provoque pas un reset du PIC,
il se contente de la réveiller. L’instruction qui suit est alors exécutée au réveil.

- Une interruption RB0/INT, RB, ou EEPROM est survenue. Notez que pour qu’une
telle interruption puisse réveiller le processeur, il faut que les bits de mise en service
de l’interruption aient été positionnés. Par contre le bit GIE n’a pas besoin d’être mis
en service pour générer le réveil du PIC. Vous pouvez donc décider par exemple de
réveiller le PIC à la fin du cycle d’écriture EEPROM. Pour ce faire, vous devez mettre

49
le bit EEIE de INTCON à 1 et lancer le cycle d’écriture, suivi par l’instruction
« sleep » Une fois l’écriture terminée, le PIC est réveillée et poursuit son programme.

14.3 Réveil avec GIE hors service.

Si votre PIC est réveillée par une interruption alors que le BIT GIE de INTCON est mis à
0, le programme se poursuivra tout simplement à l’instruction qui suit l’instruction « sleep ».

14.4 Réveil avec GIE en service

Dans le cas où votre bit GIE est positionné, un réveil suite à une interruption entraînera la
séquence suivante.

- L’instruction qui suit l’instruction « sleep » est exécutée.

- Le programme se branche ensuite à l’adresse 0x04 comme une interruption ordinaire.


Notez que si vous ne voulez pas exécuter l’instruction qui suit l’instruction « sleep », il
vous suffit de placer à cet endroit une instruction « nop ».

14.5 Cas typiques d’utilisation

Ce mode de fonctionnement est principalement utilisé dans les applications dans


lesquelles la consommation en énergie doit être économisée (piles). On placera donc dans ce
cas le PIC en mode « Power Down » ou « sleep » aussi souvent que possible.

Une autre application typique est un programme dans lequel le PIC n’a rien à faire dans
l’attente d’un événement extérieur particulier. Dans ce cas, plutôt que d’utiliser des boucles
sans fin, une instruction « sleep » pourra faire efficacement l’affaire.

D- LE PIC16F877:

1-Introduction

Le 16F877 est un microcontroleur à mémoire FLASH de la famille des PIC de


Microchip. Son prédécesseur le plus connu, est le 16F84. C’est le microcontroleur le plus
riche en périphériques de cette gamme. Il s’agit d’un circuit intégré contenu dans un boîtier
dit « DIL 40 ». Il présente donc 40 broches, 20 de chaque côté. Les broches sont virtuellement
numérotées de 1 à 40, la broche 1 étant celle qui se trouve dans le coin situé à gauche de
l’encoche de repérage.
Comme pour tout circuit intégré, chacune de ses broches a une ou plusieurs fonctions
qui sont résumées par un sigle mnémotechnique.

50
Fig9.Brochage du 16f877
1.1 Les broches d’alimentation :

Le 16F877 a des broches d’alimentation : 2 pour le 0V broche 11 et 32 et 2 pur le +5V


broche 12 et 31. Il suffit de connecter une de chaque à l’alimentation pour que le CI
fonctionne.

1.2 Les broches du Quartz :

Comme pour tout micrcontrôleur, le 16F877 a besoin d’une horloge pour fixer la
vitesse d’exécution des instructions. On utilise pour ce faire un quartz dont le rôle est de créer
une impulsion de fréquence élevée.

Le micrcontrôleur se base sur cette fréquence pour son fonctionnement interne. Notons
que le 16F877 exécute une instruction élémentaire du langage assembleur en 4 cycles
d’horloge. Il va donc pouvoir exécuter 1millions d’opérations élémentaires par seconde.Le
quartz est connecté sur les 2 broches OSC1 et OSC2.

51
Fig10.Architecture interne du 16f877
2- Les Ports du 16F877 :

Le 16F877 possède 5 ports différents :

- le port A (6 broches)
- le port B (8 broches)
- le port C (8 broches)

52
- le port D (8 broches)
- le port E (3 broches)

Les broches de chaque port sont numérotées de 0 à n.


Les broches de ports sont désignées par un R suivi de la lettre du port et du numéro de broche.
Ainsi, la broche 0 du port A est désignée par RA0, la broche 4 du port B par RB4, etc…
On a donc 33 broches d’entrées-sorties (E/S) disponibles. C’est l’un des grands avantages
du 16F877. Mais toutes ces broches ne seront pas forcément disponibles en tant que broche
E/S car presque toutes sont également utilisées par l’un ou l’autre des modules internes du
16F877. Elles ne seront pas disponibles en tant que broche E/S si le module concerné est
activé.
Toutes les broches de ces ports sont des broches E/S, on peut donc les configurer en
entrée ou en sortie.Les caractéristiques électriques de ces broches sont spécifiées dans le
datasheet du micrcontrôleur Chaque port est configuré par un registre nommé TRIS, suivi de
la lettre du port. Ainsi le port A est configuré par le registre TRISA. Chaque bit de ces
registres (TRIS) détermine le sens Entrée ou Sortie des broches du port.

2.1 Le PORTA :

Le port A contient 6 pins I/O (input/output) numérotées de RA0 à RA5. On a donc 6 bits
dans le registre PORTA et 6 bits dans le registre TRISA. Les bits 6 et 7 de ces registres ne
sont pas implémentés. Le port A est configuré comme un ensemble d’entrées analogiques.
Donc, il faut forcer une valeur dans le registre ADCON1 dans la routine d’initialisation pour
pouvoir utiliser ce port comme port d’entrée/sortie de type général.

2.2 Le PORTB :

Ce port fonctionne exactement comme celui du 16f84.

2.3 Le PORTC :

Ce port utilise un registre TRISC localisé dans la banque 1, qui permet de décider
quelles sont les entrées et quelles sont les sorties. le positionnement d’un bit à « 1 » place la
pin en entrée, le positionnement de ce bit à « 0 » place pin en sortie.
Nous trouvons également le registre PORTC, qui se trouve dans la banque 0.

2.4 Le PORTD :

Le registre TRISD comporte 8 bits de direction, pendant que le registre PORTD


correspond aux pins I/O concernées.

2.5 Le PORT E :

Il ne comporte que 3 pins, RE0 à RE2 ces pins peuvent également être utilisées comme
pins d’entrées analogiques. Le registre ADCON1 détermine si ce port sera utilisé comme port
I/O ou comme port analogique.

2.5.1 Le registre TRISE :

Le registre TRISE dispose de certains bits de configuration.

53
b7 : IBF : Input Buffer Full status bit
b6 : OBF : Output Buffer Full status bit
b5 : IBOV : Input Buffer OVerflow detect bit
b4 : PSPMODE : Parallel Slave Port MODE select bit
b3 : 0 : Non implémenté (lu comme « 0 »)
b2 : Direction I/O pour RE2 (1 = entrée)
b1 : Direction I/O pour RE1
b0 : Direction I/O pour RE0

Ls bits 0 à 2 fonctionnent de façon identique à ceux des autres TRISx.


Un bit à « 1 » positionne le pin en entrée, un bit à « 0 » la positionne en sortie.
Le bit 4 (PSPMODE) est le bit qui détermine si le PORTD sera utilisé en port I/O. Si On
place ce bit a 1, le PORTD sera considéré comme un port d’interfaçage parallèle avec un
microprocesseur (fonctionnement esclave).

3-La mémoire du Pic :

La mémoire du 16F877 est divisée en trois parties distinctes :

3.1. Une mémoire FLASH (8K).

C’est la mémoire programme proprement dite. Chaque « case » mémoire unitaire fait 13
bits. La mémoire FLASH est un type de mémoire stable, qu’on peut reécrire à volonté cette
mémoire flash fait 8Koctet.

3.2. Une mémoire RAM ( 368 octets).

La mémoire RAM disponible du 16F877 est de 368 octets, répartie de la manière


suivante :

1) 80 octets en banque 0, adresses 0x20 à 0x6F


2) 80 octets en banque 1, adresses 0xA0 à 0XEF
3) 96 octets en banque 2, adresses 0x110 à 0x16F
4) 96 octets en banque 3, adresses 0x190 à 0x1EF
5) 16 octets communs aux 4 banques, soit 0x70 à 0x7F ; 0xF0 à 0xFF ; 0x170 à 0x17F ;
0x1F0 à 0x1FF.
La signification de ces octets communs est que si on accéde au registre (adresse mémoire
RAM) 0x70 ou au registre 0XF0, en réalité on accéde au même emplacement. Ceci à
l’avantage de permettre d’utiliser ces emplacements sans devoir connaître l’état de RP0, RP1,
et IRP.

54
Fig11.La RAM du 16F877

3.3 Une EEPROM Interne ( 256 Octets).


C’est une mémoire de données.

4-Les modules internes du 16F877 :

Le 16F877 comprend :

1. Trois timers / compteurs :


- le timer 0
- le timer 1
- le timer 2

55
2. Un convertisseur analogique-numérique (CAN) 10 bits 8 canaux

3. Deux modules de génération d’impulsion à période réglable (PWM), qui


fonctionnent aussi en mode capture et comparaison

4. Un module de communication série synchrone

5. Une USART

6. Un module de communication en « port parallèle » en mode esclave

7. Un « chien de garde »

4.1. Les Trois timers / compteurs :

L’intérêt des modules de comptage, c’est qu’ils permettent de tenir compte d’évènements
qui surviennent de façon répétée sans que le microprocesseur soit monopolisé par cette tâche.
Dans la plupart des cas, une interruption a lieu que lorsque le compteur déborde (overflow).
4.1.1. Le timer 0 : fonctionne exactement comme décrit dans la partie du microcontroleur
16F84.

4.1.2. Le timer 1 :c’est un compteur 16 bits qui peut compter (de 0 à 65535) :
- soit les impulsions de l’horloge
- soit les impulsions externes, et en particulier les impulsions d’un quartz externe.
Le débordement provoque aussi une interruption.

4.1.2.1 Caractéristiques du timer 1 :

Le timer 1 fonctionne dans son ensemble comme le timer 0.


Ce timer est capable de compter sur 16 bits, il sera donc capable de compter de D’0’ à
D’65535’. Le Comptage avec le timer 16 bits nécessite 2 registres. Ces registres se nomment
TMR1L et TMR1H.
Le contenu de TMR1L et de TMR1H n’est pas remis à 0 lors d’un reset. Donc, pour compter
à partir de 0, il faut remettre à 0 les deux registres.
Le timer 1 permet également, de générer une interruption une fois le débordement effectué.
Le timer 1 dispose, de la possibilité de mettre en service un prédiviseur. Mais ce prédiviseur
ne permet qu’une division maximale de 8. Par conséquent il peut atteindre une valeur
maximale de 65536 multiplié par 8, soit 524288.

4.1.2.2 Le timer 1 et les interruptions :

Le timer 1 permet, de générer une interruption au moment ou il déborde, c’est-à-dire au


moment où sa valeur passe de 0xFFFF à 0x0000.
Pour que le timer 1 génère une interruption les conditions suivantes doivent etre satisfaites :
- Il faut que le bit d’autorisation d’interruption du timer 1 (TMR1IE) soit mis à 1. Ce bit se
trouve dans le registre PIE1.
- Pour que le registre PIE1 soit actif, il faut que le bit PEIE d’autorisation des interruptions
périphériques soit positionné dans le registre INTCON.

56
- Il faut que le bit d’autorisation générale des interruptions (GIE) soit positionné dans le
registre INTCON.
Une interruption sera alors générée à chaque débordement du timer1. Cet événement sera
indiqué par le positionnement du flag TMR1IF dans le registre PIR1.

4.1.2.3 Les différents modes de fonctionnement du timer1 :

Le timer 1 peut fonctionner en mode timer, ou en mode compteur.


Cependant, le timer 1 dispose de 2 modes différents en mode comptage : un mode de type
synchrone et un mode de type asynchrone. C’est à dire en synchronisme ou non avec
l’horloge interne.
On a la possibilité, au niveau du timer 1, d’utiliser un quartz sur les pins T1OSI et T1OSO
afin de disposer d’une horloge séparée de l’horloge principale.
Le timer peut donc fonctionner en tant que :
- Timer basé sur l’horloge interne (compteur de cycles d’instruction)
- Timer basé sur une horloge auxiliaire
- Compteur synchrone
- Compteur asynchrone.
Les modes de fonctionnement sont définis en configurant correctement le registre T1CON.

4.1.2.4 Le registre T1CON :

Ce registre, situé en banque 0, va permettre de configurer le timer1 en fonction des


besoins d’utilisation .Les bits qui le composent sont :

b7 : Inutilisé
b6 : Inutilisé
b5 : T1CKPS1 : Timer 1 oscillator ClocK Prescale Select bit 1
b4 : T1CKPS0 : Timer 1 oscillator ClocK Prescale Select bit 0
b3 : T1OSCEN : Timer 1 OSCillator ENable control bit
b2 : T1SYNC : Timer 1 external clock input SYNChronisation control bit
b1 : TMR1CS : TiMeR 1 Clock Source select bit
b0 : TMR1ON : TiMeR 1 ON bit
Les bits T1CKPS1 et T1CKPS0 déterminent à eux deux la valeur du prédiviseur. Le
prédiviseur, permet, de ne pas compter chaque événement reçu, mais seulement chaque
multiple de cet événement. La valeur de ce multiple est la valeur du prédiviseur.

T1CKPS1 T1CKPS0 Valeur du prédiviseur

0 0 1
0 1 2
1 0 4
1 1 8
T1OSCEN : ce bit permet de mettre en service l’oscillateur interne, et donc permet d’utiliser
un second quartz pour disposer d’un timer précis travaillant à une fréquence distincte de la
fréquence de fonctionnement du PIC.
Si on place ce bit à « 1 », on met en service l’oscillateur interne.
T1SYNC : permet de choisir si le comptage des événements sera effectué de façon synchrone
ou asynchrone avec l’horloge principale du PIC. Lorsque TMR1 est utilisé en mode « timer »,

57
T1SYNC n’a aucune influance. Le comptage étant déterminé par l’oscillateur principal du
PIC, il est automatiquement synchrone.
TMR1CS : permet de définir quel est le mode de comptage du timer 1 :
- Soit on place TMR1CS à « 0 », dans ce cas, le timer compte les cycles d’instructions du
PIC.
- Soit, on place ce bit à « 1 », et TMR1 compte alors les flancs montants du signal appliqué
sur le pin RC0/T1OSO/T1CKI .
TMR1ON, si ce bit est mis à « 1 », autorise le timer 1 à fonctionner, alors que s’il est mis à «
0 », fige le contenu du timer 1, et donc, le met à l’arrêt.
- lors d’une écriture dans TMR1L ou TMR1H.

4.1.3. Le timer 2 :

Le timer 2 est un timer couplé au module CCP. Il est utilisé essentiellement pour la
génération d’impulsions à période ajustable (PWM).
Le timer2 dispose de certaines caractéristiques différentes des deux autres timers.

4.1.3.1 Caractéristiques du timer 2 :

Le timer 2 est un compteur sur 8 bits. Il possède lui aussi un prédiviseur. Celui-ci peut
être paramètré avec une des 3 valeurs suivantes : 1,4, ou 16.
Cependant, le timer 2 dispose également d’un postdiviseur, qui effectue une seconde
division après l’unité de comparaison. Ce postdiviseur peut prendre n’importe quelle valeur
comprise entre 1 et 16.
La valeur du diviseur total est obtenue en multipliant la valeur du prédiviseur par celle du
postdiviseur.On obtient alors les valeurs suivante du diviseur :

1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,20,24,28,32,36,40,44,48,52,56,60,64,80,96,112,128,14
4,160,176,192,208,224,240,256

Le timer 2 incrémente le registre TMR2, (un seul registre comptage sur 8 bits).
Les valeurs de division minimale et maximale sont identiques à celles du timer 0.
Le registre TMR2 est remis automatiquement à 0 lors d’un reset, contrairement au timer 1.
Ce timer ne dispose d’aucune entrée extérieure via un pin du PIC. Il ne peut donc fonctionner
qu’en mode « timer » avec l’horloge interne.

4.1.3.2 Le timer 2 et les interruptions :

Le timer 2 fonctionne, à ce niveau, comme le timer1. Le flag d’interruption se nomme


TMR2IF tandis que le bit d’autorisation s’appelle TMR2IE.
Il s’agit d’une interruption périphérique, la procédure pour autoriser les interruptions du timer
2 se fait en 3 étapes :
- Autorisation des interruptions périphériques via le bit PEIE du registre INTCON
- Autorisation de l’interruption timer 2 via TMR2IE du registre PIE1
- Autorisation générale des interruptions via le bit GIE du registre INTCON

4.1.3.3 Le timer 2 et les registres PR2 et T2CON :

La particularité du timer 2 c’est la possibilité d’avoir un débordement avec une valeur


prédéfinie par l’utilisateur cette valeur étant mémorisée dans le registre PR2. On peut donc

58
avoir, par exemple, un débordement de 0x56 à 0x00, en plaçant la valeur 0x56 comme valeur
maximale dans le registre PR2.
On peut donc dire que le fonctionnement du timer est le suivant :
- On incrémente le contenu du prédiviseur à chaque cycle d’instruction
- Chaque fois que ce contenu correspond à un multiple de la valeur du prédiviseur, on
incrémente TMR2.
- Chaque fois que le contenu de TMR2 dépasse le contenu de PR2, on remet TMR2 à 0, et on
incrémente le contenu du postdiviseur.
- Chaque fois que le contenu du postdiviseur correspond à un multiple de la valeur du
postdiviseur, on positionne le flag TMR2IF.
- Chaque fois que le contenu du postdiviseur est égal à un multiple de la valeur de ce celui-ci,
paramètrée par TOUTPS0 à TOUTPS3, le flag TMR2IF est forcé à 1, et une interruption est
éventuellement générée.
Une écriture dans le registre TMR2 efface le contenu du prédiviseur et du postdiviseur.

En conclusion ; le principal avantage du timer2, est qu’il permet de configurer le «


débordement » sur n’importe quelle valeur de TMR2, associé à un large éventail de valeurs de
diviseur.
Cet avantage, combiné à la grande flexibilité de l’ensemble prédiviseur/postdiviseur,
permet d’obtenir très facilement des durées d’interruption précises sans complications
logicielles.
Le contenu du registre T2CON, qui permet de paramètrer le prédiviseur et le postdiviseur,
ainsi que d’autoriser ou non le fonctionnement du timer2, est le suivant :

T2CON (en banque 0 )


- b7 : non utilisé,
- b6 : TOUTPS3 : Timer2 OUTput PostScale bit 3
- b5 : TOUTPS2 : Timer2 OUTput PostScale bit 2
- b4 : TOUTPS1 : Timer2 OUTput PostScale bit 1
- b3 : TOUTPS0 : Timer2 OUTput PostScale bit 0
- b2 : TMR2ON : TiMeR 2 ON
- b1 : T2CKPS1 : Timer 2 ClocK PreScale bit 1
- b0 : T2CKPS0 : Timer 2 ClocK PreScale bit 0

Les bits TOUTPSx permettent de configurer la valeur du postdiviseur.


Il y a 16 valeurs possibles (0 à 15). Comme une valeur de diviseur de 0 n’a aucun sens, le
nombre formé par les 4 bits de TOUTPSx est incrémenté de 1 pour obtenir la valeur effective
du postdiviseur.
Les valeurs utilisables sont donc :

b6 b5 b4 b3 Postdiviseur
0 0 0 0 1
0 0 0 1 2
0 0 1 0 3
0 0 1 1 4
0 1 0 0 5
0 1 0 1 6
0 1 1 0 7
0 1 1 1 8
1 0 0 0 9

59
1 0 0 1 10
1 0 1 0 11
1 0 1 1 12
1 1 0 0 13
1 1 0 1 14
1 1 1 0 15
1 1 1 1 16

Quant au prédiviseur, il y a 3 valeurs :

b1 b0 Prédiviseur
0 0 1
0 1 4
1 0 16
1 1 16

La formule de la durée séparant 2 positionnements consécutifs du flag TMR2IF est :

Durée totale = temps d’une instruction * prédiviseur * postdiviseur * (PR2 +1)

La valeur maximale est, comme pour le timer 0 de 16*16*256 = 65536.

4.2. Un convertisseur analogique-numérique (CAN) 10 bits :

Le CAN présent dans le 16F877 est un CAN 10bits. Un CAN convertit une tension
analogique en une valeur numérique binaire, qui pourra ensuite être utilisée pour des calculs
ou autres. Sa résolution de 10bits donne une précision en 5V de 5mv environ.

Par ailleurs, ce CAN peut convertir les tensions de 8 voies analogiques.


Ce CAN étant associé au microcontrôleur, il va être possible d’envisager d’acquérir des
données.

4.2.1. Principe de conversion :

Le 16F877 travaille avec un convertisseur analogique / numérique qui permet un


échantillonnage sur 10 bits. Le signal numérique peut donc prendre 1024 valeurs possibles.
Pour pouvoir convertir une grandeur, nous devons connaître la valeur minimale qu’elle peut
prendre, ainsi que sa valeur maximale. Les pics considèrent par défaut que la valeur minimale
correspond à leur Vss d’alimentation, tandis que la valeur maximale correspond à la tension
positive d’alimentation Vdd. Mais il est cependant possible d’utiliser d’autres valeurs.
La séquence de conversion à l’interieur du PIC est la suivante :
- Le pic connecte la pin sur laquelle se trouve la tension à numériser à un condensateur
interne, qui va se charger via une résistance interne jusque la tension appliquée.
- Le pin est déconnecté du condensateur, et ce dernier est connecté sur le convertisseur
analogique/numérique interne.
- Le pic procède à la conversion.

4.2.2. Le temps d’acquisition :

60
C’est le temps qu’il faut pour que le condensateur interne atteigne une tension proche de
la tension à convertir. Cette charge s’effectue à travers une résistance interne et la résistance
de la source connectée au pin.
Ce temps est incrémenté du temps de réaction des circuits internes, et d’un temps qui dépend
de la température (coefficient de température). En effet que les résistances augmentent avec la
température, donc les temps de réaction des circuits également.
Donc, si on pose :

Tacq = temps d’acquisition total


Tamp = temps de réaction des circuits
Tc = temps de charge du condensateur
Tcoff = temps qui dépend du coefficient de température.
La formule est donc :
Tacq = Tamp + Tc + Tcoff

Le temps de réaction Tamp est typiquement de 2µs, Tamp = 2µs


Pour le coéfficient de température, il n’est nécessaire que pour les températures supérieures à
25°C. Dans les autres cas on peut le négliger. Ce coéfficient est typiquement de 0,05 µs par °C
qui est supérieur à 25°C. Donc, ce temps Tcoff sera au minimum de 0 (à moins de 25°C) et au
maximum de (50-25)*0.05, soit 1,25 µs. La t° du pic ne pouvant pas, en effet, excéder 50°C.

Le temps de charge dépend de la résistance placée en série avec le condensateur. En réalité,


il y a 2 résistances, celle de la source de signal, et celle à l’intérieur du PIC.
Il est recommandé que la résistance de la source reste inférieure à 10KOhms.
La résistance interne au PIC est directement liée à la tension d’alimentation. Plus la tension
baisse, plus la résistance est élevée, donc plus le temps de chargement est long.
La résistance interne totale (composée de 2 résistances internes) varie de 6Kohms à 6V
pour arriver à 12Kohms sous 3V, en passant par 8Kohms sous 5V.

Le condensateur interne à une valeur de 120pF, les formules du temps de chargement


d’un condensateur est :

Tc = -C * (Rinterne + Rsource) * ln (1/2047)

La valeur 2047 vient du fait que pour numériser avec une précision de ½ bit, la
numérisation utilisant une valeur maximale de 1023, la charge du condensateur doit être au
minimum de 2046/2047 ème de la tension à mesurer.
Comme « C » et « ln(1/2047) » sont des valeurs fixes la constante sera :

-C * ln(1/2047) = 0,914895 * 10 -9

La formule devient donc :

Tc = 0,914895 * 10 -9 * (Rinterne + Rsource)

Si on se place dans le cas le plus défavorable (tension de 3V, et résistance source =


10Kohms), notre temps de chargement est de =

Tc = 0,914895 * 10 -9 * (10 * 10³ + 12 * 10³)

61
Tc maximal = 20,12 µs

Pour le cas le plus favorable (tension de 6V, et résistance source négligeable) :

Tc = 0,914895 * 10 -9 * (0 * 10³ + 6 * 10³)

Tc minimal : 5,48 µs.

Dans le cas typique, à savoir une tension d’alimentation de 5V et une résistance de source de
10 Kohms, nous aurons :

Tc = 0,914895 * 10 -9 * (10 * 10³ + 8 * 10³)

Tc typique = 16,46 µs.

Le temps total d’acquisition Tacq pour le cas typique est :

Tacq sous 5V = 2µs + 16,46µs + 1,25µs = 19,71µs.

Donc, On prendra un Tacq de 20µs pour une alimentation de 5V.

4.2.3. La conversion :

Le principe utilisé est celui de l’approximation successive.


Cette méthode consiste à couper l’intervalle dans lequel se trouve la grandeur analogique en
2 parties égales, et de déterminer dans laquelle de ces deux parties se situe la valeur à
numériser. Une fois cet intervalle déterminé, on le coupe de nouveau en deux, et on continu
ainsi jusqu’à l’obtention de la précision demandée.Cette méthode permet un gain de temp
considérable.
Le temps nécessaire à la conversion est égal au temps nécessaire à la conversion d’un bit
multiplié par le nombre de bits désirés pour le résultat.
La conversion d’un bit nécessite un temps qu’on nomme Tad. Le temps de conversion Tad
peut prendre une valeure minimale de 1,6µs. La formule d’obtention des temps Tad est :

Le temps d’instruction (Tosc) divisé par le diviseur donné.

Le PIC nécessite également un temps Tad avant le démarrage effectif de la conversion, et


un temps supplémentaire Tad à la fin de la conversion. Donc, le temps total de conversion est
de :

- Tad : avant le début de conversion (le temps de connexion du condensateur est inclus)
- 10 * Tad pour la conversion des 10 bits du résultat
- Tad supplémentaire pour la fin de la conversion de b0

Le total, est un un temps de 12 Tad.

62
Un temps équivalent à 2 * Tad est nécessaire avant de pouvoir effectuer une nouvelle
conversion. Donc le temps nécessaire pour effectuer l’ensemble des opérations :

- chargement du condensateur interne (nécessite le temps Tacq)


- on effectue la conversion (nécessite le temps 12 * Tad)
- attente de 2 * Tad avant de pouvoir recommencer une autre conversion

4.2.4. Fréquence maximale d’échantillonage :

La fréquence maximale à la quelle on peut échantillonner le signal analogique, dans le


cas le plus défavorable avec une alimentation de 5V :

T entre 2 échantillonnages = Tacq + 12 Tad + 2 Tad = Tacq + 14 Tad


= 19.71+14*1.6 = 42.11µs
Ceci correspond à une fréquence de :

F = 1/T =23747 Hz

Cette fréquence permet d’échantillonner des signaux sinusoïdaux d’une fréquence maximale
de 11874 Hz (la moitié de la fréquence d’échantillonnage).

4.2.5 Les pins et les canaux utilisés par le convertisseur :

Le PIC ne contient qu’un seul convertisseur, mais il dispose de plusieurs pins sur
lesquelles connecter les signaux analogiques. Un circuit de commutation sélectionne laquelle
des pins sera reliée au condensateur de maintien interne durant le temps Tacq. Les différentes
entrées sont des canaux différents d’un seul convertisseur.
Le 16F877 dispose de 8 canaux d’entrée analogique. On peut échantillonner jusque 8 signaux
différents sur les pins AN0 à AN7. Les pins AN0 à AN4 sont les dénominations analogiques
des pins RA0 à RA5 (RA4 non inclus), tandis que les pins AN5 à AN7 sont les dénominations
analogiques des pins RE0 à RE2.

63
RA5/AN4

Fig12. Multiplexage des voies analogiques

4.2.6. Les tensions de référence :

La conversion analogique/numérique nécessite une tension de référence minimale (Vref-)


et une tension de référence maximale (Vref+).
Au niveau du PIC, il y a 3 modes de fonctionnement possibles :

- Utilisation de Vss (masse du PIC) comme tension Vref- et de Vdd (alimentation positive
du PIC) comme tension Vref+. Dans ce mode, les tensions de références sont éxtraites en
interne de la tension d’alimentation.

- Utilisation du pin Vref+ pour fixer la tension de référence maximale Vref+, et


utilisation de Vss comme tension de référence Vref-. Dans ce cas, la tension Vref+ doit
donc être fournie au PIC via le pin RA3.

- Utilisation de la pin Vref+ pour fixer la tension de référence maximale Vref+, et


utilisation du pin Vref- pour fixer la tension de référence minimale Vref-. Dans ce cas,
les deux tensions de références devront être fournies au PIC via RA3 et RA2.

64
La broche Vref+ est une dénomination alternative de la broche RA3/AN3, tandis que la
broche Vref- est une dénomination alternative de la broche RA2/AN2.
La procédure de numérisation, pour le cas où plusieurs canaux sont utilisés, est la suivante :

- On choisit le canal à numériser, on engage le convertisseur


- On attend Tacq
- On lance la numérisation
- On attend la fin de la numérisation
- On attend 2 Tad
- On recommence avec le canal suivant.

4.2.7. Les registres ADRESL et ADRESH :

Le résultat de la conversion est sauvegardé dans 2 registres. Ces registres sont ADRESL
et ADRESH.
Le résultat étant sur dix bits le résultat peut être soit justifié à gauche, soit à droite.
La justification à droite complète la partie gauche du résultat par des « 0 ». Le résultat obtenu
est de la forme :

La justification à gauche procède de la méthode inverse :

Le choix de la méthode s’effectue à l’aide du bit 7 de ADCON1.

Le registre ADRESH se situe en banque 0, alors que ADRESL se trouve en banque 1.

4.2.8. Le registre ADCON1 :

Ce registre permet de déterminer le rôle de chacune des pins AN0 à AN7.


Pour pouvoir utiliser un pin en mode analogique, il faudra que ce pin soit configuré également
en entrée par TRISE.
Le registre ADCON1 dispose de 8 bits, dont seulement 5 sont utilisés :

ADCON1
- b7 : ADFM : A/D result ForMat select
- b6 : Inutilisé : lu comme « 0 »
- b5 : Inutilisé : lu comme « 0 »
- b4 : Inutilisé : lu comme « 0 »
- b3 : PCFG3 : Port ConFiGuration control bit 3
- b2 : PCFG2 : Port ConFiGuration control bit 2
- b1 : PCFG1 : Port ConFiGuration control bit 1
- b0 : PCFG0 : Port ConFiGuration control bit 0

Le bit ADFM permet de déterminer si le résultat de la conversion sera justifié à droite (1)
ou à gauche (0).

65
On trouve dans ce registre 4 bits de configuration des pins liés au convertisseur
analogique/numérique. Ces bits permettent la détermination du rôle de chaque pin.
Il y a 16 combinaisons possibles, et autant de possibilités de configuration.

4.2.9. Le registre ADCON0 :

Ce registre est le dernier utilisé par le convertisseur analogique/numérique. Il contient les


bits qu’on manipule lors de la conversion. Sur les 8 bits du registre, 7 seront utilisés.

- b7 : ADCS1 : A/D conversion Clock Select bit 1


- b6 : ADCS0 : A/D conversion Clock Select bit 0
- b5 : CHS2 : analog Channel Select bit 2
- b4 : CHS1 : analog Channel Select bit 1
- b3 : CHS0 : analog Channel Select bit 0
- b2 : GO/DONE : A/D conversion status bit
- b1 : Inutilisé : lu comme « 0 »
- b0 : ADON : A/D ON bit

Afin de déterminer l’horloge du convertisseur en fonction de la fréquence du quartz


utilisé. On choisi le diviseur à l’aide des bits ADCS0 et ADCS1.

Le choix et la sélection du canal analogique pour procéder à la conversion s’effectuent à


travers les bits CHS0, CHS1 et CHS2.

66
CHS2 CHS1 CHS0 Canal Pin

0 0 0 0 AN0/RA0
0 0 1 1 AN1/RA1
0 1 0 2 AN2/RA2
0 1 1 3 AN3/RA3
1 0 0 4 AN4/RA5
1 0 1 5 AN5/RE0
1 1 0 6 AN6/RE1
1 1 1 7 AN5/RE2

Le bit ADON permet de mettre en service le convertisseur. Si le canal a été correctement


choisi, le positionnement de ce bit permet de démarrer la charge du condensateur interne, et
donc détermine le début du temps d’acquisition.
Le bit Go/DONE, sera placé à « 1 » à la fin du temps d’acquisition. Cette action détermine le
début de la conversion. Une fois la conversion terminée, ce bit est remis à 0 (« Done » = «
Fait ») par l’électronique du convertisseur. Cette remise à 0 est accompagnée du
positionnement du flag ADIF du registre PIR1. Ce bit permettra éventuellement de générer
une interruption.

4.2.10. La conversion analogique/numérique et les interruptions :

Cette partie ne comporte aucune difficulté particulière. En effet, l’interruption générée par
le convertisseur est une interruption périphérique, et doit donc être traitée comme telle. Les
différentes étapes de sa mise en service sont donc :
- Positionnement du bit ADIE du registre PIE1
- Positionnement du bit PEIE du registre INTCON
- Positionnement du bit GIE du registre INTCON
Moyennant quoi, toute fin de conversion analogique entraînera une interruption. Il vous
suffira de remettre à « 0 » le flag ADIF après traitement de cette interruption.

4.2.11. L’utilisation pratique du convertisseur :


Arrivé à ce stade, vous disposez de toutes les informations pour effectuer votre mesure de
grandeur analogique. Voici un résumé des opérations concrètes à effectuer pour échantillonner
votre signal :
1) Configurez ADCON1 en fonction des pins utilisées en mode analogique, ainsi que les
registres TRISA et TRISE si nécessaire.
2) Validez, si souhaitée, l’interruption du convertisseur.
3) Paramètrez sur ADCON0 le diviseur utilisé.
4) Choisissez le canal en cours de digitalisation sur ADCON0.
5) Positionnez, si ce n’est pas déjà fait, le bit ADON du registre ADCON0.
6) Attendez le temps Tacq (typiquement 19,7µs sous 5V).
7) Démarrez la conversion en positionnant le bit GO du registre ADCON0.
8) Attendez la fin de la conversion.
9) Lisez les registres ADRESH et si nécessaire ADRESL
10) Attendez un temps équivalent à 2Tad (typiquement 3,2µs).
11) Recommencez au point 4.
Notez que puisque l’acquisition redémarre automatiquement après le temps « 2 Tad »,
vous pouvez relancer l’acquisition directement, à votre charge d’attendre non pas le temps
Tacq pour la fin de l’acquisition, mais le temps Tacq + 2Tad. Ceci vous épargne une

67
temporisation. En effet, 2 temporisations qui se suivent peuvent être remplacées par une
temporisation unique de temps cumulé.
Si donc, nous prenons un PIC cadencée à 20Mhz, sous une tension d’alimentation de
5V, nous aurons :
1) Configurez ADCON1 en fonction des pins utilisées en mode analogique, ainsi que les
registres TRISA et TRISE si nécessaire.
2) Validez, si souhaité, l’interruption du convertisseur (PEIE, ADIE, GIE)
3) Paramètrez le diviseur 32 sur ADCON0 (B’10000000’)
4) Choisissez le canal en cours de digitalisation sur ADCON0 et lancez le convertisseur
(B’10xxx001’)
5) Attendez le temps (Tacq+2Tad), soit 19,7µs + 3,2µs = 22,9µs
6) Démarrez la conversion en positionnant le bit GO du registre ADCON0
7) Attendez la fin de la conversion
8) Lisez les registres ADRESH et si nécessaire ADRESL
9) Recommencez au point 4
Notez que vous pouvez, comme montré, réaliser plusieurs opérations en même temps.
Cependant, fort logiquement, vous ne pouvez pas positionner les bits ADON et
GO/DONE en même temps, puisque le temps Tacq doit impérativement les séparer.
Remarque :
Lorsque vous disposez de beaucoup de temps entre 2 lectures de la valeur analogique, nous
vous conseillons d’effectuer plusieurs mesures intermédiaires, et d’effectuer la moyenne de
ces mesures. Ainsi, un parasite éventuel, ou une légère fluctuation de votre tension sera
fortement atténuée.
Il est pratique dans ce cas d’effectuer un nombre de mesures qui est une puissance de 2 (2
mesures, 4,8,16…). Ainsi, pour effectuer votre moyenne, il suffira d’effectuer la somme de
toutes les valeurs, la division s’effectuant par simple décalage.

4.3. Les deux modules CCP et la génération (PWM) :

Ce module est très puissant pour créer des impulsions à des fréquences élevées. On pourra
définir la période, la durée du niveau haut pendant cette période.
Le 16F877 dispose de deux modules CCP. CCP signifie Capture, Compare, and PWM.
Ces modules CCP sont fortement liés et dépendant des timers 1 et 2. Ils sont également liés au
convertisseur A/D.
Les 2 modules CCP1 et CCP2 sont strictement identiques, excepté la possibilité, pour le
module CCP2, de démarrer automatiquement la conversion A/D.

4.3.1 Les registres CCP1CON et CCP2CON

Ces registres ont la même fonction, CCP1CON concerne le module CCP1, tandis que
CCP2CON concerne le module CCP2.
Le registre CCPxCON permet de déterminer le mode de fonctionnement du module.

CCPxCON
b7 : Inutilisé : Lu comme « 0 »
b6 : Inutilisé : Lu comme « 0 »
b5 : CCPxX : module Capture Compare and Pwm x bit X
b4 : CCPxY : module Capture Compare and Pwm x bit Y
b3 : CCPxM3 : module Capture Compare and Pwm x Mode select bit 3
b2 : CCPxM2 : module Capture Compare and Pwm x Mode select bit 2

68
b1 : CCPxM1 : module Capture Compare and Pwm x Mode select bit 1
b0 : CCPxM0 : module Capture Compare and Pwm x Mode select bit 0

Les bits CCPxX et CCPxY. Ces bits sont en fait les 2 bits de poids faible qui complètent le
nombre de 10 bits utilisé pour le mode de fonctionnement PWM. Dans les autres modes, ces
bits sont donc inutilisés.
Les bits CCPxM3 à CCPxM0 servent à déterminer quel sera le mode de fonctionnement
du module concerné. Les possibilités sont les suivantes :

CCPM Fonctionnement

0000 Module CCPx à l’arrêt


0100 Mode capture validé sur chaque flanc descendant
0101 Mode capture validé sur chaque flanc montant
0110 Mode capture validé sur chaque multiple de 4 flancs montants
0111 Mode capture validé sur chaque multiple de 16 flancs montants
1000 Mode compare, place la sortie à 1 sur débordement (+ bit CCPxIF = 1)
1001 Mode compare, place la sortie à 0 sur débordement (+ bit CCPxIF = 1)
1010 Mode compare, positionne CCPxIF sans affecter la sortie
1011 Mode compare, positionne CCPxIF sans affecter la sortie, et génère le trigger
11xx Mode PWM

4.3.2. Le mode « capture » :

Ce mode fait intervenir un pin comme événement déclencheur. Il s’agit donc d’une
entrée. Il est donc impératif de configurer le pin CCPx en entrée via le registre TRISC avant
de pouvoir utiliser le module CCPx en mode « capture ».

Principe de fonctionnement :
Le mode capture est en étroite liaison avec les pins RC1/CCP2 et RC2/CCP1 du PIC. le
principe est le suivant :
- Au moment de l’apparition de l’événement déclencheur sur le pin concernée, la valeur
(16bits) du timer 1 contenue dans les registres TMR1H et TMR1L est copiée dans les
registres CCPR1H et CCPR1L.
- Simultanément, le bit CCP1IF du registre PIR1 est validé, et une interruption intervient si
elle est configurée.
L’événement déclencheur est une variation du signal sur le pin CCP1/RC2 pour le module
CCP1, et sur le pin CCP2/RC1 pour le module CCP2. L’événement qui provoque la capture
dépend des bits CCPxM3 à CCPxM0.

4.3.3. Le mode « compare » :

Ce mode de fonctionnement est basé sur la correspondance de la valeur du timer


1(TMR1H/TMR1L) avec la valeur contenue dans CCPRxH/CCPRxL. L’égalité de ces valeurs
entraînera les réactions souhaitées.

4.3.4. Le mode « PWM » :

4.3.4.1 La théorie du « PWM » :

69
PWM signifie « Pulse Width Modulation », ce qu’on pourrait traduire par modulation de
largeur d’impulsion. Il s’agit d’un signal binaire de fréquence fixe dont le rapport cyclique
peut être modulé par logiciel.
Le module « PWM » a besoin d’un pin du PIC configurée en sortie.
Le rapport cyclique d’un signal binaire à fréquence fixe peut être défini comme étant le
rapport entre le temps où il se trouve à l’état « 1 » par rapport au temps total d’un cycle. Un
cycle n’étant constitué, par définition, que d’un état « 1 » suivi d’un état « 0 », la somme des
temps des 2 états étant constante.
Il y a donc deux paramètres qui définissent un signal « PWM » :
- La durée d’un cycle complet
- Le rapport cyclique

Donc, si on pose :

- Tc = Durée d’un cycle


- Rc le rapport cyclique
- Th = durée de l’état haut
- Tb = durée de l’état bas

Alors :

- Tc = Th + Tb (Durée d’un cycle en secondes = durée de l’état haut + durée de l’état


bas)
- Fréquence du signal (en hertz) = 1/Tc
- Rc = Th / Tc (rapport cyclique en % = temps à l’état haut divisé par le temps de cycle)

Fig13. Signal PWM avec un rapport cyclique de 50% (0.5)

Un signal avec un rapport cyclique de 0% est un signal dont le temps à l’état haut occupe
0% du temps total. C’est donc un signal qui est constamment à l’état bas. De même, un signal
avec un rapport cyclique de 100% est un signal qui est constamment à l’état haut.

70
Le rapport cyclique d’un signal PWM doit donc être supérieur à 0% et inférieur à 100%.
Le PIC permet donc de créer un signal périodique dont il est possible de faire varier (moduler)
le rapport cyclique.

4.3.4.2 Les registres utilisés :

On a besoin de plusieurs registres pour programmer toutes les valeurs nécéssaires au


module.
On a besoin d’une valeur de débordement pour le timer 2, cette valeur se trouve dans le
registre PR2. C’est une valeur sur 8 bits. La valeur de la seconde comparaison (celle qui fait
passer la sortie de 1 à 0) est une valeur de 8 bits complétée de 2 bits fractionnaires.
Le nombre entier sera inscrit dans le registre CCPRxL. Les 2 bits fractionnaires qui
complètent ce nombre sont les bits DCxB1(CCP1X) et DCxB0(CCP1Y) du registre
CCPxCON.
Pour lancer le mode « PWM », nous devons donc procéder aux initialisations suivantes :

1) On initialise PR2 en fonction de la durée totale du cycle (Tc):


PR2 = (TC / (prédiviseur * 4 * Tosc) – 1

2) On calcule la valeur de comparaison DCB en valeur fractionnaire suivant la formule :


DCB = Th / (prédiviseur * Tosc)
On place les bits 9 à 2 dans CCPRxL (valeur entière), les bits 1 et 0 (fraction) étant
positionnés dans DCxB1 et DCxB0 du registre CCPxCON.

3) On place le pin CCPx en sortie en configurant TRISC.

4) On lance le timer 2 en programmant son prédiviseur.

5) On configure CCPxCON pour travailler en mode « PWM ».

71
Fig14.Fonctionnement en mode PWM
4.3.4.3. Remarques :

La valeur de référence encodée dans CCPRxL ne peut être supérieure à la valeur contenue
dans PR incrémentée de 1. Dans le cas contraire, le signal ne pourrait jamais atteindre cette
consigne, et la pin CCPx resterait bloquée au niveau haut (rapport cyclique > 100%) Il est
possible d’utiliser le timer 2 à la fois comme timer classique et comme générateur pour le
module PWM.
Le registre CCPRxH n’est pas accessible en écriture lors du fonctionnement en mode
PWM.
La prise en compte du changement de valeur du rapport cyclique ne se fera qu’après la fin du
cycle en cours.

4.3.5 Champs d’application

En fait, vous utiliserez ce module chaque fois que vous aurez besoin d’un signal de
fréquence fixe, mais de rapport cyclique variable. L’application typiquee est la variation de
vitesse d’un moteur à courant continu.

4.4 Le module MSSP en mode SPI :

Le module MSSP, pour Master Synchronous Serial Port, permet l’échange de données du
PIC avec le mode extérieur, en utilisant des transmissions série synchrones.
Il n’est pas le seul à proposer des communications, nous avons déjà vu la liaison parallèle
dans le module PSP, et nous verrons d’autres communications série avec le module USART.
Vous verrez que l’ensemble de ces modules vous ouvre toutes les voies royales de la
communication, que ce soit avec votre PC, avec des afficheurs, des mémoires de type

72
eeprom, des détecteurs de température, des horloges en temps réel, etc…
Avec ces modules, nous n’avons plus à nous occuper de la transmission des bits en eux-
mêmes, mais nous les recevrons et émettrons directement sous forme d’octet, toute la
procédure de sérialisation étant alors automatique.
Outre le gain en taille programme qui en découlera, vous vous rendez compte que les
vitesses de transmission pourront être améliorées de façon notable. Au lieu que votre
programme ne soit interrompu lors de la réception ou de l’émission de chaque bit, il ne le sera
plus que pour chaque octet. Ceci multiplie allègrement la vitesse maximale possible dans un
facteur de plus de 10.
Il y a tellement de modes possibles de fonctionnement, qu’il ne nous sera pas possible de
donner systématiquement des exemples. Nous nous limiterons donc à des situations courantes.
Nous verrons que le module MSSP peut travailler selon 2 méthodes. Soit en mode SPI (Serial
Peripherial Interface), soit en mode I2C.

4.5.Le module USART :

4.5.1 Le mode série asynchrone


Une liaison série asynchrone, comme son nom l’indique, fonctionne de la même façon, en
émettant les bits les uns à la suite des autres, mais sans fournir le signal d’horloge qui a
permis de les générer.
Ceci a forcément plusieurs conséquences, dont les suivantes :
- Comme le récepteur d’une donnée ne reçoit pas le signal d’horloge, il doit savoir à quelle
vitesse l’émetteur a généré son transfert. C’est en effet la seule façon pour lui de savoir
quand commence et quand fini un bit.
- Comme émetteur et récepteur se mettent d’accord pour adopter une vitesse commune, et
étant donné que chacun travaille avec sa propre horloge, de légères différences peuvent
apparaître sur les 2 horloges, introduisant des dérives. Il faudra gérer ceci.
- Il faut un mécanisme qui permette de détecter le début d’une donnée. En effet, imaginons
que la ligne soit à niveau « 1 » et que l’émetteur décide d’envoyer un « 1 ». Comment
savoir que la transmission a commencé, puisque rien ne bouge sur la ligne concernée ?
- De la même façon, il faut établir un mécanisme pour ramener la ligne à son état de repos
en fin de transmission. Ceci étant indispensable pour permettre la détection de la donnée
suivante.
- Notez enfin que dans les transmissions asynchrones, la grande majorité des liaisons
procèdent en commençant par l’envoi du bit 0. Ce sera notre cas.
La liaison utilisera les 2 mêmes pins que pour la liaison synchrone, à savoir RC6/TX/CK
et RC7/RX/DT. Les dénominations qui conviendront dans ce cas seront bien entendu TX pour
l’émission et RX pour la réception.
Ces pins devront être configurées en entrée via TRISC pour fonctionner en mode USART.
4.5.1.1 Le start-bit :
Au repos, nous allons imaginer que notre ligne soit au niveau « 1 ». Nous choisissons ce
niveau parce que c’est celui présent sur la ligne d’émission de votre PIC. Rien n’empêche de
travailler avec une électronique qui modifie ces niveaux, comme par exemple l’utilisation
d’un driver RS485 (par exemple le MAX485), ou un pilote RS232 (comme le MAX232) qui
permettra a votre liaison série de devenir compatible électriquement avec le port RS232 de
votre PC .
Donc, notre ligne se trouve à « 1 ». Or, nous n’avons qu’une seule ligne dédicacée à un
sens de transfert, donc nous disposons d’un seul et unique moyen de faire savoir au
destinataire que la transmission a commencé, c’est de faire passer cette ligne à « 0 ».
On peut donc simplement dire que le start-bit est :

73
- Le premier bit émis
- Un bit de niveau toujours celui opposé au niveau de repos (donc 0 dans notre cas).
- Un bit d’une durée, par convention, la même que celle d’un bit de donnée.
4.5.1.2 Les bits de donnée :
Nous avons envoyé notre start-bit, il est temps de commencer à envoyer nos bits de
donnée. En général, les bits de donnée seront au nombre de 7 ou de 8 (cas les plus courants).
La durée d’un bit est directement liée au débit choisi pour la connexion. En effet, le débit
est exprimé en bauds, autrement dit en bits par seconde. Donc, pour connaître la durée d’un
bit, il suffit de prendre l’inverse du débit.
Tb = 1 / Débit.
Par exemple, si on a affaire à une connexion à 9600 bauds, nous aurons :
Tb = 1 / 9600 bauds = 104,16 µs.
4.5.1.3 La parité :
Directement après avoir envoyé nos 7 ou 8 bits de données, nous pouvons décider
d’envoyer ou non un bit de parité. Ce bit permet d’imposer le nombre de bits à « 1 » émis
(donnée + parité), soit comme étant pair (parité paire), soit comme étant impair (parité
impaire).
Le récepteur procède à la vérification de ce bit, et, si le nombre de bits à « 1 » ne
correspond pas à la parité choisie, celui-ci saura que la réception ne s’est pas effectuée
correctement. La parité permet de détecter les erreurs simples, elle ne permet ni de les réparer,
ni de détecter les erreurs doubles. Par contre, la détection fréquente d’erreurs de parité indique
un problème dans l’échange des données.
Voici par exemple, un cas de parité paire :
La donnée vaut : B’00110100’
Nous avons 3 bits à « 1 ». Donc, pour avoir notre parité paire, notre bit de parité devra donc
valoir « 1 », ce qui forcera le nombre total de bits « 1 » à valoir « 4 », ce qui est bien pair.
On enverra donc :
B’001101001’ : 4 bits à « 1 » = parité paire
4.5.1.4 Le stop-bit :
Nous avons maintenant émis tous nos bits de donnée et notre parité éventuelle. Reste à
permettre à notre ligne de transmission de revenir à l’état de repos. Ce passage est dénommé
« stop-bit ».
On peut dire à son sujet que :
- Il sera le dernier bit émis de l’octet
- Son niveau est toujours celui du niveau de repos (donc 1 dans notre cas).
- Sa durée sera par convention la même que celle d’un bit de donnée.
Le stop-bit n’est pas comptabilisé (pas plus que le start-bit) pour le calcul du bit de parité.
Notez qu’il est permis d’imposer l’utilisation de 2 « stop-bits ».
Une autre façon de voir les choses, est de dire qu’on ne pourra envoyer l’octet suivant
qu’après une durée Tb après l’émission du premier stop-bit. Où, dit encore autrement, on doit
ménager une pause d’une durée de 1 bit, entre l’émission de 2 octets consécutifs.
Un mot concernant la lecture d’un bit par le récepteur. Il est évident que la lecture de
chaque bit doit s’effectuer dans la zone présentant la plus grande probabilité de stabilité du
bit. En général, les électroniques sont construites pour mesurer le bit au milieu de sa durée.
Voici, pour illustrer tout ceci, l’émission d’une donnée codée sur 8 bits, avec parité paire
et un stop-bit. Les lectures sont indiquées par les flèches inférieures :

74
4.5.2 Mise en œuvre :
Le PIC est capable de travailler en mode full-duplex. Ceci vous laisse plusieurs
possibilités de configuration. Voyons tout d’abord comment interconnecter les circuits dans
ce mode :

Dans ce cas, notre PIC est privilégié, puisqu’il peut parler avec le circuit 2 et 3, alors que
ces circuits ne peuvent dialoguer entre eux.
Vous voyez donc que le mode full-duplex procure un inconvénient. Soit on se contente de
communiquer entre 2 composants, soit, si on a plus de 2 composants, un seul se trouve en
situation privilégiée.
Notez que nous représentons toujours des liaisons directes, connectées directement sur votre
PIC. On peut aussi, pour diverses raisons, dont la principale est d’allonger les distances de
communication, utiliser des pilotes de lignes spécifiques.
Prenons par exemple le cas de la communication half-duplex entre votre PIC et le port
série d’un PC :

Vous notez la présence d’un driver de ligne, de type MAX232 qui convertit les niveaux

75
0v/5V de votre PIC en niveaux +12V/-12V à destination de la RS232 de votre PC, et
réciproquement. La norme RS232 est également une norme qui précise un mode de
fonctionnement full-duplex.

4.5.3 le registre TXSTA :

TXSTA en mode asynchrone :

b7 : non : non utilisé en mode asynchrone


b6 : TX9 : TRANSMITT 9 bits enable bit (1 = 9 bits, 0 = 8 bits)
b5 : TXEN : TRANSMITT ENable bit
b4 : SYNC : SYNChronous mode select bit (1 = synchrone, 0 = asynchrone)
b3 : N.U. : Non Utilisé : lu comme « 0 »
b2 : BRGH : Baud Rate Generator High mode select bit
b1 : TRMT : TRansMiT shift register status bit (1 = TSR vide)
b0 : TX9D : TRANSMIT 9th bit Data

Voyons ou rappelons ce que signifie tout ceci :


TX9 : indique si vous voulez envoyer des données codées sur 8 ou sur 9 bits. Un bit placé
à 1 ici conduira à émettre des données codées sur 9 bits.
TXEN : permet de lancer l’émission. Cette fois, en mode asynchrone, votre USART pourra
émettre et recevoir en même temps. Rien donc ne vous empêche de sélectionner émission et
réception simultanée. Nous ne retrouverons donc pas ici la notion de priorité de commande.
SYNC : indique si vous travaillez en mode synchrone (1) ou asynchrone (0). Dans ce
paragraphe, nous traitons le mode asynchrone, donc ce bit devra être positionné à « 0 ».
BRGH : permet de choisir entre 2 prédiviseurs internes pour la génération des bits en
fonction de SPBRG. Nous aurons un mode grande vitesse (BRGH = 1) et un mode basse
vitesse (BRGH = 0). Nous en reparlerons au moment de l’étude de SPBRG.
TRMT : indique quand le registre TSR est vide, c’est-à-dire quand l’émission de la dernière
valeur présente est terminée.
TX9D : contient la valeur du 9ème bit à envoyer, quand vous avez décidé, via le
positionnement de TX9, de réaliser des émissions de mots de 9 bits.

4.5.4 Le registre RCSTA :

RCSTA en mode asynchrone :

b7 : SPEN : Serial Port ENable bit


b6 : RX9 : RECEIVE 9 bits enable bit (1 = 9 bits, 0 = 8 bits)
b5 : non : non utilisé en mode asynchrone
b4 : CREN : Continuous Receive ENable bit
b3 : ADDEN : ADDress detect ENable bit
b2 : FERR : Frame ERRor
b1 : OERR : Overflow ERRor bit
b0 : RX9D : RECEIVE 9th Data bit

Quant au rôle de chacun de ces bits :


SPEN : met le module USART en service.
RX9 : permet de choisir une réception sur 8 ou sur 9 bits, exactement comme pour
l’émission.

76
CREN : lance la réception continue. Les octets seront reçus sans interruption jusqu’à ce que
ce bit soit effacé par vos soins. Dans le mode asynchrone, il n’existe que ce mode de
réception.
FERR : indique une erreur de trame. Ceci se produit lorsqu’au moment où devrait
apparaître le stop-bit en mode lecture, l’USART voit que la ligne de réception est à « 0 ». Ce
bit est chargé de la même façon que le bit RX9D. Autrement dit, ce n’est pas un flag à effacer,
c’est un bit qui est lié à la donnée qu’on vient de lire. On doit donc lire ce bit, tout comme
RX9D : avant de lire RCREG. Une fois ce dernier lu, le nouveau FERR écrase l’ancien. Si
vous suivez, on a donc un bit FERR vu comme s’il était le 10ème bit du mot reçu.
OERR : indique une erreur de type overflow. Il se retrouve positionné si vous n’avez pas lu
RCREG suffisamment vite. L’effacement de ce bit nécessite le reset de CREN. Le non
effacement de OERR positionné bloque toute nouvelle réception d’une donnée.
RX9D : contient le 9ème bit de votre donnée reçue, pour autant, bien entendu, que vous ayez
activé le bit RX9.

4.5.5 Le registre SPBRG :


Ce registre, tout comme pour le mode synchrone, permet de définir le débit qui sera utilisé
pour les transferts. C’est le même registre qui est utilisé pour émission et réception. De ce fait,
un transfert full-duplex s’effectuera toujours avec une vitesse d‘émission égale à celle de
réception.
Par contre, en mode half-duplex, rien ne vous empêche de modifier SPBRG à chaque
transition émission/réception et inversément.
Nous avons 2 grandes différences pour ce registre par rapport au mode synchrone :
- Le registre SPBRG doit toujours être configuré, puisque tous les interlocuteurs doivent
connaître le débit utilisé
- La formule utilisée pour le calcul de SPBRG n’est pas identique à celle du mode
synchrone.
En réalité, nous avons 2 formules distinctes, selon que nous aurons positionné le bit
BRGH à « 1 » ou à « 0 »
Si BRGH = 0 (basse vitesse)
Débit = Fosc / (64 * (SPBRG + 1))
Ou encore :
SPBRG = (Fosc / (Débit * 64)) – 1
Les limites d’utilisation sont (avec un PIC à 20MHz) :
Débit min = 20*106 / (64 * (255+1)) = 1221 bauds
Débit max = 20*106 / (64 * (0+1)) = 312.500 bauds
Si BRGH = 1 (haute vitesse)
Débit = Fosc / (16 * (SPBRG + 1))
Ou encore :
SPBRG = (Fosc / (Débit * 16)) – 1
Les limites d’utilisation sont (avec unPIC à 20MHz) :
Débit min = 20*106 / (16 * (255+1)) = 4883 bauds
Débit max = 20*106 / (16 * (0+1)) = 1.250.000 bauds
Vous voyez tout de suite que le mode basse vitesse permet d’obtenir des vitesses plus
basses, tandis que le mode haute vitesse permet de monter plus haut en débit. Il existe une
zone couverte pas les 2 modes. Dans ce cas, vous choisirez BRGH = 1 si cela vous permet
d’obtenir le taux d’erreur le moins élevé.

Pour l’émission :
- Vous validez la mise en service de l’émission en positionnant le bit TXEN.

77
- La validation de TXEN positionne le flag TXIF à « 1 » puisque le registre TXREG est
vide.
- Si vous utilisez le format de donnée sur 9 bits, vous devez commencer par placer la valeur
du 9ème bit dans le bit TX9D.
- Ensuite, vous placez la donnée à émettre dans le registre TXREG (TRANSMITT
REGister).
- Cette donnée est transférée dès le cycle d’instruction suivant, ainsi que le bit TX9D, dans
son registre TSR. TRMT passe à « 0 » (TSR plein).
- Vous recommencez éventuellement le chargement de TX9D + TXREG, le flag TXIF
passe à « 0 » (TXREG plein)
- Dès que le premier octet est émis, le second est transféré dans TSR, le registre TXREG est
vide, TXIF est positionné. Vous pouvez charger le troisième octet, et ainsi de suite.
- Quand le dernier octet est transmis, TRMT passe à 1 (TSR vide, émission terminée)
Avec toujours les mêmes remarques :
- Vous avez toujours un octet en cours de transmission dans TSR, le suivant étant déjà prêt
dans TXREG.
- Si on a besoin de 9 bits, on place toujours TX9D avant de charger TXREG.
- Chaque fois que TXIF passe à 1 (avec interruption éventuelle), vous pouvez recharger
TXREG avec l’octet suivant (tant que vous en avez).
- Quand la communication est terminée, TRMT passe à 1.
- TXIF passe à « 1 » dès que TXEN est positionné
Pour qu’il y ait une émission, il faut donc que, le module étant initialisé et lancé :
- TXEN soit positionné
- Le registre TXREG soit chargé
Pour la réception :
- Vous positionnez CREN, ce qui a pour effet que votre PIC est prêt à recevoir une donnée.
- L’octet reçu est transféré dans le registre RCREG (le 9ème bit éventuel est transféré vers
RX9D), et le flag RCIF est positionné
- Vous lisez alors le bit RX9D éventuel puis le registre RCREG, ce qui provoque
l’effacement du bit RCIF.
De nouveau, nous retrouvons notre file FIFO, qui nous permettra de recevoir 2 octets
(plus un en cours de réception), avant d’obtenir une erreur d’overflow. Pour rappel :
- Le premier octet est en cours de réception dans RSR, RCREG est vide, donc RCIF est à
«0»
- Le premier octet est reçu et transféré dans la file de RCREG, RCIF est positionné, le
second octet est en cours de réception dans RSR
- Si vous ne réagissez pas de suite, le second octet est reçu et transféré dans la file de
RCREG, RCIF reste positionné, le troisième octet est en cours de réception dans RSR.
Comme on n’a que 2 emplacements, vous devrez réagir avant la fin de la réception du
troisième octet, mais vous voyez que votre temps de réaction peut être allongé. Voici alors ce
que vous allez faire dans ce cas :
- Vous lisez, si vous travaillez sur 9 bits, le 9ème bit, RX9D, puis RCREG, donc le premier
octet reçu. Cette lecture ne provoque pas l’effacement de RCIF, puisque RCREG n’est pas
vide. Par contre, le 9ème bit du second octet est transféré à ce moment dans RX9D, ce qui
explique que vous deviez le lire en premier.
- Vous lisez alors, si vous travaillez sur 9 bits, le bit RX9D qui est le 9ème bit de votre
second octet, puis RCREG, donc le second octet reçu. Le flag RCIF est effacé, le registre
RCREG est vide.
L’erreur d’overflow sera générée si un troisième octet est reçu alors que vous n’avez pas
lu les deux qui se trouvent dans la file FIFO. Le positionnement empêche toute nouvelle

78
réception. L’effacement de ce bit nécessite d’effacer CREN.
Votre réaction devrait donc être du style :
- Tant que RCIF est positionné
- Je lis RX9D puis RCREG
- RCIF n’est plus positionné, OERR est positionné ?
- Non, pas de problème
- Oui, je sais que j’ai perdu un octet et je coupe CREN
Evidemment, vous avez beaucoup moins de chance d’avoir une erreur d’overflow si vous
travaillez via les interruptions, ce que nous vous conseillons fortement dans ce mode.
4.5.6 L’erreur de frame :
L’erreur de frame survient si, au moment où l’USART s’attend à recevoir un stop-bit, il
voit que le niveau de sa ligne de réception est positionnée à « 0 ». Dans ce cas, quelque chose
s’est mal déroulé.
Le bit FERR sera positionné, mais, attention, ce bit fait partie de la file FIFO, tout comme
le bit RX9D. Donc, vous lisez RX9D et FERR, et, ensuite, vous lisez RCREG. A ce
moment, le nouveau bit FERR concernant l’octet suivant écrasera le FERR actuel, exactement
comme le nouveau bit RX9D effacera l’actuel.Vous n’avez donc pas à effacer FERR, qui est,
du reste, en lecture seule.

4.6.Port D en mode PSP :

4.6.1 A quoi sert le mode PSP ?


Le mode PSP (pour Parallel Slave Port) permet à un microprocesseur, ou à tout autre
système extérieur de prendre le contrôle du PORTD de votre PIC. Ce système pourra écrire de
lui-même des valeurs sur le PORTD, et y lire des valeurs que votre programme PIC y aura
préparée à son intention.
Le PORTD devra donc passer alternativement en entrée et en sortie, et sous la seule
décision du système extérieur. C’est donc celui-ci qui décide à quel moment une lecture ou
une écriture s’opère. Les transferts sont donc réalisés de façon asynchrones avec le
programme de votre PIC.
Voici une affaire qui va intéresser les électroniciens « pointus » désireux d’interfacer leur
PIC avec un autre processeur, de façon à, par exemple, obtenir un super UART.
Pour les autres, ne vous inquiétez pas si vous ne comprenez pas tout, car vous n’utiliserez
probablement jamais cette possibilité, et, du reste, cela ne vous empêchera pas de profiter des
autres possibilités de votre PIC.
La première chose est de bien se mettre d’accord sur les termes. Nous parlons ici du
PORD en mode parallèle. Il ne s’agit pas ici du port parallèle de votre imprimante, mais de la
méthode de communication entre 2 microprocesseurs.
Ensuite, il faut comprendre que ce mode est un mode « Slave » (esclave), c’est à dire sous
le contrôle du microprocesseur sur lequel vous connectez votre PIC. C’est ce processeur qui
va prendre le contrôle de votre PORTD.
4.6.2 Comment passer en MODE PSP ?
La première chose à faire est de forcer le bit PSPMODE du registre TRISE à « 1 ».
Ensuite, les 3 pins RE0/RE2 sont utilisées dans un de leur mode spécial et portent de fait les
dénominations RD/CS/WR. Ces pins sont actifs à l’état bas. Ces pins sont sous contrôle du
microprocesseur maître, ce qui fait que vous devez les configurer en entrée via les bits b0/b2
de TRISE.
Mais il se fait, toujours si vous êtes attentifs, que c’est la valeur imposée par une mise
sous tension, donc inutile de vous en occuper.
Vous notez également que le PORTD passe sous contrôle de ces pins, le registre TRISD

79
n’est donc plus d’aucune utilité : inutile de le configurer.
Notez que dans la plupart des cas, vous utiliserez les interruptions pour gérez ce mode de
fonctionnement, vous devez donc mettre en service l’interruption PSP .
En effet, les échanges d’information se font sur décision du microprocesseur maître, et
donc de façon asynchrone avec le programme de votre PIC. Les interruptions restent la
meilleure façon de traiter rapidement les événements asynchrones.

4.6.3. Connexion des PORTD et PORTE en mode PSP :


Si nous reprenons nos 3 pins du PORTE, avec les noms utilisés pour cette fonction, c’est à
dire RD, CS, et WR, nous pourrons dire :
La pin « CS » est la pin « Chip Select », que tous les électroniciens spécialisés dans les
microprocesseurs connaissent.
Pour les autres, on peut dire que le « Chip Select » permet de valider la sélection du circuit
concerné, en l’occurrence notre PIC.
Sur la carte à microprocesseur, un détecteur d’adresse, placé sur le bus d’adresse permet
de sélectionner l’adresse à laquelle va répondre notre PIC. Comme dans la plupart des
systèmes, ce « CS » sera actif à l’état bas.
Ensuite, nous trouvons les signaux « RD » pour « ReaD » et « WR » pour « WRite ». De
nouveau ces signaux sont actifs à l’état bas. Notez que sur certains microprocesseurs, il
n’existe qu’une seule pin RD/WR. A vous donc dans ce cas de générer électroniquement les 2
signaux, ce qui n’est pas compliqué.
Maintenant, concernant le PORD, il sera connecté au bus de data de la carte à
microprocesseur.
Notez, une fois de plus, que sur certains microprocesseurs, les bus de data et d’adresse
peuvent être multiplexés, ou d’une largeur différente de 8 bits. Il vous incombe une fois de
plus de rendre les signaux et les messages compatibles électroniquement.

4.7. liaison I2C :

4.7.1 Introduction
On passe directement à l’étude du module MSSP en mode I²C, et par conséquent on doit
commencer par expliquer en quoi consiste ce bus.
En effet, bien que le module prenne en charge tous les aspects de gestion de ce bus, il m’a
semblé important de comprendre ce qui se passait effectivement au niveau des lignes qui le
constituent.
De plus, l’absence de ces informations vous poserait problème au moment d’établir une
communication avec un composant I²C. En effet, lorsque vous rencontrerez un nouveau
composant, tout ce dont vous disposerez à son sujet sera, en général, son datasheet. Sans une
connaissance assez précise du bus I²C, vous vous retrouveriez confronté à quelque chose qui
risquerait bien de vous paraître incompréhensible.
Et puis, mieux vaut avoir une information qu’on n’utilisera éventuellement pas qu’une
absence d’information au moment où on en a besoin.
4.7.2 Caractéristiques fondamentales :
Le bus I²C permet d’établir une liaison série synchrone entre 2 ou plusieurs composants.
Il a été créé dans le but d’établir des échanges d’informations entre circuits intégrés se
trouvant sur une même carte. Son nom, d’ailleurs, traduit son origine : Inter Integrate Circuit,
ou I.I.C., ou plus communément I²C (I carré C). Ce bus est le descendant du CBUS, qui est de
moins en moins utilisé.
Son domaine d’application actuel est cependant bien plus vaste, il est même, par exemple,
utilisé en domotique.
Il comporte des tas de similitudes avec le SMBUS d’Intel (System Management BUS),

80
mais on ne parlera pas de ce bus ici. Si cela vous intéresse, vous trouverez des informations
sur Internet. Sachez simplement que nos 16F87x peuvent créer des signaux compatibles avec
cette norme.
L’ I²C permettait, à ses débuts, de travailler à des fréquences maximales de 100
Kbits/seconde, vitesses assez rapidement portées à 400 Kbits/seconde. Il existe maintenant
des familles de circuits pouvant atteindre des vitesses de 3.4 Mbits/seconde. Le
fonctionnement théorique reste identique.
Le bus I²C est constitué de 2 uniques lignes bidirectionnelles :
- La ligne SCL (Serial Clock Line), qui, comme son nom l’indique, véhicule l’horloge de
synchronisation
- La ligne SDA (Serial DAta line), qui véhicule les bits transmis.
Il est important de vous souvenir que :
- la ligne SCL est gérée par le maître (nous verrons que par moment, l’esclave peut prendre
provisoirement le contrôle de la ligne).
- la ligne SDA, à un moment donné, est pilotée par celui qui envoie une information (maître
ou esclave).
Tous les circuits sont connectés sur ces 2 lignes. Il existe 2 sortes de circuits pouvant être
connectés :
- Les circuits maîtres, qui dirigent le transfert et pilotent l’horloge SCL.
- Les circuits esclaves, qui subissent l’horloge et répondent aux ordres du maître.
Chacun de ces 2 types peut émettre et recevoir des informations.
Une particularité est qu’on peut placer plusieurs maîtres sur le même bus I²C. Ceci
implique que, sans précautions, si 2 maîtres désirent prendre le contrôle du bus en même
temps, on encourrait, sans précautions particulières, 2 risques :
- La destruction de l’électronique des circuits, pour le cas où l’un d’entre eux impose un
niveau haut et l’autre un niveau bas (court-circuit).
- La corruption des données destinées ou en provenance de l’esclave.
Fort heureusement, vous vous doutez bien que Philips (l’inventeur de l’I²C) a trouvé des
solutions pour parer à ces éventualités.On commence par les contraintes électroniques.
Pour la partie électronique, la parade est simple. On travaille avec des étages de sortie qui
ne peuvent imposer qu’un niveau 0, ou relâcher la ligne, qui remonte d’elle-même au niveau 1
via des résistances de rappel.
De cette façon, on n’aura jamais de court-circuit, puisque personne ne peut placer la
tension d’alimentation sur la ligne. Ces étages sont des montages que vous trouverez dans la
littérature sous la dénomination de « collecteur ouvert » ou de « drain ouvert » suivant la
technologie utilisée. Le pin RA4 de votre PIC utilise d’ailleurs la même technique.
Le schéma d’interconnexion des circuits sur un bus I²C est donc le suivant :

81
Fig15. Connexion de plusieurs composants sur le bus I2C

4.7.3 Les différents types de signaux :


Nous allons voir que cette norme joue intelligemment avec les niveaux présents sur les 2
lignes, afin de réaliser diverses opérations. Plutôt que de vous donner directement un
chronogramme de transmission, on va scinder les différentes étapes. De cette façon ca sera
beaucoup plus simple à comprendre.
4.7.3.1 Le bit « ordinaire » :
Tout d’abord, la méthode utilisée pour écrire et recevoir des bits est différente de celle
utilisée dans l’étude de notre module SPI. En effet, pour ce dernier, un bit était émis sur un
flanc de l’horloge, et était lu sur le flanc opposé suivant de la dite horloge.
Au niveau du bus I²C, le bit est d’abord placé sur la ligne SDA, puis la ligne SCL est
placée à 1 (donc libérée) durant un moment puis forcée de nouveau à 0. L’émission du bit
s’effectue donc sans aucune correspondance d’un flanc d’horloge. Il est lu lors du flanc
montant de cette horloge.
Notez qu’il est interdit de modifier la ligne SDA durant un niveau haut de SCL. La dérogation
à cette règle n’est valable que pour les séquences dites « de condition ».Voici à quoi ressemble
l’émission et la lecture d’un bit :

82
Vous constatez que le bit présent sur la ligne SDA doit être présent avant la montée du
signal SCL, et continuer un certain temps avant sa redescente.
4.7.3.2 Le start-condition :
Comme pour tout signal synchrone, le protocole ne définit pas de start et de stop-bit. Mais
il intègre toutefois les notions de « start-condition » et de « stop-condition ». Ces séquences
particulières, obtenues en modifiant la ligne SDA alors que la ligne SCL est positionnée à
l’état haut permettent de définir début et fin des messages. Nous verrons que ceci est
indispensable pour repérer le premier octet du message, qui a un rôle particulier.
Si on se souvient qu’au repos, SCL et SDA se trouvent relâchés, et donc à l’état haut, le
start-condition (symbole conventionnel : S) est réalisé simplement en forçant la ligne SDA à
0, tout en laissant la ligne SCL à 1.

Il existe un dérivé de cette condition, appelé « repeated start condition », qui est utilisé
lorsqu’un message en suit directement un autre. Il s’agit donc en fait d’un second
startcondition au sein d’un même message. Sachez à ce niveau qu’un « repeated start-
condition » peut être considéré comme identique à un « startcondition ».
4.7.3.3 Le stop-condition :
Nous venons d’y faire allusion. Cette condition indique la fin du message en cours. Elle
remet les lignes SDA et SCL au repos, mais en respectant la chronologie suivante :
La ligne SDA est ramenée à 1, alors que la ligne SCL se trouve déjà à 1. Voici ce que cela
donne :

4.7.3.4 L’acknowledge :
L’acknowledge (ACK) est en fait l’accusé de réception de l’octet envoyé. C’est donc le
récepteur qui émet ce bit pour signaler qu’il a bien lu l’octet envoyé par l’émetteur. Cet accusé
de réception est lu comme un bit classique. Il vaudra 0 si l’accusé de réception signifie « OK
», et 1 pour toute autre raison (récepteur dans l’impossibilité de répondre, par exemple).
Voici un ACK (OK) :

83
Et voici une absence d’accusé de réception, encore dénommée NOACK. En effet, un
NOACK équivaut à une absence de réaction, puisque seul le niveau bas est imposé, le niveau
haut étant lié à la libération de la ligne (ou à sa non appropriation).

4.7.3.5 Le bit read/write:


Il nous faut encore voir un bit particulier. Le bit R/W indique à l’esclave si les bits de
données contenus dans la trame sont destinés à être écris (R/W = 0) ou lus (R/W = 1) par le
maître. Dans le cas d’une écriture, le maître enverra les données à l’esclave, dans le cas d’une
lecture, c’est l’esclave qui enverra ses données au maître.
Etant donné que ce bit ne présente aucune particularité, on ne donne pas le chronogramme
(identique à celui décrit pour le bit « ordinaire »).

4.7.4 Structure d’une trame I²C :

Nous avons vu tous les signaux possibles, il nous faut maintenant étudier le protocole de
communication des intervenants en I²C.
Nous savons déjà que la transmission commence par un « start-condition » (S).
Vient ensuite l’adresse, codée sur 7 ou 10 bits, complétée par l’octet R/W qui précise si
les données qui vont suivre seront écrites ou lues par le maître.
Chaque octet envoyé est toujours accompagné d’un accusé de réception de la part de celui
qui reçoit. Un octet nécessite donc 8 + 1 = 9 impulsions d’horloge sur la pin SCL.
On distingue dès lors 2 cas : soit l’adresse est codée sur 7, soit sur 10 bits. Voici comment
se présente le début d’une trame (à partir ce cet instant, dans les chronogrammes concernant
l’I²C.
Notez donc, et c’est logique, que c’est toujours le maître qui envoie l’adresse, qu’il soit
récepteur ou émetteur pour le reste du message.

Pour coder une adresse sur 10 bits, on utilisera comme premier octet l’adresse réservée

84
B’11110xy0’ qui précise qu’un second octet est nécessaire. Voici ce que donne l’envoi d’une
adresse sur 10 bits :

5- Les Interruptions du 16F877 :

Le 16F877 possède de nombreuses sources d’interruptions. Environ plus de 14 sources


différentes d’interruption. Les plus importantes sont :

5.1. Interruption du Timer 0 :


Le débordement (le passage de 255 à 0) du timer 0 provoque une interruption.

5.2. Interruption du Timer 1 :


Le débordement (le passage de 65535 à 0) du timer 0 provoque une interruption.

5.3. Interruption externe sur RB0 :


La broche RB0 peut être configurée pour déclencher une interruption à l’apparition d’un
flanc Montant ou Descendant sur cette broche. Cette interruption peut être utile pour rendre le
microprocesseur sensible à une action sur un module externe (un clavier ou un bouton
poussoir par exemple).

5.4. Interruption à un changement sur RB4-7 :


Une modification sur une ou plusieurs broches des 4 broches RB4, 5, 6 et 7 (demi port B)
provoque une interruption.

5.5. L’interruption de fin de conversion du module CAN.


Le module CAN peut générer une interruption lorsqu’une conversion analogique
numérique est terminée.

5.6. Les autres interruptions disponibles sont :


- interruption du port parallèle PSP
- interruption du port série USART (réception et émission)
- interruption du module CCP1
- interruption du timer2

85