Cours intensif sur l'assembleur PIC12F675
Cours intensif sur l'assembleur PIC12F675
cours intensif
d’assembleur
(1)
le premier programme
L’assembleur est un langage de pro- déroulement d’une routine en assembleur. Le logiciel utilisé est mis à disposition
grammation très proche du matériel, L’assembleur est aussi le meilleur moyen gratuitement. Sous Windows, nous pou-
ce qui présente des avantages et des de découvrir le matériel dans le détail. Les vons utiliser un éditeur de texte (Note-
inconvénients. langages de haut niveau cachent (plus ou pad) pour saisir le code source, pour l’as-
Avec un langage de programmation de moins) aux yeux du programmeur ce qui sembler ensuite, c.-à-d. le traduire en
haut niveau, c’est du compilateur que se passe dans les registres & Co. langage machine, à l’aide du programme
dépend l’efficacité de la compilation du Cependant, en assembleur, tout est vrai- MPASM.exe (inclus dans la Suite MPASM
code source. En assembleur, pour obte- ment à faire soi-même – la simple mul- de Microchip). La Suite MPASM fait par-
nir un résultat optimal, il faut s’occuper tiplication de deux petits nombres peut tie de l’IDE (Integrated Development
soi-même tant de la taille du code que requérir une certaine réflexion. Environment) MPLAB. On pourra télé-
de la vitesse d’exécution. La conversion charger l’IDE MPLAB gratuitement chez
de l’assembleur en langage machine (ou Matériel et logiciel Microchip [2].
code hexadécimal) est en effet parfaite- Comme je travaille depuis longtemps Finalement, le logiciel du PICkit2 assure le
ment définie. avec les µC PIC de Microchip, j’ai opté « transport » vers le µC du fichier hexa-
La longueur du programme est un aspect ici pour l’un des plus petits d’entre eux, décimal résultant de l’assemblage. Voilà,
très important en cas d’utilisation d’un le PIC12F675 [1]. Ce µC d’un euro ou c’est tout.
petit µC (un PIC10F200 par ex. n’a que moins fait parfaitement l’affaire pour de
256 mots de mémoire de programme). nombreuses applications simples. Les registres
La performance peut jouer un rôle impor- Pour les expériences proposées, j’ai utilisé Commençons par découvrir notre µC et
tant dans les calculs complexes là où un un programmateur PICkit2 et une petite apprendre quelques instructions d’as-
compilateur C est capable parfois de pro- carte d’expérimentation (l’ensemble est sembleur. Pas de panique – le premier
duire des inepties. Dans de tels cas, il est souvent vendu sous le nom de PICkit2 paquet de théorie n’est pas très compli-
alors logique de programmer directement Starter Kit). Dans la prochaine partie qué ; ensuite nous pourrons démarrer
en assembleur les parties de programme du cours, nous verrons comment réali- dans la foulée.
critiques. Autre avantage : pour les opé- ser soi-même une carte d’expérimenta- Le PIC12F675 est un µC à 8 bits de la
rations à la chronologie critique, on peut tion simple. Rien n’interdit bien entendu famille midrange (milieu de gamme)
calculer exactement le nombre de cycles d’utiliser pour ce cours le programmateur de Microchip. Ce µC est proposé entre
d’horloge (c.-à-d. la durée) nécessaire au PICkit3 plus récent. autres en boîtier PDIP-8 (Plastic Dual
Inline Package). Six des huit pattes sont endroit, est le bit n° 5 (RP0), le Regis- Premières instructions
des broches de port numérique d’usage ter Bank Select Bit. Il est utilisé pour Il est temps maintenant de découvrir
général (GP0 à GP5). GP3 ne peut être la sélection entre les deux banques de quelques instructions d’assembleur (les
utilisée qu’en entrée, les cinq autres bro- mémoire ; le bit doit être mis à 1 (levé) instructions de base en quelque sorte).
ches peuvent l’être soit en entrée, soit en ou à 0 (effacé) avant que l’on ne puisse Le PIC12F675 fait partie des µC RISC
sortie. Le PIC dispose de 1 024 mots de donner une adresse comme paramètre à (Reduced Instruction Set = à jeu d’ins-
mémoire de programme flash, ainsi que une instruction subséquente. Nous avons tructions réduit) – il n’y a que 35 instruc-
de 64 octets de SRAM utilisables libre- accès aux emplacements de mémoire 80h tions à apprendre.
ment et de 128 octets d’EEPROM. à FFh lorsque le bit est levé ; si RP0 = 0,
nous avons accès aux emplacements de
Lorsque l’on programme en assembleur, il mémoire 00h à 7Fh.
faut travailler avec des registres ; ce sont, L’écriture du registre Config se fait lors du
ici, des unités de mémoire de 1 octet qui flashage du µC (cf. ci-dessous). Il définit
ont une fonction logique spécifique. Cer- par ex. l’utilisation (ou non) de l’oscilla-
tains registres font partie du noyau ; ils teur interne du µC.
peuvent, par ex. lors de calculs, stocker
des valeurs de 8 bits ou donner des infor- Pour le moment, laissons de côté le
mations quant à l’état du µC. D’autres registre des options. Maintenant nous
registres sont responsables des blocs allons nous intéresser brièvement à trois
périphériques du µC, le registre GPIO autres registres qui, à la différence de
qui donne l’état des entrées/sorties par ceux qui ont précédé, s’occupent des
exemple. périphériques.
clrf f goto k
où f est une valeur entre 00h et 7Fh qui où k est une adresse de la mémoire de
représente l’adresse-cible. programme. En fait, k peut prendre une
valeur entre 000h et 7FFh, mais comme
Un exemple : notre µC ne possède que 1 024 mots
de mémoire de programme, les valeurs
clrf H’20’ au-delà de 3FFh sont hors des limites.
On pourra, au lieu de k, également spéci-
Figure 5. CALL sert à appeler un sous- se traduit par l’écriture de la valeur 00h fier une étiquette (label), c’est-à-dire un
programme.
Code source
À quoi doit ressembler le programme
IC1 1 en assembleur ? Que faut-il faire au
BT2 VCC
minimum pour écrire un programme
4 7
AA GP3/MCLR GP0/AN0 exécutable ?
1V2 6
GP1/AN1 Comme nous le disions plus haut, nous
5
GP2/AN2
2 3 LED1 pouvons utiliser pour notre exemple un
BT1 GP5/CLKIN GP4/AN3
simple éditeur de texte tel que Notepad,
GND
AA y saisir le code et enregistrer le fichier.
1V2 8 PIC12F675P
L’extension doit toujours être .asm (il fau-
dra peut-être, après enregistrement, la
modifier manuellement). Nous utiliserons
Figure 6. Difficile de faire plus simple pour Figure 7. Le circuit peut être réalisé sur une comme nom de fichier : 01_LED_v_1p03.
obtenir le clignotement d‘une LED. plaque d‘essais. asm. Vous pouvez télécharger un fichier
tout fait sur la page de projet de cet
article [3].
tion des données ou de la mémoire de faut pour créer une application simple.
programme, la désactivation de la fonc- Allons-y. La figure 8 reprend le début du code.
tion de chien de garde (watchdog), etc. Notre tâche est (relativement) facile. Pour augmenter la lisibilité du programme
Nous retrouvons, comme d’habitude, la Nous allons, pour commencer, connec- et le rendre plus facile à comprendre par
description de chacun de ces bits dans ter une LED à la broche GP0 et la faire d’autres utilisateurs, nous l’avons doté de
la feuille de caractéristiques, souvent au clignoter. nombreux commentaires. Nous voulons
chapitre « Special Features of the CPU / En termes de matériel, la solution est de plus travailler avec des constantes.
Configuration Bits » (les fiches en fran- d’une mise en œuvre ultrasimple. Nous Des définitions telles que
çais sont rarissimes). utiliserons l’oscillateur d’horloge interne
(4 MHz) et n’aurons pas besoin de quartz STATUS EQU H’03’
Commentaire externe. La LED sera connectée directe-
Un commentaire commence toujours par ment à GP0 (même sans résistance) – le rendront le code plus portable si nous
un point-virgule (;). Tout ce qui suit le µC limite lui-même le courant de sortie voulons plus tard nous essayer à un PIC
point-virgule (jusqu’à la fin de ligne - End à environ 20 mA (alimentation de 5 V) un peu plus grand.
of Line) est ignoré par le compilateur et par le biais de la résistance interne du Heureusement il est inutile de réécrire à
considéré comme commentaire. port (fig. 6). chaque fois ces définitions de constantes
Si la ligne commence par un point-vir- Le circuit peut être réalisé sur une plaque dans notre code. On retrouve, dans le
gule, toute la ligne est traitée comme un d’essais (fig. 7). La source d’alimenta- fichier P12F675.INC, qui fait partie de la
commentaire. tion pourra par ex. être constituée de Suite MPASM, toutes les définitions essen-
deux piles de 1,2 V ; mais aussi n’importe tielles (adresses de registres, positions de
Application « Hello World » quelle autre source qui peut fournir au bits, etc.) pour notre type de µC.
Nous savons maintenant tout ce qu’il moins 20 mA sous 2 à 5 V. Nous incluons ce fichier tout au début
Figure 8. Les commentaires sont importants, même en assembleur. Figure 9. Définitions des registres dans le fichier
Include.
Liens
[1] www.microchip.com/wwwproducts/Devices.aspx?product=PIC12F675
[2] www.microchip.com/pagehandler/en-us/family/mplabx
[3] www.elektor-magazine.fr/130483
de notre code par une directive INCLUDE. Le petit sous-programme delay_r intro-
Cela fonctionne exactement comme avec duit une temporisation. Vous voyez peut-
tous les autres langages de programma- être immédiatement comment cela fonc-
tion « classiques » ; le résultat est le tionne ? Note : on se trouve en présence Figure 11. Capture d‘écran de l‘assembleur
même que si nous avions tout simplement de deux boucles imbriquées. MPASM qui convertit le code en fichier Hex.
copié, par un copier-coller, le code du Tout à la fin du fichier on doit impérati-
fichier à inclure dans notre programme. vement trouver la directive END.
La figure 9 nous montre le contenu
du fichier comportant les définitions de Assembler
constantes typiques au µC. Une fois le programme saisi, nous pou-
vons assembler le code. Pour cela, nous
La figure 8 nous apprend que nous avons appelons le programme MPASM.EXE (par-
en outre défini deux variables de type tie de l’IDE MPLAB).
octet (c.-à-d. des emplacements de Après le démarrage du programme
mémoire en SRAM), à savoir TIMER1 et (fig. 11), nous sélectionnons notre fichier
TIMER2. Nous les utiliserons dans notre texte (dans le champ Source File Name).
boucle de temporisation. Dans le champ Processor, il faut sélec-
tionner le type de notre µC. Le reste peut
La figure 10 montre le reste du pro- être laissé avec les valeurs par défaut.
gramme. Nous n’y utilisons que des Presser sur le bouton Assemble déclenche
instructions dont il a été question plus la compilation du fichier ASM.
haut. L’illustration montre les différents Ce processus produit alors un fichier hex
registres avec tous leurs bits. Un point (et quelques autres fichiers que nous pou-
d’interrogation noir à la place du bit signi- vons ignorer pour l’instant).
fie que sa valeur est sans importance ici.
Dans la boucle Main on voit un petit rond Le PICkit2 est accompagné du pro- Figure 12. Le logiciel de programmation du
rouge ; il signale le moment d’allumage gramme PICkit2V2.exe. Avant le lan- PICkit nous permet de flasher le programme
de la LED. Le rond gris identifie l’instruc- cement du programme, le kit doit être dans le µC.
tion qui éteint la LED. Les flèches repré- connecté à l’ordinateur via USB et le µC
sentent les sauts. doit se trouver dans le support de pro-
grammation de la carte d’expérimenta-
tion. Lors du démarrage de PICkit2V2.
exe, il y a détection automatique du µC
(cf. fig. 12).
Ensuite, le point du menu File – Import
Hex permet de charger le fichier hex et
enfin le bouton Write de le flasher dans
le µC.
IC1 1 K1
VCC 1
VPP/MCLR
LED1 7 2
GP0/AN0 VCC
6 3
VREF/GP1/AN1 GND
5 4
GP2/AN2 ICSPDAT/PGD
R1 4 5
GP3/MCLR ICSPCLK/PGC
3 6
270R
GP4/AN3 AUX
2
GP5/CLKIN
GND
8
PIC12F675P
Figure 1. Schéma de la carte d‘adaptation, une carte de développement en Figure 2. Carte d’adaptation terminée, connectée au programmateur
version minimale. PICkit2.
interne de 4 MHz. La fréquence d’horloge est moins pré- La mémoire de données regroupe tous les registres spécifiques
cise qu’avec un pilotage par quartz, mais, avec sa tolé- au processeur et à l’application. Hormis les registres du pro-
rance de ±1%, elle suffit à de nombreuses applications. cesseur préparamétrés, le contenu de la mémoire de données
Son gros avantage : permettre de se passer de composants est indéfini à la mise sous alimentation. Elle perd son contenu
additionnels, GP4 et GP5 restent disponibles comme E/S à la disparition de l’alimentation – il s’agit de SRAM volatile.
d’usage général. Contrairement à la mémoire de programme, la mémoire de
données est, classiquement, organisée en octets (8 bits cha-
Le bit 5 (MCLRE) du registre de configuration commande la cun). La fiche de caractéristiques [1] (p. 9 sqq) donne une des-
fonction de la broche 4. Si MCLRE = 1, la broche 4 sert de cription détaillée de la cartographie de la mémoire. À retenir :
Master Clear – c.-à-d. de broche de réinitialisation (reset). Si les 64 octets de mémoire de l’application se trouvent dans la
MCLRE = 0, la broche 4 peut être utilisée comme entrée, avec plage d’adresses entre 20h et 5Fh.
en corolaire la perte de la fonction de réinitialisation. Par logiciel, on pourra, stocker dans l’EEPROM, mémoire non
volatile organisée en octets elle aussi, des valeurs qui « sur-
Registre d’état (Status) vivent » à une réinitialisation ou à un redémarrage. Cependant,
Le registre d’état contient des informations relatives à des opé- il faut éviter les écritures trop fréquentes.
rations arithmétiques terminées. La figure 3 donne la signi-
fication des différents bits du registre. Autres instructions
Les deux MSB (Most Significant Bit = bit de poids fort) IRP et Passons aux instructions dont, outre celles déjà évoquées dans
RP1 sont réservés et doivent toujours être à 0 en écriture. Ils la 1ère partie de cours, nous aurons besoin pour notre pro-
ne sont pas utilisés avec le PIC12F675. jet de « démo ». À noter que la fiche de caractéristiques de
Le bit 5, RP0, est le Register Bank Select Bit. Il sert (cf. 1ère tout µC de Microchip donne une liste exhaustive de toutes les
partie du cours) à la sélection de la banque de mémoire. S’il est instructions [1].
à 0, toutes les instructions qui suivent accèdent aux emplace- Notre description commence par un complément d’informa-
ments de mémoire 00h à 7Fh – sinon, s’il est à 1, aux empla- tions sur une instruction déjà utilisée dans la première partie.
cements 80h à FFh.
Les deux bits TO et PD révèlent l’origine de la dernière réini- DECFSZ
tialisation (cf. fiche de caractéristiques [1]). Dans la 1ère partie, nous avons parlé de la fonction de l’ins-
Le bit 2 Z (= Zero) est activé si le résultat de la dernière opé- truction DECFSZ (= DECrement F and Skip if Zero) pour les
ration est égal à zéro – il n’est pas impératif qu’il ait s’agit boucles. En dehors des boucles, cette instruction permet aussi
d’une opération arithmétique. de procéder à des branchements généraux lors de l’exécution
Les deux LSB indiquent les débordements suite à une addition du programme (une boucle n’est qu’un type de branchement
ou une soustraction (états Carry). spécifique). La figure 4 montre l’ordinogramme.
Supposons qu’il y a, à l’emplacement de mémoire 20h, une
Registre des options (Option) variable X. Un branchement complet requiert trois instructions
Le registre des options permet d’activer d’autres paramètres. (cf. fig. 5). En utilisant l’argument « 0 » avec DECFSZ, le résultat
Notre application de « démo » (cf. plus loin) donne un exemple : de la soustraction (valeur dans « X » moins 1) est écrit dans
l’effacement du bit 7 active la fonction de polarisation haute le registre W. Si le résultat est 00h, on saute l’instruction sui-
(pull-up) des entrées. vante et la troisième instruction goto branche_B est exécutée.
Cartographie de la mémoire
Pour programmer en assembleur, il faut connaître la cartogra-
phie de la mémoire du microcontrôleur utilisé. Généralement
(et donc ici), la mémoire est divisée en trois zones :
• La mémoire de programme (Flash)
• La mémoire de données (SRAM)
• L’EEPROM
La mémoire de programme est utilisée, en règle générale – et
même exclusivement avec le PIC12F675 – pour y stocker le
logiciel. La largeur d’un mot y est de 14 bits. Si cette informa-
tion n’a pas grande importance en programmation, elle nous
apprend que la mémoire de programme d’un PIC12F1675 ne
comporte pas 1024 octets (de 8 bits chacun), mais 1024 mots Figure 4. Ordinogramme d‘un branchement conditionnel.
(de 14 bits chacun).
Figure 5. Exemple de code d‘un branchement conditionnel. Figure 6. Exemple de boucle avec les instructions BTFSS / BTFSC.
Cela n’a lieu que si la valeur de X est, avant décrémentation, est un nombre entre 00h et 07h ; il définit le bit à tester. Ces
de 01h. Dans tous les autres cas, on se retrouve à branche_A. instructions ne modifient ni le contenu du registre W, ni celui
de l’emplacement de mémoire.
INCFSZ Dans l’exemple de la figure 6, l’emplacement de mémoire
Vous savez tout de l’instruction DECFSZ. INCFSZ est identique à 20h a la valeur 98h (= 10011000b). À gauche l’instruction
ceci près qu’il faut lire incrémentation au lieu de décrémentation. BTFSS vérifie si la valeur du bit 00h est de 1. Si oui, on saute
l’instruction suivante goto branche_A. Cependant, comme la
BTFSS et BTFSC valeur du bit 0 est 0, ce saut n’a pas lieu et l’instruction goto
Pour les deux instructions BTFSS (= Bit Test F and Skip if Set) branche_A est alors exécutée.
et BTFSC (= Bit Test F and Skip if Clear), il s’agit aussi de bran- À droite on voit l’effet de l’instruction BTFSC. Ici on effectue un
chements. Elles permettent de vérifier l’état des différents bits saut si le bit 00h a la valeur 0 – ce qui est le cas pour la valeur
d’un emplacement de mémoire et d’effectuer le branchement de l’emplacement de mémoire 20h. On saute donc l’instruction
correspondant. goto branche_A et le programme poursuit avec l’instruction
La syntaxe est : goto branche_B.
Figure 7. Exemple de code ADDWF : résultat dans le registre W. Figure 8. Exemple de code ADDWF : résultat en SRAM.
Figure 9. Addition d‘une constante au (contenu du) registre W. Figure 10. Prototype du dé électronique.
entre 00h et 7Fh. L’argument d peut être à 0 ou 1 ; il défi- clrw
nit l’endroit de stockage du résultat. Si d = 0, le résultat est
stocké dans le registre W et l’emplacement de mémoire reste INCF et DECF
inchangé. Si d = 1, le contenu de l’emplacement est remplacé Ces instructions nous permettent d’incrémenter (INCF ; +1)
par le résultat. ou de décrémenter (DECF ; -1). La syntaxe est :
Dans l’exemple ci-après, nous allons calculer la somme de
3 + 16 (en décimal). On stocke tout d’abord 3 dans l’empla- incf f,d
cement de mémoire 20h ; on écrit ensuite 16 (10h) dans le
registre W et on effectue ensuite l’addition. Le résultat est écrit ou
soit dans le registre W (fig. 7), soit en 20h (fig. 8).
decf f,d
ANDWF
Pour ce qui est de ses syntaxe et utilisation, cette instruction Les arguments f et d ont la même signification que dans le cas
est identique à ADDWF. C’est la fonction qui diffère : ANDWF effec- de l’instruction ADDWF. En fonction de d, le résultat est écrit
tue l’opération logique ET (AND), bit par bit. dans le registre W ou à l’emplacement de mémoire d’origine.
ADDLW Dé électronique
À l’image de l’instruction ADDWF, ADDLW effectue elle aussi une La réalisation d’un dé électronique n’est pas bien plus com-
addition. ADDWF ajoute quant à elle une valeur de mémoire au pliquée que l’incontournable clignotement de LED. Comme le
registre W tandis qu’ADDLW ajoute une constante au registre W. circuit est, pour le simplifier au maximum, alimenté par un
La syntaxe est : port USB d’un PC, la figure 10 comporte un port USB. Sinon,
le dé n’a rien à faire avec l’interface USB, on pourrait tout
addlw k autant l’alimenter avec un adaptateur secteur, ou trois piles
(rechargeables) en série.
L’argument k a une valeur comprise entre 00h et FFh ; il s’agit Si vous examinez un vrai dé, vous constaterez que les points
de la constante additionnée (au contenu) du registre W. Le se trouvent à sept positions différentes. La figure 11 illustre
résultat est enregistré dans le registre W. la représentation de chacun des chiffres. Il nous faut, pour tra-
duire ces points par des LED, exactement quatre sorties d’un
Dans l’exemple de la figure 9, on commence par charger µC. Si cela vous étonne, en voici le pourquoi : les paires de
la valeur 03h dans le registre W, on additionne ensuite la LED 6 et 7, 2 et 3 ainsi que 4 et 5 ne sont toujours allumées
constante 10h. ou éteintes qu’ensemble. Chaque paire est donc pilotée par
sa propre broche de port GPIO. La LED1 a sa propre ligne de
ANDLW commande. Pour éviter que LED1 ne soit plus claire que les
Cette instruction est identique à ADDLW à ceci près que l’opé- autres, elle est dotée d’une résistance-série, R1. Bien que la
ration ET (AND) remplace l’addition. connexion directe de LED aux broches GPIO (cf. le schéma de
la figure 12) ne soit pas vraiment conforme aux règles, les
CLRF et CLRW
Nous avons déjà rencontré l’instruction CLRF dans la partie 1
(un emplacement mémoire donné est mis à 00h). De façon
similaire, l’instruction CLRW met le registre W à 00h.
La syntaxe est :
clrf f
La routine de « démo »
La routine de « démo » illustrée en figure 15 est parlante.
On y reconnaît six parties de programme similaires, une par
chiffre. La représentation des chiffres se fait par un sous-pro-
gramme : disp_1 se charge d’allumer la LED du chiffre 1. disp_2
provoque l’allumage du chiffre 2 et ainsi de suite.
Après l’affichage d’un chiffre donné, le logiciel attend avant le
chiffre suivant. C’est la fonction de delay_routine – une routine
déjà utilisée dans la 1ère partie du cours. L’instruction btfss
GPIO,D’002’ mérite le détour. Elle sert, bouton ouvert, à sauter
par-dessus l’instruction return et ainsi à produire l’affichage
du chiffre suivant. En cas d’action sur le bouton, ce saut n’est
Figure 13. Code du dé électronique : initialisations. plus effectué puisque l’entrée fournit un 0. Le programme
Programme principal
La structure de cette partie est similaire à la routine de
« démo ». Dans la figure 17, la partie étiquetée main_loop1
fait en sorte que, bouton relâché, il y ait affichage ininterrompu
du chiffre en cours. Comme dans la routine de « démo », on a
aussi, dans le programme principal, interrogation de la valeur
actuelle de l’entrée GP2 et en cas d’action sur le bouton pour-
suite du comptage avec affichage de la valeur actuelle. Tout
va si vite qu’on a l’impression que le chiffre « 7 » est affiché. Figure 15. Code du dé électronique : production des chiffres dans la routine
Après relâchement du bouton, l’instruction goto b_released de « démo ».
est exécutée ; le comptage s’arrête – l’état (du compteur) à
cet instant reste affiché. Ce chiffre est le résultat du (lancer
de) dé. Depuis l’étiquette b_release, on ressaute à main_loop1
qui arrête l’exécution du programme. On aurait aussi pu sau-
ter directement à main_loop1 ; pour rendre le programme
plus vivant, on pourrait ajouter des effets sous l’étiquette b_
release, par exemple, faire s’éteindre le comptage progressi-
vement ou faire clignoter le résultat et ne passer qu’ensuite
à l’affichage statique. Figure 16. Code du dé électronique : routine d‘affichage.
Dans le sous-programme dr2, on détermine la vitesse de chan-
gement des chiffres. En fait, on pourrait aussi s’en passer.
Essayez de ralentir l’exécution du programme au point de voir
les chiffres changer.
Comme à l’accoutumée, le logiciel est téléchargeable depuis
le site Elektor [4].
Perspectives
Nous voici arrivés à la fin de la 2e partie de ce cours d’as-
sembleur. Nous y avons décrit de nouvelles instructions et vu
comment réaliser à peu de frais (et d’efforts) un dé électro-
nique fonctionnel. On pourra, selon le même modèle, réaliser
des applications sensiblement plus complexes. Vous avez pu
constater ainsi que la programmation en assembleur est plus
facile qu’on ne le pense au premier abord.
Liens
[1] PIC12F675 : www.microchip.com/wwwproducts/Devices.aspx?product=PIC12F675
[2] MPLAB IDE : www.microchip.com/pagehandler/en-us/family/mplabx
[3] Première partie du cours: www.elektormagazine.fr/130483
[4] Logiciel : www.elektormagazine.fr/150274
La première partie de cet article était consacrée aux bases de la programmation en assembleur et
aux aspects matériels du contrôleur PIC utilisé. Dans la deuxième partie, nous avons conçu un dé
électronique. Dans cette dernière partie, nous vous montrons comment simuler un circuit intégré (CI)
standard comme le célèbre temporisateur NE555 à l’aide d’un microcontrôleur moderne.
Ne perdons pas notre temps à parler du temporisateur NE555 loge du contrôleur. Comme le montre la figure 1, le circuit ne
lui-même. Ce circuit intégré est produit depuis 1972 et détient peut pas être plus simple.
aujourd’hui encore le record du nombre de pièces vendues Le programme nécessaire ne s’occupe que du pilotage de la
alors qu’il n’est même pas « numérique ». Il est non seule- sortie. Pour un signal rectangulaire avec un rapport impulsion/
ment capable de fonctionner comme générateur de signaux pause de 50 %, on atteint la fréquence la plus élevée avec le
rectangulaires ou monostable, mais sa mise en œuvre est en code suivant en assembleur :
plus incroyablement souple.
La version normale bipolaire permet des signaux jusqu’à output_1 bsf GPIO,D’001’ ;1us @ 4 MHz
500 kHz, et ses successeurs plus modernes comme le LMC555 nop ;1us @ 4 MHz
de TI atteignent même des fréquences jusqu’à 3 MHz. On peut nop ;1us @ 4 MHz
très bien produire des signaux rectangulaires et autres avec des bcf GPIO,D’001’ ;1us @ 4 MHz
circuits intégrés polyvalents comme les microcontrôleurs. Nous
goto output_1 ;2us @ 4 MHz
vous montrons ci-dessous comment utiliser un PIC12F675 pour
remplacer un 555. Nous nous intéresserons essentiellement La première instruction met la sortie GP1 à 1 (logique). Le com-
à la fonction d’oscillateur rectangulaire. Les autres fonctions, mentaire de cette instruction indique la durée de l’instruction :
par ex. monostable…, peuvent très bien être réalisées par logi- une µs pour une horloge à 4 MHz. On attend ensuite deux µs
ciel ; nous vous encourageons à faire preuve d’imagination ! du fait de deux instructions nop, jusqu’à ce que la sortie soit de
nouveau mise à 0 (logique). Cette attente est nécessaire pour
Étape 1 : oscillateur minimal obtenir la symétrie ; en effet, le retour au début de la boucle
Pour notre premier programme, nous n’aurons besoin que d’un avec la commande goto dure 2 µs. Cette boucle sans fin crée
microcontrôleur et de quelques lignes de code – et c’est tout. La pour une cadence de l’oscillateur interne de 4 MHz une fré-
fréquence du signal rectangulaire produit peut être définie dans quence de sortie à env. 166 kHz. L’oscillogramme de la figure 2
le code, d’une valeur très faible à environ 166 kHz. Le micro- prouve la bonne qualité du signal rectangulaire ainsi obtenu.
contrôleur montre sa supériorité pour les basses fréquences Pour des fréquences plus basses, il suffit d’intégrer des pauses
parce qu’il peut produire de manière stable des périodes ou plus longues. Vous avez pour ce faire deux possibilités : pour
des impulsions avec une durée d’un jour, d’un mois ou plus la gamme des kHz, il suffit d’ajouter le nombre correct de nop
encore. La fréquence maximale dépend de la fréquence d’hor- supplémentaires. Pour les signaux plus lents, il vaut mieux
IC1 1
VDD
7
GP0/AN0
6
J1 VREF/GP1/AN1 J2
1 5
+5V GP2/AN2
4 1
GND GP3/MCLR
3
POWER GP4/AN3 OUT
2
GP5/T1CKI/OSC1
GND
8
PIC12F675P
Figure 1. La variante la plus simple du substitut au 555 se passe de Figure 2. Oscillogramme du signal de l’étape 1 : un bon 166 kHz pour un
composants externes. rapport cyclique de 50 %.
créer une boucle d’attente à part entière qui démarre dans la de huit cycles d’horloge et donc d’un temps d’exécution deux
boucle principale. Pour un rapport cyclique de 0,5, les pauses fois plus long.
doivent être symétriques. L’exemple suivant met en évidence Vous devez savoir que l’horloge interne calibrée en usine avec
le double appel de la routine wait_1: une précision de ±1 % peut également être manipulée. En cas
de besoin, il est possible de modifier la valeur de calibrage stoc-
output_1 bsf GPIO,D’001’ ;1us @ 4 MHz kée dans la puce. C’est ce que fait justement le code suivant :
nop ;1us @ 4 MHz
nop ;1us @ 4 MHz bsf STATUS,RP0
call wait_1 ;predefined delay call H’3FF’
bcf GPIO,D’001’ ;1us @ 4 MHz movwf
OSCCAL
call wait_1 ;predefined delay bcf STATUS,RP0
goto output_1 ;2us @ 4 MHz
Bien sûr, on peut enregistrer dans le registre OSCCAL une
valeur personnelle et ainsi changer le cycle d’horloge réel.
Un appel via la commande call dure déjà 4 µs (call elle-même Maintenant que ce principe est clair, voyez le listage 1, le
a besoin de 2 µs et le return dure 2 µs). On définit dans la code complet grâce auquel on va transformer un PIC12F675
routine wait_1 le temps d’attente nécessaire. en un générateur rectangulaire à 166 kHz, avec un rapport
Si on a besoin d’un rapport cyclique asymétrique, on intègre cyclique de 0,5.
des pauses asymétriques. C’est ce que fait le code suivant
avec nop : Tout d’abord, le contrôleur utilisé est défini et configuré à par-
tir de _U002. Ce faisant, l’oscillateur interne est activé avec
output_1 bsf GPIO,D’001’ ;1us @ 4 MHz la valeur « 100 » dans les trois bits de poids faible ; la broche
nop ;1us @ 4 MHz MCLR est réglée pour servir d’entrée et non de RAZ. Les quatre
nop ;1us @ 4 MHz instructions suivantes (de bsf à clrf) désactivent les fonctions
;additional delay – additional 4 µs --------- analogiques inutiles et mettent la broche GP1 en sortie. Les
trois instructions suivantes de call à bcf étalonnent l’oscilla-
nop
teur interne comme on l’a vu plus haut. La boucle principale
nop
finale de bsf jusqu’à goto ne compte que cinq instructions.
nop
nop Étape 2 : réglage de la fréquence
;-------------------------------------------- Le circuit de la figure 4 comprend en plus le potentiomètre P1,
bcf GPIO,D’001’ ;1us @ 4 MHz qui permet de régler la fréquence de sortie d’environ 885 kHz
goto output_1 ;2us @ 4 MHz à 1,45 MHz. La création du signal se fait cependant d’une tout
autre manière que dans le premier exemple. Ici, vous allez
Les 4 µs supplémentaires réduisent la fréquence à environ voir l’application de la fonction CLKOUT ainsi que l’utilisation
100 kHz. Comme la phase à 1 dure maintenant 7 µs et que la du convertisseur A/N intégré.
phase à 0 seulement 3 µs, le résultat donne un rapport cycli-
que de 70 % visible sur la figure 3. Jusqu’ici, le signal rectangulaire était créé par la mise à 1 et
la mise à 0 de la broche de sortie. Faisons maintenant travail-
Encore une chose à propos du minutage : normalement, toutes ler le matériel à notre place. Le PIC12F675 offre la possibilité
les instructions ont besoin de quatre cycles d’horloge. La durée d’appliquer directement sur une sortie la fréquence d’horloge
d’exécution est donc tout naturellement t = 4 / fréquence d’hor- divisée par 4. Si on met les trois bits de poids faible du registre
loge. Les exceptions sont par exemple goto, call ou return, de configuration à « 101 » au lieu de « 100 », la broche GP4
qui manipulent le compteur d’instructions ; elles ont besoin est utilisée comme CLKOUT. Avec une horloge à 4 MHz, c’est un
IC1 1
VDD
7 P1
GP0/AN0
6
J1 VREF/GP1/AN1 10k
1 5
+5V GP2/AN2
4
GND GP3/MCLR J2
3
POWER GP4/AN3
2 1
GP5/T1CKI/OSC1
GND OUT
8
PIC12F675P
Figure 3. Avec quatre autres instructions nop, la fréquence baisse Figure 4. Un potentiomètre supplémentaire suffit pour pouvoir régler la
à 100 kHz avec un rapport cyclique de 70 % non symétrique. fréquence.
signal de 1 MHz qui est créé et le rapport cyclique est de 50 %. dont seuls 10 bits sont significatifs. Les six autres bits ont la
Pour pouvoir changer la fréquence, on va détourner de sa valeur 0. La valeur d’ADFM définit la position des bits superflus.
fonction le calibrage de l’oscillateur interne cité précédem- Si ADFM = 0, le résultat est aligné à gauche, c’est-à-dire que
ment (en donnant d’autres valeurs au registre OSCCAL). La les six bits de poids faible du registre ADRESL sont mis à 0.
plage de valeurs du registre sur 8 bits va de 00h à FFh. L’os- Par conséquent, les huit bits de poids fort du résultat sont mis
cillateur interne se laisse habituellement régler sur une plage dans le registre ADRESH. Les deux bits de poids faible (LSB)
de 3 à 5,8 MHz. Un quart de cette valeur donne la gamme déjà restants par contre sont dans les deux bits de poids fort (MSB)
citée de la fréquence de sortie. d’ADRESL. Si ADFM = 1, c’est exactement l’inverse, le résultat
Pour que le microcontrôleur puisse détecter la position du est alors aligné à droite.
potentiomètre via le CA/N, il faut écrire encore un peu de code. VCFG choisit la tension de référence du CA/N. Si VCFG = 1,
Dans ce but, trois registres sont importants : alors c’est la broche Vref (GP1) qui est utilisée. Si VCFG = 0,
c’est VDD, tout simplement la tension d’alimentation qui sert
• ADCON0 : configuration du CA/N de référence.
• ADRESH, ADRESL : octets de poids fort et faible du résul- Les deux bits CHS1 et CHS0 choisissent la broche qui servira
tat sur 16 bits du CA/N d’entrée au CA/N. Si les deux sont à 0, le canal AN0 est sélec-
• ANSEL : Analog Select Register – fixe la vitesse d’échan- tionné, et ainsi la broche GP0.
tillonnage et détermine la broche qui sera une entrée Go/Done lance une conversion A/N, lorsqu’on l’a mis à 1.
analogique Ensuite, on peut tester si la conversion est achevée. Le bit a
alors la valeur 0.
Voyez la signification des bits du registre ADCON0 dans le Avec ADON = 0, on peut ensuite désactiver complètement
tableau 1. Le bit 7 est ce que l’on appelle A/D Result Formed l’unité A/N (pour économiser le courant) et la réactiver avec
Select Bit (ADFM). Le CA/N intégré a une résolution de 10 bits, ADON = 1.
le résultat est stocké dans deux registres de 8 bits (= 16 bits), Les registres ADRESH et ADRESL contiennent comme on l’a
Listage 1.
;************************************************** movwf
TRISIO
;* NE555 Replacement - Example 1 * clrf ANSEL ;GPIO are digital I/O’s
;* v 1.00 - 19.06.2015 * ;--------------------------------------------------
;************************************************** ;oscillator calibration
;* Microcontroller: PIC12F675 * call H’3FF’
;* Oscillator: internal * movwf
OSCCAL
;************************************************** bcf STATUS,RP0 ;switch back to Bank 0
;Pin connections:
;GP0 --> N/C ;--------------------------------------------------
;GP1 --> Output ;Main Loop
;GP2 --> N/C ;--------------------------------------------------
;GP3 --> N/C output_1 bsf GPIO,D’001’ ;1us @ 4 MHz
;GP4 --> N/C nop ;1us @ 4 MHz
;GP5 --> N/C nop ;1us @ 4 MHz
;-------------------------------------------------- ;additional delay - additional 4 us ---------------
;Chip configuration: nop
INCLUDE «P12F675.INC» nop
_U002 EQU B’00000110000100’ nop
;MCLR = input/internal osc. nop
__CONFIG U002 ;--------------------------------------------------
;-------------------------------------------------- bcf GPIO,D’001’ ;1us @ 4 MHz
;analog functions off, GP1 = output goto output_1 ;2us @ 4 MHz
bsf STATUS,RP0 ;switch to regist. bank 1 ;--------------------------------------------------
movlw
B’11111101’ END
;GP1 = output; GP0; GP2 - GP5 = input
Listage 2.
Le programme devra exécuter deux tâches. D’une part, il doit produit alors le signal de sortie proprement dit. Voilà comment
comme précédemment détecter la position du potentiomètre, cela se passe :
mais aussi délivrer un signal rectangulaire précis qui ne pourra au début, une valeur est chargée dans le registre du temporisa-
pas être perturbé par un changement de la fréquence. C’est teur TMR0. À partir de là, cette valeur est incrémentée jusqu’à
pour cette raison qu’il y a deux parties dans le code. Inutile ce qu’elle atteigne FFh. Comme il s’agit d’un registre à huit
de rappeler comment acquérir la position du potentiomètre. bits, il s’ensuit un dépassement à l’incrémentation suivante et
Pour produire le signal de sortie, deux nouvelles fonctions du le registre contient alors la valeur 00h. Le dépassement est un
microcontrôleur sont utilisées : Timer0 et Interrupts. évènement qui déclenche une interruption. On peut alors créer
le signal à délivrer dans la routine d’interruption.
La fonction Timer0 peut être utilisée en temporisateur ou comp-
teur. En temporisateur, le registre correspondant est incré- La manipulation de Timer0 et de son registre TMR0 n’est vrai-
menté périodiquement par l’horloge. En compteur, ce sont ment pas compliquée. Quand on met le bit T0CS à 0, Timer0
des évènements externes par exemple qui sont comptés. Pour sert de temporisateur. À partir de là, TMR0 est incrémenté à
simuler le 555, il faut le mode temporisateur. Le temporisateur chaque cycle d’instructions (horloge / 4).
Listage 3.
;************************************************** ;--------------------------------------------------
;* NE555 Replacement - Example 3 with Xtal * ;ISR
;* v 3.07 - 05.07.2015 * ;Save status register ------
;************************************************** int_main movwf w_save0 ;save content of W-reg.
;* Microcontroller: PIC12F675 * ;could be Bank0 or Bank1
;* Oscillator: internal * swapf STATUS,0
;move content of Status to W
;************************************************** bcf STATUS,RP0 ;switch to Bank0
;GP0 --> Poti movwf stat_save
;GP1 --> Output ;save original content of Status
;GP2 --> N/C ;GPIO toggle ------
;GP3 --> N/C movf v_value,0
;GP4 --> Xtal movwf GPIO
;GP5 --> Xtal incf v_value,1
;-------------------------------------------------- ;Store ADC value in TMR0 ------
;Chip configuration: movf v_delay,0
INCLUDE “P12F675.INC” movwf TMR0
_U003 EQU B’00000110000010’ bcf INTCON,T0IF
;MCLR = external xtal up to 20 MHz ;Restore status register ------
__CONFIG U003 swapf stat_save,0 ;restore old Status to W
;================================================== movwf STATUS
;Variable definitions ;push content to Status register
w_save0 EQU H’20’ ;select old Bank
w_save1 EQU H’A0’ swapf w_save0,1 ;rebuild content of W-reg.
stat_save EQU H’21’ swapf w_save0,0 ;restore W register
v_delay EQU H’22’ retfie
v_value EQU H’23’ ;--------------------------------------------------
v_tmp EQU H’24’ ;ISR
;================================================== rst_main
;Set adress of subroutines ...
ORG H’000’ ;missing code
goto rst_main ...
ORG H’004’ ;--------------------------------------------------
goto int_main END
Quelques mots encore sur les interruptions : toutes les proprié- des interruptions doivent toujours être 000h et 004h.
tés importantes sont pilotées par le registre INTCON. Voyez la Avant d’arriver à l’ISR (Interrupt Service Routine) int_main, il
signification de ses bits dans le tableau 2. Pour notre projet, faut bien savoir ce qu’est une interruption. En principe, l’exé-
seuls trois bits sont importants : cution du programme est interrompue par l’apparition d’un
• GIE : Global Interrupt Enable. GIE = 1 active et GIE = 0 évènement déterminé et une routine d’interruption (ISR) s’exé-
désactive les interruptions. cute. Une fois l’ISR terminée, le programme principal revient
• T0IE : Timer0 Interrupt Enable. Seulement si T0IE = 1, un à l’emplacement où il se trouvait et il continue. C’est la même
dépassement de TMR0 provoque une interruption. chose que l’appel d’un sous-programme, simplement cet appel
• T0IF : Timer0 Overflow Indicator. En cas de dépassement peut se passer à n’importe quel endroit du programme. Il est
de TMR0, T0IF = 1. On peut consulter le bit et le code doit tout à fait possible que le programme ait exécuté une opéra-
le remettre à « 0 ». tion arithmétique, ait positionné les bits du registre d’état et
qu’une interruption survienne avant l’instruction BTFSS suivante.
Point important encore, la routine d’interruption doit tou- Comme l’ISR ne peut gêner le déroulement du programme
jours commencer à l’emplacement de mémoire 004h du pro- principal, elle doit sauvegarder avant sa tâche le contenu du
gramme. Pour les interruptions, il y a encore deux instructions registre d’état et ensuite le rétablir (avant le saut de retour).
à connaître : C’est pourquoi l’ISR se plante plus souvent que l’on ne pour-
rait le supposer.
SWAPF
Cette instruction échange les deux quartets (nibbles) d’un L’instruction SWAPF s’avère ici importante, elle va nous per-
registre. Une valeur de E4h devient après l’échange 4Eh. Pour mettre de sauvegarder le contenu d’un emplacement mémoire
les interruptions, il est en outre important que le registre d’état dans le registre W. Au début de l’ISR, les registres W et d’état
reste inchangé pendant l’exécution de cette instruction. La sont sauvegardés. La première instruction movwf w_save0 sau-
syntaxe est : vegarde le registre W à l’emplacement mémoire w_save0.
Comme nous ne savons pas si le programme principal travail-
swapf
f,d lait au lancement de l’interruption avec la banque 0 ou 1, il
est très important que w_save0 (ici 20h) et w_save1 (ici A0h)
L’adresse de registre « f » peut comporter des valeurs entre restent libres. L’instruction movwf laisse d’ailleurs inchangé le
00h et 7Fh et « d » peut être soit 0, soit 1. Pour d = 0, le contenu du registre d’état. Les trois instructions suivantes
résultat est sauvegardé dans le registre W. Si d = 1, c’est de sauvegardent le contenu du registre d’état à l’emplacement
nouveau le résultat qui s’inscrit dans le registre. mémoire prévu stat_save (21h) dans la banque 0. Ainsi tout
ce qu’il faudra restaurer plus tard est sauvegardé.
RETFIE C’est ici que commence vraiment le travail de l’ISR : la variable
RTFIE est l’acronyme de RETurn From IntErrupt. Cette ins- v_value est fournie au port GPI0 à chaque interruption. La
truction met fin à la routine d’interruption et le programme variable est ensuite incrémentée. Comme la broche GP0 délivre
principal reprend son cours. Avec RETFIE, il ne faut donner le signal de sortie (dont le niveau est déterminé par le bit de
aucun paramètre (comme avec RETURN). La syntaxe est : poids faible de la variable), il y a un changement de niveau à
chaque interruption. Maintenant, il reste à copier la variable v_
retfie delay dans le registre TMR0. Comme la valeur de ces variables
correspond à la position du curseur du potentiomètre, la fré-
Au démarrage d’une interruption, le bit GIE du registre INTCON quence de sortie est ainsi définie.
est mis à 0, ce qui arrête les autres interruptions. L’instruction Il reste encore à restaurer les valeurs originales du registre
RETFIE remet le bit GIE à 1. W et du registre d’état, ensuite l’ISR peut se terminer avec
l’instruction retfie.
Les gammes de fréquences que l’on peut couvrir avec ce code
Voyons le code du listage 3 : on remarque d’abord qu’ici CLK- et ce circuit dépendent de la fréquence du quartz et sont pré-
OUT n’est pas employé. En outre, les trois bits de poids faible sentées dans le tableau 3.
du registre de configuration sont mis à « 010 », ce qui permet
l’utilisation d’un quartz de haute fréquence. La description de la partie manquante du listage nous en emmè-
Suit une section avec la déclaration des variables. On définit nerait trop loin. Vous pouvez bien sûr télécharger gratuitement
ici les variables principales v_delay, v_value et v_tmp ainsi en [4] cet exemple complet ainsi que les autres listages de
que w_save0, w_save1 et stat_save pour le traitement des cet article, pour les examiner tranquillement.
interruptions.
Dans la section suivante, la directive ORG fixe les adresses
de démarrage de deux sous-routines. Vous ne connaissez pas Tableau 3. Fréquences de sortie avec la fréquence du
encore cette directive, mais sa fonction est facile à expliquer : quartz comme paramètre
ORG fixe l’adresse de l’instruction qui suit. Dans notre cas, Fréquence du quartz fsortie min. fsortie max.
rst_main est verrouillé à l’adresse 000h et int_main à 004h.
2 MHz 237 Hz 4,63 kHz
Comme l’instruction goto n’occupe qu’un octet, les adresses
4 MHz 474 Hz 9,26 kHz
001h à 003h restent inoccupées. Nous faisons appel à cette
directive parce que les vecteurs (adresses cibles) de la RAZ et 20 MHz 2.370 Hz 46,30 kHz
Listage 4.
cours intensif
d’assembleur 2.1
(1)
interruption pour commander
un afficheur à LED
L’an dernier, nous avons publié un cours intensif d’assembleur pour microcontrôleurs PIC. Nous y
abordions, en trois articles, la théorie et la pratique de la programmation de µC la plus proche possible du
matériel. Dans cette seconde série, nous approfondissons le sujet. Commençons par les interruptions.
temporisateurs
µC mémoire prog. EEPROM RAM E/S CA/N comparateurs MSSP I2C / SPI
8/16bits
sûr, du type de µC. Sur un PIC12F1822, le programmeur pourra la déclaration dans Step 1 une valeur dans v_tmp, la position
utiliser 80 octets sur les 128 octets de RAM de la BANK 0, mais réelle de cette variable dépend non seulement des 7 bits de
seulement 32 octets de la BANK 1. Pourquoi donc ? Du total de l’adresse attribuée, mais aussi du contenu du BSR. Si, comme
128 octets, il faut encore déduire la RAM Commune avec ses dans Step 2, on sélectionne la BANK 1, la valeur 28h « n’atter-
16 octets. Il n’y a donc plus la moindre RAM pour les BANK 2 rit » pas à l’adresse 230h, mais en B0h, qui est l’adresse définie
à BANK 32. Si on lit la RAM d’Usage Général non disponible (à par la somme de 30h et de la valeur de début de la BANK 1 =
partir de l’adresse 20h dans la BANK 1 et tout pour les BANK 2 80h. On obtient l’adresse correcte pour v_tmp, à savoir 230h
à BANK 32), on obtient toujours la valeur 00h. si, cf. Step 3, on paramètre BSR à 04h pour la BANK 4 (bien
La figure 1 compare la cartographie de la BANK 0 des PIC entendu, le type de µC utilisé doit avoir de la RAM à cet endroit
des types PIC12F1822 et PIC16F1847. Elle est pratiquement – il faut donc un µC avec au moins 512 octets de RAM).
identique pour les différents types de cette famille. Les dif-
férences sont dues à des caractéristiques spécifiques : pour
le PIC16F1847, le registre PORTB occupe l’adresse 0Dh, mais
dans le cas du PIC12F1822 cet espace est inoccupé en rai-
son de l’absence de PORTB. Les fiches techniques correspon-
dantes [1] donnent les détails des banques de mémoire pour
chaque type de µC.
S1
19 VDD 16 R1 A
RA0 RC0 1k2
18 15 R2 B
RA1 RC1 1k2
17
IC1 14 R3 C
RA2 RC2 1k2
4 7 R4 D
RA3/MCLR RC3 1k2
3 6 R5 E
RA4 RC4 1k2
BT1 2 PIC16F1829 5 R6 F
RA5 RC5 1k2
RC6
8 R7
1k2
G LD0 SC08-11 LD1 SC08-11 LD2 SC08-11 LD3 SC08-11
9 R8 DP A 1
A
A 1
A
A 1
A
A 1
A
RC7 1k2
B 14 B 14 B 14 B 14
B B B B
13 10 C 12 C 12 C 12 C 12
RB4/SDA1 RB7/SCL2 C C C C
12 11 D 10 D 10 D 10 D 10
RB5/SDA2 RB6/SCL1 D D D D
VSS E 4 E 4 E 4 E 4
E E E E
20 F 2 F 2 F 2 F 2
F F F F
G 13 G 13 G 13 G 13
G G G G
DP 9 DP 9 DP 9 DP 9
DP DP DP DP
CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC
3 5 11 16 3 5 11 16 3 5 11 16 3 5 11 16
150518 - 11
Figure 2. Le circuit complet de notre exemple se résume essentiellement au µC épaulé par huit résistances et quatre afficheurs à LED (à 7 segments).
Afficheur à LED commandé avec une interruption ces LED requièrent en général quelque 10 mA de courant, il
Après les bases de l’adressage de la mémoire, passons aux est judicieux, en mode « piles » (4,5 V par trois AA ou AAA, p.
choses sérieuses : l’utilisation d’interruptions à l’aide d’un ex.), de prévoir un interrupteur, S1. Autres composants : le µC
exemple concret, la commande d’un afficheur à LED à quatre PIC16F1829 (avec ses vingt broches, il dispose de suffisam-
chiffres. Nous verrons ainsi combien la programmation est ment d’E/S et a assez de mémoire), huit résistances-série et
simplifiée par rapport à des µC moins puissants tels que le quatre afficheurs à LED à sept segments. On voit en figure 3
PIC12F675. notre prototype.
Figure 3. Le prototype du montage trouvera facilement place sur un petit Figure 4. Commande cyclique d‘un afficheur à LED à sept segments, à
morceau de platine à trous. quatre chiffres, en mode multiplexé avec pseudo-code.
sur l’afficheur actif à ce moment-là sont forcées au niveau sateurs 0, 1, 2, 4 et 6, le µC utilisé en a même plusieurs. Nous
« haut » par le µC. Il faut bien sûr veiller à ce qu’il n’y ait allons œuvrer avec le temporisateur 2. À chaque passage par
qu’une seule cathode d’activée à la fois, on aurait sinon des la routine d’interruption, il faut activer la position suivante de
affichages indéfinis. l’afficheur et la laisser allumée jusqu’à la prochaine interruption.
Le temporisateur 2 remplit diverses fonctions. La figure 5 nous
Le logiciel apprend que le module de temporisation est constitué de trois
Pour un affichage dynamique, le logiciel doit faire s’allumer compteurs montés en série :
brièvement d’abord l’afficheur LD0 puis LD1, LD2 et pour finir • Un prédiviseur (prescaler). Attaqué avec la fréquence de
LD3 – et ce de façon cyclique. La figure 4 montre le principe l’oscillateur divisée par quatre, il est paramétrable pour
avec son pseudo-code. une seconde division par 1, 4, 16 ou 64, avant déclenche-
La fréquence d’exécution du cycle complet doit être supérieure ment d’une impulsion d’horloge.
à que ce que l’on appelle la fréquence de clignotement de l’œil • TMRx. Dans le cas du temporisateur 2 il s’agit de TMR2.
humain, sinon l’afficheur scintille. Aux fréquences vraiment trop Chaque impulsion d’horloge du prédiviseur incrémente
faibles, il clignotera et sera illisible. Pour une luminosité uni- le registre TMR2. À chaque changement, il y a compa-
forme des quatre afficheurs, leurs durées d’activation doivent raison entre le contenu de TMR2 et le registre PR2 et
être identiques. en cas d’égalité, le postdiviseur (postscaler) délivre une
impulsion.
Si c’était tout ce que le µC a à faire, il suffirait d’une boucle • Un postdiviseur (postscaler). Dernier compteur de la
sans fin exécutant ce dont nous venons de parler ; un afficheur chaîne, il est paramétrable pour compter jusqu’à 1, 2...16.
qui fonctionne, mais sans contenu, ne sert pas à grand-chose. Tout dépassement provoque la mise à un de l’indicateur
Le µC peut produire des données lui-même (l’heure, p. ex.) ou TMR2IF – qui, si activé, déclenche une interruption.
en traiter (lecture de capteurs, p. ex.). Ces tâches prennent Pour la commande de l’afficheur, il y a quatre registres à obser-
du temps de calcul. Dans le cas d’une commande d’affichage
dans une boucle sans fin, il faudra que la tâche additionnelle
soit intercalée quelque part entre la commande des différentes
positions. Selon les conditions, il se peut que la fréquence de
multiplexage varie un peu, ainsi que les périodes actives des
quatre afficheurs les unes par rapport aux autres, il faut éviter
ces deux situations. Une technique plus satisfaisante et très
utilisée est de faire appel à des interruptions.
ver. Le registre T2CON en est un. Le tableau 2 décrit l’affec- Step 2 concerne la configuration de l’interruption. Le paramé-
tation des différents bits. On voit que les deux bits de poids trage à « 1 » de TMR2IE du registre PIE1 active l’interruption
faible du registre T2CON définissent le diviseur du prédiviseur. du temporisateur 2. Il ne reste plus maintenant qu’à activer
Le tableau 3 donne des informations de configuration. Le bit un commutateur d’interruption globale par la mise à « 1 » des
TMR2ON active ou désactive le temporisateur 2. Les quatre bits 6 et 7 du registre INTCON.
bits restants de T2OUTPS définissent le diviseur du postdivi- On a, dans Step 3, comme dernière étape de l’initialisation, le
seur (cf. tab. 4). démarrage de TIMER2.
Le code du micrologiciel explicite l’usage des trois derniers Intéressons-nous maintenant à l’ISR (Interrupt Service Rou-
registres requis. L’initialisation de l’interruption et du tem- tine = routine de service d’interruption) du listage 3 : il est
porisateur 2 se fait de la façon suivante : dans Step 1 du lis- évident qu’il est inutile, au début, de sauvegarder les registres
tage 2, le prédiviseur est paramétré à 1:64 (T2CKPS<1:0> = (ni W, STATUS ou tout autre). La 3e partie du premier cours
11), le postdiviseur à 1:1 (T2OUTPS<3:0> = 0000). TMR2 est intensif [2] décrivait la sauvegarde des registres W et STA-
ensuite mis à « 0 », d’où un comptage incrémentiel. Ensuite TUS du µC PIC12F675. Ici c’est inutile, vu que chaque µC de
on écrit la valeur 02h dans le registre PR2, ce qui provoque cette famille se charge automatiquement de la sauvegarde
une interruption lorsque TMR2 atteint cette valeur. Le choix du contexte. Lors d’une interruption, le matériel se charge de
d’un postdiviseur égal à 1 le désactive de fait. sauvegarder les contenus des registres W, STATUS, BSR et FSR
Step 4 n’est en fait rien de plus que quelques opérations de celle de la section Path2, etc. (cf. listage 4).
clôture. Le registre W commence par se voir affecter la valeur 02h,
l’instruction BRW est ensuite exécutée. Puisque l’on a addi-
BRW tion de la valeur de W au CO, l’instruction suivante à exécuter
Le PIC de type 12F675 « connaît » 35 instructions. La nouvelle n’est pas goto path1, mais goto path3. De ce fait, on saute à
famille plus récente et utilisée ici, avec les 49 instructions du la section de code de Path3.
« Enhanced Instruction Set », en a encore plus. L’instruction
BRW est l’une d’entre elles : elle permet, dans une ISR, d’éco- BRW permet donc de simplifier sensiblement le code de l’ISR.
nomiser bien du temps et beaucoup de mémoire de programme. On peut, par son biais, réaliser un branchement élégant, en
BRW (relative BRanch with W) est en fait une instruction de fonction de v_curr_p, vers l’une des quatre sous-routines ishow_
saut sans paramètre additionnel. D’où sa syntaxe ultra simple : digitx. Dans le listage 5 il n’y a, logiquement, rien de changé
dans Step 1, 3 et 4. Step 2 au contraire a été subdivisé : dans
brw Step 2a, on fait appel à une nouvelle technique de décision.
Dans Step 2b, on utilise l’instruction BRW et on a, en fonction
L’instruction ajoute le contenu du registre W au compteur
d’instructions (PC pour Program Counter). Ainsi, l’exécution
du programme est interrompue et reprise à un autre endroit. Listage 4
La distance de l’endroit est donnée par le registre W. On peut
movlw B'00000010' ; W = 02h
utiliser l’instruction à chaque fois que l’on veut introduire un
brw
branchement multiple qui soit fonction d’une variable dans le
goto path1
déroulement du code. Elle permet, p. ex., d’exécuter quatre sec-
goto path2
tions de code différentes en fonction du contenu du registre W.
goto path3
Si W = 0, on aura exécution de la section Path1 et pour W = 1
goto path4
;
;autre code ici...
Tableau 3. configuration Tableau 4. configuration
;
du prédiviseur du postdiviseur
path1 nop
T2CKPS<1:0> diviseur T2OUTPS<3:0> diviseur
;
00 1 0000 1 path2 nop
0001 2 ;
01 4
0010 3 path3 nop
10 16 ;
… …
11 64 1111 16 path4 nop
du contenu de v_curr_p, branchement vers l’une des quatre correspondant. Dans le programme d’exemple, onze caractères
routines pour la position d’afficheur concernée. Si v_curr_p = différents ont été définis : 0 à 9 et « - », ce dernier caractère
0, on a exécution de ishow_digit0 et, dans le cas d’une valeur est codé 0Ah.
de 1, ishow_digit1 et ainsi de suite. Au lieu de 4 x 4 instruc-
tions, il n’en faut plus que sept au total. Pour que le pilote d’affichage affiche le caractère correct, il reste
encore à définir une sorte de « jeu de caractères » sous forme
Les sous-routines ishow_digit0 à ishow_digit3 sont presque d’un tableau. Pour un « 1 » par ex., il faudra activer les seg-
identiques, la seule différence est la sortie (RB4 à RB7) qui ments « B » et « C ». Pour cela, sur le circuit, les sorties RC1
présentera un « 0 » logique et activera donc la position de l’af- et RC2 doivent être mises à « 1 », RC0 et RC3 à RC7 à « 0 ».
ficheur correspondante. Les sous-routines s’expliquent d’elles- L’instruction BRW convient également fort bien pour mettre
mêmes. Signalons l’utilisation ici d’une sorte de mémoire vidéo. en place ce tableau. Il nous faut encore un petit complément
Il y a quatre emplacements de mémoire (variables v_pos0 fourni par l’instruction du paragraphe qui suit.
à v_pos3) pour stocker les données à afficher. Ces quatre
variables servent d’interface entre l’application principale et RETLW
le pilote d’affichage qui se cache dans l’ISR décrite. L’applica- RETLW est en fait une variante de l’instruction RETURN. Cette
tion principale stocke les données à afficher dans la mémoire dernière est utilisée pour quitter une sous-routine et revenir
vidéo. Le pilote d’affichage les lit et les affiche. Pour éviter que au programme d’appel. RETLW (RETurn with Literal in W) est
l’application n’ait à se soucier du codage des caractères, il faut similaire à RETURN, à ceci près que l’on peut la doter d’un
effectuer une conversion des valeurs numériques en segments paramètre. Ce paramètre représente une constante qui, lors
de LED à allumer. Si l’une des variables de la mémoire vidéo du saut de retour, est stockée dans le registre W.
contient la valeur 00h, il apparaîtra un « 0 » à l’emplacement Sa syntaxe est :
L’application principale prend la forme d’une boucle sans fin [1] PIC1XF18XX: http://ww1.microchip.com/downloads/en/
qui crée ce compteur et écrit l’état actuel du compteur dans DeviceDoc/40001413E.pdf
les quatre variables de mémoire vidéo. La boucle sans fin [2] Troisième partie du premier cours :
demo_loop du listage 7 contient le compteur incrémental. www.elektormagazine.fr/150393
Chaque changement du compteur est suivi d’une petite pause [3] Téléchargement du logiciel : www.elektormagazine.fr/150518
(call dr2), pour éviter que le compteur n’aille trop vite. On
pourra, pour étudier le comportement du pilote d’affichage,
effectuer de petites modifications et en observer les consé-
Publicité
Les fauves et les moustiques appelés LoRa, SigFox, Neul, Qowisio, ThingSpeak,
Brillo, Nest Weave, Thread… ne vous effrayent pas ?
Ce ne sont pas ces quelques réseaux à bas débit sur
longue distance qui vous font perdre le nord ?
La relation éditeur-auteur est encadrée par un contrat d’édition qui stipule vos
droits d’auteur sous la forme d’un pourcentage déterminé du prix de vente.
cours intensif
d’assembleur 2.1
(2)
adressage indirect
Dans l’article précédent de notre cours intensif d’assembleur [1], nous avons traité de la commande
multiplexée d’un afficheur à LED. L’utilisation d’un microcontrôleur (µC) récent aux modes d’adressage
sophistiqués a permis de simplifier sensiblement la programmation. Dans ce second article, vous
découvrirez l’adressage indirect.
Miroslav Cina ([email protected]) deux autres registres spéciaux qui permettent un accès linéaire
à la mémoire de travail : INDF0 et INDF1. Mieux, ils auto-
risent même un accès linéaire à la mémoire de programme.
La famille plus moderne des µC PIC1xF18xx met à disposition Avec cette méthode d’accès, toute la mémoire, RAM + Flash
une fonction très pratique : l’adressage indirect. Son princi- (mais hors EEPROM), du µC se présente sous la forme d’un
pal avantage est que l’on peut accéder à la mémoire de façon seul bloc de 64 Ko.
totalement linéaire, ce qui permet de contourner le traitement Qui dit espace d’adressage de 64 Ko, dit adresses de 16 bits.
parfois complexe inhérent aux blocs segmentés. Ainsi, ces µC C’est ce type d’adresses que contiennent les paires de registres
redeviennent faciles à manipuler, à l’image de ce que permet- FSR0 (FSR0H | FSR0L) et FSR1 (FSR1H | FSR1L), dont nous
taient les « vrais » microprocesseurs à 8 bits tel le populaire avons déjà parlé comme membre des registres noyaux (Core).
Z80 (Zilog) des années 80. Il nous faut maintenant, pour l’adressage indirect, deux ins-
tructions additionnelles de l’assembleur. Nous verrons alors à
Registres INDFx quoi peuvent servir les registres INDF0 et INDF1.
Dans l’article précédent, nous avons vu l’adressage direct via La RAM se retrouve en double dans l’espace d’adressage
le registre BSR. Tous les µC de la série PIC1xF18xx comportent de 64 Ko. En premier lieu, dans la plage 0000h à 0FFFh, comme
mémoire de travail conventionnelle. L’accès à ces adresses
par le biais de FSRx correspond en grande partie à l’adres-
sage direct via BSR. La RAM est à nouveau disponible dans la
plage d’adresses 2000h à 29AFh – mais en linéaire cette fois.
Ceci est pertinent si l’on veut, par exemple, accéder élégam-
ment à une matrice de données, un tableau par exemple. Mais
pourquoi donc la plage d’adresses s’arrête-t-elle à 29AF et pas
à 2FFF ? Dans cet espace de mémoire, les blocs sont, à raison
de 80 octets, un miroir des banques de mémoire individuelles.
La banque BANK 0 sise dans la plage d’adresses 020h à 06Fh
se trouve ici dans la plage 2000h à 204Fh, BANK 1 entre 2050h
et 20AFh, etc. La dernière banque en miroir (BANK 30) se ter-
mine donc à l’adresse 29AFh.
L’accès à la mémoire de programme Flash se fait par les
adresses 8000h à FFFFh. Il est évident qu’il n’y a pas occu-
pation effective de tous les emplacements de mémoire. Par
exemple, la Flash de 8 Kmots du PIC16F1829 se trouve dans
la plage 8000h à 9FFFh. Les 2 Kmots du PIC12F1822 se situent
eux dans la plage 8000h à 87FFh. Le reste inutilisé est bien
adressable, mais inutile.
Caractéristique typique de ces µC PIC, des cellules de RAM
Figure 1. Cartographie de la mémoire des µC de la série PIC12F18xx. de 8 bits de large, bien que la mémoire de programme soit
MOVIW
Cette instruction est principalement destinée au transfert du
contenu du registre INDFn dans le registre W (MOVE Indfn
to W). INDFn peut être soit INDF0 soit INDF1. Maintenant,
l’astuce : le registre INDFn n’existe pas. Lors de l’accès à
Figure 2. Affichage d‘un octet sous forme hexadécimale sur l‘afficheur à
INDF0, on accède toujours à l’emplacement de mémoire dont
LED du premier article.
l’adresse se trouve dans FSR0 (pour INDF1 ce sera évidem-
ment l’adresse de FRS1).
Il existe deux variantes d’utilisation : pour l’une, on a ajuste- vant. La lecture de la valeur de FFh de la mémoire signale la
ment du pointeur (incrémenté ou décrémenté) et pour l’autre fin de la boucle. Tout repart alors à l’adresse 1000h.
pas d’ajustement. Il s’agit ici de la première variante, car sou- Comme il s’agit d’octets, la représentation requiert des carac-
vent utilisée lors de l’accès à des champs de données. tères numériques ordinaires, mais aussi hexadécimaux. L’affi-
La première variante connaît en outre quatre sous-types cf. le chage d’un octet de format hexadécimal ne nécessite que deux
tableau 1, qui se différencient par le moment de changement positions d’afficheur. Nous utilisons pour cela les deux positions
du pointeur, avant ou après l’accès, et la fonction, incrémen- gauches de l’affichage, LD0 et LD1. LD2 reste vide et la qua-
tation ou décrémentation ; « n » peut en outre avoir la valeur trième position, LD3, affiche un « h » en permanence. La valeur
« 0 » ou « 1 » (registre FSR0 ou FSR1). décimale 122 s’affiche alors comme « 7A h », cf. la figure 2.
Parallèlement à l’instruction MOVIW décrite ici, il existe, avec
MOVWI, son inverse : cette instruction écrit le contenu du Modification du pilote d’affichage
registre W dans la cellule de mémoire adressée correspondante. Nous le disions, l’affichage doit maintenant pouvoir représen-
Ceci ne fonctionne bien entendu que dans la zone où il existe ter des caractères hexadécimaux. Contrairement au code du
de la RAM. Il faudra, pour modifier le contenu de la mémoire 1er article, il ne suffit plus de pouvoir afficher uniquement les
Flash, opter pour une autre technique. Tout cela est à utiliser chiffres « 0 » à « 9 » et le signe « - », il nous faut maintenant
avec prudence : du code qui peut se modifier lui-même pré- les lettres « A » à « F », l’espace et le « h » minuscule, d’où
sente des pièges. modification du pilote d’affichage. Il devient possible alors de
représenter en hexadécimal toutes les valeurs décimales 0 à 255.
Affichage de la mémoire de programme Le générateur de police de la routine « wm_char_set » va gon-
Vu que l’on dispose déjà, avec l’afficheur à LED de l’article pré- fler un peu. Les différences entre l’ancienne version décimale
cédent, du matériel requis pour afficher des valeurs, il nous du listage 1 et la nouvelle version hexadécimale du listage 2
servira à afficher en boucle le contenu de la mémoire Flash à restent limitées. Cet exemple montre combien il est facile,
partir de l’adresse 1000h. Il suffit de modifier le programme si besoin était, d’étendre le pilote d’affichage. Un caractère
principal du logiciel du µC. Hormis cela, on réutilise le pilote est défini dans une ligne d’assembleur. Ainsi les modifications
d’affichage de l’article précédent légèrement modifié. Il n’y a nécessaires pour l’affichage sont simples et rapides.
pas cette fois de compteur dans la routine principale, mais le
code qui sert à lire les données de la mémoire de programme. Programme principal
Le principe : une boucle lit les données de la mémoire de pro- Passons au programme principal ; il est composé de trois
gramme et les affiche. Pour cela, le programme extrait les parties :
données octet par octet à partir de l’adresse 1000h. Chaque • Lecture des données de la mémoire Flash par le sous-
octet lu est affiché un court instant, on passe ensuite au sui- programme f_get_data.
• Conversion des octets au format hexadécimal à deux mémoire de programme peuvent contenir jusqu’à 14 bits. Ainsi,
chiffres avec le sous-programme calc_hex_disp. une déclaration H’AB’ est identique à H’00AB’. De ce fait, une
• Structure de la boucle principale, sans fin. telle déclaration écrase donc deux octets – d’où deux messages.
La première partie du mot ne peut prendre que des valeurs
Lecture de la Flash allant de 00h à 3Fh, mais comme, avec cette méthode, il est
Dans cette partie, nous découvrons l’utilisation de l’adressage de toute façon impossible d’accéder aux six premiers bits, on
indirect. La déclaration complète des constantes comme don- peut ici faire une déclaration abrégée.
nées pour la mémoire Flash et l’accès en lecture correspondant On aurait pu totalement oublier la directive ORG 1000, les
sont faciles à implémenter, cf. le listage 3. données auraient cependant été stockées dans la mémoire
Les données à lire doivent être stockées dans la mémoire de Flash juste après le sous-programme f_get_data. Il peut être
programme à partir de l’adresse 1000h. Ceci est obtenu par la important, à l’occasion, de connaître l’emplacement de mémoire
directive ORG 1000 (cf. step 3). En outre, le début des don- exact, car en l’absence de directive ORG la position change
nées est indiqué sous la forme de « c_data1 ». En principe, avec le code.
l’utilisation d’autres zones de mémoire est possible, mais avec La routine f_get_data (step 2) lit un octet de la mémoire Flash ;
deux restrictions : la zone de mémoire doit, pour le µC utilisé, elle ne requiert que quatre lignes de code. Comme déjà dit,
correspondre à de la mémoire Flash physique et la déclara- l’instruction MOVIW copie la valeur dans le registre W. Ensuite
tion ne doit pas entrer en conflit « accidentel » avec le code la valeur est sauvegardée dans la variable-tampon v_value
de programme proprement dit. Le µC PIC16F1829 utilisé ici pour une utilisation ultérieure ; et voilà. Comme ici on utilise
possède 8 Kmots de mémoire de programme ; la cellule de la variante post-incrémentation de l’instruction, le pointeur
la mémoire la plus haute se situe donc à l’adresse 1FFFh. Si correspondant est incrémenté après lecture. Lors du pro-
l’on utilisait à tort l’adresse 2000h, l’accès se ferait à l’adresse chain appel du sous-programme, il y a automatiquement lec-
0000h, ce qui n’est pas très malin. ture de l’octet suivant.
Avec la directive ORG, si vous déclarez la zone de mémoire des Un mot au sujet de l’initialisation du pointeur – dans ce cas,
données à une adresse trop basse, l’exécution de l’assembleur la paire de registres FSR1 : pour lire les données à partir de
produira des messages d’erreur. Cela dépendra de l’endroit l’endroit correct, il faut qu’il s’y trouve l’adresse correspon-
où l’on « débarque » dans la mémoire de programme. Pour dante. C’est la fonction du sous-programme f_get_add (step 1).
chaque octet écrasé par erreur, deux messages d’erreur sont L’adresse est divisée par les directives « LOW » et « HIGH » et
affichés, cf. l’exemple ci-après : écrite dans les moitiés de registre appropriées. La ligne
Pourquoi deux messages par octet ? Parce que les mots de Ensuite, la ligne
Listage 3. ;
;step 2
;---------------------
f_get_data clrf BSR
; déclaration et lecture des données
moviw FSR1++
;---------------------
movwf v_value
;step 1
return
f_get_add clrf BSR
;
movlw LOW c_data1
;step 3
movwf FSR1L
ORG 1000
movlw HIGH c_data1
c_data1 da H'01', H'02', H'03', H'04'
movwf FSR1H
da H'AB', H'CD', H'EF'
return
da H'FF'
lsrf f
cours intensif
d’assembleur 2.1
(3)
communication I2C et SPI
Dans les deux premiers articles de ce second cours intensif d’assembleur, nous avons abordé la
commande multiplexée d’un afficheur à LED et parlé de l’adressage indirect. Ce troisième et dernier article
s’intéresse à la communication série via les interfaces I2C et SPI.
Miroslav Cina (Allemagne) [email protected] (Maître) est particulièrement intéressante, car cette fonction
permet, lorsqu’il faut utiliser le port série en « maître », d’éco-
nomiser énormément de temps et beaucoup de mémoire de
Les microcontrôleurs (µC) modernes peuvent non seulement, programme.
comme leurs « ancêtres », échanger « de façon normale » des
données en série avec d’autres périphériques — à cet effet ils I2C
disposent généralement d’un UART (Universal Asynchronous Le protocole I2C et son bus virent le jour en 1982 (Philips
Receiver Transmitter), mais ils prennent aussi en charge des Semiconductors, NXP depuis pour ce segment) pour les TV
systèmes de bus rapides tels qu’I2C (Inter-Integrated Circuit) « smart » de l’époque. Ce bus permet de réaliser une com-
ou SPI (Serial Peripheral Interface). Les deux systèmes sont munication simple au cœur d’un appareil. Dans la pratique, un
très utilisés, car ils ne requièrent que peu de matériel et de µC communique sériellement avec d’autres circuits intégrés
logiciel et savent se « débrouiller » avec les niveaux de ten- ou d’autres µC, généralement un maître et plusieurs esclaves
sion tels que les connaissent les µC. Il existe nombre de puces dans ce cas-là. Atmel a repris ce système de bus, vu sa sim-
périphériques, des capteurs par ex., équipées de l’un au moins plicité, l’a rebaptisé TWI (Two Wire Interface) ; il ne comporte
de ces deux modes de communication. Nous allons voir ici, que deux lignes de données (plus la masse). Aujourd’hui, plus
comment les traiter en assembleur. de 50 fabricants le prennent en charge.
I2C offre une communication synchrone et bidirectionnelle,
MSSP mais en semi-duplex. Pour communiquer avec des puces indivi-
Chaque membre de la famille PIC utilisé, même le plus petit, duelles, les esclaves sont à l’écoute sur le bus par leur adresse
possède au moins une unité MSSP, certains en ont même deux. et répondent aux appels du maître. SDA est la ligne de don-
Son acronyme (Master Synchronous Serial Port) dévoile la nées et SCK la ligne d’horloge. Il ne peut, à un moment donné,
raison d’être d’un MSSP. Cas majeurs de mise en œuvre d’un circuler qu’un seul paquet de données sur le bus. Les taux
MSSP : de transmission vont de 100 kbits/s jusqu’aux modes haute
vitesse de 5 Mbits/s, les vitesses de 100, 400 et 1000 kbits/s
• Besoin d’un grand nombre de ports d’E/S (plus que le µC étant les plus fréquemment adoptées.
n’en a lui-même),
• Besoin de commander des puces périphériques spéciales SPI
(CA/N, CN/A, horloge en temps réel, capteurs, etc.), C’est à Motorola, en 1979, que l’on doit le bus SPI, protocole
• Besoin d’échanger facilement des données entre plusieurs développé pour l’introduction d’une CPU légendaire, la célèbre
puces et/ou 68K. SPI est une interface série synchrone, mais full duplex
• Échange de données à (« grande ») distance (plusieurs cette fois. Le bus en devient un peu plus complexe, car il lui
mètres souvent). faut, pour la communication bidirectionnelle, outre la ligne
d’horloge SCLK et deux lignes de données MOSI (Master Out-
Un MSSP connaît plusieurs modes. Sa configuration en tant put, Slave Input) ou SDO (Serial Data Out) et MISO (Master
qu’interface I2C ou SPI revêt une importance particulière. Avec Input, Slave Output) ou SDI (Serial Data In), au moins une
des PIC, la configuration en tant qu’esclave ou maître est pos- ligne SS (Slave Select) plus la masse. En fait chaque esclave
sible dans les deux modes. a besoin de sa propre ligne SS (parfois appelée CS pour Chip
De nombreux µC offrent un module SSP ; mais la lettre « M » Select) avec un numéro unique.
Dans la routine init_main, on configure maintenant RA2 en Le premier s’appelle SSPxCON1. Un « 1 » ou un « 2 » au lieu
sortie. À cet effet, le bit 2 du registre TRISA est mis à 0 au du « x » indique que cela concerne MSSP1 ou MSSP2. Les gros
lieu de 1. µC disposent des deux registres SSP1CON1 et SSP2CON1,
movlw B’11001100’ les plus petits n’ont qu’un seul MSSP, donc SSP1CON1. Le
movwf TRISA tableau 3 montre l’organisation du registre. Pour l’instant,
devient de ce fait : seuls les quatre bits de poids faible SSPM<3:0> et le bit SSPEN
movlw B’11001000’ présentent un intérêt.
movwf TRISA
SSPM<3:0> permet de configurer le module MSSP. Sans entrer
Là où l’on accédait auparavant à PORTA,D’005’, il doit main- dans le détail, indiquons que la valeur 1000b correspond au
tenant y avoir PORTA,D’002’. Il s’agit des endroits suivants : fonctionnement en maître I2C. Le taux de transmission, dérivé
de l’horloge du système, répond à la formule :
• À la fin de la routine init_main (désactivation de toutes I2C Clock Speed = Fosc / (4 * (SSPxADD+1))
les cathodes). Le bit SSPEN permet d’activer (=1) le MSSP ou de le désac-
• Dans le sous-programme ishow_digit3 (activation de la tiver (=0).
Tableau 3.
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
R/C/HS R/W R/W R/W R/W R/W R/W R/W
WCOL SSPOV SSPEN CK SSPM<3:0>
Listage 1. ; step 2
movlw B'00101000' ; voir fiche de carac. pg 277
;---------------------------------------------------
; bit 3-0 SSPM<3:0> = 1000
; Paramétrer MSSP2 pour la communication par bus I2C
; 1000 = maître I2C,
; (le PIC est le maître)
; horloge = FOSC/(4*(SSPADD+1))
;---------------------------------------------------
movwf SSP2CON1
;
;
; step 1
; step 3, paramétrer vitesse I2C
i2c_init nop
movlw B'00111111'
banksel TRISB
movwf SSP2ADD
bsf TRISB,D'007' ; SCL
clrf SSP2STAT
bsf TRISB,D'005' ; SDA
clrf BSR ; sélection de BANK 0
movlw H'04'
return
movwf BSR ; sélection de BANK 4
;
SSPxADD est le second registre important. Pour le mode maître En fait, il suffit de mettre à 1 le bit SEN du registre SSP2CON2.
I2C, on se contente d’y placer une valeur de division. Soyons Le sous-programme d55, tout simple, produit la pause à la fin
exhaustifs : en mode esclave I2C, on y trouve l’adresse I2C. de l’étape de communication :
Dernier registre, SSPxSTAT. Pour des expériences avec I2C, il
suffit de veiller est à ce que tous les bits soient mis à 1. d55 movlw D’255’
movwf TIMER2
Une routine d’initialisation I2C en assembleur ressemble au d55_loop decfsz TIMER2,F
code du listage 1. Premier pas, on paramètre les deux ports goto d55_loop
d’entrée (step 1) – condition sine qua non de leur utilisation return
potentielle en mode I2C.
On procède ensuite au paramétrage de SSP2CON1 (step 2) : Dans d55, on a 256 fois l’exécution d’une boucle vide. À une
la valeur 1000b règle le mode MSSP en maître. Simultanément, fréquence d’horloge de 16 MHz, cette temporisation est suf-
le MSSP est activé par la mise à 1 du bit 5 (SSPEN). fisante, avec le taux de transmission sélectionné, pour toutes
Pour terminer, on fixe la vitesse de transmission et on initialise les étapes de communication I2C.
le registre d’état (step 3). Dans notre exemple de code, on Chaque communication I2C est clôturée par une Stop Condi-
obtient 62,5 kHz (Fosc = 16 MHz, SSP2ADD = 63). Le µC est tion. Comme dans le cas de la condition de début, son implé-
maintenant prêt à fonctionner en maître I2C. mentation en assembleur est un jeu d’enfant :
Publicité
figure 2, on voit à quoi ressemble l’afficheur du premier article l’afficheur à LED, mais sont aussi visibles sous forme binaire
de ce cours doté cette fois de ports I2C et SPI après son mon- via le PCF8574N et ses huit LED. À cause de leur mode de
tage sur un morceau de platine à trous. On trouve en bas à connexion, les huit LED s’allument avec un « zéro » et sont
droite de la figure 1, l’extension de port avec huit LED autour éteintes avec un « un ». Il est facile, si on le souhaite, d’in-
d’IC2. Si on la réalise sur un morceau de platine à trous distinct verser cela dans le code.
pour en faire un module autonome, on devrait avoir quelque
chose ressemblant à la figure 3. La seule modification dans la boucle principale de l’application de
démo est l’appel du sous-programme additionnel PCF8574_send,
Les étages de sortie du PCF8574N sont connectés dans une avant l’envoi des données vers l’afficheur à LED. Comme son
configuration à drain ouvert. Cela permet, « sans risque de nom le laisse supposer, il envoie un octet via I2C au PCF8574N :
destruction », de connecter aux sorties, en plus des LED, des
boutons vers la masse. En cas d’action sur un bouton, la LED ;step 1
correspondante s’allume indépendamment de l’état du CI. Pour PCF8574_send call i2c_start
nous simplifier la vie, nous avons, dans la figure 3, remplacé movlw B‘01000000‘
les boutons par un octuple interrupteur DIP. call i2c_send
Le schéma de la figure 1 s’est vu en outre doté des deux résis- ;step 2
tances de polarisation haute, R9 et R10, sachant qu’un bus movf v_value,0
I2C est un système à collecteur ouvert ou à drain ouvert sans call i2c_send
sorties push-pull – et par conséquent une communication sans ;step 3
résistances de polarisation haute est impossible. call i2c_stop
return
Expérience 1 : écriture I2C
La première expérience consiste à envoyer des données à Le sous-programme est presque trivial grâce aux blocs de code
l’extension de port par PCF8574N. À cette fin, seule la der- I2C déjà décrits. On commence par produire la condition de
nière application de démonstration du second article a été début (step 1) pour ensuite adresser l’esclave (PCF8574N).
légèrement étoffée. Cette fois, les données lues à partir de la Dans l’exemple, l’adresse I2C de la puce est 0100000b. En
mémoire flash s’affichent non seulement en hexadécimal sur fait, l’adresse n’a que 7 bits – le dernier « zéro » indique une
1
VDD 16 R1 A
RC0 270R
19 15 R2 B
RA0 RC1 270R
18 IC1 14 R3 C
S1 RA1 RC2 270R
17 7 R4 D
RA2 RC3 270R
4 6 R5 E
RA3/MCLR RC4 270R LD1 SC08-11 LD2 SC08-11 LD3 SC08-11 LD4 SC08-11
3 5 R6 F
RA4 RC5 270R A 1 A 1 A 1 A 1
2 8 R7 G A A A A
RA5 RC6 270R B 14 B 14 B 14 B 14
9 R8 DP B B B B
RC7 270R C 12 C 12 C 12 C 12
C C C C
PIC16F1829 D 10 D 10 D 10 D 10
13 D D D D S2
RB4/SDA1 E 4 E 4 E 4 E 4
12 E E E E
BT1 RB5/SDA2 F 2 F 2 F 2 F 2
11 F F F F R11 LED1
RB6/SCL1 G 13 G 13 G 13 G 13
10 G G G G 270R
RB7/SCL2 DP 9 DP 9 DP 9 DP 9
VSS DP DP DP DP S3
20 CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC
3 5 11 16 3 5 11 16 3 5 11 16 3 5 11 16 R12 LED2
270R
S4
R13 LED3
16 270R
VDD S5
14 4
SCL P0
J1 J3 15 5 R14 LED4
5 5 SDA P1
VCC 13 IC2 6 270R
4 4 INT P2
R9 GND 7 S6
3 3 P3
4k7 SCL 9
2 2 P4
R10 N/C 1 10 R15 LED5
1 1 A0 PCF8574P P5
4k7 SDA 2 11 270R
A1 P6
3 12 S7
I2C I2C-Bus A2 P7
S8
S9
R18 LED8
270R
R19 LED9
270R
160037 - 11
Figure 1. L‘afficheur à LED doté d‘un expanseur de port avec huit LED.
Publicité
Plus de
Figure 2. Si l‘on dote l‘afficheur à LED d‘une interface I2C ou SPI, le schéma
nouveaux produits
en stock que
qui résulte pourrait ressembler à ceci.
n'importe quel
autre distributeur.
C
CM
MY
CY
CMY
Listage 3. ; step 2
movwf SSP2BUF
;-------------------------
spil2 btfss SSP2STAT,BF
; émission et réception de données SPI
goto spil2
;-------------------------
;
;
; step 3
; step 1
movf SSP2BUF,0
spi_send nop
clrf BSR
banksel SSP2CON1
movwf v_spi_buffi
bcf SSP2CON1,SSPOV ; pour la sécurité...
return
bcf SSP2STAT,BF ; pour la sécurité...
;
SPI se différencient par deux caractéristiques combinables à les deux sens. Mais cela n’est utilisé que rarement. Si le maître
volonté : veut uniquement recevoir, il envoie quand même un « octet
factice » à l’esclave, de sorte que la ligne d’horloge cadence.
• Idle Clock level : le bit 4 du registre SSP2CON1 détermine Le sous-programme spi_send s’attend à retrouver l’octet à
quel niveau sur la ligne SCK doit être considéré comme envoyer dans le registre W. Au début (step 1), on a remis
inactif (« zéro » ou « un »). à 0 des bits de dépassement, ceci pour la sécurité, au cas où
• SPI Clock Edge Select : le bit 6 du registre SSPSTAT définit il y aurait eu maldonne lors du dernier transfert de données.
à quel moment (par rapport à SCK) se fait l’échange de Ensuite (step 2) on a écriture de l’octet à transmettre dans le
données sur la ligne SDO. registre SSP2BUF, ce qui a pour effet de démarrer le matériel
MSSP et de pousser le contenu de SSP2BUF sur le bus via la
En règle générale, le niveau inactif du signal CS est un « un » ligne SDO. Le micrologiciel attend dans la boucle jusqu’à la fin
et, avec un « zéro », CS est activé – dans le cas de l’horloge en de la transmission. Il la détecte par le bit BF du registre SSPS-
temps réel (Real Time Clock) DS1306 utilisée ici, c’est l’inverse. TAT qui est mis à 1 à la fin de la communication.
Ici, le mode SPI est configuré pour que SCK à 0 soit inactif, et En raison de la bidirectionnalité, on a simultanément interro-
que l’échange de données se fasse au front montant de l’hor- gation de la ligne SDI et écriture dans le registre SSP2BUF de
loge (passage de « zéro » à « un »). Avec d’autres puces SPI l’information reçue à la fin du transfert.
esclaves, il faudra jeter un œil à la fiche de caractéristiques. Pour finir (step 3), on a lecture du registre SSP2BUF, son
À la fin de l’initialisation (step 3), on a activation de MSSP2 contenu est stocké à l’emplacement de mémoire v_spi_buffi
et mise du signal CS à 0 de sorte que la communication soit pour une utilisation ultérieure.
inactive au départ.
Connexion de l’horloge en temps réel DS1306
Pour la communication via le bus SPI, il suffit d’un seul module La connexion de l’horloge en temps réel (RTC) DS1306 via
de code. On en retrouve le code dans le listage 3 ; il est éga- SPI n’a rien de bien compliqué. On retrouve en figure 4 notre
lement utilisé pour la réception de données. Avec SPI il est en schéma SPI. Si l’on monte la RTC (en bas à droite) sur un
effet possible de transférer des données simultanément dans morceau de platine à trous pour obtenir un module distinct,
1
VDD 16 R1 A
RC0 270R
19 15 R2 B
RA0 RC1 270R
18 IC1 14 R3 C
S1 RA1 RC2 270R
17 7 R4 D
RA2 RC3 270R
4 6 R5 E
RA3/MCLR RC4 270R LD1 SC08-11 LD2 SC08-11 LD3 SC08-11 LD4 SC08-11
3 5 R6 F
RA4 RC5 270R A 1 A 1 A 1 A 1
2 8 R7 G A A A A
RA5 RC6 270R B 14 B 14 B 14 B 14
9 R8 DP B B B B
RC7 270R C 12 C 12 C 12 C 12
C C C C
PIC16F1829 D 10 D 10 D 10 D 10
13 D D D D
RB4/SDA1 E 4 E 4 E 4 E 4
12 E E E E
BT1 RB5/SDA2 F 2 F 2 F 2 F 2
11 F F F F
RB6/SCL1 G 13 G 13 G 13 G 13
10 G G G G
RB7/SCL2 DP 9 DP 9 DP 9 DP 9
VSS DP DP DP DP
20 CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC
3 5 11 16 3 5 11 16 3 5 11 16 3 5 11 16
16
VCC1
14 9
VCCIF SERMODE
2 10
J5 J1 VBAT CE
SCK 7 8 VCC SCK 7 8 VCC 13
IC2 SDO
SDI 5 6 GND SDI 5 6 GND 3 12
X1 SDI
SDO 3 4 SDO 3 4 X1 11
SCK
CS0 1 2 CS0 1 2 5 R9
INT0
BT2 4 DS1306DIP 6
SPI SPI X2 INT1
10k
32.768kHz 15
6p 32KHZ
1 7
VCC2 1HZ
SDI = input for PIC / output Device
GND
SDO = output for PIC / input Device CR2032H
8
160037 - 12
Figure 4. Le circuit de l‘afficheur à LED avec une horloge en temps réel connectée via SPI.