Vous êtes sur la page 1sur 69

Informatique Industrielle

ENSAM de Rabat

Mohammed ABDOUN
Table des matières

1 Codage des nombres 4


1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

1.2 Représentation des Entiers naturels ou Non signés . . . . . . . . . . . . . . . . . . . . 5

1.2.1 Le système décimal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

1.2.2 Le système binaire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

1.2.3 Le système octal et hexadécimal . . . . . . . . . . . . . . . . . . . . . . . . . . 6

1.2.4 Conversion d'une base vers une autre . . . . . . . . . . . . . . . . . . . . . . . 7

1.3 Entiers relatifs ou Signés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

1.3.1 Représentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

1.3.2 Conversion Décimal vers Complément à deux . . . . . . . . . . . . . . . . . . 9

1.4 Opérations sur les nombres binaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

1.4.1 Opérations Arithmétiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

1.4.2 Drapeaux d'état . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

1.4.3 Opérations Logiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

1.5 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

2 Introduction du PIC18FXX2 14
2.1 Structure d'un système automatisé . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

2.2 Un micro-contrôleur, c'est quoi ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

1
TABLE DES MATIÈRES

2.3 Architecture des PIC18FXX2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

2.3.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

2.3.2 Brochage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

2.3.3 Registres de conguration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

2.4 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

3 Entrées sorties logiques 26


3.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

3.2 Conguration des Ports Entrées-sorties du PIC18FXX2 . . . . . . . . . . . . . . . . . 26

3.3 Manipulation des Ports Entrées-sorties du PIC18FXX2 en utilisant le langage "C" . . 28

3.3.1 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

3.3.2 Solution de l'exemple : . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

3.4 Implantation de fonctions combinatoires . . . . . . . . . . . . . . . . . . . . . . . . . 31

3.5 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

3.5.1 Conguration des ports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

3.5.2 Implantation de fonction logique . . . . . . . . . . . . . . . . . . . . . . . . . . 35

4 Les interruptions 37
4.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

4.2 Cas du PIC 18Fxx2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

4.3 Gestion des interruptions du PIC 18Fxx2 . . . . . . . . . . . . . . . . . . . . . . . . . 38

4.3.1 Priorités des interruptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

4.3.2 Contrôle des interruptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

4.3.3 Schéma de la logique d'interruptions . . . . . . . . . . . . . . . . . . . . . . . 39

4.3.4 Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

4.4 Exercice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50

M.ABDOUN 2
TABLE DES MATIÈRES

5 Les Timers 52
5.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52

5.2 La fonction timer/counter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52

5.3 La fonction compare (comparateur) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

5.4 La fonction Capture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

5.5 Cas de la famille PIC18Fxx2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55

5.5.1 Timer0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56

5.5.2 Exemple1 d'application au Timer0 : en mode timer . . . . . . . . . . . . . . . 57

5.5.3 Exemple2 d'application au Timer0 : en mode compteur . . . . . . . . . . . . . 59

5.5.4 Timer1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62

5.5.5 Exemple d'application au Timer1 . . . . . . . . . . . . . . . . . . . . . . . . . 64

M.ABDOUN 3
Chapitre 1

Codage des nombres

1.1 Introduction
L'informatique industrielle couvre l'ensemble des techniques de conception d'analyse et de pro-
grammation de systèmes à base d'interfaçage de l'informatique avec de l'électronique, électrotech-
nique, mécanique, robotique, etc. à vocation industrielle. Elle concerne l'utilisation de l'outil in-
formatique pour la fabrication de produits industriels, du bureau d'études (conception assistée par
ordinateur) à leur production (fabrication assistée par ordinateur, automatique, robotique) en passant
par la logistique, la gestion des stocks, etc.

Son domaine d'application est très large :

 Automates, robotique,
 Mesures de grandeurs physiques,
 Systèmes temps-réel,
 Systèmes embarqués

La raison d'être d'un système informatique (industriel ou non) est d'acquérir les données (in-
formations) de l'extérieur, faire des calculs et transformations, avant de restituer un résultat aux
périphériques de sortie. Cette information a la forme qui va d'un seul bit (état d'un capteur par
exemple) à la forme d'un ux audio ou vidéo. Dans les sections suivantes on traitera la représenta-
tion et manipulation des données numériques et logiques.

Le système de numération utilisé dans la vie quotidienne est la base 10 ou le système de nombres
décimaux. Dans les applications à base de microprocesseur et de microcontrôleur, on utilise le plus
couramment la base 16, ou hexadécimal. Les systèmes de nombres en base 2 (binaire) ou en base 8
(ou octal) sont également utilisés.

4
CHAPITRE 1. CODAGE DES NOMBRES

Figure 1.1  Exemple : industrie agro-alimentaire

Figure 1.2  Quelques exemples de systèmes embarqués

1.2 Représentation des Entiers naturels ou Non signés


Dans le cas général on utilise une représentation pondérée des nombres entiers. Un nombre
entier naturel, N ∈ N, N(b) est décrit dans la base b par la donnée d'une sequence ordonnée
de symboles : des chires [ap , ..aj ...a1 , a0 ] qui vérient 0 ≤ aj < b et qui représente la quantité

M.ABDOUN 5
CHAPITRE 1. CODAGE DES NOMBRES

N = ap · bp + ... + aj · bj + ... + a1 · b1 + a0 · b0

1.2.1 Le système décimal

Pour les nombres entiers naturels dans la base décimale : b = 10 on utilise les symboles :
{0, 1, 2, 3, 4, 5, 6, 7, 8 et 9}.

Donc le nombre 832 décrit la quantité : 8 · 102 + 3 · 101 + 2 · 100 .

1.2.2 Le système binaire

Dans ce cas b = 2, les chires sont {0, 1}. Pour indiquer la base dans laquelle on écrit une valeur
binaire, on utilise l'indice 2 ou b. On peut donc deviner la quantité représentée par :

1100111b = 11001112 = 1 · 26 + 1 · 25 + 0 · 24 + 0 · 23 + 1 · 22 + 1 · 21 + 1 · 20
= 64 + 32 + 0 + 0 + 4 + 2 + 1
= 10310 ou 103d ou 103 tout court, sans indice

L'indice d veut dire : exprimé dans la base décimale, c'est à dire celle qu'on utilise depuis que
l'on sait compter !

Dans le langage de programmation "C", on indique un entier non signé par :

unsigned int n; // n: entier naturel

Les limites des nombres non signés représentés par n = 8 bits est 0 ≤ n ≤ 255d

1.2.3 Le système octal et hexadécimal

Pour la représentation octale, la base est b = 8 les symboles sont {0, 1, 2, 3, 4, 5, 6 et 7}. Quelle
est la quantité représentée par 2738 ?

Dans la représentation hexadécimale on utilise la base b = 16, les chires hexadécimaux sont
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E et F }. Garder en tête A → 1010 , B → 1110 , etc.... La gure 1.3
représente le tableau de correspondance décimal-binaire-hexadécimal.

Quelle quantité est représentée par 2AC16 ou 2ACh ?

M.ABDOUN 6
CHAPITRE 1. CODAGE DES NOMBRES

Figure 1.3  décimal-binaire-hexadécimal

1.2.4 Conversion d'une base vers une autre


Binaire → Décimal : est déja vue en 1.2.2.
Hexadécimal → Décimal : ressemble beaucoup à la précédente. Par exemple calculer (11A)h :
(11A)h = 1 · 162 + 1 · 161 + 10 · 160 ; rappelez-vous que Ah = 10d
= 256 + 16 + 10
= 282

Décimal → Binaire : on utilise la division par 2 successive jusqu'à avoir un quotient < 2. Voir
l'exemple de la gure 1.4a, pour calculer (29)10 = (???)2 .
Décimal → Hexadécimal : on utilise la division par 16 successive jusqu'à avoir un quotient < 16.
Voir l'exemple de la gure 1.4b
Binaire → Hexadécimal : on regroupe par 4 les bits donnés, EN COMMENÇANT PAR LA
DROITE, puis à chaque quartet de bits, on associe le symbole hexadécimal correspondant.
Penser à remplacer les nombres supérieurs à 10 par leurs symboles (exemple 11 → B ). Voir
l'exemple de la gure 1.5
Binaire → Octal : on procédera de la même manière que précédemment en regroupant par 3 les
bits donnés, EN COMMENÇANT PAR LA DROITE, puis à chaque triplet de bits, on
associe le symbole de 0 à 7 correspondant.

M.ABDOUN 7
CHAPITRE 1. CODAGE DES NOMBRES

(a) Décimal → Binaire (b) Décimal → Binaire

Figure 1.4  Vers le binaire

Figure 1.5  Binaire → Hexadécimal

1.3 Entiers relatifs ou Signés

1.3.1 Représentation

Les nombres entiers relatifs, ou signés, N ∈ Z, sont codés souvent par la méthode : "Complé-
ment à Deux", en utilisant le bit le plus à gauche, comme un bit de signe ; 1 c'est négatif, 0 c'est
positif. Ce bit est appelé le bit de poids le plus fort (en anglais, MSB : Most Signicant Bit). La
gure 1.6 donne l'exemple d'un nombre en complément à deux sur 8 bits.

Pour calculer sa valeur :

(10010100)Ca2 = −1 · 27 + 0 · 26 + 0 · 25 + 1 · 24 + 0 · 23 + 1 · 22 + 0 · 21 + 0 · 20
= −108

Remarques :

M.ABDOUN 8
CHAPITRE 1. CODAGE DES NOMBRES

Figure 1.6  Représentation d'un nombre signé en complément à deux

 Quand on donne la représentation d'un nombre signé, il faut absolument indiquer sa largeur
en bits.
 On peut déduire son signe en consultant son bit MSB
 Dans le langage de programmation "C", on indique un entier signé par :
int n; // n: entier relatif
 Les limites des nombres non signés représentés par n = 8 bits est −128d ≤ n ≤ 127d

1.3.2 Conversion Décimal vers Complément à deux

Pour convertir un entier relatif donné (dans la base 10), il faut suivre la démarche (algorithme) :
 si le nombre est positif
 alors sa conversion se fait de la même façon qu'un entier naturel
 sinon
 calculer dans la base 2, sa valeur absolue
 puis réaliser l'opération complément à deux, au résultat c-à-d :
 compléter le résultat par des 0 à gauche, an d'avoir la largeur voulue (8, 16 ou 32
bits)
 complémenter chaque bit (0 devient 1 et 1 devient 0)
 ajouter un 1 au résultat obtenu.
Exemple : Donner la représentation sur 8 bits, du complément à deux, des nombres 35d et −19d .
1. 35d est un entier positif, donc la division succéssive par deux donne 00100011b
2. −19d est négatif, donc :
 je part de sa valeur absolue → 19
 je la convertis en binaire naturel → 10011
 je complète pour avoir 8 bits → 00010011
 je complémente bit par bit → 11101100
 puis j'ajoute 1 au résultat → 11101101

M.ABDOUN 9
CHAPITRE 1. CODAGE DES NOMBRES

1.4 Opérations sur les nombres binaires

1.4.1 Opérations Arithmétiques

Toutes les opération "décimales" qu'on a apprises à l'enseignement primaire, peuvent être trans-
posées aux opérations eectuées sur les nombres binaires. Mentalement, on utilise les opérations
chire par chire : par exemple pour l'addition (0 + 0 = 0, 0 + 1 = 1 et 1 + 1 = 10 dans cette dernière
addition et dans notre tête, on dit "J'obtient 0 et je retient 1")

Quelques exemples :
1. Addition : 0110 + 0101 = 1011 (g 1.7). on vérie 6d + 5d = 11d

