Vous êtes sur la page 1sur 266

La Programmation des PIC

par Bigonoff

Premire partie rvision 34


Dmarrer les PIC avec le 16F84
2
1. INTRODUCTION............................................................................................................................................. 9

2. LES SYSTEMES DE NUMERATION ......................................................................................................... 11


2.1 LE SYSTEME DECIMAL .................................................................................................................................. 11
2.2 LE SYSTEME BINAIRE ................................................................................................................................... 11
2.3 LE SYSTEME HEXADECIMAL ......................................................................................................................... 13
2.4 LES OPERATIONS .......................................................................................................................................... 14
2.5 LES NOMBRES SIGNES .................................................................................................................................. 15
2.6 LES OPERATIONS BOOLEENNES. ................................................................................................................... 16
2.6.1 Le complment ..................................................................................................................................... 16
2.6.2 La fonction ET ou AND ............................................................................................................ 16
2.6.3 La fonction OU ou OR ............................................................................................................. 17
2.6.4 La fonction OU EXCLUSIF ou Exclusif OR ou XOR ........................................................ 18
2.7 UN MOT SUR LES UNITES .............................................................................................................................. 18
3. COMPOSITION ET FONCTIONNEMENT DES PIC............................................................................ 21
3.1 QUEST-CE QUUN PIC ? ........................................................................................................................... 21
3.2 LES DIFFERENTES FAMILLES DES PIC........................................................................................................ 22
3.3 IDENTIFICATION DUN PIC ........................................................................................................................ 23
3.4 ORGANISATION DU 16F84............................................................................................................................ 24
3.4.1 La mmoire programme ....................................................................................................................... 24
3.4.2 La mmoire Eeprom............................................................................................................................. 24
3.4.3 La mmoire Ram .................................................................................................................................. 25
4. ORGANISATION DES INSTRUCTIONS ................................................................................................... 27
4.1 GENERALITES............................................................................................................................................... 27
4.2 LES TYPES DINSTRUCTIONS ......................................................................................................................... 27
4.2.1 Les instructions orientes octet ...................................................................................................... 27
4.2.2 Les instructions orientes bits ........................................................................................................ 28
4.2.3 Les instructions gnrales.................................................................................................................... 28
4.2.4 Les sauts et appels de sous-routines..................................................................................................... 28
4.3 PANORAMIQUE DES INSTRUCTIONS .............................................................................................................. 28
4.4 LES INDICATEURS DETAT ............................................................................................................................ 30
4.4.1 Lindicateur dtat Z ...................................................................................................................... 31
4.4.2 Lindicateur dtat C ...................................................................................................................... 31
5. LES DEBUTS AVEC MPLAB.................................................................................................................... 33
5.1 PREPARATION A LUTILISATION ................................................................................................................... 33
5.2 CREATION DE NOTRE PREMIER PROJET ......................................................................................................... 34
6. ORGANISATION DUN FICHIER .ASM ............................................................................................. 41
6.1 LES COMMENTAIRES .................................................................................................................................... 41
6.2 LES DIRECTIVES ........................................................................................................................................... 41
6.3 LES FICHIERS INCLUDE ........................................................................................................................... 42
6.4 LA DIRECTIVE _CONFIG............................................................................................................................. 42
6.5 LES ASSIGNATIONS ....................................................................................................................................... 43
6.6 LES DEFINITIONS .......................................................................................................................................... 44
6.7 LES MACROS ................................................................................................................................................ 44
6.8 LA ZONE DES VARIABLES ............................................................................................................................. 45
6.9 LES ETIQUETTES ........................................................................................................................................... 45
6.10 LA DIRECTIVE ORG ............................................................................................................................. 46
6.11 LA DIRECTIVE END ET LA FIN DUN PROGRAMME ................................................................................ 46
7. REALISATION DUN PROGRAMME ....................................................................................................... 49
7.1 CREATION DE NOTRE PREMIER PROGRAMME ................................................................................................ 49
7.2 LASSEMBLAGE DUN PROGRAMME.............................................................................................................. 50
8. LA SIMULATION DUN PROGRAMME................................................................................................... 53

3
8.1 LANCEMENT ET PARAMETRAGE DU SIMULATEUR ......................................................................................... 53
8.2 EXPLICATION DES REGISTRES FONDAMENTAUX ........................................................................................... 55
8.2.1 Les registres PCL et PCLATH ................................................................................................. 55
8.2.2 Le registre W .................................................................................................................................. 56
8.2.3 Le registre STATUS ........................................................................................................................ 56
8.3 LANCEMENT DE LA SIMULATION .................................................................................................................. 57
9. LE JEU DINSTRUCTIONS ......................................................................................................................... 63
9.1 LINSTRUCTION GOTO (ALLER A) ......................................................................................................... 63
9.2 LINSTRUCTION INCF (INCREMENT FILE)............................................................................................. 64
9.3 LINSTRUCTION DECF (DECREMENT FILE) .......................................................................................... 65
9.4 LINSTRUCTION MOVLW (MOVE LITERAL TO W)............................................................................... 65
9.5 LINSTRUCTION MOVF (MOVE FILE) ................................................................................................... 66
9.6 LINSTRUCTION MOVWF (MOVE W TO FILE)...................................................................................... 67
9.7 LINSTRUCTION ADDLW (ADD LITERAL AND W)................................................................................ 67
9.8 LINSTRUCTION ADDWF (ADD W AND F) ........................................................................................... 68
9.9 LINSTRUCTION SUBLW (SUBTRACT W FROM LITERAL)..................................................................... 68
9.10 LINSTRUCTION SUBWF (SUBTRACT W FROM F) .............................................................................. 71
9.11 LINSTRUCTION ANDLW (AND LITERAL WITH W) ............................................................................ 71
9.12 LINSTRUCTION ANDWF (AND W WITH F)........................................................................................ 72
9.13 LINSTRUCTION IORLW (INCLUSIVE OR LITERAL WITH W) ............................................................... 73
9.14 LINSTRUCTION IORWF (INCLUSIVE OR W WITH FILE) ...................................................................... 73
9.15 LINSTRUCTION XORLW (EXCLUSIVE OR LITERAL WITH W)............................................................ 74
9.16 LINSTRUCTION XORWF (EXCLUSIVE OR W WITH F) ........................................................................ 74
9.17 LINSTRUCTION BSF (BIT SET F) ......................................................................................................... 75
9.18 LINSTRUCTION BCF (BIT CLEAR F).................................................................................................... 75
9.19 LINSTRUCTION RLF ( ROTATE LEFT THROUGH CARRY) ..................................................................... 76
9.20 LINSTRUCTION RRF ( ROTATE RIGHT THROUGH CARRY)................................................................... 77
9.21 LINSTRUCTION BTFSC (BIT TEST F, SKIP IF CLEAR).......................................................................... 78
9.22 LINSTRUCTION BTFSS (BIT TEST F, SKIP IF SET)............................................................................... 80
9.23 LINSTRUCTION DECFSZ (DECREMENT F, SKIP IF Z)......................................................................... 80
9.24 LINSTRUCTION INCFSZ (INCREMENT F, SKIP IF ZERO)..................................................................... 82
9.25 LINSTRUCTION SWAPF (SWAP NIBBLES IN F) .................................................................................. 82
9.26 LINSTRUCTION CALL (CALL SUBROUTINE) ...................................................................................... 83
9.27 LINSTRUCTION RETURN (RETURN FROM SUBROUTINE) ................................................................. 84
9.28 LINSTRUCTION RETLW (RETURN WITH LITERAL IN W) ................................................................... 86
9.29 LINSTRUCTION RETFIE (RETURN FROM INTERRUPT)....................................................................... 87
9.30 LINSTRUCTION CLRF (CLEAR F)....................................................................................................... 87
9.31 LINSTRUCTION CLRW (CLEAR W).................................................................................................... 88
9.32 LINSTRUCTION CLRWDT (CLEAR WATCHDOG) .............................................................................. 88
9.33 LINSTRUCTION COMF (COMPLEMENT F).......................................................................................... 88
9.34 LINSTRUCTION SLEEP (MISE EN SOMMEIL) ....................................................................................... 89
9. 35 LINSTRUCTION NOP (NO OPERATION) .............................................................................................. 89
9.36 LES INSTRUCTIONS OBSOLETES .................................................................................................................. 90
10. LES MODES DADRESSAGE .................................................................................................................... 91
10.1 LADRESSAGE LITTERAL OU IMMEDIAT ...................................................................................................... 91
10.2 LADRESSAGE DIRECT ................................................................................................................................ 91
10.3 LADRESSAGE INDIRECT ............................................................................................................................ 92
10.3.1 Les registres FSR et INDF ................................................................................................................. 92
10.4 QUELQUES EXEMPLES ................................................................................................................................ 93
11. REALISATION DUN PROGRAMME EMBARQUE ............................................................................. 95
11.1 LE MATERIEL NECESSAIRE ......................................................................................................................... 95
11.2 MONTAGE DE LA PLATINE DESSAIS ........................................................................................................... 96
11.3 CREATION DU PROJET ................................................................................................................................. 97
11.4 EDITION DU FICHIER SOURCE ..................................................................................................................... 97
11.5 CHOIX DE LA CONFIGURATION ................................................................................................................... 97
11.6 LE REGISTRE OPTION ............................................................................................................................... 99
11.7 EDITION DU PROGRAMME ......................................................................................................................... 100

4
11.8 LE REGISTRE PORTA............................................................................................................................... 103
11.8.1 Fonctionnement particulier des PORTS........................................................................................... 105
11.9 LE REGISTRE TRISA ................................................................................................................................ 106
11.10 LES REGISTRES PORTB ET TRISB......................................................................................................... 107
11.11 EXEMPLE DAPPLICATION ...................................................................................................................... 108
11.12 LA ROUTINE DINITIALISATION............................................................................................................... 108
11.13 LES RESULTATS DE LASSEMBLAGE........................................................................................................ 112
11.14 LE PROGRAMME PRINCIPAL .................................................................................................................... 112
11.15 LA SOUS-ROUTINE DE TEMPORISATION .................................................................................................. 113
12. LES INTERRUPTIONS............................................................................................................................. 119
12.1 QUEST-CE QUUNE INTERRUPTION ?....................................................................................................... 119
12.2 MECANISME GENERAL DUNE INTERRUPTION .......................................................................................... 120
12.3 MECANISME DINTERRUPTION SUR LES PIC .......................................................................................... 121
12.4 LES SOURCES DINTERRUPTIONS DU 16F84.............................................................................................. 123
12.5 LES DISPOSITIFS MIS EN UVRE................................................................................................................ 123
12.6 LE REGISTRE INTCON (INTERRUPT CONTROL)..................................................................................... 125
12.7 SAUVEGARDE ET RESTAURATION DE LENVIRONNEMENT ........................................................................ 127
12.7.1 Les registres sauvegarder ............................................................................................................. 128
12.7.2 La mthode de sauvegarde............................................................................................................... 128
12.7.3 La mthode de restauration.............................................................................................................. 129
12.7.4 OPERATIONS SUR LE REGISTRE STATUS .............................................................................................. 131
12.7.5Particularit de linstruction RETFIE ......................................................................................... 132
12.8 UTILISATION DUNE ROUTINE DINTERRUPTION ....................................................................................... 133
12.9 ANALYSE DE LA ROUTINE DINTERRUPTION ............................................................................................. 136
12.10 ADAPTATION DE LA ROUTINE DINTERRUPTION ..................................................................................... 138
12.11 LINITIALISATION................................................................................................................................... 139
12.12 CONSTRUCTION DU PROGRAMME PRINCIPAL .......................................................................................... 140
12.13 CONSTRUCTION DE LA ROUTINE DINTERRUPTION ................................................................................. 141
12.14 PASSAGE AU SIMULATEUR DUNE ROUTINE DINTERRUPTION ................................................................ 142
12.15 PREMIERE CORRECTION : RESET DU FLAG .............................................................................................. 146
12.16 SE METTRE A LECHELLE DE TEMPS DU PIC ........................................................................................ 147
12.17 LE PROBLEME DE LANTI-REBOND.......................................................................................................... 147
12.18 FINALISATION DU PROGRAMME.............................................................................................................. 148
12.19 REMARQUES IMPORTANTES.................................................................................................................... 151
12.20 CONCLUSIONS ........................................................................................................................................ 152
13. LE TIMER 0................................................................................................................................................ 155
13.1 LES DIFFERENTS MODES DE FONCTIONNEMENT ........................................................................................ 155
13.2 LE REGISTRE TMR0................................................................................................................................... 155
13.3 LES METHODES DUTILISATION DU TIMER0 ............................................................................................. 155
13.3.1 Le mode de lecture simple................................................................................................................ 156
13.3.2 Le mode de scrutation du flag .......................................................................................................... 156
13.3.3 Le mode dinterruption..................................................................................................................... 157
13.3.4 Les mthodes combines .................................................................................................................. 157
13.4 LE PREDIVISEUR ....................................................................................................................................... 157
13.5 APPLICATION PRATIQUE DU TIMER0......................................................................................................... 160
13.5.1 Prparations..................................................................................................................................... 160
13.5.2 Linitialisation.................................................................................................................................. 161
13.5.3 La routine dinterruption ................................................................................................................. 162
13.6 MODIFICATION DES REGISTRES DANS LE SIMULATEUR ............................................................................. 163
13.7 MISE EN PLACE SUR LA PLATINE DESSAIS................................................................................................ 164
13.8 PREMIERE AMELIORATION DE LA PRECISION ............................................................................................ 164
13.9 SECONDE AMELIORATION DE LA PRECISION ............................................................................................. 165
13.10 LA METHODE DITE DE RATTRAPAGE ................................................................................................. 165
13.11 LA METHODE HARDWARE - ADAPTATION DE LHORLOGE...................................................................... 167
13.12 LA METHODE DE LUXE : LA DOUBLE HORLOGE ...................................................................................... 167
13.13 EXEMPLE DUTILISATION DE 2 INTERRUPTIONS ...................................................................................... 168
13.13 CONCLUSION .......................................................................................................................................... 169
14. LES ACCES EN MEMOIRE EEPROM ............................................................................................ 171

5
14.1 TAILLE ET LOCALISATION DE LA MEMOIRE EEPROM ........................................................................... 171
14.2 PREPARATION DU PROGRAMME ................................................................................................................ 171
14.3 INITIALISATION DE LA ZONE EEPROM ....................................................................................................... 173
14.4 LE REGISTRE EEDATA............................................................................................................................ 175
14.5 LE REGISTRE EEADR .............................................................................................................................. 175
14.6 LE REGISTRE EECON1 ............................................................................................................................ 175
14.7 LE REGISTRE EECON2 ............................................................................................................................ 176
14.8 ACCES EN LECTURE DANS LA MEMOIRE EEPROM ................................................................................ 176
14.9 LACCES EN ECRITURE A LA ZONE EEPROM .............................................................................................. 177
14.10 UTILISATION PRATIQUE DE LA MEMOIRE EEPROM ............................................................................ 179
14.11 SECURISATION DES ACCES EN MEMOIRE EEPROM ............................................................................. 182
14.12 CONCLUSION .......................................................................................................................................... 183
15. LE WATCHDOG........................................................................................................................................ 185
15.1 LE PRINCIPE DE FONCTIONNEMENT .......................................................................................................... 185
15.2 LE PREDIVISEUR ET LE WATCHDOG .......................................................................................................... 186
15.3 LES ROLES DU WATCHDOG ....................................................................................................................... 186
15.4 UTILISATION CORRECTE DU WATCHDOG .................................................................................................. 187
15.5 CE QUIL NE FAUT PAS FAIRE .................................................................................................................... 188
15.6 MESURE DU TEMPS REEL DU WATCHDOG ................................................................................................. 188
15.7 SIMULATION DU PLANTAGE DUN PROGRAMME ....................................................................................... 190
15.7.1 Correction avec utilisation du watchdog ......................................................................................... 191
15.8 CHOIX DE LA VALEUR DU PREDIVISEUR.................................................................................................... 192
15.9 TEMPS TYPIQUE, MINIMAL, ET MAXIMUM ................................................................................................. 192
15.10 CONCLUSION .......................................................................................................................................... 192
16. LE MODE SLEEP ...................................................................................................................................... 195
16.1 PRINCIPE DE FONCTIONNEMENT ............................................................................................................... 195
16.2 LA SORTIE DU MODE SLEEP ................................................................................................................ 195
16.3 REVEIL AVEC GIE HORS SERVICE............................................................................................................. 196
16.4 REVEIL AVEC GIE EN SERVICE ................................................................................................................. 196
16.5 MISE EN SOMMEIL IMPOSSIBLE ................................................................................................................. 196
16.6 UTILISATION DU MODE SLEEP ............................................................................................................. 197
REMARQUE ...................................................................................................................................................... 198
16.7 CAS TYPIQUES DUTILISATION.................................................................................................................. 198
16.7 POUR UNE CONSOMMATION MINIMALE .................................................................................................... 198
16.8 CONCLUSION ............................................................................................................................................ 199
17. LE RESTE DU DATASHEET ................................................................................................................... 201
17.1 LA STRUCTURE INTERNE .......................................................................................................................... 201
17.2 LA SEQUENCE DE DECODAGE ................................................................................................................... 201
17.3 ORGANISATION DE LA MEMOIRE .............................................................................................................. 201
17.4 LES REGISTRES SPECIAUX......................................................................................................................... 202
17.5 LELECTRONIQUE DES PORTS ................................................................................................................... 202
17.6 LE REGISTRE DE CONFIGURATION ............................................................................................................ 202
17.7 LES DIFFERENTS TYPES DOSCILLATEURS................................................................................................. 203
17.7.1 La prcision de loscillateur ............................................................................................................ 204
17.8 LE RESET .................................................................................................................................................. 205
17.9 LA MISE SOUS TENSION ............................................................................................................................ 206
17.10 CARACTERISTIQUES ELECTRIQUES ......................................................................................................... 207
17.11 PORTABILITE DES PROGRAMMES ............................................................................................................ 207
17.12 LES MISES A JOUR DES COMPOSANTS ...................................................................................................... 208
17.13 CONCLUSION .......................................................................................................................................... 209
18. ASTUCES DE PROGRAMMATION ....................................................................................................... 211
18.1 LES COMPARAISONS ................................................................................................................................. 211
18.2 SOUSTRAIRE UNE VALEUR DE W ............................................................................................................... 212
18.3 LES MULTIPLICATIONS ............................................................................................................................. 212
18.4 MULTIPLICATION PAR UNE CONSTANTE ................................................................................................... 215
18.5 ADRESSAGE INDIRECT POINTANT SUR 2 ZONES DIFFERENTES ................................................................... 216

6
18.6 LES TABLEAUX EN MEMOIRE PROGRAMME............................................................................................... 217
18.7 LES VARIABLES LOCALES ......................................................................................................................... 221
18.7.1 Dtermination des variables locales ................................................................................................ 222
18.7.2 Construction sans variables locales................................................................................................ 222
18.7.3 Construction avec variables locales................................................................................................. 222
18.8 DIVISION PAR UNE CONSTANTE ................................................................................................................ 223
18.9 CONCLUSION ............................................................................................................................................ 223
19. UTILISATION DE ROUTINES DANS UN FICHIER SEPARE........................................................... 225
19.1 QUESTIONS ET POINT DE DEPART ............................................................................................................. 225
19.2 UTILISATION DIRECTE DES ROUTINES DANS LE FICHIER ........................................................................... 225
19.3 ENCAPSULATION DANS DES MACROS SIMPLES .......................................................................................... 228
19.4 MTHODE FINALISE ................................................................................................................................ 230
19.5 CONCLUSION ............................................................................................................................................ 231
20. LA NORME ISO 7816 ................................................................................................................................ 233
20.1 SPECIFICITES UTILES DE LA NORME ISO 7816 .......................................................................................... 233
20.1.1 Les commandes ISO 7816 ................................................................................................................ 234
20.1.2 Le protocole dchange dinformations ........................................................................................... 235
20.2 LES LIAISONS SERIE ASYNCHRONES ......................................................................................................... 236
20.2.1 Le start-bit........................................................................................................................................ 236
20.2.2 Les bits de donnes........................................................................................................................... 236
20.2.3 Le bit de parit ................................................................................................................................ 237
20.2.4 Le stop-bit ........................................................................................................................................ 237
20.2.5 Vitesse et dbit.................................................................................................................................. 237
20.3 ACQUISITION DES BITS ............................................................................................................................. 238
20.4 CARACTERISTIQUE DES CARTES STANDARD ....................................................................................... 239
20.5 CREATION ET INITIALISATION DU PROJET ................................................................................................. 239
20.6 LA BASE DE TEMPS ................................................................................................................................... 240
20.7 RECEPTION DUN OCTET ........................................................................................................................... 241
20.8 LEMISSION DUN CARACTERE ................................................................................................................. 243
20.9 INITIALISATION ........................................................................................................................................ 245
20.10 ENVOI DE LATR ................................................................................................................................... 246
20.11 LENVOI DU STATUT ............................................................................................................................... 247
20.12 RECEPTION DE LA CLASSE ...................................................................................................................... 248
20.13 RECEPTION DE INS, P1, P2, ET LEN ...................................................................................................... 248
20.14 CONTROLE DE LINSTRUCTION REUE .................................................................................................... 249
20.15 TRAITEMENT DUNE INSTRUCTION ......................................................................................................... 249
20.16 LES VARIABLES ...................................................................................................................................... 250
20.17 CONCLUSION .......................................................................................................................................... 251
ANNEXE1 : QUESTIONS FREQUEMMENT POSEES (F.A.Q.)............................................................... 253
A1.1 JE TROUVE QUE 8 SOUS-PROGRAMMES, CEST PEU .................................................................................. 253
A1.2 JE NUTILISE QUE 8 IMBRICATIONS, ET POURTANT MON PROGRAMME PLANTE. ....................................... 253
A1.3 MON PROGRAMME SEMBLE NE JAMAIS SORTIR DES INTERRUPTIONS ....................................................... 253
A1.4 JE NARRIVE PAS A UTILISER LE SIMULATEUR, LES OPTIONS NAPPARAISSENT PAS .................................. 253
A1.5 JE REOIS UN MESSAGE DERREUR EOF AVANT INSTRUCTION END ....................................................... 254
A1.6 COMMENT DESASSEMBLER UN FICHIER .HEX ? .................................................................................. 254
A1.7 UTILISATION DES MINUSCULES ET DES MAJUSCULES ............................................................................... 254
A1.8 LE CHOIX DUN PROGRAMMATEUR .......................................................................................................... 254
A1.9 JAI UNE ERREUR DE STACK ............................................................................................................... 255
A1.10 QUELLES SONT LES DIFFERENCES ENTRE 16F84 ET 16F84A ?............................................................... 256
A1.11 JAI UNE ERREUR 173 LORS DE LASSEMBLAGE ..................................................................................... 257
A1.12 LE PIC16F84 EST OBSOLETE, POURQUOI NE PAS UTILISER LE 16F628 ?................................................ 257
A1.13 JUTILISE UNE VERSION DE MPLAB PLUS RECENTE ........................................................................... 258
A1.14 MON PIC VIERGE NOSCILLE PAS ........................................................................................................... 258
CONTRIBUTION SUR BASE VOLONTAIRE ............................................................................................ 261

UTILISATION DU PRESENT DOCUMENT ............................................................................................... 262

7
8
1. Introduction

Et voil, nous sommes partis ensemble pour cette grande aventure quest la
programmation des PIC. Je vais tenter de rester le plus concret possible, mais, cependant,
une certaine part de thorie est indispensable pour arriver au but recherch.

Je vais donc commencer ce petit cours par un rappel sur les systmes de numration. Ca y
est, jen vois qui rlent dj. Mais je suis sr que vous comprendrez quil est impossible de
programmer srieusement un microcontrleur sans savoir ce quest un bit, ou comment
convertir les notations dcimales en hexadcimales.

Rassurez-vous, je vais faire bref, et nous pourrons trs rapidement aborder le sujet qui
nous intresse tant. Si vous tes dj un pro , vous pouvez sauter le premier chapitre et
passer directement au suivant.

Nhsitez jamais me faire part de vos remarques, ni me signaler les erreurs qui
mauraient chappes ( www.bigonoff.org). Rpercutez les infos que vous trouverez ici,
traduisez le document dans une autre langue ou un autre format. Simplement, dans ce cas,
veuillez respecter les dsirs de lauteur en fin douvrage et faites moi parvenir un exemplaire
de votre travail. Ceci pour permettre den faire profiter le plus grand nombre
(bigocours@hotmail.com).

Jattire votre attention sur le fait que ce cours, pour tre efficace, doit tre lu tout en
ralisant les exercices que je vous propose. Les solutions des exercices sont disponibles sous
forme de fichiers exemples fournis en annexe de ce cours.

Tout ce quil vous faudra, cest un 16F84(A) un quartz de 4MHz, une petite platine
dessais, une LED, un bouton poussoir et le logiciel MPLAB, mis gracieusement votre
disposition par la socit Microchip ladresse http://www.Microchip.com. A cette mme
adresse, vous pourrez vous procurer le datasheet du 16F84.

Jai pass de nombreuses journes raliser ces exercices. Je les ai personnellement tests
sur maquette un par un. Alors je vous demanderai de tenter de faire vous-mme ces petits
programmes avant de me poser par email des questions dont vous auriez eu les rponses si
vous aviez ralis cet effort. Croyez-moi sur parole, ce nest quau moment de mettre en
pratique quon saperoit quon navait finalement pas bien compris quelque chose qui
paraissait pourtant vident. Je rponds toujours au courrier reu, mais il faut dire que cest
parfois lgrement nervant de recevoir une question de quelquun qui affirme avoir assimil
la totalit de cet ouvrage en une heure. Ca mest arriv !

Jai utilis personnellement la version 6.30 de MPLAB partir de la rvision 13 du


cours. Les prcdentes rvisions utilisaient la version 5.20. La version 6.60 est disponible
section archives sur le site de Microchip.

Je vous demande, pour bien suivre, dutiliser cette version pour suivre le cours, et, une
fois votre apprentissage termin, de charger une version plus rcente et dexprimenter vous-
mme les diffrences. Le PIC utilis ici est le plus simple existant dans cette famille, il ne
sagit pas du PIC le plus avantageux lorsque vous raliserez vos montages personnels,
choisissez votre modle en fonction de votre cahier des charges.

9
La tte de mort prsente sur la premire page du cours nest pas un symbole li ce
cours, elle est dune utilit historique. En effet, lorsque jai propos les premires versions de
mon cours, je navais pas dhbergement, mes cours taient donc distribus sur le net (jusque
la rvision 6). En consquence, en cas de litige, je navais aucun moyen de prouver
lgalement que jtais lauteur de ce cours, que je pouvais donc aisment me faire
voler . Ne dsirant pas dvoiler ma vritable identit (je nai pas besoin que des cohortes
dtudiants viennent frapper ma porte), jai voulu signer ce document de faon ce que
je puisse prouver tout moment que jen tais lauteur.

Si, donc, vous vous rendez sur mon site et que vous regardez la photo de ma moto, vous
constaterez que cette tte de mort nest rien dautre que la photo dune partie de mon
carnage. Comme cette photo est sur mes cours et que je peux prouver que je suis propritaire
de la moto, je sais prouver au besoin que je suis le vritable auteur de mes cours.

10
2. Les systmes de numration
2.1 Le systme dcimal

Nous sommes habitus, depuis notre enfance utiliser le systme numrique dcimal, tel
point que nous ne voyons mme plus la manire donc ce systme fonctionne, tant cest
devenu un automatisme.

Dcimal, pourquoi ? Parce quil utilise une numration 10 chiffres. Nous dirons que
cest un systme en Base 10. Pour la petite histoire, on a utilis un systme base 10 car nos
anctres ont commenc compter sur leurs 10 doigts, pas besoin daller chercher plus loin.

Mais la position des chiffres a galement une grande importance. Les chiffres les moins
significatifs se situent droite du nombre, et leur importance augmente au fur et mesure du
dplacement vers la gauche. En effet, dans le nombre 502, le 5 a une plus grande importance
que le 2. En ralit, chaque chiffre, que lon peut appeler digit, a une valeur qui dpend de
son rang. Quel est le multiplicateur appliquer un chiffre en fonction de sa position
(rang) ? Il sagit tout simplement de llvation de la BASE utilise la puissance de son
rang .

Cela a lair complexe crire, mais est trs simple comprendre. Lorsque vous avez
compris ceci, vous comprenez automatiquement nimporte quel systme de numration.

Reprenons, par exemple notre nombre 502. Que signifie le 2 ? Et bien, tout simplement
que sa valeur est gale 2 multipli par la base (10) leve la puissance du rang du chiffre,
cest dire 0. Or un nombre lev la puissance 0 vaut 1. Le 2 reprsente donc 2*1

Remarquez ici une chose trs importante : le comptage du rang seffectue toujours de
droite gauche et en commenant par 0. Pour notre nombre 502, sa valeur est donc en
ralit :
502 = 2*10 + 0*101 + 5*10. Notez que le symbole * est utilis pour indiquer
multipli . Et rappelez-vous que 10 = (10/10) = 1, que 101 = 10, et que 10 = 10*10 = 100
etc.

2.2 Le systme binaire

Vous avez compris ce qui prcde ? Alors la suite va vous paratre simple. Cela ne pose
aucun problme pour vous de compter sur vos 10 doigts, mais pour les ordinateurs, cela nest
pas si simple. Ils ne savent en gnral faire la distinction quentre 2 niveaux (prsence ou
absence de tension). Le systme de numration dcimal est donc inadapt.

On comprendra immdiatement que le seul systme adapt est donc un systme en base
2, appel systme binaire. Ce systme ne comporte donc que 2 chiffres, savoir 0 et 1.

Comme, de plus, les premiers ordinateurs (et les PIC) travaillent avec des nombres de 8
chiffres binaires, on a donc appel ces nombres des octets (ou bytes en anglais). Le chiffre 0
ou 1 est appel un bit(unit binaire, ou binary unit) .

11
Pour nous y retrouver dans la suite de ce petit ouvrage, on adoptera les conventions
suivantes : tout nombre dcimal est crit tel quel, ou en utilisant la notation Dxxx ; tout
nombre binaire est crit suivant la forme Bxxxxxxxx dans lesquels les x valent ? 0 ou 1
effectivement, vous avez bien suivi.

Analysons maintenant un nombre binaire, soit loctet : B10010101. Quelle est donc sa
valeur en dcimal ?

Et bien, cest trs simple, on applique le mme algorithme que pour le dcimal. Partons de
la droite vers la gauche, on trouve donc :

B10010101 = 1*2 + 0*21 + 1*2 + 0*23 + 1* 24 + 0*25 + 0*26 + 1*27

Comme, videmment 0 multipli par quelque chose = 0 et que 1 multipli par un chiffre =
le chiffre en question, on peut ramener le calcul prcdent :

B 10010101 = 1+4+16+128 = 149

Vous voyez donc quil est trs facile de convertir nimporte quel chiffre de binaire en
dcimal. Et linverse me direz-vous ? Et bien, cest galement trs simple. Il faut juste
connatre votre table des exposants de 2. Cela sapprend trs vite lorsquon sen sert.

On procde simplement par exemple de la manire suivante (il y en a dautres) :

Quel est le plus grand exposant de 2 contenu dans 149 ? Rponse 7 (27 = 128)
On sait donc que le bit 7 vaudra 1. Une fois fait, il reste 149-128 = 21
Le bit 6 reprsente 64, cest plus grand que 21, donc b6 = 0
Le bit 5 reprsente 32, cest plus grand que 21, donc b5 = 0
Le bit 4 reprsente 16, donc a passe, b4 = 1, il reste 21-16 = 5
Le bit 3 reprsente 8, cest plus grand que 5, donc b3 = 0
Le bit 2 reprsente 4, donc b2 = 1, reste 5-4 = 1
Le bit1 reprsente 2, cest plus grand que 1, donc b1 = 0
Le bit 0 reprsente 1, cest ce quil reste, donc b0=1, reste 0

Le nombre binaire obtenu est donc B10010101, qui est bien notre octet de dpart. Notez
que si on avait trouv un nombre de moins de 8 chiffres, on aurait complt avec des 0 placs
gauche du nombre. En effet, B00011111 = B 11111, de mme que 0502 = 502.

Pensez toujours complter les octets de faon obtenir 8 bits, car cest impos par la
plupart des assembleurs (nous verrons ce que cest dans la suite de ces leons).

Notez que la plus grande valeur pouvant tre reprsente par un octet est donc :
B11111111. Si vous faites la conversion (ou en utilisant la calculette de Windows en mode
scientifique), vous obtiendrez 255. Tout nombre suprieur 255 ncessite donc plus dun
octet pour tre reprsent.

Je vous donne une autre mthode simple pour convertir de dcimal en binaire, en
procdant de faon inverse, c'est--dire de la droite vers la gauche. La mthode consiste
crire le reste de la division par 2 du nombre.

12
Reprenons notre nombre 149 :

149 / 2 = 74 Reste 1
74 / 2 = 37 Reste 0
37 / 2 = 18 Reste 1
18/ 2 = 9 Reste 0
9/2 = 4 Reste 1
4 / 2 = 2 Reste 0
2 / 2 = 1 Reste 0
1 / 2 = 0 Reste 1

En reprenant tous les restes en commenant par le dernier (ou en remplissant de droite
gauche), nous obtenons B10010101, qui est bien la valeur trouve prcdemment. En
gnral la seconde mthode est plus simple pour ceux qui nont pas lhabitude de jongler avec
les puissances de 2, mais la premire est plus rapide effectuer mentalement si on acquiert de
lhabitude.

2.3 Le systme hexadcimal

La reprsentation de nombres binaires nest pas vidente grer, et crire une succession
de 1 et de 0 reprsente une grande source derreurs. Il fallait donc trouver une solution plus
pratique pour reprsenter les nombres binaires. On a donc dcid de couper chaque octet en 2
quartets et de reprsenter chaque partie par un chiffre.

Comme un quartet peut varier de b0000 b1111, on constate que lon obtient une
valeur comprise entre 0 et 15. Cela fait 16 combinaisons. Les 10 chiffres du systme dcimal
ne suffisaient donc pas pour coder ces valeurs.

Plutt que dinventer 6 nouveaux symboles, il a t dcid dutiliser les 6 premires


lettres de lalphabet en tant que chiffres. Ce systme de numration en base 16 a donc t
logiquement appel systme hexadcimal.

Notez que ce systme est simplement une reprsentation plus efficace des nombres
binaires, et donc que la conversion de lun lautre est instantane. Dans la suite de ces
leons, nous reprsenterons un nombre hexadcimal en le faisant prcder de 0x. Voyons si
vous avez bien compris :

13
Tableau de conversion des diffrents quartets (un demi octet)

Binaire Hexadcimal Dcimal


B0000 0x0 0
B0001 0x1 1
B0010 0x2 2
B0011 0x3 3
B0100 0x4 4
B0101 0x5 5
B0110 0x6 6
B0111 0x7 7
B1000 0x8 8
B1001 0x9 9
B1010 0xA 10
B1011 0xB 11
B1100 0xC 12
B1101 0xD 13
B1110 0xE 14
B1111 0xF 15

Pour reprsenter un octet il faut donc 2 digits hexadcimaux. Par exemple, notre nombre
B10010101 est reprsent en hexadcimal par 0x95. Si vous faites la conversion de
lhexadcimal vers le dcimal, vous utilisez le mme principe que prcdemment, et vous
obtenez 0x95 = 9*161 + 5*16 = 149, ce qui est heureux.

Pour preuve, quel est le plus grand nombre hexadcimal de 2 digits pouvant tre
reprsent ? Rponse : 0xFF, soit 15*16 + 15 = 255.

Si vous avez bien tout compris, vous tes maintenant capable de convertir nimporte quel
nombre de nimporte quelle base vers nimporte quelle autre. Vous trouverez galement dans
certaines revues, des allusions au systme octal, qui est un systme en base 8 qui a t
largement utilis par le pass, nettement moins aujourdhui.

2.4 Les oprations

Aprs avoir converti les nombres dans diffrents formats, vous allez voir quil est
galement trs simple de raliser des oprations sur ces nombres dans nimporte quel format.
Il suffit pour cela deffectuer les mmes procdures quen dcimal.

Petit exemple : Que vaut B1011 + B 1110 ? Et bien, on procde exactement de la


mme faon que pour une opration en dcimal.

B1011
+ B1110
--------------
?

14
- On additionne les chiffres de droite, et on obtient 1+0 = 1
- On crit 1
- On additionne 1 + 1 , on obtient 10 (2 nexiste pas en binaire). On crit 0 et on reporte 1
- On additionne 0+1+le report et on obtient 10. On crit 0 et on reporte 1
- On additionne 1+1+le report et on obtient 11. On crit 1 et on reporte 1
- Reste le report que lon crit, soit 1.

La rponse est donc B11001, soit 25.

Les 2 nombres de dpart tant B1011, soit 11, et B1110, soit 14. Vous procderez de
la mme manire pour les nombres hexadcimaux, en sachant que 0xF + 0x1 = 0x10, soit
15+1 = 16 (on crit 0 on reporte 1).

2.5 Les nombres signs

Dans certaines applications, il est ncessaire de pouvoir utiliser des nombres ngatifs.
Comme les processeurs ne comprennent pas le signe - , et comme il fallait limiter la taille
des mots 8 bits, la seule mthode trouve a t dintroduire le signe dans le nombre.

On a donc choisi (pas au hasard) le bit 7 pour reprsenter le signe. Dans les nombres
signs, un bit 7 1 signifie nombre ngatif. Si on stait content de cela, on aurait perdu
une valeur possible. En effet, B10000000 (-0) serait alors gal B00000000 (0). De plus,
pour des raisons de facilit de calcul, il a t dcid dutiliser une notation lgrement
diffrente.

Pour rendre un nombre ngatif, il faut procder en 2 tapes.

- On inverse la totalit du nombre.


- On ajoute 1

On obtient alors ce quon appelle le complment deux du nombre.

Exemple : soit le nombre 5 : B00000101 Comment crire 5 ?

- on inverse tous les bits (complment 1) B11111010


- on ajoute 1 (complment 2) 5 = B11111011

Pour faire la conversion inverse, on procde de faon identique.

On inverse tous les bits B00000100


On ajoute 1 B00000101

Et on retrouve notre 5 de dpart, ce qui est logique, vu que (-5) = 5.

Dans le cas des nombres signs, on obtient donc les nouvelles limites suivantes :
- La plus grande valeur est B01111111, soit +127
- La plus petite valeur devient B10000000, soit 128.

Remarquez que les oprations continuent de fonctionner. Prenons 3 + 5

15
B 11111101 (-3)
+ B 00000101 (5)
-----------------------------
= B100000010 (2)

Et l, me direz vous, a ne fait pas 2 ? Et bien si, regardez bien, il y a 9 bits , or le


processeur nen gre que 8. Le 9me bit est donc tomb dans un bit spcial que nous
verrons plus tard. Dans le registre du processeur, il reste donc les 8 bits de droite, soit 2, qui
est bien gal (3 )+ 5.

Maintenant, si vous avez bien suivi, vous tes en train de vous poser la question suivante :
Quand je vois B11111101, est-ce que cest 3 ou est-ce que cest 253 ? Et bien vous ne
pouvez pas le savoir sans connatre le contexte.

Sachez que les nombres signifient uniquement ce que le concepteur du programme a


dcid quils reprsentent. Sil travaille avec des nombres signs ou non, ou si cet octet
reprsente tout autre chose (une t, un caractre, etc). La seule chose qui importe cest de
respecter les conventions que vous vous tes fixes lors de la cration de cet octet. Cest
donc vous de dcider ce dont vous avez besoin pour tel type de donnes.

2.6 Les oprations boolennes.

Quest-ce que cest que a, me direz-vous ? Et bien, pour faire simple, disons que ce sont
des oprations qui seffectuent bit par bit sur un octet donn. Plutt quune grosse thorie sur
lalgbre de Boole (jen vois qui respirent), je vais donner dans le concret en prsentant les
oprations indispensables connatre dans la programmation des PIC et autres
microcontrleurs.

2.6.1 Le complment

Que vous trouverez galement sous les formes inversion ou NOT ou encore
complment 1. Il est souvent not ! Son fonctionnement tout simple consiste inverser
tous les bits de loctet (0 devient 1 et 1 devient 0).

Exemple : NOT B10001111 = B01110000.

Vous voyez ici que pour les oprations boolennes, il est plus facile de travailler en
binaire. Traduisez lexemple ci-dessus successivement en hexadcimal (on dira maintenant
hexa pour parler comme les pros ), puis en dcimal, et essayez de complmenter
directement. Bonjour les neurones.

A quoi sert cette opration ? Par exemple lire une valeur dont les niveaux actifs ont t
inverss, raliser des nombres ngatifs, ou autres que nous verrons par la suite.

2.6.2 La fonction ET ou AND

Appele galement multiplication bit bit, ou AND , et souvent note &

16
Elle consiste appliquer un mot sur un autre mot et multiplier chaque bit par le bit de
mme rang. Pour faire une opration ET , il faut donc toujours 2 octets.

Les diffrentes possibilits sont donnes ci-dessous (le tableau se lit horizontalement).

Premire ligne : 0 AND 0 = 0. Ce type de tableau sappelle table de vrit dite aussi
table de Karnaugh , du nom de son inventeur , Maurice Karnaugh.

bit1 bit2 AND


0 0 0
0 1 0
1 0 0
1 1 1

On voit donc que la seule possibilit pour obtenir un 1 est que le bit1 ET le bit2 soient
1 . Ceci correspond une multiplication. 1*1 = 1, 0*1 = 0, 1*0 = 0.

Exemple :

B11001100 AND B 11110000 = B11000000

A quoi sert cette instruction ? Et bien, elle est utilise pour masquer (cacher) des bits qui
ne nous intressent pas.

Prenez lexemple ci-dessus : Le 2me octet contient 4 bits 1 et 4 bits 0. Regardez le


rsultat obtenu : Les 4 premiers bits de loctet 1 sont conservs (1100), lemplacement des 4
autres nous trouvons des 0.

On peut donc laide de cette instruction forcer nimporte quel bit dun octet 0 sans
connatre son contenu prcdent. Cette instruction est commutative, c'est--dire que vous
obtenez le mme rsultat si vous inversez le premier octet et le second.

2.6.3 La fonction OU ou OR

Encore appele OR, souvent note | elle permet, comme son nom lindique, de
positionner un bit 1 si le bit1 OU le bit2 est 1 (ou les deux ensemble).

La table de vrit suivante explique le fonctionnement de cette fonction.

Bit1 Bit2 OR
0 0 0
0 1 1
1 0 1
1 1 1

Petit exemple B10001000 OR B11000000 = B11001000

A quoi sert cette instruction ? Et bien, tout simplement elle permet de forcer nimporte
quel bit dun octet 1 sans connatre son contenu prcdent.

17
Vous voyez que dans lexemple prcdent, les 2 premiers bits ont t forcs au niveau 1,
indpendamment de leur niveau prcdent. Cette opration est galement commutative.

2.6.4 La fonction OU EXCLUSIF ou Exclusif OR ou XOR

Voici la dernire fonction que nous allons aborder dans cette mise niveau. Elle est
souvent appele XOR (eXlusif OR). Elle se comporte comme la fonction OR, un dtail
prs.

Pour obtenir 1, il faut que le Bit1 soit 1 OU que le Bit2 soit 1 lEXCLUSION des
deux bits ensemble. Si les 2 bits sont 1, alors le rsultat sera 0.

Voici donc la table de vrit.

Bit1 Bit2 XOR


0 0 0
0 1 1
1 0 1
1 1 0

Petit exemple : B10001000 XOR B11000000 = B01001000

A quoi sert cette instruction ? Et bien tout simplement inverser nimporte quel bit
dun octet sans toucher aux autres. Dans lexemple prcdent, vous voyez qu
lemplacement des 2 bits 1 du 2me octet, les bits correspondants du 1er octet ont t inverss.

Voil, ainsi se termine le premier chapitre consacr aux PIC. Je sais quil tait
particulirement rbarbatif, mais, si vous ne matrisez pas parfaitement ce qui vient dtre
expliqu, vous ne pourrez pas raliser correctement vos propres programmes.

2.7 Un mot sur les units

Nous avons parl doctets et de bits. En informatique, on utilise couramment les


termes de Byte (Octet pour la France) et bit (binary unit) . Vous rencontrerez galement le
terme Mot . Un mot est un multiple de bits. Le terme mot doit donc prciser la taille
concerne, ou peut se rfrer implicitement la taille manipule par dfaut par le composant
(un processeur de 16 bits manipule de mots de 16 bits). Lorsque vous voyez ce terme, vrifiez
de quoi il sagit en fonction du contexte.

Les symboles courants utiliss sont :

Octet : B (pour byte, dans le monde) ou o ou O (pour octet, en France)


Bit : b

Les anglais sont obligs dutiliser le B Majuscule pour loctet, pour viter quon ne
confonde avec bit. La traductomania impose en France fait que ce pays est le seul avoir
adopt le symbole o pour octet . Par contre, vu que la France na pas ( ?) impos de
traduction pour bit , il ny a pas de confusion possible ce niveau.

18
Notez que ceci reste toutefois fort relatif, puisque lorganisme de validation des
symbole (le SI) a refus de valider une srie de symboles, et donc, lgalement :

B : est illicite parce que dj utilis pour dfinir le bel


b : galement illicite parce que dj utilis pour dfinir le barn
O : illicite parce que risque de confusion inacceptable avec le chiffre zro
o : ne correspond rien pour un anglophone et donc non officialis

Bref, la situation nest pas claire, il vous faudra vous rfrer ce que vous trouverez
dans les documents que vous lirez, qui adoptent en gnral les symboles tels que je viens de
vous les noncer.

Il nous reste cependant parler des multiples (kilo, mega etc), et l la situation se gte
rapidement. En effet, en base 10, notre base de tous les jours , on a dcid dadopter des
multiples de 3 de la puissance 10. Ainsi par exemple,

kilo (k) = 10 (seul symbole > 1 en minuscule, cause de la confusion avec Kelvin)
Mega (M) = 106
Giga (G) = 109
Tera (T) = 1012

Mais en travaillant en base 2, ces valeurs ne tombent pas juste , et 10 ne reprsente


en base 2 quun nombre parmi dautres (je vous laisse le convertir en binaire). Il fallait donc
pouvoir reprsenter des multiples qui soient particuliers. On a donc procd dans un
premier temps la rcupration pure et simple des termes utiliss en base 10 (Kilo, Mega
etc.), exactement comme on avait rcupr des lettres pour en faire des chiffres en
hexadcimal. On leur a cependant raffect des valeurs en exposant de 2 par multiple de 10.

Ainsi, on a dfini (ou plutt utilis arbitrairement durant des annes) :

kilo = 210
Mega = 220
Giga = 230
Tera = 240

De ce fait un kilooctet en informatique valait 210 octets, et donc 1024 octets, alors
quun kilogramme valait, lui, 1000 grammes. La situation empirait pour le Mega, puisque si
un Megaoctet valait 220 octets, et donc 1048576 octets, un Megagramme, lui, valait 1000000
grammes.

Les vendeurs de matriel de stockage de masse ont saut sur loccasion. Ainsi, eux ont
conserv lappellation originale (lgale) en puissance de 10, alors que tous les informaticiens
raisonnaient en puissance de 2. Ainsi, lorsquon achetait un disque dur de 100Mo (100
Megaoctets), il faisait bel et bien 100.000.000 octets. Les OS (Windows) renseignant le plus
souvent la taille en Mega informatique , ils traduisaient ds lors cette capacit en
(100.000.0000 / 220 ) = 95,4Megaoctets. Bref, 100 Megaoctets de constructeur de disque dur =
95,4 Megaoctets dinformaticien.

19
Il est clair que la situation ne pouvait perdurer. Dbut des annes 2000, on dcide donc
de rglementer tout a. Il tait clair ds lors quon serait contraint dinventer de nouveaux
termes, ce qui fut fait, le premier tant le kibi qui reprsente le multiple de base : 210. On
en arriva donc aux conventions suivantes :

Kibi (Ki) 210 1024 1,024k (on retrouve la majuscule dans Ki)
Mbi(Mi) 220 1048576 1,048586 M
Gibi (Gi) 230 1073741824 1,073741824 G
Tbi (Ti) 240 1099511627776 1,099511627776 T
Pebi (Pi) 250 1125899906842624 1,125899906842624 P
Exbi (Ei) 260 1152921504606846976
Zebi (Zi) 270 1180591620717411303424
Yobi (Yi) 280 1208925819614629174706176

Ainsi poses les nouvelles conventions, il nexistait dornavant plus dambigut sur
les termes utiliss. On devrait donc retrouver en informatique les termes Ki, Mi etc, au lieu de
k, M La situation relle est loin de ressembler a, et la grande majorit des ouvrages
informatiques et des logiciels continuent utiliser les kilo pour des puissances de 2, avec
parfois mme le K en majuscule (KB). A vous dtre attentif cette situation, qui mettra
probablement des annes se rgulariser.

Notez quand mme quil y a plus de 20% de diffrence entre un Yobi (280) et un Yotta
24
(10 ), plus on monte dans les grandeurs moins la diffrence devient anecdotique.

Donc, un 210 octets, cest maintenant un KiB pour le monde, et un Kio pour la France.
230 bits, cest maintenant un Gib pour tout le monde.

Notez que votre intrt vous cest la fois de comprendre votre interlocuteur
lorsquil fait mauvais usage de la terminologie, tout en employant vous-mme les termes
corrects.

Au passage, essayez de ne pas confondre le Gibi avec une marque de Wisky clbre,
ce serait mauvais pour vos neurones ainsi que pour vos rapports avec votre employeur.

20
3. Composition et fonctionnement des PIC

Enfin quelque chose de plus intressant. Nous allons maintenant nous pencher sur un
PIC, et en particulier sur le PIC16F84. Rassurez-vous, tout ce que nous verrons sur le
16F84 pourra tre directement utilis sur les autres PIC16Fxxx, qui ne sont rien dautre que
des PIC16F84 amliors. Chaque PIC dispose des fonctionnalits des modles infrieurs,
augmentes de nouvelles fonctions. Au moment de passer la rvision 13 du cours, les
modles que vous rencontrerez seront probablement des PIC16F84A, mais a ne posera
aucun problme pour ltude de ce cours, les diffrences ne sont quhardwares.

Tout dabord, vous devez tlcharger le datasheet du PIC16F84, car cest un document
que nous allons utiliser dans le reste de ces petites leons. Je vous conseille vivement de
limprimer, car vous en aurez toujours besoin quand vous vous lancerez dans la ralisation de
vos propres programmes.

Ces datasheets sont mes livres de chevet. Jai trouv plus judicieux de travailler par la
pratique et de les commenter dans lordre utile, plutt que de les traduire btement .

3.1 Quest-ce quun PIC ?

Un PIC nest rien dautre quun microcontrleur, cest dire une unit de traitement
de linformation de type microprocesseur laquelle on a ajout des priphriques internes de
communication avec lextrieur permettant de raliser des montages sans ncessiter lajout de
composants externes, ou du moins avec un nombre restreint de composants.

La dnomination PIC est sous copyright de Microchip, donc les autres fabricants sont
dans limpossibilit dutiliser ce terme pour leurs propres microcontrleurs. Un PIC est
donc un microcontrleur de marque Microchip.

Les PIC sont des composants dits RISC (Reduced Instructions Set Computer), ou
encore composant jeu dinstructions rduit. Pourquoi ? Et bien, sachez que plus on rduit le
nombre dinstructions, plus facile et plus rapide en est le dcodage, et plus vite le composant
fonctionne.

Vous aurez devin quon trouve sur le march 2 familles opposes, les RISC et les CISC
(Complex Instructions Set Computer). Sur les CISC, on dispose de moins de vitesse de
traitement, mais les instructions sont plus complexes, plus puissantes, et donc plus
nombreuses. Il sagit donc dun choix de stratgie.

Tous les PIC Mid-Range ont un jeu de 35 instructions, stockent chaque instruction
dans un seul mot de programme, et excutent chaque instruction (sauf les sauts) en 1 cycle.
On atteint donc des trs grandes vitesses, et les instructions sont de plus trs rapidement
assimiles. Lexcution en un seul cycle est typique des composants RISC.

Lhorloge fournie au PIC est prdivise par 4 au niveau de celui-ci. Cest cette base de
temps qui donne la dure dun cycle. Si on utilise par exemple un quartz de 4MHz , on
obtient donc 1000000 de cycles/seconde, or, comme le PIC excute pratiquement 1

21
instruction par cycle, hormis les sauts, cela vous donne une puissance de lordre de 1MIPS (1
Million dInstructions Par Seconde).

Pensez que les PIC peuvent monter plusieurs dizaines de MHz, selon la famille et le
type. Cest donc une vitesse de traitement plus quhonorable.

3.2 Les diffrentes familles des PIC

La famille des PIC 8 bits (qui manipulent des donnes 8 bits en une seule opration)
tait subdivise au moment dcrire la rvision 1 de cet ouvrage en 3 grandes familles :

- La famille Base-Line, qui utilise des mots dinstructions (nous verrons ce que cest) de 12
bits pour certains PIC (12C508), de 14 pour dautres (12F675),

- La famille Mid-Range, qui utilise des mots dinstruction de 14 bits (et dont font partie les
16F84 et 16F876).

- La famille High-End, qui utilise des mots dinstruction de 16 bits et qui est dcrite dans le
cours-part5.

Par la suite, dautres familles sont apparues, comme la Enhanced family, les PIC10F et
les choses ne devraient faire quvoluer. Nous trouvons aussi des PIC 16 bits, dont certains
incluent un DSP (Digital Signal Processor), et des 32 bits. En outre, pour chaque famille de
nouveaux modles et de nouvelles fonctionnalits apparaissent sans cesse, il vous incombe
donc, une fois votre apprentissage termin, de consulter le site de Microchip pour choisir le
modle convenant le mieux votre application particulire.

Nous nous limiterons dans les 4 premiers ouvrages (cours-part1 cours-part4) la famille
Mid-Range. Louvrage que vous tes en train de lire vous enseigne les bases ncessaires, en
utilisant le plus simple des PIC16F, le PIC16F84.

Le cours-part5 vous mettra sur la piste de la plus puissante famille en 8 bits, la famille
High-End. Lorsque vous aurez tout compris, vous aurez toutes les bases ncessaires pour
passer dautres familles, et mme dautres types de microcontrleurs.

Notez ds prsent que le datasheet du 16F84 nest quune petite partie de la


documentation complte. Pour obtenir la documentation complte, vous ajoutez encore plus
de 600 pages en tlchargeant 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 dun fichier par chapitre. Jai pour ma
part presque tout imprim, mais je vous conseille plutt daller les chercher le jour o vous en
aurez besoin. Ce document comporte des informations supplmentaires pointues, surtout au
niveau lectronique.

22
3.3 Identification dun PIC

Pour identifier un PIC, vous utiliserez simplement son numro.


Les 2 premiers chiffres indiquent la catgorie du PIC, 16 indique un PIC Mid-Range.

Vient ensuite parfois une lettre L : Celle-ci indique que le PIC peut fonctionner avec une
plage de tension beaucoup plus tolrante (par exemple 3V).

Ensuite, vous trouvez une des possibilits suivantes :

C indique que la mmoire programme est une EPROM ou plus rarement une EEPROM
CR pour indiquer une mmoire de type ROM
Ou F pour indiquer une mmoire de type FLASH.

Notez ce niveau que seule une mmoire FLASH ou EEPROM est susceptible dtre
efface, donc nesprez pas reprogrammer vos PIC de type CR. Pour les versions C,
voyez le datasheet. Le 16C84 peut tre reprogramm, il sagit dune mmoire eeprom. Le
12C508, par exemple, possde une mmoire programme EPROM, donc effaable uniquement
par exposition aux ultraviolets. Donc, leffacement ncessite une fentre transparente sur le
chip, qui est une version spciale pour le dveloppement, et non la version couramment
rencontre.

Un composant quon ne peut reprogrammer est appel O.T.P. pour One Time
Programming : composant programmation unique. Puis vous constatez que les derniers
chiffres identifient prcisment le PIC. (84)

Finalement vous verrez sur les botiers le suffixe -XX dans lequel XX reprsente la
frquence dhorloge maximale que le PIC peut recevoir. Par exemple 04 pour un 4MHz.
En fait, il semble bien que cette donne soit purement commerciale et que tous les PIC dun
mme modle acceptent de tourner la vitesse maximale de ce modle, vitesse donne en
dbut du datasheet. Cette inscription semble donc dans la ralit des faits parfaitement inutile.
Cette information nengage pas ma responsabilit, vous de juger et de vous renseigner. De
toutes faons, pour un projet commercial et afin dviter toute poursuite, je vous conseille de
respecter la limite inscrite. Pour vos propres projets, vous de voir.

Donc, un 16F84-04 est un PIC Mid-Range (16) donc la mmoire programme est de
type FLASH (F) donc rinscriptible de type 84 et capable daccepter une frquence dhorloge
de 4MHz en thorie (probablement : 10Mhz pour un 16F84 et 20Mhz pour un 16F84A).

Une dernire indication que vous trouverez est le type de botier. Nous utiliserons pour
nos exprience le botier PDIP, qui est un botier DIL 18 broches, avec un cartement entre
les ranges de 0.3 (troit). La version 4MHz sera amplement suffisante.

Microchip fait voluer ses rfrences, il y a maintenant dautres mentions, vous de


vrifier si besoin est quoi elles correspondent.

Notez ds prsent que les PIC sont des composants statiques, cest dire que la
frquence dhorloge peut tre abaisse jusqu larrt complet sans perte de donnes et sans
dysfonctionnement.

23
Ceci par opposition aux composants dynamiques (comme les microprocesseurs de votre
ordinateur ou la RAM de celui-ci), dont la frquence dhorloge doit rester dans des limites
prcises. Nessayez donc pas de faire tourner votre PIII/500 166MHz, car cest un
composant dynamique. Par contre, vous pouvez faire tourner votre PIC16F84-04 1Khz sans
aucun souci, et mme moins si vous en avez lusage, en allant mme jusqu le stopper (sans
couper lalimentation).

Donc, si vous voulez passer commande pour le PIC que nous allons utiliser dans le reste
de cet ouvrage, demandez donc un PIC 16F84A-xx en botier PDIP (xx quelconque) . Cet
ouvrage a t crit du temps du 16F84, qui est maintenant remplac par le 16F84A. Jai
conserv le terme original dans le cours, les diffrences se limitent quelques amliorations
hardwares (plus rapides entre autres). Je conserve donc le terme 16F84 pour indiquer
indiffremment un 16F84 ou un 16F84A.

3.4 Organisation du 16F84

La mmoire du 16F84 est divise en 3 parties. Page 4 du datasheet, vous trouverez la


table 1-1 qui donne un aperu de la famille 16F8X. Les numros de pages peuvent varier en
fonction des mises jour de Microchip. Vous devrez peut-tre chercher un peu, ou alors
utilisez le datasheet que je fournis avec le cours.

Pour ceux qui veulent tout comprendre, la figure 3-1 de la page 8 montre lorganisation
interne dun 16F84.

3.4.1 La mmoire programme

La mmoire programme est constitue de 1Ki mots de 14 bits. Cest dans cette zone que
vous allez crire votre programme. Ceci explique pourquoi vos fichiers sur PC font 2Kio
(Kibioctets) car il faut 2 octets pour coder un mot de 14 bits. Ceci explique galement
pourquoi, lorsque vous lisez un PIC vierge, vous allez lire des 0x3FFF. Cela donne en
binaire B0011111111111111, soit 14 bits utiles. Jexpliquerai plus loin do proviennent ces
fameux 14 bits.

Notez ce point quune instruction est code sur 1 mot. Donc, 1Ki mots donne 1 bon
millier dinstructions possibles pour votre programme (ce nest dj pas si mal). Quand vous
en serez crire des programmes de 1Ki, vous serez sans aucun doute autonome pour vos
applications.

3.4.2 La mmoire Eeprom

La mmoire EEPROM (Electrical Erasable Programmable Read Only Memory), est


constitue de 64 octets que vous pouvez lire et crire depuis votre programme. Ces octets sont
conservs aprs une coupure de courant et sont trs utiles pour conserver des paramtres
semi-permanents. Leur utilisation implique une procdure spciale que nous verrons par la
suite, car ce nest pas de la RAM, mais bien une ROM de type spcial. Il est donc plus rapide
de la lire que dy crire. Si vous programmez souvent des eeproms (2416) vous aurez constat
dj ce phnomne.

24
3.4.3 La mmoire Ram

La mmoire RAM (Random Access Memory) est celle que nous allons sans cesse
utiliser. Toutes les donnes qui y sont stockes sont perdues lors dune coupure de tension.

La mmoire RAM est organise en 2 banques pour le 16F84. La RAM est subdivise de
plus en deux parties. Dans chacune des banques nous allons trouver des cases mmoires
spciales appeles registres spciaux ou SFR (Special Function Registers) ainsi que des
cases mmoires libres dont vous pouvez vous servir votre guise.

Les SFR servent donc configurer des options de votre PIC, alors que les autres
emplacements servent ranger vos variables (nous verrons de quoi il en retourne).

Pour le cas du 16F84, vous disposerez de 68 octets libres. Lorganisation de la RAM est
montre dans le tableau 4-2 page 13. Vous voyez la sparation verticale en 2 banques, et tout
en bas vous voyez deux banques de 68 octets de RAM.

Malheureusement, lindication mapped in bank 0 vous indique quaccder ces 68


octets depuis la banque 0 ou la banque 1 donne en fait accs la mme case mmoire.

Vous voyez dans la partie suprieure le nom de tous les registres spciaux utiliss dans le
PIC. Nous les verrons tous, rassurez-vous.

Chaque registre provoque un fonctionnement spcial du PIC ou la mise en service dune


fonction particulire. Vous remarquerez enfin que certains registres sont identiques dans les 2
banques (FSR par exemple). Cela signifie quy accder depuis la banque 0 ou 1 ne fait pas de
diffrence.

Remarquez que la banque 0 utilise les adresses de 0x00 0x7F, la banque 1 allant de 0x80
0xFF. Les zones en gris sont des emplacements non utiliss (et non utilisables).
Lemplacement 0x00 est un emplacement auquel on ne peut pas accder.

Pour la grande majorit des registres, chaque bit a une fonction spciale. Page 14, tableau
4-1, vous trouverez les noms des bits utiliss dans ces registres.

25
Notes :

26
4. Organisation des instructions
4.1 Gnralits

Allez, courage, cela devient de plus en plus concret. On va faire un petit survol du jeu
dinstructions des PIC. On saute directement page 55 du datasheet, au chapitre 9. Eh oui,
comme cet ouvrage nest pas un manuel de rfrence technique, mais un apprentissage, il faut
voir les chapitres du datasheet dans le dsordre.

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

4.2 Les types dinstructions

Vous constaterez donc quil existe 4 types dinstructions, que nous allons dcrire.
Vous navez cependant pas retenir la faon dont sont organises les instructions, il sagit
simplement de vous permettre de comprendre comment a se passe.

4.2.1 Les instructions orientes octet

Ce sont des instructions qui manipulent les donnes sous forme doctets. Elles sont
codes de la manire suivante :

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

- 1 bit de destination(d) : 0 indique que le rsultat de lopration sera plac dans le registre
de travail W (Work), 1 indique que ce rsultat sera palc dans loprande prcise dans les
7 bits suivants

- 7 bits pour encoder loprande (File) : Si d vaut 1 (voir ci-dessus), cette oprande
renseigne la fois la donne manipuler et galement lendroit o le rsultat sera stock.

Aie, premier problme, 7 bits ne donnent pas accs la mmoire RAM totale, donc
voici ici lexplication de la division de la RAM en deux banques. En effet, il faut 8 bits pour
accder 256 emplacements diffrents.

Il faudra bien trouver une solution pour remplacer le bit manquant. Vous avez dit un bit
dun des registres ? BRAVO, je vois que vous avez tout compris. Il sagit en ralit du bit
RP0 du registre STATUS.

Ah, vous avez remarqu quil y a un RP1? Et oui, le 16F876, par exemple, dispose de 4
banques, ce bit sera de fait utilis pour certains autres PIC que nous verrons dans la seconde
partie. Vous veillerez laisser RP1 0 pour le 16F84, afin de pouvoir porter votre
programme sans problme vers un PIC suprieur.

27
4.2.2 Les instructions orientes bits

Ce sont des instructions qui manipulent les donnes sous forme de bits. Autrement dit,
elles sont destines modifier des bits prcis dun registre spcifi. Elles sont codes de la
manire suivante :

- 4 bits pour linstruction (dans lespace rest libre par les instructions prcdentes)

- 3 bits pour indiquer le numro du bit manipuler (bit 0 7 possible), et de nouveau :

- 7 bits pour indiquer loprande.

4.2.3 Les instructions gnrales

Ce sont les instructions qui manipulent des donnes qui sont codes dans linstruction
directement. Nous verrons ceci plus en dtail lorsque nous parlerons des modes dadressage.
Elles sont codes de la manire suivante :

- 6 bits pour coder linstruction

- 8 bits pour coder la valeur concerne (valeur dite immdiate parce que se trouvant
immdiatement dans linstruction). La valeur peut de fait varier de 0 255.

4.2.4 Les sauts et appels de sous-routines

Ce sont les instructions qui provoquent une rupture dans la squence de droulement
du programme. Elles sont codes de la manire suivante :

- 3 bits pour coder linstruction

- 11 bits pour coder ladresse de la destination

Nous pouvons dj en dduire que les sauts ne donnent accs qu 2Ki de mmoire
programme (211). Ceci ne pose aucun problme, le 16F84 ne disposant que de 1K mots de
mmoire. Pour coder une adresse de saut lintrieur de la mmoire programme dun 16F84,
il faut donc 10 bits (210 = 1024 = 1Ki).

Noubliez pas que la rglementation officielle veut quon utilise le terme de kilobinary
ou kibi , abrg en Ki pour exprimer 2 la puissance 10. Il semble malheureusement
que bien peu de monde ne lutilise en pratique.

4.3 Panoramique des instructions

Je vais maintenant vous montrer comment fonctionne le tableau de la figure 9-2 page 56.
Ce tableau vous permet dun simple regard de vous informer de la manire dont fonctionne
chaque instruction

28
La premire colonne indique le mnmonique et les oprandes pour chaque opration.
Les mnmoniques sont des mots rservs (donc que vous ne pouvez utiliser que pour cet
usage, et non pour nommer une variable, par exemple), qui sont compris et interprts par le
programme dassemblage, dnomm Assembleur .

Notez ici la confusion de langage commune pour le terme assembleur , quon utilise
la fois pour indiquer le programme qui permet dassembler le code (programme
dassemblage), et le langage utilis dans lditeur (langage dassemblage). Essayez dutiliser
les bons termes, la situation en informatique nest dj pas toujours trs simple sans quon ny
ajoute des confusions inutiles. Dire je programme en assembleur , a ne veut en fait rien
dire, mme si tout le monde vous comprend. Vous devez dire je programme en langage
dassemblage .

Lassembleur, cest le programme qui assemble votre programme crit en langage


dassemblage.

Vous allez donc trouver cet emplacement les instructions proprement dites que vous
allez pouvoir encoder dans votre programme.

La syntaxe doit tre la suivante pour lassembleur MPASM (lassembleur fourni avec
lenvironnement de dveloppement intgr MPLAB), que nous utiliserons ds la prochaine
leon. Nous avons dans lordre pour chaque ligne de code :

- Etiquette (facultative ou pouvant se trouver seule sur une ligne)


- Espace(s) ou tabulation(s)
- Mnmonique (en majuscules ou minuscules)
- Tabulation ou Espace(s)
- Oprande ou la valeur
- Virgule ventuelle de sparation
- Bit de destination W ou F ou ventuellement numro du bit de 0 7 si ncessaire
- Espace(s) ou tabulation(s) (facultatif)
- Commentaire prcd du point-virgule. (facultatif)

Notez que le mnmonique ne peut pas se trouver en premire colonne, et que tout ce
qui suit le point-virgule est ignor par lassembleur (donc cest de la zone commentaire).

La premire colonne est rserve pour les tiquettes (repres).

Vous disposez galement de la possibilit dinsrer un ou plusieurs espace(s) ou


tabulation(s) de chaque ct de la virgule.

Voici titre dexemple deux lignes valides, les mots en bleu sont des mots rservs. Celui
en rouge est un nom de registre SFR. Les commentaires sont en italique. Les instructions
peuvent tre crites en minuscules ou en majuscules.

Ma_ligne ; Ceci est une tiquette

MOVF STATUS,W ; charge le registre status dans le registre de travail

Pour en terminer avec notre tableau :


- La seconde colonne du tableau donne un bref descriptif de linstruction.

29
- La troisime colonne donne le nombre de cycles ncessaires pour excuter linstruction.
Notez que toutes les instructions ncessitent un seul cycle, sauf les sauts qui en
ncessitent 2 (inclus les oprations de test avec saut, lorsque le rsultat du test engendre le
saut : instructions notes 1(2)).

La 4me colonne donne ce quon appelle l OPCODE, cest dire le mot binaire que
MPASM va gnrer pour vous au dpart du mnmonique.

Vous ne vous en servirez donc pas, mais sachez que vous pourriez programmer
directement le PIC sans passer par un assembleur, directement en construisant un fichier
.hex et en entrant les valeurs trouves ici.

Vous devriez alors tout calculer, y compris les sauts. Cest ce que jai fait mes dbuts sur
un processeur 6502, car je ne disposais pas dun assembleur. On pouvait galement utiliser
cette technique pour construire des programmes auto-modifis pour cause de limitation svre
de la taille mmoire.

Rassurez-vous, ces techniques appartiennent maintenant au Moyen-ge de linformatique.


Tout au plus pouvez-vous mettre en corrlation les valeurs prsentes ici avec les valeurs du
tableau 9-1 titre ducatif. Sinon, oubliez cette colonne.

La 5me colonne, par contre, est primordiale, car elle donne les indicateurs dtat
(Status Flag) affects (modifis) une fois linstruction effectue. Nous verrons ces indicateurs
en dtail, car ils constituent une cl indispensable de la programmation. En fait, ces
indicateurs dtat sont les moyens de prendre une dcision dans un programme
(conditions).

La dernire colonne renvoie des notes en bas de page. La note 1 est trs importante, elle
fait allusion la mthode lecture/modification/criture propre aux ports dentres/sortie
(I/O). Nous y reviendrons au moment de la mise en uvre des PORTS.

La note 2 indique quune modification dun timer remet zro son prdiviseur. Nous y
reviendrons en abordant le timer 0.

La troisime note indique que si vous vous servez de linstruction pour modifier le
compteur de programme (celui qui pointe sur la prochaine instruction excuter), il y aura un
cycle supplmentaire. Cest logique car cela quivaut un saut. Nous verrons que cette
technique est pratique pour aller chercher des valeurs dans une table construite en mmoire
programme.

4.4 Les indicateurs dtat

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


ncessaire davoir 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
traits lors de ltude du registre STATUS (chapitre 8.2.3).

30
4.4.1 Lindicateur dtat Z

Cest lindicateur Zro, il fonctionne de la manire suivante :

Si le rsultat dune instruction pour lequel ce bit est affect donne un rsultat gal
0, le flag Zro passe 1.

Donc, ne vous mlangez pas les pinceaux . Dire si Z = 1 correspond dire si


rsultat = 0 . Le tableau 9-2, colonne 5 vous indique les instructions qui modifient Z.

Donc, si vous faites une addition avec ADDWF et que le rsultat obtenu est 0, le bit Z
sera forc 1. Si le rsultat est != 0 (diffrent de 0), le bit Z vaudra 0. Dans les 2 cas il est
modifi.

Par contre, si vous stockez une valeur avec linstruction MOVWF, le bit Z ne sera pas
modifi, mme si la valeur vaut 0. Ces remarques sont valables pour les autres flags, donc je
ny reviendrai pas.

4.4.2 Lindicateur dtat C

Cest lindicateur pour Carry (report). Si le rsultat dune opration entrane un


dbordement, le bit C sera positionn 1. Il sagit en fait du 9me bit de lopration.
Petit exemple :

Si vous ajoutez B11111110 (254)


+ B00000011 (3)
Vous obtenez B100000001, (257) donc 9 bits.

Comme les registres du PIC ne font que 8 bits, vous obtiendrez B00000001 (1) et C
positionn 1 (en fait le 9me bit, donc le bit 8, donc 28 = 256). Donc le rsultat final est de
256 + 1 = 257.

Remarquez que si vous aviez ajout B11111110 et B00000010, vous auriez obtenu
B00000000.

Dans ce cas, vous auriez eu C = 1 et Z = 1, ce qui signifie rsultat nul, mais avec report
(donc rsultat = 256).

Attention, ce bit sert aussi de borrow (emprunt) lorsque vous effectuez une soustraction.
Dans ce cas C vaut 0 si vous tentez de soustraire un nombre plus grand que le le nombre de
dpart, indiquant ainsi un rsultat ngatif. Dans le cas contraire, C vaudra 1 (rsultat nul ou
positif). C fonctionne donc de faon un peu inverse dans le cas des soustractions, nous
tudierons en dtail ces instructions.

Nous verrons les autres bits du registre dtat dans la suite de cet ouvrage, au moment o
la ncessit se fera sentir.

31
Notes :

32
5. Les dbuts avec MPLAB

Nous allons maintenant dmarrer la grande aventure avec notre tout premier et modeste
programme. Jexpliquerai les instructions et les registres au fur et mesure de leur utilisation.
A partir de la rvision 13 du cours, nous travaillons avec MPLAB 6.x, qui est la version qui
succde la version 5.x utilise dans le cours jusque la rvision 12.

5.1 Prparation lutilisation

La premire chose faire est daller chercher la version actuelle de MPLAB 6.60 sur le
site Microchip : http://www.Microchip.com section archives . Vous pouvez galement
utiliser une version plus rcente (8.x), mais vous de vous dbrouiller avec les diffrences. Je
vous conseille plutt dtudier avec la version 6.6 et de passer une version rcente une fois
votre apprentissage termin, ce qui vous vitera de cumuler les difficults.

Attention, MPLAB-X est une version spcifique de MPLAB, qui dispose de pas mal
de diffrences avec les versions classiques. Cette version prsente lavantage dtre
compatible avec dautres OS, notamment Linux.

. Dans ce cours, les copies dcrans ont t faites avec MPLAB 6.3, mais les diffrences
devraient tre minimes avec la 6.6 (plus stable). Si vous utilisez une version plus rcente de
MPLAB et que celui-ci vous pose la question de savoir quel type de code vous voulez
produire, choisissez toujours ABSOLUTE .

Dcompactez le fichier et procdez son installation. Lors de linstallation, vous aurez


plusieurs fentres explicatives concernant diffrents outils de Microchip, comme le
debugger et le simulateur. Comme je prsume que vous navez pas (encore) ces outils, fermez
toutes ces fentres en fin dinstallation.

Personnellement, je naime pas laisser les donnes dans les rpertoires dinstallation de
mes programmes, dans la partition principale. Si vous tes comme moi, crez un rpertoire
dans un endroit o vous rangez vos data et appelez-le, par exemple DataPIC.

Copiez y le fichier m16F84.asm fourni avec le cours. Cest un fichier que jai cr afin de
pouvoir dmarrer instantanment un nouveau programme. Je lai appel m16f84.asm ,
avec m pour maquette . Si vous navez pas ce fichier cest que vous avez tlcharg le
cours un endroit incorrect, rendez-vous sur mon site : www.bigonoff.org pour tlcharger
une version correcte, rcente et complte (gratuitement).

Si vous ne dsirez pas crer un nouveau rpertoire, copiez ce fichier dans le rpertoire
dinstallation : par dfaut c:\program files\MPLAB IDE. Mais je rappelle que sauver ses
donnes dans la partition contenant les programmes est une trs mauvaise ide, surtout en cas
de plantage de votre OS (la restauration craserait vos donnes).

Pour chaque nouveau programme que vous allez crer, faites un copier/coller du fichier
m16F84.asm. Pour notre premier programme, copiez/collez ce fichier et renommez la
copie obtenue en Essai1.asm.

33
5.2 Cration de notre premier projet

Vous pouvez maintenant lancer MPLAB IDE partir du menu dmarrer ou de licne
de votre bureau, si vous en avez accept linstallation. Aprs quelques instants, vous vous
retrouvez avec un cran vide avec menu et barres doutils. Sil y a des fentres ouvertes dans
le bureau de MPLAB 6, fermez-les toutes, ainsi vous saurez comment les rouvrir, et tout le
monde dbutera avec la mme configuration.

MPLAB est un logiciel qui est construit sur la notion de projets. Un projet permet de
mmoriser tout lenvironnement de travail ncessaire la construction dun . projet. Il vous
permettra de rtablir tout votre environnement de travail lorsque vous le slectionnerez.

MPLAB 6 dispose dun wizard (assistant) pour la cration des projets, qui vous
permet den crer automatiquement de nouveaux. Cependant, afin de vous permettre de
localiser les principales options des projets, je ne men servirai pas dans ce petit tutorial. Si
par la suite vous dsirez lutiliser, il se slectionne laide du menu project->wizard

Allez dans le menu Project et slectionnez new . La fentre qui souvre vous
permet dintroduire le nom du projet et le rpertoire de travail du dit projet. Pour le rpertoire,
vous disposez du bouton browser qui vous permet de pointer sur le bon rpertoire sans
risque de vous tromper.

Entrez essai1 comme nom de votre nouveau projet, et slectionnez le rpertoire dans
lequel vous avez plac votre fichier maquette et votre fichier essai1.asm. Jai nomm le
fichier asm de faon identique au projet, mais ce nest nullement obligatoire.

Une fois le bouton <OK> press, une nouvelle fentre apparat dans le coin suprieur
gauche du bureau de MPLAB IDE.

34
Dans cette fentre, vous voyez le nom de votre projet (essai1.mcp), ainsi que les
fichiers lis celui-ci. Pour linstant, vous nen avez aucun, cest normal.

Nous allons commencer prciser les paramtres importants de notre projet, et tout
dabord le type de PIC que nous allons utiliser. Slectionner le menu configure->select
device , une fentre apparat pour vous proposer le choix du PIC. Notez que par dfaut,
Microchip vous propose un PIC de la famille 18F, promotion de nouveau produit oblige
Slectionnez le PIC16F84 (si vous choisissez PIC16F84A, modifiez toutes les rfrences au
PIC16F84 dans tous les fichiers source utiliss : cest cependant inutile)

35
La fentre vous montre alors, laide de leds vertes ou rouges quels outils sont
supports par le PIC slectionn. Vous voyez donc que le simulateur intgr (MPLAB
SIM) fonctionne avec ce PIC, et ainsi de mme pour les autres outils de dveloppement
disponibles chez Microchip. Une fois cliqu <OK>, la fentre se referme.

Nous allons maintenant prciser quel langage nous allons utiliser, sachant que nous
travaillons en langage dassemblage, mais que diffrents assembleur/compilateurs sont
proposs par Microchip et dautres socits. Slectionnez le menu project -> Select
langage toolsuite . Dans la fentre qui souvre, slectionnez dans le menu droulant :
Microchip MPASM toolsuite . MPASM est en effet lassembleur par dfaut de
Microchip.

Dans les fentres infrieures, vous voyez le nom des excutables utiliss par MPASM,
ne vous en proccupez pas. Cliquez <OK> pour fermer la fentre.

Il nous faut maintenant indiquer MPASM quel est notre ou nos fichiers source(s). Ceci
seffectue dans la fentre essai1.mcw qui est reste ouverte dans le coin suprieur gauche.
Pour ajouter un fichier source, cest trs simple : cliquez avec le bouton droit sur source
files , puis slectionnez Add . Une fois slectionn le fichier, le nom de celui-ci apparat
dans larborescence. Notez que MPLAB pointe par dfaut sur votre rpertoire de travail,
prcdemment choisi.

36
Ici, il est important de bien comprendre que le fichier source choisi sera celui qui sera
assembl (ou compil si vous utilisez un autre langage). Autrement dit, si dans ce fichier se
trouve une instruction include qui inclut un autre fichier, vous ne devez pas le slectionner
en supplment, il sera joint au projet au moment de lassemblage.

Par contre, si vous dsirez assembler simultanment deux fichiers, et que votre premier
fichier ne fait pas rfrence au second, alors vous devez ajouter ce fichier larborescence.

Tous nos projets ne ncessiteront dajouter quun seul fichier. Si votre projet ncessite un
ou plusieurs fichier(s) supplmentaire(s), la directive include sera ajoute au fichier source
afin que lassembleur intgre automatiquement ce ou ces autre(s) fichier(s).

Vous navez besoin de rien dautre, les autres lments de larborescence ne sont pas
ncessaires pour un projet en langage dassemblage du type dont nous allons parler.

Il nous reste un lment important prciser, celui du systme de numration utilis


par dfaut. Slectionnez le menu : Project -> build options -> project . Une fentre
souvre.

Slectionnez longlet MPASM assembler .

37
Comme nous avons dcid de numroter lhexadcimal sous la forme 0x, et le binaire
sous la forme B. Tout nombre sans prfixe sera considr comme dcimal. Cochez donc
la case Decimal . Ne touchez pas aux autres options, vous les utiliserez peut-tre lorsque
vous serez devenus un pro et que vous voudrez adapter certains paramtres. A ce moment,
leur rle vous semblera clair.

Afin dviter tout oubli, je vous conseille cependant de toujours placer un prfixe
devant vos nombres, ceci vous vitera bien des dboires. Utilisez par exemple les syntaxes
suivantes :

0x10, H10, ou 10h : notations hexadcimales


B00010000 : notation binaire
D16 : notation dcimale
.16 : autre notation dcimale (noubliez pas le . )

Un nombre crit sans prfixe sera interprt selon le paramtre prcdemment


dcrit, et donc risque de poser problme si vous intgrez votre fichier dans un autre
projet, ou, simplement, si vous communiquez autrui votre fichier source sans prciser
la notation par dfaut.

38
Si, cependant, vous prfrez utiliser un prfixe par dfaut, signalez-le dans vos
fichiers sources laide de la directive radix, comme par exemple :

radix dec ; on travaille en dcimal par dfaut

Cette directive supplante le choix fait dans MPLAB, et donc votre fichier fonctionnera
correctement quel que soit la configuration de MPLAB et donc chez tous ceux qui vont
assembler votre fichier. Cette directive ne peut pas se trouver en premire colonne, placez un
espace ou une tabulation devant le terme radix .

Maintenant, MPASM est prt assembler votre programme. Mais, allez-vous me


dire, il ny a toujours rien lcran !

Effectivement, MPASM ne se proccupe pas des fichiers affichs lcran, seuls


comptent le fichier inscrit dans larborescence et les fichiers inclus partir de ce fichier.

Vous pouvez avoir autant de fichiers que vous voulez sur lcran, ou ne pas en avoir du
tout. MPLAB sen moque. Par contre, tous les fichiers ouverts lors de la sauvegarde de
votre projet seront automatiquement rouverts lors de la prochaine ouverture du projet, mme
sils ne servent rien. Cette proprit est pratique pour faire des copier/coller partir dun
autre fichier ou pour voir tout en programmant ce quun autre a bien pu faire.

Bien entendu, nous allons afficher notre fichier source, pour voir ce quil contient. La
mthode la plus simple est de double-cliquer sur son nom dans larborescence de la fentre
essai1.mcw. Faites-le. Voici votre fichier de dpart ouvert. Mettez-le la taille approprie en
lui faisant occuper la moiti gauche de lcran si vous manquez de place (vous naurez plus
besoin de fentre du projet, vous pouvez la masquer ou la rduire).

Pour ouvrir un fichier qui nest pas inclus dans larborescence, utilisez le menu file-
>open ou licne douverture dans la barre doutils.

Si vous voulez que vos crans ressemblent au mien, changez la police de lditeur.
Pour ceci, slectionnez Edit -> properties , puis longlet text . Ensuite, un clic sur le
bouton Select font vous permettra de choisir la police de caractres : Courier New
de style Standard et dimposer une taille de 9 .

Pour ceux que a intresse, je travaille sur un moniteur 22 pouces, et ma rsolution est de
1680 X 1050, a vous indique les proportions. Vrifiez galement dans longlet Tabs que
la longueur de la tabulation est fixe 4 ( size sur MPLAB >7.5). Au besoin, modifiez-
la.

Votre fichier asm est maintenant affich lcran. Notez pour ceux qui viennent de
MPLAB 5 que la gestion des tabulations est diffrente sur MPLAB 5 et MPLAB 6, ce
qui signifie que les mises en page dun fichier crit sur MPLAB 5 ne seront plus respectes
lors du passage MPLAB 6. Jai donc modifi tous les fichiers en consquence. Ceux qui
disposent de la version prcdente ont intrt utiliser les nouveaux fichiers.

39
Pour ceux qui viennent de MPLAB 5, vous constatez que MPLAB 6 est plus
simple manipuler, ceci va encore plus se confirmer lorsque nous verrons le simulateur.

Nous allons maintenant examiner ce fichier dun peu plus prs.

40
6. Organisation dun fichier .asm

Tout dabord, cliquez nimporte o lintrieur de ce fichier. Vous tes lintrieur dun
simple diteur de texte avec colorisation syntaxique. Dans le coin infrieur gauche, vous
verrez un numro de ligne et de colonne. Cest la position actuelle de votre curseur. Je me
servirai de cette position pour vous guider au travers du fichier. Najoutez donc pas de lignes
pour linstant, pour garder la correspondance correcte avec ce texte. Si vous ne voyez pas de
numro de lignes, allez dans le menu edit -> properties et cochez line numbers dans
longlet editor

Si vous narrivez pas effectuer des modifications dans votre fichier, et que votre clavier
semble inactif (rencontr avec MPLAB 5.x), cest que vous avez utilis un caractre tendu
dans le nom de votre fichier. Au contraire de MPLAB 5, MPLAB 6 gre maintenant tous
les caractres tendus, pour les fichiers et pour les dossiers.

6.1 Les commentaires

De la ligne 1 la ligne 31 vous voyez un grand cadre. Si vous regardez attentivement le


premier caractre de chaque ligne, vous verrez le symbole ; . Tout ce qui suit tant
considr comme zone de commentaire, vous pouvez y mettre tout ce que vous voudrez.

Prenez lhabitude de toujours commenter vos programmes. Soyez sr que dans 6 mois,
vous ne vous rappellerez plus de tout ce que vous avez voulu faire, les commentaires vous
seront alors dune grande utilit si vous dcidez de modifier votre programme. Et je passe le
cas o, comme moi, vous distribuez vos sources ou que vous travaillez dans une bote o
dautres sont amens les relire.

Remplissons donc le cadre en indiquant les diffrentes rfrences. Je joins avec cette
leon le fichier essai1.asm , qui reprend le fichier tel quil sera la fin de cette leon.

6.2 Les directives

A la ligne 34, nous trouvons une directive destine MPASM pour lui indiquer quel
type de processeur est utilis dans ce programme.

Les directives ne font pas partie du programme, elles ne sont pas traduites en
OPCODES, elles servent indiquer lassembleur de quelle manire il doit travailler.
Ce sont donc des commandes destines lassembleur lui-mme.

Au contraire, les instructions seront traduites en OPCODES et charges dans le PIC.


Il est donc impratif de bien faire la distinction.

La ligne 36 contient du reste une directive dont nous avons dj parl, qui indique
MPASM que chaque fois que nous ne prcisons aucun prfixe pour un nombre, que ce
nombre doit tre considr comme tant en reprsentation dcimale.

41
6.3 les fichiers include

La ligne 35 signale lassembleur, , via la directive #include , quil doit charger cet
endroit prcis le contenu du fichier P16F84.inc (MPASM effectue un simple copi/coll
pour sa copie de travail interne). Que contient ce fichier ? Et bien tout simplement la valeur de
toutes les constantes que nous allons utiliser.

Pour voir ce quil contient, allez dans le menu file ->Open , choisissez all source
files dans le cadre infrieur, et ouvrez p16F84.inc. dans le rpertoire
C:\Program Files\MPLAB IDE\MCHIP_Tools pour MPLAB 6 et
C:\Program Files\Microchip\MPASM Suite pour MPLAB 7

Une fois dpasse la zone de commentaires, vous y verrez des lignes du style :

FSR EQU H'04'

Cette ligne, incluant la directive EQU signifie tout simplement que FSR est EGAL
0x04. Autrement dit, lorsque vous utiliserez le mot FSR dans une instruction, MPASM
remplacera simplement FSR par H04 (0x04). 04 tant simplement ladresse du registre FSR
dans la mmoire RAM du PIC.

H04 est une autre mthode autorise pour exprimer un nombre hexadcimal, tout comme
04h. Notez que le prfixe est toujours prcis, car Microchip ne peut savoir davance quel
systme de numration vous utilisez par dfaut dans votre programme.

Si vous prenez votre tableau 4-2 page 13, vous constaterez que cest bien le cas. Ce
fichier est donc principalement destin vous viter davoir mmoriser toutes les adresses,
un nom est bien plus simple utiliser et retenir quune adresse. Fermez le fichier p16F84.inc
pour ne pas encombrer votre fentre.

6.4 La directive _CONFIG

La ligne suivante, commence par __CONFIG . Cette ligne contient les fameux
fusibles , pour reprendre une expression populaire, qui fixent le fonctionnement du PIC.

Les valeurs crites ici seront intgres dans le fichier .hex pour signaler au
programmateur les valeurs encoder aux adresses spcifiques du PIC. Nous y reviendrons.

Sachez donc que si un fichier .hex a t cr par un programmeur attentif qui a


utilis cette directive, vous naurez nul besoin de dfinir ces paramtres au moment de la
programmation. Le logiciel du programmateur ira normalement chercher ces valeurs dans le
fichier lui-mme.

Malheureusement, on trouve nombre de personnes qui pensent que cette directive,


commentaires, et autres facilits sont rserver aux dbutants et ne les utilisent pas. Cest une
grossire erreur ! Je reois rgulirement du courrier de personnes qui ont estim cette
procdure inutile, et qui se sont trompes par la suite. Si vous nutilisez pas la directive
__CONFIG , vous serez contraints de plus dindiquer explicitement chaque utilisateur de
vos fichiers .hex de quelle faon ils doivent configurer ces bits de configuration au niveau

42
de leur programmateur de PIC. Et vous-mme devrez vous en souvenir chaque fois que vous
programmerez un PIC avec votre fichier. Avouez que cest plutt barbare comme
mthode.

Jai plac dans le fichier toutes les valeurs possibles de ces paramtres, avec les
explications correspondantes. Il suffit de remplacer une des valeurs par celle souhaite.

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 diffrentes valeurs sont lies par le symbole & (AND)
expliqu dans la leon sur les systmes de numrations. __CONFIG fonctionne donc en
plaant des bits 0 , si vous avez tout suivi. Donc, attention de toujours bien prciser tous
les paramtres, mme ceux que vous nutilisez pas.

Les valeurs correspondantes sont de nouveau dans le fichier P16F84.INC . Donc, pas
de magie, tout sexplique en rflchissant un peu.

6.5 Les assignations

Aux lignes 58 et 63, vous trouverez des assignations personnelles qui fonctionnent selon
le mme 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. Dans le monde du travail, la facilit de maintenance dune application est une
des priorits principales dun projet, pour la bonne raison que cette maintenance un cot.

Les assignations se comportent comme de simples substitutions de textes. Au moment de


lassemblage, chaque fois que lassembleur va trouver une assignation, il la remplacera
automatiquement par sa valeur.

Un autre avantage est que si vous remplacez la valeur dune assignation, le changement
sera effectif pour tout le programme. Vous ne risquez donc pas doublier des valeurs en
chemin.

Je vous encourage vivement utiliser les assignations ainsi que les autres mthodes que
nous allons voir plus bas. La syntaxe est simple puisquil sagit de EQU (gal ). Le symbole
= fonctionne galement.

Exemple dassignation :

mavaleur EQU 0x05

43
6.6 Les dfinitions

Descendons encore un peu. Nous dcouvrons, lignes 73 75 des exemples de lutilisation


de la directive #DEFINE . Sachez que les dfinitions fonctionnent comme des
assignations, ceci prs que nous rserverons les assignations pour les valeurs, et les
dfinitions pour substituer un texte plus complexe.

Par exemple nous pourrons utiliser un PORT suivi dun numro de bit, ou bien carrment
une instruction avec ses paramtres.

Une dfinition est construite de la manire suivante : La directive #DEFINE, suivie par le
nom que lon dsire utiliser, puis la chane substituer. Par exemple :

#DEFINE monbit PORTA,1

Lutilisation de cette dfinition seffectue tout simplement en utilisant son nom dans le
programme. Par exemple :
bsf monbit ; mettre monbit 1

Sera traduit par MPLAB comme suit :

bsf PORTA,1 ; mettre monbit 1

6.7 Les macros

Plus bas, lignes 83 86, nous trouvons une macro.

LIREIN macro
comf PORTB,0
andlw 1
endm

La macro se compose dun nom crit en premire 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 dfinie par la directive endm ) (end of macro).

On en dduit quune macro remplace un bloc de code que nous utilisons souvent. La
macro fonctionne galement uniquement comme un simple traitement de texte. Si vous
utilisez 10 fois la macro dans votre code, le bloc de code y sera recopi 10 fois.

Dans notre exemple, chaque fois que la macro LIREIN sera rencontre, elle sera
remplace au moment de lassemblage par les 2 lignes :

comf PORTB , 0
andlw 1

La macro simplifie donc lcriture, mais ne raccourcit pas la taille du fichier .hex obtenu,
puisque les 2 lignes seront crites dans le PIC.

44
Notez que lon peut utiliser des macros plus complexes, avec passage de paramtres. Cest
mme un des intrts principaux des macros. Nous nentrerons pas dans ces fonctions
particulires pour linstant.

Notez galement que vous disposez dune aide dans le menu help->MPASM Help .
En effet, laide de MPLAB concerne lutilisation du logiciel. Les aides concernant le
langage sont dans MPASM, puisque cest ce langage que MPLAB utilise (revoyez au
besoin ldition des nuds).

6.8 La zone des variables

Toute zone dfinie par lutilisateur comme dclarant des variables commence avec la
directive CBLOCK, suivie par ladresse du dbut de la zone.

Pour placer nos variables, qui sont des emplacements mmoires 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 ; dbut de la zone variables

Ensuite, vous pouvez utiliser 68 emplacements mmoire, qui rpondront la syntaxe


suivante : nom de la variable suivi du signe : (les espaces sont ignors) suivi de la taille
utilise.

Par exemple :

w_temp : 1 ; Zone de 1 byte


montableau : 8 ; zone de 8 bytes

Ensuite, vous devrez prciser la fin de la zone en cours laide de la directive ENDC :

ENDC ; Fin de la zone

6.9 Les tiquettes

Vous trouverez dans les programmes en 1ere colonne ce que nous appellerons des
tiquettes. Ce sont des noms que vous choisissez et qui ne sont rien dautre que des repres
pour MPASM, ces repres pouvant tre utiliss tels quels directement dans votre code
source.

Lassembleur les remplacera par ladresse du programme lendroit o elles sont


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

45
6.10 La directive ORG

La directive ORG, suivie de ladresse, prcise quelle adresse linstruction suivante sera
place dans la mmoire programme du PIC. dfaut de cette prcision, chaque instruction est
place ladresse suivant directement linstruction prcdente.

Il est important de savoir 2 choses :

Aprs un reset ou une mise sous tension, le PIC dmarre toujours ladresse 0x00.
Le dbut de votre programme doit donc se situer l.

Ladresse 0x04 est ladresse utilise par les interruptions (nous verrons le principe plus
tard). Il ne vous reste donc pas grand place pour placer votre programme (entre 0x00 et 0x03).
Nous commencerons donc par un saut vers lemplacement du programme principal o nous
aurons plus de place. Allons donc voir ligne 104 comment tout ceci fonctionne :

org 0x000 ; Adresse de dpart aprs reset


goto init ; Adresse 0: initialiser

La premire ligne est notre directive ORG, qui indique que la ligne suivante sera place
ladresse 0x00.

La seconde ligne est une instruction, explique page 62, qui indique au PIC que le
programme doit sauter ladresse init pour y excuter la suite du programme. init est
donc une tiquette.

Aprs le reset, le PIC excute donc linstruction goto init qui se trouve ladresse 0x00,
suivie par linstruction qui se trouve ladresse init plus bas dans le programme (donc juste
en dessous de ltiquette init).

6.11 La directive END et la fin dun programme

Cette directive prcise lendroit o doit cesser lassemblage de votre programme. Elle est
obligatoire dans tout programme, sous peine dune erreur qui vous signalera que la fin de
fichier (End Of File) a t atteinte avant de rencontrer la directive END.

Toutes les instructions situes aprs la directive END seront tout simplement ignores. Il
ne sagit pas dune instruction destine stopper le PIC, mais dune directive destine
stopper le travail de MPASM cet endroit. Dit de faon explicite :

END ne signifie nullement que le PIC va sarrter cet endroit !

Partant de l, si vous crivez un programme se terminant comme ceci :

Instruction x
Instruction y
END

Et si nous imaginons que instruction x se trouve ladresse 0x50 (par exemple), vous
trouverez ceci dans votre mmoire flash :

46
Adresse 0x50 : instruction x assemble
Adresse 0x51 : instruction y assemble
Adresse 0x52 : 0x3FFF (mmoire flash vide = 14 bits 1)
Adresse 0x53 : 0x3FFF (idem)
..

Aucune trace de votre end , puisquil sagit dune directive. Autrement dit, votre pic,
une fois linstruction y excute ne va pas sarrter, il va excuter linstruction dont le code
hexadcimal vaut 0x3FFF. Et cette instruction existe, il sagit de addlw 0xFF . Donc, votre
pic va btement excuter des addlw 0xFF jusqu la fin de la mmoire programme.
Une fois arriv la fin, il ne va pas sarrter non plus, il va simplement incrmenter son
compteur de programme, qui va dborder et donc revenir 0x00. Votre programme va alors
sexcuter une nouvelle fois (avec les registres ventuellement modifis suite au passage
prcdent, ne sagissant pas dun reset).

Si vous voulez stopper votre programme aprs une seule excution, il faut le bloquer dans
une boucle. Soit si vous ne voulez pas placer votre pic en veille par :

boucle
goto boucle

Soit si vous pouvez le mettre en veille, par :

boucle
sleep
goto boucle

La boucle tant alors une scurit en cas de rveil du pic suite un parasite ou le dbordement
du watchdog. Donc, noubliez pas : END ne veut pas dire arrt .

Je suis dsol davoir si lourdement insist ce niveau, mais je continue de rencontrer


des programmes envoys par des internautes qui stonnent du comportement curieux de leur
programme qui na en fait pas de fin, ceux-ci pensant quune fois le end rencontr, le
PIC ne fait plus rien.

47
Notes :

48
7. Ralisation dun programme

7.1 Cration de notre premier programme

Avant de lancer notre premier programme, nous allons procder quelques modifications
du fichier essai1.asm , afin de ne conserver que ce qui nous intresse. Premirement, allez
ligne 105 (le numro peut tre diffrent chez vous) et remplacez la ligne

goto init
par
goto start.

Ne faites pas de faute dorthographe.

goto start ; Adresse 0: dmarrer

Descendez ensuite en ligne 226, vous trouverez l notre tiquette start, cest donc l que
notre programme va sauter. Effacez ensuite la ligne

clrwdt ; effacer watch dog

Rassurez-vous, nous verrons tout ceci par la suite.

Il reste donc une instruction que nous avons dj vue, linstruction goto .

goto start ; boucler

Le datasheet, page 62, nous apprend que linstruction goto est suivie dune valeur
immdiate (cest dire une valeur sous forme dun nombre), code sur 11 bits (rappelez-
vous, le programme peut faire 1Ki mots, donc, avec 11 bits, on peut sauter nimporte o dans
la mmoire programme.

La valeur peut bien sr tre remplace par une tiquette, MPASM se chargeant pour
vous de calculer son emplacement. Le datasheet vous indique aussi quil sagit dun saut
inconditionnel, cest dire quil seffectuera toujours, sans condition. Il est rappel quun
saut prend 2 cycles.

Faisons de la place sous ltiquette start, et ajoutons la ligne suivante (attention, pas en
premire colonne) :

clrf mavariable ; effacer mavariable

CLRF est une instruction dtaille dans le chapitre ddicac aux instructions. Il y est dit
que lemplacement mmoire prcis derrire linstruction (ou une variable) est effac. Le bit
Z est positionn 1 ou 0 selon le rsultat de lopration, comme dj expliqu.

Mais comme le but de lopration est de mettre la variable 0, le bit Z vaudra toujours 1
aprs cette instruction. Notez que lemplacement mmoire peut se situer de 0 127 (0x7F).
Cest logique : si vous consultez le tableau 4-2, vous voyez que la RAM sarrte au 127me
emplacement pour chacune des 2 banques.

49
Placez ensuite une tiquette (premire colonne) que vous appellerez boucle. Sous cette
tiquette, ajoutez linstruction :

boucle
INCF mavariable,f

Cette instruction est explique galement dans le chapitre relatif aux instructions. Vous
voyez que cette instruction incrmente (+1) le contenu de la variable mavariable, et que le
rsultat de lopration est plac dans lemplacement d. Pour toutes les instructions, d peut
valoir soit f , dans ce cas le rsultat est stock dans la variable en question, soit w , dans
ce cas le rsultat est plac dans le registre de travail, et la variable nest pas modifie.

Vous voyez galement que le bit Z du registre SFR STATUS est affect par lopration.
Je rappelle une dernire fois : si le rsultat de lincrmentation donne 0, Z sera mis 1. Il
sera mis 0 dans tous les autres cas (pour une instruction modifiant Z, videment).

Pour terminer, remplacez

goto start
par
goto boucle

Le programme doit toujours se terminer par la DIRECTIVE END .Vous devriez


donc vous retrouver avec ceci :

start
clrf mavariable ; effacer mavariable
boucle
incf mavariable,f ; incrmenter mavariable
goto boucle ; boucler
END ; directive fin de programme

7.2 Lassemblage dun programme

Lassemblage dun projet peut seffectuer de 2 faons. Soit on assemble uniquement le


fichier slectionn avec <F10>, soit on assemble tous les fichiers de larborescence en
pressant <CTRL> + <F10>. Etant donn que nous navons quun seul fichier dans
larborescence, nous utiliserons <F10>

Nous allons maintenant tenter dassembler ce programme pour en faire un fichier .hex.
Pressez la touche F10 , des fentres souvrent, MPLAB passe les commandes
MPASM qui tente dassembler notre programme.

Lassemblage sarrte en chemin, une barre rouge apparat et nous nous retrouvons
une nouvelle fentre (output ) qui contient les rsultats de sortie de la commande. Si vous
rencontrez un problme non prvu (erreur 173 par exemple) jetez un oeil en fin de cours, dans
les annexes.

50
Deleting intermediary files... done.
Executing: "C:\Program Files\MPLAB IDE\MCHIP_Tools\mpasmwin.exe" /q /p16F84 "Essai1.asm"
/l"Essai1.lst" /e"Essai1.err" /rDEC
Message[302] D:\DATAPIC\ESSAI1.ASM 199 : Register in operand not in bank 0. Ensure that bank bits
are correct.
Message[302] D:\DATAPIC\ESSAI1.ASM 215 : Register in operand not in bank 0. Ensure that bank bits
are correct.
Error[113] D:\DATAPIC\ESSAI1.ASM 227 : Symbol not previously defined (mavariable)
Error[113] D:\DATAPIC\ESSAI1.ASM 229 : Symbol not previously defined (mavariable)
Halting build on first failure as requested.

Que sest-il pass ? Et bien, examinons le rapport construit. Vous voyez dabord des
messages (warning). Ce sont des messages destins attirer votre attention, mais qui ne
gnrent pas dimpossibilit dassemblage. Noubliez pas quil y a toute une partie du
programme qui ne sert rien dans notre exemple, mais qui est tout de mme crite (au dessus
de ltiquette start). Nous mettrons cette partie en pratique dans les chapitres suivants.

Le problme vient videmment des lignes error . Il y est dit que le symbole
mavariable na pas t dfini par lutilisateur. Cette erreur se retrouve dans les 2 lignes
o nous avons utilis notre variable. En fait, nous avons oubli de la dclarer . Pour
remdier cela, fermons la fentre des messages derreurs, et retournons dans notre diteur.

Faisons de la place sous la ligne 97, dans la zone des variables. Ajoutons alors

mavariable : 1 ; je dclare ma variable

Vous vous retrouvez donc avec ceci :

CBLOCK 0x00C ; dbut de la zone variables


w_temp :1 ; Zone de 1 byte
status_temp : 1 ; zone de 1 byte
mavariable : 1 ; je dclare ma variable
ENDC ; Fin de la zone

Relanons lassemblage en pressant sur <F10>.

Cette fois, tout sest bien pass, lindicateur est rest vert, et, aprs les warnings, nous
obtenons la phrase :

BUILD SUCCEEDED: construction acheve avec succs.

Nous venons de construire notre premier programme, et nous avons dj appris 3 des 35
instructions que comporte le PIC. Qui a dit que ctait compliqu ?

Notez au passage que la dclaration de mavariable nen est pas une au sens o on
lentend dans un langage volu (C par exemple). En fait cette dclaration ne rserve
rien du tout, neffectue aucun travail et na dautre effet que dassigner une adresse
(valeur) la variable en question.

51
Sachant que w_temp se trouve ladresse RAM 0x0C (puisque CBLOCK renseigne cette
adresse), et quon a dclar 1 octet, status_temp se trouve donc ladresse 0x0D et
mavariable ladresse 0x0E. Vous auriez pu tout aussi bien crire, plutt que de placer
mavariable dans la zone CBLOCK :

mavariable EQU 0x0E

ou

#DEFINE mavariable 0x0E

Alors, pourquoi utiliser CBLOCK ? Tout simplement parce que les calculs sont
effectus automatiquement, sans risque derreur, et quune modification vous assure de
ne pas devoir tout recalculer. Il y a dautres raisons pour ceux qui dveloppent des
programmes objet, mais ceci sort du cadre de ce cours.

Je vous conseille donc vivement de toujours utiliser la directive CBLOCK plutt


que de vous amuser (chacun son truc) calculer vous-mmes toutes les adresses de toutes
vos variables.

Vous pouvez maintenant laisser la fentre de sortie ouverte, la fermer ou la minimiser.


Sortons de notre programme, et confirmez les demandes de sauvegarde.

Je vous conseille de toujours sauver rgulirement votre fichier source lorsque vous
effectuez des modifications, laide du raccourci <Ctrl> + s . Ceci vous vitera de perdre
votre travail en cas de plantage de votre machine ou simplement de panne de courant.

Allez voir maintenant dans votre rpertoire de travail, et vous devriez y trouver 7 fichiers
gnrs par votre application du type essai1.xxx

Remarquez surtout lexistence de votre premier fichier .hex. Le fichier tel quil devrait
tre la fin de ce chapitre, est disponible dans les fichiers dexemples, comme tous les autres
crs par la suite.

52
8. La simulation dun programme

Nous avons cr, dans le chapitre prcdent, notre premier petit programme en 16F84.
Bien sr, ce programme ne sert strictement rien. Cependant nous allons lutiliser en vue
dexprimenter le simulateur de MPLAB. Une fois ce chapitre vu, vous serez en mesure
de :

- Crer et modifier un projet


- Assembler votre programme
- Le faire tourner sur simulateur pour le dbuguer

8.1 Lancement et paramtrage du simulateur

Commencez donc par lancer MPLAB. Ce dernier connat le nom de votre dernier projet
(essai1.mcp) et louvre automatiquement. Si vous avez procd des essais personnels
depuis, chargez-le depuis le menu project->open . Vous vous retrouvez avec la fentre de
votre dernire leon.

Rappelez-vous que si vous avez un problme, le fichier essai1.asm est disponible dans
les fichiers dexemples fournis avec ce cours. Rappelez-vous alors de lancer lassemblage par
la touche <F10>.

Lintrt dun simulateur est de visualiser le fonctionnement du programme, nous allons


donc signaler MPLAB ce que nous dsirons observer. Slectionnons dabord la mise en
service du simulateur de MPLAB.

Slectionnez le menu : Debugger -> select tool -> MPLAB Sim . Cest tout. De
nouveaux outils apparaissent dans la barre doutils. Notez aussi lapparition de nouveaux
items dans le menu debugger

Si ce nest dj fait, placez la fentre du fichier source fond vers la gauche. Nous
allons donc faire apparatre lcran les informations surveiller. Slectionnez View ->
Special function registers . Une nouvelle fentre souvre. Agrandissez-la et placez la
droite de la fentre du fichier source (ou ailleurs si vous manquez de place).

Vous voyez dans cette fentre le contenu de tous les registres que vous avez dcouverts
dans le tableau 4-2 de la page 13. Dans les chapitres suivants, nous les utiliserons
progressivement tous ces registres.

Dans notre petit programme, nous utilisons une variable. Nous allons donc la faire
apparatre. Allez dans le menu View -> watch . Une nouvelle fentre apparat. Vous
disposez de 4 onglets pour y placer 4 sries de variables, cest trs pratique pour dbuguer.

Pour visualiser une variable, vous disposez de plusieurs mthodes.

- Vous double-cliquez dans la case situe juste sous symbol name et vous tapez le nom
de la variable. Si la variable nexiste pas, la mention not found apparat dans la
colonne value , dans le cas contraire, cest la valeur actuelle qui apparat.

53
- Vous double-cliquez dans la case juste sous la colonne Add.. (adresse), et vous entrez
manuellement ladresse (dans ce cas-ci, 0x00E, vous entrez donc E )

- Vous slectionnez le nom dans le fichier source, puis vous cliquez une fois sur la slection
obtenue, et vous tirez la variable vers la fentre Watch en maintenant le bouton
enfonc. Une fois au-dessus, relchez le bouton de la souris ( Drag and drop ).

Pour supprimer une variable, il suffit de la slectionner et de presser <Del>.

Votre environnement ressemble maintenant ceci :

Notez quau dmarrage, MPLAB suppose que la valeur de votre variable vaut
0 , ce qui nest pas forcment le cas rellement dans le PIC, puisque la RAM prend
une valeur alatoire lors dune procdure de mise sous tension. Ceci peut occasionner de
svres surprises pour ceux qui oublient dinitialiser leurs variables : En effet, le
programme peut fort bien fonctionner sur simulateur (variable initialise 0) mais pas
rellement dans le PIC (variable contenant une valeur alatoire).

Cliquez avec le bouton droit de la souris, puis properties pour indiquer le style
daffichage des valeurs, soit 8 bits et format hexadcimal, mais ceci devrait tre fait par
dfaut.

54
Pressez ensuite sur <OK> pour fermer cette fentre.

8.2 Explication des registres fondamentaux

Vous voici prt lancer une simulation. Mais quoi cela pourrait-il vous servir si vous ne
comprenez pas les changements qui vont soprer dans les registres spciaux ? Je vais donc
commencer par vous expliquer les registres de base ncessaires la comprhension du
processus.

8.2.1 Les registres PCL et PCLATH

Un processeur au sens de cet ouvrage est un composant qui excute squentiellement


une srie dinstructions organises selon un ensemble appel programme .

Il existe donc dans le processeur un squenceur, cest dire un compteur qui permet de
pointer sur la prochaine instruction excuter. Ce squenceur est appel suivant les
processeurs compteur ordinal , pointeur de programme etc. Dans le cas des PIC, il
sappelle officiellement PC, pour Program Counter. Notez que le PC est un registre qui nest
pas accessible directement par lutilisateur.

Le principe de base est toujours le mme. Dans les PIC16F, les registres ne font que 8
bits, on ne peut donc stocker quune adresse maximale de 255. Il faudra donc 2 registres pour
accder une adresse. Ces PIC ont un fonctionnement un peu particulier ce sujet.

55
Nous trouvons tout dabord un registre qui contient ladresse basse du PC, cest dire les
8 bits de poids faibles. Ce registre est accessible en lecture et en criture. Il est appel PCL
(Program Counter Low)

Il existe un autre registre dont 5 bits seulement sont utiles et qui participe au
fonctionnement du squenceur. Il sappelle PCLATH (Program Counter LATch High). Il est
galement accessible en lecture et en criture par lutilisateur.

Le PC complet tant cod sur 13 bits, il faudra donc complter PCL avec 5 bits
supplmentaires pour pointer sur une adresse complte en mmoire programme. Il existe deux
cas possibles :

- Lors dun saut, par exemple, le contenu du PC est charg directement avec les 11 bits de
destination contenus dans linstruction en elle-mme. Les 2 bits manquants sont extraits
du registre PCLATH via ses bits 3 et 4. Ces bits, qui doivent tre positionns par
lutilisateur, sont placs directement dans les bits 11 et 12 du PC afin de complter
ladresse de destination. Comme le 16F84 ne gre que 1Ki mots de mmoire programme,
nous naurons pas besoin de ce registre dans le cas des sauts. Rappelez-vous que le 16F84
ne gre que 10 des 13 bits du PC. Attention que ce ne sera pas vrai lors de ltude du
16F876, par exemple (voir cours-part2).

- En cas de modification du PCL directement par lutilisateur, comme pour un registre


ordinaire, PCL est charg dans PC et complts par les 5 bits du registre PCLATH.
Comme le 16F84 ne traite que 1Ki mots de mmoire programme, les bits b2, b3 et b4 de
PCLATH seront inutiliss ici. Les bits 0 et 1 de PCLATH complteront donc les 8 bits de
PCL pour former une adresse complte sur 10 bits.

Remarquez que la limite du PC est de 13 bits, ce qui implique que les PIC de la famille
mid-range auront une capacit de mmoire programme de 8Ki mots maximum (soit 213).

Il est trs important de se rappeler que le PC pointe toujours sur linstruction


suivante, donc linstruction qui nest pas encore excute. Cest indispensable de bien
comprendre ceci pour analyser les programmes en cours de debuggage.

8.2.2 Le registre W

Ce registre est un registre utilis par les PIC pour raliser toutes sortes de calculs.
Souvenez-vous que la destination dun rsultat (d) peut en gnral tre un emplacement RAM
(f) ou le registre de travail (w). Cest donc un registre fondamental. Dans les 16F, ce registre
nest pas directement accessible. Cest diffrent pour dautres PIC, comme les PIC18F (cours-
part5).

8.2.3 Le registre STATUS

Cest un registre dont chaque bit a une signification particulire. Il est principalement
utilis pour tout ce qui concerne les tests. Il est donc galement dune importance
fondamentale. Il est dcrit dans le tableau de la page 15.

56
Voici les diffrents bits qui le composent, en commenant par le bit0 (b0), donc le bit le
plus droite, ou encore le moins significatif. Remarquez quon utilise le terme LSB, parfois
comme byte le moins significatif, parfois comme bit le moins significatif. Cest galement un
abus de langage, mais le contexte permet trs bien de les distinguer.

b0 : C Carry (report) Ce bit est en fait le 9me bit dune opration.


Par exemple, si une addition de 2 octets donne une valeur >255
(0xFF), ce bit sera positionn 1. Cest galement lemprunt lorsque
lopration est une soustraction, auquel cas il est positionn si le rsultat
de la soustraction nest pas ngatif.
.
b1 : DC Digit Carry Ce bit est utilis principalement lorsque lon travaille avec
des nombres BCD : il indique un report du bit 3 vers le bit 4.
Pour info, un nombre BCD est un nombre dont chaque
quartet reprsente un chiffre dcimal. Nous naborderons
pas ce principe ici.

b2 : Z Zro Ce bit est positionn 1 si le rsultat de la dernire


opration vaut 0. Rappelez-vous cependant que ces flags ne
sont positionns que pour les instructions qui le prcisent
(Status bit affected).

b3 : PD Power Down Indique quel vnement a entran le dernier arrt du PIC


(instruction sleep ou dpassement du temps du watchdog).
Nous y reviendrons plus tard. En ralit, vous verrez que PD
est surmont dune petite barre qui signifie : actif ltat
bas. Donc que 0 = bit valid. Comme je narrive pas avec ce
traitement de textes crire ces petites barres, jcrirai les
inversions en mode barr lorsque ce sera utile de le prciser

b4 : TO Time-Out bit Ce bit indique (si 0), que la mise en service suit un arrt
provoqu par un dpassement de temps ou une mise en
sommeil. Dans ce cas, PD effectue la distinction.

b5 : RP0 Register Bank Select0 Permet dindiquer dans quelle banque de RAM on
travaille.0 = banque 0.

b6 : RP1 Register Bank Select1 Permet la slection des banques 2 et 3. Inutilis pour le
16F84, doit tre laiss 0 pour garantir la compatibilit
ascendante (portabilit du programme).

b7 : IRP Indirect RP Permet de dcider quelle banque on adresse dans le cas


de ladressage indirect (que nous verrons plus tard).

8.3 Lancement de la simulation

Et voil, vous connaissez maintenant 4 des registres. Nous allons pouvoir commencer
simuler notre programme.

57
Contrairement MPLAB 5, il ny a pas besoin de slectionner la fentre source pour les
commandes de simulateur, elles sont toujours actives quelle que soit la fentre slectionne
lintrieur de MPLAB. Si ce nest pas fait, pressez <F10> pour assembler,

Puis pressez <F6>, la ligne :

goto start ; Adresse 0: initialiser

Est maintenant indique par une flche verte. La flche verte indique la prochaine ligne
qui sera excute par le simulateur. Vous avez en fait provoqu un reset de votre programme.

Au lieu dutiliser les touches clavier (plus pratiques), vous pouvez galement utiliser les
outils de la barre doutils ou les items du menu debugger . La correspondance est la
suivante :

<F6> : reset
<F7> : step into (avancer dun pas dans le programme)
<F8> : step over (idem, mais un appel de sous-programme est excut en une fois au lieu
dentrer lintrieur).

Rappelez-vous que le reset provoque le dmarrage ladresse 0x00. Vrifions donc :

- Au dessus de la ligne slectionne, vous trouvez la directive ORG 0x00 qui prcise
que la ligne suivante est ladresse 0x00 : premier bon signe.

- Ensuite, examinons PCL et PCLATH, tous deux 0 : Donc, la prochaine instruction


excute sera celle situe ladresse 0x00. Cest tout bon.

Examinons la ligne en question. Elle nous dit que la prochaine instruction, aprs son
excution, sera celle situe ladresse start .

Pressez <F7>. Votre programme est maintenant positionn sur la ligne qui suit ltiquette
start . Il a donc effectu un saut, ou encore une rupture de squence.

start
clrf mavariable ; effacer mavariable

Rappelez-vous qu ce stade, linstruction nest pas encore excute.


PCL vaut maintenant :

PCL 34 52 00110100, soit 0x34 ou 52 dcimal, ou encore B00110100

MPASM a donc calcul tout seul quel emplacement se situe ltiquette start . Si
vous aviez voulu indiquer ladresse vous-mme, vous auriez d compter toutes les lignes
prcdentes pour voir o vous en tiez. De plus, chaque modification du programme, vous
devriez recalculer toutes les adresses. Heureusement, MPASM le fait pour vous.

Pressez de nouveau <F7> pour excuter cette instruction : Effacer mavariable. Comme
mavariable vaut dj 0 (dans le simulateur), il ne se passe rien au niveau de celle-ci.

58
ATTENTION, RAPPEL : la mise sous tension, les cases mmoires (RAM) du PIC se
trouvent une valeur quelconque. Or, MPLAB ne peut savoir quelle est cette valeur. Il met
donc par dfaut 0. Si vous voulez quune case RAM du PIC contienne effectivement 0, vous
tes oblig de le faire vous-mme, sinon, le programme fonctionnera correctement sur
simulateur, mais pas sur circuit rel.

Eh oui, une simulation, a reste une simulation !

La ligne pointe devient est :

Incf mavariable,f ; incrmenter mavariable

PCL pointe alors sur : 0x35 D53 B00110101

Cest donc bien ladresse suivante : absence de saut signifie absence de rupture de
squence, donc fonctionnement squentiel du programme : les adresses sincrmentent
simplement.

Profitons-en pour jeter un il sur la fentre Watch . Vous voyez votre variable
mavariable . Sa valeur est 0x00 (ou H00), et son adresse est 0x0E. Nous avons dj
expliqu pourquoi prcdemment.

Pressons encore <F7>. La variable mavariable vaut maintenant 0x01 , car


lopration dincrmentation a t excute. Vous lavez dj compris, lexcution suivante va
vous renvoyer la ligne qui suit ltiquette boucle . Amusez-vous presser plusieurs fois
la touche <F7> pour observer lvolution de votre variable.

A ce stade, vous vous demandez ce qui va se passer lorsque votre variable atteindra la
valeur 0xFF ? Bien entendu, vous navez pas envie de presser encore 500 fois la touche <F7>.
On va donc acclrer le processus.

Nous allons donc modifier la valeur de mavariable . Pour ceci, rien de plus simple, il
suffit de double-cliquer sur la case value situe face au nom de mavariable et
dinscrire une nouvelle valeur (en hexadcimal, puisque nous avons choisi ce format.)

Double-cliquez, et indiquez ff . Ensuite cliquez nimporte o ailleurs pour valider la


valeur.

Pressez maintenant <F7> jusqu ce que la ligne suivante soit excute :

incf mavariable,f ; incrmenter mavariable

La ligne suivante est maintenant slectionne :

goto boucle ; boucler

Examinons ce qui sest pass :

La variable mavariable est passe 0. Logique, car 0xFF + 1 = 0x100. Or, coder
0x100 ncessite 9 bits (256). On obtient donc 00 (et on reporte le bit 8).

59
Examinons maintenant le registre STATUS : que constate-t-on. ?

Les bits 2, 3 et 4 sont 1, les autres sont 0. Les bits 3 et 4 sont actifs ltat bas (0).
Comme ils sont 1, ils sont donc inactifs.

Reste le bit2. Un coup dil sur le tableau 4-3 nous informe quil sagit du bit Z (pour
Zro). Logique, car le rsultat de lopration est 0.

Si ce niveau, vous vous demandez pourquoi le bit C (carry) nest pas positionn 1,
bravo, car vous vous posez les bonnes questions, puisque le rsultat de la dernire
incrmentation est B00000000 et on reporte B1. Mais alors, chapeau pour ceux qui ont
pens vrifier le fonctionnement de linstruction incf page 62 du datasheet. En effet,
vous constaterez en vrifiant que le seul bit affect (modifi) par cette instruction est le bit Z,
lexclusion du bit C : Status affected : Z .

En fait, cest logique : si vous utilisez linstruction incf et que vous obtenez un rsultat
null, cest forcment que vous avez dbord. Inutile de positionner deux bits diffrents pour
donner la mme information.

Nous allons clturer par les autres mthodes dexcution du programme par le simulateur.
Pressez <F6> pour ramener le PC 0. Dans le menu Debugger->run vous trouvez toutes
les mthodes possibles : essayez ceci :

- Pressez <F9> pour lancer rapidement le programme sans visualisation. Pressez <F5> pour
larrter l o il est arriv.

- Le menu debugger -> animate vous donne une excution anime, plus lente
lexcution, mais qui vous permet de suivre visuellement lexcution du programme.

- Lavance en pas pas avec <F8> vous permet deffectuer la mme chose quavec <F7>,
la diffrence prs quune sous-routine, que nous verrons plus tard, est excute en une
seule fois, comme si ctait une seule instruction. La touche <F7> entrera dans la sous-
routine pour excuter les instructions une une.

- Encore une autre mthode : Allez sur la ligne

goto boucle ; boucler

de votre petit programme. Positionnez votre souris en dbut de ligne et cliquez avec le
bouton de droite. Un menu apparat. Vous pouvez mettre des points darrt dans votre
programme. Vous pouvez galement demander votre programme de dmarrer jusquau
point spcifi (run to cursor), ainsi que dautres options. La fentre trace menu view-
>trace vous donne des informations supplmentaires sur la trace du programme. Le menu
debugger vous permet dautres configurations. Lisez laide concernant le simulateur pour
des informations dtailles. Le sous-menu debugger->stimulus controler vous permet
par exemple de placer des points darrts conditionnels.

Un double-clic sur une ligne place galement un point darrt, que vous remarquerez
grce au symbole B qui apparat gauche de la ligne. Un autre double-clic lannule.

60
Placez un point darrt dans votre programme. Pressez <F6>, puis <F9>, le programme
va sexcuter jusque la ligne rouge, puis passer en stop. Voil encore une nouvelle mthode
pratique pour dbuguer les longs programmes.

Il existe cependant une nouvelle procdure encore plus rapide : la trace de votre
programme.

Enlevez le point darrt, pressez <F6>, puis slectionnez : view -> simulator trace .
Une nouvelle fentre souvre, avec un message no items to display . Pressez maintenant
<F9> puis quelques fractions de seconde plus tard, <F5>.

Dans la fentre trace , vous obtenez le compte-rendu de toutes les instructions excutes
par votre programme depuis le lancement jusque larrt. Ceci se rvle trs pratique en cas de
plantage inexpliqu par exemple.

Il y a encore plein doptions concernant le debugger, je ne peux cependant pas toutes les
expliquer dans le cadre de cet ouvrage. Vous les dcouvrirez petit petit lors de vos
exprimentations, nhsitez pas examiner tous les menus.

A lheure actuelle, il y a cependant encore moins doptions que sur la version 5 de


MPLAB. Cependant, je pense que cest d la jeunesse du produit. Microchip a dj
ajout des fonctions qui existaient sur la version 5, et qui nexistaient pas sur la version 6.0.
Pour les anciens de MPLAB 5, il faudra encore un peu de patience pour tout rcuprer.

61
Notes :

62
9. Le jeu dinstructions

Les instructions sont dtailles partir de la page 57 du datasheet. Il peut donc sembler
inutile de les reprendre dans ce cours. Mais jai finalement opt pour une explication pratique
de ces instructions. Jai choisi en effet de les expliquer avec des petits exemples concrets,
plutt que de simplement traduire le datasheet ou de vous y renvoyer.

Bien entendu, vous pouvez exprimenter ces instructions avec MPLAB et son
simulateur, en insrant ces instructions aprs ltiquette start de votre programme.

Je vais donc expliquer ces instructions dans un ordre qui me facilite les explications, en
commenant par celles dj vues, dans le but final dobtenir toutes les rfrences aux
instructions dans le mme document.

9.1 Linstruction GOTO (aller )

Cette instruction effectue ce quon appelle un saut inconditionnel, encore appel rupture
de squence synchrone inconditionnelle. Rupture de squence parce que le programme
ne se droule pas dans lordre des instructions, synchrone parce quon sait quel
instant du programme se produit la rupture de squence (lendroit du goto ), et
inconditionnelle parce que le saut se produit dans tous les cas, en labsence de toute
condition.

Rappelez-vous que linstruction goto contient les 11 bits de lemplacement de


destination. Les 2 bits restants sont chargs depuis le registre PCLATH. Rappelez-vous en
effet la manire dont est construit le PC dans le cas des sauts. On ne peut sauter qu
lintrieur dune mme PAGE de 211, soit 2048 mots.

Ceci na aucune espce dimportance pour le 16F84, qui ne dispose que de 1Ki mots de
mmoire programme, mais devra tre considr pour les PIC de plus grande capacit
(16F876). Nous en reparlerons dans le cours-part2.

Voici donc en rsum le fonctionnement du goto :

- Ladresse de saut sur 11 bits est charge dans le PC.


- Les 2 bits manquants sont chargs depuis PCLATH (b3 et b4) : pas pour le 16F84.
- Le rsultat donne ladresse sur 13 bits (10 bits pour le 16F84)
- La suite du programme seffectue la nouvelle adresse du PC.

Souvenez-vous, que pour le 16F84 : Adresse de saut = adresse relle. Vous ne devez
donc vous proccuper de rien. Pour les autres, en cas de dbordement, MPLAB vous le
signalera.

Syntaxe

goto etiquette

63
Exemple

Start
goto plusloin ; le programme saute linstruction qui suit ltiquette
; plusloin
xxxxxxxx
plusloin
xxxxxxxx ; instruction excute aprs le saut : le programme se poursuit ici

Remarquez que vous pouvez sauter en avant ou en arrire. goto ncessite 2 cycles
dhorloge, comme pour tous les sauts

9.2 Linstruction INCF (INCrement File)

Cette instruction provoque lincrmentation de la valeur contenue lemplacement


spcifi (encore appel File).

Syntaxe

incf f,d

Comme pour toutes les instructions, f reprsente File , cest dire lemplacement
mmoire concern pour cette opration, d , quant lui: reprsente la destination. f
vaut donc dans la ralit une adresse, ou le symbole dune adresse, comme ceci :

incf variable,f

Ne confondez donc pas le f remplac par variable par le f situ aprs la virgule et
qui prcise la destination.

Sauf spcification contraire, d vaut toujours, au choix :

- f (la lettre f) ou 1 (le chiffre) : dans ce cas le rsultat est stock dans lemplacement
mmoire prcis par f (donc dans variable pour notre exemple)

- W (la lettre w) ou 0 (le chiffre) : dans ce cas, le rsultat est laiss dans le registre de
travail, et le contenu de lemplacement mmoire nest pas modifi. Ce registre de
travail est appel galement accumulateur .

La formule est donc (f) + 1 -> (d) : Les parenthses signifient le contenu de . Soit, en
franais : Le contenu de lemplacement spcifi est incrment de 1, le rsultat est plac dans
lemplacement dsign par d . Emplacement qui pourra tre soit lemplacement spcifi
par f , soit laccumulateur, (f) restant dans ce cas inchang.

Bit du registre STATUS affect

Le seul bit affect par cette opration est le bit Z.

64
Rappel : tant donn que la seule manire en incrmentant un octet dobtenir 0, cest de
passer de 0xFF 0x00. Le report nest pas ncessaire, puisquil va de soi. Si, aprs une
incrmentation, vous obtenez Z=1 , cest que vous avez dbord. Z vaudra donc 1 si (f) avant
lexcution valait 0xFF, il ny a aucune autre possibilit.

Exemples

incf mavariable , f ; le contenu de ma variable est augment de 1


; le rsultat est stock dans mavariable.
; W est inchang

incf mavariable , w ; Le contenu de mavariable est charg dans w et


; augment de 1. W contient donc le contenu de
; mavariable + 1. mavariable nest pas modifie

9.3 Linstruction DECF (DECRement File)

Decrmente le contenu de lemplacement spcifi. Le fonctionnement est


strictement identique linstruction prcdente, except que cette fois, on dcrmente.

Syntaxe

decf f , d ; (f) 1 -> (d)

Bit du registre STATUS affect

Le seul bit affect par cette opration est le bit Z.


Si avant linstruction, (f) vaut 1, Z vaudra 1 aprs lexcution (1-1 = 0)

Exemples

decf mavariable , f ; dcrmente mavariable, rsultat dans mavariable


decf mavariable , w ; prends (mavariable) 1 et place le rsultat dans w

9.4 Linstruction MOVLW (MOVe Literal to W)

Cette instruction charge la valeur spcifie dans le registre W (registre de travail). La


valeur prcise est dite littrale ou immdiate car ne dpend pas du contenu dun
emplacement mmoire.

Syntaxe

movlw k ; k-> w : k reprsente une valeur de 0x00 0xFF.

Bit du registre STATUS affect

Aucun ( donc mme si vous chargez la valeur 0.)

65
Exemple

movlw 0x25 ; charge la valeur 0x25 dans le registre w

9.5 Linstruction MOVF (MOVe File)

Charge le contenu de lemplacement spcifi dans la destination.

Syntaxe

movf f , d ; (f) -> (d)

Bit du registre STATUS affect

Une fois de plus, seul le bit Z est affect : si (f) vaut 0, Z vaut 1.

Exemple 1

Pour cette instruction, je vais me montrer beaucoup plus explicite. Vous allez comprendre
pourquoi

movf mavariable,w ; charge le contenu de mavariable dans w.

ATTENTION

Il est impratif ici de bien faire la distinction entre movlw k et movf f,w.

Dans le premier cas, cest la valeur qui est charge dans w, dans le second cest le
contenu de lemplacement spcifi. Si nous nous rappelons, dans la leon prcdente que
mavariable reprsentait ladresse 0x0E de notre zone de RAM. Supposons maintenant qu
lemplacement Ram 0x0E se trouve la valeur 0x50 (on dit : mavariable contient 0x50).

Si nous excutons linstruction suivante :

movlw mavariable

Lassembleur va traduire en remplaant mavariable par sa valeur. Attention, la valeur


dune variable, ce nest pas son contenu mme si le langage courant le laisse supposer.
Lassembleur va donc raliser la simple substitution de texte suivante :

movlw 0x0E

Aprs linstruction, le registre W contiendra 0x0E. Nous parlerons dans ce cas dun
adressage immdiat. Le droulement est du type f -> (d) (f nest pas entre parenthses).

Si nous excutons par contre linstruction suivante :

movf mavariable , w

66
Lassembleur va traduire galement en effectuant une simple substitution de texte (il
travaille toujours de cette faon. Nous obtenons donc :

movf 0x0E , w

Ce qui signifie : charger le contenu de lemplacement 0x0E dans w. Nous parlerons ici
dun adressage direct. Je rappelle quil est primordial de ne pas confondre, sinon, vous ne
comprendrez plus rien lors de la ralisation des programmes. Aprs cette instruction, W
contient donc 0x50 puisquon trouve cette valeur ladresse RAM 0x0E. Le droulement est
du type (f) -> (d).

Exemple 2

movf mavariable , f

Que fait cette instruction ? Si vous avez tout suivi, elle place le contenu de mavariable
dans mavariable. Dire que cela ne sert rien est tentant mais prmatur. En effet, si le
contenu de mavariable reste bien inchang, par contre le bit Z est positionn selon ce que
contient mavariable. Cette instruction permet de dterminer si (mavariable) = 0.

9.6 Linstruction MOVWF (MOVe W to File)

Permet de sauvegarder le contenu du registre de travail W dans un emplacement


mmoire. Cest lopration inverse de movf f,d.

Syntaxe

movwf f ; (W) -> (f)

Bit du registre STATUS affect

Aucun

Exemple

movlw 0x50 ; charge 0x50 dans W


movwf mavariable ; mavariable contient maintenant 0x50.

9.7 Linstruction ADDLW (ADD Literal and W)

Cette opration permet dajouter une valeur littrale au contenu du registre de travail
W. Nous sommes de nouveau dans le cas de ladressage immdiat.

Syntaxe

addlw k ; (W) + k -> (W)

67
Bits du registre STATUS affects

Z : Si le rsultat de lopration vaut 0, Z vaudra 1


C : Si le rsultat de lopration est suprieur 0xFF (255) , C vaudra 1
DC : Si le rsultat de lopration entrane en report du bit 3 vers le bit 4, DC vaudra 1

Ne vous inquitez pas trop pour DC, il nest utilis que pour les oprations sur les
quartets, par exemple, les nombres Binary Coded Decimal. Ds lors, je ne dtaille pas ici.

Exemple

movlw 253 ; charger 253 en dcimal dans W


addlw 4 ; Ajouter 4. W contient 1, Z vaut 0, C vaut 1(dborde)
addlw 255 ; ajouter 255 W vaut 0, C vaut 1, Z vaut 1

9.8 Linstruction ADDWF (ADD W and F)

Le contenu du registre W est ajout au contenu du registre F. Ne pas confondre avec


linstruction prcdente. Il sagit maintenant dun adressage direct.

Syntaxe

addwf f , d ; (w) + (f) -> (d)

Bits du registre STATUS affects

C, DC, et Z

Exemple

movlw 12 ; charger 12 dans W


movwf mavariable ; mavariable contient maintenant 12
movlw 25 ; charger 25 dans W
addwf mavariable,f ; rsultat : (W) + (mavariable), donc 25+12
; rsultat = 37 sauv dans mavariable (,f).

9.9 Linstruction SUBLW (SUBtract W from Literal)

Attention, ici il y a un pige. Linstruction aurait d sappeler SUBWL. En effet, on


soustrait W de la valeur littrale, et non linverse. Comme le nom lindique, il sagit dun
adressage littral ou immdiat.

Syntaxe

sublw k ; k (W) -> (W)

Bits du registre STATUS affects

C, DC, Z

68
Notez ici que le bit C fonctionne de manire inverse que pour laddition. Ceci est commun
la plupart des microprocesseurs du march. Les autres utilisent parfois un bit spcifique
pour la soustraction, bit le plus souvent appel borrow (emprunt).

Si le rsultat est positif, donc, pas de dbordement : C =1. S il y a dbordement, C


est forc 0.

Ceci est logique, et sexplique en faisant une soustraction manuelle. Le bit C reprsente le
me
9 bit ajout doffice 1 la valeur initiale. Si on effectue une soustraction manuelle
donnant une valeur <0, on obtient donc une valeur finale sur 8 bits, le report obtenu venant
soustraire le bit C. Si le rsultat est >0, il ny a pas de report, le rsultat final reste donc sur 9
bits.

La formule de la soustraction est donc : k prcd dun neuvime bit 1 contenu


de W = rsultat sur 8 bits dans W avec 9me bit dans C.

Exemple 1

movlw 0x01 ; charger 0x01 dans W


sublw 0x02 ; soustraire W de 2
; rsultat : 2 (W) = 2-1 = 1
; Z = 0, C = 1, donc rsultat positif

Effectuons cette opration manuellement (les exposants noirs sont les reports) :

C b7 b6 b5 b4 b3 b2 b1 b0 Dec
1 0 0 0 0 0 0 1 010 2
- 0 0 0 0 0 0 0 01 1 1
= 1 0 0 0 0 0 0 0 1 1

Comment procder ? Et bien, comme pour une soustraction dcimale. On commence par
les bits de droite : 0-1, a ne passe pas, donc on emprunte 10, et on soustraira videmment une
unit supplmentaire au bit b1. On a donc :B 10 B1, car souvenez-vous quon a
emprunt 10 en BINAIRE. Rsultat 1. On soustrait ensuite les b1 : on aura 1 0 lemprunt,
donc 1-0-1 = 0. On continue de droite gauche jusquau 9me bit qui est le carry, positionn
1 uniquement pour le nombre soumis la soustraction. Rsultat final : B00000001 et carry
1 : C.Q.F.D. Interprt, a donne : 2 1 = 1, C = 1 donc le rsultat est positif

Exemple 2

movlw 0x02 ; charger 0x02 dans W


sublw 0x02 ; soustraire 2 (w) = 2 2 = 0
; Z = 1 , C = 1 : rsultat nul

C b7 b6 b5 b4 b3 b2 b1 b0 Dec
1 0 0 0 0 0 0 1 0 2
- 0 0 0 0 0 0 0 1 0 2
= 1 0 0 0 0 0 0 0 0 0

On procde toujours de la mme manire. Interprtation : 2 2 = 0 : C est sans


importance mais positionn 1.

69
Exemple 3

movlw 0x03 ; charger 0x03 dans W


sublw 0x02 ; soustraire 2 (W) = 2 3 = -1
; Z = 0, C = 0, rsultat ngatif

C b7 b6 b5 b4 b3 b2 b1 b0 Dec
1 010 010 010 010 010 010 110 010 2
- 01 01 01 01 01 01 01 11 1 3
= 0 1 1 1 1 1 1 1 1 -1

Procdons de la mme manire, et nous obtenons B11111111, avec le bit C 0. Et l,


me dites-vous, B11111111, cest FF, pas 1. Et bien, rappelez-vous ceci : Vous devez lire
le bit C pour interprter le rsultat de votre soustraction.

Linterprtation est donc : 2 3 = 255. C vaut -1 donc le rsultat est ngatif.

Comme ce dernier vaut 0, vous tes averti que le rsultat de lopration est ngatif.
Attention, ne prenez pas le raccourci dangereux de dire jobtiens 255 ngatif et donc -255 .
En effet, souvenez-vous : Comment connatre la valeur absolue dun nombre ngatif ? En
prenant son complment 2.
.
Si vous navez pas compris, cest que vous avez saut les premiers chapitres en pensant
quils ne vous taient pas ncessaires, manifestement vous aviez tort. Si vous comprenez, les
explications suivantes vous sont inutiles.

Complment 1 de B11111111 = B00000000 (on inverse tous les bits)


Complment 2 = complment 1 + 1, donc B00000001.

Donc, le complment 2 de 0xFF vaut 0x01. C.Q.F.D.

Je peux donc maintenant interprter correctement le rsultat de mon opration : 2 3 =


-1. car C valant 0, jacte que mon rsultat est ngatif et je complmente 2 pour obtenir sa
valeur absolue.

Pour preuve, si vous ajoutez 1 1, vous obtenez B11111111 + B00000001 =


B00000000 = 0.

Vous matrisez maintenant les soustractions. Certains auront sans doute pens que
jexpliquais trop en dtail, mais mon exprience ma appris que les soustractions
reprsentaient souvent un cueil dans la ralisation de trop de programmes.

Encore un dernier dtail :

Pour effectuer une soustraction dun nombre, vous pouvez bien entendu effectuer
une addition de son complment 2.

Le rsultat sera strictement le mme condition de correctement interprter les bits Z et


C. Je vous laisse le faire vous-mme pour vous convaincre. Du reste cette astuce est pratique
car si vous disposez de sublw pour effectuer k (w), utiliser le complment 2 de k via un

70
addlw vous permet deffecuter lopration inverse (w) k. Comme MPASM sait parfaitement
calculer les complments deux lui-mme, sagissant dune constante, vous pouvez crire
ceci :
sublw 8 ; effecture 8 (w)
addlw -8 : effectue (w) 8

Constatez vous-mme une nouvelle fois que le nombre dinstructions ne dit pas grand-
chose sur les possibilits relles dun micro si vous ntudiez pas le contexte de faon prcise
et si vous ne faites pas fonctionner votre cerveau. Dans notre cas, nous aurions pu regretter
labsence dune instruction qui effectue (w) 8, alors quen ralit nous disposons de cette
instruction via laddition littrale. Un bon programmeur est quelquun qui sait voir plus loin
que ce qui semble vident, pour exploiter toutes les possibilits visibles ou caches.

9.10 Linstruction SUBWF (SUBtract W from F)

Cette opration soustrait le contenu de W du contenu de F. Nous restons dans les


soustractions, mais, cette fois, au lieu dun adressage immdiat, nous avons un adressage
direct.

Syntaxe

subwf f , d ; (f) (W) -> (d)

Bits du registre STATUS affects

C , DC , Z

Exemple

movlw 0x20 ; charger 0x20 dans w


movwf mavariable ; mettre w dans (mavariable) (0x20)
movlw 0x1F ; charger 0x1F dans w
subwf mavariable,w ; (mavariable) - (w) -> (w)
; 0x20 0x1F = 0x01
; rsultat dans w, C=1, Z=0
movwf autrevariable ; sauver 0x01 dans une autre variable

Je vous renvoie linstruction prcdente pour plus dinformations sur la faon dont se
droulent les soustractions et la gestion des bits C et Z.

9.11 Linstruction ANDLW (AND Literal with W)

Cette instruction effectue un ET logique bit bit entre le contenu de W et la valeur


littrale qui suit. Il sagit donc dun adressage littral ou immdiat.

Syntaxe

andlw k ; (w) AND k -> (w)

71
Bit du registre STATUS affect

Exemple

movlw B11001101 ; charger w


andlw B11110000 ; effectuer un and(&)

b7 b6 b5 b4 b3 b2 b1 b0
1 1 0 0 1 1 0 1
And 1 1 1 1 0 0 0 0
= 1 1 0 0 0 0 0 0

Rappelez-vous quon effectue un ET logique entre chaque bit de mme rang. Seuls
restent donc positionns 1 les bits dont les 2 oprandes valent 1. Donc, le fait deffectuer un
AND avec la valeur B11110000 masque les bits 0 3, et ne laisse subsister que les bits 4 7
du premier nombre. Jen profite pour vous rappelez que le ET logique est une opration
commutative.

Tant que vous ne jonglerez pas avec lhexadcimal, je vous conseille de toujours traduire
les nombres en binaires pour toutes les instructions concernant les bits.

9.12 Linstruction ANDWF (AND W with F)

Ralise un ET logique bit bit entre le contenu du registre W et le contenu de F.


Maintenant, vous devriez avoir bien compris, il sagit de la mme opration que
prcdemment, mais ralise en adressage direct. Je vais donc acclrer les explications.

Syntaxe

andwf f , d ; (f) AND (w) -> (d)

Bit du registre STATUS affect

Exemple

movlw 0xC8 ; charger 0XC8 dans w


movwf mavariable ; sauver dans mavariable
movlw 0xF0 ; charger le masque
andwf mavariable,f ; (mavariable) = 0xC0 (on a limin le quartet faible)

72
9.13 Linstruction IORLW (Inclusive OR Literal with W)

Ralise un OU inclusif logique bit bit entre le contenu du registre w et la valeur


immdiate prcise. La notion dinclusif, nous en avons dj parl, prcise que le rsultat de
lopration pour un rang de bit donn vaudra 1 si un des 2 bits de ce rang vaut 1, incluant le
cas o les deux bits valent simultanment 1. Nous avons ici affaire un adressage littral, ou
immdiat.

Syntaxe
iorlw k ; (w) OR k -> (w)

Bit du registre STATUS affect

Exemple

movlw 0xC3 ; charger 0xC3 dans W


iorlw 0x0F ; FORCER les bits 0 3 : rsultat : (w) = 0xCF

b7 b6 b5 b4 b3 b2 b1 b0
1 1 0 0 0 0 1 1
OR 0 0 0 0 1 1 1 1
= 1 1 0 0 1 1 1 1

Donc, avec un ou inclusif (OR), on peut forcer nimporte quel bit 1 (pour rappel, avec
AND, on peut forcer nimporte quel bit 0).

9.14 Linstruction IORWF (Inclusive OR W with File)

Effectue un OU inclusif logique bit bit entre le contenu de W et le contenu de F.


Il sagit dune instruction utilisant ladressage direct. Je ne donnerai pas dexemple, vous
devriez maintenant avoir compris.

Syntaxe

iorwf f , d ; (w) OR (f) -> (d)

Bit du registre STATUS affect

73
9.15 Linstruction XORLW (eXclusive OR Literal with W)

Ralise un OU exclusif logique bit bit entre le contenu du registre W et la


valeur littrale prcise. La notion exclusif se rapport au fait que, pour un rang donn, le
bit de rsultat vaudra 1 si le bit de ce rang pour le premier oprateur vaut 1 ou si celui du
second oprateur vaut 1, lexclusion du cas o les deux bits valent 1 simultanment. Nous
avons affaire ici de ladressage littral, ou immdiat.

Notez que si vous appliquez un bit 0 un bit quelconque Bx xor B0, vous
obtenez comme rsultat le bit x inchang. Par contre, si vous appliquez un bit 1 : Bx xor
B1, vous obtenez comme rsultat linverse de x. En effet, 0 xor 1 donne 1, mais 1 xor 1
donne 0, du fait de lexclusion.

Cette instruction peut donc servir inverser nimporte quel bit dun octet. Il vous
suffit pour cela dappliquer un bit 1 pour toute position de bit que vous voulez inverser.

Syntaxe

xorlw k ; (w) xor k -> (w)

Bit du registre STATUS affect

Exemple

movlw B11000101 ; charger W


xorlw B00001111 ; xor avec la valeur
; rsultat : B 11001010
; les 4 bits de poids faible ont t inverss

b7 b6 b5 b4 b3 b2 b1 b0
1 1 0 0 0 1 0 1
Xor 0 0 0 0 1 1 1 1
= 1 1 0 0 1 0 1 0

Remarquez que tous les bits de loctet initial ont t inverss par chaque bit du second
oprande qui tait 1.

Avec tout ce que nous avons vu, vous savez maintenant forcer un bit 1 (OR), forcer
un bit 0 (AND), autrement dit le masquer , ou inverser un bit (XOR). Vous savez donc
manipuler chaque bit comme vous lentendez.

9.16 Linstruction XORWF (eXclusive OR W with F)

Effectue un OU exclusif logique bit bit entre le contenu du registre W et le


contenu de F. Il sagit exactement la mme opration que XORLW, mais en adressage
direct.

74
Syntaxe

xorwf f , d ; (w) xor (f) -> (d)

Bit du registre STATUS affect

9.17 Linstruction BSF (Bit Set F)

Force le bit de rang spcifi du contenu de lemplacement F 1. Dit autrement, force


un numro de bit dun registre prcis 1. Il sagit dun adressage direct.

Syntaxe

bsf f , b ; (f).b = 1
; le bit n b est positionn dans la case mmoire (f)
; b est videmment compris entre 0 et 7

Bit du registre STATUS affect

Aucun

Exemples

bsf STATUS , C ; positionne le bit C 1 dans le registre STATUS


bsf mavariable , 2 ; positionne bit 2 de (mavariable) 1

Attention: Lorsque vous manipulez un bit particulier, le PIC nagit pas


directement sur cet unique bit. En fait, il ralise un cycle appel read/modifiy/write,
c'est--dire : lecture/modification/criture.

Si vous prenez le premier exemple, le PIC va en fait charger STATUS (les 8 bits),
modifier le bit C, puis r-crire STATUS son emplacement dorigine.

Vous allez me dire que cest le problme du PIC et que a ne vous concerne pas. En
fait, oui et non. Oui pour lexemple en question, mais non lorsque vous agissez sur des bits
dun port de sortie : nous en reparlerons le moment venu.

Cette remarque vaut videmment pour toute les instruction manipulant un bit
particulier, et donc pour BCF.

9.18 Linstruction BCF (Bit Clear F)

Force le bit de rang spcifi du contenu de lemplacement F 0. Dit autrement, force


un numro de bit dun registre prcis 0. Il sagit dun adressage direct.

75
Syntaxe

bsf f , b ; (f).b = 0
; le bit n b est positionn dans la case mmoire (f)
; b est videmment compris entre 0 et 7

Bit du registre STATUS affect

Aucun

Exemples

bcf STATUS , C ; positionne le bit C 0 dans le registre STATUS


bcf mavariable , 2 ; positionne b2 de (mavariable) 0

9.19 Linstruction RLF ( Rotate Left through Carry)

Rotation vers la gauche du registre F en utilisant le carry. Il sagit ici dune


instruction utilisant ladressage direct.

Les oprations de dcalage sont des oprations trs souvent utilises. Les PIC16F ont la
particularit de ne disposer que dinstructions de rotation sur 9 bits. Vous allez voir quavec
ces instructions, on peut trs facilement raliser des dcalages. Le mot qui va subir les
rotations est constitu des 8 bits du registre spcifi, complt par le bit Carry du registre
STATUS.

Lopration de rotation effectue lopration suivante : Le bit de carry C est mmoris.


Ensuite chaque bit de loctet est dplac vers la gauche. Lancien bit 7 sort de loctet par la
gauche, et devient le nouveau carry. Le nouveau bit 0 devient lancien carry. Il sagit donc
bien dune rotation sur 9 bits.

Syntaxe

rlf f , d ; (f) rotation gauche avec carry-> (d)

Bit du registre STATUS affect

Exemple1

Un petit exemple vaut mieux quun long discours.

bsf STATUS,C ; positionne le carry 1


movlw B00010111 ; charge la valeur dans w
movwf mavariable ; initialise mavariable
rlf mavariable,f ; rotation vers la gauche

C b7 b6 b5 b4 b3 b2 b1 b0
F 1 0 0 0 1 0 1 1 1
Rlf 0 0 0 1 0 1 1 1 1

76
Vous voyez que tous les bits ont t dcals vers la gauche. C a t rintroduit dans
b0. Le rsultat reste sur 9 bits.

Exemple 2

bcf STATUS,C ; positionne le carry 0


movlw b00010111 ; charge la valeur dans w
movwf mavariable ; initialise mavariable
rlf mavariable,f ; rotation vers la gauche

Si vous avez compris, le rsultat sera B00101110, avec le carry 0. Si le carry tait 0
au dpart, on effectue un simple dcalage vers la gauche. Notez quune rotation sur 9 bits peut
fort bien servir de dcalage de 8 bits avec rsultat sur 9 bits. Que se passe-t-il si, en dcimal,
on effectue ce type dopration ?

Prenons le nombre 125 et dcalons-le vers la gauche en dcimal, nous obtenons 1250.
Nous avons multipli le nombre par sa base (dcimal = base 10). Et bien cest la mme chose
en binaire (une fois de plus).

Prenons B00010111 , soit 23 en dcimal. Dcalons-le, nous obtenons B00101110, soit


46. Nous avons donc effectu une multiplication par 2. Retenez ceci, cela vous sera trs utile
par la suite.

Un dcalage dun rang vers la gauche quivaut une multiplication par 2.

En partant dun nombre compris entre 0 et 255 vous obtenez un rsultat pair compris entre
2 et 510 (le carry tant le bit de rang 8).

9.20 Linstruction RRF ( Rotate Right through Carry)

Rotation vers la droite du registre F en utilisant le carry. Il sagit ici dune


instruction utilisant ladressage direct.

Lopration de rotation vers la droite effectue lopration suivante : Le bit de carry C


est mmoris. Ensuite chaque bit de loctet est dplac vers la droite. Lancien bit 0 sort de
loctet par la droite, et devient le nouveau carry. Lancien carry devient le nouveau bit7. Il
sagit donc galement dune rotation sur 9 bits.

Syntaxe

rrf f , d ; (f) rotation droite avec carry-> (d)

Bit du registre STATUS affect

Exemple1

bsf STATUS,C ; positionne le carry 1


movlw B00010111 ; charge la valeur dans w

77
movwf mavariable ; initialise mavariable
rrf mavariable,f ; rotation vers la droite

b7 b6 b5 B4 b3 b2 b1 b0 C
F 0 0 0 1 0 1 1 1 1
Rrf 1 0 0 0 1 0 1 1 1

Vous voyez que tous les bits ont t dcals vers la droite. C a t rintroduit dans b7. Le
rsultat reste sur 9 bits.

Exemple 2

bcf STATUS,C ; positionne le carry 0


movlw b00010111 ; charge la valeur dans w
movwf mavariable ; initialise mavariable
rrf mavariable,f ; rotation vers la droite

Si vous avez compris, le rsultat sera B00001011, avec le carry 1. Si le carry est 0 au
dpart, on effectue un simple dcalage vers la droite.

Que sest-il pass ? Et bien notre nombre de dpart, soit 23 en dcimal est devenu 11. Le
carry reprsente le bit -1 , donc, la moiti du bit 0, donc . En effet, en dcimal, le chiffre
1 derrire les units a comme valeur 1/base, donc 1/10. En binaire ce sera donc .

Si nous regardons alors les 9 bits, nous obtenons 11 . Nous avons donc effectu une
division par 2. Retenez ceci, cela vous sera galement trs utile par la suite.

Un dcalage dun rang vers la droite quivaut une division par 2.

En partant dun nombre compris entre 0 et 255 nous obtenons un rsultat fractionnaire
compris entre 0 et 127.5 (le carry tant le bit de rang -1)

9.21 Linstruction BTFSC (Bit Test F, Skip if Clear)

Teste le bit prcis du contenu de lemplacement F et saute sil vaut 0. Il sagit ici de
votre premier saut conditionnel (li une condition), ou rupture de squence synchrone
conditionnelle.

En effet, il ny aura saut que si la condition est remplie. Les instructions conditionnelles
sont la base de tout ce qui est prise de dcision dans un programme.

Notez que dans ce cas linstruction prendra 2 cycles, sinon, elle nutilisera quun cycle.
De plus, il faut retenir que pour tous ces types de saut, on ne saute que linstruction
suivante (skip et non goto). En effet, la syntaxe ne contient pas dadresse de saut, comme
nous allons le voir

78
Syntaxe

btfsc f, b ; on teste le bit b de la mmoire (f).


; si ce bit vaut 0, on saute linstruction suivante, sinon
; on excute linstruction suivante.
Instruction x ; excute seulement si f.b vaut 1
Instruction y ; excute directement si b vaut 0

Notez que pour passer de linstruction btfsc linstruction y il vous faudra en gnral
2 cycles. En effet :

- Soit la condition f.b est remplie et donc au saute linstruction x, un saut prenant 2
cycles.

- Soit la condition nest pas remplie et on excute linstruction x. Il ny a pas de saut et


donc btfsc prend un seul cycle, mais il faut un cycle galement pour excuter
linstruction x. Notez que ceci ne vaut que si linstruction x nest pas elle-mme une
instruction de saut, selon la syntaxe suivante, par exemple :

btfsc f, b ; on teste le bit b de la mmoire (f).


; si ce bit vaut 0, on saute linstruction suivante, sinon
; on excute linstruction suivante.
goto plusloin ; si b vaut 1 on traite plus loin ce cas
Instruction y ; on traite ici le cas o b valait 0

plusloin : ; on traite ici le cas o b valait 1


instruction z

Cette faon de procder est trs souvent utilise lorsquil y a plusieurs instructions
excuter dans un cas et dans lautre. Le goto peut ventuellement tre remplac par un
call si le droulement du programme doit reprendre linstruction y dans tous les cas.

Ces faons de faire sont applicable aux autres instructions impliquant un skip , je nen
reparlerai donc pas.

Bit du registre STATUS affect

Aucun

Exemple1

Voici un exemple dans lequel on doit excuter une seule instruction supplmentaire si
le bit vaut 1.

btfsc STATUS,C ; tester si le bit C du registre STATUS vaut 0


bsf mavariable,2 ; non (C=1), alors bit 2 de mavariable mis 1
xxxx ; la suite du programme est ici dans les 2 cas

79
Exemple 2

Que faire si les traitements ncessitent plusieurs instructions ? Et bien, comme dj


expliqu on combine les sauts conditionnels avec les saut inconditionnels (par exemple goto).

movlw 0x12 ; charger 12 dans le registre de travail


subwf mavariable,f ; on soustrait 0x12 de mavariable
btfsc STATUS,C ; on teste si le rsultat est ngatif (C=0)
goto positif ; non, alors au saute au traitement des positifs
xxxx ; on poursuit ici si le rsultat est ngatif
...
positif: ; on poursuit ici si le rsultat est positif

9.22 Linstruction BTFSS (Bit Test F, Skip if Set)

Teste le bit prcis du contenu de lemplacement F et saute sil vaut 1. Le


fonctionnement est strictement identique celui de linstruction prcdente.

Syntaxe

btfss f, b ; on teste le bit b de la mmoire (f).


; si ce bit vaut 1, on saute linstruction
; suivante, sinon
; on excute linstruction suivante.
xxxx ; si le bit vaut 1, ne sera pas excute (skip)
xxxx ; Le programme continue ici

Bit du registre STATUS affect

Aucun

Exemple
btfss STATUS,C ; tester si le bit C du registre STATUS vaut 1
bsf mavariable,2 ; non (C=0), alors bit 2 de mavariable mis 1
xxxx ; la suite du programme est ici dans les 2 cas

9.23 Linstruction DECFSZ (DECrement F, Skip if Z)

Dcrmente le contenu de lemplacement F et saute linstruction suivante si le


rsultat vaut 0. Cette instruction est trs utilise pour crer des boucles.

Syntaxe

decfsz f, d ; (f) 1 -> (d). Saut si (d) = 0

Bit du registre STATUS affect

Aucun

80
Exemple1

movlw 3 ; charger 3 dans w


movwf compteur ; initialiser compteur
movlw 0x5 ; charger 5 dans w
boucle ; tiquette
addwf mavariable , f ; ajouter 5 ma variable
decfsz compteur , f ; dcrmenter compteur et tester sa valeur
goto boucle ; si compteur pas 0, on boucle
movf mavariable , w ; on charge la valeur obtenue dans w

Comment crit-on ce type de programme ? Et bien tout simplement de la manire


suivante :

- on initialise le compteur de boucles.


- on place une tiquette de dbut de boucle
- on crit les instructions qui doivent sexcuter plusieurs fois
- linstruction decfsz permet de dterminer la fin de la boucle
- linstruction goto permet de localiser le dbut de la boucle.

ATTENTION

- Si vous aviez mis

decfsz compteur , w ; dcrmenter compteur et tester sa valeur

la boucle naurait jamais de fin, car la variable compteur ne serait jamais modifie. Ceci
vous permet, en faisant fonctionner votre cerveau, de tester une nouvelle utilit cette
instruction

Astuce : En prcisant w comme destination, vous pouvez tester si une variable vaut 1
sans la modifier.

Remarquez donc quun movff variable,f vous permettait de tester si une variable tait
nulle, voici maintenant quun decfsz variable,w vous permet de tester si elle vaut 1. Encore
une fois, le nombre dinstructions ne rsume pas des capacits du micro utilis.

Pour revenir notre exemple, si vous placez 0 dans le compteur de boucles, elle sera
excute 256 fois. Si vous ne dsirez pas quelle soit excute dans cette circonstance, vous
devez ajouter un test avant lexcution de la premire boucle, comme dans lexemple suivant :

Exemple 2

movf compteur,f ; permet de positionner Z


btfsc STATUS , Z ; sauter si Z = 0, donc si compteur >0
goto suite ; compteur = 0, ne pas traiter la boucle
boucle ; tiquette de dbut de boucle
addwf mavariable , f ; ajouter 5 ma variable
decfsz compteur , f ; dcrmenter compteur et tester sa valeur
goto boucle ; si compteur pas 0, on boucle
suite ; on saute directement ici si compteur = 0
movf mavariable , w ; on charge la valeur obtenue dans w

81
9.24 Linstruction INCFSZ (INCrement F, Skip if Zero)

Incrmente le contenu de lemplacement F et saute linstruction suivante si le


rsultat vaut 0. Je ne vais pas dtailler cette instruction, car elle est strictement identique la
prcdente, hormis le fait quon incrmente la variable au lieu de la dcrmenter.

Syntaxe

incfsz f , d ; (f) + 1 -> (d) : saut si (d) = 0

Bit du registre STATUS affect

Aucun

Notez que si vous effectuez incfsz f,w vous testez le rsultat de lincrmentation sans
modifier la variable. Or, une incrmentation donne 0 si la valeur prcdente du registre valait
0xFF. Autrement dit, voici une nouvelle astuce :

Astuce : En prcisant w comme destination, vous pouvez tester si une variable


contient 0xFF sans la modifier.

Encore une instruction non rpertorie, et qui pourtant existe dans la ralit du
programmeur.

9.25 Linstruction SWAPF (SWAP nibbles in F)

Inverse les 2 quartets du contenu de lemplacement F.. Cette opration inverse


simplement le quartet (demi-octet) de poids faible avec celui de poids fort. Ce genre
dopration est utile lorsque vous manipulez des quartet, lexemple typique tant le codage
BCD.

Syntaxe

swapf f , d ; inversion des b0/b3 de (f) avec b4/b7 -> (d)

Bit du registre STATUS affect

Aucun : cette particularit nous sera trs utile lorsque nous verrons les interruptions.

Exemple

movlw 0xC5 ; charger 0xC5 dans w


movwf mavariable ; placer dans mavariable
swapf mavariable , f ; (mavariable) = 0x5C

82
9.26 Linstruction CALL (CALL subroutine)

Appelle une sous-routine. Cette opration effectue un saut inconditionnel vers un


sous-programme. Il sagit dune rupture de squence inconditionnelle synchrone avec
mmorisation de ladresse de retour.

Quest un sous-programme ? Et bien, il sagit tout simplement dune partie de programme


qui peut tre appel depuis plusieurs endroits du programme dit principal et qui prsente
la particularit de renvoyer en fin de son excution linstruction suivant lendroit o il avait
t appel.

Syntaxe

call sousroutine ; (pc)->(pile), puis sousroutine + PCLATH -> (pc)

Mcanisme

Lors de lexcution de linstruction, le contenu du PC est sauvegard sur le sommet


dune pile. Une pile fonctionne comme une pile dassiettes : la dernire assiette que vous avez
mise sur la pile sera la premire pouvant tre rcupre. Or, comme nous lavons dj
expliqu, le PC contient toujours ladresse de la prochaine instruction excuter.

Une fois le PC sauv, son contenu est remplac par les 11 bits de valeur de ladresse de
saut (sousroutine), complts (pour les PIC ayant plus de 2KiB de mmoire programme) par
les 2 bits de poids fort de PCLATH. Le programme va donc sauter lemplacement
sousroutine exactement comme avec un goto.

lemplacement sousroutine va se trouver une srie dinstruction, le sous-programme


devant imprativement se terminer par une instruction de retour de sous-programme (par
exemple linstruction return). Une fois cette instruction rencontre, ladresse prsente sur la
pile va en tre retire et place dans PC, ce qui va ramener le programme linstruction qui
suivait lappel via linstruction call.

Notez que si le sous-programme (ou sous-routine) appelle lui-mme un autre sous


programme, ladresse sera galement sauve au dessus de la pile. Ceci explique pourquoi il
doit sagir dune pile, puisque ladresse de retour doit toujours tre la dernire adresse
sauvegarde.

Attention, cette pile a une taille limite 8 emplacements. Il nexiste aucun


moyen de tester la pile, vous devez donc grer vos sous-programmes pour ne pas
dpasser 8 emplacements, sinon, votre programme se plantera.

Notez que lorsque vous sortez dun sous-programme, lemplacement est videmment
libr. La limite nest donc pas dans le nombre de fois que vous appelez votre sous-
programme, mais dans le nombre dimbrications (sous-programme qui en appelle un autre qui
en appelle un autre) etc.

Bit du registre STATUS affect

Aucun

83
9.27 Linstruction RETURN (RETURN from subroutine)

Retour de sous-routine. Va toujours de pair avec une instruction call. Cette


instruction indique la fin de la portion de programme considre comme sous-routine (SR).
Rappelez-vous que pour chaque instruction call rencontre, votre programme devra
rencontrer une instruction return .

Syntaxe

return ; (pile) -> PC


; Le programme poursuit ladresse qui suit la ligne call.

Bit du registre STATUS affect

Aucun

Exemples

Pour le mcanisme, je vous renvoie linstruction call. Comme ceci est un concept
trs important, je vais dtailler un peu plus par lexemple.

Imaginons un programme qui a besoin dune petite temporisation (comme chaque


instruction prend du temps, on peut sarranger pour en faire perdre volontairement au
programme afin de retarder son fonctionnement. Ecrivons-la :

movlw 0xCA ; valeur du compteur


movwf compteur ; initialiser compteur de boucles
boucle
decfsz compteur,f ; dcrmenter compteur, sauter si 0
goto boucle ; boucler si pas 0
xxx ; suite du programme

Imaginons maintenant que cette petite temporisation soit appele rgulirement par
notre programme principal. Ecrivons quoi ressemble le programme principal :

xxx ; instruction quelconque


xxx ; instruction quelconque
xxx ; instruction quelconque
xxx ; instruction quelconque
tempo ; ici, on a besoin dune tempo
xxx ; instruction quelconque
xxx ; instruction quelconque
xxx ; instruction quelconque
tempo ; ici aussi
xxx ; instruction quelconque
xxx ; instruction quelconque
tempo ; et encore ici
xxx ; instruction quelconque

La premire chose qui vient lesprit, est deffectuer un copier/coller de notre


temporisation. On obtient donc un programme comme ceci :

xxx ; instruction quelconque

84
xxx ; instruction quelconque
xxx ; instruction quelconque
xxx ; instruction quelconque
movlw 0xCA ; valeur du compteur
movwf compteur ; initialiser compteur de boucles
boucle
decfsz compteur,f ; dcrmenter compteur, sauter si 0
goto boucle ; boucler si pas 0
xxx ; instruction quelconque
xxx ; instruction quelconque
xxx ; instruction quelconque
movlw 0xCA ; valeur du compteur
movwf compteur ; initialiser compteur de boucles
boucle2
decfsz compteur,f ; dcrmenter compteur, sauter si 0
goto boucle2 ; boucler si pas 0
xxx ; instruction quelconque
xxx ; instruction quelconque
movlw 0xCA ; valeur du compteur
movwf compteur ; initialiser compteur de boucles
boucle3
decfsz compteur,f ; dcrmenter compteur, sauter si 0
goto boucle3 ; boucler si pas 0

Ceci nest pas lgant, car, si nous devons changer la valeur de notre tempo, nous devons
la changer partout dans le programme, sans oublier un seul endroit. De plus, a prend
beaucoup de place en mmoire programme.

On peut galement se dire : utilisons une macro , qui, rappelez-vous, effectue une
substitution au moment de lassemblage. Cest vrai, qualors, il ny a plus quun endroit
modifier, mais, dans notre PIC, le code se retrouvera cependant autant de fois quon a utilis
la temporisation. Que de place perdue, surtout si la portion de code est grande et utilise
plusieurs fois.

Pour remdier ceci, nous utiliserons la technique des sous-programmes. Premire


tape, modifions notre temporisation pour en faire une sous-routine :

tempo ; tiquette de dbut de la sous-routine


movlw 0xCA ; valeur du compteur
movwf compteur ; initialiser compteur de boucles
boucle
decfsz compteur,f ; dcrmenter compteur, sauter si 0
goto boucle ; boucler si pas 0
return ; fin de la sous-routine.

Deuxime tape, nous modifions notre programme principal pour que chaque fois que
nous avons besoin dune tempo, il appelle le sous-programme. Nous obtenons :

xxx ; instruction quelconque


xxx ; instruction quelconque
xxx ; instruction quelconque
call tempo ; appel du sous-programme
xxx ; instruction quelconque, le programme continue ici
xxx ; instruction quelconque
xxx ; instruction quelconque
call tempo ; appel du sous-programme
xxx ; instruction quelconque, le programme continue ici
xxx ; instruction quelconque

85
call tempo ; appel du sous-programme
xxx ; instruction quelconque, le programme continue ici

Dans ce cas, la routine tempo nest prsente quune seule fois en mmoire
programme.

Mais on peut amliorer : supposons que nous dsirons une temporisation dure variable.
Il nous suffit de modifier la sous-routine en supprimant la valeur dinitialisation, et on place
celle-ci dans le programme principal. Cela sappelle un sous-programme avec passage de
paramtre(s).

Exemple, notre sous-programme devient :

tempo ; tiquette de dbut de la sous-routine


movwf compteur ; initialiser compteur de boucles
boucle
decfsz compteur,f ; dcrmenter compteur, sauter si 0
goto boucle ; boucler si pas 0
return ; fin de la sous-routine.

Quant notre programme principal :


xxx ; instruction quelconque
xxx ; instruction quelconque
xxx ; instruction quelconque
xxx ; instruction quelconque
movlw 0x25 ; charger w avec 0x25
call tempo ; appel du sous programme tempo dune dure de 0x25
xxx ; instruction quelconque, le programme continue ici
xxx ; instruction quelconque
xxx ; instruction quelconque
movlw 0x50 ; charger w avec 0x50
call tempo ; appel du sous programme tempo dune dure de 0x50
xxx ; instruction quelconque, le programme continue ici
xxx ; instruction quelconque
movlw 0x10 ; charger w avec 0x10
call tempo ; appel du sous programme tempo dune dure de 0x10
xxx ; instruction quelconque, le programme continue ici

Et nous obtenons des temporisations variables sans devoir crire chaque fois notre
routine de temporisation. Voil, maintenant vous savez ce quest un sous-programme.
Enfantin, nest-ce pas ?

9.28 Linstruction RETLW (RETurn with Literal in W)

Retour de sous-routine avec valeur littrale dans W. Cest une instruction trs simple :
elle quivaut linstruction return, mais permet de sortir dune sous-routine avec une valeur
spcifie dans W.

Syntaxe

retlw k ; k -> (w) puis (pile)->(pc)

86
Bit du registre STATUS affect

Aucun

Exemple

test ; tiquette de dbut de notre sous-programme


btfss mavariable,0 ; teste le bit 0 de mavariable
retlw 0 ; si vaut 0, fin de sous-programme avec (w)=0
retlw 1 ; sinon, on sort avec (w) = 1

Le programme qui a appel la sous-routine connat donc le rsultat de lopration en lisant


le registre w . Lintrt est limit dans cet exemple, mais ceci vous montre comment
procder.

9.29 Linstruction RETFIE (RETurn From IntErrupt)

Retour dinterruption. Nous verrons dans un chapitre spar ce que sont les
interruptions, il serait idiot de caser tout un chapitre dans lexplication dune instruction.
Sachez cependant que cette instruction effectue un retour dinterruption, exactement comme
return effectue un retour de sous-programme, ceci prs que reftie relance automatiquement
les interruptions, il y a donc une opration supplmentaire ralise.

Syntaxe

retfie ; retour dinterruption

Bit du registre STATUS affect

Aucun

9.30 Linstruction CLRF (CLeaR F)

Efface le contenu de lemplacement F. Effacer signifie simplement placer la valeur 0


lemplacement prcis.

Syntaxe

clrf f ; (f) = 0

Bit du registre STATUS affect

Z : Vaut donc toujours 1 aprs cette opration, lintrt est donc pour le moins limit.

Exemple

Clrf mavariable ; (mavariable) = 0

87
9.31 Linstruction CLRW (CLeaR W)

Efface le registre W. Dit autrement, charge la valeur 0 dans le registre de travail.

Syntaxe

clrw ; (w) = 0

Cest une instruction qui nest pas vraiment indispensable, car on pourrait utiliser
linstruction movlw 0 . Cependant, la diffrence de movlw 0, clrw positionne le bit Z.

Bit du registre STATUS affect

Z : Vaut donc toujours 1 aprs cette opration.

9.32 Linstruction CLRWDT (CLeaR WatchDog)

Rarme le chien de garde (watchdog) de votre programme. Nous aborderons la mise en


uvre du watchdog ultrieurement. Sachez cependant que cest un mcanisme trs pratique
qui permet de provoquer un reset automatique de votre PIC en cas de plantage du
programme (parasite par exemple).

Le mcanisme est de toutes faons trs simple comprendre : il sagit pour votre
programme denvoyer cette instruction intervalles rguliers. Si la commande nest pas reue
dans le dlai imparti (programmable), le PIC redmarre ladresse 0x00. Cest exactement
le mcanisme, dit de lhomme mort utilis par les conducteurs de train qui doivent presser
un bouton intervalle rgulier. Si le bouton nest pas press, le train sarrte. On dtecte ainsi
si le conducteur est toujours dans ltat dattention requis (et vivant).

Syntaxe

clrwdt ; (wdt) = 0

Bit du registre STATUS affect

Aucun

9.33 Linstruction COMF (COMplement F)

Effectue le complment 1 du contenu de lemplacement mmoire spcifi. Dit de


faon plus vidente : inverse tous les bits de lemplacement

Syntaxe

comf f , d ; NOT (f) -> (d)

88
Bit du registre STATUS affect

Exemple

movlw B11001010 ; charge valeur dans W


movwf mavariable ; initialise mavariable
comf mavariable,f ; inverse tous les bits de mavariable
; (mavariable) = B00110101

Notez que si vous prcisez w comme destination, vous positionnez le flag Z sans modifier
la variable.

Astuce : si vous prcisez w comme destination, vous pouvez tester si votre variable
vaut 0xFF sans la modifier.

9.34 Linstruction SLEEP (Mise en sommeil)

Place le PIC en mode sommeil. Arrt de lexcution du programme et diminution de la


consommation en sont les rsultats esprs. Il ne se rveillera que sous certaines conditions
que nous verrons plus tard.

Syntaxe

sleep ; Silence, je dors !

Bit du registre STATUS affect

T0, PD : ces bits seront dcrits dans ltude des modes de reset du PIC.

9. 35 Linstruction NOP (No Operation)

Aucune opration. Comme vous devez tre fatigu, et moi aussi, je vous prsente
linstruction qui ne fait rien, qui ne positionne rien, et qui ne modifie rien. On pourrait croire
quelle ne sert rien. En fait elle est surtout utilise pour perdre du temps, par exemple pour
attendre une ou deux instructions, le temps quune acquisition ai pu se faire, par exemple.
Nous lutiliserons donc loccasion.

Syntaxe

nop ; Faire semblant de travailler, cest dj travailler !

Ceci termine lanalyse des 35 instructions utilises normalement dans les PIC mid-
range.

89
Ceci peut vous paratre ardu, mais en pratiquant quelque peu, vous connatrez trs vite
toutes ces instructions par cur. Pensez pour vous consoler que certains processeurs CISC
disposent de plusieurs centaines dinstructions.

9.36 Les instructions obsoltes

Il reste 2 instructions qui taient utilises dans les prcdentes versions de PIC16F. Elles
sont encore reconnues par le PIC16F84 mais leur utilisation est dconseille par
Microchip. En effet, leur compatibilit future nest pas garantie.

Il sagit de linstruction OPTION, qui place le contenu du registre W dans le registre


OPTION_REG, et de linstruction TRIS, qui place le contenu de W dans le registre
TRISA ou TRISB suivant quon utilise TRIS PORTA ou TRIS PORTB.

Ces instructions ne sont plus ncessaires actuellement, car ces registres sont dsormais
accessibles directement laide des instructions classiques.

Je vous conseille donc fortement dviter de les utiliser, sous peine de rencontrer des
problmes avec les futures versions de PIC de Microchip.

Je ne vous les ai donc prsentes que pour vous permettre de comprendre un ventuel
programme crit par quelquun dautre qui, lui, les aurait utilises.

90
10. Les modes dadressage
Les instructions utilisent toutes une manire particulire daccder aux informations
quelles manipulent. Ces mthodes sont appeles modes dadressage . Jai parl de
plusieurs modes dadressage lors de ltude des instructions, vous devriez donc dj avoir
compris ce quest un adressage littral ou immdiat, ou un adressage direct.

Je vais simplement commencer par donner un petit exemple concret de ce quest chaque
mode dadressage. Supposons que vous vouliez mettre empocher de largent :

10.1 Ladressage littral ou immdiat

Avec ladressage immdiat, ou littral, vous pouvez dire :

jempoche 100 .

La valeur fait immdiatement partie de la phrase elle-mme. Jai donn littralement la


valeur concerne. Je nai besoin daucune autre information situe ailleurs pour savoir la
somme que jai empoche.

Exemple

movlw 0x55 ; charger la valeur 0x55 dans W

10.2 Ladressage direct

Avec ladressage direct, vous pouvez dire en allant votre banque :

Je vais empocher le contenu du compte n 123456.

Ici, le renseignement mindiquant o se trouve largent est indiqu directement dans la


phrase. Cependant, il mest ncessaire daller voir dans lemplacement en question (le compte
123456) pour savoir ce que je vais empocher.

En effet, je vais mettre le contenu du compte numro 123456 et non un montant de


123456 (dommage). On ne met donc pas en poche le numro du compte, mais ce que
contient le compte qui possde ce numro. Pour faire lanalogie avec les syntaxes expliques
dans les instructions, je mets (compte 123456) dans ma poche.

Exemple

movf 0x10 , W ; charger le contenu de lemplacement 0x10 dans W

91
10.3 Ladressage indirect

Avec ladressage indirect, vous pouvez imaginer que vous voulez empocher par
procuration largent du compte de votre ami. Or, lui connat son numro de compte mais pas
vous. Vous pouvez donc dire :

Mon ami va me fournir le numro de compte dont je vais empocher le contenu

Vous avez donc plusieurs oprations raliser :


- Tout dabord, demander le numro du compte votre ami (sympa, votre ami)
- Ensuite, vous devez regarder ce que contient ce compte
- Et seulement maintenant vous savez combien vous allez empocher (et lui rendre,
videmment, vu que vous tes honnte).

Ceci permet de dire que vous allez obtenir le numro du compte utiliser indirectement
par lintermdiaire de votre ami.

Vous nempochez donc ni votre ami (le pauvre), ni le numro du compte, mais le contenu
du compte dont le numro est fourni par votre ami. Le chemin daccs est donc beaucoup
plus indirect . (ami)->(compte)->poche

Je rsume donc :
Adressage littral : montant -> poche
Addressage direct : (compte) -> poche
Adressage indirect : (ami)->(compte)->poche

Si vous avez compris ceci, vous avez tout compris. Comme il faut un lment
dindirection (votre ami), ceci se traduit dans le PIC par la prsence de registres particuliers.
Examinons-les donc :

10.3.1 Les registres FSR et INDF

Ceux qui suivent sont dj en train de chercher dans le tableau 4-2 aprs INDF.

INDF signifie INDirect File. Vous le voyez maintenant ? Et oui, cest le fameux registre
de ladresse 0x00. En fait, ce registre nexiste pas vraiment, ce nest quun procd daccs
particulier FSR utilis par le PIC pour des raisons de facilit de construction lectronique
interne.

Sur certains micros, le mode dadressage indirect est spcifi dans linstruction. Dans les
PIC16F, le mode dadressage indirect utilise un pseudo-registre pour y accder. De nouveau,
un mode prsent non rpertori dans la liste des instructions explicites.

Le registre FSR quant lui se trouve ladresse 0x04 dans les 2 banques. Il nest donc
pas ncessaire de changer de banque pour y accder, quelle que soit la banque en cours
dutilisation. Il est, lui, un vritable registre.

Dans lexemple schmatique prcdent, votre ami est reprsent par ce registre FSR.
Ladressage indirect est un peu particulier sur les PIC, puisque cest toujours la mme

92
adresse que se trouvera ladresse de destination. En somme, on peut dire que vous navez
quun seul ami (sniff). Heureusement ce dernier dispose de plusieurs comptes. Comment tout
cela se passe-t-il en pratique ?

Premirement, nous devons crire ladresse pointe (le numro du compte) dans le registre
FSR. Ensuite, nous accdons cette adresse pointe par le registre INDF.

On peut donc dire que INDF est en fait le registre FSR utilis pour accder la case
mmoire. Donc, quand on veut modifier la case mmoire pointe, on modifie FSR, quand on
veut connatre ladresse de la case pointe, on accde galement FSR. Si on veut accder au
contenu de la case pointe, on accde 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 certains PIC, la
zone RAM contient 4 banques (16F876) et donc 512 emplacements. Ladresse complte est
donc une adresse sur 9 bits.

Cette adresse complte est obtenue, en adressage direct, par lajout des bits 7 et 8 sous
forme de RP0et RP1.

Par contre, pour ladressage indirect, ladresse complte est obtenue par lajout du bit 8
sous forme du bit IRP. Ne confondez pas.

Dans le cas du 16F84(A), la Ram tient sur 256 emplacements, et donc peut tre code sur
8 bits. RP1 et IRP sont donc inutiliss, laissez-les de prfrence 0.

Exemple

movlw 0x50 ; chargeons une valeur quelconque


movwf mavariable ; et plaons-la dans la variable mavariable
movlw mavariable ; on charge lADRESSE de mavariable, par
; exemple, dans les leons prcdentes, ctait
; 0x0E. (W) = 0x0E
movwf FSR ; on place ladresse 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 tant le contenu de


lemplacement mmoire point par FSR.

10.4 Quelques exemples

Je vais me rpter, mais les modes dadressages doivent imprativement tre


compris. En multipliant les exemples, jespre que tout le monde pourra comprendre. Pour
les habitus des processeurs divers, excusez ces rptitions.

Nous considrons les registres sont initialiss avec les valeurs de lexemple prcdent.

movlw mavariable

93
Cest de ladressage immdiat ou littral ; donc on charge la valeur de mavariable, ce
qui correspond en ralit son adresse. Donc 0x0E est plac dans (W). Ceci se reconnat au
L de linstruction movlw. Attention, la valeur de mavariable ce nest pas son contenu,
cest son adresse.

movf mavariable , w

Cette fois, cest de ladressage direct, donc, on va ladresse mavariable voir ce quil y a
lintrieur. On y trouve le contenu de mavariable, donc (w) = 0x50 (dans notre exemple).

Pour lassembleur, mavariable sera remplace par 0x0E , donc movf 0x0E,w

movf INDF , w

Maintenant, cest de ladressage indirect. Ce mode dadressage se reconnat


immdiatement par lutilisation du registre INDF. Le PIC va voir dans le registre FSR, et lit
ladresse contenue, dans ce cas 0X0E. Il va ensuite lemplacement vis, et lit le contenu de
cet emplacement. Donc, dans W on aura le contenu de 0x0E, soit 0x50.

movf FSR , w

Ceci est un pige. Cest en effet de ladressage direct. On placera donc dans W le
contenu du registre FSR, donc 0X0E (ladresse pointe) sera mis dans (W).

Je terminerai avec un petit mot pour les spcialistes des microprocesseurs qui lisent ce
cours comme mise niveau.

Vous aurez donc constat que je ne parle nulle part des modes dadressage de type
index (pr et post, avec ou sans offset). En fait, cest tout simplement parce que ce mode
dadressage nexiste pas dans les PIC de type 16F (au contraire dautres familles de PIC)

Il vous faudra donc faire preuve dastuce pour compenser ces lacunes.

Il est logique que la facilit dapprentissage et de mise en uvre se paye par une moins
grande souplesse de cration des applications.

94
11. Ralisation dun programme embarqu
On dsigne gnralement sous la dnomination logiciel embarqu un programme
destin tourner localement sur une carte disposant de fonctionnalits hardwares spcifiques
et cibles, par opposition un logiciel destin tourner sur un PC gnraliste . Par contre,
vu lvolution rcente, lembarqu commence couvrir des ralits fort diffrentes, allant du
smartphone la tablette, ou mme des cartes qui sont quipes de microprocesseurs sur
lesquelles on fait tourner un OS. On tend maintenant rapprocher le terme embarqu du
terme mobile , toutes ces limites devenant progressivement floues. En ce qui nous
concerne, nous parlerons de programme embarqu dans cet ouvrage pour dsigner un
programme destin une carte quipe dun PIC.

Nous allons donc commencer la partie la plus amusante. Nous allons crer de petits
programmes sur une carte PIC.

11.1 Le matriel ncessaire

Utilisez une platine dessais constitue de petits trous relis ensemble par ranges. Les
liaisons seffectuent alors en fils volants. Vous trouverez ces platines chez tous les marchands
dlectronique. Connectez quand mme le quartz au plus prs du PIC, sans fil additionnel.
Pour mettre ces leons en pratique, il vous faudra le matriel suivant (rcuprable et peu
onreux) :

- 1 PIC 16F84 ou 16F84A en botier PDIP et de frquence quelconque


- 2 supports de type tulipe 18 pins / cartement entre les ranges : 0.3
- 1 Quartz de 4MHz
- 2 condensateurs de 27pF
- 1 Led rouge
- 1 Rsistance de 330 ohms.
- 1 bouton-poussoir normalement ouvert (N.O.)
- 1 peu de fil rigide pour les connexions sur la platine dessais
- 1 alimentation stabilise ou un bloc secteur 5V continu stabilis.
-
Si vous ne disposez pas dune alimentation de 5V, vous pouvez, soit utiliser une pile
plate de 4.5V, soit raliser une petite alimentation dont le schma est donn page
suivante.

Il vous faudra dans ce dernier cas :

- 1 Bloc dalimentation secteur, tension continue de 9 15V, pas critique.


- 1 Condensateur de 10 100F/35V.
- 1 Condensateur de 0.1 F
- 1 diode 1N4007, ou autre diode permettant un courant de 1A (pas critique)
- 1 Rgulateur de type 7805.

Cet ensemble ne vous ruinera pas. De plus, les composants pourront tre rcuprs pour
vos prochaines applications. Vous verrez que les PIC peuvent tre utiliss dans des tonnes
dapplications au quotidien. Bien entendu, nomettez pas de vous construire un
programmateur de PIC, ou den acheter un. Voyez lannexe A1.8 pour plus de dtails.

95
11.2 Montage de la platine dessais

- Insrez le PIC dans un des supports tulipe.


- Insrez le support restant dans la platine dessais, et procdez aux connexions suivant le
schma ci-joint.
- Vrifiez tout avant de connecter lalimentation.

Une fois tout ceci fait, vrifiez une dernire fois, sans placer le PIC avec son support
dans le support de la platine, puis mettez sous tension. Vrifiez si les tensions sont correctes
au niveau des broches dalimentation du PIC.

Schma de connexion du PIC (noubliez pas de relier MCLR Vdd)

Schma de la petite alimentation stabilise (si ncessaire)

96
11.3 Cration du projet

Vous tes maintenant prt commencer les exprimentations.

Effectuez une copie de votre fichier m16F84.asm, et renommez cette copie Led_cli.asm.
Lancez MPLAB et rpondez non si on vous demande si vous voulez charger Essai1.

Dans MPLAB, vous savez maintenant crer un projet. Crez donc le projet Led_cli
dans votre rpertoire de travail (project->new project). Si vous avez une fentre untitled
lcran, fermez-la pralablement.

Si vous utilisez une version plus rcente de MPLAB qui vous demande de choisir le
type dexcutable, choisissez Absolute .

Noubliez pas bien sr douvrir votre fichier Led_cli.asm .De nouveau, ce fichier est
disponible termin en annexe.

11.4 Edition du fichier source

Compltez le cadre den-tte suivant votre dsir. Je vous indique ci-dessous un


exemple. Prenez lhabitude de toujours documenter vos programmes. Ce nest pas un luxe,
cest impratif 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. *
;**************************************************************************
; *
; NOM: LED-CLI *
; Date: 09/02/2001 *
; Version: 1.0 *
; Circuit: Platine d'essais *
; Auteur: Bigonoff *
;**************************************************************************
; *
; Fichier requis: P16F84.inc *
; *
;**************************************************************************
; *
; Notes: Ce petit programme permet de faire clignoter une LED *
; sur le port A.2 une frquence de 1Hz *
; Ce programme fait partie de la leon 6 des cours *
; *
;**************************************************************************

11.5 Choix de la configuration

Plus bas dans le fichier, vous trouverez ceci :


__CONFIG _CP_OFF & _WDT_ON & _PWRTE_ON & _HS_OSC

; '__CONFIG' prcise les paramtres encods dans le processeur au moment de

97
; la programmation. Les dfinitions sont dans le fichier include.
; Voici les valeurs et leurs dfinitions :

;_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 rseau RC

Jai inclus les commentaires dans le fichier de faon ce quil soit plus rapidement
modifiable sans devoir recourir au datasheet. Je vais donner un brin dexplication.

Remarquez quon effectue un ET logique (&) entre les diffrentes valeurs, les niveaux
actifs sont donc des niveaux 0, puisquun AND ne permet dimposer que des 0 . Vous
devez donc prciser toutes les valeurs que vous nutilisez pas sans quoi vous ne pourriez pas
forcer les 1 correspondants.

Le premier paramtre prcise si votre PIC sera protg ou non contre la lecture la fin
de la programmation. Laissez ici ce paramtre sur CP_OFF = non protg.

Le second paramtre prcise 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_ON pour prciser que vous utilisez un reset scuris , donc
avec un allongement du temps avant dmarrage. Ceci vous met labri des alimentations un
peu lentes dmarrer. Jexpliquerai ceci plus tard.

Enfin, vient le fonctionnement de loscillateur que vous allez utiliser. Le tableau 8-1 page
40 donne les valeurs recommandes en fonction des frquences utilises pour un PIC de
10MHz.

Retenez que la valeur _HS_OSC convient pour les frquences leves, ce qui le cas
partir de 4Mhz. Notez qu cette frquence le mode XT fonctionnerait galement.

Il est important de ne pas utiliser _RC_OSC si on utilise un quartz. Ce paramtre est


rserv un fonctionnement par rseau R/C tel que dessin figure 8-7 page 41.

Le fait dutiliser le paramtre RC avec une horloge externe peut entraner la


destruction du PIC.

Mme, si en pratique, les PIC sont des composants trs 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 & _HS_OSC

98
11.6 Le registre OPTION

Si vous regardez le tableau 4-2, vous constaterez que ce registre se trouve ladresse
0x81, donc dans la banque1. Dans les fichiers include de MPLAB, ce registre est
dclar avec le nom OPTION_REG.

Cest donc ce nom que vous devrez utiliser. Nous allons le dtailler ici. Ce registre est un
registre de bits, cest dire que chaque bit a un rle particulier. Le tableau de la page 16
reprsente le contenu de ce registre :

b7 : RBPU

Quand ce bit est mis 0 (actif niveau bas), une rsistance de rappel au +5 volts est
place sur chaque pin du PORTB. Nous verrons dans cette leon le fonctionnement du
PORTB. Si vous regardez notre schma, vous constaterez que le bouton-poussoir connect sur
RB2 place cette pin la masse si on le presse.

Il nexiste aucune possibilit pour envoyer du +5V dans notre schma. En validant
cette option, la rsistance interne force la pin RB2 1 lorsque le bouton nest pas press.

Notez que cette option valide les rsistances sur toutes les pins du PORTB. Il nest donc
pas possible de choisir certaines rsistances en particulier. De mme cette fonction nexiste
que pour le PORTB.

Vous constatez donc dj que tous les ports ne sont pas identiques : il faut y penser au
moment de la conception dun circuit. Dans notre cas, nous mettrons donc les rsistances en
service avec b7 = 0. Retenez que lorsque vous dveloppez une application base de PIC,
vous devez penser au schma et au logiciel simultanment, cest une habitude prendre.

b6 : INTEDG

Donne, dans le cas o on utilise les interruptions sur RB0, le sens de dclenchement de
linterruption. Si b6 = 1, on a interruption si le niveau sur RB0 passe de 0 vers 1. Si b6 = 0,
linterruption seffectuera lors de la transition de 1 vers 0. Comme nous nutilisons pas les
interruptions dans cette leon, nous pouvons laisser b6 = 0.

b5 : TOCS

Non, notre PIC ne souffre pas de troubles obsessionnels compulsifs. Ce bit dtermine
simplement le fonctionnement du timer0, que nous verrons bientt. Retenez que le timer0 est
incrment soit en fonction de lhorloge interne (synchronis au programme) , dans ce cas b5
= 0, soit il compte les impulsions reues sur la pin RA4, dans ce cas b5=1.

Comme ce dernier mode ncessite un circuit de gnration dimpulsions externe, nous


utiliserons pour le timer0 lhorloge interne, donc b5 = 0

99
b4 : TOSE

Donne, pour le cas ou le bit 5 serait 1, le sens de la transition qui dtermine 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 prdiviseur. Quest-ce que cest ? Et bien tout
simplement, ceci indique le nombre dimpulsions qui devront tre reues pour provoquer une
incrmentation de la destination. Nous y reviendrons en dtail avec le fonctionnement du
tmr0.

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

b2, b1,b0 : PS2,PS1,PS0

Ces trois bits dterminent la valeur de prdivision pour le registre dtermin ci-dessus. Il y
a donc 8 valeurs possibles, montres dans le petit tableau de la page 16.

Remarquez que les valeurs sont diffrentes pour le watchdog et pour tmr0. En effet, il ny
a pas de division par 1 pour ce dernier registre.

Si vous dsirez ne pas utiliser de prdiviseur du tout, la seule mthode est de mettre b3=1
(prdiviseur sur watchdog) et PS2 PS0 0. Dans ce cas : pas de prdiviseur sur tmr0, et
prdiviseur 1 sur watchdog, ce qui correspond pas de prdiviseur non plus. Nous mettrons
donc b2=b1=b0= 0.

11.7 Edition du programme

Voil encore un registre vu. Nous utiliserons donc la valeur B00001000 pour notre
programme, soit 0x08. Jai lhabitude de ne pas traner des valeurs fixes travers mes
programmes, afin den faciliter la maintenance. Je place ces valeurs en dbut de programme
en utilisant des assignations ou des dfinitions.

Lassignation est dj cre plus bas dans le programme. Jai cr une constante que jai
appele OPTIONVAL et qui contiendra la valeur placer plus tard dans le registre
OPTION_REG. Je rappelle que les constantes noccupent pas de place dans le PIC, elles
sont simplement remplaces par lassembleur au moment de lassemblage. Elles servent
faciliter la lecture du programme.

Cherchez donc plus bas dans le programme aprs les assignations, et remplacez la valeur
affecte OPTIONVAL par celle que nous avons trouve et ajoutez vos commentaires.

100
Supprimez lassignation 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'08 ; Valeur registre option


; Rsistance pull-up ON
; Pas de prscaler

Descendons encore jusqu la zone des dfinitions. 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 les registres daccs sappelant PORTA
(pour le port A) et PORTB (pour le port B), nous utiliserons des directives #DEFINE
permettant dintgrer f et n en mme temps.

Nous voyons sur le schma que la LED est connecte sur le bit 2 du port A. Le bouton-
poussoir est connect sur le bit 2 du port B. Nous effaons donc les dfinitions dexemple, et
nous les remplaons par les ntres. 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 quil ne sagisse pas dun mot-cl. Pas question par exemple dutiliser STATUS ou
encore MOVLW, bien que ce dernier exemple soit tir par les cheveux, cela pourrait vous
arriver un jour dutiliser un mot rserv par inadvertance. A quoi servent les dfinitions ?

Et bien supposons que vous dcidez 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. De plus, lorsquon lira dans le code source le terme LED, ce sera bien
plus explicite que PORTA,2 . Souvenez-vous de donner de prfrence la priorit la
lisibilit et la maintenance de votre code, du moins tant que vous ntes pas contraint
recourir diverses optimisations.

On descend encore un peu, et on arrive dans la zone des macros. Nous nen avons pas
vraiment besoin ici, mais nous allons quant mme les utiliser titre dexemple.
Effacez la macro donne titre dexemple et entrons celles-ci.

;*********************************************************************
; MACRO *
;*********************************************************************
LEDON macro
bsf LED
endm

LEDOFF macro

101
bcf LED
endm

la premire colonne donne le nom de la macro (ici, 2 macros, LEDON et LEDOFF). La


directive macro signifie dbut de la macro la directive endm signifie fin de la macro.
Notez que les macros peuvent videmment comporter plusieurs lignes de code.

Remarquez quune macro peut utiliser une dfinition (LED), tout ceci nest que simple
traitement de texte.

Prenons notre exemple : quand nous utiliserons la ligne suivante dans notre
programme (attention, ne pas mettre le nom de la macro en premire colonne lors de
lutilisation) :

LEDON

Au moment de lassemblage, notre assembleur remplacera LEDON par :

bsf LED

Il remplacera ensuite LED par PORTA,2. Ce qui fait quen ralit nous obtiendrons :

bsf PORTA , 2

Nous avons donc obtenu une facilit dcriture et de maintenance. Gardez lesprit 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 copies 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 ncessit. Effacez donc les 2 variables prsentes, car elles sont utilises dans les routines
dinterruption que nous nutiliserons pas ici.

;*********************************************************************
; DECLARATIONS DE VARIABLES *
;*********************************************************************
CBLOCK 0x00C ; dbut de la zone variables

ENDC ; Fin de la zone

A la directive ORG 0x00, laissons lappel vers la routine dinitialisation. Tout


programme comporte en effet une tape dinitialisation des variables et des registres. Prenez
lhabitude de sparer cette initialisation du reste du programme.

Comme nous nutiliserons pas les interruptions, supprimez tout ce qui suit jusqu la
routine dinitialisation, vous obtenez :

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

org 0x000 ; Adresse de dpart aprs reset


goto init ; Adresse 0: initialiser

;*********************************************************************

102
; INITIALISATIONS *
;*********************************************************************
init:
suite du programme

A ce stade, avant de poursuivre, nous allons tudier les registres dont nous allons nous
servir, et tout dabord :

11.8 Le registre PORTA

Ce registre est un peu particulier, puisquil donne directement accs au monde extrieur.
Cest en effet ce registre qui reprsente limage (numrique 0/1) des pins RA0 RA4, soit 5
pins. Si vous suivez toujours, cest ce registre qui va servir allumer la LED.

Ce registre se situe ladresse 05H, dans la banque 0. Chaque bit de ce registre


reprsente une pin. Donc, seuls 5 bits sont utiliss. Pour crire sur une pin en sortie, on place
le bit correspondant 1 ou 0, selon le niveau souhait.

Par exemple :

bsf PORTA , 1 ; envoyer niveau 1 sur RA1

place un niveau +5V (+Vdd pour tre prcis) sur la pin RA1. Notez quil faut pour cela
que cette pin soit configure en sortie (voir TRISA).

Pour tester une entre, on pourra par exemple utiliser

btfss PORTA,3 ; tester RA3 et sauter si vaut +1 (>2.5V)

Pour les lectroniciens, vous avez le schma interne des bits RA0 RA3 figure 5-1 page
21. Vous voyez que la sortie peut tre place au niveau haut ou bas grce aux deux transistors
de sortie (montage push-pull). Quand ces pins sont programmes en entre, elles sont
sensibles des niveaux 0/5V. Le niveau de transition dpend du modle de PIC, mais se
situe gnralement la moiti de la tension dalimentation. Une entre en lair est vue
comme tant au niveau 0. Evitez cependant ce cas pour les problmes de grande sensibilit
aux parasites.

Pour la pin RA4, figure 5-2, en sortie elle est de type drain ouvert, et en entre elle
comporte un trigger de Schmitt. Si vous navez pas les connaissances en lectronique pour
comprendre ces concepts, mmorisez seulement que cette pin, en sortie, peut imposer un
niveau 0 (Vss) mais pas un niveau 1 (Vdd) : Si vous reliez une led entre RA4 et la masse,
vous ne pourrez jamais lallumer.

Les PORTS disposent dune diode de protection vers le 0V et vers le 5V. De sorte quavec
une simple rsistance srie, vous pouvez envoyer des signaux vers ces pins qui sortent de la
gamme de tension Vss/Vdd.

Attention : Si vous envoyez une tension telle que le courant drain par les diodes de
limitation vers Vdd devient suprieur au courant absorb par le PIC, ce courant va
alimenter votre alimentation, qui sera contrainte de labsorber. Si votre alimentation nest

103
pas conue pour rguler une tension provenant dun courant inverse, le risque est que Vdd
augmente de telle faon quil provoque le claquage du PIC.

Nutilisez donc cette astuce de connexion que si vos connaissances en lectronique


vous permettent de parfaitement apprhender les consquences de ce mode dutilisation.

De nouveau, la pin RA4 fait exception cette rgle, car elle ne dispose que dune
diode vers la masse.

Pour tous, retenez que les pins RA0 RA3 peuvent tre utilises en entre avec des
niveaux 0/5V ou en sortie en envoyant du 0V ou du 5V. Quant la pin RA4, en sortie, elle ne
peut pas envoyer du 5V.

Elle ne peut que mettre la sortie en lair sur niveau 1 et la forcer la masse sur niveau
0. En entre, elle comporte en outre un dispositif permettant dempcher les hsitations
lorsque le niveau prsent nest pas franc. Par exemple lorsque le niveau varie lentement de
0V 5V.

Tenez compte de ces spcificits lorsque vous construirez votre montage. Par exemple, si
nous avions plac la LED telle quelle entre RA4 et Vss, elle ne se serait jamais allume.

A partir de la page 75 du datasheet, chapitre 11, vous avez les caractristiques maximales
de fonctionnement du PIC. Vous pouvez retenir simplement de vous limiter utiliser 20mA
maximum par pin de sortie, avec un maximum total de 80mA pour le PORTA, et 150mA pour
le PORTB.

Si vous utilisez des caractristiques proches de cette limite, analysez les tableaux avec
plus de prcision pour obtenir les limites en puissance et t ainsi que les chutes de tension
engendres. Nous naurons pas ce genre de problme dans nos exercices. La consommation
de notre LED sur RA2 rpond la formule approximative suivante :

Intensit : (5V Tension Led) / 330 ohms, soit (5V 1,75V) / 330 ohms = 9,85mA.

Notez, et cest commun un grand nombre de microcontrleurs, quil est prfrable


de commander une charge sur niveau 0 (charge connecte entre la pin et Vdd) que sur
niveau 1 (charge connecte entre la pin et Vss, comme la led de notre montage).

Ceci pour la bonne raison que les chutes de tension (voir partie lectrique du datasheet)
sur envoi dun niveau 1 sont plus importantes que pour lenvoi dun niveau 0. Ceci est d aux
technologies utilises.

Si jai utilis la mauvaise faon de procder lectroniquement, cest parce quen


procdant de la bonne faon, tout le raisonnement se retrouve invers : il faut envoyer 0
pour allumer la LED, et 1 pour lteindre. Sagissant dun cours didactique concernant la
programmation, jai prfr rester le plus intuitif possible.

104
11.8.1 Fonctionnement particulier des PORTS

Souvenez- vous que toute opration portant sur un bit unique met en uvre le
principe read/modify/write (lecture/modification/criture). Ceci est videmment vrai pour
les oprations concernant les ports, par exemple lallumage et lextinction de notre LED.

Par exemple, si vous crivez bsf PORTA,1, le PIC procde de la manire suivante :

1) Le PORTA est lu en intgralit (pins en entre et en sortie)


2) Le bit 1 est mis 1
3) Tout le PORTA est rcrit (nagit que sur les pins en sortie).

Consquences importantes

Attention, ce qui suit est important comprendre, le problme classique tant la


fameuse pin RA4 configure en sortie et qui semble changer de valeur toute seule.

Supposons par exemple que le RA4 soit en sortie et mis 1 dans votre programme :

bsf PORTA,4 ; libre la ligne RA4 (on ne force plus un niveau 0 ventuel)

Comme il est drain ouvert, supposons quune lectronique externe le force actuellement
0 : Vous pouvez fort bien, par exemple, relier la pin RA4 de 2 PIC diffrents pour obtenir
une sorte de ou logique. Ou, cas classique, utiliser RA4 pour piloter lhorloge dun bus IC.

Si vous effectuez maintenant lopration suivante :

bsf PORTA , 1 ; mettre RA1 1

Le PIC va donc procder comme suit :

- Lecture de PORTA : Donc, le pic constate que RA4 vaut 0 (alors que votre programme la
plac 1)
- Mettre le bit 1 1
- criture du PORTA complet, donc criture non seulement de RA1 = 1 mais aussi de RA4
= 0.

Moralit, cest maintenant votre programme (et donc votre PIC), qui bloque la ligne RA4
0 (alors que vous aviez crit bsf PORTA,4). Si la ligne est libre par lautre composant
elle sera maintenant bloque par votre PIC sans espoir de libration.

Cest donc un mcanisme dont il faut tenir compte.

Pire, si vous crivez plus simplement ceci, en admettant RB1 et RB4 soient en sortie :

bsf PORTB,1 ; on met RB1 1


bsf PORTB,4 ; on met RB4 1

Le rsultat vous semble vident, puisque RB1 et RB4 sont placs tous les deux 1. Or,
de nouveau, il y a un pige cach. En effet, imaginez que sur RB1 vous avez plac une charge
fortement capacitive. La sortie, constitue de la rsistance interne de RB1 et du condensateur

105
de la charge, forme ainsi un rseau RC. Ce rseau a une certaine constante de temps. Il faut
donc un certain temps la sortie RB1 pour atteindre Vdd/2 et donc dtre considre comme
un tat 1. Vous comprenez maintenant ce qui va arriver ?

En fait, au moment du bsf PORTB,4, il va se passer ceci :

- Le PIC lit PORTB, mais RB1 nest pas encore arriv une tension suffisante et donc est
lu 0
- Le bit 4 est forc 1
- Le PIC rcrit le PORTB, et donc remet RB1 0.

Moralit, RB1 ne passera pas 1 et restera (dans ce cas prcis) 0. Si on tudie le


datasheet au niveau des caractristiques lectriques, on saperoit quon peut rencontrer ce cas
mme si on respecte le dit datasheet. Par contre, toujours en respectant le datasheet, le temps
dtablissement restera infrieur un temps de cycle dinstruction. Moralit, pour viter ce
cas, il vous faut ajouter une instruction nop :

bsf PORTB,1 ; on met RB1 1


nop ; on attend dtre certain que le niveau soit stable
bsf PORTB,4 ; on met RB4 1

Donc, sauf si vous avez calcul exactement le temps dtablissement de vos tensions
de sortie en fonction de vos charges, de la frquence du PIC, et du cycle interne des
instructions :

Placez toujours une instruction nop entre deux instructions de manipulation


successives de deux pins situes sur le mme port.

Par contre, souvenez-vous : pour RA4, nop ou pas, rien ny changera, vous devez
tenir ventuellement compte de cette possibilit en conservant en mmoire ltat que votre
programme est cens imposer RA4. Sur dautres PIC, comme les 18F, ce problme nexiste
plus.

11.9 Le registre TRISA

Ce registre est situ la mme adresse que PORTA, mais dans la banque 1. Son adresse
complte sur 8 bits est donc 0x85.

Ce registre est dun fonctionnement trs simple et est li au fonctionnement du PORTA.

Chaque bit positionn 1 configure la pin correspondante en entre. Chaque bit 0


configure la pin en sortie.

Au reset du PIC, toutes les pins sont mises en entre, afin de ne pas envoyer des signaux
non dsirs sur les pins. Les bits de TRISA seront donc mis 1 lors de chaque reset.

Notez galement que, comme il ny a que 5 pins utilises sur le PORTA, seuls 5 bits
(b0/b4) seront utiliss sur TRISA.

106
Exemple dutilisation

Prenons en exemple le schma de notre petit circuit : que devons-nous faire pour allumer
la LED ? (PS : ne mettez pas pour linstant ces instructions dans votre projet).

Premirement, nous devons configurer TRISA et mettre le bit2 (RA2) en sortie.

Comme le registre TRISA se trouve en banque1, et que ladressage direct nutilise que 7
bits, nous devrons donc mettre le bit RP0 du registre STATUS au niveau 1 (voir chapitres
prcdents).

Ensuite, nous pourrons envoyer un niveau 1 sur PORTA, correspondant 5V sur la pin
RA2. La squence correcte sera donc :
bsf STATUS , RP0 ; on passe en banque 1
bcf TRISA , 2 ; bit 2 de TRISA 0 = sortie pour RA2
bcf STATUS , RP0 ; on repasse en banque 0
bsf PORTA , 2 ; on envoie 5V sur RA2 : la LED sallume
.
.
.
bcf PORTA , 2 ; 0V sur RA2, la LED steint

Notez que comme RA2 restera en sortie durant tout le programme (tant donn le schma
de notre application), nous placerons la valeur de TRISA dans la routine dinitialisation.
Lorsque nous voudrons allumer ou teindre la LED dans le programme principal, nous
naurons donc plus quune seule instruction utiliser. On commence entrer dans le concret.

11.10 Les registres PORTB et TRISB

Ces registres fonctionnent exactement de la mme manire que PORTA et TRISA, mais
concernent bien entendu les 8 pins RB. Tous les bits sont donc utiliss dans ce cas.

Voyons maintenant les particularits du PORTB. Nous en avons dj vu une, puisque


les entres du PORTB peuvent tre connectes une rsistance de rappel au +5V de manire
interne.

La slection seffectuant par le bit 7 du registre OPTION. Le schma interne visible


figures 5-3 et 5-4 page 23 du datasheet vous montre que les bits b0 et b4/b7 peuvent tre
utiliss comme source dinterruption, le bit 0 peut de plus tre utilis de manire autonome
pour gnrer un autre type dinterruption.

Nous verrons le fonctionnement des interruptions dans un autre chapitre. Sachez


cependant dj que les schmas que vous concevrez vous-mme dans le futur devront tenir
compte des particularits des PORTs.

Note :

Aprs un reset, vous vous demandez peut-tre quel est ltat de tel ou tel registre ?

107
Vous trouverez ces explications dans le tableau de la page 14. Vous voyez quaprs un
reset, le registre OPTION_REG voit tous ses bits mis 1. Vous devez donc spcifier
leffacement du bit7 pour valider les rsistances de rappel au +5V.

11.11 Exemple dapplication

Toujours en partant de notre schma, nous dsirons allumer la LED lorsque nous
pressons le bouton, et lteindre lorsque nous le relchons. Voici un exemple du programme
ncessaire (attention, prenez garde que le niveau sur RB2 passe 0 lorsque le bouton est
enfonc (connexion la masse)

bsf STATUS , RP0 ; on passe en banque 1


bcf OPTION_REG, NOT_RBPU ; rsistance de rappel en service
bcf TRISA , 2 ; bit 2 de TRISA 0 = sortie pour RA2
; inutile de configurer TRISB, car il est
; en entre par dfaut au reset du PIC
bcf STATUS , RP0 ; on repasse en banque 0
boucle ; tiquette dbut de la boucle principale
btfss PORTB , 2 ; tester RB2, sauter si vaut 1
bsf PORTA , 2 ; RB2 vaut 0, donc on allume la LED
btfsc PORTB , 2 ; tester RB2, sauter si vaut 0
bcf PORTA , 2 ; RB2 vaut 1, donc LED teinte
goto boucle ; et on recommence

11.12 La routine dinitialisation

Examinons les instructions contenues partir de ltiquette init

Les 2 premires lignes ,

clrf PORTA ; Sorties portA 0


clrf PORTB ; sorties portB 0

prparent le forage des sorties des PORTs 0. Comme a, lorsque vous configurerez les
ports en sortie, ils enverront par dfaut des niveaux 0V. Si votre lectronique demande, pour
tre scurise, dautres valeurs, vous de vous en charger.

La ligne suivante permet de se connecter sur la banque1. Jusqu nouvel ordre, les
instructions suivantes utilisent des registres situs banque1.

bsf STATUS,RP0 ; passer en banque 1

Ensuite, nous trouvons ceci :

movlw OPTIONVAL ; charger masque


movwf OPTION_REG ; initialiser registre option

Rappelez-vous que OPTIONVAL est une constante. Sa valeur a t dfinie


prcdemment par nos soins 0x08. Cette valeur sera envoye ici dans le registre OPTION
(OPTION_REG). Souvenez-vous que OPTION_REG est le nom dclar dans MPLAB
pour le registre OPTION.

108
Suit la petite routine suivante, destine effacer la RAM. Souvenez-vous, et cest trs
important, qu la mise sous tension, la RAM contient des valeurs alatoires. Pour viter les
mauvaises surprises, jai intgr cette routine chaque dmarrage, qui assure que la RAM ne
contienne que des 0. Cette routine nest nullement indispensable si vous initialisez
correctement vos variables avant de les utiliser. Il sagit juste dune prcaution, mais cette
prcaution ne vous cote quun peu despace en mmoire programme, pourquoi sen priver ?
Certains pourraient avancer largument de perte de temps lexcution, mais ces
instructions ne sont excutes qu la mise sous tension ou au reset du PIC, a naffecte donc
en rien la vitesse de traitement du programme principal. Effet secondaire : tant donn que
nous forons tous les emplacements de la RAM 0, nous avons alors une parfaite
correspondance entre les valeurs affiches dans le simulateur et celles se trouvant dans notre
PIC : voici dj des bugs potentiels beaucoup plus faciles localiser.

; Effacer RAM
; ------------
movlw 0x0c ; initialisation pointeur
movwf FSR ; pointeur d'adressage indirect
init1
clrf INDF ; effacer ram pointe par FSR
incf FSR,f ; pointer sur suivant
btfss FSR,6 ; tester si fin zone atteinte (>=0x40)
goto init1 ; non, boucler
btfss FSR,4 ; tester si fin zone atteinte (>=0x50)
goto init1 ; non, boucler
xxxxx ; ici se trouve la suite du programme

Voil donc un exemple concret de lutilisation de ladressage indirect (notez lutilisation de


INDF, qui caractrise ce mode dadressage).

En premier lieu, on initialise le pointeur vers la zone manipuler (ici, la zone RAM
utilisateur). Cette zone commence ladresse 0x0C (voir tableau 4-2) et se termine ladresse
0x4F incluse. La zone situe dans la banque 1 nexiste pas pour ce PIC (image de la banque
0) et na donc pas besoin dtre initialise.

Puis vous trouvez linstruction clrf INDF, qui signifie donc, si vous avez suivi, non pas
effacer le registre INDF (qui nexiste pas), mais effacer lemplacement mmoire dont
ladresse se trouve dans le registre FSR. On efface donc la mmoire situe lemplacement
0x0C.

Vient ensuite lincrmentation de FSR, donc, maintenant, FSR pointe sur 0x0D.

On trouve alors 2 tests. Pour sortir de cette routine et arriver la ligne que jai indique
ici se trouve la suite , il faudra donc viter les 2 lignes goto.

Vous ne tombez sur le premier goto que si le bit 6 de FSR vaut 0, sinon vous le sautez.
Pour sauter ce goto (skip), FSR devra donc valoir au moins B01000000, ou encore 0x40.
A ce moment, les adresses 0x0C 0x3F auront dj t mises 0.

On arrive au deuxime test. Le goto suivant sera excut seulement si le bit 4 de FSR
vaut 0. Dans le cas contraire, il sera saut. On arrivera donc la ligne ici se trouve la suite
uniquement lorsque les bits 4 et 6 de FSR seront gaux 1. Ceci donne ladresse suivante :
B01010000, soit 0x50.

109
Notez pour ceux qui ont suivi que vous auriez pu galement utiliser un compteur de
boucles et vous servir de linstruction decfsz. Ceci aurait cependant ncessit lutilisation
dune variable. Or, noubliez pas que votre variable se serait efface elle-mme par la
prsente routine, avec plantage du programme, ce qui aurait ncessit des oprations
supplmentaires. La mthode prsente ici est de fait la plus simple et la plus efficace.

Effacez ensuite les lignes suivantes :

bcf TRISA,0 ; Bit PORTA.0 en sortie (exemple)


bcf STATUS,RP0 ; Slectionner banque 0
movlw INTERMASK ; masque interruption
movwf INTCON ; charger interrupt control

car elles ne nous intressent pas pour notre programme.

Voyons maintenant ce que nous devons ajouter :

Tout dabord, nous devons initialiser RA2 en sortie, pour pourvoir agir sur la LED.
Linstruction sera donc (souvenez-vous, nous sommes toujours bien en banque 1) :

bcf TRISA , 2

Or, nous avons dclar dans les dfinitions que LED tait un alias de PORTA,2 .
Pour permettre un remplacement facile de la LED sur une autre pin, que se passe-t-il si nous
crivons ?

bcf LED

Certains vont dire on teint la LED . Et bien, pas du tout. Pour ceux qui ont dj
saisi lastuce : toutes les flicitations. En fait, cette instruction sera, comme dhabitude,
btement remplace par lassembleur par la ligne suivante :

bcf PORTA , 2

Autrement, aprs une nouvelle substitution avec la valeur de PORTA dclare dans notre
fichier p16F84.inc, par :

bcf 0x05 , 2

Or, RP0 est toujours positionn 1 au moment de lexcution de cette ligne. On pointe
donc toujours sur la banque 1. Si vous regardez ce quil y a ladresse 0x05 dans la
banque1, cest dire ladresse 0x85, vous trouvez TRISA. Ainsi, lopration a plac RA2
en sortie.

En changeant simplement la dfinition de LED au dbut du programme, vous pouvez


changer toutes les rfrences RA2 dans tout le programme, mme pour TRISA.
Corollaire : ce nest pas parce que vous utilisez un #define que a rsout comme par magie la
ncessit de slectionner la banque correcte, restez toujours attentif.

Placez un petit commentaire den-tte, et vous obtenez :

110
; initialisations spcifiques
; ---------------------------

bcf LED ; LED en sortie (banque1)

Repassez ensuite en banque 0 avant de quitter linitialisation. Cest une bonne pratique,
car beaucoup derreurs sont provoques par oublis de changements de banque, ajoutez donc :

bcf STATUS , RP0 ; Repasser en banque 0

Terminez avec la ligne

goto start

qui envoie vers le programme principal. Pour le moment, cela peut paratre inutile, car le
programme principal suit directement cette instruction, mais nous allons ajouter plus loin un
sous-programme qui sera intercal entre les deux.

Voici quoi devrait maintenant ressembler votre routine dinitialisation, que vous
devriez maintenant avoir entirement comprise (pas besoin dune aspirine?). Rassurez-vous,
cela a lair dur au dbut, mais, une fois assimil, cest trs simple. De plus, vous avez vu
pratiquement tout ce quil faut savoir pour raliser un programme sans routine dinterruption.

;*********************************************************************
; INITIALISATIONS *
;*********************************************************************
init
clrf PORTA ; Sorties portA 0
clrf PORTB ; sorties portB 0
clrf EEADR ; permet de diminuer la consommation
bsf STATUS , RP0 ; slectionner banque 1
movlw OPTIONVAL ; charger masque
movwf OPTION_REG ; initialiser registre option

; Effacer RAM
; ------------
movlw 0x0c ; initialisation pointeur
movwf FSR ; pointeur d'adressage indirect
init1
clrf INDF ; effacer ram
incf FSR,f ; pointer sur suivant
btfss FSR,6 ; tester si fin zone atteinte (>=0x40)
goto init1 ; non, boucler
btfss FSR,4 ; tester si fin zone atteinte (>=0x50)
goto init1 ; non, boucler

; initialisations spcifiques
; ---------------------------
bcf LED ; LED en sortie (banque1)
bcf STATUS , RP0 ; repasser banque 0
goto start ; sauter au programme principal

Descendons maintenant dans le programme principal, et supprimons la ligne :

clrwdt ; effacer watchdog

111
11.13 Les rsultats de lassemblage

Lancez lassemblage par la touche <F10>.


Notez au passage quon appelle assemblage la traduction (simple) dun programme crit
en langage dassemblage en un excutable. Par contre, on appelle compilation la
conversion (complexe) dun code source en langage haut niveau en un excutable.

Dans la fentre de rsultat de lassemblage, vous devez trouver une ligne du type

Message[302] D:\DOCUME~1\LESSONS\DATAPIC\LED_CLI.ASM 101 : Register in operand


not in bank 0. Ensure that bank bits are correct.

Ceci est un message davertissement (warning) qui vous signale qu la ligne 101 (dans
mon cas, mais suivant vos espaces ou commentaires, vous aurez un autre numro de ligne),
vous avez accd un registre qui nest pas situ en banque 0.

MPASM vous demande de vrifier que votre bit RP0 est positionn correctement.
Allez dans l diteur sur la ligne dont vous avez le numro (101 dans mon cas). Vous tombez
sur la ligne :

movwf OPTION_REG ; initialiser registre option

Un coup dil sur le tableau 4-2 vous indique que le registre OPTION est dans la
banque1. Mais comme votre RP0 a t positionn 1 cet endroit, il ny a pas de problme.
Quand vous aurez ralis de gros programmes, vous aurez normment de warning de ce
type . Si vous voulez viter ces warnings de banque, ajoutez la directive

Errorlevel 302

directement sous la ligne #include de votre fichier source. Le - signifie que vous retirez
ce message des messages actifs, et le 302 est le numro du warning viter. Ce numro
est indiqu entre crochets dans le message renvoy : Message[302]. Attention cependant
quenlever des warnings signifie que MPASM ne surveille plus ce point pour vous. Vous
pouvez remettre les warnings en service nimporte quel endroit de votre code en utilisant le
signe + la place du signe - . Une bonne pratique consiste donc vrifier une zone
donne de votre programme, puis de ne supprimer les warnings que pour cette zone, une fois
oprationnelle et teste.

11.14 Le programme principal

Nous voulons faire clignoter notre LED une frquence de 1Hz (1 clignotement par
seconde) . Lorsque, il y a plusieurs annes, jai dcid dcrire la premire version de ce
cours, en chapitre spars sur un forum, jtais loin de penser que le clignotement de la led
allait devenir un grand classique de lapprentissage des microcontrleurs. Cet exercice est
maintenant devenu comme allant de soi , ce que je trouve trs amusant.

112
Bref, nous allons de ce fait crer un programme de la forme :

debut
Jallume la LED
Jattends seconde
Jteins la LED
Jattends seconde
Je retourne au dbut

Ah ben oui, faites attention au pige grossier : pour obtenir un clignotement 1Hz il faut
temporiser 500ms et non 1 s.

Nous voyons que nous utilisons 2 fois la temporisation de seconde. Nous crerons donc
un sous-programme que nous appellerons tempo . Notre programme principal aura donc
laspect suivant :

start
bsf LED ; allumer la LED
call tempo ; appeler la tempo de 0.5s
bcf LED ; teindre LED
call tempo ; appeler la tempo de 0.5s
goto start ; boucler

On aurait pu crire galement (en utilisant nos macros)

start
LEDON ; allumer la LED
call tempo ; appeler la tempo de 0.5s
LEDOFF ; teindre LED
call tempo ; appeler la tempo de 0.5s
goto start ; boucler

Choisissez la mthode que vous prfrez. Limportant, cest davoir compris les deux
mthodes. Je vous rappelle cependant que la seconde mthode est plus propre et plus aise
maintenir, mme si a semble demander un lger effort supplmentaire au codage initial.

11.15 La sous-routine de temporisation

Nous navons pas encore vu le timer0, ni les interruptions. Le but ici est de vous faire
comprendre le fonctionnement du 16F84. Pour raliser une tempo, il suffit dans notre cas de
faire perdre du temps au 16F84 entre chaque inversion de la LED.

Nous devons donc perdre approximativement 0.5s. Les secondes ne sont pas appropries
pour les PIC, qui travaillent une vitesse beaucoup plus leve. Nous utiliserons donc des
units lchelle de temps du PIC.

Cette notion dchelle de temps est trs importante en programmation, il faut toujours
essayer de vous reprsenter les vnements qui arrivent comme si vous tiez un PIC. Attendre
1 seconde quivaut alors une ternit, et certains vnements qui vous semblaient
ngligeables deviennent alors parfaitement perceptibles, nous en reparlerons.

113
Notre PIC est cadenc la frquence de notre quartz, soit 4MHz. Or, le PIC excute
un cycle dinstruction tous les 4 cycles de lhorloge principale. Le PIC excutera donc
(4.000.000/4) = 1 million de cycles dinstruction par seconde. Souvenez-vous que votre
simple PIC16F84A peut parfaitement travailler avec un quartz de 20Mhz, nous sommes donc
au cinquime de ses possibilits.

Ce cours a t crit initialement pour des PIC tournant 4Mhz, cest la raison du choix de
cette valeur, qui ne ncessite pas de modifier tous les exercices. Notez au passage quil est
inutile de faire tourner votre PIC plus que ncessaire : le faire travailler 4Mhz dans lunique
but de faire clignoter une led 1Hz est dj parfaitement inutile (nous sommes dans une
dmarche didactique et non doptimisation ou de fabrication grande chelle). Il existe
galement dautres modles de PIC 8 bits capables de travailler avec des vitesses encore bien
plus importantes.

Notez au passage que la consommation de votre PIC augmente avec la vitesse laquelle
vous le faites travailler. Pensez-y si vous ralisez des montages aliments par piles.

La plupart des instructions (hormis les sauts) sexcutent en 1 cycle, ce qui vous donne
approximativement un million dinstructions par seconde. Vous verrez parfois la
dnomination MIPS. Ceci signifie Million dInstructions Par Seconde. Notre PIC avec ce
quartz a donc une puissance de traitement de prs de 1MIPS.

Chaque cycle dinstruction dure donc 1 millionime de seconde, ou encore une


microseconde (s). Voil donc lunit pour travailler avec notre PIC.

Donc, notre tempo de 0.5s est donc une tempo de 500.000 microsecondes. Autrement dit,
nous devons perdre pour rien 500.000 cycles dinstruction dans notre routine de
temporisation. Vous voyez donc que votre PIC, pour notre application, va passer son temps
ne rien faire dutile : 1 instruction utile (allumer ou teindre la led) pour 500.000
instructions destines lui faire perdre son temps.

La premire ide qui vient lesprit est de raliser une boucle qui va incrmenter ou
dcrmenter une variable.

Ralisons-la. Commenons donc par dclarer notre variable (cmpt1) dans la zone de
RAM. Ajoutons donc cette dclaration . Nous obtenons :

;*********************************************************************
; DECLARATIONS DE VARIABLES *
;*********************************************************************
CBLOCK 0x00C ; dbut de la zone variables
cmpt1 : 1 ; compteur de boucles 1
ENDC ; Fin de la zone

Crons maintenant lossature de notre sous-routine, que nous placerons entre la routine
dinitialisation et le programme principal (en fait, vous pouvez parfaitement la placer
nimporte o, avant ou aprs votre programme principal, il ne sagit que dun exemple).
Noubliez pas de toujours utiliser des commentaires :

114
;*********************************************************************
; SOUS-ROUTINE DE TEMPORISATION *
;*********************************************************************
;---------------------------------------------------------------------
; Cette sous-routine introduit un retard de 500.000 s.
; Elle ne reoit aucun paramtre et n'en retourne aucun
;---------------------------------------------------------------------
tempo
; nous allons placer notre code ici
return ; retour de la sous-routine

Ralisons maintenant notre boucle.

tempo
clrf cmpt1 ; effacer compteur1
boucle1
decfsz cmpt1 ; dcrmenter compteur1
goto boucle1 ; si pas 0, boucler
return ; retour de la sous-routine

Lanons lassemblage avec <F10> :

Nous obtenons dans la fentre des rsultats une ligne supplmentaire de la forme :

Message[305] D:\DOCUME~1\LESSONS\DATAPIC\LED_CLI.ASM 134 : Using default


destination of 1 (file).

Le numro de ligne peut varier suivant votre code source. Comme lassemblage sest
effectu correctement, il sagit une fois de plus dun message de type warning. Positionnez-
vous dans lditeur sur la ligne incrimine (ligne 134 pour moi). Vous tes sur la ligne :

decfsz cmpt1 ; dcrmenter compteur1

Que vous dit le message ? Simplement que vous navez pas prcis la destination de
linstruction, et que la valeur 1 pour file , et donc ,f sera utilise par dfaut. En
effet, linstruction decfsz est de la forme decfsz f , d . Nous avons donc oubli dindiquer
la destination de lopration (le ,d )

Faites donc attention, car si vous aviez voulu obtenir le rsultat dans w, votre programme
tait faux. Corrigez donc toujours les warnings de ce type. Modifiez donc votre commande
en ajoutant ,f :

decfsz cmpt1 , f ; dcrmenter compteur1

Maintenant, nous allons calculer la dure de cette tempo.

tempo
clrf cmpt1 ; 1 cycle
boucle1
decfsz cmpt1 , f ; 1 cycle si on ne saute pas, 2 si on saute. Donc, on
; ne sautera pas 255 fois et on sautera 1 fois
goto boucle1 ; 2 cycles multipli par 255 passages
return ; 2 cycles.

115
Nous lavons vu, un temps est quivalant un nombre de cycles dinstructions.
Nous pouvons donc mesurer du temps en comptabilisant les cycles dinstructions excuts.

Le temps total est donc de :

2 cycles pour lappel de la sous-routine (call tempo)


1 cycle pour le reset de la variable
257 cycles pour les 256 dcrmentations
510 cycles pour les 255 goto
2 cycles pour le return.

Soit un total de 772 cycles. On est loin des 500.000 cycles ncessaires. Pour la suite
des calculs, nous allons ngliger les 2 cycles du call et les 2 cycles du return (compars aux
500.000 cycles, cest effectivement drisoire dans notre application).

Bon, nous allons allonger notre routine, en ralisant une seconde boucle qui va forcer
la premire boucle sexcuter 256 fois. Commenons par dclarer une nouvelle variable
cmpt2 :

cmpt1 : 1 ; compteur de boucles 1


cmpt2 : 1 ; compteur de boucles 2

Ecrivons donc les 2 boucles imbriques :

tempo
clrf cmpt2 ; effacer compteur2
boucle2
clrf cmpt1 ; effacer compteur1
boucle1
decfsz cmpt1 , f ; dcrmenter compteur1
goto boucle1 ; si pas 0, boucler
decfsz cmpt2 , f ; si 0, dcrmenter compteur 2
goto boucle2 ; si cmpt2 pas 0, recommencer boucle1
return ; retour de la sous-routine

Vous voyez que notre premire boucle est toujours l, mais au lieu deffectuer le return
une fois termine, nous recommenons la boucle tant que cmpt2 ne soit pas galement gal
0. Nous allons donc excuter 256 fois notre boucle1.

Quelle est la temporisation obtenue ? Calculons approximativement :

Dure de la boucle 1 : 257 cycles + 510 cycles + 1 cycle (clrf cmpt1) = 768 cycles.
Or cette boucle va tre excute 256 fois, donc 768*256 = 196608 cycles, auquel il
convient dajouter les quelques cycles dinitialisation etc.

Or, nous dsirons 500.000 cycles. Nous devrons donc utiliser cette double-boucle
(500.000/196608) = 2,54 fois. Nous ne savons pas faire de demi boucle. Nous effectuerons
donc 2 boucles. Nous allons nous arranger pour que nos deux premires boucles durent
500.000/2 = 250.000 cycles.

Chaque instruction ajoute dans la boucle1 est excute 256*256 fois. Chaque instruction
ajoute dans la boucle 2 est excute 256 fois. Chaque cycle extrieur aux boucles est excut

116
1 fois. Nous avons donc la possibilit de raliser des temporisations trs prcises. Ce nest pas
ncessaire ici. Cependant, nous allons quand mme amliorer la prcision.

Si nous ajoutons 1 cycle inutile dans la boucle1, nous ajouterons 256*256 = 65536
cycles. Nous devons en ajouter 250.000 196608 = 53392. Cela nous donnerait une erreur de
12000 cycles, soit 12 millimes de seconde (12ms). La prcision est largement suffisante pour
notre application, mais je rappelle que vous pouvez affiner cette prcision en effectuant les
calculs prcis. Je vous conseille mme de le faire vous-mme comme exercice. Vous pourrez
vrifier vos rsultats avec un chronomtre (sur un grand nombre de clignotements).

Pour perdre un cycle, nous ajouterons simplement linstruction NOP, qui ne fait
rien. Vous voyez que mme ne rien faire peut servir quelque chose.

Reste donc raliser la dernire boucle de 2. Crons une troisime variable cmpt3 et une
troisime boucle. (Rassurez-vous, il y a des mthodes plus simples, ceci est expliqu dans un
but didactique : il importe simplement davoir compris).
;*********************************************************************
; DECLARATIONS DE VARIABLES *
;*********************************************************************
CBLOCK 0x00C ; dbut de la zone variables

cmpt1 : 1 ; compteur de boucles 1


cmpt2 : 1 ; compteur de boucles 2
cmpt3 : 1 ; compteur de boucles 3

ENDC ; Fin de la zone

Voici le code final :

;*********************************************************************
; SOUS-ROUTINE DE TEMPORISATION *
;*********************************************************************
;---------------------------------------------------------------------
; Cette sous-routine introduit un retard de 500.000 s.
; Elle ne reoit aucun paramtre 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 *256 *256 *2
decfsz cmpt1 , f ; dcrmenter compteur1
goto boucle1 ; si pas 0, boucler
decfsz cmpt2 , f ; si 0, dcrmenter compteur 2
goto boucle2 ; si cmpt2 pas 0, recommencer boucle1
decfsz cmpt3 , f ; si 0, dcrmenter compteur 3
goto boucle3 ; si cmpt3 pas 0, recommencer boucle2
return ; retour de la sous-routine

Lancez lassemblage avec <F10>. Si tout sest bien pass, vous obtenez dans votre
rpertoire de travail le fichier Led_cli.hex

117
Envoyez-le dans votre PIC laide de votre programmateur. Placez ensuite le
PIC programm sur la carte hors-tension. Envoyez lalimentation et regardez bien :

VOTRE LED CLIGNOTE A LA FREQUENCE DE 1HZ.

Flicitations, voici votre premier programme embarqu. La porte est ouverte des
tonnes de nouvelles applications.

CONSEIL IMPORTANT

Si, ce stade, vous sautez au plafond en criant a marche !!! (jai connu a), ne
vous prcipitez pas en hurlant pour faire admirer votre ralisation votre pouse. Je doute
quelle partage votre enthousiasme pour cette petite lampe qui clignote .

Le fichier tel quil devrait tre la fin de cette leon est disponible dans les fichiers joints.

118
12. Les interruptions
Voil un chapitre qui fera certainement peur beaucoup de futurs programmeurs.
Certains en parlent comme un sujet rserv aux Geeks, ou mme estiment quil sagit l de
secrets de magie noire destins faire fuir tout malheureux novice qui tenterait de trop sen
approcher. Dautres enfin tentent dy chapper en recourant un quelconque langage de haut
niveau magique qui aurait la proprit de faire disparatre cet aspect matriel pourtant
indispensable.

Mais pourtant, le mcanisme des interruptions est trs ais comprendre, et galement
mettre en uvre, pour autant que lon travaille de manire propre et structure. Il ne
viendrait lide daucun programmeur de microcontrleurs de ce type dviter de sen servir.

12.1 Quest-ce quune interruption ?

Imaginez une conversation normale :

- Chaque interlocuteur prend la parole quand vient son tour de parler.


- Survient alors un moment inconnu davance un vnement extrieur dont le
traitement est urgent. Par exemple, un piano tombe du 3me tage de limmeuble au pied
duquel vous discutez.
- Vous imaginez bien que votre interlocuteur ne va pas attendre la fin de votre phrase pour
vous signaler le danger. Il va donc vous interrompre durant le cours normal de votre
conversation., afin de pouvoir traiter immdiatement lvnement extrieur.

Les interlocuteurs reprendront leur conversation o elle en tait arrive, sitt le danger
cart (sils ont vit le piano, bien sr). Vous avez compris ce qui prcde ? Alors vous avez
compris ce quest une interruption.

En effet, pour les programmes, cest exactement le mme principe :

- Votre programme se droule normalement.


- Survient un vnement spcifique un moment imprvisible.
- Le programme principal est interrompu (donc, subit une interruption), et va traiter
lvnement, avant de reprendre le programme principal lendroit o il avait t
interrompu.

Linterruption est donc une rupture de squence asynchrone, cest dire non synchronise
avec le droulement normal du programme, ou encore qui peut survenir nimporte quel
moment de lexcution de votre programme, sans que cet endroit ne soit prvisible.

Vous voyez ici lopposition avec les ruptures de squences synchrones, provoques par
le programme lui-mme (goto, call, btfss), et donc un endroit parfaitement prvisible
puisqu lendroit mme o se trouvent les instructions en question.

119
12.2 Mcanisme gnral dune interruption

Nous pouvons dire, sans nous tromper de beaucoup, quune routine dinterruption est un
sous-programme particulier, dclench par lapparition dun vnement spcifique. Ceci peut
sembler un peu ardu, mais vous allez voir que cest trs simple.

Voici donc comment cela fonctionne :

- Le programme se droule normalement


- Lvnement survient
- Le programme achve linstruction en cours de traitement
- Le programme saute ladresse de traitement de linterruption (0x04)
- Le programme traite linterruption
- Le programme termine le traitement de linterruption et saute linstruction qui suit la
dernire excute dans le programme principal.
-
Il va bien sr de soi que nimporte quel vnement ne peut pas dclencher une
interruption. Il faut que 2 conditions principales soient remplies :

- Lvnement en question doit figurer dans la liste des vnements susceptibles de


provoquer une interruption pour le processeur sur lequel on travaille

- Lutilisateur doit avoir autoris linterruption, cest dire doit avoir signal que
lvnement en question devait gnrer une interruption. Voyons lorganigramme
gnral de lexcution dune interruption :

- ::

120
Que pouvons-nous dire en voyant cet ordinogramme ? Et bien, nous pouvons dj nous dire
que le programme principal ne sait pas quand il est interrompu, ni mme quil la t. Il
est donc crucial de lui remettre ses registres dans ltat o ils taient avant linterruption. En
effet, supposons que linstruction xxx ait positionn un flag (par exemple, le bit dindicateur
Z). Si par malheur, la routine dinterruption a modifi ce bit, le programme ne pourra pas se
poursuivre normalement.

Nous voyons galement que linstruction xxx termine son excution avant de se
brancher sur la routine dinterruption. Une instruction commence nest donc jamais
interrompue.

Note : Pour certaines familles de microcontrleurs il existe une adresse de


branchement par type dinterruption, il est donc inutile de tester dans la routine de traitement
quelle est la source de linterruption.

12.3 Mcanisme dinterruption sur les PIC

Bien entendu, les PIC rpondent au fonctionnement gnral ci-dessus, mais ils ont
galement leurs particularits. Voyons maintenant le principe des interruptions sur les
PIC16F

- Tout dabord, ladresse de dbut de toute interruption est fixe. Il sagit toujours de
ladresse 0x04.

- Corollaire : Toute interruption provoquera le saut du programme vers cette adresse.


Toutes les sources dinterruption arrivant cette adresse, si le programmeur utilise
plusieurs sources dinterruptions, il faudra quil dtermine lui-mme laquelle il est
en train de traiter.

- Les PIC16F en se connectant cette adresse, ne sauvent rien automatiquement,


hormis le contenu du PC, qui servira connatre ladresse du retour de linterruption.
Cest donc lutilisateur de se charger des sauvegardes, et donc des restaurations.

- 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 dimbrication pour vos
sous-programmes. Moins si vous utilisez des sous-programmes dans vos
interruptions.

Le temps de raction dune interruption est calcul de la manire suivante :

- Le cycle courant de linstruction est termin.


- Le flag dinterruption est lu au dbut du cycle suivant.
- Celui-ci est achev, puis le processeur sarrte un cycle pour charger ladresse 0x04
dans PC.
- Le processeur se connecte alors ladresse 0x04 o il lui faudra un cycle
supplmentaire pour charger linstruction excuter.

121
Le temps mort total sera donc compris entre 3 et 4 cycles. Si on veut tre prcis, la
logique interne fait que toute interruption survenue avant le premier quart de
linstruction en cours sera prise en compte comme si linstruction navait pas
commenc. Autrement dit, le temps mort sera compris entre 3 et 3,75 cycles. Notez
galement que si linterruption est synchrone avec loscillateur du PIC (interruption
interne, genre timer), elle ne pourra pas survenir au milieu dun cycle, le temps mort
sera donc obligatoirement de 3 cycles.

Remarquez que :

- Une interruption ne peut pas tre interrompue par une autre interruption. Les
interruptions sont invalides automatiquement lors du saut ladresse 0x04 par
leffacement du bit GIE (que nous allons voir). Ceci est automatique.

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


linterruption. Linstruction de retour sur un PIC16F, RETFIE agit donc
exactement comme linstruction RETURN, mais elle repositionne en mme temps le
bit GIE.

Ceci nous amne lordinogramme des interruptions sur PIC16F :

122
12.4 Les sources dinterruptions du 16F84

Le PIC16F84 est trs pauvre ce niveau, puisquil ne dispose que de 4 sources


dinterruptions possibles (contre 13 pour le PIC16F876 par exemple). Les vnements
susceptibles de dclencher une interruption sont les suivants :

- TMR0 : Dbordement du timer0 (tmr0). Une fois que le contenu du tmr0 passe de
0xff 0x00, une interruption peut tre gnre. Nous utiliserons ces proprits dans le
chapitre sur le timer 0.

- EEPROM : cette interruption peut tre gnre lorsque lcriture dans une case
EEPROM interne est termine. Nous verrons ce cas dans le chapitre sur lcriture en
zone eeprom.

- RB0/INT : Une interruption peut tre gnre lorsque, la pin RB0, encore appele
INTerrupt pin, tant configure en entre, le niveau qui est appliqu est modifi. Nous
allons tudier ce cas ici.

- PORTB : De la mme manire, une interruption peut tre gnre lors du changement
dun niveau sur une des pins RB4 RB7. Il nest pas possible de limiter linterruption
une seule de ces pins. Linterruption sera effective pour les 4 pins ou pour aucune.

12.5 Les dispositifs mis en uvre

Comment interdire ou autoriser les interruptions, comment dtecter quel est lvnement
dclencheur, et comment les grer ? Nous allons aborder ceci dabord de manire
symbolique, pour vous aider bien visualiser la procdure.

Imaginons un htel. Le groom de service reprsente notre programme. Cet htel comporte
4 chambres (nos 4 sources dinterruption), et chaque chambre est quipe dun bouton-
poussoir. Chaque bouton-poussoir servant appeler le groom est reli une lampe laccueil
de lhtel.

Chaque lampe a la possibilit de faire rsonner une sonnette (dclencher une


interruption) :

- Si linterrupteur gnral de la sonnette est positionn sur ON


- Et si linterrupteur particulier reliant chaque lampe la sonnette est enclench.

Voil donc le schma de principe obtenu :

123
Quand vous comprendrez bien ce petit schma quivalent lectrique, vous aurez
compris le principe des interruptions.Vous voyez tout de suite quil y a deux mthodes pour
que le groom soit prvenu lorsquon sonne dans une chambre :

Soit via la lampe, soit via la sonnette.

- Pour la premire mthode, le groom doit venir voir les lampes intervalles rguliers,
lorsquil le dsire, pour vrifier si personne na appel. Il doit donc venir scruter le
tableau de signalisation. Cest la mthode de scrutation. Cest le groom qui dcide
quand il vient regarder le tableau, et donc qui dcide quand ragir une requte dun
client.

- Avec la sonnette, le groom est interrompu dans son travail par celle-ci. Il na pas
besoin de venir scruter inutilement, mais il sera drang dans son travail par la
sonnette. Cest la mthode des interruptions. Le groom ne dcide plus du tout quand
il ragira la requte dun client, il doit ragir ds quil entend la sonnette (sinon il
se fait virer). Notez dj les points suivants :

- Le locataire de la chambre (lvnement) ne peut dcider quelle mthode sera utilise,


cest le groom (le programme) qui dcide de valider ou non les sonnettes.

- Le groom peut inhiber toutes les possibilits de faire rsonner la sonnette en une seule
fois (interrupteur gnral), ou dcider quelle chambre va pouvoir actionner la sonnette
(1 interrupteur par chambre).

- Les interrupteurs de validation nagissent pas sur les lampes.

124
- Si le groom est interrompu dans son travail par la sonnette, il doit de toute faon aller
regarder les lampes pour voir qui a sonn. Sauf sil sait quil na autoris quune
seule chambre actionner la sonnette.

- Ce qui napparat pas sur ce schma simplifi, mais quil faut savoir, cest que, une
fois une lampe allume, elle le reste (laction du bouton est mmorise). Cest le
groom qui doit lteindre manuellement.

Mettons donc tout ceci en pratique sur le 16F84. Vous avez dj compris que lampes et
interrupteurs taient, dans le 16F84, des bits de registres particuliers. Voici maintenant le
registre principal de gestion des interruptions pour le 16F84.

12.6 Le registre INTCON (INTerrupt CONtrol)

Ce registre se situe ladresse 0x0B, dans les 2 banques. Il est donc toujours
accessible. Il est dtaill figure 4-5 page 17. Cest un registre de bits, donc, chaque bit a une
fonction particulire. Voici le dtail de ces bits :

b7 : GIE

Global Interrupt Enable bit. Il permet de valider ou dinvalider toutes les interruptions
dune seule fois. Ce bit correspond donc notre interrupteur de validation gnrale.

b6 : EEIE

EEprom write complete Interrupt Enable bit. Ce bit permet de valider linterruption de fin
dcriture en eeprom (nous tudierons plus tard le mcanisme dcriture eeprom). Il sagit,
ainsi que des autres bits E , dun des interrupteurs spcifiques une chambre.

b5 : T0IE

Tmr0 Interrupt Enable bit : Valide linterruption gnre par le dbordement du timer0.
Attention, cest le chiffre zro et non la lettre O .

b4 : INTE

INTerrupt pin Enable bit : Valide linterruption dans le cas dune modification de niveau
de la pin RB0.

Attention : rappelez-vous le bit 6 du registre OPTION, qui dtermine quel est le sens de
transition qui provoque linterruption. On pourra donc choisir si cest une transition 0->1 ou
1->0 qui provoque linterruption, mais pas les deux ensemble.

b3 : RBIE

RB Interrupt Enable bit : Valide les interruptions si on a changement de niveau sur une
des entres RB4 RB7.

125
b2 : T0IF

Tmr0 Interrupt Flag bit. Cest un Flag, donc il signale. Ici cest le dbordement du
timer0. Tous les bits termins par F dans ce registre sont des flags (drapeaux, dans le sens
signalisation ), correspondant aux ampoules sur notre schma.

b1 : INTF

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

b0 : RBIF

RB Interrupt Flag bit : signale quune des entres RB4 RB7 a t modifie.

Remarque

Rappelez-vous que les flags ne se remettent pas 0 tout seuls. Si ces flags sont lis
une interruption autorise, votre programme doit les remettre 0 dans le traitement de cette
interruption, sous peine de ne plus jamais pouvoir en sortir. En effet, ds la sortie de
linterruption, les conditions initiales restant remplies, linterruption serait immdiatement
rappele. Nous dirons que ces flags sont rmanents.

Remarque : Prenez garde que le reset de RBIF doit tre prcd dune lecture ou
dune criture du PORTB afin denregistrer (automatiquement) la dernire valeur de
PORTB utilise. Faute de quoi, ds leffacement de RBIF effectu, il serait immdiatement
repositionn, le PIC constatant une modification de PORTB depuis la dernire valeur
mmorise lors de la dernire lecture de PORB.

Remarquez dj que tous les bits dont le nom se termine par E (Enable) sont en fait des
commutateurs de validation (ce sont les interrupteurs de notre schma symbolique). Les bits
dont le nom se termine par F sont des Flags (indicateurs). Ils sont reprsents par des lampes
sur notre schma symbolique. Sur celui-ci nous avons 5 interrupteurs et 4 ampoules. Or nous
navons que 8 bits dans INTCON0. Que nous manque-t-il ?

Si vous regardez attentivement, il nous manque le bit EEIF. Mais, rassurez-vous, ce bit
existe bien, il est tout simplement dans un autre registre, en locccurence EECON1, que nous
verrons dans la leon sur les accs EEPROM. Nous allons donc dessiner un petit schma
symbolique correspondant la ralit dun PIC 16F84 :

126
Aprs ces explications dtailles, trop diront les habitus des processeurs, vous devez
maintenant avoir compris le fonctionnement des interruptions sur le 16F84. Analysons
maintenant quelques points de la routine dinterruption en elle-mme. Pour rester concrets,
nous allons mlanger thorie et pratique.

12.7 Sauvegarde et restauration de lenvironnement

Si vous regardez de nouveau lorganigramme de la routine dinterruption, vous constatez


que vous devez procder la sauvegarde et la restauration de lenvironnement de
votre programme. En quoi cela consiste-t-il ?

Et bien, comme nous lavons dj dit, votre programme interrompu ne sait pas quil la
t. Vous devez donc remettre les registres dans ltat o ils se trouvaient au moment de
linterruption, et ce pour permettre votre programme de continuer fonctionner
correctement une fois le traitement de linterruption termin.

Petit exemple :

Supposons votre programme principal interrompu entre les 2 instructions suivantes :

movf mavariable , w ; charger mavariable et positionner Z


-> interruption ici
btfss STATUS , Z ; tester bit Z et sauter si vaut 1

Il est plus que probable que votre routine dinterruption va utiliser au moins une
instruction qui modifie le bit Z. Vous devrez donc restaurer le registre STATUS dans ltat
quil tait avant de sortir de la routine dinterruption. Sinon le test ne se fera pas sur la valeur
de mavariable, mais sur une valeur de Z modifie par la routine dinterruption.

De plus, il est peut prs certain que le registre w va tre modifi galement, donc il
vous faudra veiller le sauvegarder galement.

127
12.7.1 Les registres sauvegarder

Commenons par une gnralit : Dans notre routine dinterruption, nous devons
sauver

- Tout registre modifi par cette routine


- Si notre programme principal utilise ce registre
- ET si notre programme principal ne sattend pas une modification de ce registre

Dit autrement, vous devez sauver (et restaurer, videmment) tout ce qui, tant modifi par
la routine dinterruption, induirait un comportement erron du programme principal.

Il y a videmment des registres dont il est presque certain (ou compltement certain)
quils doivent tre sauvegards, en raison des conditions prcdentes :

Pour commencer, le plus simple : le PC. Sil ntait pas sauv, il serait impossible de
retourner lendroit o notre programme a t interrompu. Il doit donc tre sauv lendroit
mme de linterruption. Il est donc impossible deffectuer manuellement cette sauvegarde.
Cest pourquoi cette sauvegarde fait partie du fonctionnement automatique des interruptions.
Vous ne vous en proccupez donc pas.

Ensuite, le registre STATUS. Il contient tous les flags conditionnels. Or, il est
pratiquement inconcevable davoir une interruption qui nutilise aucune instruction modifiant
STATUS (ou alors votre interruption ne fait pas grand-chose). Comme votre programme
principal a galement toutes les chances dutiliser une instruction conditionnelle ou des
changements de banques, la sauvegarde de STATUS est donc pratiquement obligatoire.

Il en va exactement de mme pour le registre de travail W.

Les registres sauvegarder/restaurer doffice dans vos interruptions seront donc


99,99% de chance : STATUS et W.

En ce qui concerne dautres sauvegardes ventuelles, vous devez agir en fonction du


contexte. Par exemple si votre programme principal utilise ladressage index et votre routine
dinterruption galement, il y a fort parier que vous devrez galement sauver le registre
FSR.

On pourrait penser sauver les variables utilises dans la routine dinterruption, mais il
faudrait alors un emplacement de sauvegarde (donc une variable) pour sauver chaque
variable, ce qui naurait aucun sens. Moralit, lorsque vous utilisez des variables dans vos
routines dinterruption, ce seront des variables rserves cet usage, ne pas utiliser dans
votre programme principal (sauf si les modifications effectues sont justement utiles votre
programme principal)

12.7.2 La mthode de sauvegarde

Pour sauver les registres W et STATUS on utilise une mthode tout fait classique. Il
importe de commencer par sauver W avant STATUS, puisque la sauvegarde de STATUS

128
impose de dabord charger ce registre dans le registre de travail, ce qui induit donc la perte du
registre W. La sauvegarde se rsume donc :

movwf w_temp ; sauve W dans un emplacement de sauvegarde


movf STATUS,w ; transfre STATUS dans W
movwf status_temp ; sauvegarde de STATUS

Notez que les datasheets et les documents de rfrence, comme le mid-range reference
manual, indiquent la mthode suivante :

movwf w_temp ; sauve W dans un emplacement de sauvegarde


swapf STATUS,w ; transfre STATUS swapp dans W
movwf status_temp ; sauvegarde de STATUS

Vous constatez quau lieu dun movf, Microchip recommande lutilisation dun swapf,
(qui ne modifie aucun bit de STATUS) dans la manuvre. Evidemment, loctet charg est
swapp et donc il faudra galement utiliser un swap lors de la restauration.

Il ny a pourtant aucun problme modifier STATUS en le chargeant dans W, puisque


cest W (contenant lancienne valeur de STATUS) qui sera sauv.

Aprs interrogation sur ce point prcis, je nai pas pu obtenir dinformation auprs de
Microchip sur la raison exacte de cette mthode conseille (peut-tre le rsidu dun ancien
bug concernant les manipulations de STATUS ?). Il semble mme que cette mthode ait
disparu des recommandations officielles Microchip. Nanmoins, les premires versions de ce
cours ont utilis cette mthode recommande, ce qui fait que cest cette faon de procder que
vous retrouverez dans les sources et documents. Sachez simplement que vous pouvez utiliser
la mthode qui vous convient, a ne change strictement rien. videmment, si vous utilisez un
swap pour sauver, vous devez utiliser un swap pour restaurer, sans quoi votre valeur
restaure serait inverse par rapport la valeur originale. Mais bon, pourquoi faire simple
quand on peut faire compliqu ?

Attention : ceci ne vaut QUE pour le registre STATUS. En ce qui concerne la


restauration de W, les remarques qui vont suivre restent dapplication.

12.7.3 La mthode de restauration

Vous allez me dire : mais que dire ce sujet ? En effet, il semble logique de procder
de faon inverse, savoir :

movf status_temp,w ; charge le STATUS sauvegard


movwf STATUS ; restaurer STATUS
movf w_temp,w ; restaurer W

Tout semble simple, et pourtant se cache ici un pige grossier. En effet, la dernire
instruction movf modifie le bit Z de STATUS. Donc, en restaurant le registre w, vous
dtruisez votre restauration de STATUS. Et si vous restaurez dabord W, vous le dtruisez en
rcuprant STATUS. Ceci est videmment inacceptable, cest pourquoi il est ncessaire
dutiliser une autre mthode.

129
Lastuce est dutiliser pour restaurer W une instruction qui ne modifie aucun bit du
registre STATUS. Un coup dil sur les instructions disponibles nous permet de voir que
linstruction swapf amne la variable dans W sans modifier aucun bit de STATUS.

Cependant, cette instruction prsente linconvnient dinverser les 4 bits de poids


fort avec les 4 bits de poids faible de loctet dsign, ce qui conduirait une restauration
incorrecte. Il sera donc ncessaire pour annuler cette inversion dutiliser 2 instructions
swapf conscutives, ce qui remettra loctet dans le bon ordre.

La routine modifie se prsente alors comme suit :

movf status_temp,w ; charge le STATUS sauvegard


movwf STATUS ; restaurer STATUS
swapf w_temp,f ; swappe lemplacement de sauvegarde
swapf w_temp,w ; re-swappe et amne le rsultat dans W

De cette faon, W est bel et bien restaur sans avoir modifi le registre STATUS
prcdemment restaur.

Bref, voici les deux faons de procder, qui sont strictement quivalentes,
La mthode intuitive :

sauvegarde
movwf w_temp ; sauve W dans un emplacement de sauvegarde
movf STATUS,w ; transfre STATUS dans W
movwf status_temp ; sauvegarde de STATUS



restauration
movf status_temp,w ; charge le STATUS sauvegard
movwf STATUS ; restaurer STATUS
swapf w_temp,f ; inverse lemplacement de sauvegarde de W
swapf w_temp,w ; rinverse et amne le rsultat dans W

Ou la mthode prconise lorigine, et utilise dans le cours pour des raisons


historiques :

sauvegarde
movwf w_temp ; sauve W dans un emplacement de sauvegarde
swapf STATUS,w ; transfre STATUS swapp dans W
movwf status_temp ; sauvegarde de STATUS



restauration
swapf status_temp,w ; charge le STATUS sauvegard
movwf STATUS ; restaurer STATUS
swapf w_temp,f ; inverse lemplacement de sauvegarde
swapf w_temp,w ; rinverse et amne le rsultat dans W

Il ny a en fait aucune diffrence pratique entre les deux, mais il importe de vous
souvenir que lutilisation de 2 swapf pour restaurer W reste obligatoire.

130
Voici donc la structure de base dune routine dinterruption :
;**********************************************************************
; ROUTINE INTERRUPTION *
;**********************************************************************

;sauvegarder registres
;---------------------
ORG 0x004 ; adresse d'interruption
movwf w_temp ; sauver registre W
swapf STATUS,w ; swap status avec rsultat dans w
movwf status_temp ; sauver status swapp

; switch vers diffrentes interrupts


; ----------------------------------
; ici, on teste ventuellement de quelle interruption il sagit

; traitement des interruptions


; -----------------------------
; ici, on peut traiter une interruption puis effacer son flag

;restaurer registres
;-------------------
swapf status_temp,w ; swap ancien status, rsultat dans w
movwf STATUS ; restaurer status
swapf w_temp,f ; Inversion L et H de l'ancien W
; sans modifier Z
swapf w_temp,w ; R-inversion de L et H dans W
; W restaur sans modifier status
retfie ; return from interrupt

Et voil votre squelette de routine dinterruption : vraiment pas compliqu, nest-ce pas ?
Il ny a plus qu complter, car le fichier m16F84.asm contient dj les routines de
sauvegarde et restauration (que nous venons dexpliquer) et les tests de type dinterruption
(que nous allons dtailler).

Comme je suis partisan de la programmation structure, la routine de switch branche


en ralit sur des sous-programmes spars. Rien nempche en effet dutiliser des sous-
programmes dans une routine dinterruption. Attention cependant votre limite de pile
disponible.

12.7.4 Oprations sur le registre STATUS

Je ne voudrais pas terminer cette partie sans attirer votre attention sur un point
particulier, savoir les instructions dont la destination est le registre STATUS.

Toute instruction dont le rsultat est susceptible de modifier un ou plusieurs


bit(s) du registre STATUS, et dont la cible est le registre STATUS lui-mme, induit que
chaque bit susceptible dtre modifi par linstruction se retrouve en lecture seule.

Pour tre plus explicite, quelques exemples :

movwf STATUS ; aucun problme, movwf ne modifie aucun flag


movf STATUS,w ; aucun problme, STATUS nest pas la destination
andwf STATUS ; le bit Z sera positionn en fonction du rsultat

131
addwf STATUS ; idem pour C, DC, et Z.
clrf STATUS ; modifie Z, et donc ne donne pas le rsultat escompt

Si vous prenez par exemple la dernire instruction, vous vous attendez obtenir STATUS
= 0. Or, tout ce passe comme si, clrf modifiant le bit Z, celui-ci ntait pas affect par votre
instruction. Au final, immdiatement aprs avoir effacer STATUS, le rsultat valant 0, le bit Z
va tre directement repositionn, votre STATUS ne vaudra plus 0.

Soyez donc trs prudent, et si la destination de votre instruction est le registre


STATUS, utilisez de prfrence un movwf, un swapf, ou les instructions de manipulation
de bits (bcf et bsf).

12.7.5Particularit de linstruction RETFIE

A ce niveau de lexpos, une remarque pertinente serait la suivante :


Pourquoi existe-t-il une instruction RETFIE, alors quon pourrait utiliser RETURN, quitte
le faire prcder dune remise en service de GIE ?

Tout dabord, la structure mme de notre routine interdit quune interruption puisse en
interrompre une autre. Si ctait le cas, les sauvegardes des registres W et STATUS seraient
crases par une seconde opration (mais cest possible sur dautres processeurs et mme
dautres PIC). On dira que notre routine nest pas r-entrante.

Pour tenir compte de ce problme, le PIC force donc le bit GIE 0 ds lentre dans la
routine dinterruption. Pour quune nouvelle interruption puisse avoir lieu une fois celle en
cours termine, il faut remettre GIE 1. Ceci est excut automatiquement par RETFIE.

Vous allez alors me dire : et si je fais ceci ?

bsf INTCON , GIE ; remettre GIE 1


return ; et sortir de la routine dinterruption

Et bien, cest exactement ce que fait RETFIE, mais un dtail prs, et ce dtail est de la
plus grande importance : RETFIE est une seule et mme instruction, donc ne peut pas tre
interrompu par une interruption. On dit que lopration est atomique (non divisible).

Dans le cas o les 2 instructions prcdentes seraient utilises, une fois GIE mis un, si
un des flags dinterruption est toujours 1 (autre interruption, o la mme qui se reproduit
une autre fois), le programme se reconnecterait sur la routine dinterruption avant davoir
excut le RETURN, donc avant davoir restaur le PC.

Celui-ci continuerait occuper un emplacement sur la pile. En sachant que la pile est
limite 8 emplacements, il y aurait de nombreuses chances de plantage du programme par
dbordement de la pile. Il vous serait en outre impossible de calculer la taille maximale de la
pile occupe par votre programme, car vous ignorerez le nombre de r-entrance de votre
routine dinterruption. Toutes les conditions un plantage alatoire seraient remplies.

Donc, utilisez toujours linstruction RETFIE pour sortir de votre interruption, sauf
si vous dsirez ne pas remettre les interruptions en service une fois excutes une
premire fois (cas particulier).

132
12.8 Utilisation dune routine dinterruption

Effectuez une copie de votre fichier m16f84.asm. Renommez-la en myinter.asm .


Crez un nouveau projet MPLAB avec le nom myinter suivant le processus habituel.

Nous allons construire un programme qui inverse lallumage dune LED chaque
pression sur un bouton-poussoir. Modifiez votre petite platine dexprimentation de faon
connecter le bouton-poussoir sur lentre RB0 (dsol, quand jai dessin le schma, je
pensais expliquer les interruptions avec le timer).

Ceci vous montre cependant que llectronique et la programmation avec les


microcontrleurs sont trs dpendantes. Quand vous construisez un circuit, vous devez dj
penser la manire dont vous allez raliser la programmation. A linverse, si vous disposez
dun circuit dj existant, des contraintes vous sont dj imposes au niveau de la
programmation. Il est par exemple impossible de traiter notre bouton-poussoir par
interruption sil est cbl sur lentre RB2.

La rsistance est interne au PIC, il sagit dune des rsistances de rappel au +5V (pull-
up) quon peut activer par logiciel.

Comme dhabitude, remplissez le cadre den-tte, et supprimez les lignes inutilises


dans les variables, macro, et DEFINE. Attention, ne supprimez pas les variables w_temp et
status_temp..

#include <p16F84.inc> ; Dfinitions des constantes

Voici len-tte tel que vous pourriez le complter :

;**********************************************************************
; Ce programme est un programme didactique destin montrer *
; le fonctionnement des interruptions *
; *
;**********************************************************************
; *
; NOM: Interruption par bouton-poussoir sur RB0 *
; Date: 13/02/2001 *
; Version: 1.0 *
; Circuit: Platine d'essais *
; Auteur: Bigonoff *
; *
;**********************************************************************

133
; *
; Fichier requis: P16F84.inc *
; *
; *
; *
;**********************************************************************
; Notes: Ce programme transforme un bouton-poussoir en *
; tlrupteur. Un pulse allume la LED, un autre *
; lteint *
;**********************************************************************

Vous allez dire que jexagre en vous faisant mettre des commentaires partout.
Croyez-moi sur parole, les commentaires permettent une maintenance aise du programme.
Ils vous feront gagner coup sr beaucoup plus de temps quils ne vous en feront perdre.

Je suis dsol dinsister mais je reois rgulirement des programmes venant


dinternautes, compltement dpourvus de commentaires. Et pourtant, si ces internautes me
les envoient, cest justement parce quils ne trouvent pas lerreur qui sy trouve. Ces
internautes devraient ds lors se montrer modestes en estimant que les commentaires, cest
bon pour les autres . De toutes faons, lorsque je reois un programme dpourvu de
commentaires, il va directement la poubelle, mon temps vaut bien celui de ces internautes
conomes .

Modifiez la config pour supprimer le fonctionnement du watch-dog :

__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC

Calculons la future valeur envoyer dans le registre OPTION

- b7 0, car on a besoin de la rsistance de rappel au +5V pour le bouton-poussoir.

- b6 0, car on veut une interruption quand on presse le bouton, donc quand le niveau
passe de 1 0 (flanc descendant)

- b5/b0 0, aucune importance dans cette application.

Donc, nous placerons notre assignation B00000000, donc :

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

OPTIONVAL EQU H'00' ; Valeur registre option


; Rsistance pull-up ON
; Interrupt flanc descendant RB0

Pour le registre INTCON, nous devrons avoir :

- b7 1 : pour valider les interruptions


- b6 0 : pas dinterruption EE
- b5 0 : pas dinterruption tmr0
- b4 1 : interruption RB0 en service
- b3 0 : Pas dinterruption RB4/RB7

134
- b2/b0 0 : effacer les flags

Cela donne : B10010000, soit 0x90

Assignons une constante pour cette valeur ;

INTERMASK EQU H'90' ; Masque d'interruption


; Interruptions sur RB0

Ensuite, dans la zone des DEFINE, nous dfinirons notre LED et notre bouton-poussoir :

;*********************************************************************
; DEFINE *
;*********************************************************************
#DEFINE Bouton PORTB , 0 ; bouton poussoir
#DEFINE LED PORTA , 2 ; LED

Dans la zone macros , nous pouvons crire 2 macros que nous utiliserons souvent. Ce
sont les instructions pour passer en banque 0 et banque1. Elles seront incluses dans le
nouveau fichier m16f84.asm nomm m16f84_new.asm . A la fin de cette leon,
supprimez lancien fichier et renommez m16F84_new en m16f84 .

;*********************************************************************
; MACRO *
;*********************************************************************
BANK0 macro
bcf STATUS , RP0 ; passer en banque 0
endm

BANK1 macro
bsf STATUS , RP0 ; passer en banque1
endm

Venons-en la zone des variables. Nous devons garder w_temp et status_temp, car ces
variables sont utilises dans la routine dinterruption pour sauver les registres W et STATUS.

Nous allons galement rcuprer notre petite routine de tempo de notre fichier
led_cli.asm . Nous aurons donc besoin des variables utilises dans cette routine. Tout ceci
nous donne donc pour linstant :

;*********************************************************************
; DECLARATIONS DE VARIABLES *
;*********************************************************************
CBLOCK 0x00C ; dbut de la zone variables

w_temp :1 ; Sauvegarde de W dans interruption


status_temp : 1 ; Sauvegarde de STATUS dans interrupt
cmpt1 : 1 ; compteur de boucles 1 dans tempo
cmpt2 : 1 ; compteur de boucles 2 dans tempo
cmpt3 : 1 ; compteur de boucles 3 dans tempo

ENDC ; Fin de la zone

135
12.9 Analyse de la routine dinterruption

Nous avons dj vu la premire partie, qui est la sauvegarde des registres utiliss

;**********************************************************************
; ROUTINE INTERRUPTION *
;**********************************************************************

;sauvegarder registres
;---------------------
org 0x004 ; adresse d'interruption
movwf w_temp ; sauver registre W
swapf STATUS , w S ; swap status avec rsultat dans w
movwf status_temp ; sauver status swapp

Ensuite, nous devons dterminer quelle est lorigine de linterruption en cours. Dans le
cas prsent, il sagit obligatoirement de linterruption RB0/INT, car nous navons autoris que
celle-l. Dans le cas prsent, nous pourrions donc nous passer de ce test. Mais le but poursuivi
est de vous expliquer les mthodes utiliser. Nous garderons donc la totalit des explications
afin que vous puissiez utiliser nimporte quelle combinaison. Examinons donc cette partie :

; switch vers diffrentes interrupts


; inverser ordre pour modifier priorits
;----------------------------------------

btfsc INTCON,T0IE ; tester si interrupt timer autorise


btfss INTCON,T0IF ; oui, tester si interrupt timer en cours
goto intsw1 ; non test suivant
call inttimer ; oui, traiter interrupt timer
goto restorereg ; et fin d'interruption
; SUPPRIMER CETTE LIGNE POUR
; TRAITER PLUSIEURS INTERRUPT
; EN 1 SEULE FOIS

Les 2 premires instructions examinent si nous avons affaire une interruption tmr0.
Vous allez me dire : pourquoi 2 lignes ? Il suffit dexaminer T0IF, tout simplement.

Et bien, ce nest pas si simple. Imaginons en effet que le tmr0, que nous nutilisons pas,
ait dbord. Le bit T0IF est donc mis 1 et na pas gnr dinterruption, car T0IE est 0. De
mme, si nous avions accept les interruptions timer et que linterruption soit due une autre
cause, nous aurions T0IE 1 et T0IF 0.

Nous ne devons donc traiter linterruption que si linterruption est en service, et que si le
flag est positionn, do le double test. Examinez ce double test et observez le fonctionnement
des btfsc et btfss :

Si T0IE vaut 0, on saute directement au test suivant par la ligne goto. Sil vaut 1, on teste
ensuite T0IF. Si celui-ci vaut 0, on arrive la ligne goto qui passe au test suivant. Sil vaut
galement 1, on appelle la sous-routine de traitement de linterruption timer0.

La dernire ligne permet de sauter la fin de la routine dinterruption, donc de restaurer


les registres et de sortir. Donc, dans le cas o on aurait deux sources dinterruptions
simultanes, une seule serait traite la fois. Si par contre on supprime cette ligne,

136
linterruption suivante sera traite ds celle en cours termine. Jai donc tudi cette ossature
pour vous laisser toutes les variantes possibles, et directement utilisables.

Remarques

- Si on nutilise jamais linterruption tmr0, on peut supprimer cette partie de code

- Si linterruption tmr0 tait en service tout au long du programme, on pourrait


supprimer le test de T0IE (car il serait tout le temps 1)

- En cas de 2 interruptions simultanes de 2 vnements distincts, la premire


interruption traite sera celle teste en premier. Lordre des tests modifie donc la
priorit de traitement des interruptions.

Ensuite, nous trouvons la mme procdure pour les interruptions de type RB0 (dont nous
allons nous servir) et dinterruption RB4/RB7. Remarquez lemplacement prvu pour ajouter
le test pour linterruption eeprom. Nous complterons m16F84.asm ce niveau en tudiant les
procdures dcriture en eeprom. Toutes ces modifications ont t incluses dans le fichier
m16f84_new.asm .

intsw1
btfsc INTCON , INTE ; tester si interrupt RB0 autorise
btfss INTCON , INTF ; oui, tester si interrupt RB0 en cours
goto intsw2 ; non sauter au test suivant
call intrb0 ; oui, traiter interrupt RB0
bcf INTCON,INTF ; effacer flag interupt RB0
goto restorereg ; et fin d'interruption
; SUPPRIMER CETTE LIGNE POUR
; TRAITER PLUSIEURS INTERRUPT
; EN 1 SEULE FOIS
intsw2
btfsc INTCON,RBIE ; tester si interrupt RB4/7 autorise
btfss INTCON,RBIF ; oui, tester si interrupt RB4/7 en cours
goto intsw3 ; non sauter
call intrb4 ; oui, traiter interrupt RB4/7
bcf INTCON,RBIF ; effacer flag interupt RB4/7
goto restorereg ; et fin d'interrupt
intsw3

; ici, la place pour linterruption eeprom

Enfin, nous trouvons la partie servant la restauration des registres sauvegards. Nous
avons dj vu cette procdure :

;restaurer registres
;-------------------
restorereg
swapf status_temp , w ; swap ancien status, rsultat dans w
movwf STATUS ; restaurer status
swapf w_temp , f ; Inversion L et H de l'ancien W
; sans modifier Z
swapf w_temp , w ; R-inversion de L et H dans W
; W restaur sans modifier status
retfie ; return from interrupt

137
12.10 Adaptation de la routine dinterruption

Nous allons maintenant modifier cette routine dinterruption pour ladapter notre cas
prcis. Nous navons quune seule source dinterruption valide, donc, si nous entrons dans
cette interruption, ce sera forcment pour traiter INT/RB0. Supprimons donc les tests. Il nous
reste donc :
;**********************************************************************
; ROUTINE INTERRUPTION *
;**********************************************************************

;sauvegarder registres
;---------------------
org 0x004 ; adresse d'interruption
movwf w_temp ; sauver registre W
swapf STATUS , w ; swap status avec rsultat dans w
movwf status_temp ; sauver status swapp
call intrb0 ; traiter interrupt RB0

;restaurer registres
;-------------------

swapf status_temp , w ; swap ancien status, rsultat dans w


movwf STATUS ; restaurer status
swapf w_temp , f ; Inversion L et H de l'ancien W
; sans modifier Z
swapf w_temp , w ; R-inversion de L et H dans W
; W restaur sans modifier status
retfie ; return from interrupt

Nous pourrions galement nous passer de la ligne call intrb0, et placer la procdure de
traitement directement sa place. Conservons cependant cet appel de sous-routine, car nous
ne sommes pas quelques instructions ni un emplacement de pile prs. En cas o vous
devriez optimiser une application lextrme, vous pourriez y penser. Dans le cas contraire, je
vous conseille de donner priorit la lisibilit de votre programme (oui, jinsiste encore).

Voyons maintenant la suite du programme. Nous allons trouver les 3 routines de


traitement des interruptions appeles lorigine par notre routine dinterruption. Comme nous
avons supprim 2 de ces appels, inutile de conserver les sous-routines correspondantes. La
seule dont nous aurons besoin sera donc :

;**********************************************************************
; INTERRUPTION RB0/INT *
;**********************************************************************
intrb0
return ; fin d'interruption RB0/INT
; peut tre remplac par
; retlw pour retour code d'erreur

Elle ne contient que le retour de sous-routine correspondant lappel du call intrb0.


Attention, ce niveau vous nutiliserez pas RETFIE, car vous ne sortez pas de
linterruption, vous sortez dune sous-routine appele par la routine dinterruption.

Si vous utilisiez RETFIE ce moment, vous remettriez les interruptions en service avant
den sortir, donc plantage de votre programme.

138
Remarquez que vous pourriez utiliser retlw pour retourner une valeur prdfinie traite
dans votre routine dinterruption. Par exemple, retlw0 si on veut traiter dautres interruptions
et retlw 1 si on sort de la routine. Dans ce cas, la ligne

goto restorereg ; et fin d'interruption

correspondante pourrait tre prcde du test de w retourn par la sous-routine. Ceci est
un exemple un peu complexe traiter ici, mais parfaitement envisageable lorsque vous
jonglerez avec les PIC.

12.11 Linitialisation

Poursuivons : nous trouvons la routine dinitialisation que nous avons dj explique


la leon prcdente. Nous nous contenterons de remplacer les changements de banque par
les macros que nous avons crites , et configurer RA2 en sortie pour la LED.

Nous obtenons :
;*********************************************************************
; INITIALISATIONS *
;*********************************************************************

init
clrf PORTA ; Sorties portA 0
clrf PORTB ; sorties portB 0
clrf EEADR ; permet de diminuer la consommation
BANK1 ; passer banque1
movlw OPTIONVAL ; charger masque
movwf OPTION_REG ; initialiser registre option

; Effacer RAM
; ----------------
movlw 0x0c ; initialisation pointeur
movwf FSR ; pointeur d'adressage indirect
init1
clrf INDF ; effacer ram
incf FSR,f ; pointer sur suivant
btfss FSR , 6 ; tester si fin zone atteinte (>=0x40)
goto init1 ; non, boucler
btfss FSR , 4 ; tester si fin zone atteinte (>=0x50)
goto init1 ; non, boucler

; configurer PORTS
; ---------------
bcf LED ; RA2 en sortie (TRISA)

BANK0 ; passer banque 0


movlw INTERMASK ; masque interruption
movwf INTCON ; charger interrupt control
goto start ; sauter programme principal

Il ne nous reste plus qu supprimer la ligne

clrwdt ; effacer watch dog

du programme principal, puisque nous avons dsactiv le watchdog.

139
Remarque

Une grande partie des erreurs dans les programmes est le fait derreurs de
slection de banques (surtout pour les PIC 4 banques). Je vous conseille dadopter
comme convention de toujours entrer dans une routine avec la banque 0, et de toujours
sassurer que vous tes en banque 0 avant den sortir. En cas de drogation, indiquez-le
clairement dans len-tte de votre sous-routine.

Lancez lassemblage pour vrifier que vous navez pas fait derreurs. Vous devriez obtenir
ceci (au numro de ligne prs) :
Message[302] D:\DOCUME~1\LESSONS\DATAPIC\MYINTER.ASM 143 : Register in operand
not in bank 0. Ensure that bank bits are correct.

Build completed.

Je ne reviendrai pas ici sur les warnings.

12.12 Construction du programme principal

Nous allons maintenant raliser un tlrupteur. Quest-ce dire ? Et bien nous allons
raliser la fonction suivante : Une pression sur le bouton-poussoir allume la LED, une
seconde pression lteint. Je vais vous guider pas pas dans cette petite ralisation, en
essayant de vous montrer les problmes pratiques rencontrs dans une ralisation de ce type.

Je rappelle que ceci est un programme didactique. Nous raliserons ce tlrupteur de


manire un peu plus lgante dans la leon sur le timer0.

Puisque nous dsirons utiliser les interruptions, linversion de lallumage de la LED se


fera dans la routine dinterruption du bouton-poussoir. Dans un premier temps, nous pourrions
penser que le programme principal na rien faire.

Remarque trs importante

En aucun cas vous ne pouvez laisser un programme se balader hors de la zone


de votre programme. Si le programme na plus rien du tout faire, vous devez alors le
boucler sur lui-mme. Car le programme ne sarrte pas (sauf passage en mode sleep
que nous verrons plus tard).

Notre programme principal pourrait donc tre de la forme :

start
goto start ; boucler

Mais, pour faciliter la visualisation de ce qui se passe sous lmulateur, je vous


demanderai dajouter quelques NOP inutiles.

Voil donc notre programme principal :

140
;*********************************************************************
; PROGRAMME PRINCIPAL *
;*********************************************************************
start
nop ; instruction inutile
nop ; instruction inutile
nop ; instruction inutile
nop ; instruction inutile
nop ; instruction inutile
goto start ; boucler
END ; directive fin de programme

12.13 Construction de la routine dinterruption

Nous avons programm le PIC de faon ce quune interruption sur flanc


descendant de INT/RB0 provoque une interruption. Il nous suffit donc dexcuter dans cette
routine dinterruption linversion du niveau de la LED. Nous avons dit inverser un bit ?
Ceci devrait vous faire penser la lopration logique Ou exclusif Nous pouvons donc
crire :

;**********************************************************************
; INTERRUPTION RB0/INT *
;**********************************************************************
;----------------------------------------------------------------------
; inverse le niveau de RA2 chaque passage
;----------------------------------------------------------------------
intrb0
movlw B'00000100' ; bit positionn = bit inverser
BANK0 ; car on ne sait pas sur quelle banque
; on est dans une interruption (le programme
; principal peut avoir chang de banque). Ce nest
; pas le cas ici,mais c'est une sage prcaution
xorwf PORTA , f ; inverser RA2
return ; fin d'interruption RB0/IN

Notez qu ce stade notre LED est dfinie par la ligne


#DEFINE LED PORTA , 2 ; LED

Il nous suffit donc de changer cette ligne pour placer notre Led sur une autre pin, sans
intervenir dans notre programme. Par contre, a ne fonctionnera plus au niveau de linversion
de la sortie. Lidal est donc dutiliser galement un define pour le masque en dbut de
programme :

#DEFINE LED PORTA , 2 ; LED


#DEFINE LED_MASK B00000100 ; Masque dinversion de la led

Et ensuite de remplacer la ligne


movlw B'00000100' ; bit positionn = bit inverser

par
movlw LED_MASK ; bit positionn = bit inverser

141
Ainsi on peut rellement changer la LED de pin sans intervenir dans le programme
mais juste au niveau des deux Define .

Voil, notre premier essai est termin. Nous allons passer ce programme au simulateur.
Mais avant, je vous donne lordinogramme du programme que nous avons ralis. Lorsque
vos programmes deviendront complexes, je vous conseille de recourir lordinogramme
avant de les crire, sauf si vous prfrer le pseudo-code (crire le programme en franais).

Ordinogramme 1 (version thoriquement fonctionnelle)

Vous voyez que cette routine dinterruption est on ne peut plus simple, et correspond bien
ce quon pourrait simaginer de prime abord. Nous allons donc commencer par passer le test
du simulateur.

12.14 Passage au simulateur dune routine dinterruption

N oubliez pas que le simulateur doit tre en service, si ce nest pas le cas, faites-le
(voir chapitre sur le debugger). Slectionnez laffichage de la fentre Special Functions
Registers) si ce nest dj fait.

Lanons lassemblage avec <F10>. Ensuite pressez <F6> pour faire le reset du
programme, puis <F7>. Rptez <F7> en suivant lvolution du programme. Noubliez pas
quil va effectuer 68 boucles pour effacer la RAM, soyez patient. Profitez-en pour observer le
comportement de FSR pour ladressage indirect. Vous pouvez galement presser <F9>, et
ensuite <F5> aprs quelques instants.

Une fois arriv dans le programme principal, le programme boucle indfiniment. En


effet, un vnement extrieur (bouton-poussoir) est ncessaire pour provoquer le passage dans
la routine dinterruption. Je vais maintenant vous expliquer comment simuler un vnement
extrieur. Ces explications varient dune version de MPLAB lautre. Une fois votre
apprentissage termin, vous de vous adapter aux diffrences de fonctionnalit, a na rien de
compliqu.

Allez dans le menu debugger -> stimulus . Si par hasard vous avez des messages
derreur concernant un fichier, ignorez-les. Slectionnez longlet pin stimulus

142
Cliquez sur add Row pour obtenir un bouton daction. Une nouvelle ligne est
cre dans la fentre, avec un bouton intitul Fire . Cliquez une fois dans la colonne
pin juste ct du bouton. Les cases pin et action se remplissent. Elargissez les
colonnes la souris pour mieux voir.

Nous allons maintenant prciser laction de notre bouton. Dans la case type , nous
slectionnons asynch pour asynchrone . En effet, lvnement pourra intervenir
nimporte quel moment de lexcution du programme. Ne cliquez pas sur le bouton fire
pour linstant.

A laide du menu droulant de la case pin , nous allons dterminer quelle pin sera
stimule par laction sur le bouton. Comme notre bouton se trouve sur la pin RB0,
slectionnez cette pin.

Si vous regardez dans la case action , vous voyez que vous avez accs au mode de
fonctionnement du bouton. Vous avez le choix entre Pulse (gnre une impulsion), Low
(place un niveau 0), High (place un niveau 1), ou Toggle (inversion du niveau chaque
pression). Nous choisirons la moins pratique pour cet exemple, mais la plus explicite.

Choisissez donc Low . Votre bouton de stimulation est maintenant configur. Vous
devriez obtenir une fentre du style :

143
Crez maintenant une nouvelle ligne, avec add row , et crez un second bouton.

Choisissez High dans la case action. Vous pouvez galement placer un commentaire
dans les cases comments . Ne vous gnez pas.

Examinons le registre PORTB dans la fentre daffichage des registres spciaux.


Vous voyez que tous les bits sont des 0. En effet, MPLAB ne peut pas connatre
llectronique que vous avez connecte sur ses pins. Cest donc vous de lui indiquer le
niveau que vous tes sens avoir sur les dites pins. Pour ceux qui nauraient pas compris le
fonctionnement de la rsistance de rappel, voici une nouvelle fois le schma quivalant :

144
Nous voyons donc que, quand le bouton-poussoir nest pas press, nous avons un
niveau 1 sur RB0 provoqu par la rsistance de rappel que nous avons mise en service.

Pressons donc le second bouton une seule fois, et allons dans lditeur. Pressons <F7>
pour avancer dun pas et valider la modification de niveau. Examinez PORTB : RB0 est
maintenant pass 1. Notre bouton-poussoir nest pas enfonc. Pressez quelques fois <F7>
pour vrifier que rien dautre ne sest pass.

Nous allons maintenant simuler la pression du bouton-poussoir :

- Pressez le premier bouton pour envoyer 0 sur RB0.


- Revenez dans lditeur et pressez une seule fois sur <F7>. Linstruction qui suit
lvnement est alors linstruction situe ladresse 0x04, car le passage de 1 0 sur
RB0 a provoqu notre interruption.
- Avancez lentement par pressions de <F7> dans la routine dinterruption. Examinez
leffet des diffrentes instructions vues. Une fois la ligne :

xorwf PORTA , f ; inverser RA2

excute, vous constatez que la LED sest allume (RA2 est pass 1 sur le registre PORTA).
Avancez lentement jusqu ce que la ligne :

retfie ; return from interrupt

soit slectionne et ne pressez plus <F7>. A cet endroit, nous trouvons le retour de la routine
dinterruption vers le programme principal. Pressez une nouvelle fois <F7>.

Que se passe-t-il ? Au lieu de revenir au programme principal, nous recommenons


une nouvelle interruption.

Pour provoquer une interruption, il faut que le bit Enable ET le bit Flag dune des sources
dinterruptions soient 1. Or, il ny a quun seul bit Enable 1, et cest INTE.

Examinons donc INTF (cest le bit 1 de INTCON). Ce bit est toujours 1, donc
nouvelle interruption. Nous avons donc commis une erreur classique. Nous avons oubli
deffacer le flag la fin du traitement de notre interruption. Remarquez que cet
effacement est intgr dans la partie switch de la routine dinterruption du fichier
m16f84.asm.

145
Nous avons effac cette ligne par mgarde en supprimant les diffrents tests. En fait je
vous lai volontairement fait supprimer linsu de mon plein gr pour paraphraser un
clbre sportif : jai not quon mmorise mieux suite une erreur.

12.15 Premire correction : reset du flag

Il nous faut donc ajouter la ligne suivante dans notre sous-routine intrb0

bcf INTCON , INTF ; effacer flag INT/RB0

Nous obtenons donc :

movlw B'00000100' ; bit positionn = bit invers


BANK0 ; car on ne sait pas sur quelle banque
; on est dans une interruption (le
; programme principal peut avoir chang
; de banque). Ce n'est pas le cas ici,
; mais c'est une sage prcaution
xorwf PORTA , f ; inverser RA2
bcf INTCON , INTF ; effacer flag INT/RB0
return ; fin d'interruption RB0/INT

Assemblons de nouveau notre programme avec <F10>, puis <F6>, et enfin,


recommencez toute la procdure que nous venons de voir.

Vrifiez que la routine dinterruption se termine maintenant en rendant la main au


programme principal.

La LED 1 est maintenant allume (RA2 = 1).

Pressez le second bouton pour simuler le relchement du bouton-poussoir. Pressez


quelques fois <F7> et pressez <RB0 (L)> pour simuler une seconde pression de bouton-
poussoir. Suivez la routine dinterruption et constatez que cette fois la LED steint.

On obtient donc au simulateur le fonctionnement suivant :


- Une pression sur le B.P. (bouton-poussoir) allume la LED
- Une autre pression teint la LED
- Et ainsi de suite.

Nous avons donc obtenu le rsultat souhait.

Placez votre PIC dans le programmateur, et envoyez lui le fichier Myinter.hex .


Placez votre PIC sur la platine dessais (modifie) et pressez le B.P. plusieurs reprises. La
LED ne fonctionne pas du tout comme prvu, Elle ragit, mais de manire alatoire. Que se
passe-t-il ?

146
12.16 Se mettre lchelle de temps du PIC

Souvenez-vous, jai dj attir votre attention sur ce point prcis. Transformons-nous


donc en PIC et examinons ce que nous voyons : En fait, lchelle des temps est lie lchelle
des tailles, nous voyons de ce fait un norme Bouton poussoir, avec un contact lectrique de
la taille dun rail de chemin de fer.

Lorsque ce B.P. est press, cest alors une norme barre qui vient court-circuiter 2
contacts. Cette barre est lastique. Que voit le PIC ? Il voit cette norme barre mtallique
qui tombe dune norme hauteur sur 2 contacts mtalliques. Une fois la barre en contact, elle
rebondit videmment plusieurs fois avant de simmobiliser. A chaque pression sur le B.P., le
PIC voit donc une srie de fermeture et douverture du B.P., au lieu dune seule notre
chelle de temps.

Le PIC est donc plus rapide que notre B.P.

Une nouvelle fois, noubliez donc jamais que les PIC ne travaillent pas une
chelle de temps humaine. Vous devez en tenir compte.

12.17 Le problme de lanti-rebond

Comment remdier ce problme ? Et bien, tout simplement par exemple en


ralentissant les ractions du PIC, et donc en attendant un temps suprieur au temps de
rebondissement avant dautoriser une nouvelle interruption sur RB0.

Nous allons utiliser nos connaissances actuelles pour rsoudre ce problme. Il devient
utile de dessiner un ordinogramme (je vous lavait dit) de ce que nous voulons faire :

147
Explications

Le programme principal effectue normalement ses initialisations, puis teste si une


demande de tempo a t introduite en positionnant le flag tempo . Si le flag nest pas mis,
il boucle sans fin.

Si le B.P. est press, une interruption est gnre, RA2 est invers, la routine
dinterruption positionne le flag tempo 1 et interdit toute nouvelle interruption de RB0.
Toute autre action sur RB0 sera donc sans effet (donc les rebonds ne sont pas pris en compte).
Constatez donc que rien nempche une routine dinterruption de sinterdire elle-mme.

La routine dinterruption prend fin. Retour au programme principal, qui continue alors
tester le flag tempo. Celui-ci vient dtre positionn par la routine dinterruption. Le
programme principal appelle alors une routine de temporisation (que nous avons dj vue
dans la leon principale).

Aprs coulement du temps ncessaire la fin des rebonds, le flag tempo est annul (pour
ne pas boucler sans fin), et les interruptions sont nouveau autorises, afin de permettre de
prendre en compte une nouvelle pression sur le B.P.

Vous voyez donc ici quil peut tre utile dans un programme dinterrompre et de relancer
les interruptions certains moments spcifiques.

12.18 Finalisation du programme

Tout dabord, il nous faut une routine de temporisation. Ouvrez le fichier


Led_cli.asm et effectuez un copier/coller de la routine de temporisation.

;*********************************************************************
; SOUS-ROUTINE DE TEMPORISATION *
;*********************************************************************
;---------------------------------------------------------------------
; Cette sous-routine introduit un retard de 500.000 s.
; Elle ne reoit aucun paramtre 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 ; dcrmenter compteur1
goto boucle1 ; si pas 0, boucler
decfsz cmpt2 , f ; si 0, dcrmenter compteur 2
goto boucle 2 ; si cmpt2 pas 0, recommencer boucle1
decfsz cmpt3 , f ; si 0, dcrmenter compteur 3
goto boucle3 ; si cmpt3 pas 0, recommencer boucle2
return ; retour de la sous-routine

148
Nous allons modifier lgrement cette sous-routine. Nous pouvons enlever la boucle
extrieure, car, 500ms cest beaucoup plus que le temps de rebond du B.P. Enlevons
galement linstruction nop. Nous obtenons :

;*********************************************************************
; SOUS-ROUTINE DE TEMPORISATION *
;*********************************************************************
;---------------------------------------------------------------------
; Cette sous-routine introduit un retard
; Elle ne reoit aucun paramtre et n'en retourne aucun
;---------------------------------------------------------------------
tempo
clrf cmpt2 ; effacer compteur2
boucle2
clrf cmpt1 ; effacer compteur1
boucle1
decfsz cmpt1 , f ; dcrmenter compteur1
goto boucle1 ; si pas 0, boucler
decfsz cmpt2 , f ; si 0, dcrmenter compteur 2
goto boucle2 ; si cmpt2 pas 0, recommencer boucle1
return ; retour de la sous-routine

Nous ne nous sommes donc pas servi de la variable cmpt3. Nous pouvons donc la
supprimer de notre zone des variables. Tant que nous y sommes, nous allons avoir besoin
dun flag, cest dire dun bit. Crons-le dans cette zone.
;*********************************************************************
; DECLARATIONS DE VARIABLES *
;*********************************************************************

CBLOCK 0x00C ; dbut de la zone variables


w_temp :1 ; Sauvegarde de W dans interruption
status_temp : 1 ; Sauvegarde de STATUS dans interrupt
cmpt1 : 1 ; compteur de boucles 1 dans tempo
cmpt2 : 1 ; compteur de boucles 2 dans tempo
flags : 1 ; un octet pour 8 flags
; rservons b0 pour le flag tempo
; b1 : libre
; b2 : libre
; b3 : libre
; b4 : libre
; b5 : libre
; b6 : libre
; b7 : libre
ENDC ; Fin de la zone

#DEFINE tempoF flags, 0 ; Dfinition du flag tempo

Modifions notre programme principal en suivant notre ordinogramme. Nous obtenons :

;*********************************************************************
; PROGRAMME PRINCIPAL
*
;*********************************************************************
start
btfss tempoF ; tester si tempo flag mis
goto start ; non, attendre qu'il soit mis
call tempo ; oui, excuter tempo
bcf tempoF ; effacer flag tempo

149
bsf INTCON , INTE ; remettre interrupts INT en service
goto start ; boucler
END ; directive fin de programme

Il ne reste plus qu modifier notre routine dinterruption en fonction de notre


ordinogramme. Nous obtenons :
;**********************************************************************
; INTERRUPTION RB0/INT *
;**********************************************************************
;----------------------------------------------------------------------
; inverse le niveau de RA2 chaque passage
; interdit toute nouvelle interruption
; valide le flag tempo
;----------------------------------------------------------------------
intrb0
movlw B'00000100' ; bit positionn = bit invers
BANK 0 ; car on ne sait pas sur quelle banque
; on est dans une interruption (le
; programme principal peut avoir chang
; de banque). Ce n'est pas le cas ici,
; mais c'est une sage prcaution
xorwf PORTA , f ; inverser RA2
bcf INTCON , INTF ; effacer flag INT/RB0
bcf INTCON , INTE ; interdire autre inter. RB0
bsf tempoF ; positionner flag tempo
return ; fin d'interruption RB0/INT

Assemblons notre programme et chargeons le nouveau fichier .hex dans notre PIC.
Lanons lalimentation. Cela ne fonctionne toujours pas, pourquoi ? Et bien rflchissons ce
qui se passe.

Une fois la routine dinterruption termine, les interruptions sont invalides.


Linterrupteur rebondit sans causer dappel dinterruption, mais son flag se positionne
cause des rebonds. Souvenez-vous que les bits Enable nagissent pas sur les flags. Donc,
ds que le programme principal remet linterruption en service, une interruption est gnre
directement, INTF ayant t positionn avant, justement pendant le temps o vous ne dsiriez
pas prendre en compte les rebonds.

Vous devez donc penser tout lorsque vous utilisez les interruptions. Si un programme
fonctionne au simulateur et pas sur le circuit rel, commencez par souponnez des problmes
de timing.

Corollaire : ce nest pas parce quun programme fonctionne au simulateur quil est
correct.

Il nous suffit donc dajouter une instruction de reset du flag INTF avant de remettre les
interruptions INT en service.

bcf INTCON , INTF ; effacer flag INT

Bien entendu, vous pouvez vous dire quil devient inutile deffacer ce flag dans la routine
dinterruption. Cest logique, mais il vaut mieux prendre de bonnes habitudes. Laissons donc
cette instruction.

150
Assemblez de nouveau votre programme, et rechargez-le dans votre PIC. Alimentez
votre montage.

Cette fois cela fonctionne parfaitement. Voici un montage trs pratique utiliser. Si vous
remplacez la LED par un petit relais ou un triac optocoupl, vous voil en possession dun
tlrupteur. Placez un bouton-poussoir dans chaque endroit do vous dsirez allumer la
lampe, et vous pouvez allumer ou teindre celle-ci depuis plusieurs endroits, sans utiliser
dinterrupteurs spciaux avec un tas de fils tirer. Cest la technique utilise dans les
immeubles tages.

A titre de bonus, voici le schma dun tlrupteur oprationnel fonctionnant avec votre
programme :

Remarque sur notre programme

Nous avons utilis une temporisation de valeur quelconque. Cette temporisation inhibe
toute action sur le B.P. (cest son but) durant +- 250mS. Donc, vous pourrez presser au grand
maximum 4 fois sur le B.P. par seconde.

Mais quelle est la dure relle des rebonds ? Et bien, elle dpend de linterrupteur
utilis, technologie et taille. Pour connatre le temps de rebond de votre propre interrupteur,
diminuez progressivement la dure de la temporisation. Une fois que votre tlrupteur ne
fonctionne plus chaque pression, vous avez atteint la limite. Calculez alors la dure de votre
temporisation, vous aurez la dure approximative des rebonds. Lordre de grandeur est
souvent de quelques ms.

12.19 Remarques importantes

Souvenez-vous, quune fois que vous utilisez les interruptions dans un programme,
vous ne pouvez jamais savoir le temps qui va sparer 2 instructions successives.

En effet, entre les instructions en question peuvent avoir t traites une ou plusieurs
routine(s) dinterruption.

151
En consquence, vous ne pouvez pas utiliser de calcul de temps en utilisant le calcul
du nombre dinstructions dans toute partie de code dans lequel une interruption risque
de survenir. Du moins si le temps maximal de la routine de temporisation importe, car le
temps mis peut tre allong mais videmment pas tre raccourci (vous avez uniquement la
garantie du temps minimal de votre temporisation).

Notre sous-routine de temporisation de Led-cli , par exemple, dans ces conditions,


donnerait un dlai qui risquerait dtre allong. Dans ce programme, cependant, les
interruptions ne sont plus en service au moment de lexcution de cette temporisation. Voyez
lordinogramme. Et, de toutes faons, le temps perdu dans linterruption serait ngligeable par
rapport la dure de la temporisation.

De plus, pour toute squence dont le droulement en temps est critique et ne peut
tre interrompu, vous devez inhiber les interruptions. A votre charge de les remettre en
service en temps utile.

Une fois que vous utilisez les interruptions, votre programme devra affronter des
vnements asynchrones son droulement. Donc vous ne pourrez jamais tester toutes
les ventualits possibles.

Vous ne pouvez donc jamais etre certain par simulation que votre programme est
completement debugg.

Dsol mais ceci est le lot de tous les programmeurs. Viser labsence totale de bug est
dautant plus irraliste que le programme devient complexe et recours des vnements
asynchrones. Ceci ne veut pas dire que vous ne devez pas absolument chercher viter toutes
les failles prvisibles de vos programmes.

Ceci vous explique pourquoi des gestions de processus critiques en temps rel utilisent
plusieurs ordinateurs (navette spatiale). Ces ordinateurs tant dsynchroniss, un bug de cette
nature qui apparat sur un deux a peu de chance de se produire simultanment sur un second.
Pour savoir lequel a pos problme, il faut donc un troisime ordinateur, la majorit
lemporte.

Pensez toujours ceci si vous tes amens un jour raliser un programme dont dpend la
scurit de personnes ou de biens, et, du reste, ne vous fiez jamais un mcanisme logiciel
comme ultime scurit.

Si vous comprenez bien tout ceci, vous voyez que les bugs ventuels lis des erreurs
de programmation peuvent apparatre tout moment et de faon qui semble alatoire. Et vous
vous tonnez que votre ordinateur plante ?

12.20 Conclusions

Au terme de ce chapitre, vous pouvez apprhender les mcanismes dinterruption et leur


mise en uvre. Nous utiliserons encore cette possibilit dans la leon sur le timer.

152
Jespre avoir dmystifi ce concept, trop souvent imagin comme la mthode des
pros . En ralit, une fois de plus, pas de magie. Ce nest quune exploitation, certes parfois
complexe, de processus simples et faciles apprhender.

Gardez seulement lesprit que vous quittez le monde scurisant et prvisible du


synchrone pour entrer dans le monde de lasynchrone, beaucoup plus difficile simuler
totalement de faon efficace.

Lutilisation des interruptions impose de ce fait la parfaite comprhension des mcanismes


mis en place, et vous oblige envisager toutes les possibilits au niveau de la survenance dun
vnement extrieur. Ceci est surtout vrai pour les programmes avec plusieurs sources
dinterruptions.

Je vous conseille donc fortement, lors de la ralisation de programme complexe, de


commencer par crire un algorithme gnral, soit en franais, soit en utilisant des
ordinogrammes.

153
Notes :

154
13. Le Timer 0
Dans ce chapitre, nous allons parler temporisations et comptages. Le 16F84 ne
comporte quun seul timer sur 8 bits, contrairement dautres PIC de la famille (comme le
16F876). Si on examine attentivement le fonctionnement du timer0, on voit quil sagit en
fait dun compteur.

13.1 Les diffrents modes de fonctionnement

Nous avons vu que le timer0 est en fait un compteur. Mais quallez-vous compter avec ce
timer? Et bien, vous avez deux possibilits :

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

- Vous pouvez aussi dcider de compter les cycles dhorloge du PIC lui-mme.
Dans ce cas, comme lhorloge est fixe, nous compterons donc en ralit du temps.
Donc, nous serons en mode timer.

La slection dun ou lautre de ces deux modes de fonctionnement seffectue par le bit
5 du registre OPTION : T0CS pour Tmr0 Clock Source select bit. (de nouveau le chiffre 0,
par la lettre O)

T0CS = 1 : Fonctionnement en mode compteur


T0CS = 0 : Fonctionnement en mode timer

Dans le cas o vous dcidez de travailler en mode compteur, vous devez aussi
prciser lors de quelle transition de niveau le comptage est effectu. Ceci est prcis grce au
bit 4 du registre OPTION : T0SE pour Timer0 Source Edge select bit.

T0SE = 0 : comptage si lentre RA4/TOKI passe de 0 1


T0SE = 1 : comptage si lentre RA4/TOKI passe de 1 0

13.2 Le registre tmr0

Ce registre, qui se localise ladresse 0x01 en banque 0, 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 dvnements
survenus sur la pin RA4/TOKI.

13.3 Les mthodes dutilisation du timer0

Comment utiliser le timer0, et quelles sont les possibilits offertes ce niveau ? Voil de
quoi nous allons parler ici.

155
13.3.1 Le mode de lecture simple

La premire mthode qui vient lesprit est la suivante : Nous lisons le registre tmr0
pour voir ce quil contient. La valeur lue est le reflet du nombre dvnements survenus, en
prenant garde au fait que le tmr0 ne peut compter que jusque 255. En cas de dpassement, le
tmr0 recommence 0. Cest donc vous de grer cette possibilit.

Petit exemple :

clrf tmr0 ; dbut du comptage 2 cycles plus loin


; (voir remarque encadre plus bas)
xxx ; ici un certain nombre dinstructions
movf tmr0 , w ; charger valeur de comptage
movwf mavariable ; sauver pour traitement ultrieur

13.3.2 Le mode de scrutation du flag

Nous devons savoir ce niveau, que tout dbordement du timer0 (passage de 0xFF
0x00) entrane le positionnement du flag T0IF du registre INTCON. Vous pouvez donc
utiliser ce flag pour dterminer si vous avez eu dbordement du timer0, ou, en dautres
termes, si le temps programm est coul.

Petit exemple :

clrf tmr0 ; dbut du comptage dans 2 cycles


; (voir remarque encadre plus bas)
bcf INTCON , T0IF ; effacement du flag
loop
btfss INTCON , T0IF ; tester si compteur a dbord
goto loop ; non, attendre dbordement
xxx ; poursuivre : 256 vnements couls

Mais vous pourriez vous dire que vous ne dsirez pas forcment attendre 256
incrmentations de tmr0. Supposons que vous dsiriez attendre 100 incrmentations. Il suffit
dans ce cas de placer dans tmr0 une valeur telle que 100 incrmentations plus tard, tmr0
dborde.

exemple :
movlw 256-100 ; charger 256 100
movwf tmr0 ; initialiser tmr0
bcf INTCON,T0IF ; effacement du flag
loop
btfss INTCON,T0IF ; tester si compteur a dbord
goto loop ; non, attendre dbordement
xxx ; oui, poursuivre : 100 vnements couls

Ceci pourrait sembler correct, mais en fait :

Toute modification de TMR0 entrane un arrt de comptage de la part de celui-ci


correspondant 2 cycles dinstruction.

156
Si lexemple prcdent nutilise pas de prdiviseur, il faudra donc tenir compte de
cette perte en plaant 256-98 et non 256-100 dans le timer.

movlw 256-98 ; dbordement dans 100 cycles

13.3.3 Le mode dinterruption

Cest videmment le mode principal dutilisation du timer0. En effet, lorsque T0IE est
positionn dans le registre INTCON, chaque fois que le flag T0IF passe 1, une interruption
est gnre. La procdure utiliser est celle vue dans la leon sur les interruptions.

13.3.4 Les mthodes combines

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

1) A la premire impulsion sur RB0, on lance le timer 0 en mode interruption.


2) A chaque interruption de tmr0, on incrmente une variable
3) A la seconde interruption de RB0, on lit tmr0 et on arrte 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 units .

13.4 Le prdiviseur

Supposons maintenant que nous travaillions avec un quartz de 4MHz. Nous avons donc
dans ce cas (4000000/4) = 1.000.000 de cycles par seconde. Chaque cycle dhorloge dure
donc 1/1000000me de seconde, soit 1s.

Si nous dcidons dutiliser le timer0 dans sa fonction timer et en mode interruption. Nous
aurons donc une interruption toutes les 256s, soit peu prs tous les quarts de millime de
seconde.

Si nous dsirons raliser une LED clignotante une frquence de +- 1Hz, nous aurons
besoin dune temporisation de 500ms, soit 2000 fois plus. Ce nest donc pas pratique.
Nous disposons cependant dun prdiviseur pour diminuer la base de temps du timer .

Quest-ce donc ? Et bien, tout simplement un diviseur dvnements situ avant


lentre de comptage du timer0. Nous pourrons donc dcider davoir incrmentation de tmr0
tous les 2 vnements par exemple, ou encore tous les 64 vnements.

Consquences :

- Notre compteur avance plus lentement, ce qui vite des tas dinterruptions inutiles
- Par contre, notre prcision est limite un multiple de la valeur du prdiviseur

157
Regardez le tableau de la page 16 du datasheet. Vous voyez en bas le tableau des bits PS0
PS2 du registre OPTION qui dterminent la valeur du prdiviseur.

Ces valeurs varient, pour le timer0, entre 2 et 256. Le bit PSA, quant lui, dtermine si le
prdiviseur est affect au timer0 ou au watchdog. Voici un tableau exprimant toutes les
possibilits de ces bits :

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

- PSA PS0 : bits de configuration du prdiviseur


- /tmr0 : valeur du prdiviseur rsultante sur le timer0
- /WD : valeur du prdiviseur rsultante sur le Watchdog
- temps tmr0 : nombre de cycles dinstructions entranant un dbordement de tmr0
- Temps watchdog indique le temps typique disponible entre 2 reset watchdog. La valeur
entre parenthses indique le temps minimal, qui est celui utiliser pour faire face toutes
les circonstances.

Notez que le temps de dbordement du timer dpend la fois du nombre de cycles


compts entre deux dbordements (tableau ci-dessus) ainsi que du temps ncessaire
pour excuter un cycle dinstruction (1s 4Mhz). Par contre, pour le watchdog, ce
temps est fig et ne dpend pas du temps de cycle, et donc de la frquence de votre
horloge.

Remarques importantes :

- Il ny a quun prdiviseur, 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 mme temps.

- Il nexiste pas de prdiviseur = 1 pour le timer0. Si vous ne voulez pas utiliser le


prdiviseur, vous devez donc imprativement le slectionner sur le watchdog avec une valeur
de 1 (ligne violette du tableau).

158
- La valeur contenue dans le prdiviseur nest pas accessible. Par exemple, si vous
dcidez dutiliser un prdiviseur de 64, et quil y a un moment donn 30 vnements dj
survenus, vous navez aucun moyen direct de le savoir. Le prdiviseur limite donc la
prcision en cas de lecture directe puisque vous obtenez un rsultat multiple entier du
prdiviseur.

- Lcriture dans le registre tmr0 efface le contenu du prdiviseur. Les vnements


survenus au niveau du prdiviseur sont donc perdus dans ce cas.

- Toute modification de TMR0 (effacement, incrmentation, opration...) entranera


un arrt du timer correspondant aux deux prochaines incrmentations, ce qui donne
deux units comptes en moins que ce qui tait prvu.

Astuce 1

Si vous deviez, pour une raison ou pour une autre, stopper le timer, il vous suffit de le
passer en mode compteur externe, condition videmment que vous nayez pas
dlectronique relie sa pin de comptage (RA4/T0CKI). Je vous conseille dans ce cas de
forcer un niveau bas sur cette pin, pour viter un comptage gnr par une perturbation
lectromagntique, et, videmment, de rgler T0SE sur 0 (comptage sur front 0->1).

Astuce 2

Je vous ai signal quen cas de lecture du timer, les impulsions dj comptes au


niveau du compteur du prdiviseur, et donc non accessibles, taient perdues pour la mesure.
En fait, il y a une astuce pour avoir une prcision complte mme avec un prdiviseur.

Imaginons que vous dsiriez (par exemple) compter les impulsions reues sur T0CKI
entre deux vnements donns. Imaginons que vous vous soyez arrang pour quen labsence
dimpulsion reue, le niveau sur votre pin soit haut (rsistance de rappel, par exemple). Il
vous suffit alors de dsactiver votre lectronique de comptage (autre pin du PIC, par exemple,
moins que, tout simplement, vous ne receviez plus aucun vnements compter). Imaginons
encore pour notre exemple concret que vous avez reu 53 lments et que votre prdiviseur
soit configur sur 16. partir de cet instant, vous vous trouvez dans la situation suivante :

- Tmr 0 contient 3 (partie entire de 53/16)


- Le compteur du prdiviseur contient 5 : 53 (3*16)

Vous savez donc que vous avez compt entre 48 et 63 vnements, mais vous ignorez la
valeur exacte (pas daccs au compteur du prdiviseur). Lastuce va consister simplement
basculer RA4 en sortie, et envoyer via votre programme des changements de niveau
haut/bas. Ceci va entraner le comptage des vnements que vous avez vous-mme
dclenchs. Il vous suffit alors de compter ces vnements et de surveiller linstant o le timer
va passer de la valeur 3 la valeur 4.

Une fois que vous passez la valeur 4, vous avez comptabilis exactement 64
vnements. Il vous suffit alors de soustraire les vnements gnrs vous-mme, et vous
obtenez le nombre dvnements que vous aviez rellement comptabiliss. Comme quoi, en
rflchissant, on peut se sortir de toutes les situations.

159
13.5 Application pratique du timer0

Nous allons mettre en uvre notre tmr0 dans une premire application pratique.
Reprenons donc notre premier exercice, savoir, faire clignoter une LED la frquence
approximative de 1Hz.

13.5.1 Prparations

Faites un copier/coller de votre nouveau fichier m16f84.asm et renommez cette copie


Led_tmr.asm . Relancez MPLAB et crez un nouveau projet intitul Led_tmr.pjt .
Ajoutez-y votre nud Led_tmr.asm .

Crez votre en-tte (je continue dinsister)

;**********************************************************************
; *
; Fait clignoter une LED une frquence approximative de 1Hz *
; *
;**********************************************************************
; *
; NOM: LED CLIGNOTANTE AVEC TIMER0 *
; Date: 17/02/2001 *
; Version: 1.0 *
; Circuit: Platine d'essai *
; Auteur: Bigonoff *
; *
;**********************************************************************
; *
; Fichier requis: P16F84.inc *
; *
;**********************************************************************
; *
; Notes: Utilisation didactique du tmr0 en mode interruption *
;**********************************************************************

Dfinissez ensuite les configurations en plaant le watch-dog hors service. Vous


savez maintenant comment procder.

Calculons ensuite le nombre de dbordements de tmr0 ncessaires. Nous avons besoin


dune temporisation de 500 ms, soit 500.000s, soit 500.000 temps de cycle dinstruction

Le timer0 gnre, sans prdiviseur, une interruption tous les 256 cycles . Nous allons donc
utiliser le prdiviseur. Si nous prenons la plus grande valeur disponible, soit 256, nous
aurons donc une interruption toutes les (256*256) = 65536 temps de cycle = 65536s (
4Mhz).

Nous devrons donc passer (500.000/65536) = 7,63 fois dans notre routine dinterruption.
Comme nous ne pouvons pas passer un nombre dcimal de fois, nous choisirons 7 ou 8 fois,
suivant que nous acceptons une erreur dans un sens ou dans lautre.

Notez que si vous passez 7 fois, vous aurez compt trop peu de temps, il sera toujours
possible dallonger ce temps. Dans le cas contraire, vous aurez trop attendu, donc plus de
correction possible.

160
Il est vident que lacceptation dune erreur est fonction de lapplication. Si vous
dsirez faire clignoter une guirlande de Nol, lerreur de timing sera drisoire. Si par contre
vous dsirez construire un chronomtre, une telle erreur sera inacceptable. Commenons donc
par ignorer lerreur.

Nous allons dcider dutiliser une prdivision de 256 avec 7 passages dans la routine
dinterruption. Le temps obtenu sera donc en ralit de (256*256*7) = 458752s au lieu de
nos 500.000s thoriques.

En reprenant notre tableau page16 sur le contenu du registre OPTION, nous devrons
donc initialiser celui-ci avec : B10000111, soit 0x87. En effet, rsistances de rappel hors-
service (on nen na pas besoin), source timer0 en interne et prdiviseur sur timer0 avec
valeur 256. Nous obtenons donc :

OPTIONVAL EQU H'87' ; Valeur registre option


; Rsistance pull-up OFF
; Prscaler timer 256

Ensuite nous devons dterminer la valeur placer dans le registre INTCON pour obtenir
les interruptions sur le timer0. Ce sera B10100000, soit 0xA0

INTERMASK EQU H'A0' ; Interruptions sur tmr0

Ensuite, nos dfinitions :

;*********************************************************************
; DEFINE *
;*********************************************************************
#DEFINE LED PORTA,2 ; LED

Ne touchons pas notre routine dinterruption principale, car nous avons


suffisamment de place pour conserver nos tests.

Ecrivons donc notre routine dinterruption timer. Nous voyons tout dabord que nous
allons devoir compter les passages dans tmr0, nous allons donc avoir besoin dune variable.
Dclarons-la dans la zone 0X0C.

cmpt : 1 ; compteur de passage

13.5.2 Linitialisation

Comme il est plus facile de dtecter une valeur gale 0 qu 7, nous


dcrmenterons donc notre variable de 7 0. Nous inverserons la LED une fois la valeur 0
atteinte. Nous devons donc initialiser notre variable 7 pour le premier passage.

Nous effectuerons ceci dans la routine dinitialisation, avant le goto start. Profitons-en
galement pour placer notre port LED en sortie.

Nous obtenons donc :

161
;*********************************************************************
; INITIALISATIONS *
;*********************************************************************
init
clrf PORTA ; Sorties portA 0
clrf PORTB ; sorties portB 0
clrf EEADR ; permet de diminuer la consommation
BANK1 ; passer banque1
movlw OPTIONVAL ; charger masque
movwf OPTION_REG ; initialiser registre option

; Effacer RAM
; ------------
movlw 0x0c ; initialisation pointeur
movwf FSR ; pointeur d'adressage indirect
init1
clrf INDF ; effacer ram
incf FSR,f ; pointer sur suivant
btfss FSR,6 ; tester si fin zone atteinte (>=0x40)
goto init1 ; non, boucler
btfss FSR,4 ; tester si fin zone atteinte (>=0x50)
goto init1 ; non, boucler

; initialiser ports
; -----------------
bcf LED ; passer LED en sortie
BANK0 ; passer banque 0

movlw INTERMASK ; masque interruption


movwf INTCON ; charger interrupt control

; initialisations variables
; -------------------------
movlw 7 ; charger 7
movwf cmpt ; initialiser compteur de passages

goto start ; sauter programme principal

13.5.3 La routine dinterruption

Ralisons donc maintenant notre routine dinterruption :

Tout dabord, on dcrmente notre compteur de passage, sil nest pas nul, on na rien
faire lors de ce passage, tant donn quon nagit quune fois tous les 7 passages.

decfsz cmpt , f ; dcrmenter compteur de passages


return ; pas 0, on ne fait rien

Ensuite, si le rsultat est nul , nous devons inverser la LED et recharger 7 dans le
compteur de passages. Voici le rsultat final :

162
;**********************************************************************
; INTERRUPTION TIMER 0 *
;**********************************************************************
inttimer
decfsz cmpt , f ; dcrmenter compteur de passages
return ; pas 0, on ne fait rien
BANK0 ; par prcaution
movlw b'00000100' ; slectionner bit inverser
xorwf PORTA , f ; inverser LED
movlw 7 ; pour 7 nouveaux passages
movwf cmpt ; dans compteur de passages
return ; fin d'interruption timer

Il ne nous reste plus qu effacer la ligne

clrwdt ; effacer watch dog

du programme principal, puisque le watchdog nest pas en service. Notez que si vous ne
leffacez pas a na aucune importance, la ligne est de toutes faons sans aucun effet en
labsence de watchdog.

Assemblez votre programme. Nous allons maintenant le passer au simulateur.

Noubliez pas de mettre le simulateur en service, et ouvrez la fentre des registres


spciaux. Avancez ensuite votre programme en pas pas jusqu ce quil arrive dans le
programme principal.

Remarques

- Le dernier registre est dans la fentre des registres spciaux T0pre est un registre qui
nest pas rellement accessible, il sagit du compteur de notre prdiviseur. Si vous pouvez
le voir, cest que cest MPLAB qui compte les prdivisions pour les besoins de la
simulation. Ce registre napparat cependant plus dans les versions de MPLAB
suprieures 5.x pour les PIC16F (bien pour les 18F). Peut-tre quil rapparatra
dans une future version, cest pour cela que je vous le signale.

- Chaque fois que T0pre atteint la valeur de prdivision, tmr0 est incrment de 1. Ce
nest que lorsquil dbordera que nous aurons une interruption.

- Dans le programme principal, T0pre est incrment de 2 units chaque pression sur
<F7>. Cest normal, car ce programme ne comporte quun saut (goto), et chaque saut
prend 2 cycles.

En labsence de visualisation de T0pre, il ne vous reste qu limaginer en comptant les


temps de cycle entre deux dbordements du timer.

13.6 Modification des registres dans le simulateur

Comme nous nallons pas passer des heures simuler ce programme, nous allons modifier
les registres en cours de simulation. Ceci est trs simple effectuer dans MPLAB6,
puisquil suffit de double-cliquer sur la valeur modifier, dans la fentre Special Function

163
Nous allons nous servir de cette possibilit. Premirement, supprimons le prdiviseur.
Pour ce faire, nous allons crire B10001000, soit 0x88. Double-cliquez sur la case hex
de la ligne OPTION_REG

Maintenant, chaque pression de <F7> incrmente tmr0 (pas de prdiviseur)

Ouvrez ensuite une fentre de visualisation des variables, avec view >watch. Affichez
ensuite la variable cmpt comme expliqu dans les chapitres prcdents.

Continuez de presser <F7> et constatez que le dbordement de tmr0 provoque une


interruption et que cette interruption provoque la dcrmentation de cmpt. Pour ne pas
attendre trop longtemps, servez-vous de la fentre modify pour positionner cmpt 1.

Ensuite, poursuivez la simulation. Vous constaterez que la prochaine interruption


provoque la modification de RA2.

13.7 Mise en place sur la platine dessais

Chargez le fichier .hex obtenu dans votre PIC et alimentez votre platine dessais.
Comptez les allumages de la LED obtenus en 1 minute. Vous devriez trouver aux alentours de
65/66 pulses par minute. Ceci vous montre la prcision obtenue.

En ralit, vous aurez un allumage toutes les (256*256*7*2) = 917504S.

En 1 minute, on devrait obtenir : 60.000.000/917504 = 65,3 allumages. La thorie rejoint


la pratique.

Le fichier est fourni sous la dnomination led_tmr1.asm .

13.8 Premire amlioration de la prcision

Nous allons chercher amliorer la prcision de notre programme. Nous pouvons


commencer par modifier notre prdiviseur. Essayons plusieurs valeurs successives :

/1 : donne 500000/256 = 1953,125 passages. Pas pratique


/2 : donne 500000/512 = 976,5625 passages. Pas plus pratique
/4 : donne 500000/1024 = 488,28125 passages . Idem
/8 : donne 500000/2048 = 244,140625 passages. Dans ce cas, un seul compteur est
galement ncessaire, car le nombre de passages est infrieur 256.

Quelle va tre la prcision obtenue ? Et bien, nous initialiserons cmpt 244, avec
prdiviseur 8. Dans ce cas, la dure obtenue sera de :

256*8*244 = 499712 s, donc 499712*2 = 999424s par allumage.

164
En une minute, nous aurons donc 60000000/999424 = 60,034 allumages. Voici donc
une prcision nettement meilleure.

Vous pouvez maintenant modifier vous-mme votre programme selon ces indications.

Vous voyez que vous devez modifier la valeur 07 en 244 2 endroits. Ce nest pas
pratique. Ajoutez donc une assignation, par exemple :

TIMEBASE EQU D244 ; base de temps = 244 dcimal

Si vous avez un problme, le fichier fonctionnel de cet exercice est disponible sous la
dnomination Led_tmr.asm .

- Avantage obtenu : Une plus grande prcision

- Inconvnient : plus dinterruptions gnres, donc plus de temps perdu pour le


programme principal. Dans notre cas, cela na pas dimportance, le programme ne fait
rien dautre, mais ce ne sera pas toujours le cas.

13.9 Seconde amlioration de la prcision

Vous pouvez encore amliorer la prcision de votre programme. En effet, vous pouvez
ne pas utiliser de prdiviseur, donc utiliser plusieurs compteurs pour 1953,125 passages. Au
1953me passage, vous pourrez mme gnrer une dernire tempo en ajoutant une valeur au
tmr0. Par exemple :

- On dtecte 1953 passages laide de plusieurs compteurs

- Lors du 1953me passage, on en est 1953*256 = 499968s, il nous manque donc :


500.000 - 499.968 = 32s.

- On devrait donc ajouter 256-32 = 224 tmr0, mais vu les 2 incrments perdus
systmatiquement lors de toute modification de TMR0, on ajoutera 256-30 :

movlw 226 ; dbordement dans 30 + 2 cycles


addwf tmr0

Bien entendu, 32s pour tout raliser, cest trs court, aussi nous devrons optimiser les
routines dinterruption au maximum. Suppression des tests et des sous-programmes etc. Mais
cela reste en gnral possible. Nous ne traiterons pas ce procd ici, car cela ne prsente pas
dintrt, dautant que les interruptions vont finir par occuper la majorit du temps CPU.

13.10 La mthode dite de rattrapage

Il existe une mthode astucieuse qui garantit quau bout dun temps donn vous aurez
le bon nombre dinterruptions, et donc dallumage de votre LED (dans notre cas). Par contre,
cette mthode ne garantit pas un temps constant entre deux interruptions successives.

165
Lastuce consiste diviser le temps souhait en un nombre entier dinterruptions.
Ensuite, nous prenons en compte la partie fractionnaire qui a t perdue. Si nous
reprenons notre exemple 13.8, nous trouvions quil nous fallait 244, interruptions pour
obtenir une demi-seconde.

Nous prenons donc 244 interruptions. Vu les paramtres utiliss nous obtenons une
interruption toutes les 256 * 8 = 2048s.

Or, il nous aurait fallu en ralit, pour obtenir 500ms au bout de 244 interruptions, un
temps de 500.000 / 244 = 2049,180327868852459016393442623s. Il nous manque donc
1,1803 s chaque interruption pour obtenir la bonne dure.

Qu cela ne tienne, plutt que de tenter de rectifier, nous allons mmoriser les temps
perdus, en les cumulant dans une ou plusieurs variables. Plus nous voulons de prcision, plus
il faut videmment mmoriser de chiffres significatifs. Limitons-nous aux 4 premires
dcimales. On ne va videmment pas travailler avec des dcimales, et donc on va tout
convertir en dix-millimes de s.

Lors de chaque passage, nous allons ajouter le temps perdu, soit 11803 notre
compteur de temps perdu. Une fois que ce compteur aura atteint ou dpass la dure dune
interruption, soit 20480000 (il faut une variable sur plusieurs octets, videmment), alors il
nous suffira de :

1) Prendre en compte une interruption supplmentaire (245 au lieu de 244)


2) Soustraire ce temps rattrap, soit 20480000 de notre compteur de temps perdu.

Ainsi, nous obtenons un temps moyen de (dans notre cas) 2049,1803s, et donc une
temporisation moyenne de 2049,1803 * 244 = 499999,9932s. Nous obtenons donc un
nombre moyen de clignotement de led de 60,0000008 allumages par seconde.

Notez lextraordinaire augmentation de la prcision. Le seul inconvnient est quentre


deux commutations de la led nous pourrons avoir une diffrence de temps de 2048s, donc
2ms, ce qui est absolument imperceptible.

Vous pouvez aussi diminuer le nombre de calculs de la faon suivante : il nous fallait
244,140625 interruptions pour obtenir un dlai de 500ms. Donc, chaque inversion de la led
(toutes les 244 interruptions) nous avons perdu 0,140625 interruption. Il nous suffit donc de
comptabiliser 140625 (millionime) toutes les 244 interruptions, et dajouter une interruption,
donc 245 au lieu de 244 de la mme faon que prcdemment, chaque fois que nous
atteignons la valeur 1000000 (1 interruption entire). La mthode est la mme, seule la faon
de prendre en compte les temps perdu change.

Voici une mthode trs puissante pour obtenir des temps moyens trs prcis. Vous
trouverez une application relle dhorloge base sur ce principe sur mon site, page trucs et
astuces , via lexcellente application dhorloge en temps rel dErio, qui explique
parfaitement cette mthode, et que je remercie au passage.

166
13.11 La mthode hardware - Adaptation de lhorloge

Supposons que vous vouliez construire un chronomtre. La prcision est la donne la plus
importante dans ce cas, et passe bien avant la vitesse. Nous allons donc nous arranger pour
que les dmultiplicateurs tombent sur des multiples entiers. Comment ? Et bien simplement
en changeant le temps dune instruction, donc, en changeant le quartz du PIC.

Exemple :

Comme nous ne pouvons pas acclrer un PIC au dessus de sa vitesse maximale


(nous utilisons un PIC 4MHz), nous pouvons seulement le ralentir. Nous partons donc dune
base de temps trop rapide.

Par exemple : reprenons notre cas de dpart : prdiviseur 256, compteur de passages 7.
Dure avec un quartz de 4MHz : 256*256*7 par tempo, donc 256*256*7*2 par allumage, soit
917504 s. Or, nous dsirons 1000000s.

Il suffit donc de recalculer lenvers :


Que doit durer une instruction ? 1000000/(256*256*7*2) = 1,089913504s.

Cela nous donne donc une frquence dinstructions de 1/1,089913504s = 0,917504


MHz.

Comme la frquence des cycles internes est gale la frquence du quartz/4, nous aurons
donc besoin dun quartz de 0,917504 * 4 = 3,670016 MHz. (MHz car nous avons divis par
des s : or, diviser par un millionime revient multiplier par un million).

La seule contrainte est donc de savoir sil existe des quartz de cette frquence
disponibles dans le commerce. Dans le cas contraire, vous recommencez vos calculs avec
dautres valeurs de prdiviseurs et de compteur. Soyez certains que vous allez trouver des
quartz permettant une division exacte, pour la simple raison que plein dhorloges quartz sont
bases sur des microcontrleurs, rencontrant le mme genre de contraintes.

Si vous trouvez donc un quartz de frquence approprie, vous obtenez une horloge de
la prcision de votre quartz. Vous ajoutez un affichage, et voil une horloge quartz.

13.12 La mthode de luxe : La double horloge

La mthode prcdente prsente linconvnient de ralentir le PIC. Que faire si vous


voulez la fois une vitesse maximale et une prcision galement maximale ? Et bien,
aucun problme.

Vous alimentez votre PIC avec votre quartz et vous crez un autre oscillateur externe
avec votre quartz spcial timing. Vous appliquez le signal obtenu sur la pin RA4/TOKI et
vous configurez votre timer0 en mode compteur.

Donc, votre PIC tourne vitesse maximale, et les interruptions timer0 sont gnres par
une autre base de temps, plus adapte la mesure de vos vnements.

167
13.13 Exemple dutilisation de 2 interruptions

Dans ce petit exemple nous allons utiliser 2 sources dinterruption diffrentes, afin de
vous montrer un exemple concret de ce type dutilisation. Nous allons recrer notre
programme de tlrupteur, mais en remplaant la temporisation par une interruption sur le
timer0.

Remarquez que notre programme principal ne fait plus rien. Vous pouvez donc utiliser
dautres fonctionnalits sur cette carte sans perturber le fonctionnement du tlrupteur.

Nous aurons donc une interruption pour RB0, et une autre pour tmr0. Vous voyez ci-
dessous lordinogramme qui va nous servir.

Effectuez une copie de votre fichier m16f84.asm et renommez-le telerupt.asm .

Crez un nouveau projet telerupt.pjt . Editez votre fichier comme prcdemment :


coupure du watchdog, positionnement de la LED en sortie, mise en service initiale des
interruptions RB0/INT.

Crez votre routine dinterruption timer0 toutes les 260ms, soit prdiviseur 256, et 4
passages .

168
Essayez de raliser vous-mme ce programme. Chargez-le dans votre PIC et lancez-le.
Notez que lordinogramme ne contient pas le compteur de passages dans tmr0. Je vous laisse
le soin de rflchir.

Une pression sur le B .P. allume la LED, une autre lteint. Si cela ne fonctionne pas,
cherchez lerreur ou servez-vous du simulateur. Je vous fourni le programme fonctionnel avec
les autres fichiers du cours, pour le cas o vous seriez bloqu.

Remarque

Il est trs important de bien comprendre quil faut effacer tmr0 avant deffacer le flag
T0IF et de relancer les interruptions tmr0.

En effet, si vous faites le contraire, vous risquez que tmr0 dborde entre le moment de
leffacement du flag et le moment de leffacement de tmr0. Dans ce cas le flag serait remis
immdiatement aprs lavoir effac. Votre programme pourrait donc avoir des rats par
intermittence.

Il ne faut pas non plus oublier que toute modification de TMR0 entrane le non comptage
des deux prochaines incrmentations prvues.

13.13 Conclusion

Vous savez maintenant exploiter le timer0. Les mthodes voques ici sont une base de
travail pour des applications plus srieuses. Je vous conseille vraiment deffectuer toutes les
manipulations voques. Mme les erreurs vous seront profitables.

169
Notes :

170
14. Les accs en mmoire eeprom
Je vais vous parler dans ce chapitre des procdures daccs dans leeprom interne du
PIC. Il ne faut pas confondre ceci avec lcriture dans une eeprom externe type 2416. Pour
ce type deeprom, il suffit de suivre les directives du datasheet du composant concern,
jen parlerai dailleurs dans le cours-part2.

Il sagit ici dune mmoire particulire : elle ne fait pas partie de la mmoire
programme puisquon ne peut y excuter des instructions, et pourtant elle y ressemble par ses
adresses daccs qui ne ressemblent pas du tout aux accs en mmoire RAM. Elle contient des
lments non volatiles pouvant tre programms en mme temps que la programmation du
PIC, tout en tant accessible directement par le programme en cours dexcution.

14.1 Taille et localisation de la mmoire eeprom

Ladresse physique de la zone eeprom commence, pour les PIC mid-range, ladresse
0x2100.

Cette adresse se situe hors de lespace dadressage de la mmoire programme des


PIC16F (rappelez-vous, maximum 8Ki mots, donc adresse maxi : 0x1FFF), et hors de
lespace dadressage de la RAM (4 banques de 256 lments). Nous pouvons dors et dj en
dduire quil nous faudra utiliser une procdure spciale pour y accder.

Notez dj 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 spciaux des PIC. Par exemple, ladresse
0x2007 contient les paramtres que vous crivez dans _CONFIG. Vous pourriez donc
remplacer cette directive par une initialisation directe ladresse 0x2007. Je vous le
dconseille cependant pour des raisons de portabilit et dvolution rapide vers une autre
famille de PIC. De plus, pourquoi faire compliqu quand on peut faire simple ?

De mme, ladresse 0x2006 contient lidentification du composant. Cest ainsi quun


programmateur volu peut faire la distinction entre un 16F84 et un 16F84A, car leur
identification constructeur diffre.

Le 16F84 dispose de 64 emplacements en mmoire eeprom disponibles pour votre libre


usage. Nous allons voir comment les utiliser.

14.2 Prparation du programme

Commencez par effectuer un copier/coller de votre fichier Led_tmr1.asm et


renommez cette copie en eep_test.asm . Construisez votre nouveau projet dans MPLAB
avec le mme nom et ajoutez-y ce nud.

Editez la zone den-tte du programme

171
;**********************************************************************
; *
; Fait clignoter une LED une frquence dpendant d'une valeur en *
; eeprom *
; *
;**********************************************************************
; *
; NOM: LED CLIGNOTANTE AVEC TIMER0 et utilisation de l'eeprom *
; Date: 18/02/2001 *
; Version: 1.0 *
; Circuit: Platine d'essai *
; Auteur: Bigonoff *
; *
;**********************************************************************
; *
; Fichier requis: P16F84.inc *
; *
;**********************************************************************
; *
; Notes: Dmonstration de l'utilisation des donnes en eeprom *
; La base de temps de clignotement est contenue dans *
; l'eeprom. *
;
*
;**********************************************************************

Ajoutons ensuite une variable dans la zone des variables. Elle contiendra la valeur
recharger dans le compteur.

reload : 1 ; valeur recharger dans compteur

Dans notre programme initial, chaque fois que le compteur de passages dans le timer
arrivait 0, on le rechargeait avec la valeur 0x07. Maintenant, nous le rechargerons avec la
valeur contenue dans la variable reload . La procdure utilise est la suivante :

- On initialise un emplacement eeprom eereload avec la valeur 0x07 lors de la


programmation

- Au dmarrage, on lit leeprom eereload et on place son contenu dans reload

- Le contenu de reload est utilis pour recharger le cmpt une fois celui-ci arriv 0.

Avantage de la procdure : si on modifie la valeur de la base de temps dans leeprom,


cette modification ne sera pas perdue au moment de la remise sous tension de leeprom.

Je vous donne lordinogramme de ce que nous allons raliser dans un premier temps.

172
Vous pourriez remarquer quil peut sembler inutile de lire leeprom et de recopier son
contenu dans reload. Pourquoi donc ne pas utiliser la valeur eeprom directement dans le reste
de notre programme ? La rponse est simple. La procdure de lecture en eeprom est plus
complexe quune simple lecture en RAM. Il faut donc limiter les accs eeprom au
maximum.

Commenons par modifier notre routine dinterruption. La seule ligne modifier cest
celle qui chargeait doffice la valeur 7 dans w. Maintenant, nous y mettons le contenu de
reload. Nous aurons donc :

inttimer
decfsz cmpt , f ; dcrmenter compteur de passages
return ; pas 0, on ne fait rien
BANK0 ; par prcaution
movlw b'00000100' ; slectionner bit inverser
xorwf PORTA , f ; inverser LED
movf reload , w ; charger valeur contenue dans reload
movwf cmpt ; dans compteur de passages
return ; fin d'interruption timer

14.3 Initialisation de la zone eeprom

Nous voyons sur notre ordinogramme que nous lisons notre eeprom afin de placer le
contenu dans notre variable. Mais nous devons bien quant mme initialiser cette eeprom au
moment de la programmation de notre PIC.

Vous vous doutez bien quil ne sert rien dinitialiser leeprom chaque dmarrage du
PIC, sinon, quel est lintrt dutiliser une zone mmoire qui rsiste au reset et la mise
hors tension ?

173
Nous initialiserons donc cette zone directement au moment de la programmation.
Ceci seffectue laide de la directive DE pour Data Eeprom, place dans la zone de
donnes eeprom, cest dire en 0x2100.

Crons donc une zone eeprom, tout de suite aprs celle des variables.

;*********************************************************************
; DECLARATIONS DE LA ZONE EEPROM *
;*********************************************************************
org 0x2100 ; adresse dbut zone eeprom
DE 0x07 ; valeur de recharge du compteur

Lancez lassemblage de votre programme. Vous voulez sans doute vrifier que votre
eeprom contient bien la valeur 0x07 ? Rien de plus simple : lancez EEPROM memory
dans le menu Windows et vous voyez votre valeur.

Mais, allez-vous me rpondre, la valeur est ladresse 0x00 et pas ladresse 0x2100 ?

En effet, il faut distinguer 2 adresses. Ladresse physique de cet emplacement mmoire,


vue par le programmateur est bien 0x2100. Cette adresse est uniquement accessible en
mode programmation.

Par contre, votre programme accdera ces emplacements partir dune procdure
spciale et avec une adresse dite relative. Ladresse vue par votre programme commence
donc 0x00. Il ny a aucun risque de confondre cette adresse 0x00 avec une adresse en RAM,
ni avec ladresse dune instruction, car les accs cette adresse se font avec une procdure
particulire et non via un mode dadressage classique.

Donc, pour rsumer,

- Pour programmer un emplacement Eeprom via votre programmateur, vous utilisez les
adresses commenant 0x2100 via un ORG 0x2100 : aucun risque de confusion avec une
adresse concernant une instruction de la mmoire programme.
- Pour accder un emplacement Eeprom via votre programme, vous utilisez les adresses
commenant 0x00, via une procdure particulire que nous allons dcrire : aucun risque
de confusion non plus.

Bien entendu, vous pouvez galement donner un nom ces adresses, tout comme pour
les variables. Utilisons donc le nom eereload pour dsigner la valeur de reload contenue en
eeprom ladresse 0x00. Ajoutons simplement un #define dans la zone dinitialisation
eeprom

#DEFINE eereload 0x00 ; adresse eeprom de eereload

ou encore

eereload EQU 0x00

Dans notre ordinogramme nous allons avoir besoin de lire leeprom. 4 registres sont
utiliss pour accder leeprom. Nous allons maintenant les examiner.

174
14.4 Le registre EEDATA

Cest dans ce registre que va transiter la donne crire vers ou la donne lue en
provenance de leeprom. Ce registre est situ ladresse 0x08 banque 0.

14.5 Le registre EEADR

Dans ce registre, situ ladresse 0x09 banque 0, nous allons prciser sur 8 bits
ladresse concerne par lopration de lecture ou dcriture en eeprom. Nous voyons dj
que pour cette famille de PIC, nous ne pourrons pas dpasser 256 emplacements
deeprom. Pour le 16F84, la zone admissible va de 0x00 0x3F, soit 64 emplacements.

14.6 Le registre EECON1

Ce registre, situ ladresse 0x88 en banque1, contient 5 bits qui dfinissent ou indiquent
le fonctionnement des cycles de lecture/criture en eeprom. Voici son contenu :

bits 7/6/5

N.U. (non utiliss)

bit 4 : EEIF

Pour EEprom write operation Interrupt Flag bit. Cest le flag qui est en liaison avec
linterruption EEPROM. Il passe 1 une fois lcriture en eeprom termine. Si le bit EEIE
du registre INTCON est 1, une interruption sera alors gnre

bit 3 : WRERR

WRite ERRor. Cest un bit derreur. Il passe 1 si une opration dcriture en eeprom a
t interrompue, par exemple par un reset.

bit 2 : WREN

WRite ENable. Autorisation de dmarrage du cycle dcriture. Cest une sorte de


verrou de scurit.

bit 1 : WR

WRite. Dmarrage du cycle dcriture. Est remis 0 automatiquement une fois


lcriture termine.

bit 0 : RD

ReaD. Dmarrage dun cycle de lecture. Reste 1 durant un cycle, puis est remis 0
automatiquement

175
Remarque : Dans le cas o le cycle dcriture serait interrompu suite au dpassement du
watchdog ou un reset, vous pouvez lire le bit WRERR qui vous le signalera. Les registres
EEDATA et EEADR demeurent inchangs et vous pouvez relancer le cycle dcriture. Ceci
ne fonctionne videmment pas pour une coupure de tension. Dans ce cas, je vous expliquerai
ma mthode personnelle de vrification la fin de ce chapitre.

14.7 Le registre EECON2

Nous revoici en prsence dun registre fantme , puisque ce registre nexiste


physiquement pas, ou, du moins, nest pas rellement accessible. Il sagit tout simplement
dune adresse 0x89 banque1, qui sert envoyer des commandes au PIC concernant les
procdures eeprom. Vous ne pouvez lutiliser quen vous servant des instructions expliques
plus bas.

14.8 Accs en lecture dans la mmoire eeprom

Pour lire une donne en eeprom, il suffit de placer ladresse concerne dans le registre
EEADR. Ensuite, vous positionnez le bit RD 1. Vous pouvez ensuite rcuprer la donne
lue dans le registre EEDATA. Il ne faut pas bien sr oublier les diffrents changements de
banques.

Comme cette procdure est courte et toujours la mme, nous allons crer une macro
cette intention. Comme la macro doit contenir ladresse de lecture, nous raliserons une
macro avec passage de paramtre.

Note : Le terme passage de paramtre est un peu abusif car on ne passe rien en
ralit une macro. Cest plutt lassembleur qui remplace au moment dassembler le
programme tous les termes de paramtres par leur valeur spcifie sur la ligne dexcution
de la macro. Encore une fois, ce nest que du traitement de texte, tout tant connu au moment
de lassemblage (au contraire dun paramtre pass une sous-routine), mais ceci donne
lillusion quon a une routine tout faire laquelle on peut passer un paramtre .

Voici la macro ajouter. Vous devrez tre dans la banque 0 pour appeler cette macro, et
elle vous retourne la valeur lue dans le registre W.
READEE macro adeeprom ; macro avec 1 paramtre (argument)
movlw adeeprom ; charger adresse eeprom (argument reu)
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 banque 0
movf EEDATA , w ; charger valeur lue dans W
endm ; fin de la macro

Vous remarquez que vous spcifiez un argument la macro. Vous dsignez cet ou ces
arguments aprs la directive macro.

176
Nous avons utilis ici largument adeeprom pour indiquer ladresse eeprom. Chaque
utilisation de adeeprom dans notre macro sera simplement remplace par largument reu au
moment de lappel de la macro.

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

READEE eereload ; lecture de ladresse eereload de leeprom

Constatez donc quau moment de lassemblage, MPASM prend connaissance de la


valeur de eereload, et donc remplace cette valeur directement dans le corps de la routine. En
mmoire programme, aprs assemblage, vous ne voyez plus aucune trace dun ventuel
paramtre.

Cette macro effectuera ds lors : Lire leeprom ladresse eereload, cest dire ladresse
0x00.

Cette macro, comme toutes les modifications principales, seront ajoutes votre fichier
m16f84.asm. Je vous le fournis modifi sous la dnomination m16f84_n2.asm .

A partir de la prochaine leon, il remplacera votre fichier m16F84.asm actuel.

Revenons notre ordinogramme. Nous devons donc ajouter la lecture de leeprom dans
linitialisation, et placer cette valeur lue dans reload ET dans cmpt. Voici la routine modifie :
; initialisations variables
; ----------------------------
READEE eereload ; lire emplacement eeprom 0x00
movwf reload ; placer dans reload
movwf cmpt ; et initialiser compteur de passages
goto start ; sauter programme principal

Assemblez votre programme et placez-le dans le PIC. La LED doit maintenant


clignoter une frquence de 1Hz. Si cela ne fonctionne pas, vrifiez ou consultez le fichier
eep_test1.asm fourni avec cette leon.

14.9 Laccs en criture la zone eeprom

Maintenant vous allez me dire avec raison que cela ne sert rien de lire en eeprom si on
narrive pas y crire. Notre programme ne prsente donc aucun avantage par rapport ce
que nous avions auparavant. Votre remarque est tout fait justifie. Aussi allons-nous tudier
la mthode dcriture. Comme vous vous en doutez, cette mthode utilise les mmes registres.

La procdure suivre consiste dabord placer la donne dans le registre EEDATA et


ladresse dans EEADR. Ensuite une squence spcifique (il ny a rien comprendre, cest
impos par le constructeur) doit tre envoye au PIC.

Remarques

- Microchip recommande que cette procdure spcifique ne soit pas interrompue


par une interruption, donc nous couperons les interruptions durant cette phase.

177
- A la fin de la procdure dcriture, la donne nest pas encore enregistre dans
leeprom. Elle le sera approximativement 10ms plus tard (ce qui reprsente tout de
mme pas loin de 10.000 instructions). Vous ne pouvez donc pas crire une
nouvelle valeur en eeprom, ou lire cette valeur avant davoir vrifi la fin de
lcriture prcdente.

- La fin de lcriture peut tre constate par la gnration dune interruption (si le bit
EEIE est positionn), ou par la lecture du flag EEIF (sil avait t remis 0 avant
lcriture), ou encore par consultation du bit WR qui est 1 durant tout le cycle
dcriture.

Nous allons crire une macro dcriture en eeprom. Cette fois, nous devrons passer 2
paramtres, savoir la donne crire (mais nous supposerons que nous lavons place dans
W), et ladresse dcriture.

WRITEE macro addwrite ; la donne se trouve dans W


LOCAL loop ; tiquette locale
movwf EEDATA ; placer data (w) dans registre
movlw addwrite ; charger adresse d'criture
movwf EEADR ; placer dans registre
loop
bcf INTCON , GIE ; interdire interruptions
btfsc INTCON , GIE ; tester si GIE bien 0 (inutile)
goto loop ; non, recommencer (inutile)
bsf STATUS , RP0 ; passer en banque1
bcf EECON1 , EEIF ; effacer flag de fin d'criture
bsf EECON1 , WREN ; autoriser accs criture
movlw 0x55 ; charger 0x55
movwf EECON2 ; envoyer commande
movlw 0xAA ; charger 0xAA
movwf EECON2 ; envoyer commande
bsf EECON1 , WR ; lancer cycle d'criture
bcf EECON1 , WREN ; verrouiller prochaine criture
bsf INTCON , GIE ; rautoriser interruptions
bcf STATUS , RP0 ; repasser en banque 0
endm

Remarques

- Jai utilis ici 3 instructions pour mettre GIE 0. Ceci tait ncessaire cause dun
bug dans le 16C84, que jexplique plus bas, mais a t corrig dans le 16F84 (et
modles suivants). Le test de vrification nest maintenant plus ncessaire. Mais
ceci me donnait loccasion de vous montrer les tiquettes locales. Laissez-le donc pour
exemple, dans le futur utilisez simplement une seule ligne : bcf INTCON,GIE.

- La directive LOCAL prcise que le symbole utilis dans cette macro nexistera qu
lintrieur de celle-ci. Sans cette directive, si vous utilisiez un seul appel de la macro
WRITEE dans votre programme, aucun problme. Si maintenant vous utilisiez 2 fois
cette macro, pour chaque appel MPASM remplacerait WRITEE par toute la liste
dinstructions contenues jusque la directive endm, y compris ltiquette loop . Vous
auriez donc dans votre programme rel 2 fois ltiquette loop 2 emplacements
diffrents. Ceci gnrerait une erreur. La directive LOCAL informe MPASM que

178
chaque utilisation de la macro travaille avec une tiquette loop diffrente. Il ny a
donc plus double emploi.

- Toute la partie en gras/bleu contient la squence impose par Microchip pour


lcriture en eeprom. Il ny a strictement rien comprendre au niveau de ces 4
lignes, elles dclenchent simplement des oprations hardwares internes (ce sont des
sortes dinstructions).

- La procdure dcriture en eeprom est relativement longue mais de plus prend


normment de temps. Pensez que pour remplir la zone complte de 64 octets, il
faudra plus de 6/10me de seconde. Ceci varie cependant dune version de PIC
lautre, vrifiez dans votre datasheet.

- Le nombre de cycle dcritures en eeprom est limit. La dure de vie de leeprom


est denviron 10 millions de cycles. Si votre programme comporte une erreur et quil
crit sans arrt des donnes dans leeprom, votre PIC sera hors service en un peu
moins de 28 heures. Soyez donc vigilants et vrifiez votre programme. De nouveau, le
nombre de cycles (garanti et typique) en criture varie dun modle de PIC lautre,
vrifiez dans votre datasheet.

- Avant dcrire dans leeprom, vous devez vrifier quune autre criture nest en
cours. Utilisez le bit WR du registre EECON1. Sil vaut 0, il ny a pas dcriture
en cours.

Notez que vous avez deux faons de procder pour vrifier cette dernire condition :

- Soit vous attendez la fin de lopration dcriture avant de terminer votre routine
dcriture : vous bloquez votre programme tant que lcriture nest pas termine.

- Soit vous attendez la fin de lcriture prcdente avant den lancer une nouvelle
ventuelle. Vous sortez immdiatement de votre routine, mais avant de la dmarrer
vous vrifiez quune ventuelle criture prcdente nest pas toujours en cours, auquel
cas vous attendez.

Choisissez la mthode en fonction de votre application, mais, dans tous les cas, effectuez
cette vrification. Vous pouvez videmment inclure la vrification directement dans votre
macro.

14.10 Utilisation pratique de la mmoire eeprom

Maintenant, nous allons de nouveau modifier notre programme pour quil crive dans
leeprom. Nous allons incrmenter la dure de temporisation tous les 16 clignotements de
la LED (donc tous les 32 passages dans la routine dinterruption), et sauvegarder cette
nouvelle valeur dans leeprom.

Nous naurons pas besoin des interruptions eeprom ici, mais vous devez avoir compris le
principe des interruptions suffisamment bien pour pouvoir vous en servir en cas de besoin.

Nous allons donc procder la modification de notre routine dinterruption. Nous devons
ajouter un second compteur (cmpt2) en zone RAM. Dclarons donc cette variable.

179
cmpt2 : 1 ; compteur de passages 2

Oui, je sais, il y avait moyen doptimiser tout a pour nutiliser quun compteur. Ce nest
pas le but de cet exercice. Autant rester clair et centrer notre attention sur le sujet de ce
chapitre. La modification est trs simple, en ralit. Dans la routine dinterruption timer, nous
incrmenterons le compteur 2 qui sera utilis dans le programme principal.

Un petit mot sur le bug des interdictions dinterruption sur le 16C84

Sur le 16C84, la fin de lautorisation des interruptions ntait prise en compte quaprs
linstruction suivante. Donc, entre bcf INTCON, GIE et linstruction suivante, une
interruption pouvait avoir lieu.

Comme retfie remettait automatiquement le bit GIE 1, linterruption tait remise en


service linsu du programmeur.

Il tait donc ncessaire, aprs la mise de 0 de GIE, de vrifier si cette mise 0 stait
effectivement ralise. Dans le cas contraire, cest quune interruption avait eu lieu cet
endroit, et il fallait donc recommencer lopration.

A partir du 16F84, les interruptions sont interdites ds linstruction excute, et donc


avant lexcution de linstruction suivante . Le bug nexiste donc plus. Je vous lexplique pour
le cas o vous trouveriez sur le net une des nombreuses applications mettant en uvre ce
vieux PIC qui a longtemps t une rfrence, devenu ensuite 16F84, puis 16F84A.

Bref, voici le nouvel ordinogramme obtenu.

Et la routine dinterruption timer :

180
;**********************************************************************
; INTERRUPTION TIMER 0 *
;**********************************************************************
inttimer
; tester compteur de passages
; --------------------------
decfsz cmpt , f ; dcrmenter compteur de passages
return ; pas 0, on ne fait rien
; inverser LED
; ------------
BANK0 ; par prcaution
movlw b'00000100' ; slectionner bit inverser
xorwf PORTA , f ; inverser LED

; recharger compteur de passages


; ------------------------------
movf reload , w ; charger valeur contenue dans reload
movwf cmpt ; dans compteur de passages

; incrmenter compteur de passages 2


; ----------------------------------
incf cmpt2 , f ; incrmenter compteur de passages2
return ; fin d'interruption timer

Nous allons crire dans leeprom depuis notre programme principal. Pourquoi pas
dans notre routines dinterruption ?

Il faut, dans la mesure du possible, quitter le plus rapidement possible une routine
dinterruption, celles-ci tant en gnral dans un programme, rserves aux traitements
urgents des informations, et ntant pas elles-mmes interruptibles.

Notez que si votre programme ne comporte quune seule source dinterruption, a peut
navoir aucune importance dallonger la dure dexcution de linterruption concerne. Autant
cependant prendre de bonnes habitudes.

Notez que notre macro coupe et relance les interruptions. Vous ne pouvez videmment
pas relancer les interruptions depuis lintrieur dune interruption. Si vous dcidiez dutiliser
la macro lintrieur dune interruptions, vous devez supprimer linstruction de remise en
service (et de coupure) de GIE au niveau de la macro.

Notez de mme que notre macro relance doffice les interruptions. Il est donc vident que
si vous utilisez cette macro dans un code qui nutilise pas les interruptions, vous devrez
galement supprimer la ligne en question. Par contre, pour le cas plus vicieux o les
interruptions seraient en service par intermittente dans votre programme, vous devez ajouter
un test dans votre macro pour ne remettre les interruptions que si elles taient prsentes lors
de lentre dans la macro. Le plus simple est alors de sauver ltat de GIE dans un bit dune
variable RAM (flag) et de ne remettre GIE en service que si ce flag a t positionn.

Voyons donc notre programme principal :

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

181
; tester si 16 inversions de LED
; ------------------------------
btfss cmpt2 , 5 ; tester si 32 passages
goto start ; non, attendre
clrf cmpt2 ; oui, effacer compteur2

; incrmenter reload
; ------------------
incf reload , f ; incrmenter reload
incf reload , f ; incrmenter 2 fois c'est plus visible

; Tester si criture prcdente eeprom termine


; ---------------------------------------------
; facultatif ici, car le temps coul
; est largement suffisant
BANK1 ; passer banque1
wait
btfsc EECON1 , WR ; tester si criture en cours
goto wait ; oui, attendre
BANK0 ; repasser en banque 0

; crire contenu de reload en eeprom


; -----------------------------------
movf reload , w ; charger reload
WRITEE eereload ; crire l'adresse 0x00
goto start ; boucler
END ; directive fin de programme

Assemblez le programme et chargez-le dans le PIC. Placez le montage sur votre


platine dessais. Remarquez que la LED clignote une frquence approximative de 1Hz. Au
17me allumage, la frquence de clignotement diminue lgrement, et ainsi de suite tous les 16
passages.

Estimez la frquence de clignotement en cours, et coupez lalimentation du PIC.


Attendez quelques secondes, et remettez le PIC sous tension. La LED clignote la
frquence prcdente, car le paramtre a t sauvegard en EEPROM .

Le fichier tel quil devrait tre la fin de cette leon est disponible sous la
dnomination eep_test.asm

14.11 Scurisation des accs en mmoire eeprom

Notre programme prcdent souffre dun dfaut grave. Admettons que vous coupiez
lalimentation juste durant lopration dcriture en mmoire eeprom. Dans ce cas, les
donnes prsentes en eeprom pourraient tre corrompues.

Vous avez plusieurs faons courantes de vous prmunir de ce problme :

- Vous pouvez prvoir une rserve dalimentation (condensateur) pour votre PIC, et le
prvenir que la tension principale a t coupe. Ainsi, il nentamera pas de nouvelle
opration dcriture en eeprom (par exemple), la rserve dalimentation lui assurant un
temps ncessaire pour terminer toute opration dcriture ventuelle en cours.

182
- Vous pouvez carrment faire grer lalimentation par votre PIC, surtout sil sagit
dune alimentation sauvegarde (batterie etc). Dans ce cas, lors de lappui sur un BP
(par exemple), le PIC terminera ses oprations en cours, puis se coupera lui-mme son
alimentation via une de ses pins, pilotant lalimentation (tout comme un PC steint
lui-mme).

- Vous pouvez aussi ne vous proccuper de rien lextinction, tout en vrifiant


lallumage suivant que les donnes en eeprom sont valides. Au besoin, utiliser deux
jeux de valeurs pour sassurer den avoir toujours un valide.

Nous allons parler de la dernire mthode, les autres mthodes tant principalement
mettre en uvre au niveau hardware. Voici donc une procdure permettant de vrifier vos
donnes :

- Placez un en-tte dans le premier ou les premiers octets de votre eeprom. Par
exemple, nous placerons 0x55 dans loctet 0.

- Lors de lcriture de nouvelles valeurs dans leeprom, nous commenons par effacer
notre en-tte.

- Puis nous crivons notre ou nos donne(s) dans leeprom

- Pour finir, nous rinscrivons notre en-tte dans leeprom.

Lors dun dmarrage du PIC, si len-tte est prsent, cela signifie que les donnes
eeprom sont valides. Dans le cas contraire, le cycle dcriture a t interrompu. A vous alors
de ragir en consquence, par exemple en rinscrivant dans leeprom les valeurs par dfaut.

Pour augmenter la scurit du systme pour les donnes critiques, vous pouvez placer
plusieurs octets den-tte.

Pour ne pas revenir aux valeurs par dfaut, vous pouvez utiliser 2 blocs de donnes,
chacun commenant par un en-tte : ainsi, si lcriture dans un bloc a t interrompue, vous
pouvez toujours utiliser lautre bloc.

14.12 Conclusion

Voici encore une nouvelle tape franchie dans votre connaissance du 16F84. Vous pouvez
maintenant utiliser la zone eeprom de votre PIC pour y stocker vos donnes rmanentes.

Si vous avez un risque dcriture de plusieurs donnes intervalles rapprochs, noubliez


pas de vrifier la fin de lopration dcriture prcdente avant den dmarrer une nouvelle.

Nhsitez pas exprimenter, mais noubliez pas de vrifier votre programme pour viter
les critures inutiles et trop frquentes dans votre eeprom.

Pas de panique cependant, si votre programme est correctement crit, vous ntes pas prt
datteindre les 1.000.000 de cycles dcritures garantis.

183
Notes :

184
15. Le watchdog

Le watchdog, ou chien de garde est un mcanisme de protection de votre


programme. Il sert surveiller si celui-ci sexcute toujours dans lespace et dans le temps
que vous lui avez attribus.

15.1 Le principe de fonctionnement

La mise en service ou larrt du watchdog se dcide au moment de la programmation


de votre PIC, laide de la directive _CONFIG. Si _WDT_OFF est prcis, le
watchdog ne sera pas en service. Si au contraire vous prcisez _WDT_ON , le watchdog
sera actif. Consquence :

Il nest pas possible de mettre en ou hors service le watchdog durant lexecution de


votre programme !

Le fonctionnement du watchdog est li un timer interne spcifique, qui nest pas


synchronis au programme, ni un vnement extrieur, et qui ne dpend pas de la
frquence de lhorloge de votre PIC.

La dure spcifique de dbordement de ce timer est approximativement de 18ms. Cette


valeur est prendre avec prcaution, car elle varie en fonction de diffrents paramtres
comme la tension dalimentation ou la temprature. Elle peut aussi varier dun modle de PIC
lautre, consultez votre datasheet.

La valeur minimale de dbordement est de 7ms. Cest elle que vous devrez utiliser
dans la pratique.

En effet, Microchip vous garanti quaucun PIC ne provoquera un reset avant ces 7ms.
Il vous indique que le temps moyen de reset de ses PIC sera de 18ms, mais il ne vous
garantit pas ce temps, cest juste un temps gnralement constat . Si vous resettez votre
watchdog au bout de 10ms seulement, votre programme pourrait fonctionner sur une srie de
PIC et pas sur une autre srie, ou, mme, pourrait fonctionner ou non en fonction de la
temprature.

Chaque fois que linstruction clrwdt est envoy au PIC, le timer du watchdog
est remis 0, ainsi que la valeur contenue dans son prdiviseur. Si par accident cette
instruction nest pas reue dans le dlai prvu, le PIC est redmarr ladresse 0x00 et le
bit TO du registre STATUS est mis 0.

En lisant ce bit au dmarrage, vous avez donc la possibilit de dtecter si le PIC vient
dtre mis sous tension, ou si ce dmarrage est du un plantage de votre programme par
dfaut de watchdog.

185
15.2 Le prdiviseur et le watchdog

Nous avons vu dans les leons prcdentes que le prdiviseur pouvait tre affect au tmr0
ou au watchdog, via le bit PSA du registre OPTION. Si nous dcidons de mettre le
prdiviseur sur le watchdog (PSA = 1) , le tableau de la page 16 du datasheet nous donnera
les valeurs du prdiviseur obtenues suivant les bits PS0/PS2.

En ralit, pour le watchdog, il sagit dun postdiviseur, mais cela ne concerne que
llectronique interne du PIC. Vous navez pas vous tracasser pour cette diffrence.

Ce postdiviseur multiplie le temps de dbordement du timer du watchdog. Par


exemple, avec un diviseur de 2, vous obtenez un temps minimal de 7ms*2 = 14ms. En
sachant que le reset seffectuera typiquement aprs une dure de 18ms*2= 36ms.

Donc, pour cet exemple, avec un quartz de 4MHz, cela vous oblige envoyer
linstruction clrwdt au moins une fois tous les 14.000 cycles dinstructions. Dans la plupart
des cas, le reset seffectuera en ralit aprs 18ms*2 = 36ms, soit 36.000 cycles
dinstructions.

15.3 Les rles du watchdog

Le watchdog est destin vrifier que votre programme ne sest pas gar dans
une zone non valide de votre programme (perturbation sur lalimentation par exemple),
ou sil nest pas bloqu dans une boucle sans fin (bug du programme). Il sert galement
rveiller un PIC plac en mode sleep , ce que nous verrons plus tard.

Notez que nous parlons du module watchdog intgr au PIC. Cependant, tout
microcontroleur (et donc un PIC) peut tre quip dun systme de watchdog externe
(circuit resett intervalles priodiques via une pin du microcontroleur), qui prsente
galement des avantages particuliers, comme celui de pouvoir agir directement sur
llectronique externe (coupure de lalimentation gnrale par exemple).

Je vais lister ici quelques notions lies au watchdog, quil soit interne au PIC, ou
ventuellement externe:

1) Le watchdog est un mcanisme interne ou externe destin assurer une scurit relative
l'application place sur site. Il s'active lorsqu'il n'est pas sollicit intervalles rguliers. Il
s'assure que le logiciel embarqu semble continuer fonctionner selon la squence
prvue.

2) Le watchdog peut servir selon les cas redmarrer une application depuis le dbut, la
stopper, la mettre dans un tat scuris, signaler un dfaut, ou toute autre action
voulue par le concepteur de l'application

3) Le watchdog intgr au PIC est tributaire de son fonctionnement lectronique correct.


Son rle consiste provoquer un reset du PIC, charge du concepteur du logiciel
embarqu de prendre les mesures ncessaires ventuelles si le reset est d au watchdog
(arrt, redmarrage ordinaire ou limit, signalisation etc.). Des bits spcifiques sont prvus
pour tester la cause dun reset au sein du programme.

186
4) Le watchdog peut tre externe, ce qui, au prix d'une plus grande complexit de la carte,
peut prsenter l'avantage de pouvoir agir mme en cas de dfaillances lectroniques du
PIC et de ses commandes, le mcanisme n'tant plus tributaire du fonctionnement de
celui-ci. Il peut ainsi par exemple couper l'alimentation gnrale d'un systme, stopper des
moteurs, etc. mme si les circuits de commande principaux sont dfectueux.

5) Le watchdog intgr est une scurit trs efficace au vu de sa simplicit et relativement


fiable pour se sortir de situations non prvues plaant le programme du PIC dans un tat
indtermin. Il devrait d'office tre utilis pour toute application finalise.

6) Le watchdog peut remdier des situations anormales provoques aussi bien par un bug
non dtect en phase de debuggage que par une anomalie de droulement du programme
provoqus soit par un phnomne externe (perturbations, problmes d'alimentation etc.),
par un tat non prvu d'un priphrique (blocage en cours de transmission), ou toute autre
situation anormale.

7) Le watchdog n'est pas une mthode infaillible et absolue permettant de se sortir de toutes
les situations dlicates. Pour les applications risque critique ou ltal (ascenseurs,
machines-outils, etc.), des mcanismes redondants de scurits supplmentaires hardwares
(sans "intelligence embarque") doivent toujours tre prvus. Le port de la ceinture de
scurit augmente votre scurit, mais ne garantira jamais que vous vous sortirez indemne
dun accident, et ne remet pas en cause lutilit des ambulances.

8) Le watchdog n'est pas destin masquer des erreurs de conception des logiciels, un
logiciel correctement conu doit pouvoir tourner sans problme sans activation du
watchdog, qui ne sera donc valid qu'aprs la phase de debuggage.

9) Il ne faut pas insrer dinstruction clrwdt dans les routines d'interruption, sous peine de
cacher une anomalie au niveau du programme principal.

10) Dans les PIC, le watchdog intgr peut permettre la sortie du mode veille du PIC
intervalles de temps rguliers au prix dune relative imprcision.

11) Les PIC 16F (au contraire dautres modles de PIC) sont dpourvus de linstruction
reset . Une faon simple de provoquer un reset software est dutiliser une boucle sans
fin ne contenant pas dinstruction clrwdt , ce qui provoquera un reset du PIC par
dbordement du watchdog.

15.4 Utilisation correcte du watchdog

La premire chose faire, si vous dsirez profiter de cette protection intgre, est de
paramtrer la configuration pour la mise en service du watchdog. La premire chose
constater, cest que :

Si vous indiquez _WDT_ON pour un programme qui ne gre pas le watchdog,


celui-ci redmarrera sans arrt, et donc ne fonctionnera pas, car il ne contiendra aucune
instruction clrwdt .

187
Cest une erreur frquente pour ceux qui ne matrisent pas les bits de configuration de
leur programmateur. Les bits de configurations indiqus dans le fichier sont en effet
modifiables par la plupart des logiciels de programmation, qui sont capables de forcer une
valeur de configuration diffrente de celle prvue par le concepteur du programme PIC.

Ceci est dautant plus frquent que certains programmeurs oublient dinclure la
directive _CONFIG dans leur programme, ce qui ne permet pas la configuration
automatique des flags de configuration. Cest une trs mauvaise pratique, car lutilisateur
final devra savoir (ou deviner) quel est ltat des flags quil lui faudra configurer au moment
de la programmation.

Ensuite, vous devez placer une ou plusieurs instructions clrwdt dans votre
programme en vous arrangeant pour quune instruction clrwdt soit reue dans les dlais
requis par votre PIC. Pour rappel, ne tenez pas compte du temps nominal de 18ms, mais
plutt du temps de la situation la plus dfavorable. Ce temps est de minimum 7ms. En prenant
ce temps comme temps maximum autoris, vous tes certain que vote programme
fonctionnera dans toutes les conditions.

15.5 Ce quil ne faut pas faire

Souvenez-vous quune interruption interrompt le programme et branche ladresse 0x04.


Une fois linterruption termine, le programme est reconnect lendroit o il se trouvait,
mme si cest hors de votre zone normale de programme.

De ce fait, si vous placez une instruction clrwdt dans une routine dinterruption, cette
instruction risque de sexcuter mme si votre programme est plant . Cest donc le
contraire du but recherch. En consquence :

Il ne faut jamais utiliser linstruction clrwdt dans une routine dinterruption.

Vous allez me rpondre : Daccord, mais si ma routine dinterruption dure trop


longtemps ? Ma rponse sera alors: Cest que vous avez ignor mon conseil qui est de
toujours rester le moins de temps possible dans une interruption.

15.6 Mesure du temps rel du watchdog

La valeur de 7ms est la valeur minimale, la valeur de 18ms est la valeur gnralement
constate. Mais quelle est la valeur effective de votre propre PIC ?

Nous allons tenter de rpondre cette question. Attention, cette mesure sera
indicative, ne vous y fiez pas dans la pratique, cette dure pouvant changer avec les conditions
(alimentation, temprature). Il est toutefois intressant de dterminer si la thorie rejoint la
pratique.

Effectuez un copier/coller de votre fichier Led_cli.asm . Renommez ce fichier en


wdt.asm et crez un nouveau projet.

Dans un premier temps, ne touchez pas la configuration

188
Modifiez la valeur du registres OPTION

OPTIONVAL EQU B'10001111' ; Valeur registre option


; Rsistance pull-up OFF
; prscaler Wdt = 128

Ensuite, supprimez la variable cmpt3 et modifiez la routine tempo pour enlever la boucle
extrieure.

;*********************************************************************
; SOUS-ROUTINE DE TEMPORISATION *
;*********************************************************************
;---------------------------------------------------------------------
; Cette sous-routine introduit un retard de 250ms.
; Elle ne reoit aucun paramtre et n'en retourne aucun
;---------------------------------------------------------------------
tempo
clrf cmpt2 ; effacer compteur2
boucle2
clrf cmpt1 ; effacer compteur1
boucle1
nop ; perdre 1 cycle
decfsz cmpt1 , f ; dcrmenter compteur1
goto boucle1 ; si pas 0, boucler
decfsz cmpt2 , f ; si 0, dcrmenter compteur 2
goto boucle2 ; si cmpt2 pas 0, recommencer boucle1
return ; retour de la sous-routine

Ajoutons la ligne

clrwdt ; effacer watchdog

Juste aprs ltiquette init pour tre bien sr de remettre le watchdog 0 (en ralit, inutile).

Modifions pour finir le programme principal pour quil allume la LED aprs 250ms :

;*********************************************************************
; PROGRAMME PRINCIPAL *
;*********************************************************************
start
call tempo ; on attends 250ms
bsf LED ; allumer la LED
loop
goto loop ; on reste ici
END ; directive fin de programme

Assemblez le programme, chargez-le dans votre PIC, et alimentez votre platine.

Que se passe-t-il ? Et bien, aprs approximativement seconde, la LED sallume, et cest


tout. Il ne se passe plus rien. Cest bien ce que nous avions prvu.

Modifiez maintenant la ligne _CONFIG pour mettre le watchdog en service :

__CONFIG _CP_OFF & _WDT_ON & _PWRTE_ON & _HS_OSC

189
Assemblez de nouveau votre programme, et rechargez-le dans votre PIC. Alimentez
votre montage.

Que se passe-t-il ? Et bien maintenant la LED clignote. Vous constaterez


probablement que le temps sparant deux extinctions (ou deux allumages) est
approximativement 2secondes.

Explications

Si vous avez suivi tout ce qui prcde, vous avez dj compris. Notre watchdog na
pas t remis zro depuis le dmarrage du PIC. Donc, une fois le temps : dure de
base * prdiviseur atteint, un reset est provoqu qui entrane une extinction de la LED et
un redmarrage sans fin du cycle.

Pour connatre la base de temps de notre watchdog personnel dans les circonstances
actuelles de tension et de temprature, nous devons donc diviser le temps entre 2 extinctions
(ou allumage) par le prdiviseur, cest dire 128.

Personnellement, jai chronomtr 2,2 secondes. Donc, mon watchdog travaille avec
un temps de base de : 2200ms / 128 = 17,2 ms. On est donc bien dans les environs des 18ms
typiques annonces. Remarquez que cest moins que les 18ms typiques. Donc, si javais
utilis un clrwdt toutes les 18ms, mon programme aurait plant sur ce PIC. Preuve que cest
bien la valeur de 7ms quil faut prendre en compte.

15.7 Simulation du plantage dun programme

Effectuez de nouveau une copie de votre fichier Led_cli.asm et renommez cette copie
secur.asm . Crez un nouveau projet.

Changez la ligne de configuration :

OPTIONVAL EQU H'0F' ; Valeur registre option


; Rsistance pull-up ON
; Prscaler wdt 128

et le DEFINE (vu que nous avons modifi notre platine)

#DEFINE BOUTON PORTB,0 ; bouton-poussoir

Modifiez ensuite votre programme principal :

start
bsf LED ; allumer la LED
call tempo ; appeler la tempo de 0.5s
bcf LED ; teindre LED (LEDOFF)
call tempo ; appeler la tempo de 0.5s
btfsc BOUTON ; tester bouton-poussoir
goto start ; pas press, boucler
plante
goto plante ; le programme n'est pas sens
; arriver ici
; simulation de plantage

190
END ; directive fin de programme

De cette manire, une pression du bouton-poussoir envoie le programme dans une


zone que nous avons cre et qui simule un plantage du programme sous forme dune boucle
sans fin.

Vous allez me dire quil ne sagit pas dun plantage, cest notre BP qui envoie le
programme ladresse plante . Ben oui, mais cest difficile de planter volontairement un
PIC sur demande. Dans la ralit il vous suffit dimaginer que le BP nexiste pas et quil
reprsente une perturbation envoyant notre programme l o il ne devrait pas aller.

Compilez le programme et chargez-le dans votre PIC. Alimentez le montage : la


LED clignote.

Maintenez un instant le bouton-poussoir enfonc, la LED sarrte de clignoter, le


programme est dans une boucle sans fin qui simule dans notre cas le plantage suite, par
exemple, un parasite qui a ject notre programme hors de sa zone de fonctionnement
normal.

15.7.1 Correction avec utilisation du watchdog

Modifions maintenant notre programme. Tout dabord, nous mettons le watchdog en


service, comme vu prcdemment dans la configuration. Nous allons ensuite nous arranger
pour remettre notre watchdog 0 intervalles rguliers.

Voici donc notre programme principal modifi :

start
bsf LED ; allumer la LED
clrwdt ; effacer watchdog
call tempo ; appeler la tempo de 0.5s
bcfLED ; teindre LED (LEDOFF)
clrwdt ; effacer watchdog
call tempo ; appeler la tempo de 0.5s
btfsc BOUTON ; tester bouton-poussoir
goto start ; pas press, boucler
plante
goto plante ; le programme n'est pas sens
; arriver ici
; simulation de plantage
END ; directive fin de programme

Nous avions programm notre watchdog avec un prdiviseur de 128, ce qui nous
impose denvoyer une commande clrwdt toutes les 7*128 ms, soit toutes les 896ms.

Comme lappel notre tempo prend 500ms, nous devrons donc envoyer clrwdt avant ou
aprs chaque appel de tempo, pour ne pas dpasser ce temps.

Nous aurions pu, au lieu de ces 2 instructions, utiliser un seul clrwdt dans la sous-
routine tempo .

Assemblons notre programme, et rechargeons le PIC. Lanons lalimentation.

191
La LED clignote toujours.

Pressez le bouton quelques instants, la LED sarrte de clignoter un instant, puis


recommence de nouveau. Le watchdog a rcupr le plantage de votre programme.

15.8 Choix de la valeur du prdiviseur

En gnral, il faut essayer de calculer le prdiviseur de faon ne pas devoir placer de


commande clrwdt en de trop nombreux endroits.

Mais il faut galement tenir compte du temps de raction obtenu en augmentant le


prdiviseur. Si une rcupration de plantage en 2 secondes vous convient ou si votre
programme ncessite une rcupration en 18ms max conditionnera la valeur du prdiviseur
utiliser. Tout est donc histoire de compromis.

Vous naurez cependant pas toujours le choix. Si votre prdiviseur est dj occup
pour le timer0, par exemple, il ne vous restera pas dautres choix que denvoyer une
commande clrwdt toutes les 7ms. Cest par contre une trs mauvaise ide den dduire
quautant ne pas utiliser le watchdog : vous rouleriez moto sans casque ?

Dans le cas cit, vous auriez du placer une instruction de ce type au cur de la routine de
temporisation, car celle-ci dure plus de 7ms.

Rappelez-vous de ne pas utiliser cette instruction dans une routine dinterruption, car cela
est contraire au principe mme du watchdog (sauf cas trs spciaux). Vous pouvez par
contre utiliser clrwdt dans une sous-routine sans aucun problme.

15.9 Temps typique, minimal, et maximum

Nous avons vu apparatre plusieurs notions de temps de watchdog. Il me semble


important de rappeler la distinction entre les diffrentes valeurs. Je vais donc rcapituler ici :

- Le temps typique (18ms) est le temps que met en gnral le watchdog pour
provoquer le reset de votre programme en cas de plantage. Cest donc le temps de
raction normal (ou typique) du watchdog

- Le temps minimal (7ms), cest le dlai maximum dont vous disposez entre 2
instructions clrwdt pour viter un reset de votre programme non dsir.

- Le temps maximum (33ms), cest le temps de raction du watchdog dans le cas le


plus dfavorable en fonction du composant et des conditions dutilisation.
Microchip vous garantit ici que le reset seffectuera au maximum en 33 ms.

15.10 Conclusion

Vous tes maintenant en mesure de crer des programmes rsistants aux plantages
classiques, pour peu que vous utilisiez judicieusement le watchdog. En gnral, il est

192
prfrable de faire leffort de lutiliser, car le surplus de travail est ngligeable en contrepartie
de la scurit de fonctionnement obtenue.

Attention : Le watchdog utilis en protection dans le cas dune programmation


correcte et dune carte bien conue ne devrait jamais entrer en fonctionnement. Il
nagira donc en gnral que dans de trs rares occasions (parasites violents, orage). Il ne
doit pas servir masquer une erreur de conception de votre programme. Celui-ci doit
pouvoir fonctionner sans le secours du watchdog.

Je vous conseille donc de raliser vos programmes de la faon suivante :

- Vous crivez votre programme en y plaant comme prvu les instructions clrwdt, mais
vous ne mettez pas le watch-dog en service avec la directive _CONFIG

- Vous mettez votre programme en PIC, et vous le debuggez en le laissant tourner


suffisamment de temps pour tre certain de labsence de bug.

- Une fois le programme fiabilis, vous reprogrammez votre PIC avec le


watchdog en service.

De cette faon, vous tes certain que votre watchdog ne va pas servir rcuprer une
erreur de programmation de votre part (en relanant le PIC lors dun blocage dans une
boucle sans fin, par exemple).

193
Notes :

194
16. Le mode Sleep

Nous allons tudier dans cette leon un mode trs particulier des PIC, qui leur
permet de se mettre en sommeil afin de limiter leur consommation.

16.1 Principe de fonctionnement

Le mode sleep ou power down est un mode particulier dans lequel vous pouvez
placer votre PIC grce linstruction sleep . Une fois dans ce mode, le PIC est plac
en sommeil et cesse dexcuter son programme. Ds rception de cette instruction, la
squence suivante est excute :

- 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.

- Loscillateur est mis larrt, le PIC nexcute plus aucune instruction.

Une fois dans cet tat, le PIC est larrt. La consommation du PIC est rduite au
minimum. Si le tmr0 est synchronis lhorloge interne, il est galement mis dans
lincapacit de compter.

Par contre, il est trs important de se rappeler que le timer du watchdog possde son
propre circuit dhorloge. Ce dernier continue de compter comme si de rien ntait.

16.2 La sortie du mode sleep

Le passage en mode sleep na rellement dintrt que sil est possible den sortir. Le
16F84 ne ragit dans ce mode quaux vnements suivants, qui sont seuls susceptibles de
replacer le 16F84 en mode de fonctionnement normal. Ces vnements sont les suivants :

- Application dun niveau 0 sur la pin MCLR. Ceci provoquera un reset du 16F84.
Le PIC effectuera un reset classique ladresse 0x00. Lutilisateur pourra tester les
bits TO et PD lors du dmarrage pour vrifier lvnement concern (reset, watch-
dog, ou mise sous tension).

- Ecoulement du temps du timer du watchdog. Notez que pour que cet vnement
rveille le PIC, il faut que le watchdog ait t mis en service dans les bits de
configuration. Dans ce cas particulier, le dbordement du watchdog ne provoque pas
un reset du PIC, il se contente de le rveiller. Linstruction qui suit est alors
excute au rveil.

- Apparition dune interruption RB0/INT, RB ou EEPROM.

195
Notez dans ce dernier cas, que pour quune telle interruption puisse rveiller le
processeur, il faut que les bits de mise en service de linterruption aient t positionns.
Par contre le bit GIE na pas besoin dtre mis en service (mais il peut ltre) pour gnrer
le rveil du PIC.

Vous pouvez donc dcider par exemple de rveiller le PIC la fin du cycle dcriture
EEPROM. Pour ce faire, vous devez mettre le bit EEIE de INTCON 1 et lancer le cycle
dcriture, suivi par linstruction sleep Une fois lcriture termine, le PIC est rveill et
poursuit son programme.

Il est impossible de rveiller le PIC sur une interruption du timer, parce que, en mode
sleep, le timer est stopp et donc ne peut pas gnrer dinterruption. Il ne peut pas non plus
compter les vnements extrieurs car le comptage est synchronis avec son horloge interne.

16.3 Rveil avec GIE hors service.

Si votre PIC est rveill par une interruption alors que le BIT GIE de INTCON est mis
0, le programme se poursuivra tout simplement linstruction qui suit linstruction
sleep .

16.4 Rveil avec GIE en service

Dans le cas o votre bit GIE est positionn, un rveil suite une interruption entranera la
squence suivante.

- Linstruction qui suit linstruction sleep est excute.

- Le programme se branche ensuite ladresse 0x04 comme une interruption


ordinaire.

Note : Si vous ne voulez pas excuter linstruction qui suit linstruction sleep , il
vous suffit de placer cet endroit une instruction nop .

16.5 Mise en sommeil impossible

Si le bit GIE est positionn 0, et que les bits de mise en service et le flag dune
interruption sont tous deux 1 au moment de linstruction sleep (par exemple
INTE=INTF =1), linstruction sleep est tout simplement ignore par le processeur.

Ceci est logique, car les conditions de rveil sont dj prsentes avant la mise en
sommeil. Cest donc vous de remettre ventuellement ces bits 0. Le bit PD vous permettra
de savoir si votre instruction sleep sest excute (PD = 0).

Si le bit GIE est positionn 1, il va sans dire, mais je lcris tout de mme, que le cas
prcdent ne pourra survenir, vu quune interruption serait alors gnre, interruption qui

196
provoquerait leffacement du flag concern. Except bien entendu si vous avez plac votre
instruction sleep lintrieur de la routine dinterruption.

Notez galement que dans le cas o linstruction sleep nest pas excute, votre
watchdog nest pas non plus remis 0. Si vous deviez le faire ce moment, et si vous
ntes pas sr de la bonne excution de sleep , ajoutez linstruction clrwdt avant cette
instruction.

16.6 Utilisation du mode sleep

Nous allons raliser un petit exercice sur la mise en veille de notre PIC.

Effectuez un copier/coller de votre nouveau fichier m16F84.asm et renommez-le en


sleep.asm Crez un nouveau projet.

Placez le prdiviseur sur le watchdog avec une valeur de 32. Ceci nous donne une
valeur typique de dbordement de 18ms*32 = 576 ms.

OPTIONVAL EQU H'8D' ; Valeur registre option


; Prscaler wdt 32

Dfinissez votre LED sur la pin RA2

#DEFINE LED PORTA, 2 ; LED de sortie

Placez ensuite votre LED en sortie dans la routine dinitialisation (attention, en banque1)

bcf LED ; LED en sortie

Ecrivons ensuite notre programme principal :

;*********************************************************************
; PROGRAMME PRINCIPAL *
;*********************************************************************
start
bsf LED ; Allumage de la LED
sleep ; mise en sommeil
bcf LED ; extinction de la LED
sleep ; mise en sommeil
goto start ; boucler

Le fonctionnement est trs simple. Aprs avoir allum ou teint la LED, le PIC est mis
en sommeil. Une fois le temps du watchgog coul, le PIC se rveille et excute
linstruction suivante. Voil donc un programme de clignotement de votre LED ultracourt et
avec une consommation minimale.

De plus, voici une autre faon simple de mesurer le temps de watchdog de votre
propre PIC.

197
Remarque

Notez que le rveil de votre PIC nest pas instantan. En effet, si vous utilisez un
quartz, le PIC attendra 1024 cycles dhorloge avant de relancer le programme. Il vous
faudra en tenir compte. Ce temps mort est ncessaire pour que loscillateur de prcision
quartz atteigne une certaine stabilit.

Attention donc, soyez conscients que le rveil de votre PIC prendra un certain temps.

16.7 Cas typiques dutilisation

Ce mode de fonctionnement est principalement utilis dans les applications dans


lesquelles la consommation en nergie doit tre limite (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 na rien faire
dans lattente dun vnement extrieur particulier. Dans ce cas, plutt que dutiliser des
boucles sans fin, une instruction sleep pourra faire efficacement laffaire.

16.7 Pour une consommation minimale

Le mode sleep assure une mise en veille du PIC. Son rle premier tant lconomie
dnergie, il incombe de baisser la consommation globale du composant. Pour ce faire, il ne
suffit pas de placer le PIC en mode sleep, il faut encore veiller tout son environnement.
Or le passage en mode sleep ne modifie pas ltat des pins configures en sortie.

Attention : Lorsque le PIC est plac en mode sommeil, aucun niveau sur ses pins de
sortie ne change. Si vous avez des consommateurs dnergie en service sur ces pins (par
exemple une led), ces consommateurs continueront de consommer du courant (la led
restera allume). Pour rellement profiter dune conomie dnergie, il faut, avant de
passer en mode sleep, sassurer de placer ses pins dans un tat tel que la consommation
totale du montage soit la plus faible possible.

Il ne faut pas videmment oublier la consommation des rsistances de pull-up sur le


PORTB, si vous les avez mises en service. Toute entre relie la masse consommera alors
du courant.

Une ventuelle horloge externe devra tre stoppe.

Pour dautres PIC, il y a encore dautres mesures prendre, comme larrt du


convertisseur analogique/numrique.

Toutes les entres non utilises ainsi que lentre Tocki seront de prfrence forces
soit la masse, soit Vdd, car si vous les laissez flottantes, chaque transition accidentelle de
niveau consommera un petit courant. Notez que vous arrivez au mme rsultat en configurant
les pins inutilises en sortie.

198
Notez sur ce point que contrairement certaines affirmations loufoques trouves sur le
net :

- Une pin en lair ne risque pas de planter un PIC : ses entres sont protges par des
diodes, et, de plus, il sagit dun composant programmable, pas dune porte logique
MOS dont les sorties peuvent varier en fonction des entres inutilises. Dans votre
programme vous nutilisez pas (en principe) des entres qui ne sont raccordes rien,
leur transition na donc aucune consquence (sauf bug dans votre programme).

- Le risque de commutation est faible dans un environnement classique, car les entres
ne basculent que pour des tensions de lordre de Vdd/2 (2.5V classiquement), ce qui,
vu limpdance dentre des pins, assure une relative immunit.

La seule consquence dune entre en lair sur un pic, ce sont les quelques pA
consomms durant une transition non prvue.

Vous laurez compris, il faut considrer le problme de la consommation sous son


ensemble, et ne pas se borner crire linstruction sleep . Du moins si la limitation de la
consommation fait partie de votre cahier des charges.

16.8 Conclusion

Vous tes maintenant capable de placer un PIC en mode de sommeil afin


dconomiser au maximum lnergie. Je ne doute pas que vous trouverez des tas
dapplications pour ce mode trs pratique et trs simple grer.

199
Notes :

200
17. Le reste du datasheet
Et voil, nous arrivons au bout de ltude de notre 16F84. Dans ce chapitre, je vais
parcourir avec vous le datasheet du 16F84 pour voir tout ce dont nous navons pas parl
jusqu prsent.

Cest donc une sorte de fourre-tout que je vous propose ici. Je nentrerai cependant pas
dans les descriptions techniques dtailles, car ceci nintressera que les lectroniciens. Ceux-
ci tant parfaitement aptes comprendre une figure telle que la figure 3-1. Pour les autres,
ceci napportera rien de plus lutilisation des PIC.

Cette leon vous montrera du mme coup comment comprendre un datasheet.

Comme les datasheet sont sans cesse mis jour chez Microchip (et cest une bonne
chose), je joins la leon celui qui ma servi jusqu prsent pour faire ces cours, et qui
sappelle 16F84.pdf

17.1 La structure interne

Figure 3-1, justement, vous voyez comment est construit un 16F84. Comme je le disais
plus haut, ceci ne prsente quun intrt limit pour lutilisation pratique du processeur.

Cependant, vous pouvez remarquer les largeurs de bus internes qui vous rappellent les
limitations des modes dadressage. Vous voyez par exemple que le PC (Program Counter) na
quune largeur de 13 bits.

Le cur du 16F84, comme dans tout processeur, est lALU. Cest dans cette Unit
Arithmtique et Logique que seffectuent tous les calculs. Notez la liaison privilgie entre le
registre W et lunit ALU.

17.2 La squence de dcodage

Figure 3-2, vous voyez clairement la division dun cycle dinstruction en fonction
des 4 cycles doscillateur ncessaires. Chacun des 4 cycles ncessaires la ralisation dune
instruction est dtaille. Vous voyez lexemple 3-1 qui montre lexcution dun bout de
programme.

Remarquez que durant quune instruction est excute, la suivante est dj charge
( fetch ). Ceci explique que lors dun saut, linstruction suivante charge (la suivante)
ntant pas celle qui doit tre excute, il faut alors un cycle supplmentaire pour charger la
bonne instruction.

17.3 Organisation de la mmoire

Sur la figure 4-1 vous voyez lorganisation mmoire du PIC. Notez que la pile et le PC
sont situs hors de lespace dadressage, et donc sont inaccessibles par le programme.

201
17.4 Les registres spciaux

Le tableau 4-1 vous donne une vue globale de tous les registres spciaux. La premire
colonne vous donne ladresse du registre , la seconde le nom symbolique du registre, ensuite
le nom de chaque bit.

Lavant-dernire colonne vous donne la valeur de chaque bit aprs une mise sous
tension, tandis que la dernire colonne fait de mme pour les autres types de reset
(watchdog et MCLR). Les bits nots 0 ou 1 sont ceux dont le niveau est celui indiqu. Les bits
nots u sont les bits non affects par un reset (unchanged = inchang). Les bits nots
x sont les bits dont ltat ne peut tre connu ce moment.

17.5 Llectronique des ports

Les figures 5-1 5-4 permettront aux lectroniciens de comprendre les spcificits
des ports IO au niveau de leurs caractristiques lectriques. Vous verrez alors, comme je vous
lai indiqu, que la pin RA4, par exemple, est une sortie collecteur ouvert , ou plus
prcisment drain ouvert , configuration qui ne permet pas dimposer un niveau haut sur
la sortie.

17.6 Le registre de configuration

Le registre de configuration est situ ladresse 0x2007, hors de lespace


dadressage normal du PIC. Il nest accessible quau moment de la programmation.

Vous accdez ce registre laide de la directive _CONFIG , ou laide de la


directive DA prcde de la directive ORG 0x2007 . A ce moment, la donne que vous
indiquerez suite la directive DA prcisera le niveau des 14 bits utiles pour le 16F84 (5
bits pour le 16C84).

Lexplication et la position de ces 14 bits sont donns figure 8-1. Noubliez pas quil
sagit ici dun mot de 14 bits (tout comme les instructions).

A titre dexemple, la ligne suivante :

__CONFIG _CP_OFF & _WDT_ON & _PWRTE_ON & _HS_OSC

Correspondra donc pour un 16F84 ceci :

ORG 0x2007
DA B111111111111110

Je vous dconseille ce genre de pratique, nous verrons plus bas pourquoi.

202
17.7 Les diffrents types doscillateurs

La figure 8-3 nous montre la configuration que nous avons utilise pour lhorloge de
notre PIC. Cest lutilisation avec quartz externe. La rsistance RS est inutile pour un quartz
classique dans un environnement standard. Si vous utilisez un rsonateur cramique avec
condensateurs intgrs, au lieu dun quartz, vous pourrez supprimer les condensateurs C1 et
C2. Pour une application robuste ou commerciale, je vous conseille de lire la bible de
loscillateur du PIC , de Michel Stokowski, en tlchargement sur mon site, page de
tlchargement du cours-part2.

La table 8-1 montre les diffrentes valeurs utiliser en fonction des frquences, ainsi que
les modes correspondants slectionns par les bits de configuration FOSC1 et FOSC0 si vous
utilisez un rsonateur cramique.

La table 8-2 fait de mme pour les oscillateurs quartz. Notez que les bits cits sont
intgrs dans les _HS_ OSC et autres configurations doscillateur. Cest ce qui explique que
vous ne les ayez jamais rencontrs directement.

La figure 8-4 indique comment utiliser une horloge externe au lieu de loscillateur
interne. Rappelez-vous dans ce cas de ne jamais paramtrer votre oscillateur sur RC
sous peine de destruction de votre PIC.

Les figures 8-5 et 8-6 vous montrent comment construire un oscillateur externe. Je vous
conseille titre personnel dutiliser dans ce cas le 74HCU04 qui fonctionne bien pour des
frquences suprieures ou gales 4MHz. Evitez les modles de type LS (74LS04), sous
peine de dboires.

Jutilise pour ma part dans ce cas un schma driv du montage parallle indiqu. Mon
montage, sur 4MHz, utilise une R de 3,3Mohms la place des 47kohms, je remplace la R
ajustable par une fixe de 2kohms, et je supprime la R ajustable lextrme gauche du schma.
Je remplace les deux condensateurs par des 27pF.

Reste le mode doscillateur avec rseau Rsistance Condensateur. Dans ce mode,


loscillation est assure par deux composants passifs, sans ncessiter de quartz (pour raisons
dconomie).

Nutilisez ce mode que si vos constantes de temps dans votre programme ne sont pas
critiques. Connectez suivant la figure 8-7 et utilisez une Rsistance de lordre de 47kohms et
un condensateur de lordre de 27 picofarads (27pF).

Noubliez pas dans tous les cas que la frquence dexcution des instructions vaut le quart
de la frquence dhorloge. Utilisez la formule suivante pour calculer la dure dun temps de
cycle de votre programme. Soit Tcy la dure dun cycle dinstruction, et Fosc la frquence de
lhorloge fournie :

TCy = 4 / FOsc

Cy est labrviation de Cycle (dinstruction) , donc Tcy = priode de cycle et Fcy =


Frquence de cycle.

203
Osc pour Oscillateur avec Tosc = priode doscillateur et Fosc = frquence doscillateur.

Par exemple, pour un quartz de 4MHz : T = 4 / 4000000 = 1 microseconde.

Et rciproquement : Fosc = 4 / Tcy pour calculer la frquence qui correspond un


temps de cycle calcul.

Donc, si je veux un temps de cycle de 1,5 s (microseconde), il me faudra une horloge


cadence :

Fosc = 4 / (1,5*10-6) = 2,667 * 106 = 2,667 MHz (Mega Hertz)

17.7.1 La prcision de loscillateur

Noubliez pas dans vos calculs de tenir compte de lerreur toujours existante. La tolrance
de votre horloge est directement tributaire de la mthode utilise. Une horloge quartz
donnera une bien meilleure prcision quun simple rseau RC.

A titre dexemple, supposons que vous dsiriez construire une horloge avec une carte
PIC. Nous allons valuer lordre de grandeur des erreurs obtenues en fonction du type
doscillateur retenu.

Nous supposerons que votre logiciel est correctement ralis, et que lerreur de mesure
de temps, ce niveau, est nulle.

Commenons par le rseau RC.

Si vous choisissez ce mode pour une horloge, alors vous avez vraiment fait le mauvais
choix. En effet, la frquence de loscillateur varie alors fortement en fonction de la
temprature, de la prcision des composants, varie dans le temps, et en plus est diffrente dun
composant lautre. Ne vous tonnez pas, alors, si vous obtenez une erreur de plusieurs
heures par jour. A rejeter.

Si maintenant vous avez dcid dutiliser un rsonateur cramique, la table 12-1 vous
donne les prcisions obtenues en fonction de quelques marques et modles tests par
Microchip. Ces valeurs nous donnent une prcision de lordre de 0.5%.

Sachant que dans une journe, il y a 24 heures, et que chaque heure contient 3600
secondes, nous pouvons dire quune journe compte : 24 * 3600s = 86400 s.

Une erreur de 0.5% nous donne donc une erreur estime de 86400 * 5 * 10-3 = 432
secondes. Votre horloge risque donc de driver de plus de 6 minutes par jour.

Passons au quartz. Celui-ci va nous donner une erreur typique, et comme indiqu sur le
tableau 12-2, de lordre de 50 ppm (partie par million), soit 0,005%. Calculons donc la drive
de notre horloge sur une journe :

86400 * 50 * 10-6 = 4,32 s.

204
Voici dj un rsultat beaucoup plus acceptable. De nouveaux, lisez le document prcit si
votre but est une prcision maximale, car, dans ce cas, les quartz sont mettre en uvre dans
des conditions trs prcises et en respectant leur datasheet.

Ce petit apart avait pour but de vous faire sentir par un exemple concret lordre de
grandeur des prcisions pouvant tre obtenues par des mthodes courantes.

Notez, que pour notre exemple dhorloge, nous pouvions obtenir des prcisions encore
plus grandes. Nous pouvions par exemple utiliser un circuit dhorloge externe spcifiquement
conu pour de telles applications, ou encore compter les sinusodes du rseau.

En effet, cette dernire mthode est trs fiable, car les socits de production dlectricit
corrigent la frquence en permanence, avec obligation de respecter un nombre exact de cycles
au bout de 24 heures (50Hz = 50 cycles par seconde).

17.8 Le reset

Figure 8-8 vous avez le schma du circuit de reset interne. Ne vous inquitez pas, tout le
travail a t fait pour vous. Retenez ceci : pour faire fonctionner le PIC normalement, reliez
la pin MCLR au +5V. La mise la masse de cette broche provoque un reset du PIC.

SI vous voulez par exemple un bouton reset sur votre montage, reliez la pin MCLR au +5
via une rsistance de 10kohms. Placez votre bouton reset entre la pin MCLR et la masse,
comme dans ce petit schma.

Ce schma ne comporte pas les condensateurs ncessaires une bonne mise en conformit
lectromagntique. Mettez pour ce faire un condensateur de 100nF entre Vdd et Vss au plus
prs possible de Vdd. Faites de mme entre Mclr et Vss.

205
Le tableau 8-3 vous montre tous les vnements lis au reset, et leurs effets sur le PC (o
le programme se branchera) et le registre STATUS. Je vous traduis le tableau ci-dessous dans
une forme claire.

Evnement Branchement (PC) STATUS


Mise sous tension 0x00 00011xxx
MCLR la masse durant fonctionnement normal 0x00 000uuuuu
MCLR la masse durant mode sleep 0x00 0001uuuu
Reset par dpassement timer watchdog 0x00 00001uuu
Sortie du mode sleep par dpassement watchdog Suite programme (PC+1) uuu00uuu
Sortie du mode sleep par interrupt avec GIE = 0 PC + 1 uuu10uuu
Sortie du mode sleep par interrupt avec GIE = 1 PC + 1 puis 0x04 uuu10uuu

Le tableau 8-4 est trs intressant, car il vous montre le contenu de chaque registre
aprs un reset et aprs un rveil. Rappelez-vous que les valeurs x renseignent un tat
inconnu, u signifie inchang par rapport la valeur prcdente, et q signifie que ltat
dpend de la cause de lvnement (voir tableau ci-dessus).

17.9 La mise sous tension

Ds que vous placez votre PIC sous tension, un circuit interne analyse la tension
dalimentation. Un reset automatique est gnr ds que cette tension monte dans la zone 1,2
1,7 volts. Ceci est le reset de mise sous tension (Power On Reset). Notez dj que ce circuit
ne provoque pas un reset si la tension baisse. Cest vous de grer ce cas particulier sil vous
pose problme.

Notez par contre que dautres PIC grent ce cas, comme le 16F876. Je laborderai donc
dans le cours-part2.

Ce reset dclenche un timer interne et indpendant de la vitesse du PIC. Ce timer


maintient le PIC larrt durant un temps typique de 72ms ds dtection de la condition de
reset . Ce timer est appel PoWeR-up Timer ou PWRT. Il peut tre mis en ou hors
service via le bit de configuration PWRTE. Je vous conseille de le mettre toujours en
service, sauf si le temps de dmarrage sous tension tait critique pour votre application.

Ensuite, aprs coulement du temps prcdent, nous avons un dlai supplmentaire sous
forme dun comptage de 1024 oscillations de lhorloge principale (Oscillator Start-up
Timer).

Ceci permet de sassurer dun fonctionnement stable de cette horloge. Cet OST nest pas
utilis pour le mode doscillateur RC, et est en service pour les mises sous tension et les
rveils (pas pour les autres formes de reset, pour lequel loscillateur est sens tre dj dans
un tat stable).

La figure 8-10 vous montre le chronogramme typique dune mise sous tension. Jexplique
rapidement. Sachez que le dplacement horizontal de gauche droite reprsente le temps.

La ligne 1 montre larrive de lalimentation (VDD). Une fois cette alimentation arrive
1,2/1,7V, le processus de mise sous tension est amorc.

206
La seconde ligne vous montre que le dmarrage du processus ne dpend pas du niveau de
la ligne MCLR. Dans cet exemple, cette ligne passe ltat haut un peu plus tard. Si vous
lavez relie au +5V, elle passera 1 en mme temps que la ligne VDD sans aucune sorte
dinfluence.

Ensuite, vous voyez que le reset interne (POR) est valid ds que lalimentation est passe
au point prcit. Scoule ensuite ventuellement le temps de 72ms du PWRT sil est mis en
service.

A la fin de ce temps, lOST dmarre ses 1024 cycles dhorloge pour les modes concerns.
La procdure est alors termine.

Si ce moment MCLR est 1, le PIC dmarre directement (tableau 8-10). Si MCLR


est toujours 0, le PIC dmarrera instantanment ds le passage de MCLR 1 (tableau 8-
11).

Le tableau 8-13 vous montre ce qui se passerait si lalimentation montait trop lentement
en tension, alors que MCLR est reli lalimentation.

Dans ce cas, le reset interne serait termin avant ltablissement de la tension normale, ce
qui nest pas conseill. Dans ce cas, utilisez le schma de la figure 8-9 pour ralentir la monte
en tension sur MCLR et allonger le temps du reset.

Les figures 8-14 et 8-15 vous donnent les mthodes de protection utiliser en cas de
baisse de la tension sans arrt complet.

17.10 Caractristiques lectriques

A partir du chapitre 11, vous trouvez toutes les spcifications lectriques de votre
composant. Ceci intresse les lectroniciens concepteurs de montages particuliers. Pour un
usage courant, les explications des leons prcdentes suffisent largement. Pour des
applications pointues au niveau des spcificits lectriques, il vous faudra tudier ces tableaux
plus en dtail et mme le datasheet gnral des PIC MID-RANGE. Je pense donc inutile de
dtailler ces caractristiques dtailles.

17.11 Portabilit des programmes

Voil un point dlicat. Que deviendra votre programme si vous changez de modle de
PIC ? Voici ce que vous devez faire pour assurer la portabilit de votre programme. Notez
cependant que la portabilit ce niveau est illusoire, vous pouvez juste esprer devoir oprer
le moins de modifications possibles.

- Vous devez imprativement utiliser les directives prvues (_CONFIG) au dtriment


des accs directs style (ORG 0x2007). En effet, ces emplacements et leur contenu sont
susceptibles de modifications dun modle lautre. Malheureusement, mme au
niveau des configurations, les options sont diffrentes dun modle lautre.

207
- Vous devez utiliser les fichiers .inc de Microchip correspondant au PIC sur
lequel va tourner votre programme. Par exemple P16f84.inc . Ceci vous assure
davoir toujours les bonnes adresses pour les bons registres. Les registres qui changent
de banque dun PIC lautre sont rares, mais vrifiez quand mme.

- Vous devez lire les nouveaux datasheets pour analyser les diffrences entre le
composant initial et le nouveau. Au besoin effectuez des modifications dans votre
source. Dans certains cas, Microchip fournit explicitement des documents de
migration, reprenant les points modifier (ex : migration du 16F876 vers le 16F876A)

- Vous pouvez ensuite assembler de nouveau votre programme, aprs avoir remplac la
ligne include par celle contenant le nouveau fichier include , la directive
dclarant votre PIC par le nouveau, et aprs avoir indiqu la bonne cible de votre
projet.

Notez donc que votre programme sera dautant plus facilement portable que vous
aurez suivi les consignes donnes dans ce cours, que vous aurez utilis au maximum les
dclarations, define et macros, et que vous aurez comment votre programme.

Notez galement que si vous avez compris ce qui prcde, un fichier .hex concu pour un
composant ne peut jamais tre utilis tel quel pour un autre composant, sauf cas trs
rares.

Nesprez donc pas placer tel quel votre fichier 16F84 dans un 16F876. Dans la seconde
partie du cours, jexpliquerai comme procder pour effectuer la migration de votre
programme. Par contre, pour un 16F84A a ne pose pas de problme particulier.

17.12 Les mises jour des composants

A lappendice E, vous trouverez un tableau donnant les diffrences entre le 16C84 et le


16F84. Nous allons y jeter un il.

La premire ligne montre que PWRTE a chang de niveau. En effet, PWRTE 1 mettait
en service le timer sur reset de 72ms pour le 16C84. Pour le 16F84, il faut mettre ce bit 0.

Notez dj que si vous avez utilis la directive _CONFIG, il vous suffira de r-assembler
votre programme, car le nouveau fichier p16F84.inc intgre automatiquement la
modification. Si par contre vous avez voulu utiliser une criture directe en 0x2007, en dpit
des avertissements de ces leons, il vous faudra modifier votre programme.

Ensuite vous voyez que la capacit en RAM utilisateur (variables) est passe de 36 octets
68 octets.

Puis vous constatez que Microchip a ajout un filtre sur la pin MCLR afin dviter que
des parasites ne provoquent un reset inopinment. Ceci allonge cependant la longueur de
limpulsion ncessaire pour provoquer un reset souhait.

Viennent ensuite un avertissement sur quelques caractristiques lectriques du PIC. Cet


avertissement vous renvoie aux diffrents tableaux des caractristiques lectriques.

208
Directement aprs, encore une correction au niveau du fonctionnement du PORTA,
lorsque le PIC tait utilis avec une frquence infrieure 500 kHz.

Puis Microchip a ajout un trigger de Schmitt au niveau de lentre RB0 lorsquelle


est utilise en interruption. Pour les non-lectroniciens, sachez simplement que cela limite le
risque de fausse interruption suite un niveau incertain sur la pin.

Vous voyez galement que la mise 0 des bits 7 et 6 de EEADR ne provoque plus une
modification du courant consomm par le PIC. Cest une correction de bug. En effet, sur le
16C84, le fait de laisser ces pins ltat haut augmentait le courant consomm.

Notez ensuite que le fameux CP (code protect) qui contenait un seul bit sur le 16C84,
passe maintenant 9 bits. Ceci permet de crer diffrents types de protection de code sur les
autres PIC de la famille (protection data, protection eeprom etc.).

Une fois de plus, si vous aviez utilis les directives _CONFIG, il vous suffit de
recompiler votre programme aprs avoir simplement remplac le type de composant dans la
directive include . Pour les autres, il vous faudra relire le datasheet en entier pour chaque
nouvelle version du mme composant, et de modifier le programme en consquence.

Constatez enfin la correction dun bug interne lorsque vous placiez le bit GIE 0.
Dsormais, une interruption ne pourra plus tre gnre au cycle suivant. La boucle loop
qui tait ncessaire pour vrifier la bonne mise hors service des interruptions nest plus
ncessaire sur le 16F84. Cette boucle tait de la forme :

loop
bcfINTCON , GIE ; Arrter les interruptions
btfsc INTCON , GIE ; Tester si une interruption na pas remis GIE 1
goto loop ; si, alors on recommence

Je vous en ai galement parl dans cet ouvrage.

17.13 Conclusion

Vous voil maintenant en possession de la totalit des informations ncessaires pour


dvelopper vos propres programmes en 16F84.

Attention, il vous faudra cependant pratiquer avant de devenir un crack de la


programmation. Vous vous direz souvent : cest pas possible, a devrait marcher, mon
16F84(A) est dfectueux .

Dans 99,99% des cas, il sagira dun bug de votre programme (ou dun dfaut de
conception hardware), que vous trouverez peut-tre aprs plusieurs jours de recherche. En
effet, a fait trs longtemps que le PIC16F84(A) est debugg, sil y avait un problme
manifeste, ce problme serait dj signal depuis longtemps. Ne vous dcouragez pas et
relisez les documentations, mme si vous tes certains de les connatre par cur.

209
Je vous ai souvent volontairement fait faire des erreurs, que jai corriges par la suite. Jai
fait cette dmarche dans le but de vous faciliter la vie, en vous montrant ce qui taient parfois
de fausses vidences, et en vous expliquant la bonne dmarche pour obtenir un rsultat fiable.

Je ne vous laisse pas encore tomber, car je vais vous expliquer quelques astuces bien
pratiques pour les programmes les plus courants. Mais dj maintenant, vous tes capables de
travailler seul.

Je vous ai fourni le dictionnaire de rimes, vous dcrire les pomes

210
18. Astuces de programmation

Dans ce chapitre, nous allons examiner quelques mthodes simples pour se tirer de
situations classiques.

18.1 Les comparaisons

Quoi de plus simple que deffectuer une comparaison entre 2 nombres ? Il suffit
deffectuer une soustraction. Soit par exemple comparer mem1 avec mem2 :

movf mem1 , w ; charger mem1


subwf mem2 , w ; soustraire mem2 mem1

Il vous suffit ensuite de tester les bits C et Z du registre STATUS pour connatre le rsultat :

- Si Z = 1 , les 2 emplacements mmoires contiennent la mme valeur

- Si Z = 0 et C = 1, le rsultat est positif, donc mem2 est suprieur mem1

- Si Z = 0 et C = 0, le rsultat est ngatif, donc mem2 est infrieur mem1

Si vous dsirez simplement comparer lidentit entre 2 valeurs, sans modifier C, vous
pouvez galement utiliser linstruction xor

movf mem1 , w ; charger mem1


xorwf mem2 , w ; Si galit, tous les bits sont 0 et Z est 1

Les comparaisons multiples sur galit de constantes sont un cas intressant, car il y a
galement moyen dutiliser une astuce.

Admettons un code qui demande ceci :


Si valeur = 1 -> excution code 1
Si valeur = 2 -> excution code 2
Etc

Vous pouvez conomiser des instructions en utilisant le xolw et en faisant prcalculer


les diffrences par MPASM. Je mexplique :

movf variable,w ; charger variable


xorlw 1 ; comparaison avec 1
btfs STATUS,Z ; galit ?
goto code1 ; oui, excuter code 1
xorlw 1^2 ; comparer variable avec valeur 2
btfs STATUS,Z ; galit ?
goto code2 ; oui, excuter code 2
xorlw 2^3 ; comparer avec valeur 3

Lastuce prsente dans les 2 lignes en gras, est la suivante :

211
Plutt que de recharger variable pour effectuer un xorlw avec la valeur 2, on compare
directement le registre W avec la valeur 1^2 (1 xor 2). MPASM va se charger de calculer cette
valeur.

Ce qui va se passer, cest quen regardant ce qui sest dj pass avec le premier xorlw
1, vous aurez effectu au final lopration suivante :

variable xor1 xor (1 xor 2). , 1 xor 2 tant une constante qui donc est calcule par
MPASM.

Mais lopration xor est associative (vous pouvez changer lemplacement des
parenthses), et donc le rsultat est strictement identique ceci :

(variable xor 1 xor 1) xor 2

Or, le rsultat de la premire parenthse vaut variable , puisque vous inversez deux
fois les mmes bits (deux fois xor 1). Une double inversion quivaut ne rien inverser .

Toute cette opration se rsume donc variable xorlw 2 . Moralit, vous avez
compar variable avec 1, puis avec 2, puis avec 3 etc, sans jamais devoir recharger variable
dans W.

Ce quil faut retenir, cest que lorsquon travaille avec des constantes (comparaisons,
oprations mathmatiques etc) il y a trs souvent moyen de trouver des astuces pour se
simplifier la vie.

18.2 Soustraire une valeur de w

Supposons que vous avez une valeur dans W et que vous dsirez soustraire 5 de cette
valeur. Le premier rflexe est le suivant :

sublw 5

Cest une erreur classique, car vous avez en ralit effectu (5-w) au lieu de (w-5). Il
vous faudra donc effectuer le complment 2 de cette valeur pour obtenir le bon rsultat.
Mais, sagissant encore dune constante, MPASM peut de nouveau le faire pour vous.
Effectuez plutt ceci :

addlw -5

Eh oui, ajouter 5 correspond soustraire 5. Faites-le par crit si vous ntes pas
convaincu. Par contre, la gestion du bit C ncessitera un peu plus de gymnastique, je vous
laisse y rflchir.

18.3 Les multiplications

Comment effectuer une multiplication ? Et bien tout simplement de la mme manire que
nous leffectuons manuellement.

212
Nous allons crer une routine qui multiplie ensemble 2 nombres de 8 bits. Le rsultat
ncessitera donc 16 bits, donc 2 octets. En effet, pour obtenir le nombre de digits maximal du
rsultat dune multiplication, il suffit dadditionner le nombre de digits des diffrentes
oprandes.

Ralisons donc une multiplication manuelle. Nous allons multiplier 12 par 13. Nous
allons travailler avec 4 bits multiplis par 4 bits, avec rsultat sur 8 bits. Ceci afin de rduire
notre explication. Excutons donc notre multiplication manuellement.

1 1 0 0 12
X 1 1 0 1 13
1 1 0 0 12
0 0 0 0 0 0
1 1 0 0 0 0 48
1 1 0 0 0 0 0 96
1 0 0 1 1 1 0 0 156

Quavons-nous effectu ? Et bien nous avons multipli 12 par chaque chiffre de 13


en commenant par la droite . Nous avons dcal dune range vers la gauche chaque rsultat
intermdiaire avant sont addition finale.

La particularit en binaire, cest quil ny a que 2 chiffres : 0 et 1. Donc on multiplie


soit par 0 (ce qui revient ne rien faire) soit par 1 (ce qui revient simplement recopier le
chiffre).

Voici donc ce que nous obtenons en binaire :

- On multiplie 1100 par 1 . On obtient donc 1100 (D12)


- On multiplie 1100 par 0 et on dcale le rsultat vers la gauche. On obtient donc 0000
- On multiplie 1100 par 1 et on dcale le rsultat vers la gauche. On obtient 1100 complt
par 00, soit 110000, donc D 48
- On multiplie 1100 par 1 et on dcale le rsultat vers la gauche. On obtient 1100 complt
par 000, soit 1100000, donc D96.
- On additionne le tout et on obtient 10011100, soit D156.

Si on ralisait ce programme, il nous faudrait 4 variables supplmentaires pour stocker les


rsultats intermdiaires. 8 dans le cas dune multiplication de 8 bits par 8 bits. On peut alors
imaginer de se passer de ces rsultats intermdiaires en procdant laddition au fur et
mesure du rsultat intermdiaire avec le rsultat final.

On obtient alors lalgorithme suivant :

- On multiplie 1100 par 1. On place le rsultat dans rsultat final


- On multiplie 1100 par 0. On dcale une fois. On ajoute au rsultat final
- On multiplie 1100 par 1. On dcale 2 fois. On ajoute au rsultat final
- On multiplie 1100 par 1. On dcale 3 fois. On ajoute au rsultat final.

Vous pouvez tenter dcrire ce programme. Ceci reste pratique pour des multiplications de
4 par 4 bits. Pour des multiplications de 8 bits par 8 bits, vous allez devoir raliser des tas
dadditions de nombres de 16 bits avec des nombres de 16 bits. De plus vous devrez dcaler le

213
multiplicateur, ce qui impliquera, soit de le modifier (ce qui nest peut-tre pas toujours
souhaitable), soit de le sauvegarder, ce qui consomme 1 octet supplmentaire.

En rflchissant un peu, on peut se dire que plutt que de dcaler le multiplicateur vers
la gauche, nous pouvons dcaler le rsultat vers la droite. Ceci revient au mme,
mais vous navez plus que des additions de 8 bits, toujours dans le poids fort du rsultat
Voici comment cela fonctionne avec notre exemple, pour ne pas faire trop long :

- On multiplie 1100 par 1. On place le rsultat fond gauche du rsultat. Dans rsultat on
a : 11000000
- On dcale le rsultat vers la droite : rsultat = 01100000
- On multiplie 1100 par 0 . On ajoute au rsultat : rsultat = 01100000
- On dcale le rsultat vers la droite : rsultat = 00110000
- On multiplie 1100 par 1. On ajoute au rsultat gauche : rsultat :11000000 + 00110000
= 11110000
- On dcale le rsultat vers la droite : rsultat = 01111000
- On multiplie 1100 par 1. On ajoute au rsultat gauche : rsultat : 11000000 + 01111000
= 100111000 (9 bits). Le bit8 (en vert) est dans le carry.
- On dcale le rsultat vers la droite : rsultat = 10011100 = D156

Notez quon ajoute toujours au quartet de poids fort (centrage gauche). Dans le cas
dune multiplication de 8 bits par 8 bits, on ajoutera donc loctet de poids fort. Par moment,
nous aurons dbordement de laddition sur 9 bits. Souvenez-vous que le report se trouve dans
le carry. Or, dans un dcalage, le carry est amen dans le rsultat, donc on rcupre
automatiquement notre 9me bit, qui deviendra le 8me aprs dcalage vers la droite.

Cette procdure est trs simple mettre en programme : la preuve, voici le pseudo-
code pour une multiplication 8 bits par 8 bits.

Effacer le rsultat
Pour chacun des 8 bits du multiplicateur
Si bit de droite du multiplicateur = 1
Ajouter multiplicande au poids fort du rsultat
Dcaler 16 bits du rsultat vers la droite
Dcaler multiplicateur vers la droite
Bit suivant

Si nous plaons de plus le dcalage du multiplicateur en-tte, avant le test de bit, nous
rcuprons le bit tester dans le carry. Le programme devient :

Effacer le rsultat
Pour chacun des 8 bits du multiplicateur
Dcaler multiplicateur vers la droite
Si carry = 1
Ajouter multiplicande au poids fort du rsultat
Dcaler 16 bits du rsultat vers la droite
Bit suivant

Remarquez que ceci est trs simple. Nous allons mettre ce pseudo-code sous forme de
programme. Nous utiliserons la variable multi comme multiplicateur, multan comme

214
multiplicande, resulH comme rsultat poids fort et resulL comme poids faible. multemp est le
multiplicateur temporaire qui sera modifi. cmpt est le compteur de boucles Voici donc le
programme :

clrf resulH ; effacer rsultat poids fort


clrf resulL ; idem poids faible
movlw 0x08 ; pour 8 bits
movwf cmpt ; initialiser compteur de boucles
movf multi , w ; charger multiplicateur
movwf multemp ; sauver dans multemp
movf multan , w ; multiplicande dans w
loop
rrf multemp , f ; dcaler multiplicateur vers la droite
btfsc STATUS , C ; tester si bit sorti = 1
addwf resulH , f ; oui, ajouter au rsultat poids fort
rrf resulH , f ; dcaler rsultat poids fort
rrf resulL , f ; dcaler rsultat poids faible
decfsz cmpt , f ; dcrmenter compteur de boucles
goto loop ; pas fini, bit suivant

Vous pouvez crer un petit projet et tester ce programme dans le simulateur. Vous
verrez quil fonctionne parfaitement. Vous pouvez en faire une sous-routine ou une macro
ajouter dans votre propre fichier include.

Les 2 lignes en gris effectuent un dcalage du rsultat sur 16 bits. Le bit perdu dans
resulH est rcupr dans le carry et remis comme bit7 dans resulL. Astuce de
programmation : si laddition prcdente eu lieu, le 9me bit rsultant de laddition est dans le
carry, et se retrouve donc comme b7 dans resulH. Par contre, sil ny a pas eu laddition, le
carry est forcment 0 du fait du test. Vous voyez maintenant lintrt davoir test le bit
faible du multiplicateur en se servant du carry.

Rassurez-vous, cest avec lexprience que vous arriverez ce genre de rsultat. Ce


petit programme est disponible sous la dnominations : multi.asm

Par contre, une astuce recommander, cest daller tlcharger les librairies
mathmatiques dj toutes crites sur le site de Microchip, et particulirement les librairies
AN526 et AN617. Tout ce qui sy trouve est particulirement optimis, mme si certaines
optimisations sont loin dtre aises comprendre sans un srieux bagage mathmatique.

18.4 Multiplication par une constante

Dans le cas prcdent, nous avons effectuer une multiplication entre 2 variables qui
peuvent prendre nimporte quelle valeur. Dans le cas o vous utilisez une constante, cest
dire que vous connaissez le multiplicateur au moment de la conception de votre programme,
vous devez essayer, pour des raisons doptimisation de raisonner en multiplications par 2.

En effet, pour effectuer une multiplication par 2 il suffit de dcaler la valeur vers la
gauche. Cest trs rapide mettre en uvre. Ne pas oublier cependant de mette C 0 avant le
dcalage, pour ne pas entrer un bit non dsir dans le mot dcal.

215
Supposons donc que vous deviez, dans votre programme, effectuer des multiplications par
10 (dcimal). Et bien nous allons essayer de ramener ceci en multiplications par 2. Cest tout
simple :

Pour multiplier par 10, il faut :

- multiplier par 2 (donc dcaler loprande vers la gauche)


- multiplier encore par 2 (= multiplier par 4, donc dcaler encore une fois).
- Ajouter loprande originale (donc oprande + oprande*4 = oprande *5)
- Multiplier le rsultat par 2 (donc dcalage vers la gauche).

Voici donc une multiplication par 10 trs rapide. On a fait *2, *2, +1, *2). Donc 3
dcalages et une simple addition.

En gnral, on peut sarranger pour obtenir les rsultats des multiplications par des
constantes en utilisant cette mthode.

Ceci vous fera gagner un prcieux temps programme.

Voici un petit programme qui multiplie un nombre de 4 bits contenu dans mem1 par
10. Rsultat dans resul. Vous pouvez adapter pour un nombre de 8 bits trs facilement :

movf mem1 , w ; charger oprande sur 4 bits


movwf resul ; sauver dans rsultat
bcf STATUS , C ; effacer carry
rlf resul , f ; multiplier par 2
rlf resul , f ; multiplier par 4
addwf resul , f ; ajouter mem1, donc multiplier par 5
rlf resul , f ; multiplier par 10

18.5 Adressage indirect pointant sur 2 zones diffrentes

Voici encore une astuce. Imaginez que vous deviez copier 15 variables dun emplacement
mmoire vers un autre (ou encore comparer 2 zones mmoires diffrentes etc.). En fait vous
allez rapidement vous heurter un problme. Vous ne disposez que dun seul pointeur FSR
pour pointer sur vos variables.

Ralisons donc ce programme : mem1 est ladresse de dpart de la premire zone, mem2
ladresse de dpart de la seconde zone

movlw mem ; on pointe sur la premire zone


movwf FSR ; on initialise le pointeur sur la zone source
movlw 15 ; 15 variables transfrer
movwf cmpt ; sauver dans compteur de boucles
loop
movf INDF , w ; charger source
movwf tampon ; on doit sauver dans un emplacement tampon
movlw mem2-mem1 ; cart dadresse entre les 2 emplacements
addwf FSR , f ; pointer sur destination
movf tampon , w ; recharger valeur source
movwf INDF ; sauver dans destination
movlw (mem1-mem2)+1 ; Ecart entre adresse de destination et adresse
; de la source suivante, do le +1

216
addwf FSR , f ; ajouter au pointeur
decfsz cmpt , f ; dcrmenter compteur de boucles
goto loop ; pas dernier emplacement, suivant

Ce programme est valable lorsque vous navez pas le choix des zones de dpart et de
destination. Maintenant, qui vous empche de placer vos variables dans des endroits qui vous
arrangent ? Plaons mem1 et mem2 dans la zone de variables :

CBLOCK 0x10 ; on choisit une zone mmoire dans la RAM


mem1 : 15 ; 15 emplacements pour la source
ENDC

CBLOCK 0x30 ; on choisit une autre zone, mais pas au hasard


mem2 : 15 ; 15 emplacements destination.
ENDC

Ou encore, mais on ne voit pas bien lorganisation des zones utilises :


mem1 EQU 0x10
mem2 EQU 0x30

Maintenant, la source va de B00010000 B00011111 , et la destination de B00110000


B00111111

Il ny a donc que le bit 5 de FSR qui change entre source et destination. Pour modifier
des bits, pas besoin de laccumulateur, donc pas besoin de sauver et recharger la valeur
transfrer.

Nous pouvons donc modifier notre programme de la manire suivante :

movlw mem1 ; on pointe sur la premire zone


movwf FSR ; on initialise le pointeur sur la zone source
movlw 15 ; 15 variables transfrer
movwf cmpt ; sauver dans compteur de boucles
loop
movf INDF , w ; charger source
bsf FSR , 5 ; on pointe sur destination
movwf INDF ; sauver dans destination
bcf FSR , 5 ; on pointe sur source
incf FSR , f ; pointer sur suivant
decfsz cmpt , f ; dcrmenter compteur de boucles
goto loop ; pas dernier emplacement, suivant

Avec les PIC qui utilisent plusieurs banques, comme le 16F876, vous pouvez
galement utiliser la mme adresse dans 2 banques diffrentes, et passer dune lautre en
modifiant le bit IRP du registre STATUS.
.

18.6 Les tableaux en mmoire programme

Supposons que nous avons besoin dun tableau de taille importante. Par exemple un
tableau de 200 lments. O placer ce tableau ? Dans la RAM il ny a pas assez de place,
dans leeprom non plus. Ne reste donc plus que la mmoire de programme.

217
Le problme, cest que le 16F84, contrairement au 16F876, par exemple, ne dispose
daucune mthode pour aller lire les donnes dans la mmoire programme. La seule mthode
pour y avoir accs est dutiliser des instructions.

Supposons un cas simple : nous voulons crer un tableau contenant le carr des nombres
de 0 15. Nous pourrions utiliser un petit sous-programme de la forme suivante :

- On teste si le nombre pass en argument = 0. Si oui, on retourne 0


- On teste si le nombre pass en argument = 1. Si oui, on retourne 1
- On teste si le nombre pass en argument = 2. Si oui, on retourne 4
- Et ainsi de suite

Vous voyez tout de suite quil faudra plusieurs instructions par valeur du tableau. En cas
dun tableau de 200 lments, on naura pas assez de mmoire programme pour tout crire.
Nous allons donc utiliser une autre astuce.

Le cur de lastuce est dutiliser linstruction retlw qui permet de retourner une valeur
passe en argument. Ecrivons donc notre tableau sous forme de retlw : cela donne :

retlw 0 ; carr de 0 = 0
retlw 1 ; carr de 1 = 1
retlw 4 ; carr de 2 = 4
retlw 9 ; carr de 3 = 9
retlw 16 ; carr de 4 = 16
retlw 25 ; carr de 5 = 25
retlw 36 ; carr de 6 = 36
retlw 49 ; carr de 7 = 49
retlw 64 ; carr de 8 = 64
retlw 81 ; carr de 9 = 81
retlw 100 ; carr de 10 = 100
retlw 121 ; carr de 11 = 121
retlw 144 ; carr de 12 = 144
retlw 169 ; carr de 13 = 169
retlw 196 ; carr de 14 = 196
retlw 225 ; carr de 15 = 225

Il ne nous reste plus qu trouver une astuce pour nous brancher sur la bonne ligne de
notre tableau/programme. Si nous nous souvenons que nous pouvons effectuer des oprations
sur le PCL, nous pouvons utiliser cette proprit.

Supposons donc que le nombre lever au carr soit contenu dans le registre w. Si, une
fois sur la premire ligne du tableau, nous ajoutons w PCL, nous sauterons directement sur
la bonne ligne. Compltons donc notre sous-routine. Il nous suffit donc dajouter avant notre
tableau la ligne :

carre
addwf PCL , f ; ajouter w PCL

Donc, si on charge 4 dans w et quon effectue un appel call carre . Le programme se


branche sur cette ligne, le PCL est incrment de 4 et le programme excute donc alors la
ligne retlw 16 .

218
Rappelez-vous, en effet, que le PC pointe toujours sur linstruction suivante, donc au
moment de lexcution de addwf PCL , f , celui-ci pointait sur la ligne retlw 0 .

A ce stade, vous devez vous rappeler que ladresse pour une opration sur le registre PCL
est complte par le contenu de PCLATH. Vous devez donc initialiser correctement celui-ci
avec le numro de la page de 8 bits de ladresse de votre tableau.

Par exemple, si votre tableau est ladresse 0x200, vous devrez mettre 0x02 dans
PCLATH.

De plus, lopration sur PCL ne modifiera pas automatiquement PCLATH, donc votre
tableau ne devra pas dpasser 256 lments, et, de plus, ne devra pas dborder sur la page de
8 bits suivante. Une page tant la plage adresse par les 256 valeurs possibles de PCL, sans
toucher PCLATH.

Comment viter ceci ? Tout simplement en imposant au tableau une adresse de dpart
telle que le tableau tienne tout entier dans la mme page de 256 emplacements.

Ceci permet alors dutiliser un tableau de 256 lments. Voici donc les emplacements
disponibles pour un tableau dune telle taille :

Adresse B00000 00000000, soit adresse 0x00. Pas utilisable, car adresse de reset
Adresse B00001 00000000, soit adresse 0x100. Premier emplacement utilisable
Adresse B00010 00000000, soit adresse 0x200. Second emplacement utilisable
Adresse B00011 00000000, soit adresse 0x300. Dernier emplacement utilisable.

Il va de soi que si vous avez besoin dun plus petit tableau, vous pouvez le commencer
ailleurs, en veillant bien ne pas occasionner de dbordement. Vous pouvez donc ajouter la
ligne : org 0x300 avant ltiquette de dbut de sous-routine.

Notez que ce que jexplique ici est valable pour les tableaux dont la fin est dans la mme
page que le dbut. Or, comme la ligne addwf est incluse dans la page, il faut soustraire
cette ligne des 256 emplacements disponibles. Nous obtenons donc :

;*********************************************************************
; TABLEAU DES CARRES *
;*********************************************************************
;---------------------------------------------------------------------
; N'oubliez pas que la directive "END" doit se
; trouver aprs la dernire ligne de votre programme. Ne laissez donc
; pas cette directive dans le programme principal.
;---------------------------------------------------------------------
org 0x300 ; adresse du tableau
carre
addwf PCL , f ; ajouter w PCL
retlw .0 ; carr de 0 = 0
retlw .1 ; carr de 1 = 1
retlw .4 ; carr de 2 = 4
retlw .9 ; carr de 3 = 9
retlw .16 ; carr de 4 = 16
retlw .25 ; carr de 5 = 25
retlw .36 ; carr de 6 = 36
retlw .49 ; carr de 7 = 49
retlw .64 ; carr de 8 = 64

219
retlw .81 ; carr de 9 = 81
retlw .100 ; carr de 10 = 100
retlw .121 ; carr de 11 = 121
retlw .144 ; carr de 12 = 144
retlw .169 ; carr de 13 = 169
retlw .196 ; carr de 14 = 196
retlw .225 ; carr de 15 = 225
END ; directive fin de programme

Il ne nous reste plus qu construire un petit programme principal qui fasse appel cette
sous-routine.

;**********************************************************************
; DEMARRAGE SUR RESET *
;**********************************************************************
org 0x000 ; Adresse de dpart aprs reset

;*********************************************************************
; PROGRAMME PRINCIPAL *
;*********************************************************************
start
clrf nombre ; effacer nombre
loop
movf nombre , w ; charger nombre
call carre ; prendre le carr du nombre
incf nombre , f ; incrmenter nombre
btfss nombre , 4 ; tester si nombre >15
goto loop ; non, nombre suivant
goto start ; oui, on recommence 0

Compilez votre programme puis passez-le au simulateur. Vous constaterez. Que


cela ne fonctionne pas. Pourquoi ?

Et bien, en ralit, toute opration dont le PC est la destination fait intervenir


PCLATH. Or nous avons laiss PCLATH 0. Ladresse de calcul nest donc pas la bonne.
Avant le saut sous aurions du ajouter :
movlw 03
movwf PCLATH

Afin de permettre PCLATH de pointer sur la page 0x300 lors du calcul dincrmentation de
PCL.

Vous pouvez avantageusement remplacer la ligne org 0x300 par :

repere
ORG (repere+.31)& 0x3E0 ; adresse du tableau

Le but de cette manipulation est dobtenir automatiquement la premire adresse


disponible pour laquelle il ny aura pas de dbordement de notre PCL (pour un tableau juste
32 lments saut inclus). Pour un tableau de 256 lments (instruction de saut incluse) utilisez
ORG (repere+255) & 0x300. Faites des essais la main sur un bout de papier pour vous en
convaincre.

220
Il y a des tas dautres mthodes, comme dutilise une directive de test (IF) pour
vrifier que la fin du tableau est dans la mme page que le dbut, sinon on passe la page
suivante.

Le fichier obtenu est disponible sous la dnomination tableau.asm

Il est important de comprendre que cest lensemble des instructions retlw qui
doivent se trouver dans la mme page. Dans le cas prcdent (petit tableau), vous notez quil
y a une instruction qui se trouve dj dans cette page, ce qui fait 1 emplacement de moins
disponible.

Nous aurions pu modifier le tableau en consquence, de faon que le premier lment


du tableau pointe loffset 0 de la page de 8 bits .

org 0x2FF ; adresse du tableau (premire ligne retlw = 0x300)


carre
addwf PCL , f ; ajouter w PCL
retlw 8 ; premier lment du tableau : adresse 0x300
retlw 4 ; second lment du tableau : adresse 0x301

Toujours pour le cas dun tableau de 256 lments, nous voyons que nous devons
imprativement commencer le tableau un offset de 0 (PCL = 0). Inutile donc de faire une
addition de 0 , il suffit de placer directement w dans PCL, quelque soit ladresse de
cette imputation, du moment que PCLATH soit correctement configur. Nous obtenons donc :

carre
movwf PCL ; ajouter w PCL (adresse = suite du programme principal)
org 0x300 ; adresse effective du tableau(256 emplacements disponibles)
retlw 8 ; premier lment du tableau : adresse 0x300
retlw 4 ; second lment du tableau : adresse 0x301

18.7 Les variables locales

Un des reproches quon entend souvent au sujet des PIC16F est le nombre restreint
des emplacements disponibles en mmoire RAM. Il ne faudrait cependant pas croire que, sous
prtexte que nous programmions en langage dassemblage, nous ne disposions pas de
variables locales.

En fait, lutilisation de ce type de variable est trs simple et rduit considrablement le


nombre de variables ncessaires dans un programme. Voici ma mthode personnelle
dutilisation de ce type de variables.

Pour rappel, ce sont des variables qui ne seront utilises qu lintrieur dune sous-routine, et
qui ne servent plus une fois la sous-routine termine. Partons donc dun programme
imaginaire qui utilise deux sous-routines.

- La premire sous-routine sappelle tempo , elle utilise 2 compteurs pour effectuer un


comptage de temps.

221
- La seconde est la sous-routine fonction . Elle reoit un paramtre dans W, doit sauver
le rsultat dans une variable, et utilise 2 autres variables pour ses calculs intermdiaires.

- La condition pour lutilisation de variables locales identiques, est quune des routines
nappelle pas lautre.

18.7.1 Dtermination des variables locales

Si nous examinons les routines, nous constatons que les 2 variables de la sous-routine
tempo ne sont utiles qu lintrieur de celle-ci. Nous pouvons donc utiliser des variables
locales.

La variable rsultat de la sous-routine fonction devra tre conserv aprs excution


de cette sous-routine, ce nest donc pas une variable locale. Nous dirons que cest une variable
globale. Par contre, les 2 variables utilises pour les calculs intermdiaires ne seront plus
daucune utilit. Ce sont des variables locales.

18.7.2 Construction sans variables locales

Que serait notre zone de variables sans lutilisation des variables locales ? Et bien
crons notre zone de variables :
CBLOCK 0X0C
Cmpt1 : 1 ; compteur 1 pour routine tempo
Cmpt2 : 1 ; compteur 2 pour routine tempo
Resultat : 1 ; rsultat pour routine fonction
Interm1 : 1 ; rsultat intermdiaire1 pour fonction
Interm2 : 1 ; rsultat intermdiaire2 pour fonction
ENDC

Nous voyons que nous aurons besoin de 5 variables. Utilisons maintenant les variables
locales.

18.7.3 Construction avec variables locales

Premirement, nous allons rserver les emplacements mmoires ncessaires pour les
variables locales. Le plus grand nombre de variables locales utilises par une fonction, est de
2. Nous aurons donc 2 variables locales. Dclarons-les.
Ensuite, il nous reste une variable globale ajouter. Crons notre zone data :

CBLOCK 0X0C
Local1 : 1 ; variable locale 1
Local2 : 1 ; variable locale 2
Resultat : 1 ; rsultat pour fonction
ENDC

Il ne nous faudra donc plus que 3 variables au lieu des 5 initiales. Pour mieux nous y
retrouver, nous pouvons attribuer les mmes noms que prcdemment pour nos variables
locales, en ajoutant simplement des DEFINE ou des EQU.

#DEFINE cmpt1 Local1 ; compteur1 = variable locale1

222
#DEFINE cmpt2 Local2 ; compteur2 = variable locale2
#DEFINE interm1 Local1 ; rsultat intermdiaire1 = variable locale1
#DEFINE interm2 Local2 ; rsultat intermdiaire2 = variable locale2

Et voil, pas besoin du C pour utiliser les variables locales trs simplement.

18.8 Division par une constante

Voici une astuce qui ma t envoye par un internaute, Richard L. :

Pour diviser un nombre par une constante, il suffit de multiplier ce nombre par une autre
constante qui vaut 256 divis par la constante .

On obtient un rsultat sur 16 bits, le rsultat de la division se trouve dans loctet de poids
fort.

Exemple :

Pour diviser un nombre par 10, il suffit de le multiplier par (256/10). En hexadcimal,
256/10 donne 0x19 ou 0x1A (il faut bien arrondir)

Imaginons que notre variable contienne la valeur 120 dcimal, soit 0x78.

Si on multiplie 0x78 par 0x1A, a donne 0x0C30. Le poids fort est donc 0x0C, ce qui
donne 12 en dcimal.

Si on avait choisi 0x19, on aurait trouv 11 comme rponse.

En se servant de plusieurs octets (65536 divis par la constante, par exemple) on peut
amliorer la prcision.

18.9 Conclusion

Vous voici en possession de quelques astuces de programmation. Le but tait de vous


montrer les mthodes de raisonnement afin de vous permettre de dvelopper vos propres trucs
et astuces.

223
Notes :

224
19. Utilisation de routines dans un fichier spar

19.1 Questions et point de dpart

Comment puis-je placer mes routines dans un fichier spar ? Pourquoi est-ce que
jobtiens des erreurs de type overwriting lorsque je tente de le faire ? Pourquoi MASM
me donne-t-il des erreurs de liaison (link) en ajoutant des fichiers supplmentaires ?

Toutes ces questions, je les retrouve intervalles rguliers dans mon courrier, il est
temps de clarifier un peu les diffrentes faons de procder pour placer du code dans des
fichiers secondaires joindre au fichier source principal.

La premire chose comprendre, cest quil ne faut pas ajouter la rfrence au fichier
concern dans la hirarchie du projet, car ceci amnerait MPASM croire quil doit lier
plusieurs fichiers au moment de lassemblage, ce qui nest pas le cas concernant des fichiers
sources (a se conoit pour des fichiers objets mais na pas grand intrt pour nous).

Nous allons donc placer nos sous-programmes dans un fichier spar. Par convention,
nous suffixerons ce fichier avec lextension .inc . Par exemples, imaginons
mesroutines.inc .

Il existe deux grandes faons dinclure du contenu sous forme de source dans notre
programme principal. Commenons par la plus vidente.

19.2 Utilisation directe des routines dans le fichier

Nous crons donc un fichier mesroutines.inc dans lequel nous allons btement
crire nos sous-programmes sous forme de code source. Par exemple, imaginons que nous
dsirions utiliser deux sous-routines : ajoute16bits et soustrait16bits . Nous crirons
dans le code source simplement le contenu de nos deux sous-routines :

ajoute16bits
instruction 1
instruction 2
instruction 3

instruction n
return

soustrait16bits
instruction 1
instruction 2
instruction 3

instruction n
return

Et ainsi de suite pour chaque sous-routine inclure. Remarquez que ce fichier ne


contiendra ni directive ORG ni dclaration de variables de type cblock .

225
Un fichier inclure nest pas un fichier autonome, et, inversement, on ninclut
pas un fichier autonome asm dans un autre fichier asm , car il y aurait impossibilit
dassemblage du fait de la prsence de plusieurs donnes contradictoires aux mmes adresses.

Il nous faut maintenant inclure ce code dans notre fichier source principal (notre
fichier asm ). Cela seffectue en insrant dans le source la ligne :

#include <mesroutines.inc>

MPASM remplacera votre ligne # include par tout le contenu de votre fichier
.inc . Cest une simple opration de copi/coll faite automatiquement par MPASM, il
ny a aucune intelligence l-dedans.

Attention donc au pige : vous devez insrer la ligne include non pas en dbut de
fichier mais au contraire lendroit o le code contenu dans le fichier .inc devra tre
copi.

Ceci, par exemple, conduira une erreur :

#include <mesroutines.inc> ; le code de mesroutines.inc est insr en 0x00


ORG 0x00 ; ce qui suit doit se trouver aussi en 0x00
Instruction 1 ; instruction en 0x00 = emplacement dj occup
Instruction 2 ; instruction en 0x01 = emplacement dj occup

Pourquoi ? Tout simplement parce que le contenu du fichier mesroutines.inc va tre


copi avant toute directive ORG, et donc par dfaut partir de ladresse 0x00 (si on ne prcise
rien, cest automatiquement le cas), et donc en 0x00 on aura la premire instruction de
ajoute16bits ainsi que instruction 1 du programme principal.

MPASM ne peut videmment pas mettre deux instructions la mme adresse et donc
enverra une erreur doverwrite (crasement) pour les instructions ladresse 0x00 et les
suivantes.

Vous allez me dire : Oui, mais jcris bien #include <p16F84.inc> avant la directive
ORG 0x00, et pourtant je nobtiens aucune erreur. Cest tout fait logique, parce que votre
fichier p16F84.inc ne contient que des dfinitions, mais aucune instruction. Il najoute donc
aucun code dans votre source, et donc ncrit rien ladresse 0x00.

Il faudra donc placer la directive #include au bon endroit, comme ceci par
exemple :
ORG 0x00 ; ce qui suit se trouve en 0x00
goto main ; instruction en 0x00 : correct

ORG 0x04 ; vecteur dinterruptions


Traiterinterrupts ; le code ici commence en 0x04 : correct

main ; dmarrage rel du programme aprs le saut


Instruction 1
call ajoute16bits ; appel de la sous-routine (exemple)

#include <mesroutines.inc> ; le code de mesroutines.inc se trouve ici : correct
suite du programme ; la suite ventuelle du programme se trouve ici

226
Comme ceci, vos routines seront places aprs votre programme principal et il ny a
aucune impossibilit pour MPASM crire ce code. MPASM va simplement procder
un copi/coll implicite, et il assemblera le code suivant :

ORG 0x00
goto main

ORG 0x04
Traiterinterrupts

main
Instruction 1
call ajoute16bits


ajoute16bits
instruction 1
instruction 2
instruction 3

instruction n
return

soustrait16bits
instruction 1
instruction 2
instruction 3

instruction n
return

suite du programme

Reste le problme des variables. Si vous dclarez un bloc CBLOCK dans votre fichier
de routnes, vous allez de nouveau vous retrouver avec une impossibilit : deux blocs relatifs
la mme adresse et avec des contenus diffrents. Vous avez deux faons de procder :

- Soit vous dclarez deux blocs diffrents, un dans votre programme principal (CBLOCK
0x00), et un autre dans votre fichier de routines : CBLOCK x. Mais ceci prsente
plusieurs graves inconvnients, donc celui de perdre de la place dans votre programme
principal, dempcher lutilisation de variables locales dans vos routines incluses, ou
encore dempcher dinclure deux fichiers diffrents de routines. Je vous dconseille donc
cette mthode

- Soit vous utilisez des variables non dclares dans vos routines. Lors de lassemblage,
MPLAB vous indiquera quelles sont les variables manquantes, que vous dclarerez alors
dans le CBLOCK de votre programme principal. Cest la mthode que je vous conseille si
vous adoptez la faon de procder en cours de description (vous verrez quil y a mieux).

Bref, vos variables seront donc utilises dans vos routines mais dclares dans la
zone CBLOCK de votre programme principal.

Le fichier de routines contiendra donc des lignes du genre :

movf variable1,w

227
et variable1 devra tre dclare dans le programme principal (fichier .asm) sous peine
dune erreur indiquant que variable1 nexiste pas .

Bref, lavantage de la mthode consistant inclure des routines telles quelles est que
linclusion est simple effectuer, il ny a aucune complication particulire. Cest une mthode
que jutilise dans des cas particuliers, par exemple dans le cas o une srie de fichiers asm
dun mme projet (voir mon projet Domocan) partagent systmatiquement les mmes routines
inclure (bootloader commun, structure de programme commune, etc).

Mais dans un cas plus gnral, cette mthode prsente une srie dinconvnients majeurs :

- Lorsque vous vous crez un fichier de sous-routines, tout le contenu de ce fichier est
copi dans votre fichier asm et donc est assembl. Par consquent, vous placez en
mmoire programme tout le code contenu dans votre fichier inc mme si vous navez
pas besoin de toutes les routines qui y sont incluses. Cas typique : vous vous faites une
librairie mathmatique contenant addition, multiplication, division, et dans un programme
vous navez besoin que de laddition. Donc, perte de place en mmoire programme.

- Vous tes contraint dans votre fichier asm de dclarer toutes les variables cites dans
votre fichier inc mme si certaines ne sont utilises que par des routines dont vous
navez pas besoin. Donc, perte de place en mmoire RAM.

- Vous tes contraint de connatre le nom de toutes les variables de votre fichier inc et
dutiliser les mmes noms dans votre programme principal.

- Si vous incluez deux fichiers inc contenant des noms dtiquettes identiques, vous
aurez une erreur lassemblage (impossible rsoudre pour MPASM).

- Si vous incluez deux fichiers inc contenant des noms de variables identiques, a risque
de produire de bugs dans votre programme principal, les mmes variables tant utilises
par des routines diffrentes sans que vous ne le remarquiez forcment.

19.3 Encapsulation dans des macros simples

Il existe donc une mthode plus subtile pour crer votre fichier inc , cest
dencapsuler toutes vos sous-routines dans des macros, comme ceci :

m_ajoute16 bits macro ; encapsuler dans une macro


instruction1
instruction2
.
return
endm ; fin de macro

m_soustrait16 bits macro ; encapsuler dans une macro


instruction1
instruction2
.
return
endm ; fin de macro

228
Partant de l, vous placez en dbut de votre fichier asm lordre dinclure votre
fichier de macros contenant des sous-programmes en dbut de votre programme (avec les
autres directives #include) par exemple :

#include <mesroutines.inc> ; on ajoute la dclaration des macros, pas de code


ORG 0x00 ; le code suivant commence en 0x00
Instruction 1 ; instruction en 0x00, pas encore utilise : correct
Instruction 2

Cette fois-ci, plus aucune erreur, puisquune macro nest transforme en code que
lorsquon lappelle, pas lorsquon la dclare. Donc, pour linstant, votre code source asm
ne contient aucun code contenu dans votre fichier mesroutines.inc , et cest l lastuce, on
lui a simplement dit ce quil devait faire sil rencontre le nom dune de ces macros dans le
fichier source.

Il vous suffit maintenant de placer une tiquette dappel suivi de lappel de la macro,
pour placer le code de la macro lendroit o vous voulez quil soit. Imaginons que vous
navez besoin que de la seule addition, et non de la soustraction, votre fichier source prendrait
la forme suivante :
#include <mesroutines.inc> ; ajout de la dclaration des macros
ORG 0x00 ; code commenant en 0x00

goto main ; saut au programme principal


ORG 0x04 ; vecteur dinterruption

Traiterinterrupts ; traitement des interruptions

main ; programme principal


Instruction 1 ; instructions quelconques
call ajoute16bits ; appel du sous-programme ltiquette donne


ajoute16bits ; tiquette = nom du sous-programme
m_ajoute16bits ; qui contient le code de la macro

Avantages :

- Vous incluez votre fichier de macros en dbut de programme, peu importe si vous
utiliserez ou non les macros.

- Vous ne dclarez que les variables rellement utilises, aucune place ne sera perdue en
mmoire RAM.

- Seul le code rellement ncessaire est prsent dans le fichier assembl, aucune perte de
mmoire programme.

- Toutes vos tiquettes peuvent tre dclares locales dans vos macros, et donc aucun risque
de duplicata dtiquettes.

Inconvnients :

- Vous devez toujours connatre le nom des variables utilises dans votre macro partir de
votre fichier source asm .

229
- Si vous incluez deux macros utilisant les mmes noms de variable, vous risquez les
mmes bugs quavec la premire mthode.

Mais il existe un moyen de surmonter ces derniers obstacles :

19.4 Mthode finalise

Les seuls inconvnients quil nous reste concernent ces fichues variables. Il existe
pourtant un moyen de rsoudre cet problme : utiliser des macros avec des paramtres.

Il nous suffit ds lors de modifier nos macros en y incluant le nom des variables en
tant que paramtres, comme ceci :

m_ajoute16 bits macro var1,var2,result ; macros avec paramtre


movf var1,w ; paramtres = noms de variable
addwf var2,w


movwf result

return
endm ; fin de macro

Dans notre fichier asm , nous utiliserons alors notre macro en prcisant le nom
que nous avons dcid de donner nos variables dans le CBLOCK de notre programme
principal.

Imaginons que nous ayons dcid de dclarer operande1 et operande2 nos


deux variables additionner et monresultat comme rsultat, il nous suffira alors dcrire
notre fichier source comme ceci :

#include <mesroutines.inc> ; ajout de la dclaration des macros


ORG 0x00 ; code commenant en 0x00
goto main ; saut au programme principal

ORG 0x04 ; vecteur dinterruption


Traiterinterrupts ; traitement des interruptions

main ; programme principal


Instruction 1 ; instructions quelconques
call ajoute16bits ; appel du sous-programme ltiquette donne


ajoute16bits ; tiquette = nom du sous-programme
_ajoute16bits operande1,operande2,monresultat ; macro avec variables utiliser

Avantages :

- Tous les avantages de la mthode prcdente

- Plus besoin de connatre le nom des variables, on utilise nos propres variables, ces
variables peuvent tre locales (r-utilises ailleurs ou pour dautres macros).

230
Inconvnients :

Plus aucun inconvnient, on a le beurre et largent du beurre.

19.5 Conclusion

Avec ces mthodes vous disposez de la faon de vous crer vos propres librairies de
routines en code source, aisment rcuprables, et sans gnrer de code inutile dans le fichier
assembl. Ce serait idiot de ne pas en profiter, surtout si vous naimez pas les copis/colls de
code, comme moi.

231
Notes :

232
20. La norme ISO 7816
Le but de ce chapitre est de vous montrer comment raliser une application pratique en
dpassant les limites apparentes du PIC. Jai choisi de crer lossature dun programme de
gestion dune carte ISO7816, car ctait un sujet dactualit lors de la cration de la premire
version du cours, notamment en ce qui concerne le dcodage des missions de TV par
satellite.

Notez que lutilisation de dcodage usage priv dans un but non commercial (ce que
disait la loi) tait parfaitement lgal en Belgique. Pour la France, la lgislation a volu
dfavorablement pour les liberts individuelles, cest une tendance qui se poursuit
malheureusement. Aujourdhui, je pense donc quil est devenu illgal, dans ce pays, de
dcoder chez soi pour son propre usage des ondes qui bombardent pourtant le citoyen jusque
chez lui sans son consentement.

De plus, cest un excellent prtexte pour montrer quil est possible dutiliser un 16F84,
pourtant dpourvu de la gestion srie, pour communiquer de cette manire avec le monde
extrieur.

Cette partie se limitera la norme en gnral, sans entrer dans une application
spcifique de cette norme. Le but nest pas en effet de construire votre propre application (par
exemple une serrure code), mais plutt de vous montrer comment la concevoir vous-mme.

Encart politique : Je rappelle que cette norme est utilise pour les cartes de
dcodage satellite ou TNT, pour les cartes didentit, les cartes bancaires, et bien dautres
applications. SI le fournisseur de la carte le dsire, il est trs simple de crer des cartes
inviolables : le fait de savoir comment fonctionne une carte, et mme davoir son code
source, nest pas une condition suffisante pour avoir accs aux informations codes
lintrieur. Ceci vous explique que si les cartes satellite pirates ont pu exister, cest
uniquement parce que les fournisseurs de ces chanes cryptes lont explicitement voulu,
ceux-l mme qui pleuraient aux JT parce quils perdaient soi-disant de largent. Constatez du
reste que ces cartes pirates nexistent plus, on est pourtant toujours en ISO7816. Les cartes
bancaires belges nont jamais pu tre pirates, et si, dans certaines conditions, les franaises
lont t, ctait d la ngligence crasse des banquiers franais, pourtant parfaitement au
courant ds le dpart de cette possibilit, induite par lutilisation dune cl de longueur
insuffisante. Mais le vol fait tourner lconomie, et donc rapporte de largent ltat. Fin de
lencart politique.

20.1 Spcificits utiles de la norme ISO 7816

Bref, voyons tout dabord quelques spcificits de cette fameuse norme 7816, base de
notre application fictive.

Vous trouverez ces cartes partout dans le commerce de composants lectroniques, sous
la dnomination carte pour serrure code . Elles permettent de raliser des tas
dapplications, et les lecteurs sont disponibles partout. Vous aurez besoin pour communiquer
avec cette carte dune interface dont vous trouverez le schma sur Internet sous la
dnomination phnix , et dun logiciel de communication ou du logiciel fourni avec
linterface.

233
Les spcificits sont les suivantes :

- La carte ne dispose pas de sa propre horloge, elle est fournie par linterface, ou matre,
et est gnralement sous la barre des 4MHz. Certaines cartes modernes dpassent
cependant maintenant cette limite.

- Le temps sparant chaque bit est dfini par la norme comme tant de 1 bit mis toutes les
372 impulsions de lhorloge du matre. Ceci donne un dbit de lordre de 9600 bauds
avec une frquence dhorloge de 3,57 MHz (3570000/372), ou encore 10752 bauds avec
une horloge 4Mhz. Ceci explique que dans pas mal de lecteurs de cartes vous retrouviez
la valeur de 3.57Mhz, permettant de travailler un dbit standard de 9600 bauds.

- La transmission est du type asynchrone, avec 1 start-bit, 8 bits de data, 1 bit de parit
paire, et 2 stop-bits.

- La communication est du type half-duplex, cest dire que les entres et les sorties
seffectuent par alternance et en se servant de la mme ligne physique.

20.1.1 Les commandes ISO 7816

Nous allons dans cet exercice utiliser des commandes bidon de la norme ISO7816.
Il faut savoir que notre carte devra rpondre des commandes organises suivant le protocole
standard de cette norme.

Rgle : La carte ne prend jamais linitiative de lchange dinformations. Elle ne


fait que rpondre des commandes de la forme :

CLASSE INSTRUCTION PARAMETRE1 PARAMETRE2 LONGUEUR

Ou encore, sous forme abrge :

C LASS INS P1 P2 LEN

Voici les significations de chacun des octets de la commande reue :

- CLASS : dtermine le groupe dinstructions concernes. Si le nombre dinstructions


utilis nest pas lev, rien ninterdit de nutiliser quune seule classe. Cest ce que nous
ferons dans cet exercice simplifi.

- INS : cest linstruction proprement dite, ou encore la commande. Cest cet octet qui
dtermine lopration effectuer par la carte dans la classe prcise.

- P1 et P2 : sont 2 paramtres que la carte reoit avec la commande. Leur signification


dpend de la commande envoye. Ils peuvent tre inutiliss mais doivent tout de mme
tre prsents. En gnral sils sont inutiliss on place leur valeur 0 (non obligatoire).

- LEN : peut reprsenter 2 choses. Soit cest le nombre doctets qui suit la commande, dans
ce cas la carte sattendra recevoir LEN octets supplmentaires avant de traiter la
commande dans sa totalit. Soit ce sera la longueur de la chane de rponse que le matre

234
sattend recevoir en provenance de la carte. Cest linstruction qui permet dtablir le
rle de LEN.

Notez quil existe des modes tendus pour la norme ISO7816, qui permet la fois
denvoyer et de recevoir plusieurs octets en une seule opration. Ce mode est dfini comme
mode T=1. Dans notre cas, nous supposons que linformation ne circule que dans un sens
pour une instruction donne (Mode T=0), comme le faisaient les cartes satellite de lpoque.

20.1.2 Le protocole dchange dinformations

Voici comment se droule un change standard dinformations entre le matre et la


carte ISO 7816.

- A la mise en service, le matre gnre un RESET sur la pin MCLR (de la carte). La carte
rpond avec un certain nombres doctets. Cette rponse sappelle ATR, pour Answer To
Reset (rponse au reset).

- Le matre envoie la commande Class INS P1 P2 LEN


- La carte renvoie linstruction comme accus de rception INS
- Le matre envoie ventuellement les donnes complmentaires
- La carte envoie ventuellement la rponse
- La carte envoie le statut et repasse en mode dattente de commande

Donc, si nous supposons par exemple linstruction imaginaire 0x14 de la classe 0xD5 qui
ncessite une rponse de la part de la carte (instruction carte vers matre). Le matre prcise
P1 =0x01 et P2 = 0x02. Nous aurons donc (en imaginant les octets de data) :

- Le matre envoie : D5 14 01 02 10
- Nous en dduisons que le matre attend 16 octets en rponse (0x10 = D16)
- La carte rpond : 14 (accus de rception = instruction reue)
- La carte envoie : 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F (par exemple), soit 16
octets de rponse, exclus laccus de rception et le statut.
- La carte envoie : 90 00 : statut employ en gnral pour indiquer que lopration sest
bien passe. Le statut peut informer dun certain nombre de codes derreurs, propres la
carte, du genre instruction inconnue , ou carte pas dans la bonne configuration etc.

Notez au passage que dans ces cartes on a souvent recours des commandes dites
signes . Si les informations ne sont pas cryptes avec une cl enregistre dans la carte
(cache de lutilisateur), on obtient une erreur en retour.

Si, par contre, dans les mmes conditions, nous imaginons linstruction 0x15
accompagne doctets destination de la carte (instruction matre vers carte), nous aurons :

- Le matre envoie : D5 15 01 02 10
- La carte rpond : 15 (accus de rception)
- Le matre envoie : 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F (par exemple)
- La carte rpond : 90 00

235
Vous voyez que seul le sens de circulation des 16 octets de data change et que cest
linstruction qui dtermine quel sera ce sens de circulation. Cest donc toujours le matre qui
envoie la trame de dpart, et la carte (esclave) qui envoie laccus de rception et le statut.

20.2 Les liaisons srie asynchrones

Les changes dinformation entre le matre et la carte se font sur une liaison srie
asynchrone. Pour comprendre la suite de ce chapitre, il faut donc comprendre ce que cela
signifie.

Le mode srie est dfini pour signaler que tous les bits dun octet vont tre envoys en
srie les uns derrire les autres. Ceci par opposition au mode parallle pour lequel tous les bits
seraient envoys en mme temps, chacun, de ce fait sur un fil spar.

Asynchrone est loppos de synchrone, cest--dire quil sagit dune liaison qui ne
fournit pas une horloge destine indiquer le dbut et la fin de chaque bit envoy.

Nous aurons donc besoin dun mcanisme destin reprer la position de chaque bit.
Notez quil sagit ici dun mode asynchrone particulier, tant donn que la carte utilise
la mme horloge que le matre. La vitesse ne sera donc exceptionnellement pas donne en
bauds, mais en nombre dimpulsions dhorloge. Un bit toutes les 372 impulsions dhorloge.
Autrement dit, bien que la communication soit asynchrone, les changes sont en ralits
synchroniss par lutilisation dune horloge commune : cest assez particulier.

Pour recevoir correctement les bits envoys, il faut convenir dun protocole de
communication. Ce dernier doit comprendre les informations suivantes :

- La vitesse de transmission en bauds


- Le format, cest dire le nombre de start-bits, de stop-bits, de bits de donnes et le type de
parit

Nous allons maintenant expliquer ces concepts et indiquer quelles sont les valeurs
employes dans la norme ISO 7816.

20.2.1 Le start-bit

Au repos, la ligne se trouve ltat haut. Lmetteur fait alors passer la ligne ltat
bas : cest le start-bit. Cest ce changement de niveau qui va permettre de dtecter le dbut de
la rception des bits en srie.

Les valeurs admissibles sont 1 ou 2 start-bit(s). La norme ISO 7816 ncessite un seul
start-bit.

20.2.2 Les bits de donnes

Aprs avoir reu le start-bit, on trouve les bits de donnes, en commenant par le bit 0.
Les normes usuelles utilisent 7 ou 8 bits de data. Pour la norme ISO 7816, nous aurons 8 bits
de donnes, ce qui nous donne des valeurs admissibles de 0 0xFF pour chaque octet reu.

236
20.2.3 Le bit de parit

Le bit de parit est une vrification du bon droulement du transfert. Lors de


lmission, on comptabilise chaque bit de donne qui vaut 1. A la fin du comptage, on ajoute
un bit 1 ou 0 de faon obtenir un nombre de bits total impair ou pair.

On dira quon utilise une parit paire si le nombre de bits 1 dans les bits de donnes
y compris le bit de parit est un nombre pair.

De mme, une parit impaire donnera un nombre impair de bits 1.

Notez que le bit de parit nest pas indispensable dans une liaison srie asynchrone.
Nous avons donc 3 possibilits, savoir pas de parit, parit paire, ou parit impaire.

Dans le cas de la norme ISO 7816, nous devrons utiliser une parit paire.

20.2.4 Le stop-bit

Aprs la rception des bits prcdents, il est impratif de remettre la ligne ltat haut
pour pouvoir dtecter le start-bit de loctet suivant. Cest le rle du stop-bit. Les valeurs
admissibles sont de 1 ou 2 stop-bits.

Dans la norme ISO 7816, nous utiliserons 2 stop-bits, cest dire tout simplement un
stop-bit dune dure quivalente la dure de 2 bits (la ligne ne subit pas de changement entre
les deux stop-bits).

20.2.5 Vitesse et dbit

La dure de chaque bit est une constante et dpend de la vitesse de transmission.


Par exemple, pour une vitesse de 9600 bauds, cest dire 9600 bits par seconde, chaque bit
durera 1s/9600 = 104,17 S.

Le temps ncessaire pour recevoir un octet entier est la somme du temps ncessaire
pour recevoir chacun des bits de cet octet. Dans le cas de la norme ISO 7816, nous utiliserons
1 start-bit + 8 bits de donnes + 1 bit de parit + 2 stop-bits = 12 bits. Le temps total pour
recevoir un octet est donc de 1250 S.

Le dbit maximum en octets par seconde est donc gal :

Dbit maximum = 1 / (nbre de bits * dure dun bit), soit pour la norme ISO 7816 :

1 / 1250 * 10-6 = 800 octets par seconde.

Ceci pour une vitesse de transfert de 9600 bauds. Notez que cette valeur nest pas impose
par la norme, il est donc possible daugmenter ce dbit.

Nous parlons ici de dbit maximum car ceci est le cas dans lequel un octet commence ds
la fin du prcdent, ce qui nest pas obligatoire pour une liaison asynchrone.

237
20.3 Acquisition des bits

Nous allons dabord reprsenter ce que nous venons de voir sous forme dun
graphique. Sur laxe vertical nous avons les niveaux, sur laxe horizontal, le temps.

Examinons ce graphique. La ligne est ltat haut depuis un temps indtermin. Survient
le start-bit, qui commence aprs un temps indfini. Nous voyons que le meilleur moment pour
lire le bit 0 est de le mesurer au milieu de sa largeur afin dobtenir le moins de risque derreur
de timing possible.

Souvenez-vous que pour la norme ISO 7816, la largeur dun bit vaut 372 impulsions
dhorloge. Comme notre PIC divise dj la frquence dhorloge par 4 pour obtenir sa
frquence de cycles dinstruction, cela nous fera une largeur de bit quivalent 372/4 = 93
cycles dinstruction.

Le bit 0 sera donc lu 93 + 46 cycles dhorloge aprs le dbut du start-bit. Ensuite nous
pourrons lire tous les bits un intervalle de temps quivalent 93 instructions.

Une fois le bit de parit lu, nous avons 2 possibilits :

- Si nous souhaitons faire suivre cette lecture par la lecture dun autre octet, nous devons
nous positionner quelque part lintrieur des 2 stop-bits afin dtre prt dtecter le
start-bit suivant. Nous devons donc attendre entre 0.5 et 2.5 bits.

- Si nous souhaitons envoyer un octet aprs cette lecture, nous ne pourrons pas le faire
avant la fin du second stop-bit, soit au minimum aprs 2.5 cycles.

Par curiosit, quel est donc loctet que nous avons reu dans cet exemple ? Et bien tout
simplement :

b0 = 1
b1 = 0
b2 = 0
b3 = 1
b4 = 0
b5 = 1
b6 = 0
b7 = 1
Parit = 0

238
Loctet reu est donc B10101001 , soit 0XA9. Profitons-en pour vrifier la parit.
Nombre de bits 1 reus = 4, donc parit paire, cest donc conforme la norme ISO 7816,
loctet est prsum reu correctement.

20.4 Caractristique des cartes standard

Sur les cartes du commerce, de type carte pour serrure code 16F84, les
connexions utilises sont gnralement les suivantes :

Nom pin Pin Signal Rle du signal Type


MCLR 4 RST Commande de reset de la carte Entre
VSS 5 GND Masse Alimentation
RB4 10 SDA data pour eeprom externe (24C16) Bi-directionnel
RB5 11 SCL horloge pour eeprom externe Sortie
RB7 13 DATA donnes mode srie half-duplex Bi-directionnel
VDD 14 +5V Alimentation +5V Alimentation
CLKIN 16 CLK Entre de lhorloge externe Oscillateur

20.5 Cration et initialisation du projet

Suivant note mthode habituelle, copiez / collez votre fichier m16f84.asm et


renommez la copie iso7816.asm . Crez votre projet dans MPLAB.

Ensuite, crez votre en-tte de programme :


;***********************************************************************
; Ce fichier est la base de dpart pour la gestion d'une carte *
; rpondant la norme ISO7816. *
; *
;***********************************************************************
; *
; NOM: ISO7816 *
; Date: 10/03/2001 *
; Version: 1.1 *
; Circuit: Carte pour serrure code *
; Auteur: Bigonoff *
; *
;***********************************************************************
; *
; Fichier requis: P16F84.inc *
; *
;***********************************************************************
; *
; - MCLR Commande de reset de la carte Entre *
; - RB4 SDA - data pour eeprom externe Bi-directionnel *
; - RB5 SCL - horloge pour eeprom externe Sortie *
; - RB7 DATA - donnes mode srie Bi-directionnel *
; *
;***********************************************************************

Dfinissons la configuration : Nous nallons pas utiliser le watch-dog pour cette


application, et nous utiliserons une horloge externe. Nous aurons donc :

239
LIST p=16F84 ; Dfinition de processeur
#include <p16F84.inc> ; Dfinitions des constantes
radix dec ; travailler en dcimal par dfaut

__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC

; Code protection OFF


; Timer reset sur power on en service
; Watch-dog hors service
; Oscillateur quartz grande vitesse

Calculons maintenant la valeur encoder dans notre registre OPTION :

Nous devons utiliser, pour des raisons de compatibilit lectronique, la rsistance de


rappel au +5V de la pin RB7. Nous aurons donc b7 du registre OPTION = 0. Ensuite, nous
allons travailler avec le timer0.

Comme lcart entre 2 bits est de 93 instructions, nous travaillerons sans prdiviseur,
ce qui nous impose de rediriger le prdiviseur vers le watchdog.

Dfinissons donc la valeur placer dans OPTION :

OPTIONVAL EQU 0x08 ; Valeur registre option


; Rsistance pull-up ON
; Prscaler timer 1

20.6 La base de temps

Nous voyons dj que nous allons avoir besoin de 2 temporisations : une de 93


instructions et une de 93+46 instructions, correspondant 1 et 1,5 bits. Nous allons donc
construire une sous-routine.
;*********************************************************************
; TEMPORISATION *
;*********************************************************************
;---------------------------------------------------------------------
; temp_1bd: initialise tmr0 pour que la temporisation soit gale
; l'quivalent d'un bit et demi, soit 46+93 incrmentations
; de tmr0 le temps ncessaire pour arriver dans la routine
; temp_1b : Attend que l'cart entre la prcdente tempo et la tempo
; actuelle soit de 1 bit, soit 93 instructions
;---------------------------------------------------------------------
temp_1bd
movlw -38 ; en tenant compte des 2 cycles darrt de Tmr0
movwf TMR0 ; initialiser tmr0
call temp_suite ; et attendre 1/2 bit

temp_1b
movlw -91 ; cart entre 2 bits + 2 cycles darrt
addwf TMR0 , f ; ajouter la valeur actuelle

temp_suite
bcf INTCON , T0IF ; effacer flag

temp_wait
btfss INTCON , T0IF ; attendre dbordement timer
goto temp_wait ; pas fini, attendre

240
return ; et sortir

Comment cette routine fonctionne-t-elle ? Et bien vous remarquez que vous avez 2
points dentre, temp_1bd et temp_1b. Commenons par examiner ce dernier point.

Nous commenons par charger la dure correspondant 91 instructions avant le


dbordement du timer, soit 0 91, ou encore plus simplement 91. Il ne faut cependant pas
oublier quun certain nombre dinstructions ont dj t excutes depuis le dernier passage
dans la routine timer, lors de la rception ou lmission du bit prcdent (et quon perd 2
incrmentations du timer du fait de sa modification).

Quel est le nombre de ces instructions ? Et bien tout simplement le nombre contenu
dans TMR0, puisque le prcdent passage avait attendu sa remise 0. Il ne faut donc pas
placer 91 dans tmr0, mais bien AJOUTER 91 au contenu actuel de TMR0.

De cette faon, nous sommes assurs que le dbordement du TMR0 se fera exactement
93 cycles aprs le prcdent dbordement, quelque soit le nombre dinstructions excut entre
les 2 appels. Ceci, bien entendu condition que le timer nai pas dbord avant, mais ceci
impliquerait que nous navons pas le temps de tout excuter entre 2 bits, donc que le PIC
nest pas suffisamment rapide, ou notre application pas suffisamment optimise en temps
dexcution.

Tout de suite aprs, nous replaons le flag T0IF 0, et nous attendons simplement que
le dbordement du timer entrane le repositionnement du flag.

Examinons maintenant le point dentre temp_1bd : Nous commenons par initialiser


TMR0 avec 38, pour dmarrer la temporisation de 40 instructions partir de ce point.

Comme cest au dbut de lacquisition que nous avons besoin dun demi-bit, il ny a pas
eu de bit prcdent, donc nous devons placer cette valeur et non faire une addition. De plus,
entre la dtection du start-bit et linitialisation de TMR0, il sest pass quelques instructions.
On peut grossirement considrer quil sest pass 6 instructions, ce qui nous donne une
valeur charger de (46 6) = -40, et en tenant compte des 2 cycles perdus : -38.

Quelle est en ralit notre marge derreur autorise ? Et bien tout simplement la moiti
de la dure dun bit, cest dire 46 cycles, afin de ne pas tomber sur le bit voisin. Nous ne
sommes donc pas 1 cycle prs, mais il faut rester le plus prcis possible pour le cas o une
drive de lappareil connect augmenterait notre imprcision. Il faut penser que le concepteur
du logiciel du matre a peut-tre lui aussi profit de cette tolrance.

Ensuite nous appelons la sous-routine elle-mme de faon attendre la dure prvue,


puis la sous-routine poursuit en excutant la temporisation de 93 cycles. Nous avons donc
attendu en tout 93 + 40 cycles plus le temps dappel de la routine plus le temps de retour, plus
le temps ventuel perdu dans la boucle dattente du start-bit, soit la dure approximative de
1,5 bit. De plus cette sous-routine nutilise aucune variable.

20.7 Rception dun octet

Maintenant que vous avez compris comment recevoir un octet en mode srie
asynchrone, il est temps dcrire notre sous-programme de rception dun octet. Dans cet
exercice, nous ne vrifierons pas si le bit de parit reu est correct. Je vous laisse de soin

241
dintgrer ce test vous-mme si cela vous intresse. Dans ce cas, vous devrez lire 9 bits et
vrifier si le nombre de 1 reus est pair. Il y a plusieurs mthodes possibles, la plus simple
est dutiliser le bit reu comme appliquant un xor sur le bit de parit, ainsi, chaque bit 1
reu, le bit de parit calcul est invers, ne vous reste qu le comparer au final avec le bit
reu.

Notre sous-programme devra donc effectuer les oprations suivantes :

- Attendre le dbut du start-bit


- Attendre une dure de 93 + 46 instructions
- Pour chacun des 8 bits, lire le bit et le placer dans le caractre reu en bonne position
- Se positionner quelque part dans les stop-bits

Voici donc notre sous-programme :

;*********************************************************************
; Rception d'un octet provenant du matre *
;*********************************************************************
;---------------------------------------------------------------------
; Caractre lu dans W. La parit pas n'est pas vrifie
;---------------------------------------------------------------------
Receive
; attendre dbut start-bit
; ------------------------

btfsc SERIAL ; Tester si start bit arriv


goto Receive ; non, attendre

; se positionner sur le milieu du 1er bit utile


; ---------------------------------------------
call temp_1bd ; attendre 1bit et demi

; rception du caractre
; ----------------------

movlw 0x8 ; pour 8 bits


movwf cmptbts ; dans compteur de bits

Recloop
bcf STATUS , C ; Carry = 0
btfsc SERIAL ; tester si bit = 0
bsf STATUS , C ; Carry = bit reu
rrf caract , f ; faire entrer le bit par la gauche
call temp_1b ; attendre milieu caractre suivant
decfsz cmptbts , f ; dcrmenter compteur de bits
goto Recloop ; pas dernier, suivant

; on pointe actuellement sur le centre du bit de parit


; reste donc attendre +- 1.5 bits pour tre dans le second stop-bit
; -------------------------------------------------------------------

call temp_1bd ; Attendre 1,5 bit


movf caract , w ; charger caractre lu
return ; et retour

242
Ce sous-programme ne contient pas de difficults particulires. Remarquez que plutt
que de positionner chaque bit reu directement la bonne position, on le fait entrer dans b7 en
se servant dune instruction rrf . Le bit prcdent est de fait recul en b6 et ainsi de suite.

Au final, le premier bit lu se retrouve donc en b0, le dernier restant en b7, ctait bien le
but recherch.

Concernant la dernire temporisation, nous pointons ce moment sur le centre du 9me


bit, cest dire le bit de parit. Comme nous ne le traitons pas, inutile de le lire. Nous devons
alors nous positionner sur un endroit o la ligne est repasse au niveau 1 , cest dire un
des stop-bits, afin de pouvoir ventuellement commencer une attente dun nouveau caractre.

Nous devons donc attendre entre 0.5 et 2.5 bits. La sous-routine 1.5 bit est en plein
dans cette zone et est directement utilisable.

Le prsent sous-programme utilise des variables que nous dclarerons plus loin.

20.8 Lmission dun caractre

Noublions pas que notre carte nmet quen rponse une interrogation du matre .
Donc, notre sous-programme dmission sera appel aprs le sous-programme de rception
dun octet.

Il est important galement de se souvenir que nous travaillons en mode half-duplex,


cest dire que la mme ligne sert pour les entres et les sorties. Comme chacun des
interlocuteurs parle tour de rle, il faut laisser chacun le temps de repasser en lecture aprs
lenvoi de son dernier message. Ceci sappelle temps de retournement . Il faut galement
se rappeler que notre routine de rception sachvera quelque part au milieu des stop-bits, il
faudra galement laisser lmetteur le temps de finir denvoyer la fin de ses stop-bits.

Un bon compromis et la facilit dcriture du programme nous permet de choisir une


attente de 1.5 bit avant de commencer mettre. Jai choisi cette valeur car cette
temporisation permet dinitialiser le timer. Cette valeur nest cependant pas critique. Il faut
simplement rpondre aprs que le matre soit plac en mode de rception, et avant quil ne
considre que vote carte na pas rpondu.

Notre programme va donc effectuer les oprations suivantes :

- Attendre temps choisi avant mission


- Passer en mission et envoyer le start-bit
- Envoyer les 8 bits en commenant par b0
- Pour chaque bit 1 envoy, inverser la parit, pour obtenir une parit paire
- Envoyer la parit
- Envoyer les 2 stop-bits
- Repasser en rception

Voici donc notre sous-programme :

;*********************************************************************
; Envoi d'un octet vers le lecteur de carte *

243
;*********************************************************************
;---------------------------------------------------------------------
; envoie l'octet contenu dans le registre w vers le lecteur de carte
;---------------------------------------------------------------------
Send
movwf caract ; Sauver caractre envoyer
call temp_1bd ; attendre 1 bit et demi
BANK1 ; passer banque1
bcf SERIAL ; port srie en sortie
BANK0 ; repasser banque 0

; envoyer start-bit
; --------------------
bcf SERIAL ; envoyer 0 : start-bit
clrf parite ; effacer bit de parit

movlw 8 ; pour 8 bits envoyer


movwf cmptbts ; dans compteur de bits
call temp_1b ; attente entre 2 bits

; envoyer 8 bits de data


; ---------------------------
Send_loop
rrf caract , f ; dcaler caractre, b0 dans carry
rrf caract , w ; carry dans b7 de w
xorwf parite , f ; positionner parit
xorwf PORTB , w ; Garder 1 si changement sur SERIAL
andlw 0x80 ; on ne modifie que RB7
xorwf PORTB , f ; si oui, inverser RB7
call temp_1b ; attente entre 2 bits
decfsz cmptbts , f ; dcrmenter compteur de bits
goto Send_loop ; pas dernier, suivant

; envoyer parit
; --------------
movf parite , w ; charger parit paire calcule
xorwf PORTB , w ; Si serial diffrent de bit envoyer
andlw 0x80 ; on ne modifie que RB7
xorwf PORTB , f ; alors inverser RB7
call temp_1b ; attendre fin de parit

; envoyer 2 stop-bits
; -------------------
BANK1 ; passer banque1
bsf SERIAL ; repasser en entre (et niveau haut)
BANK0 ; passer banque 0
call temp_1b ; attendre temps entre 2 bits
call temp_1b ; attendre temps entre 2 bits
return ; et retour

Si vous tes attentifs, vous avez remarqu une lgre inversion en ce qui concerne la
fin du protocole. En effet, plutt que denvoyer un niveau 1 (stop-bit) puis dattendre 2 bits et
enfin de repasser en entre, nous sommes pass en entre puis avons attendu 2bits.

Ceci est strictement identique, car la rsistance de rappel au +5V du PORTB, que nous
avons active se charge dimposer un niveau haut sur RB7 ds que cette pin est remise en
entre, un niveau haut correspondant un stop-bit.

244
La routine servant envoyer les 8 bits utilise linstruction xorwf au lieu de tester si
le bit mettre vaut 1 ou 0. La routine commence par placer le bit mettre en position b7.

Pourquoi b7 ? Et bien tout simplement parce que cest galement b7 dans le PORTB que
nous devrons modifier. Nous utilisons en effet RB7. La procdure utilise permet de
positionner en mme temps le bit de parit.

Effectuez lopration manuellement sur papier pour vous en convaincre. Tentez dcrire
une routine utilisant btfss et btfsc et comparez les rsultats obtenus.

Un petit mot concernant lenvoi du bit proprement dit, cest dire les 3 instructions :

xorwf PORTB , w ; Garder 1 si changement sur SERIAL


andlw 0x80 ; on ne modifie que RB7
xorwf PORTB , f ; si oui, inverser RB7

Nous commenons ici par lire le PORTB et nous effectuons un xorlw avec le bit
envoyer contenu dans W . Comme W ne contient que ce bit, RB0 RB6 ne seront pas
modifis par les oprations suivantes.

Si le bit7 contenu dans W est diffrent de celui prsent sur RB7, nous obtenons b7
= 1 dans W. Dans le cas o b7 de W est identique RB7, nous obtenons 0. Noublions pas en
effet que le ,w permet de placer le rsultat dans W .

Si nous appliquons W sur le PORTB en effectuant un xorwf , nous inverserons


RB7 uniquement si b7 de W vaut 1, cest dire, en dautres mots : Nous inverserons RB7
uniquement si son niveau actuel est diffrent du niveau que nous devons envoyer.

Ceci parat un peu tordu , mais si vous essayez dcrire cette routine autrement,
vous verrez quen effectuant plusieurs essais, vous arriverez un rsultat au moins aussi long,
tout ceci cause de la parit grer. Sauf si vous acceptez de modifier les autres lignes du
PORTB (vous pouvez si elles ne sont pas utilises pour autre chose).

Remarquez que vous pouvez ignorer la vrification du bit de parit en rception, cest
votre problme. Par contre, vous tes oblig de positionner correctement celle-ci lmission,
car il y a de fortes chances pour que le matre vrifie cette parit.

20.9 Initialisation

Nous allons maintenant tudier le corps de notre programme principal. Comme tout
programme qui se respecte, nous commencerons par linitialisation. Celle-ci va tre trs
simple, elle se limite initialiser le registre OPTION.

;*********************************************************************
; INITIALISATIONS *
;*********************************************************************
org 0x000 ; Adresse de dpart aprs reset
init
BANK1 ; passer banque1
movlw OPTIONVAL ; charger masque
movwf OPTION_REG ; initialiser registre option

245
BANK0 ; passer banque 0

20.10 Envoi de lATR

ATR signifie Answer To Reset, cest dire rponse un reset. Cest une commande
envoye par la carte lors dune mise sous tension ou lors dun reset gnr par le matre via la
broche MCLR .

Tout dabord, nous allons attendre un peu que le matre soit prt recevoir notre ATR.
Il peut tre ncessaire dajuster ce temps en fonction des caractristiques du matre, qui a
probablement dautres choses faire au dmarrage que de soccuper directement de votre
carte.

;*********************************************************************
; PROGRAMME PRINCIPAL
*
;*********************************************************************
start
; on commence par attendre un peu
; -------------------------------
call temp_1bd ; attendre 1 bit et demi

Ensuite, nous pouvons envoyer lATR. Pour des raisons de facilit, nous avons crit
notre ATR dans la zone eeprom interne. Jai choisi un ATR de 5 caractres que jai invent.
Consultez les caractristiques du matre pour connatre les ATR valides de votre application.

;===============================================================
; ENVOI DE L'ATR =
;===============================================================
;---------------------------------------------------------------
; Envoi d'un ATR fictif : l'ATR est dans les 5 octets de 0x04
; 0x00 de l'eeprom interne. L'ATR est cris en sens inverse
;---------------------------------------------------------------
movlw 0x5 ; pour 5 octets
movwf cmpt1 ; dans compteur de boucles = adresse
ATR_loop
decf cmpt1 , w ; adresse lire = compteur de boucles-1
call Rd_eeprom ; Lire un octet eeprom interne
call Send ; Envoyer sur le dcodeur
decfsz cmpt1 , f ; dcrmenter compteur
goto ATR_loop ; pas fini, suivant

Remarques

Lutilisation de la commande decfsz facilite lcriture des boucles, mais, comme le


compteur de boucles est en mme temps loffset de la position en eeprom, lATR sera crit
lenvers dans leeprom, cest dire du dernier vers le premier octet.

A lendroit de lappel de la sous-routine Rd_eeprom , le compteur de boucles


variera de 5 1. Or, notre adresse eeprom variera de 4 0. Donc, lopration decf permet
de charger dans W la valeur du compteur de boucles 1.

Le sous-routine Rd_eeprom nest rien dautre que notre macro de lecture de


mmoire eeprom transforme en sous-programme. La voici :

246
;*********************************************************************
; Lecture d'un octet en eeprom interne *
;*********************************************************************
;---------------------------------------------------------------------
; Lecture d'un octet de l'eeprom interne. L'adresse est passe dans w.octet lu
est dans W
;---------------------------------------------------------------------
Rd_eeprom
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 banque 0
movf EEDATA , w ; charger valeur lue dans W
return ; retour

Pensons galement inscrire notre ATR dans la zone eeprom :

;*********************************************************************
; DECLARATIONS DE LA ZONE EEPROM *
;*********************************************************************
org 0x2100 ; adresse dbut zone eeprom

ATR DE 0x07 ; Rponse l'ATR


DE 0xAB ; B7 01 BB AB 07
DE 0xBB
DE 0x01
DE 0xB7

20.11 Lenvoi du statut

La norme ISO 7816 demande que chaque mission dune rponse de la carte soit suivi
de 2 octets de statut qui indiquent la manire dont a t interprte la commande.

Jai invent des statuts pour cet exercice. Le statut 80 00 indiquera que la
commande a t excute correctement (la valeur 90 00 est courante). Jutiliserai galement le
statut 60 40 pour indiquer que la commande nexiste pas.

Nous allons donc crer 2 sous-programmes. Un qui envoie le statut standard, lautre
qui envoie nimporte quel statut.

;===============================================================
; ENVOI DU STATUS STANDARD =
;===============================================================
;---------------------------------------------------------------
; Envoie le statut standard, dans ce cas on a pris 0x80 0X00
;---------------------------------------------------------------
Statstd
movlw 0x80 ; prendre 1er octet statut
call Send ; l'envoyer
clrw ; effacer w
call Send ; envoyer 00
goto classe ; et traiter classe

;================================================================
; ENVOI D'UN STATUT SPECIFIQUE =
;================================================================
;----------------------------------------------------------------

247
; Envoie d'abord l'octet contenu dans w, puis l'octet contenu dans status2
;----------------------------------------------------------------
Statxx
call Send ; on envoie valeur
movf status2 , w ; charger byte envoyer
call Send ; on envoie 2me octet du statut

20.12 Rception de la classe

Maintenant, notre carte passe en mode rception et attend sa premire commande.


Notre programme, pour des raisons de facilit ne gre quune seule classe. Nous nous
contentons donc de lire loctet, sans le vrifier ni le traiter. Il sagit en effet dun exercice
didactique.

;=================================================================
; LECTURE DE LA CLASSE =
;=================================================================
;-----------------------------------------------------------------
; on considre dans cet exemple qu'il n'y a qu'une seule classe valide.
; on attend l'arrive de la classe et on ne la traite pas
;-----------------------------------------------------------------
classe
call Receive ; Lire le byte venant du matre

20.13 Rception de INS, P1, P2, et LEN

Examinons maintenant notre routine de rception de linstruction, des paramtres P1 et


P2, ainsi que de la longueur de la chane.
;===============================================================
; LECTURE DE INS,P1,P2,LEN =
;===============================================================
;---------------------------------------------------------------
; INS sera plac dans la variable Ser_ins P1 sera plac dans
; Ser_P1 et P2 dans Ser_P2
; La longueur du champs de data sera dans Ser_len
;---------------------------------------------------------------
movlw Ser_Ins ; pointer sur emplacement instruction
movwf FSR ; initialiser pointeur indirection
read_loop
call Receive ; Lire un octet
movwf INDF ; sauver dans emplacement prvu
incf FSR , f ; pointer sur suivant
btfss FSR , 0x4 ; Tester si adresse 0x10 atteinte
goto read_loop ; non, octet suivant

Vous pouvez constater lutilisation de ladressage indirect pour sauvegarder les octets
reus dans 4 emplacements conscutifs. Nous choisirons les adresses 0x0C 0x0F, ce qui
nous permet facilement de dtecter la fin de la commande. En effet, une fois le 4me octet
sauv, FSR pointe sur 0x10 (B0001 0000) il suffit donc de tester son bit 4 pour tester la fin
de la boucle, sans avoir besoin dun compteur de boucles supplmentaire.

248
20.14 Contrle de linstruction reue

Une fois la commande reue, nous devons traiter les diffrentes commandes reues.
Dans notre exemple didactique, jai implment une seule instruction. La seule instruction
valide est linstruction 0x25.

Cette instruction calcule la somme de P1 et P2, et renvoie le rsultat. Comme LEN


contient la longueur de la chane de rponse, si LEN est suprieur 1, la rponse sera
complte par des 0xFF. Toute autre instruction sera considre comme incorrecte.

Voici notre test :

;==============================================================
; SWITCH SUIVANT INSTRUCTION RECUE =
;==============================================================
;--------------------------------------------------------------
; Nous allons imaginer que nous allons ragir une instruction 0x25
; Toute autre instruction sera considre comme incorrecte
;--------------------------------------------------------------
; tester instruction reue
; ------------------------
movf Ser_Ins , w ; charger instruction reue
sublw 0x25 ; comparer avec 0x25
btfsc STATUS , Z ; tester si identique
goto Ins25 ; oui, traiter instruction 25

; traiter instruction incorrecte


; ------------------------------
movlw 0x40 ; charger octet2 statut envoyer
movwf status2 ; placer dans variable
movlw 0x60 ; charger octet 1 statut
goto Statxx ; envoyer statut
Nous voyons ici que si linstruction reue est 0x25, nous sautons au traitement de
linstruction. Dans le cas contraire, nous envoyons le statut 60 40 qui signifie dans notre
cas instruction incorrecte .

20.15 Traitement dune instruction

Nous en arrivons maintenant au traitement de notre instruction proprement dite.

On va traiter cette instruction de la manire suivante :

- Comme dans toute instruction, on renvoie linstruction reue


- La carte renvoie la somme de P1 et de P2.
- La trame d'envoi est complt par des 0xFF pour atteindre une longueur totale de data
identique Ser_Len
- Ensuite notre statut standard est envoy : 80 00

;================================================================
; TRAITER INSTRUCTION 25 =
;================================================================
Ins25
; envoyer cho de la commande
; ---------------------------

249
movf Ser_Ins,w ; charger commande reue
call Send ; renvoyer en cho

; renvoyer P1 + P2
; ----------------
movf Ser_P1,w ; charger P1
addwf Ser_P2,w ; + P2
call Send ; envoyer rsultat

; Tester longueur de la rponse


; -----------------------------------
decf Ser_Len,f ; car dj rsultat envoy
btfsc STATUS,Z ; tester si complet
goto Statstd ; oui, envoyer statut standard

; complter avec des 0xFF


; -----------------------
Insloop
movlw 0xFF ; valeur envoyer
call Send ; envoyer 0xFF
decfsz Ser_Len,f ; dcrmenter compteur de boucles
goto Insloop ; pas fini, suivant

; envoyer status standard


; -----------------------------
goto Statstd ; envoyer status standard

20.16 Les variables

Il nous reste maintenant dclarer les variables utilises. Jai dcid ici dutiliser des
variables locales lorsque ctait possible :

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

CBLOCK 0x00C ; dbut de la zone variables


Ser_Ins : 1 ; instruction ISO7816
Ser_P1 : 1 ; paramtre 1 ISO7816
Ser_P2 : 1 ; paramtre 2 ISO7816
Ser_Len : 1 ; longueur data ISO7816
local1 : 1 ; variable locale 1
local2 : 1 ; variable locale 2
local3 : 1 ; variable locale 3
local4 : 1 ; variable locale 4
temp_sauvw : 1 ; sauvegarde de W pour temp
ENDC ; Fin de la zone

; routine ATR
; -----------
#DEFINE cmpt1 local1 ; compteur d'octets pour ATR

; sous-routine send et receive


; ----------------------------
#DEFINE caract local2 ; caractre envoyer
#DEFINE parite local3 ; bit de parit
#DEFINE cmptbts local4 ; compteur de bits

; pour STATUS

250
; -----------
#DEFINE status2 local1 ; octet 2 du statut

; pour instruction 25
; -------------------
#DEFINE cmpt2 local1 ; compteur d'octets

20.17 Conclusion

Vous savez maintenant communiquer en liaison srie asynchrone. De plus vous


avez les notions de base ncessaire pour raliser une carte rpondant la norme ISO7816.
Nul doute que vous trouviez de nombreuses applications mettant en uvre la thorie vue ici.

Je vous rappelle quil sagit ici dun exemple imaginaire mais les cas rencontrs dans
la pratique sont trs proches de cet exemple et les techniques mises en uvres ont t utilises
avec succs dans plusieurs logiciels travaillant avec des cartes ISO7816 relles : il ne sagit
donc pas que de thorie pure, et jai test avec succs le logiciel prsent avec un lecteur de
carte ISO7816.

Notez que jai reu ( lpoque de la gloire du dcodage satellite) de nombreux


courriers de lecteurs qui ont cru avis de commencer la lecture du cours par ce chapitre,
surtout lpoque rvolue de la ralisation personnelle de cartes destines au dcryptage des
programmes TV par satellite. Il ne faut pas mettre la charrue avant les bufs, et si ce chapitre
est plac en fin de cours, cest que jai estim quil ncessitait la comprhension de ce qui
prcde.

Notez pour lanecdote que, si ce cours existe, cest grce aux cartes ISO7816 et au
dcryptage des chanes TV satellite. En effet, jtais lpoque administrateur dun gros
forum ax sur le dcodage satellite, et jai propos la premire version de ce cours sous forme
de chapitres indpendants prsents en tant que leons directement en ligne sur ce forum.
Je comptais profiter de lengouement du dcodage pour inciter les jeunes (et moins
jeunes) sintresser la faon dont fonctionnait rellement un microcontrleur. Avant cette
poque je travaillais sur 8051, ce sont ces cartes ISO qui mont fait adopter les PIC.

251
Notes :

252
Annexe1 : Questions frquemment poses (F.A.Q.)

Je vais tenter de rpondre ici un maximum de questions que se posent les utilisateurs
en gnral.

A1.1 Je trouve que 8 sous-programmes, cest peu

Attention, vous ne devez pas confondre le nombre de sous-programme et le nombre


dimbrications de sous-programmes. Le nombre de sous-programme est illimit (dans la
limite de la mmoire disponible).

Une imbrication, cest quand un sous-programme appelle un autre sous-programme.


Pour compter les niveaux dimbrications, suivez le chemin de votre programme dans lordre
dexcution. Faites +1 pour chaque instruction call rencontre et (-1) pour chaque
instruction return ou retlw .

Si votre programme est correct, les 3 conditions suivantes doivent tre remplies :

- On ne doit jamais durant le comptage passer en ngatif


- On ne peut jamais dpasser 8 durant le comptage
- A la fin de lexcution du programme, on doit tre revenu 0

Attention, noubliez pas de tenir compte des interruptions (voir lannexe A1.2).

A1.2 Je nutilise que 8 imbrications, et pourtant mon programme plante.

Vous ne devez pas oublier que les interruptions utilisent aussi la pile. Si vous utilisez
les interruptions, vous navez droit qu 7 niveaux dimbrication au lieu de 8 (moins les sous-
routines utilises ventuellement par la routine dinterruption).

A1.3 Mon programme semble ne jamais sortir des interruptions

Vous avez oubli deffacer le flag qui a provoqu linterruption. Noubliez pas non
plus de sortir des interruptions avec retfie et non return, sans quoi vos interruptions ne seraient
pas remises en service et vous ny rentreriez plus. Une autre erreur classique est de remettre
0 le flag RBIF sans avoir pralablement lu PORTB.

A1.4 Je narrive pas utiliser le simulateur, les options napparaissent pas

Vous avez oubli de signaler MPLAB que vous utilisez le simulateur intgr. Allez
dans le menu debugger -> select tool et slectionnez MPLAB SIM . Configurez
ensuite comme expliqu dans le chapitre concern.

253
A1.5 Je reois un message derreur EOF avant instruction END

Vrifiez si votre fichier comporte la directive END.

Ouvrez votre fichier .asm dans le bloc-notes de Windows et vrifiez quil se


prsente correctement, avec les mises la ligne correctes. Si ce nest pas le cas, cest que le
fichier a t crit avec un diteur qui ne gnre pas les bons retours de ligne. Dans ce cas,
essayez un copier/coller de ce fichier dans un fichier vide cr avec un autre diteur.

A1.6 Comment dsassembler un fichier .hex ?

Je vais vous dcrire 2 mthodes pour dsassembler un fichier en format hexadcimal.


La premire mthode utilise MPLAB :

1) Allez dans le menu File-> import


2) Slectionnez le fichier .hex dsassembler
3) Slectionnez View-> program memory
4) Slectionner longlet qui correspond votre dsir

La seconde mthode utilise IC-Prog, le clbre utilitaire de programmation des PIC


(pass aujourdhui de mode) disponible partout une certaine poque :

1) Chargez le fichier .hex depuis le menu File->open file


2) Slectionnez view->assembler . Cest tout.

A1.7 Utilisation des minuscules et des majuscules

Par dfaut, MPLAB effectue la distinction entre minuscules et majuscules (casse). Si


cela vous pose problme, vous pouvez le modifier dans les proprits de votre projet.
Pour effectuer cette opration :

- Slectionnez project -> build options -> project


- Slectionnez longlet MPASM assembler
- Cochez la case disable case sensitivity

Je vous dconseille cependant dignorer la casse car votre source ne serait plus portable
sur tous les assembleurs.

A1.8 Le choix dun programmateur

Jai dcid de modifi radicalement mon conseil initial des premires versions de ce
cours, suite lvolution de la stratgie commerciale de Microchip, qui rend mon avis peu
judicieuse la constructeur dun programmateur personnel . Dautant plus que les
programmes les plus clbres de pilotage dun programmateur de PIC ne suivent plus
maintenant vraiment la sortie des nouveaux modles.

254
Si vous dcidez de construire quand mme votre programmateur, au moins ne
construisez pas un programmateur de type JDM (source de problme vident), qui se
reconnat au fait quil est connect sur le port srie (com) sans disposer dune alimentation
lectrique (il tire son alimentation directement du port srie).

Evitez aussi surtout de construire un programmateur srie que vous brancheriez, pour
cause dabsence de port srie sur votre PC, sur un convertisseur USB/RS232, tout
simplement parce quen gnral a ne fonctionne pas, lintgralit des lignes ncessaires
ntant pas prise en charge de faon complte par les interfaces sries connectes au port
USB.

Mon conseil est donc devenu clairement : achetez un programmateur officiel


PicKit3 ou ICD3. Nachetez plus les versions 2 , elles ne seront plus utilisables sur les
futurs nouveaux PIC. Les avantages seront nombreux :

- Possibilit de programmer le PIC directement partir de MPLAB (pas besoin


dutiliser un autre logiciel)

- Le programmateur reconnatra tous les PIC prvus dans votre version de MPLAB,
quil suffit donc de mettre jour lors de la sortie dun nouveau PIC

- Ces programmateurs fonctionnent aussi en tant que debugger sur circuit (voir cours-
part4), et donc vous pourrez dbuguer au vol tous vos programmes ciblant des PIC
qui disposent de la fonctionnalit ICD , soit une grande majorit des PIC rcents (pas
le 16F84).

- Vous serez certain que votre programmateur fonctionne et donc vous pourrez vous
concentrer sur quelque chose dutile si votre montage ne fonctionnait pas.

- La garantie est trs tendue, lICD2 en ma possession, par exemple, est toujours
considr par Microchip comme tant sous garantie malgr plusieurs annes
dutilisation (garantie de fait vie ?).

Mon conseil est donc clairement : ne construisez votre propre programmateur que si
vous navez quun seul pic programmer ou quil vous est impossible de vous procurer
un programmateur officiel. Evitez aussi les clones, sources potentielles dennuis et pas
moins chers. De prfrence, achetez un PicKit3 ou un ICD3 officiel.

A1.9 Jai une erreur de stack

Je reois galement pas mal de courrier de personnes qui me disent : Lorsque


jexcute mon programme en pas--pas dans MPLAB, je reois un moment donn un
message de type : Stack overflow ou Stack underflow .

Que signifie ces messages ?

En fait un message stack overflow peut signifier que vous avez dpass les 8 niveaux
de sous-programme autoriss. En effet, je rappelle quil ny a que 8 emplacements sur la pile

255
(stack), et que donc, une nouvelle tentative dempilement, suite une sous-routine ou une
interruption provoquera lcrasement de la pile.

Dans la plupart des cas, cependant, il sagit dune erreur dans la structure de votre
programme. Le message stack overflow intervient si vous empilez plus de 8
emplacements, le message stack underflow intervient si vous dpilez plus que ce que vous
avez empil (par exemple, return sans call ). Un stack underflow est donc
toujours une erreur de programmation.

Pour rsoudre ces problmes, si vous navez pas dpass les 8 niveaux (voir A1.2),
vrifiez les points suivants :

- Chaque appel via un call doit revenir au programme appelant par un return ou un
retlw

- Chaque return ou retlw rencontr doit avoir t prcd du call correspondant


- La sortie dune sous-routine avec un goto doit mener un point o on trouvera un
return

- Une routine ne doit pas sappeler elle-mme. Lappel dune fonction par elle-mme est
appel rcursivit et est une pratique courante en langage volu sur grosse cible (PC),
mais nutilisez pas cette mthode avec un PIC dont la pile est aussi limite, sauf si vous
tes un programmeur particulirement affut pour arriver grer la rcursivit
simultanment avec la capacit de la pile.

A1.10 Quelles sont les diffrences entre 16F84 et 16F84A ?

Voici une question qui revient rgulirement dans mon courrier. Je vous livre ici les
principales diffrences entre ces composants :

- La frquence maximale disponible passe de 10 20 Mhz.


- La tension maximale admissible pour Vdd est ramene de 6V 5.5V.
- Le reset ncessite une dure dimpulsion de 2s sur Mclr au lieu de 1s.
- Le temps de monte de la tension dalimentation prise en compte pour le dmarrage
change (voir datasheet).
- Le courant typique lors de la programmation flash passe de 7,3 3 mA (concerne les
ralisateurs de programmateurs).
- Le courant typique consomm double entre un 16F84 10Mhz et un 16F84A 20Mhz,
mais cest uniquement la consquence de laugmentation de vitesse ( 10Mhz la
consommation nest pas plus grande que sur un 16F84).
- Plusieurs modifications des caractristiques lectriques (tensions des niveaux, courants)
- Division par 2.5 des temps dcriture et deffacement eeprom
- Division par 2.5 des temps dcriture et deffacement en mmoire flash

En sommes rien qui concerne la programmation, ce sont des diffrences au niveau


lectrique. Sauf si vous alimentiez votre 16F84 en 6V, vous pouvez donc le remplacer par un
16F84A sans rien changer. Ce cours sapplique donc indiffremment un 16F84 et un
16F84A.

256
A1.11 Jai une erreur 173 lors de lassemblage

Au moment de lancer lassemblage, vous obtenez une erreur 173, du genre :

Error[173] Source file path exceeds 62 characters

Ceci signifie que le chemin pour accder votre source excde 62 caractres, ce qui
peut tre le cas si vous utilisez des noms trop longs ou trop de sous-rpertoires. Par exemple :

C:\Mon_repertoire\sources\Sources_MPLAB\Cours\Cours_Part1\Exercices\test1.Asm

Il vous suffit dans ce cas de dplacer votre rpertoire dans un dossier plus proche de la
racine, ou de raccourcir les noms utiliss. Voici un exemple correct :

C:\Cours_PIC_1\Exercices\test1.asm

Ou, mieux, en vitant de placer vos donnes dans votre partition systme :

D:\Cours_PIC_1\Exercices\test1.asm

Ce problme tait frquent avec les versions 5.x de MPLAB mais devrait cependant
disparatre avec les versions plus rcentes car la longueur autorise a augment.

A1.12 Le PIC16F84 est obsolte, pourquoi ne pas utiliser le 16F628 ?

Ah, que de fois on ma pos cette question. Certains anti-pic primaires mont
mme agress sur des forums ce sujet. La rponse est pourtant simple : il ne sagit pas ici de
raliser un montage spcifique prcis, mais au contraire le but est dtudier le fonctionnement
de base des PIC16F.

Or, le 16F84(A) est et reste le PIC le plus simple de la gamme : tous les modules
expliqus dans ce PIC se retrouvent sur lintgralit des autres PIC16F. Dit autrement :
tout ce que vous allez tudier dans ce cours sera utilisable directement sur toute la gamme,
rien nest tudi inutilement.

Le 16F628, lui, est un PIC disposant de fonctionnalits supplmentaires,


fonctionnalits qui sont expliques dans le cours-part2, destin, lui, au 16F87x qui tait un des
PIC16F les plus complets de la gamme au moment dcrire le cours-part2.

Le 16F84 est donc particulirement bien adapt lapprentissage de base des PIC
mid-range, malgr quil est clair que le 16F628 (et dautres maintenant) le dtrne en terme
de rapport performances/prix pour une ralisation pratique relle. Le cahier des charges pos
pour un cours dapprentissage nest pas le mme que celui pos pour une ralisation pratique,
ce qui explique que le 16F84 reste mon matre choix pour ltude des PIC mid-range.

Le 16F87x, utilis dans le cours-part2, est le prtexte, lui, lapprentissage dun trs
grand nombre de fonctionnalits quon peut retrouver en tout ou en partie dans les autres
PIC de la gamme mid-range, et mme dans les PIC High-End 18F abords dans le cours-
part5. Mais, de nouveau, le 16F87x nest quun prtexte dapprentissage, il ne reprsente plus
non plus aujourdhui un matre choix pour une application relle pratique.

257
Achetez donc un 16F84(A) pour ltude de ce cours plutt quun 16F628, sans quoi
vous vous retrouveriez grer des problmes inattendus ce qui vous distrairait de
lapprentissage de base. Je vous assure que vous avez tout y gagner. Le cours est gratuit,
vous pouvez bien faire le sacrifice dacheter un16F84(A), non ?

Ensuite, une fois votre apprentissage termin, cherchez le PIC qui convient le mieux
votre application sur le site de Microchip. Si ce PIC dispose de fonctionnalits avances
dont vous avez besoin, prenez la peine dtudier le cours-part2.

Si le fait que jutilise le 16F84 et le 16F876 dans mes cours vous drange, considrez
plutt que les titres de mes cours sont :

- Part 1 : Les fonctions de base


- Part 2 : Les fonctions avances facultatives

A1.13 Jutilise une version de MPLAB plus rcente

Encore une question qui revient souvent. Des utilisateurs pensent judicieux dutiliser
ce cours avec une version rcente de MPLAB (par exemple 8.x) et se retrouvent coincs
dans des oprations pourtant basiques.

Jai dj rcris le cours initialement rdig partir de MPLAB 5.x pour le passer
sous MPLAB 6.6. Malheureusement les versions voluent trop vite et il mest videmment
impossible de rcrire sans arrt le cours en fonction des volutions.

Mon conseil est donc le suivant, afin de ne pas cumuler les problmes : Pour tudier ce
cours, installez MPLAB 6.6 uniquement, ce qui vous permettra de suivre au mieux. Ensuite,
une fois votre apprentissage ralis, il sera toujours temps pour vous de passer une version
plus rcente, sachant que la migration devrait se faire sans trop de problme une fois les
notions de base assimiles. Une fois de plus, vitez de cumuler les obstacles, faites au plus
simple.

Pour tlcharger une ancienne version de MPLAB :

- Rendez-vous sur le site de Microchip : www.microchip.com

- Dans la zone search du site, tapez MPLAB IDE Archives

- Vous devriez arriver rapidement sur une page o se trouvent toutes les versions archives
de MPLAB, prenez celle correspondant au cours choisi.

A1.14 Mon pic vierge noscille pas

Jajoute cette annexe parce quun internaute ma signal avoir essay son PIC neuf
sans y mettre de programme, ceci afin de vrifier quil avait bien tout compris niveau
lectronique.

258
Or, cet internaute sest cass la tte en essayant de comprendre pourquoi il navait
aucune trace doscillation sur le quartz de son PIC.

Voyons donc ce qui sest pass :

Un pic contient ses informations de configuration (oscillateur, watchdog etc) dans sa


mmoire flash. Du fait de la technologie, effacer ce type de mmoire revient placer tous les
bits de chaque case mmoire 1.

Un coup dil sur la figure 8.1 du datasheet montre que la slection du mode
doscillateur seffectue via 2 bits : FOSC1 et FOSC2. Donc, dans un pic neuf, ces deux bits
sont placs 1.

Un coup dil sur lexplication de ces bits montre que dans ce cas cest le mode RC
qui est slectionn.

Conclusion : un pic vierge est configur par dfaut pour fonctionner en


oscillateur RC, le quartz ne peut donc pas osciller.

Retenez, du reste, que, par prcaution, vous ne devez jamais alimenter un pic vierge
sur votre platine : commencez toujours par le programmer, et seulement ensuite alimentez-le
sur votre platine.

259
Notes :

260
Contribution sur base volontaire
La ralisation de ces cours ma demand beaucoup de temps et dinvestissements
(documentations, matriel, abonnements, etc.).

Aussi, pour me permettre de poursuivre, je vous demande, si cela est dans vos possibilits,
et si vous apprciez ce que je fais, de contribuer un peu, chacun selon ses possibilits et ses
dsirs.

J'ai donc besoin de votre aide pour continuer l'aventure. En effet, je ne dispose plus
vraiment de la capacit de consacrer l'intgralit de mon temps libre crire des cours et des
programmes sans recevoir un petit "coup de pouce".

Cependant, je ne voulais pas tomber dans le travers en verrouillant l'accs aux fichiers, et
en imposant un payement pour les obtenir. En effet, je tiens ce qu'ils restent disponibles
pour tous.

J'ai donc dcid d'instaurer un systme de contribution sur base volontaire en permettant
celui qui le dsire, et en fonction de ses propres critres, de m'aider financirement. Le but
n'tant pas de me faire riche, mais plutt de m'aider "joindre les 2 bouts".

Il ne s'agit donc pas d'un payement, ni d'une obligation. Il s'agit simplement d'une
assistance sans promesse d'aucun sorte, et sans contrainte. Je continuerai rpondre au
courrier de tout le monde, sans distinction, et sans interrogation ce sujet.

Une bonne mthode consiste donc, pour celui qui le dsire, tlcharger le document
choisi, le lire ou l'utiliser, puis dcider si cela vaut ou non la peine de m'aider sur base de
l'usage que vous en faites.

Si oui, vous vous rendez sur mon site : www.abcelectronique.com/bigonoff ou


www.bigonoff.org, et vous suivez la page cours-part1 . Vous y trouverez, dans la page
contributions , la procdure suivre. Pensez que ces contributions me sont trs utiles, et
contribuent me permettre de continuer travailler pour vous.

Noubliez pas de mettre votre email en caractre dimprimerie, pour que je puisse vous
rpondre.

Je rponds toujours au courrier reu. Aussi, si vous nobtenez pas de rponse, nhsitez
surtout pas me contacter pour vrifier sil ny a pas eu un problme. Notez que si je ne
rponds pas un de vos mails, ce nest pas parce que je suis grossier, cest simplement parce
que je nai pas pu rpondre (votre messagerie est pleine, votre adresse nest plus valide, je
nai pas reu votre message, votre message a t class automatiquement comme spam par
ma messagerie, etc).

Merci davance tous ceux qui mont aid ou maideront poursuivre ce travail de longue
haleine.

261
Utilisation du prsent document

Le prsent ouvrage est destin faciliter la comprhension de la programmation des


PIC en gnral, et du 16F84 en particulier. Les suites de cette ouvrage sont disponibles sur
mon site, en tlchargement gratuit.

Communiquez-moi (avec politesse) toute erreur constate afin que la mise jour puisse
tre effectue dans lintrt de tous.

Pour de raisons de facilit de maintenance et de mises jour, jai dcid (et cest ma
seule exigence) que ce cours ne pouvait tre propos en tlchargement que sur mon
site :www.bigonoff.org . Si vous trouvez mon cours ailleurs, envoyez un mail au webmaster
du site en question pour lui demander de respecter la seule et unique rgle du jeu.

Bien entendu, jautorise (et jencourage) les webmasters placer un lien vers mon site,
inutile den faire la demande. Bien entendu, je ferai de mme en retour si la requte men est
faite. Ainsi, jespre toucher le maximum dutilisateurs.

Le prsent ouvrage peut tre utilis par tous, et copi et/ou imprim dans son intgralit,
condition de ne rien modifier. Il peut cependant tre utilis comme support de cours en tout
ou en partie, condition de prciser la rfrence originale et le lien vers mon site. Jautorise
explicitement les coles et autres organisations ducatives imprimer mon cours en nombre
lev dexemplaires dans le but de rendre service aux tudiants. Dans ce cas, je demande que
lachat du cours ne soit pas obligatoire et quon prcise aux tudiants quils ont la possibilit
de tlcharger gratuitement le cours sur mon site. Vous pouvez me signaler tout abus ce
sujet.

Tous les droits sur le contenu de ce cours, et sur les programmes qui laccompagnent
demeurent proprit intellectuelle de lauteur, et ce, mme si une notification contraire tend
dmontrer le contraire (charte de lhbergeur par exemple).

Lauteur ne pourra tre tenu pour responsable daucune consquence directe ou indirecte
rsultant de la lecture et/ou de lapplication du cours ou des programmes.

Toute utilisation commerciale est interdite sans le consentement crit de lauteur. Tout
extrait ou citation dans un but dexemple doit tre accompagn de la rfrence de louvrage.

Jespre navoir enfreint aucun droit dauteur en ralisant cet ouvrage et je nai utilis
que les programmes mis gracieusement la disposition du public par la socit Microchip.
Les datasheets sont galement disponibles en tlchargement gratuit sur le site de cette
socit, savoir : http://www.Microchip.com

Si vous avez aim cet ouvrage, si vous lutilisez, ou si vous avez des critiques, merci
de menvoyer un petit mail. Ceci me permettra de savoir si je dois ou non continuer cette
aventure avec les parties suivantes.

Sachez que je rponds toujours au courrier reu, mais notez que :

262
- Je ne ralise pas les programmes de fin dtude pour les tudiants (mme en payant), cest
une demande qui revient toutes les semaines dans mon courrier. Tout dabord je nai pas
le temps, et ensuite je ne pense pas que ce soit un bon service. Enfin, pour faire un peu
dhumour, si je donnais mes tarifs, ces tudiants risqueraient un infarctus.

- Je nai malheureusement pas le temps de dbuguer des programmes complets. Inutile donc
de menvoyer vos programmes avec un message du style Ca ne fonctionne pas, vous
pouvez me dire pourquoi ? . En effet, je passe beaucoup de temps rpondre au courrier,
si, en plus, je devais dbuguer, jy passerais la journe. Vous comprenez bien que cest
impossible, pensez que vous ntes pas seul poser des questions. Posez plutt une
question prcise sur la partie qui vous semble inexacte.

- Si vous avez des applications personnelles, nhsitez pas les faire partager par tous. Pour
ce faire, vous pouvez me les envoyer par mail.

- Avec cette version, jessaye de rpondre aux demandes lgitimes des personnes qui
travaillent sur diffrentes plates-formes (Mac, Linux, Windows, etc.). Si, cependant, la
version fournie est inexploitable sur votre machine, merci de me le faire savoir. Notez
cependant que ce cours utilise MPLAB pour les exercices, il faudra donc ventuellement
adapter ces exercices en fonction du logiciel quil vous sera possible dutiliser. Notez que
Microchip fournit maintenant une version de MPLAB baptise MPLAB-X, et qui
tourne sur toutes les plateformes courantes. Nhsitez pas le tlcharger.

Merci au webmaster de www.abcelectronique.com, pour son hbergement gratuit.


Merci Byte, pour sa proposition dhbergement gratuit.
Merci Grosvince pour sa proposition dhbergement gratuit.
Merci Bruno pour avoir assur quelques temps le paiement de mon nom de domaine
Merci Thierry pour mavoir offert mon nom de domaine et den assurer le paiement
Merci tous ceux qui mont report les correctifs effectuer
Merci tous ceux qui mont envoy des contributions partager.
Merci mon pouse et mes enfants pour leur patience.
Merci tous ceux qui mont envoy des mails dencouragement, a motive.

Dernire remarque : il est impossible que vous trouviez trace dun plagiat ici, tout
comme dans les prcdents cours, tant donn que je nai lu aucun ouvrage sur le sujet, autre
que les datasheets de Microchip. Tout est donc issu de mes propres expriences. Si vous
trouvez trace dun plagiat (jen ai vu), sachez que ce sont les autres qui ont copi, et ceci vaut
galement pour les ouvrages dits de faon classique (cette remarque nest pas innocente).

Edition termine le 09/02/2001, reprise des leons spares en un ouvrage complet

- Mise jour rvision 2 le 15/06/2001 : correction de quelques erreurs

- Mise jour rvision 3 le 24/07/2001 : correction dtaille avec les Fribottes

- Mise jour rvision 4 le 26/10/2001 : quelques petites erreurs retrouves

- Mise jour rvision 5 le 27/02/2002 : encore quelques erreurs tenaces

263
- Mise jour rvision 6 le 20/04/2002 : quelques corrections, amliorations de points
suscitant des questions frquentes, passage en format pdf sous compression rar pour
permettre lutilisation sur toutes les machines, masculinisation du terme PIC

- Mise jour rvision 7 le 22/09/2002 : quelques corrections syntaxiques et orthographiques


mineures et quelques ajouts. Ajout de linterdiction de distribuer ailleurs que sur mon site.

- Mise jour rvision 8 le 25/10/2002 : Petite correction chapitre 2.4. Lnonc cit en
exemple ne correspond pas celui effectivement dvelopp. Correction du lien vers le site
Microchip en page 27. Modification de la dfinition de CISC et RISC page 17.

- Mise jour rvision 9 le 01/11/2002 : Fautes dorthographe pages 82, 83, 85, 86, 87, 89,
90, 94.

- Mise jour rvision 10 le 04/12/2002 : suppression dune ligne qui prte confusion page
183, quelques correctifs mineurs pages 99, 100, 104,108, 122, 124, 128, 129, 131,132,
134, modification de contribution page 209.

- Mise jour rvision 11 le 19/04/2003 : modification des registres modifis pour


linstruction sleep page 74, ajout du programmateur dans la liste des composants
ncessaires, modif dans le define page 123, correctif mineur page 70.

- Mise jour rvision 12 le 16/06/2003 : Corrections mineures page 108, 198

- Mise jour rvision 13 le 19/09/2003 : Grosses modifications pour le passage de


MPLAB 5.50 MLPAB IDE 6.30. Numrotation change, nombreuses modifications
sur des chapitres entiers. Rimpression complte ncessaire, fichiers exemples
reconstruits.

- Mise jour rvision 14 le 11/12/2003 : Modification du schma page 134, correctifs pages
201,190,191 (modification de radix suite au passage de MPLAB 5 MPLAB 6).

- Mise jour rvision 15 le 13/02/2004 : Correction dune erreur rptitive sur les exemples
et le cours, au niveau de linitialisation de EEADR (changement de banque une ligne trop
tt), pages 96,99,123,142 et fichiers dexemples et de maquette.

- Mise jour rvision 16 le 09/03/2004 : correction page 58,59

- Mise jour rvision 17 le 09/06/2004 : corrections page 34, 198,annexes, ajout dune
astuce de programmation, table des matires, modification de mon adresse courrier.

- Mise jour rvision 18 le 02/08/2004 : Ajout du temps de rveil page 171, remarque page
113

- Mise jour rvision 19 le 27/03/06 : correctifs pages 11, 12, 13, 15, 17, 19, 21, 24, 26, 27,
29, 30, 33, 37, 38, 40, 47, 50, 52, 54, 63, 72, 80, 83, 85, 93, 96, 114, 131, 133, 135, 171,
197, 198, 220, remises en page des portions de codes suite une modification accidentelle
des tabulations, mise jour page 20, remarque pages 24 et 58. Ajout dune annexe.

264
- Mise jour rvision 20 le 03/04/06 : Ajout dun petit chapitre sur la consommation
minimale en mode sleep

- Mise jour rvision 21 le 13/10/06 : correctifs mineurs (surlignages, parenthses,


orthographe) pages 19, 25, 39, 40, 41, 47, 51, 52, 53, 54, 57, 61, 67, 68, 69, 71, 72, 76,
80, 81, 86, 98, 118, 120, 128, 152, 178, passage des nombres H00xx sur 8 bits. Ajout
dune remarque page 44. Rvision 21b, remise en place du schma de loptocoupleur qui
avait disparu.

- Mise jour rvision 22 le 24/01/07 : Modifications importantes dans tout ce qui traite du
timer0 suite loubli de prendre en compte les 2 cycles perdus lors de toute modification
de TMR0. Modifications et adaptations pages 29, 44, 52, 95 y compris les fichiers asm
concerns. Divers correctifs mineurs (tabulations, espaces, ponctuations, orthographe...),
petite modification page 54 concernant le simulateur (lexplication tait reste sur la
version 5). Modification page 21 au niveau de lexplication de la mention -xx que
javais oubli dadapter aux diverses expriences effectues ce sujet.

- Mise jour rvision 23 le 04/11/07 : Ajout dune liste de considrations sur le watchdog,
au chapitre 15.3. Correctifs orthographiques ou tournures de phrases pages 16, 23, 34, 37,
44, 61, 64, 79, 83, 86, 89, 91, 96, 108, 111, 112, 113, 114, 120, 124, 128, 138.
Modification dun chemin page 38. Prcisions sur le terme positionn pages 27, 43,
50, 54, 60, 110. Correctif nde bit page 12. Dcalage de certains numros de pages. A la
demande amicale de Microchip, ajout du symbole pour tout terme dpos par
Microchip.

- Mise jour rvision 24 le 08/02/08 : Modification mineure page 47. Remplacement de


systme de numrotation par numration. Refonte totale des chapitres 12.7.2 12.7.4
(ajouts) impliquant la renumrotation de toutes les pages suivantes.

- Mise jour 25 le 07/09/08 : Correctif important page 140.

- Mise jour 26 le 08/02/09 : Correctifs mineurs page 50 et 63. Ajout du reset explicite du
flag dinterruption de linterruption eeprom.

- Mise jour 27 le 15/02/09 : prcisions concernant le temps de latence des interruptions


page 109.

- Mise jour rvision 28 le 24/02/09 : Ajout dun paragraphe sur les units, adoption
dfinitive des Kibi plutt quune simple remarque.

- Mise jour rvision 29 le 05/10/10 : Correctifs pages 18, 19, 22, 41, 49, 56. Ajout
dexplications page 44 sur la fin des programmes (directive END). Modification totale de
lannexe A1.8 (choix du programmateur).

- Mise jour rvision 30 le 13/10/10 : Suite labandon des versions 2 des PicKit et
ICD, modification du conseil annexe A1.8

- Mise jour rvision 31 le 28/11/10 : remarque modifie page 148. Ajout dun chapitre
concernant lutilisation de routines dans un fichier spar.

265
- Mise jour rvision 32 le 13/03/11 : correction lien page 9, correctifs mineurs chapitre 20,
ajout dannexes.

- Mise jour 33 le 26/11/11 : Ajout de remarque page 129. Correctifs pages 41, 64, 93, 96,
100, 113, 132, 144, 153, 169,182, 202.

- Mise jour 34 le 05/01/13 : Rvision majeure : Lifting complet du cours : Suppression de


tous les surlignages (facilit dimpression), correctifs, ajout dexplications, modification
de paragraphes, modification de certains fichiers fournis, etc.

Sur mon site, vous trouverez galement des livres de reports dinformation, qui vous
permettront de vous exprimer sur ce cours, et sur les autres fichiers proposs en
tlchargement. Posez de prfrence vos questions et envoyez vos correctifs par email.

Ralisation : Bigonoff

Site : http://www.abcelectronique.com/bigonoff (merci lhbergeur)


Domaine : www.bigonoff.org
Email : bigocours@hotmail.com

266

Vous aimerez peut-être aussi