Apprendre à programmer avec le 16F877A - 2e partie

publicité
http://www.didel.com/
[email protected]
www.didel.com/pic/Cours877-2.pdf
Apprendre à programmer avec le 16F877A - 2e partie
Exemples et exercices sous www.didel.com/pic/Cours877-2.zip
1ere partie sous www.didel.com/pic/Cours877.pdf
Gérons des entrées
Câblons le microdule P4S4 sur le portA. Il a 4
poussoirs sur les 4 bits de poids faibles, et 4
interrupteurs.
Copions le portA sur le portD Ex877-201.asm
On voit que les poussoirs sont actifs à zéro
(quand on presse, on a un zéro, affiché en
rouge) et que les interrupteurs ont leur état
‘’1’’ en haut, ce qui est logique.
Le portA n’a que 6 bits connectés. On voit
que les 2 interrupteurs à droite n’ont pas
d’effet, et que le processeur met ces bits à
zéro.
Masquage – instruction ET
Pour n’observer qu’un seul bit ou un groupe de bits, on fait un ET logique avec une valeur que
l’on appelle masque, et que l’on écrit naturellement en binaire. Par exemple, si on veut surveiller
le poussoir tout à droite, câblé sur le bit 0, on écrit
Move
And
Move
PortA,W
#2'00000001,W
W,PortD ; pour voir l’effet
Le résultat est qu’un seul bit passe, et la valeur est nulle ou non, ce qui permet d’aiguiller le
programme dans deux directions selon la valeur du bit.
Le programme Ex877-202.asm allume tous les bits du port C si le poussoir est pressé.
Ce programme est bien écrit avec une étiquette inutile (Allume:) qui met en évidence la structure
du programme avec 2 branches.
En assembleur, l’efficacité du code compte plus et on fait une jolie astuce : on se prépare à écrire
des zéros dans le portC, et si le poussoir est pressé, on change d’avis. On économise 4
instructions, et aussi quelques microsecondes.
Move
PortA,W
And
#2'00000001,W
Move
W,PortD
Move
#2'00000000,W ; Si la touche est relâchée
Skip,NE
; NE si relâché
Move
#2'11111111,W ; On passe ici si la touche est pressée
Move
W,PortC
Jump
Loop
Créez vous-même le programme Ex877-203.asm avec ces instructions, et retenez bien ce truc,
c’est efficace.
Instruction OU
Le OU logique superpose les 2 opérandes, chaque bit étant le OU des bits correspondants.
Cela permet de forcer les bits du masque à un (le ET force les bits à 0. Par exemple, si on veut
masquer les bits de poids forts et les mettre tous à un pour ne voir que les poussoirs du microdule
P4S4, on écrit
Move
Or
Move
PortA,W
#2'11110000,W
W,PortD
Une application fréquente est de décider si une variable 16 bits (un compteur, un long registre à
décalage) ne contient que des zéros. Le OU des deux mots est nul que si chaque mot est nul.
Le programme Ex877-204.asm améliore le programme Ex877-110 vu précédemment . Il arrête le
décalage dès que les deux registres sont vides.
Instruction XOR
Le OU-Exclusif XOR met un 1 si les 2 bits correspondants sont différents. Si l’un des deux mots
(masque) est à zéro ne change rien ; un masque à un change tout.
Si le masque est égal à l’autre mot, le résultat est nul, et il est nul seulement dans ce cas.
Par exemple, on veut savoir si les interrupteurs sont en
haut et le poussoir de droite activé, donc si le
processeur lit 2’00111110 sur le portA.
On écrit
Move PortA,W
XOR
#2’00111110,W
Skip,EQ
Jump Mauvais
Jump BonneCombinaison
Inversion logique – Instruction NOT
On a vu comment inverser tous les bits : Xor #2’11111111,W en plus court Xor #-1,W
L’instruction NOT fait la même chose sur une variable.
Vous voulez savoir si tous les bits d’une variable ou d’un port sont à 1 ?
1ere solution
2e solution
Not
Var
Skip,EQ
Jump
Pas à un
; tout est à un
Inc
Var
Skip,EQ
Jump
Pas à un
; tout est à un
Test d’un bit – Instruction TestSkip,BS
L’instruction TestSkip,BS Var:#bit est longue à écrire, mais elle dit bien ce qu’elle fait : on teste
un bit de la variable ; si ce bit est à 1 (set) on saute l’instruction suivante.
Pour nos poussoirs, c’est donc facile. On veut afficher différents motifs selon le poussoir :
TestSkip,BS
PortA :#0
Jump Poussoir0Actif
TestSkip,BS
PortA :#1
Jump Poussoir1Actif
etc.
Ecrire #0 #1 n’est pas recommandé, il faut toujours donner des noms aux signaux. Une bonne
habitude est de distinguer les noms donnés aux bits en ajoutant au début un b minuscule (pour
les masques un m minuscule). C’est ce qui est fait dans le programme Ex877-205.asm. Cela
devient plus intéressant, mais étudiez bien ce qui permet le clignotement.
L’instruction TestSkip,BC Var:#bit saute si le bit testé est clear (à zéro).
Compter des impulsions
Si on veut compter les actions d’un poussoir, le programme ne doit compter qu’une fois par
action, et ne pas compter quand on presse, ni quand on relâche. Il faut donc deux boucles
d’attente. On peut décider d’agir quand on presse ou quand on relâche.
Loop:
AtPous:
TestSkip,BC
PortA:#bPousD
Jump AtPous
; on vient de presser, que faut-il faire
AtRel:
TestSkip,BS
PortA:#bPousD
Jump AtRel
; on vient de relâcher, que faut-il faire
Jump
Loop
Le programme Ex877-206.asm compte sur le PortC quand on presse, et sur le portD quand on
relâche. Que remarque-t’on ?
Les contacts mécaniques ont des rebonds,
pendant 0.1 à 5 millisecondes (selon la
mécanique interne) et le processeur peut les
voir comme des actions séparées si on
échantillonne trop souvent. On échantillonne
donc à plus de 1ms pour des poussoirs
miniatures, et moins de 0.1s pour ne pas
rater les actions humaines les plus rapides.
Modifiez le programme Ex877-206.asm pour vérifier. Evidemment, il ne faut pas écrire
AtPous:
TestSkip,BC
PortA:#bPousD
Call Del1ms
Jump AtPous
2.16 Testeur de réflexes
On veut savoir combien de temps, ou quand on a pressé sur un poussoir. Il faut dans la boucle
d’attente, surveiller le signal du poussoir, toutes les 10 millisecondes par exemple si on veut être
assez précis, et presser moins de 10ms * 255 = 2.55 secondes si on ne veut pas de
débordement. Pour un détecteur de réflexes, on met un compteur à zéro, on attend quelques
secondes avant d’allumer une LED et on compte à partir de cet instant. Le cœur du programme
Ex877-207.asm est donc :
TestReflexe:
Clr
PortC
Move
#20,W
Call
DelWx01s
; attente 2 secondes
Dec
PortC
; PortC à 1
Clr
PortD
AtPous:
Move
#10,W
Call
DelWx1ms
Inc
PortD ; Durée en multiple de 10ms
TestSkip,BC PortA:#bPousD
Jump
AtPous
Fini: Jump
Fini ; ou Jump TestReflexe
On se pose naturellement quelques questions avec ce programme. Comment compter en décimal
et pas en binaire, comment faire une attente initiale aléatoire, comment recommencer
Agir sur une seule ligne de sortie
Si on sait observer une seule entrée, on doit aussi pouvoir agir sur une seule sortie. Ce sont les
instructions Set Var:#bit et Clr Var:#bit (Clr Var existe, on l’a utilisé pour mettre des ports à
0, mais pas Set Var).
Ces instructions très utiles agissent aussi sur les fanions et ont une notation abbrégée
SetC Force le carry à 1
ClrC Force le carry à 0
Par exemple, comment simuler l’instruction RR Var, qui fait un rotate 8 bits sans passer par le
carry ? On teste le carry et on le copie dans le bit de poids fort.
ClrC
RRC Var ; le bit 7 (poids fort) et à 0
Skip,CC
Set
Var :#7 ; à 1 si carry à 1
Imaginons une application qui demande de permuter les paires de bits. Les bits 76543210 doivent
devenir 67452301. Avec 8 TestSkip et 8 Set bits et quelques instructins supplémentaires, ou peut
résoudre le problème. Une autre solution utilise des masquages (un bit sur deux) et un décalage.
Joli exercice de style pour se faire la main.
Instruction Swap
Les mots de 8 bits représentent souvent deux chiffres hexa ou décimaux (code BCD).
L’instruction Swap Var permute ces deux moitiés. Swap Var,W copie dans W les bits
permutés, sans modifier Var. 76543210 32107654.
Arithmétique
L’arithmétique binaire ou hexadécimale ne nous est pas naturelle, et la limitation des opérations à
8 bits ne facilite pas les choses. En assembleur, on ne fait pas des applications qui nécessitent
des calculs. Les applications pour des petits microcontrôleurs se limitent à corriger des
paramètres et comparer des valeurs, on ne va donc chercher à comprendre que l’essentiel.
Les PICs ne savent qu’ajouter et soustraire des nombres
binaires de 8 bits. en hexa, cela fait des nombres entre
16’00 et 16’FF. On a vu que si on compte, après FF on a
00. La représentation sur un cercle, le cercle des nombres
arithmétiques, va nous être utille.
Mais raisonnons avec un cercle décimal, de 0 à 99, ce qui
permettra de prendre des exemples numériques. Dans
chaque base, les problèmes de dépassement de capacité
de nombres négatifs, de comparaison, sont les mêmes.
Seul le diamètre du cercle change !
Additionnons deux nombres de 2 chiffres. Si le résultat
dépasse la capacité. 100 dans toutes les bases, un report
(carry) est généré.
Ce carry peut vouloir dire qu’il
y quelque chose d’anormal
dans l’application, ou qu’il
faut en tenir compte pour
calculer avec des chiffres
supplémentaires, comme on
verra plus loin.
S’il y a dépassement de
capacité, le bit C (Carry) est
mis à un. Si le résultat est
nul, le bit Z (Zero) est activé.
Pour les tests, on va utiliser le microdule
PotToD8 en série avec un affichage sur le
portA, en se limitant à des valeurs inférieures
à 16’3F, puisqu’il n’y a que 6 bits sur le
portA.
Vérifions avec le programme qui copie A sur
D, le Ex877-201.asm déjà vu. L’interrupteur
sur le PoToD8 doit être en bas.
Additionnons le portA avec une valeur
constante affichée sur le portC. Le résultat
est copié sur le portD. Ex877-210.asm
Comment visualiser le Carry ? Le
programme Ex877-211.asm.affiche sur le
port C le registre Status, qui contient ces
deux bits, carry C en position 0 et Z en
position 2. Oubliez le bit 1 qui va changer
parfois et qui aide les calculs en décimal.
Observez quand on tourne le potentiomètre
et que le total passe de FF à 00 puis 01.
Double précision
Calculer en 16 bits nécessite, comme à la main, d’additionner les poids faibles, de mémoriser le
report et l’ajouter à la somme des poids forts. L’exemple Ex877-212.asm montre de plus que
l’assembleur sait aussi calculer et masquer. Les opérations dans l’assembleur CALM facile à
mémoriser : + - * / .And. .Or. etc (on retrouve le nom des instructions).
Exercice : Fibonacci
La suite de Fibonacci est 1 1 2 3 5 8 13 21 … chaque nouveau nombre est la somme des deux
précédents. Afficher cette suite sur le portD (en hexa .. 8 D 15 …) en s’arrêtant dès qu’il y a
dépassement de capacité. Solution Ex877-220.asm
Complément à 1 et à 2
Le complément à 1 inverse tous les bits, c’est ce que fait l’instruction Not. vue précédemment.
Il ne faut pas confondre avec le complément à 2, ou
complément vrai, résultat de l’opération zéro moins le nombre.
Le figure ci-contre justifie ce terme : 20 est le complément de
80 (en format 2 digits décimal), et ceux qui ont étudié les
logarithmes vont comprendre la suite sans peine : au lieu de
soustraire, on peut additionner le complément.
La figure ci-contre montre qu’au lieu de calculer 40-20,
on peut calculer 40 + (100-20) = 40 + 80.
Cette addition du complément génère un Carry, alors
que la soustraction ne génère pas d’emprunt (borrow).
Contrairement à la majorité des micro-contrôleurs, les
PICs ne soustraient pas, ils ajoutent le complément, et
le carry a la valeur inverse du borrow. C’est tout ce
dont il faut se souvenir si on veut savoir si la
soustraction est possible (a donné un résultat positif).
Le programme Ex877-213.asm effectue les
soustractions 16’10 – (valeur du potentiomètre=0..3F).
Observez C et Z.
Donc, au lieu de soustraire, on peut ajouter le complément. Pour les constantes, l’assembleur sait
calculer les compléments, on a déjà utilisé des Move #-1,W au lieu de Move #16’FF,W.
On écrit donc souvent pour soustraire une valeur immédiate
Move
#-Valeur,W
Move
#Valeur,W
calcule Var - #Valeur Var
Add
W,Var
Sub
W,Var
L’instruction Sub des PICs est inhabituelle. Heureusement CALM (inspiré de Motorola et pas
d’Intel) dit exactement ce que font les instructions arithmétiques. Le 1e opérande est soustrait du
2e, et le résultat est mis dans le 3e opérande, s’il y en a un, autrement dans le 2e.
Les instructions arithmétiques sont les suivantes :
Add #Val,W
; #Val + W W
; pas sur 10F 12F
Add Var,W
; Var + W W
Add W,Var
; W + Var Var
Sub W,#Val,W
; #Val - W W
; pas sur 10F 12F
Sub W,Var,W
; Var - W W
Sub W,Var
; Var - W Var
Nombres négatifs
Encore une complexité à mentionner, mais que nous
n’allons pas analyser. On a placé des nonbres négatifs
sur notre cercle des nombres. Où s’arrêter, comment
savoir si un point sur le cercle est –10 ou F0?
Le processeur ne connaît que des groupes de 8 bits, et
son électronique transforme ces mots sans savoir ce
qu’ils représentent. C’est le programmeur qui décide s’il
travaille avec des nombres positifs de 0 à 16’FF = 255,
ou avec des nombres positifs et négatifs, usuellement
les positifs vont de 0 à 16’7F et les négatifs de
- 1 (= 16’FF) à -16’80 (= 16’80).
La soustraction de deux nombres positifs peut donner un résultat négatif, représenté en
complément à 2. Pour avoir sa valeur absolue, positive, on doit soustraire le résultat de zéro
(prendre son complément à 2)
Clr
Sub
Temp ; variable temporaire
W,Temp,W
; W 0-W = -W ou
–W W
Quand on parlera de vitesse positive et négative d’un moteur, il faudra choisir une représentation
adaptée.
L’arithmétique des nombres négatifs est délicate, des explications, des routines et des macros
sont données sous www.didel.com/pic/Arith.pdf.
En C, il faut déclarer des types de données (8 bits, 16 bits, positifs, signés, etc) et le compilateur
choisit les routines de calcul correspondantes. On choisit une taille suffisante pour les nombres,
pour ne pas avoir de dépassement de capacité, et on achète un processeur plus rapide avec une
mémoire plus grande.
Comparaison
On a souvent besoin de comparer deux
nombres positifs ou négatifs et on utilise la
soustraction pour cela.
En positifs
Move
Sub
Nb1,W
W,Nb2,W
Si C est à 1, Nb1 > Nb2
Si Z est à 1, Nb1 = Nb2
En négatifs, c’est compliqué
(www.didel.com/pic/Compare.pdf )
L’exercice Ex877-214.asm dit si le nombre lu
sur le portA est entre 16’10 et 16’20. On affiche
sur le port D des motifs différents.
Saturation
Souvent, un compteur doit avoir une butée et cela s’implémente avec quelques instructions. Une
addition peut aussi devoir être saturée ; c’est un peu plus délicat puisque le résultat d’une addition
peut être petit, s’il y a dépassement de capacité. Avant d’accéder dans une table, il peut être
important de saturer la valeur pour éviter de lire en dehors des valeurs prévues.
Le document www.didel.com/pic/Satu.pdf traite les cas les plus fréquents.
Multiprécision
Ne parlons pas de la multiprécision et des nombres négatifs difficiles à maîtriser. Les PICs ne
sont pas faits pour calculer, mais pour manipuler des bits.
Des routines et macros très utiles sont décrites sous www.didel.com/pic/Arith.pdf
BCD (Décimal codé binaire)
Le code BCD représente 2 chiffres décimaux (0 à 9) sur les deux moitiés d’un octet. On peut
additionner, soustraire, des nombres BCD, des exemples de routines sont donnés sous
www.didel.com/pic/BCD.pdf . Compter et décompter en BCD est souvent utile, si le résultat doit
être présenté sur un affichage 7 segments. Convertir de binaire en décimal est souvent
nécessaire si on interagit avec un clavier écran. Voir www.didel.com/picg/doc/DopiBinD.pdf
Moyennes
Calculer la moyenne de nombres consécutifs, par exemple pour filtrer un capteur, n’est pas
évident. Le document www.didel.com/pic/Moyennes.pdf montre comment faire.
Résumé du chapitre
On a vu comment lire des entrées et supprimer les rebonds de contact.
Les opérations logiques permettent de masquer des bits, ou modifier leur valeur.
On teste et modifie des bits isolés avec les instructions TestSkip,BS (ou ,BC), Set Clr
Les bits sont numérotés de 0 (poids faible) à 7 (poids fort). Le bit n a un poids 2n, noté 2**n dans
l’assembleur.
Le cercle des nombres aide à comprendre le rôle des fanions C (Carry) et Z (Zero bit, qui vaut 1 si
le résultat est nul) dans les opérations de comptage/décomptage et d’addition ou soustraction.
Le PIC soustrait en additionnant le complément, ce qui a pour effet que le carry est inversé par
rapport à notre habitude scolaire du borrow.
La 3e partie liste les instructions, sans exemples. Il faut parcourir cette partie, et y revenir en cas
d’incertitude, ou d’erreur d’assemblage due à une mauvaise syntaxe.
jdn 101001
Téléchargement