Figure 1.7  Addition binaire

2. Soustraction : 1011 − 0101 = 0110 (g 1.8). on vérie 11d − 5d = 6d

Figure 1.8  Soustraction binaire

3. Multiplication : 0110 × 0101 = 0011110 (g 1.9). on vérie 6d × 5d = 30d


A remarquer que la multiplication (division) par 2 correspond à un décalage à gauche (à droite).

M.ABDOUN 10
CHAPITRE 1. CODAGE DES NOMBRES

Figure 1.9  Multiplication binaire

1.4.2 Drapeaux d'état

Dans un calculateur, la partie qui réalise les opérations arithmétiques et logiques, est appelé :
Unité Arithmétique et Logique (UAL). Cette UAL contient un jeu de bascules appelés : Drapeaux
ou (Flags en ang.), qui par leurs états 1 ou 0, indiquent les conditions sous lesquelles s'est passé la
dernière opération (y a-t-il eu un report ? un débordement ? ...). On ne s'intéresse qu'à quelques uns
de ces drapeaux :

 C (Carry) : par son état à 1, indique que l'opération a produit un report dans l'addition ou
soustraction des bits les plus forts (MSB : Most Signicant Bit). Dans la gure 1.10, c'est
C8 ,
 DC (Digit Carry) : par son état à 1, même chose que précédemment mais après l'opération
sur les bits b3 => C4
 Z (Zero) : par son état à 1, indique le résultat est nul (tous les bits du résultat son à 0),
 OV (OVerow) : son état est = C7 ˆC8 où ˆ est le 'ou exclusif',
 N (Negate) : a la même valeur que le MSB du résultat (ici le bit b7 ).

Remarque

Si on prend comme exemple des entiers sur 8bits. Pour verier que le résultat d'une addition
ou d'une soustraction sur des entiers, ne déborde pas (au delà de 8 bits), il faut consulter, après
l'opération :

 Le carry C , si ce sont des entiers naturels (non signés), C = 1 =⇒ le résultat est > 255
 Le dépassement OV , si ce sont des entiers relatif (signés), OV = 1 =⇒ soit l'addition de
deux entiers positifs a donné un résultat négatif, soit l'addition de deux entiers négatifs a
donné un résultat positif !

M.ABDOUN 11
CHAPITRE 1. CODAGE DES NOMBRES

Figure 1.10  Soustraction binaire

1.4.3 Opérations Logiques

On peut appliquer ce qu'on connaît sur les fonctions booléennes (le "et", "ou" et "ou-exclusif"
logiques) aux opérations bit à bit (bitwise en anglais) sur des nombres binaires. Pour diérencier les
opérations arithmétiques et logiques on utilise les symboles logiques suivants :

”non” → ˜
”et” → &
”ou” → |
”ou − exclusif ” → ˆ

La gure 1.11, représente quelques exemples d'opérations logiques.

Figure 1.11  Exemples d'opérations logiques

M.ABDOUN 12
CHAPITRE 1. CODAGE DES NOMBRES

1.5 Exercices
Conversion bin-hex, dec-bin, complément à 2
1. Soit l'expression binaire 10011110, Quelle est sa valeur en décimal :
 si ça représente une quantité entière naturelle ?
 si ça représente un nombre signé sur 8 bits ?
Donner son écriture en hexadécimal.
2. Convertir (113)d en binaire sur 8 bits et en déduire sa représentation hexadécimale et octale.
3. Même question que la précédente avec (−113)d
4. Pour chacune des opérations arithmétiques suivantes, écrire les opérandes en binaire, donner
leurs valeurs décimales : 1) s'ils représentent des nombres non-signés ou 2) s'ils représentent
des nombres signés en complément à deux. Puis eectuer les opérations binaires en indiquant
aussi l'état des drapeaux (ags) :
(a) 00100100b + 01011000b
(b) 11100101b + 00101100b
(c) 00100100b − 10101000b
(d) 11100011b − 01100111b
5. Eectuer les opérations logiques sur des nombres binaires, en donnant l'état du drapeau Z :
(a) 0 0 0 0 0 1 0 0 & b7 b6 b5 b4 b3 b2 b1 b0 = ? avec & est le "et logique". Le nombre
0 0 0 0 0 1 0 0b est appelé : le masque. Conclure si le résultat est nul (c-à-d Z=1) de la
valeur du bit b2 ,
(b) 0 0 0 1 0 1 1 0 & b7 b6 b5 b4 b3 b2 b1 b0 . Avec cette opération et en consultant le drapeau
Z s'il est à 1, on a réalisé quelle fonction logique des variables f (b7 , b6 , b5 , b4 , b3 , b2 , b1 , b0 ) ?
6. Donner le résultat binaires des opérations suivantes, sachant que A représente un octet dont la
valeur initiale est b7 b6 b5 b4 b3 b2 b1 b0 :
(a) A ← (A) | 0 0 0 0 0 1 0 0, qu'on peut lire : A reçoit le contenu de A "ou bit à bit" avec
00000100
(b) A ← (A) & 1 1 1 1 1 0 1 1, qu'on peut lire : A reçoit le contenu de A "et bit à bit" avec
11111011
(c) A ← (A) ˆ 0 0 0 0 0 1 0 0, qu'on peut lire : A reçoit le contenu de A "ou exclusif bit à
bit" avec 0 0 0 0 0 1 0 0

M.ABDOUN 13
Chapitre 2

Introduction du PIC18FXX2

2.1 Structure d'un système automatisé


La gure 2.1, représente la structure générale d'un système automatisé. On distingue deux parties
fondamentales :
 La partie opérative (PO), qui permet la transformation de la Matière d'÷uvre par des
processus physico-chimiques et donc consommatrice d'énergie. Son activité est séquencée par
des Ordres ou Consignes opératives provenant de la partie commande. La (PO) renseigne
son état actuel (état des capteurs, n de courses, ..) par les Compte-rendus.
 La partie commande (PC), qui est actuellement, plus de type programmée (utilisation des
automates programmables, micro-contrôleurs, FPGA, ...) que de type câblée (on trouve de
moins en moins des relais ou séquenceurs pneumatiques), permet à partir des Consignes
opérateur et des compte-rendus de la (PO), de calculer les consignes opératives et les
Informations visuelles à montrer à l'opérateur. Au contraire de la (PO), elle ne consomme
pas beaucoup d'énergie et s'intéresse plutôt au coté Traitement de l'information.

Un exemple d'application : Contrôleur de niveau de uide (voir g. 2.2).

Dans ce cours, on s'intéressera à la partie commande programmée principalement à base de


Micro-contrôleurs.

2.2 Un micro-contrôleur, c'est quoi ?


Un microcontrôleur (MCU en abrégé) se présente sous la forme d'un circuit intégré (gure 2.3)
utilisé pour contrôler d'autres systèmes électroniques et des pré-actionneurs. A l'intérieur il contient
un Microprocesseur (MPU), des mémoires de programme et de données, et plusieurs périphériques.
Ces dispositifs sont faits pour des applications embarquées qui demandent à la fois des fonctionnalités

14
CHAPITRE 2. INTRODUCTION DU PIC18FXX2

Figure 2.1  Structure PC-PO

Figure 2.2  Contrôleur de niveau de uide

de traitement et une interaction agile et réactive avec des composants numériques ou analogiques.

Le marché des microcontrôleurs est formé par plusieurs fabricants (Microchip Technology Inc.,
STMicroelectronics, Atmel, ... ) et chacun propose plusieurs types de microcontrôleur. Ici on s'inté-
ressera aux microcontrôleurs PICs du fabricant Microchip. Ceux-ci sont référencés sous la forme :
PIC suivi de deux chires exemple : PIC (10, 12, 16, 18, 24 ,32) ou dsPIC (30, 33). Les PICs se
répartissent en plusieurs familles, par ordre de puissance croissante : PIC10 et PIC12, les PIC16,

M.ABDOUN 15
CHAPITRE 2. INTRODUCTION DU PIC18FXX2

Figure 2.3

les PIC18, les PIC24F/PIC24H/PIC24E etc.... Pour plus d'information, consulter : Familles de
PIC-wikipedia

Dans notre cours, on s'intéressera à la famille PIC18, car cette famille a un jeu d'instruction plus
complet puisqu'il comprend quelque 75 instructions machines et donc lui permet de faire executer
du code en langage C compilé de manière plus ecace. On a choisi d'exploiter les pics PIC18fXX2
(chaque X représente un chire, ex PIC18F452). Mais tout ce qu'on peut apprendre sur cette fa-
mille est exploitable pour étudier d'autres microcontrôleurs. Les PICs sont basés sur l'Architecture
Harvard, voir gure 2.4, où le bus qui véhicule le code à executer depuis la mémoire programme
(Flash : Program memory) vers le CPU, est diérent de celui qui véhicule la donnée à utiliser depuis
la mémoire de données (RAM : Data memory). Cette architecture permet de paralléliser la recherche
du code de la prochaine instruction et l'execution de l'instruction actuelle, et donc plus rapide que
celle de Von-Neumann.

Figure 2.4

M.ABDOUN 16
CHAPITRE 2. INTRODUCTION DU PIC18FXX2

2.3 Architecture des PIC18FXX2

2.3.1 Introduction

Les microcontrôleurs PIC18F fournissent une mémoire de programme ash (d'où le 'F' dans
la désignation) dans des tailles, de mémoire programme, de 8 à 128 Ko (Ko = KiloOctets, avec
1Ko = 210 = 1024 octets) et mémoire de données (RAM) de 256 à 4 Ko, fonctionnant dans une
limite d'alimentation entre 2,0 et 5,0 volts, à des vitesses allant jusqu'à 40 MHz.

Le tableau (g. 2.5) présente les éléments de la famille PIC18FXX2 et ses caractéristiques :

Figure 2.5

Vous pouvez télécharger la che technique (datasheet en anglais) de la famille PIC18FXX2


depuis le datasheet de la famille 18Fxx2.

2.3.2 Brochage

Le brochage du PIC18F452, par exemple, est donné dans la gure 2.6. Chaque broche est indiquée
par sa position (1 à 40), par le sens des signaux (entrée, sortie ou bidirectionnelles) et par ses

M.ABDOUN 17
CHAPITRE 2. INTRODUCTION DU PIC18FXX2

possibles fonctions, par exemple la broche 3 : RA1/AN 1 indique que c'est une broche qui pourrait
être congurée comme entrée/sortie tout-ou-rien 'RA1' ou comme entrée analogique 'AN 1'. On
remarque qu'il y a beaucoup de fonctions (T 0CKI , CCP 2, ...) dont le traitement de quelques unes
se fera le long des chapitres suivants.

Quelques broches qui méritent d'être considérées à ce point :


 VDD et VSS : Respectivement la broche d'alimentation 5volts et la broche de masse (0volts).
 M CLR/V pp : Entrée Master Clear (Reset). Cette broche sert à la réinitialisation du MCU,
elle est active sur un état bas. Quand elle redevient au niveau haut le MCU commence
l'execution des premières instructions au début du programme. Elle est aussi utilisée pendant
la programmation du MCU ; V pp reçoit une tension ∼ 13V olts.
 OSC1/CLKI et OSC2/CLKO/RA6 : Ces deux broches sont utilisées soit pour recevoir
un crystal de résonance (composant électronique, avec deux broches) qui va imposer une
fréquence à une horloge interne stable pour le fonctionnement du MCU, soit pour recevoir une
horloge externe. La série de microcontrôleurs PIC18F peuvent fonctionner avec des fréquences
d'horloge jusqu'à 40 MHz.

Figure 2.6  Brochage du PIC18f452

La gure 2.7, montre le schéma bloc interne du PIC18f452, on distingue :

 la RAM, qui est la mémoire des données. C'est là où on loge les variables du programme. Le
contenu de cette mémoire est eacé qu'on coupe l'alimentation le VDD .

M.ABDOUN 18
CHAPITRE 2. INTRODUCTION DU PIC18FXX2

Figure 2.7  Schéma bloc du PIC18f452

 La ROM, de type mémoire Flash, donc programmable et eaçable électriquement. C'est elle
qui contient le programme sous forme d'un code sur 16 bits. Le programme qui y est écrit
persiste après coupure de l'alimentation.
 l'Unité Arithmétique et Logique l'UAL (ALU en anglais), c'est le c÷ur des des calculs Arith-

M.ABDOUN 19
CHAPITRE 2. INTRODUCTION DU PIC18FXX2

métiques et Logiques ; le premier opérande se trouve souvent dans l'accumulateur W REG


et le deuxième, est soit une valeur constante codée dans l'instruction (ramenée de la ROM),
soit une variable ramenée depuis la mémoire des données : la RAM. La vitesse d'execution
des instructions est dénie par la fréquence d'horloge (fréquence d'oscillation divisée par 4).
 Ports E/S ( Entrées/Sorties ) : Ce sont les unités qui font le lien entre ce qui se passe à
l'intérieur du PIC et l'extérieur.
 Modules annexes : Toutes les fonction annexes (timers, comparateurs, convertisseurs analo-
giques/numériques . . . )

Le schéma bloc est assez compliqué à étudier en une seule séance. Il est utile à com-
á prendre, mais il l'est encore plus pour celui qui utilisera l'assembleur comme langage
de programmation. Nous, on va plutôt utiliser le langage 'C'. Mais on reviendra à ce
schéma quand c'est nécessaire.

2.3.3 Registres de conguration

Les microcontrôleurs PIC18F452 ont un ensemble de registres de conguration (g. 2.8). Ils sont
écrits lors de la programmation de la mémoire ash du MCU par le programmateur. On ne traitera
pas tous ces registres, par manque de temps, mais il faut savoir que ceux là, ont des valeurs par
défaut (non programmées) qui satisfont la plupart des projets et on ne programmera que quelques
congurations particulières. Certains des registres de conguration les plus importants sont décrits
en détail dans cette section.

Comme exemple, pour le registre de conguration CON F IG1H (voir g. 2.9)

Voici la signication de ces bits :

 OSCSEN (Clock source switching enable) : Les PIC18FXX2 incluent une fonction qui per-
met de passer de l'oscillateur principal haute fréquence vers une autre source d'horloge basse
fréquence, an d'économiser la consommation électrique du MCU (car sa consommation est
croissante en fonction de la fréquence de l'horloge). Pour les PIC18FXX2, cette autre source
d'horloge est l'oscillateur du Timer1 (entre les broches T 1OSO et T 1OSI ). Si ce bit, qui
est le bit b5 du registre CON F IG1H , est dans l'état actif c-à-d à 0, cette commutation est
possible. Sinon, (si OSCSEN = 1) on n'utilise que l'horloge principale. D'après le tableau
(g. 2.8), par défaut (si on ne le programme pas) ce bit est inactif.
 F OSC2 : F OSC0 : Ces trois bits permettent la selection l'un des modes d'horloge (g.
2.10) :
 111 : On utilise un circuit RC externe et en plus la broche RA6 peut être utilisée comme
entrée-sortie logique. Le choix R = 3.9kΩ et C = 30pF , par exemple, donne une fréquence
de 2M Hz .
 011 : Oscillateur RC avec sortie FOSC /4 sur la broche OSC2

M.ABDOUN 20
CHAPITRE 2. INTRODUCTION DU PIC18FXX2

Figure 2.8  Les registres de conguration du PIC18f452

Figure 2.9  Conguration de l'horloge : CON F IG1H

 101 : Oscillateur externe et RA6 comme entrée-sortie logique.


 100 : Oscillateur externe avec sortie FOSC /4 sur la broche OSC2.
 001 : Oscillateur utilisant un crystal de résonance jusqu'à 4MHz. Le temps d'execution
d'une instruction machine étant TCY = 4/FOSC donne pour ce cas TCY = 1µs.

Un autre exemple est le registre de conguration CON F IG2H , utilisé pour contrôler le timer
du chien de garde (Watch Dog Timer ou WDT).

M.ABDOUN 21
CHAPITRE 2. INTRODUCTION DU PIC18FXX2

Figure 2.10  Les modes horloge

La plupart des microcontrôleurs ont au moins une fonction de surveillance. Le chien de garde
est essentiellement une minuterie qui est actualisée par le programme utilisateur. Si le programme ne
parvient pas à actualiser le chien de garde au bout d'un certain temps, un RESET (réinitialisation)
est déclenché. Le minuteur de surveillance est utilisé pour détecter un problème système, tel que
le programme se trouvant dans une boucle sans n. Cette fonction de sécurité empêche le micro-
contrôleur d'exécuter du code erroné et indésirable. Les dispositifs de surveillance sont couramment
utilisés dans les systèmes en temps réel où la n réussie d'une ou plusieurs activités doit être vériée
régulièrement.

Dans les membres de la famille des microcontrôleurs de la série PIC18F, la minuterie de sur-
veillance (WDT) est pilotée par un oscillateur RC interne au MCU à fonctionnement indépendant
et ne nécessite aucun composant externe. Il a une période de ∼ 18ms. Le fonctionnement du WDT
est donné sur la gure 2.11.

M.ABDOUN 22
CHAPITRE 2. INTRODUCTION DU PIC18FXX2

Figure 2.11  Principe du chien de garde

Lorsque le délai WDT expire, un RESET de périphérique est généré.

Sur le microcontrôleur PIC18F452, un post-diviseur 8 bits est utilisé pour multiplier la période
de temporisation de base de 1 à 128 en puissances de 2. Ce post-diviseur est contrôlé à partir du
registre de conguration CON F IG2H (g. 2.12). Par défault, le bit W DT EN est à 1 (voir g. 2.8),
donc le WDT est actif. Si on veut l'inhiber, il faut programmer W DT EN à 0.

Le délai d'expiration WDT de base typique est de 18 ms pour une valeur de post-diviseur de
(1 :1), de 36ms si post-diviseur de (1 :2), ....

Figure 2.12  Conguration du chien de garde : CON F IG2H


Pour congurer ces registres de conguration en langage C , on utilise la directive ]pragma conf ig
suivi par N om_conf ig = V aleur. Par exemple si on veut valider le WDT et programmer le post-
diviseur, il faut écrire la ligne suivante au debut du cher contenant la fonction principale "main" :

#pragma cong WDT=ON, WDTPS = 32 // Valide le WDT, programme le post-diviseur


// par 32.

M.ABDOUN 23
CHAPITRE 2. INTRODUCTION DU PIC18FXX2

// ou bien l'équivalent de la directive précédente:


#pragma cong CONFIG2H = 0x0D // en indiquant le registre entier CONFIG2H,
// 0x0D est une représentation hexadécimale
// 0x0D = 00001011 en binaire donc WDTPS2:0 = 101

2.4 Exercices

Exercice 1

On veut choisir un PIC de la famille PIC18FXX2 à utiliser dans une application qui nécessite :
 Mémoire programme (Flash) : 20134 octets,
 Mémoire de données (RAM) : 1024 octets,
 Nombre d'entrées analogiques (fonction AN) : 2 entrées,
 Nombre d'entrées logiques (tout ou rien) : 11 entrées et
 Nombre de Sorties logiques : 8 sorties.

1. Choisir un PIC parmi 18F242, 18F252, 18F442 et 18F452, ayant le plus petit nombre de broches,
et qui convient pour cette application. Consulter le datasheet des PIC18F452, section "1.0
Device overview".

Exercice 2 : Conguration de l'horloge

On veut congurer l'horloge d'un système à base de PIC18F252, en utilisant le mode RC


(résistance-capacité. La fréquence d'horloge désirée est ∼ 3, 3M Hz . On utilisera une capacité C =
22pF (1pico = 10−12 ). Aussi on veut utiliser la broche RA6 comme entrée-sortie.

1. Calculer la résistance R à utiliser, sachant que la période d'oscillation de l'horloge TOSC est
proportionnelle au produit R × C .
2. Donner le mot à programmer dans le registre de conguration CON F IG1H , puis la pragma
en langage C associée.

Exercice 3 : Conguration du chien de garde

Un des moyens utilisés pour detecter le mal fonctionnement d'un système à base de microcon-
trôleurs, est d'utiliser le chien de garde (Watchdog). Soit un système à base de PIC18F452.

M.ABDOUN 24
CHAPITRE 2. INTRODUCTION DU PIC18FXX2

1. Donner le mot de conguration du CON F IG2H , pour avoir un Reset du MCU si on ne


rafraîchit pas le chien de garde au bout de 0, 6s.
2. Donner le pragama associée.

M.ABDOUN 25
Chapitre 3

Entrées sorties logiques

3.1 Introduction
Un microcontrôleur possède des bus internes de données et d'adresses. D'une certaine manière,
ce sont comme des autoroutes, transportant de grandes quantités de trac dans les deux sens vers une
variété de destinations diérentes (RAM, FLASH, TIMERS, ...). Le microcontrôleur doit être doté
d'un moyen de permettre à ce ux de données de se connecter au monde extérieur, de sorte qu'il puisse
lire des valeurs numériques externes ou produire d'autres valeurs aprés calcul, vers l'extérieur. Ces
jonctions sont des broches physiques, et sont appelés des Ports d'Entrées-sorties. Ils peuvent être
parallèles ou séries. Dans ce chapitre, on traitera les entrées-sorties parallèles logiques (tout-ou-rien).

On interface, par exemple, au microcontrôleur des capteurs n de course, des claviers, des diodes
électroluminescentes (DEL), des acheurs....

Ces PORTS se connectent en interne à des registres à l'intérieur du PIC. Ces registres sont
simplement une collection de cellules (bascules D) individuelles que nous appelons des bits. Dans le
18fxx2, on peut grouper ensemble 8 cellules ou bits pour former un registre. En eet, le 18fxx2 est
un micro 8 bits, ses bits sont numérotés de droite à gauche sous forme de bit 7, bit 6, bit 5, bit 4,
bit 3, bit 2, bit 1 et bit 0 (voir gure 3.1). Une sortie tout ou rien indique que le micro-contrôleur
impose le potentiel de la broche à 0V pour un 0 logique et à 5V pour un 1 logique.

3.2 Conguration des Ports Entrées-sorties du PIC18FXX2


Les microcontrôleurs de la famille des PICs considérés ici, ont trois ou cinq ports logiques :
 PIC18F242 et PIC18F252, ont trois ports PORTA, PORTB et PORTC (voir 2.5),
 PIC18F242 et PIC18F252, ont cinq ports PORTA, PORTB, PORTC, PORTD et PORTE.

26
CHAPITRE 3. ENTRÉES SORTIES LOGIQUES

Figure 3.1  Exemple port B du PIC

Avec :
 PORTA → 7 bits : RA0 à RA6,
 PORTB, PORTC et PORTD → 8 bits : RB0 à RB7, RC0 à RC7 et RD0 à RD7,
 PORTE → 3 bits : RE0 à RE2.
Pour congurer les fonctionnalités de ses périphériques, un microcontrôleur contient un en-
sembles de registres appelés 'Special function Registers' (SFR). Chaque registre ayant une adresse
donnée. Parmi ces registres, il y en a ceux qui permettent de congurer individuellement en entrée
ou bien en sortie, chacune des broches des ports du PIC : TRISA pour le port A, TRISB pour le
port B, ... C'est vous comme programmeur, qui allez indiquer au PIC, au moyen d'instructions dans
votre programme, quelle est la direction que vous voulez pour chaque bit d'un port.

Un 1 écrit dans un bit TRISx (x prend la lettre correspondant au port en question), indique que
la broche correspondante est en Entrée, un 0 indique que la broche est en Sortie.

Quand on dit : en entrée ou en sortie, c'est par rapport au microcontrôleur. Par défaut,
á à l'alimentation du PIC, tous les bits des TRISx sont à 1, donc toutes les broches sont
par défaut vues comme des entrées par le microcontrôleur.

Pour indiquer, par exemple, que la broche RB2 (la broche b2 du PORTB) est programmée en
sortie, il faut écrire la valeur 0 dans le bit 2 du TRISB.

Bien faire la diérence entre le registre PORTB (lui aussi appartenant au SFR) et le
* registre de conguration de direction TRISB. Le premier est utilisé pour pour lire l'état
d'une ou des broches associées au port B (0 → 0volt ou 1 → 5volts), le deuxième c'est
pour congurer telle ou telle broche du port B en entrée ou bien en sortie.

M.ABDOUN 27
CHAPITRE 3. ENTRÉES SORTIES LOGIQUES

3.3 Manipulation des Ports Entrées-sorties du PIC18FXX2 en


utilisant le langage "C"
Dans notre cours, on utilisera le langage C pour programmer le microcontrôleur PIC. Un chier
"Initiation_au_langage_C_sur_PIC.pdf", qui est un rappel sur l'utilisation du langage C appliqué
aux PICs, est joint à ce chapitre. Il est important de l'étudier, car il contient, en plus du rappel sur
le langage C , un rappel sur comment représenter des algorithmes en utilisant un organigramme.

Pour utiliser un port, il faut considérer deux phases :


 Initialisation : se passe une fois pour toute au début du programme principal (dans la fonction
main) et sert à congurer les broches du port en entrée ou bien sortie. Puis donner une valeur
initiale aux broches congurées en sortie,
 Lecture des broches (en entrée) ou écriture dans le registre associé aux broches (en sortie),
qui se fait souvent dans une boucle innie.

3.3.1 Exemple

Sur une carte à base de PIC18F452, on connecte : trois boutons poussoirs et une LED (diode
electro-luminescente). Le bouton poussoir BP0 est connecté sur la broche 3 du port B, BP1 sur la
broche 4 du port B et BP2 sur la broche 5 du port B. La LED est connectée sur la broche 6 du port
A. On veut que la LED s'allume, lorsque les trois boutons sont actifs (un "et logique"). Elle restera
éteinte sinon.

Il faut donc congurer les broches 3, 4 et 5 du port B en entrées et la broche 6 du port A en


sortie.

3.3.2 Solution de l'exemple :

Initialisation

Les boutons poussoirs sont connectés à des entrées du micro-contrôleur. Il faut donc forcer à 1
les bits 3, 4 et 5 du registre TRISB. Deux solutions :
 Congurer bit par bit : Un bit individuel de TRISB (par exemple) est accessible en spéciant
"TRISB", suivi du mot "bits", puis d'un symbole de point et du nom du bit correspondant.
Dans notre exemple :
TRISB3 = 1; // ou bien pour accéder à un bit dans un registre, on peut aussi
// utiliser TRISBbits.TRISB3 = 1, on préfère la première écriture
TRISB4 = 1;

M.ABDOUN 28
CHAPITRE 3. ENTRÉES SORTIES LOGIQUES

TRISB5 = 1;
 ou bien par forçage à 1 des bits du registre TRISB :
TRISB |= 0x38; // | est le 'ou logique', 0x38 = 0b00111000
// |= veut dire TRISB <- TRISB | 0X38

Figure 3.2
La LED est connectée à une sortie du microcontrôleur. Il faut donc forcer le bit 6 de TRISA à
0:

TRISA6 = 0;
// ou bien
TRISA &= 0xBF; // & est le 'et logique', 0xBF = 0b10111111

Pour éditer et compiler nos programmes, j'utilierai l'éditeur integré 'MPLAB X', que
á vous pouvez télécharger et installer gratuitement, et le compilateur "XC8" aussi gratuit.
Pour utiliser les étiquettes TRISA, TRISB, PORTA, ..., il faut inclure dans le chier
"C" une entête : '# include <xc.h>'.

Pour écrire un état initial 0 dans la sortie LED (qui est sur PORTA6), on doit écrire 0 dans le
bit associé : LA6, dans un registre : LATA. Ce registre est utilisé pour inscrire un 0 → 0volts ou un
1 → 5volts sur une broche du port A congurée en sortie. Dans notre exemple on écrit :

LATAbits.LA6 = 0; // ou tout simplement LA6 = 0;

Lecture et écriture des ports :

On va lire l'état des boutons et le mettre dans une variable "btns" de type 'unsigned int' :

M.ABDOUN 29
CHAPITRE 3. ENTRÉES SORTIES LOGIQUES

unsigned int btns;


.
.
.

btns = PORTB; // lecture en une seule fois du PORTB


.

En résumé à chaque port du PIC, on associe trois registres. On prendra comme exemple
ÿ le port B ou le bit 3 du port B :
1. TRISB ou TRISB3 : pour congurer la direction du port ou du bit 3 du port B,
2. LATB ou LB3 : pour écrire dans le port B ou dans la broche RB3 déjà conguré
en sortie,
3. PORTB ou RB3 : pour lire l'état physique des broches du port B ou l'état de la
broche RB3 conguré en entrée.

Organigramme :

L'organigramme (voir gure 3.3) permet d'élaborer le programme relatif à l'exemple. La LED
s'allumera si les trois boutons sont à 5volts.

Le code :

D'où le contenu du chier exemple1.c écrit en langage "C" représentant le programme :

/*
* File: exemple1.c
* Author: abdoun
*
* Created on May 15, 2021, 3:43 PM
*/

#include <xc.h>

#pragma config WDT = OFF // inhiber la fonction chien de garde

M.ABDOUN 30
CHAPITRE 3. ENTRÉES SORTIES LOGIQUES

void init_ports(void) {
TRISB |= 0b00111000; // configurer les bits 3, 4 et 5 du port B en entrée
TRISA6 = 0; // configurer le bit 6 du port A en sortie

LA6 = 0; // initialiser la broche 6 du port A à 0


}

void main(void) {
unsigned int btns; // variable locale

init_ports();

while(1) { // boucle infinie


btns = PORTB; // lire l'état des boutons du port B
if((btns & 0b00111000) == 0b00111000){ // les boutons tous à 1?
LA6 = 1; // allumer la LED
} else {
LA6 = 0; // éteindre la LED
}
}

return;
}

3.4 Implantation de fonctions combinatoires


On s'intéressera dans cette section, à réaliser à partir des états des entrées logiques (tout-ou-rien
ou TOR) arrivant sur le microcontrôleur, un programme ou sous-programme pour le calcul des valeurs
des fonctions combinatoire et donc des résultats TOR (par exemple g 3.4). Ces fonctions peuvent
être utilisées pour positionner des broches du microcontrôleur congurées en sortie ou comme des
réceptivités utilisées dans l'implantation d'un Grafcet. La structure globales du programme utilisé
est donné sur la gure 3.5. C'est une boucle innie.

Entre le point de lecture A de la gure et le point de sortie B , se passe un temps τ (xe ou


variable) que l'on veut le plus bref possible, si on veut un système rapide.

Il y a plusieurs méthodes pour implanter ces fonctions. Ici on expliquera une méthode dite
orientée "données" utilisant des mots de masques et des mots de valeurs.

On sait qu'on peut toujours ramener n'importe quelle fonction logique à la forme d'une somme

M.ABDOUN 31
CHAPITRE 3. ENTRÉES SORTIES LOGIQUES

Figure 3.3  Organigramme

Figure 3.4

de produits. Supposons par exemple (voir g. 3.4), que f1 (a, b, c, d) s'exprime par :

f1 (a, b, c, d) = a.b.c + a.b.d


= P 1 + P2

Le calcul de la valeur de cette fonction se ramène au calcul du produit P1 . S'il est vrai, on s'arète

M.ABDOUN 32
CHAPITRE 3. ENTRÉES SORTIES LOGIQUES

Figure 3.5  Structure générale

car on est sur que f1 est "vrai" (1 + φ = 1). Sinon on continue à évaluer P2 , puis le suivant s'il y
en a d'autres jusqu'à avoir un produit "vrai" ou si on atteint la n, alors la valeur de la fonction est
"faux".

Le problème revient maintenant à "coder" un produit pour que son évaluation soit rapide : Les
variables d'entrée sont généralement rangées dans un "mot" (un octet par exemple g. 3.6).

Figure 3.6  Ranger les entrées dans un mot

Prenons l'exemple du produit P2 = a.b.d, il ne contient que les variables a, b et d, d'où le mot
de masque binaire M2 =0b00001011 = 0x0B. Le mot de valeur permet de préciser l'état desiré de
chacune des variables (1 : si direct, 0 : si complémenté). Continuons toujours pour le produit P2 ,
puisque a et b interviennent "complémentés", leurs positions seront à 0. Pour d, il intervient "direct",
donc sa position est à 1 dans le mot de valeur. D'où le mot de valeur associé à P2 : V2 =0b00001000
= 0x08.

M.ABDOUN 33
CHAPITRE 3. ENTRÉES SORTIES LOGIQUES

Le produit P2 sera donc "vrai" si on a :

(E.M2 ) ⊕ V2 = 00000000
ou bien avec les opérateur du langage C
(E & M2 )ˆV2 = 00000000

Comme exercice, calculer M1 et V1 correspondant au produit P1 .

Finalement, pour représenter la fonction f1 complètement, il faut donner deux mots de masque
et deux mots de valeur, et les ranger sous forme d'un tableau [M1 , V1 , M2 , V2 , 0]. Pour notre exemple :

M V1 = [0x07, 0x05, 0x0B, 0x08, 0x00]

La n du tableau est indiquée par l'utilisation d'un mot de masque 0x00. Notre pro-
á gramme utilisera ça pour terminer le traitement d'une fonction et conclure de sa valeur
"faux".

3.5 Exercices

3.5.1 Conguration des ports

La gure 3.7 représente une partie de l'interfaçage à un PIC18F242 d'un bouton poussoir départ
cycle : m, de deux ns de course a0 et a1 associés à un vérin A et de deux commandes de bobines
A− et A+ d'un distributeur électro-pneumatique.

1. Calculer les valeurs de conguration des TRISx du PIC.


2. En utilisant le langage "C", donner la dénition :
(a) de la fonction
void init_ports(void);
pour congurer les ports et initialiser les sorties à 0.
(b) de la fonction
unsigned int read_buttons();
qui permet de lire l'état de a1 , de a0 et de m, et de les ranger dans le même ordre (m
étant le poids faible) dans l'octet retourné. Si par exemple m et a0 sont actionnés, l'octet
retourné sera : 0b00000011.
Attention : ce sont des contacts normalement ouverts et donc s'ils ne sont pas actionnés
les broches correspondantes sont à l'état 5volts → 1.

M.ABDOUN 34
CHAPITRE 3. ENTRÉES SORTIES LOGIQUES

Figure 3.7  Conguration des ports

3.5.2 Implantation de fonction logique

On se propose d'utiliser la méthode orientée données utilisant les mots de masque et les mot de
valeur, pour implanter les fonctions logiques de la gure 3.8. Les entrées sont rangées dans l'ordre
du bit de poids fort au bit de poids faible : e4 , e3 , e2 , e1 , et e0 . Les sorties rangées dans l'ordre
s3 , s2 , s1 , et s0 .

Figure 3.8  Exercice 2

1. Exprimer chacune des fonctions logiques de sortie s3 ...s0 sous forme de sommes de produits.
2. Pour chaque sortie, donner le tableau mots de masque, mots de valeur se terminant par un
0x00. En utilisant le langage "C", on peut dénir un tableau (par exemple de la fonction s0 )
par :

M.ABDOUN 35
CHAPITRE 3. ENTRÉES SORTIES LOGIQUES

const unsigned int mvs0[] = {0x03, 0x03, 0x00};


3. Élaborer une fonction en "C"

unsigned int eval(const unsigned int mvs[], unsigned int input)


// const unsigned int mvs[] veut dire un tableau appelé "mvs" d'octets
// constants (qui va être stocké dans la mémoire FLASH).
qui permet de calculer la valeur d'une fonction logique, étant donné son tableau des mot de
masque et de valeurs : mvs[] et un octet image des entrée : input. Son organigramme est donné
à la gure 3.9. Prière de consulter le pdf joint : "Initiation_au_langage_C_sur_PIC.pdf" pour
savoir comment interpreter un organigramme. L'organigramme utilise des variables locales à la
fonction eval : i (un index qui parcourt le tableau), M (mot de masque courant) et V (mot de
valeur courant), tous des entiers non signés. On peut les déclarer en "C" par :

unsigned int i = 0, M, V;
L'appel de cette fonction se fera par exemple comme suit :

temp = eval(mvs0, inputs);


// puis tester la valeur de l'octet variable locale "temp" retournée.
// "inputs" est un octet qui contient l'image des états des broches
// d'entrée.

Figure 3.9  Organigramme de la fonction eval

M.ABDOUN 36
Chapitre 4

Les interruptions

4.1 Introduction
Nous avons vu au chapitre precédent (voir gure 3.5), qu'on a utilisé une boucle de consul-
tation, on consulte périodiquement les entrées (polling loop) et qu'entre le point de lecture A de la
gure et le point de sortie B , se passe un temps τ (xe ou variable). Le temps de réponse du système
tr est le temps écoulé entre la lecture des entrées et l'aectation des sorties. En supposant que la
lecture des entrées et l'aectation des sorties consomme un temps négligeable devant le temps des
traitements qui est ∼ τ , on a τ < tr < 2.τ (pourquoi ?).

Parfois on veut que le système réponde plus rapidement à des événements intérieurs ou extérieurs
plus urgents. Pour celà, au lieu de laisser le programme consulter les états des entrées périodiquement,
on utilise les interruptions qui sont des événements qui vont attirer l'attention immédiate du CPU.
On utilisé ce mécanisme dans les applications critiques en termes de temps (exemple gestion de
l'airbag d'une voiture).

Une Interruption est un événement qui oblige le CPU à arrêter l'exécution normale du pro-
gramme, puis à exécuter un code de programme lié à l'événement à l'origine de l'interruption. Les
interruptions peuvent être générées en interne (par un événement à l'intérieur de la puce) ou en
externe (par un événement externe). Un exemple d'interruption interne est un débordement d'un
Timer ou la n d'une conversion Analogique/Numérique. Un exemple d'interruption externe est un
changement d'état de broche d'une E/S.

37
CHAPITRE 4. LES INTERRUPTIONS

4.2 Cas du PIC 18Fxx2


Le microcontrôleur PIC18Fxx2 possède à la fois des sources d'interruption déclenchées par l'ex-
térieur sur les broches du MPU et celles déclenchées par les périphériques. Les sources externes
d'interruption sont :
 Interruption déclenchée par un front externe sur les broches INT0, INT1 et INT2.
 Interruption déclenchée par le changement d'état des broches du PORTB (l'une des broches
RB4  RB7 change son état : front montant ou front descendant)
 Interruption de dépassement de Timer 0.
Quelques sources d'interruption périphériques sont :
 Interruption n de la conversion Analogique/Numérique
 Interruption de réception USART (récéption série)
 Interruption de transmission USART (transmission série)
 Interruption de débordement TMR1
 Interruption de débordement TMR2
 Interruption de détection de basse tension
 Interruption de débordement du TMR3

4.3 Gestion des interruptions du PIC 18Fxx2


Je conseille vivement de consulter, quand il le faut, le datasheet du PIC 18Fxx2.

4.3.1 Priorités des interruptions

Les interruptions de la famille PIC18F peuvent être divisées en deux groupes : haute priorité et
basse priorité. Les événements qui nécessitent plus d'attention peuvent être placées dans le groupe
de priorité le plus élevé. Une interruption de priorité élevée peut arrêter une interruption de priorité
basse en cours et accéder au CPU. Cependant, les interruptions de haute priorité ne peuvent pas être
arrêtées par des interruptions de faible priorité.

C'est le programmeur, qui décidera d'utiliser ce mécanisme de priorités, en mettant le bit :

IPEN = 1; // Ca indique le bit appelé IPEN dans le registre appelé RCON.


// (voir le datasheet section: "8.5 RCON Register")

Mais si l'application n'a pas besoin de dénir des priorités pour les interruptions (toutes ont la
même priorité), le programmeur peut choisir de désactiver ce schéma de priorité an que toutes les
interruptions aient le même niveau de priorité, en laissant IPEN à 0, qui est sa valeur par défaut.

M.ABDOUN 38
CHAPITRE 4. LES INTERRUPTIONS

4.3.2 Contrôle des interruptions

Chaque source d'interruption (sauf INT0) dispose de trois bits pour contrôler son fonctionne-
ment. Ces bits sont :
 Un bit de ag pour indiquer si une interruption s'est produite. Ce bit a un nom se terminant
par. . .IF. Ces bits indicateurs d'interruption sont mis à 1 par la circuiterie de l'interruption
et doivent être mis à 0 par logiciel au début du sous-programme d'interruption pour réarmer
et préparer l'arrivée des interruptions suivantes.
 Un bit de validation d'interruption pour activer ou désactiver la source d'interruption. Ce
bit a le nom se terminant par. . .IE
 Un bit de priorité pour sélectionner une priorité élevée ou faible. Ce bit a un nom se terminant
par. . .IP. Ce bit n'est utile que si l'on a choisi d'activer les priorités : IPEN à 1.
Par exemple : L'interruption provoquée par le débordement du Timer0 (qui sera traité ultérieu-
rement), mettra en jeu les bits : TMR0IF, TMR0IE et TMR0IP.

4.3.3 Schéma de la logique d'interruptions

La gure 4.1, représente le fonctionnement de la logique d'interruption, la priorité accordée à


une interruption, et la conguration de la logique à mettre en place pour l'application souhaitée.

Pour qu'une interruption soit acceptée par le CPU, les conditions suivantes doivent être remplies :
 Le bit de validation d'interruption de la source d'interruption doit être activé. Par exemple,
si la source d'interruption était la broche d'interruption externe INT0, alors le bit INT0IE
du registre INTCON devrait être mis à 1 (voir gure 4.2). En C :
INT0IE = 1;
 L'indicateur d'interruption de la source d'interruption doit être eacé. Par exemple, si la
source d'interruption était la broche d'interruption externe INT0, alors le bit INT0IF du
registre INTCON devrait être remis à 0. En C :
INT0IF = 0;
 Le bit d'activation/désactivation d'interruption de périphérique PEIE d'INTCON devrait
être mis à 1 si la source d'interruption est un périphérique (et pas une interruption externe).
En C :
PEIE = 1;
 Le bit d'activation/désactivation d'interruption globale GIE d'INTCON doit être mis à 1.
En C :
GIE = 1;
Avec une source d'interruption externe, nous devons normalement dénir si l'interruption doit
se produire lors de la transition front montant ou front descendant de la source d'interruption. Avec

M.ABDOUN 39
CHAPITRE 4. LES INTERRUPTIONS

Figure 4.1  La logique d'interruption

les interruptions INT0, par exemple, cela se fait en mettant/eaçant le bit INTEDG0 de enregistrez
INTCON2. On pourrait dire la même chose pour INT1 (→ INTEDG1) et INT2 (→ INTEDG2) dans
le même registre INTCON2.

4.3.4 Applications

Il faut savoir que nous, comme programmeurs, quand on veut utiliser les interruptions, il faut
penser à deux choses :
1. une suite d'instructions en "C" pour les congurer. Souvent dans une fonction ayant la forme :

void init_xxx(void) {...}


appelée au debut de la fonction main
2. un sous programme d'interruption, qui est une fonction appelée à chaque arrivée d'une inter-
ruption, et qui a la forme :

M.ABDOUN 40
CHAPITRE 4. LES INTERRUPTIONS

Figure 4.2  Le registre INTCON

void __interrupt(high_priority) xxx_ISR(void) {...}


C'est comme une fonction ordinaire, mais on a ajouter le mot clé : __interrupt(high_priority),
ou __interrupt(low_priority), selon la priorité, devant son nom.

M.ABDOUN 41
CHAPITRE 4. LES INTERRUPTIONS

Figure 4.3  Le registre INTCON2

Comme illustration de tout ça, on va utiliser trois exemples :

Exemple 1 :

Congurez INT1 comme une entrée d'interruption déclenchée par front descendant de faible
priorité, puis donnez un sous programme d'interruption, appelé int1_ISR qui permet d'incrémenter,
à chaque front descendant, une variable entière : compteur, initialement à 0.

Réponse :

Les bits suivants doivent être congurés avant que les interruptions déclenchées par front des-
cendant INT1 puissent être acceptées par le CPU en mode basse priorité :

M.ABDOUN 42
CHAPITRE 4. LES INTERRUPTIONS

1. Puisqu'on va utiliser le schéma de priorité, alors IPEN = 1


2. Faites de INT1 une broche d'entrée. En consultant le brochage du 18Fxx2, on voit que INT1
est aecté à la broche RB1/INT1, donc TRISB1 = 1 (le bit b1 du PORTB)
3. Réglez les interruptions INT1 pour qu'elles agissent sur front descendant : INTEDG1 = 0
4. Validez l'interruption INT1 par INT1IE = 1
5. Indiquer sa priorité faible par INT1IP = 0
6. Eacer l'indicateur INT1 par INT1IF = 0
7. Activez les interruptions de faible priorité par GIEL = 1
8. Activez globalement toutes les interruptions par GIEH = 1.
Le code source "C" est le suivant :

/* Main.c file generated by New Project wizard


*
* Created: Tue May 25 2021
* Processor: PIC18F452
* Compiler: MPLAB XC8
*/

#include <xc.h>

#pragma config WDT = OFF

unsigned int compteur = 0;

void init_int1() {
// configuration de l'interruption INT1, front descendant et faible priorité
IPEN = 1; // Puisqu'on va utiliser le schéma de priorité
TRISB1 = 1; // La broche RB1/INT1, en entrée
INTEDG1 = 0; // Réglez les interruptions INT1 pour qu'elles agissent sur front
// descendant
INT1IE = 1; // Validez l'interruption INT1
INT1IP = 0; // Indiquer que sa priorité est faible
INT1IF = 0; // Effacer l'indicateur ou flag INT1
GIEL = 1; // Activez les interruptions de faible priorité
GIEH = 1; // Activez globalement toutes les interruptions
}

void main(void)
{

M.ABDOUN 43
CHAPITRE 4. LES INTERRUPTIONS

init_int1();

TRISC = 0x00; // portC en sortie

// Boucle infinie
while (1)
PORTC = compteur;
}

void __interrupt(low_priority) int1_ISR(void)


{
if (INT1IE && INT1IF){ // est ce bien INT1 qui est validée et déclenchée?
compteur++; // incrémenter le compteur

INT1IF = 0; // TRES IMPORTANT A NE PAS OUBLIER!!! de réarmer le flag


}
}

Exemple 2 :

Congurez INT1 comme une entrée d'interruption déclenchée sur front montant ayant une prio-
rité élevée, puis donnez un sous programme d'interruption, appelé int1_ISR qui permet d'incré-
menter, à chaque front montant, une variable entière : compteur, initialement à 0.

Réponse :

Les bits suivants doivent être dénis avant que les alarmes déclenchées par front montant INT1
puissent être acceptées par le CPU en mode haute priorité :
1. Activez le schéma de priorité. Dénir IPEN = 1
2. Faites de INT1 une broche d'entrée. Dénir TRISB1 = 1
3. Réglez les interruptions INT1 pour le front montant. Dénir INTEDG1 = 1
4. Validez les interruptions INT1. Dénir INT1IE = 1
5. Activez la priorité élevée. Dénir INT1IP = 1
6. Eacer l'indicateur ou ag de INT1. Dénir INT1IF = 0
7. Activez globalement toutes les interruptions. Dénir GIEH = 1.
Le code source "C" est le suivant :

M.ABDOUN 44
CHAPITRE 4. LES INTERRUPTIONS

/* Main.c file generated by New Project wizard


*
* Created: Tue May 25 2021
* Processor: PIC18F452
* Compiler: MPLAB XC8
*/

#include <xc.h>

#pragma config WDT = OFF

unsigned int compteur = 0;

void init_int1() {
// configuration de l'interruption INT1, front montant et haute priorité
IPEN = 1; // Puisqu'on va utiliser le schéma de priorité
TRISB1 = 1; // La broche RB1/INT1, en entrée
INTEDG1 = 1; // Réglez les interruptions INT1 pour qu'elles agissent sur front
// montant
INT1IE = 1; // Validez l'interruption INT1
INT1IP = 1; // Indiquer que sa priorité est haute
INT1IF = 0; // Effacer l'indicateur ou flag INT1
GIEH = 1; // Activez globalement toutes les interruptions
}

void main(void)
{
init_int1();

// Boucle infinie
while (1)
;
}

void __interrupt(high_priority) int1_ISR(void)


{
if (INT1IE && INT1IF){ // est ce bien INT1 qui est validée et déclenchée?
compteur++; // incrémenter le compteur

INT1IF = 0; // TRES IMPORTANT A NE PAS OUBLIER!!! de réarmer le flag


}

M.ABDOUN 45
CHAPITRE 4. LES INTERRUPTIONS

Exemple 3, Interfaçage d'une roue codeuse :

L'application qu'on va étudier, est une partie d'un asservissement de position d'une table de
machine-outil entraînée par un moto-réducteur à courant continu à travers un système vis-écrou. Un
capteur angulaire est couplé à l'arbre de la vis. L'objectif est d'interfacer ce capteur : Un codeur
incrémental, à une carte à base du PIC18F452.
Le principe de base de fonctionnement d'un codeur incrémental est illustré par la gure 4.4. Il
utilise un disque régulièrement percé de fentes le long d'un secteur et dont le centre est solidaire à
l'arbre de rotation. Un système d'émetteur-récepteur de lumière est placé de part et d'autre de la
roue (constitué par exemple d'une LED et d'un capteur infrarouge). Lorsque la lumière émise par
la LED franchie une des fentes du disque lors de sa rotation, le récepteur génère un signal logique
1. Lorsque la lumière heurte le disque plein, le récepteur émet un signal logique 0. Ainsi lorsque la
roue tourne en continu, le récepteur génère un train d'impulsion soit un signal carré. Ce signal nous
renseigne sur le nombre de passages de fentes ayant délé devant la cellule photo-électrique mais pas
sur le sens de rotation. Pour capter le sens de rotation il faut utiliser deux secteurs de fentes ou deux
capteurs photo-électriques décalés en quadrature, et donc fournissent deux signaux rectangulaire en
quadrature de phase (déphasés de 90deg) souvent nommés A et B (voir g. 4.5).

Le disque comporte au maximum 3 pistes. Une ou deux pistes extérieures divisées en (n) in-
tervalles d'angles égaux alternativement opaques et transparents. Et une troisième qui indique la
position le Top Zéro.

Pour un tour complet du codeur, le faisceau lumineux est interrompu (n) fois et délivre (n)
périodes de signaux carrés (A et B) en quadrature. Le déphasage de 90° électrique des signaux A et
B permet de déterminer le sens de rotation :
 Si on tourne dans le sens 1, à chaque front montant du signal A, le signal B est dans l'état
zéro, on utilisera ce fait pour incrémenter un compteur (une variable dans le microcontrôleur).
 Si on tourne dans le sens 2, à chaque front montant du signal A, le signal B est dans l'état
un, on utilisera ce fait pour décrémenter le compteur.
On parle de la Résolution du capteur comme le nombre N de points par tour, que peut
détecter le capteur.

Trois cas peuvent se présenter :


1. Le système de traitement n'utilise que les fronts montants de la voie A (exploitation simple).
La résolution est égale au nombre de points (n).
2. Le système de traitement utilise les fronts descendants et montants de la voie A (exploitation
double). La résolution est multipliée par 2 (2 x n).
3. Le système de traitement utilise les voies A et B (exploitation quadruple). La résolution est

M.ABDOUN 46
CHAPITRE 4. LES INTERRUPTIONS

Figure 4.4  Principe utilisé dans le codeur incrémental

Figure 4.5  Codeur incrémental - deux signaux en quadrature

M.ABDOUN 47
CHAPITRE 4. LES INTERRUPTIONS

multipliée par 4 (4 x n).


Par exemple pour un codeur "GIM 900 A V N 400", le fabricant nous renseigne sur son "Nombre
d'impulsions par tour" de n=360 ; on peut donc obtenir une résolution N de 360, 720 ou 1440 points
par tour.

Questions :

Sur la carte microcontrôleur (voir g. 4.6), on connecte le signal A du codeur à la broche
RB1/INT1 du PIC, et le signal B à sa broche RB2/INT2. L'objectif est de concevoir un programme
qui à partir des signaux A et B, met à jour une variable compteur de type int (initialement à 0)
qui est une image de la position angulaire de l'arbre du motoréducteur. Pour celà, on va utiliser les
interruptions pour acquérir ces signaux, car se sont des signaux assez rapides (et on a vu que les
interruptions sont utilisées lorsqu'il y a des signaux urgents à gérer).

On va utiliser la résolution de base c-à-d N = n (voir ci-dessus). On utilisera le signal A comme


interruption externe, sensible à un front montant, pas de priorité.

1. En utilisant un codeur incrémental de n = 360 impulsions par tour, et en supposant que l'arbre
tourne à une vitesse de Narbre = 20tr/mn, déterminer la période TA (en secondes) du signal A.
2. Donner les instructions pour congurer l'interruption

void init_PORTB() { ... }


3. Donner le sous programme d'interruption

void INT1_isr() { ... }


4. Pour pouvoir suivre l'évolution du compteur, on va utiliser le PORTC pour faire sortir sa valeur.
Dans la boucle innie de la fonction main, aecter la valeur de compteur au PORTC(penser
à la conguration du PORTC).

Réponses :
1. En une minute, nous aurons Narbre × n impulsions sur A. Donc
60
TA =
Narbre × n
60
=
22 × 360
= 7, 6ms

Il faut donc vérier que notre solution permet bien de répondre rapidement (moins que 7, 6ms)
aux demandes d'interruption.

M.ABDOUN 48
CHAPITRE 4. LES INTERRUPTIONS

Figure 4.6  Connection du codeur incrémental

2. Donner les instructions pour congurer l'interruptions :

void init_PORTB() {
IPEN = 0; // pas besoin des priorités d'interruptions

// gestion de l'interruption INT1 changement


INTEDG1 = 1; // Réglez les interruptions INT1 pour qu'elles agissent sur f
// descendant
INT1IE = 1; // Valider l'interruption
INT1IF = 0; // Préparer l'indicateur d'interruption (ré-armer))

GIEL = 1; // Activez les interruptions de faible priorité


GIEH = 1; // Valider les interruptions globalement

TRISB |= 0xE; // la broche PORTB1:3 en entrée


}
3. Donner le sous programme d'interruption

void __interrupt() INT1_isr(void) {


if (INT1IE && INT1IF) { // c'est une interruption due à INT1?
if(RB2) // le signal B=RB2 est à 1?
compteur--; // décrémenter
else

M.ABDOUN 49
CHAPITRE 4. LES INTERRUPTIONS

compteur++; // sinon incrémenter

INT1IF = 0; // prepare l'indicateur ou flag


}
}
4. Congurer le PORTC en sortie

void init_PORTC(void){
TRISC = 0x00; // on utilse le port C en sortie
LATC = 0x00; // l'initialiser à 00000000
}
Aecter compteur au PORTC dans main :

void main(void) {
init_PORTB();

init_PORTC();

while (1){
LATC = compteur; // faire sortir la valeur du compteur sur le PORTC
}
return;
}

4.4 Exercice
On reprend l'exemple 3 (voir section 4.3.4), mais cette fois-ci on veut améliorer la résolution de
l'acquisition en la multipliant par 2. On utilisera alors les changement fronts montants et descendants
du signal A comme source d'interruption.

Les broches du port RB4 à RB7 d'un PIC18Fxx2 (voir 8.8 PORTB Interrupt-on-Change)
peuvent être utilisées comme entrées d'interruption réagissant à tout changement de leur état lo-
gique, et qui provoquerait la mise à 1 du ag RBIF et ainsi une demande d'interruption au CPU.
Les bits de validation d'interruption et d'indicateur RBIE et RBIF sont dans le registre INTCON.

Dans notre cas on va câbler le signal A à la broche RB4 et le signal B à RB5/PGM.

M.ABDOUN 50
CHAPITRE 4. LES INTERRUPTIONS

L'interruption de changement des broches RB4 :7 est gérée par les bits RBIE et RBIF,
W qui gèrent les changements des quatre broches en même temps. Il faut donc encore
un moyen pour detecter, dans notre sous programme d'interruption, laquelle de ces
broches à changé d'état. Por celà on va utiliser une variables : a_p de type __bit,
pour mémoriser la précédente valeur de la broche RB4 (le signal A) et la comparer à
son état actuel (par un ou exclusif).

Les variables utilisés sont a_p et b_p dénies à l'extérieur de main :

int compteur = 0;
__bit a_p = 0;

1. Donner les instructions pour congurer l'interruption

void init_PORTB() { ... }


2. Donner le sous programme d'interruption relatif aux changements d'état du PORTB

void RB_isr() { ... }


3. Pour pouvoir suivre l'évolution du compteur, on va utiliser le PORTC pour faire sortir sa valeur.
Dans la boucle innie de la fonction main, aecter la valeur de compteur au PORTC(penser
à la conguration du PORTC).
4. Quel est la modication à faire, pour encore améliorer la résolution en la multipliant par 4, en
protant des fronts montants et descendants de RB4=A et de RB5=B ?

M.ABDOUN 51
Chapitre 5

Les Timers

5.1 Introduction
Comme la plupart des microcontrôleurs, les PICs possèdent des périphériques appelés : Timers
qui permet de gérer la dimension temps. Les temporisateurs matériels sont utilisés pour les opérations
de temporisation et de comptage, permettant au processeur de poursuivre un autre processus pendant
que le processus de temporisation s'exécute. Le fonctionnement de base du temporisateur ; une entrée
d'horloge pilote un registre de comptage pour mesurer le temps ou compter des événements externes.
Sa fonctionnalité peut être étendue en utilisant des registres supplémentaires pour stocker les valeurs
de la minuterie, créant ainsi un module CCP. CCP signie capture/comparer/PWM.

Pratiquement, on utilise les timers dans des applications pour réaliser :


 Génération d'une fréquence d'horloge pour piloter la liaison série,
 Génération d'un impulsion électrique d'une durée bien calibrée
 Comptage d'événements externes (par ex le nombre de bouteilles passant à travers un dis-
positif photo-électrique)
 Générer une sortie PWM (Modulation de Largeur d'Impulsion, voir g. 5.3)
 Mesure de temps entre deux événements (comme un chronomètre), voir (g. 5.4)

5.2 La fonction timer/counter


La gure 5.1 donne le principe des modes de fonctionnement d'un timer. On y a utilisé un
registre compteur qui peut être 8 ou 16-bits. Le programmeur peut sélectionner un des deux modes :
 Mode Timer : le registre compte le nombre d'impulsions venant d'un oscillateur à fréquence
constante (peut être la sortie d'un pré-diviseur excité par l'horloge principale du microcon-
trôleur). Ou bien,

52
CHAPITRE 5. LES TIMERS

 Mode Compteur, et dans ce cas le registre s'incrémente à chaque arrivée d'un front de
l'événement externe conduit à l'entrée horloge H.
Dès que le registre compteur déborde (passe de 0xFF à 0, cas de 8-bits, ou de 0xFFFF à 0, cas de
16-bits), un drapeau (ag) est mis à 1, ce qui pourrait déclencher une interruption du CPU.

Figure 5.1  Les modes Timer/Counter

5.3 La fonction compare (comparateur)


La gure 5.2, représente l'unité Comparateur (anglais : Compare Unit) qui permet de comparer
la valeur du registre Timer/Compteur avec celle du Registre comparateur (anglais : Comparator
Register).

Figure 5.2  Le mode Comparateur


En recevant des impulsions d'horloge sur l'entrée H, le registre Timer/Compteur s'incrémente.
Quand sa valeur atteint la valeur du Registre comparateur, il y a égalité et la sortie du Compa-
rateur se met à 1, ainsi que la sortie de la bascule, positionnant par la même occasion la Broche
de sortie à 1. En continuant à évoluer, le registre Timer/Comparateur déborde quand sa valeur
M.ABDOUN 53
CHAPITRE 5. LES TIMERS

atteint 0xFF (pour un 8-bits par exemple). Ce qui provoque la mise à 1 du Flag puis l'entrée R de
la bascule, l'état de la Broche de sortie tombera alors à 0.

Prenons comme exemple, un registre Timer/Comparateur de 8-bits (valeur Maxi : Nmax


0xFF=255), un signal d'horloge H de période τ . Si on charge dans le Registre comparateur par
programmation la valeur RC = 0x64 = 100, on aura la Broche de sortie qui va évoluer comme
indiqué sur la gure 5.3. Le signal de sortie est un signal rectangulaire de Rapport Cyclique : λ
(qui est le rapport de la durée à l'état 1, divisé par la période) :

(256 × τ − 100 × τ )
λ=
256 × τ
156 × τ
= ∼ 0, 61
256 × τ

Et dans le cas général, si RC est la valeur chargée dans le Registre comparateur et Nmax la
valeur maxi du Registre Timer/Comparateur :

RC
λ=1− .
Nmaxi

On a alors la largeur de l'impulsion de la broche de sortie, qui varie selon la valeur de RC . D'où
l'appellation PWM (Pulse Width Modulation) ou Modulation à largeur d'impulsion.

La valeur moyenne du signal de sortie est Vmoy = λ×Vcc . On obtient donc une conversion
á d'une valeur numérique : RC en une valeur continue analogique : Vmoy . C'est une façon
d'économiser l'utilisation d'un composant convertisseur Numérique/Analogique externe
au MPU.

5.4 La fonction Capture


Le mode capture fournit une mesure d'intervalle de temps d'un signal d'entrée (Figure 5.4).
Lorsque l'entrée change, la valeur du registre de Timer/Compteur est capturée (ou stocké) dans
le Registre de Capture (penser comme un ash photo) ; le temps entre le démarrage de Ti-
mer/Compteur et le changement d'entrée est donc enregistré. Dans une application, par exemple,
la minuterie peut être démarrée lorsqu'une impulsion est reçue d'un capteur, et le temps capturé
lorsque la prochaine impulsion arrive, donnant la période de l'impulsion du capteur. Une interrup-
tion peut être activée pour signaler cet événement.

M.ABDOUN 54
CHAPITRE 5. LES TIMERS

Figure 5.3  Utilisation du mode Comparateur pour générer un signal PWM

Figure 5.4  Utilisation du mode Capture

5.5 Cas de la famille PIC18Fxx2


Le microcontrôleur PIC18F452 dispose de quatre timers programmables qui peuvent être utili-
sées dans de nombreuses tâches, telles que la génération de signaux de synchronisation, la génération
d'interruptions à des intervalles de temps spéciques, la mesure de fréquences et d'intervalles de
temps, etc.

Cette section présente les minuteries disponibles dans le microcontrôleur PIC18F452. On ne


traîtera que les deux timers : Timer0 et Timer1.

M.ABDOUN 55
CHAPITRE 5. LES TIMERS

5.5.1 Timer0

Le Timer0 peut fonctionner en mode 8-bits ou 16-bits. Il a les caractéristiques de base suivantes :
 Fonctionnement 8-bits ou 16-bits
 Pré-diviseur programmable 8-bits
 Source d'horloge externe ou interne
 Génération d'interruption sur débordement
La gure 5.5, donne le principe de fonctionnement du Timer0 en mode 8-bits. L'interruption
TMR0 est générée lorsque le registre TMR0 déborde de 0xFF à 0x00 en mode 8 bits, ou de 0xFFFF
à 0x0000 en mode 16 bits. Ce débordement positionne le bit TMR0IF.

Le registre de contrôle du temporisateur 0 est T0CON, illustré à la gure 5.7. Les deux premiers
bits sont utilisés pour sélectionner le mode de fonctionnement 8-bits ou 16-bits et pour démar-
rer/stopper le temporisateur.

Pour choisir le mode 8-bits, il faut mettre le bit T08BIT à 1. Et dans ce cas seule la partie
8-bits TMR0L est utilisée pour l'initialiser ou pour le lire le timer. Dans le cas 16-bits ( T08BIT
à 0), on aura le même fonctionnement que précédemment, sauf qu'on utilise tout le registre 16-bits
TMR0.

Pour y accéder au registre 16-bits, on est obligé de le faire en deux temps et dans
W l'ordre :
 Lecture : D'abord lire TMR0L puis lire TMR0H
 Écriture : l'inverse ; d'abord écrire dans TMR0H puis écrire dans TMR0L.

Figure 5.5  Diagramme Bloc du Timer0, en mode 8-bits

M.ABDOUN 56
CHAPITRE 5. LES TIMERS

Figure 5.6  Comment fonctionne le multiplexeur ?

Figure 5.7  Registre T0CON

5.5.2 Exemple1 d'application au Timer0 : en mode timer

Dans une carte à base de PIC18F452, fonctionnant au rythme d'une horloge FOSC = 4M Hz ,
on veut utiliser le Timer0 sur 8-bits, pour provoquer une interruption périodique au bout de chaque
T secondes, après qu'on l'aie démarré (c-à-d à l'écriture de 1 dans le bit TMR0ON). Pour celà, on

M.ABDOUN 57
CHAPITRE 5. LES TIMERS

doit sélectionner l'entrée FOSC /4, utiliser le prescaler (le prédiviseur) avec un rapport de P S = 32.

Questions :
1. Donner la conguration du registre T0CON et préparer le MPU pourqu'il tient compte de
l'interruption provenant de TMR0 puis démarrer le Timer0.
2. Donner la forme du programme d'interruption

void __interrupt() TMR0_ISR(void) {..}


3. Quelle est alors la valeur de T obtenue ?
4. Que devient cette période T si au début du traitement de l'interruption TMR0, on charge le
registre TMR0L par une valeur N / 0 < N < 255 ?
Solutions :
1. void init_timer0(){
TMR0ON = 0; // arrêter le TMR0
T08BIT = 1; // utiliser TMR0 en 8-bits
T0CS = 0; // sélectionner FOSC/4

PSA = 0; // utiliser le prédiviseur


T0PS2 = 1; // choix de prescaler 32
T0PS1 = 0;
T0PS0 = 0;

// preparer l'interruption TMR0 (voir cours chap4-Interruptions)


IPEN = 0; // pas de priorités
TMR0IE = 1; // valider la source d'interruption du TMR0
TMR0IF = 0; // preparer le flag du TMR0

GIE = 1; // valider les interruptions globalement

TMR0ON = 1; // démarrer le TMR0


}

2. // et quelque part définir le sous-programme d'interruption:


void __interrupt() TMR0_ISR(void){
if(TMR0IF & TMR0IE){
...
TMR0IF = 0;
}
}

M.ABDOUN 58
CHAPITRE 5. LES TIMERS

3. La durée d'un cycle d'instruction est TCY C = FOSC4


. La sortie du prescaler (pré-diviseur de
fréquence) et qui est l'entrée du compteur, fournit une période de TP S = TCY C × P S et il y
aura donc, débordement du compteur au bout de chaque TP S × 28 et la période recherchée est :
4
T = × P S × 28
FOSC
4
= × 32 × 256
4000000
= 8, 192ms.

4. Au lieu de compter 0 à 255 puis débordement (c-à-d 256 points), le Compteur comptera à partir
de NT M R0 jusqu'au débordement 255 -> 0, et donc il aura compté : 256 − NT M R0 points. La
formule deviendra :
4
T = × P S × (28 − NT M R0 ).
FOSC
Cette formule est plutôt utilisée dans l'autre sens ; c'est à dire à partir de la période T , déter-
miner la valeur à charger dans TMR0 : NT M R0 .
T × FOSC
NT M R0 = 28 − .
4 × PS

La durée maximale qu'on peut obtenir est :


á 4
TM AX = × P S × 28 .
FOSC
La résolution d'un timer est le plus petit intervalle de temps qu'il peut distinguer
(ce qui correspond à 1 incrément du compteur). Dans notre cas c'est :

4
τ= × PS
FOSC
Donc si on souhaite une bonne résolution, il faut choisir un P S le plus petit
possible. Mais dans ce cas, l'intervalle de temps TM AX se trouve réduit.

5.5.3 Exemple2 d'application au Timer0 : en mode compteur

Sur une chaîne d'emballage, les pièces doivent être assemblées par lots de 10. Lorsque le lot est
réalisé, un signal Fin de lot est émis : LOT_REALISE. Une carte PIC18F452 (g. 5.8) permet de
gérer le nombre de pièces par lot. Pour celà on utilisera le Timer0 en mode comptage. Le passage
d'une pièce est simulé par le bouton poussoir PASSAGE PIECE. Pour visualiser l'état du compteur
de pièces déjà passées n_pieces_fabriquees, on fait sortir son contenu sur le PORTD.

Questions :

1. Pour congurer les ports utilisés donner la dénition de la fonction :

M.ABDOUN 59
CHAPITRE 5. LES TIMERS

Figure 5.8  Exemple2 : Timer0 en mode comptage

void init_PORTs(void){...}
2. On veut congurer le Timer0 en mode comptage sur 8-bits (pas sur 16-bits) car le nombre
maxi de pièces dans un lot est < 256. L'incrémentation se fait sur front montant sur la broche
RA4/T0CKI. Pour détecter le passage de Np pièces par lot, on utilise l'interruption sur
débordement du Timer0. Quelle est alors la valeur à charger dans le registre TMR0L pour
avoir une interruption à chaque passage de Np pièces ?

void init_timer0(void){...}
3. Donner le corps de la fonction :

void __interrupt() cnt(void){...}


qui permet de changer (complémenter) l'état de la broche de sortie PC7=LOT_REALISE
et mettre à jour le nombre des pièces déjà emballées dans une variable :

unsigned int n_pieces_emballees;


4. Créer une fonction qui calcule le nombre total de pièces (ayant passées)= déjà emballées +
celle en cours d'emballage. Le registre TMR0L nous informe sur le nombre de pièces en cours
d'emballage :

unsigned int n_pieces_passees(){...}


Appeler cette fonction dans la boucle innie de la fonction principale main, pour faire sortir le
nombre de pièces passées sur le PORTD.

M.ABDOUN 60
CHAPITRE 5. LES TIMERS

Réponses :

1. void init_PORTs(void) {
TRISA4 = 1; // RA4/T0CKI=PASSAGE_PIECE en entrée
TRISC7 = 0; // RC7=LOT_REALISE en sortie
TRISD = 0x00; // PORTD pour visualisation, en sortie

LC7 = 0; // valeurs initiales des


LATD = 0; // sorties
}

2. Le débordement du Timer0 arrive après comptage de Np à 256(0x100), c-à-d 256 − Np incré-


ments. On dénit, alors au début du cher 'C' les constantes :

// constante représentant le nombre de pièces par lot


#define PIECES_PAR_LOT (10)
// valeur à recharger dans le TMR1
#define RECHARGE_TMR0 (0X100 - PIECES_PAR_LOT)

// Timer 0 en compteur
void init_timer0(void) {
T08BIT = 1; // n'utiliser qu'un octet pour comptage: TMR0L
T0CS = 1; // incrémentation sur front de l'entrée RA4/T0CKI
T0SE = 0; // front montant sur RA4/T0CKI

PSA = 1; // pas de pre-diviseur

TMR0L = RECHARGE_TMR0;

TMR0ON = 1; // préparer le Timer0 à compter

TMR0IE = 1; // valider les interruptions dues à TMR0


TMR0IF = 0;
}

3. Le corps de la fonction d'interruption est :

void __interrupt() cnt(void) {


if (TMR0IF && TMR0IE) {
TMR0L = RECHARGE_TMR0;

M.ABDOUN 61
CHAPITRE 5. LES TIMERS

LC7 ^= 1; // complémenter la sortie LOT_REALISE:PC7

// mettre à jour nombre total de pièces emballées


n_pieces_emballees += PIECES_PAR_LOT;

TMR0IF = 0;
}
}
4. La fonction n_pieces_passees, utilise la valeur actuelle dans TMR0L pour déduire le nombre
de pièces déjà comptées depuis le dernier LOT (depuis le dernier débordement du Timer0) et
donc

n_pieces_passees = n_pieces_emballees + T M R0L − RECHARGE _T M R0

unsigned int n_pieces_passees() {


return n_pieces_emballees + TMR0L - RECHARGE_TMR0;
}

void main() {
unsigned int output;

init_PORTs();
init_timer0();

GIE = 1; // Valider les interruptions globalement

while (1) {
output = n_pieces_passees();
LATD = output;
}
}

5.5.4 Timer1

Le temporisateur/compteur du module Timer1 a les caractéristiques suivantes :


 Temporisateur/compteur 16 bits (deux registres 8 bits ; TMR1H et TMR1L)
 Lecture et écriture (les deux registres)
 Sélection d'horloge interne ou externe
 Interruption sur débordement de 0xFFFF à 0x0000
 RÉINITIALISATION à partir du déclencheur d'événement spécial du module CCP

M.ABDOUN 62
CHAPITRE 5. LES TIMERS

La gure 5.9 est un schéma fonctionnel simplié du module Timer1. Le registre 5.10 détaille le
registre de contrôle Timer1. Ce registre contrôle le mode de fonctionnement du module Timer1 et
contient le bit de validation de l'oscillateur Timer1 (T1OSCEN). Timer1 peut être activé ou désactivé
en réglant ou en eaçant le bit de contrôle TMR1ON (T1CON<0>).

Figure 5.9  Schéma fonctionnel du Timer1

Le Timer1 peut être utilisée soit comme une minuterie, soit comme un compteur. Lorsque le
bit TMR1CS du registre T1CON est bas, l'horloge : FOSC /4 est sélectionnée pour le temporisateur.
Lorsque TMR1CS est haut, le module fonctionne comme un compteur cadencé à partir de l'entrée
T1OSI. Un circuit oscillateur à quartz, activé à partir du bit T1OSCEN de T1CON, est construit
entre les broches T1OSI et T1OSO où un cristal jusqu'à 200 KHz peut être connecté entre ces
broches. Cet oscillateur est principalement destiné à un fonctionnement en cristal à 32 KHz dans les
applications d'horloge temps réel. Un pré-diviseur (de fréquence) est utilisé dans le Timer1 qui peut
diviser la fréquence de synchronisation d'un facteur de 1, 2, 4 ou 8, selon la valeur des bits T1CKPS1
et T1CKPS0 du T1CON.

Le Timer 1 peut être conguré pour que la lecture/écriture puisse être eectuée soit en mode
16 bits (les deux registres TMR1H et TMR1L échantillonnés en même instant), soit en deux modes
8 bits. Le bit RD16 du registre T1CON contrôle ce mode. Lorsque RD16 est bas, les opérations
de lecture et d'écriture du temporisateur sont exécutées comme deux opérations de 8 bits. Lorsque
RD16 est au niveau haut, les opérations de lecture et d'écriture du temporisateur sont en 16 bits, et
on peut utiliser TMR1, qui est de 16-bits ; par exemple TMR1 = 0XFF45.

Si les interruptions du Timer1 sont activées (TMR1IE = 1), une interruption sera générée lorsque
la valeur du temporisateur passe de 0xFFFF à 0x0000, c-à-d lors d'un débordement.

M.ABDOUN 63
CHAPITRE 5. LES TIMERS

Figure 5.10  Registre de conguration T1CON du Timer1

5.5.5 Exemple d'application au Timer1

Reprendre l'exemple 2 de la section : 5.5.3 et au lieu de complémenter la broche RC7 à chaque


n d'un lot, faire sortie sur cette broche une impulsion calibrée de durée Tlot = 125ms réglable par
pas de 4µs. On doit utiliser pour celà le Timer1 en mode timer. La carte est rythmée par une horloge
de Fosc = 8M Hz .

Donc pour cet exemple, on utilisera le timer0 en compteur (comme on l'a déjà fait) et le Timer1
en générateur d'impulsion (monostable). Quelle est la valeur à donner au prédiviseur : P S et quelle
est la valeur à recharger dans TMR0 : NT M R0 pour obtenir la durée fournie ?

Durée réglable par pas de 4µs, veut dire la résolution de TMR1 est de 4µs et donc la valeur du

M.ABDOUN 64
CHAPITRE 5. LES TIMERS

pre-diviseur est P S (voir la note : 4)


4
τ= × PS
FOSC
FOSC
=⇒ P S = τ ×
4
8.106
= 4.10−6 ×
4
=8

On a déjà vu que :
T × FOSC
NT M R0 = 216 −
4 × PS
125.10−3 × 8.106
= 65536 −
4×8
= 65536 − 31250
= 34286

Remarquez le 216 au lieu de 28 , car le Timer1 est un 16-bits.

Réponse :

La réponse est donnée sous forme du chier en "C" nal et commenté :

#include <xc.h>

#pragma config WDT=OFF

// constante représentant le nombre de pièces par lot


#define PIECES_PAR_LOT (10)
// valeur à recharger dans le TMR1
#define RECHARGE_TMR0 (0X100 - PIECES_PAR_LOT)

// Avec Fosc = 8MHz et PS=8, durée=125ms -> 31250 increments


#define INC_1SEC (31250)
#define RECHARGE_TMR1 (0x10000 - INC_1SEC)

// -------
unsigned int n_pieces_emballees = 0;

void init_PORTs(void) {

M.ABDOUN 65
CHAPITRE 5. LES TIMERS

TRISA4 = 1; // RA4/T0CKI=PASSAGE_PIECE en entrée


TRISC7 = 0; // RC7=LOT_REALISE en sortie
TRISD = 0x00; // PORTD pour visualisation, en sortie

LC7 = 0; // valeurs initiales des


LATD = 0; // sorties
}

// Timer 0 en mode compteur


void init_timer0(void) {
T08BIT = 1; // n'utiliser qu'un octet pour comptage: TMR0L
T0CS = 1; // incrémentation sur front de l'entrée RA4/T0CKI
T0SE = 0; // front montant sur RA4/T0CKI

PSA = 1; // pas de pre-diviseur

TMR0L = RECHARGE_TMR0;

TMR0ON = 1; // préparer le Timer0 à compter

TMR0IE = 1; // valider les interruptions dues à TMR0


TMR0IF = 0;
}

// Timer 1 en mode timer


void init_timer1(void) {
TMR1ON = 0; // s'assurer que le Timer 1 est à l'arrêt

T1CONbits.RD16 = 1; // utiliser 16-bits en lecture/écriture

T1OSCEN = 0; // on n'utilise pas l'oscillateur secondaire T1OSC


TMR1CS = 0; // mais plutôt Fosc/4

T1CKPS0 = 1; // pre-diviseur par 8


T1CKPS1 = 1; //

TMR1 = RECHARGE_TMR1;

TMR1IE = 1; // valider l'interruption au Timer1


TMR1IF = 0;

M.ABDOUN 66
CHAPITRE 5. LES TIMERS

PEIE = 1; // Timer1 fait partie des périphériques, valider les


// interruptions des périphériques
}

void __interrupt() cnt(void) {


if (TMR0IF && TMR0IE) { // interruption due à LOT_REALISE
TMR0L = RECHARGE_TMR0;

// LC7 ^= 1;
LC7 = 1; // activer la sortie LC7
TMR1 = RECHARGE_TMR1; // préparer la durée de l'impulsion sur LC7
TMR1ON = 1; // lancer la tempo associée au Timer1

// mettre à jour nombre total de pièces passées


n_pieces_emballees += PIECES_PAR_LOT;

TMR0IF = 0;
} else if (TMR1IF && TMR1IE) { // durée sur sortie LC7 dépassée
LC7 = 0; // mettre la sortie LC7 à 0; fin de l'impulsion
TMR1ON = 0; // stopper la tempo du Timer1

TMR1IF = 0;
}
}

unsigned int n_pieces_passees() {


return n_pieces_emballees + TMR0L - RECHARGE_TMR0;
}

void main() {
unsigned int output;

init_PORTs();
init_timer1();
init_timer0();

GIE = 1;

while (1) {
output = n_pieces_passees();

M.ABDOUN 67
CHAPITRE 5. LES TIMERS

LATD = (unsigned char)output;


}
}

M.ABDOUN 68

Vous aimerez peut-être aussi