Bases : nombres, constantes, variables, programme

publicité
http://www.didel.com/
[email protected]
http://www.bricobot.ch/
[email protected]
www.didel.com/pic/Bases.pdf
Bases : nombres, constantes, variables, programme
La lecture de ce document devrait logiquement se faire aveant de commencer à programmer. Dans les
faits, avoir exécuté au préalables des programmes simples facilite la compréhension de ce document.
1. Signification d’un mot binaire
Le processeur travaille sur des mots binaires sans savoir ce qu’ils représentent. Si le programmeur
écrit Move #2’00111001,W il peut avoir des intentions très différentes :
Il veut afficher le chiffre 4 sur un affichage 7 segments et la
prochaine instruction sera un transfert sur le registre de sortie
qui commande l’affichage. Les bits sont numérotés de 0 à 7.
A noter qu’un bon programmeur aurait déclaré
Quatre = 2’00111001 et écrit
Move #Quatre,W
Il veut préparer la valeur 83 dans un décompteur pour attendre
par exemple 83 fois une seconde. Il aurait du écrire
Move #83,W l’assembleur aurait traduit en binaire. Avec les
poids binaire, on peut faire de tête la conversion dans les deux
sens : de 83, on ne peut pas extraire 128, on extrait 64, il reste
19, on ne peut pas extraire 32, on extrait 16, etc.
A droite on a les bits de poids faible, et à gauche les bits de
poids forts.
Il veut calculer en décimal codé binaire (BCD) avec deux
groupes de 4 bits pour les chiffres de 0 à 9. Il devrait donc
écrire de préférence
Move #16’53,W car le BCD se code comme
l’hexadécimal, mais en n’utilisant que les chiffres de 0 à 9.
Il veut préparer la lettre S pour l’envoyer via une ligne série et
il utilise le code ASCII. Ce code représente les lettres, les
chiffres et les signes et il est connu de l’assembleur. Il faudrait
donc écrire Move # "S",W
Note 1: Les notations utilisées ici sont celles de CALM, logiques et intuitives. D’autres assembleurs utilisent des
notations du type 03FH ou H’3F’.
Note 2: Wikipedia vous donne plus d’information sur BCD, ASCII, etc. Il faut souvent ajouter un mot qui focalise la
recherche : porte ET, registre PIPO.
2 Bits et octets
Tous les systèmes informatique travaillent en binaire, avec seulement des zéros et des uns,
plus facile à coder de façon fiable par des états électriques, magnétiques ou lumineux. Un bit
est l'élément d'information qui n'a que deux valeurs: 0 et 1. Plusieurs bits sont utilisés pour
coder une information quelconque, voire reconnaître un objet, puisqu'il suffit de coder le
numéro de l'objet. Un octet (byte en anglais et en franglais des informaticiens) est un mot de 8
bits, qui peut donc représenter 256 combinaisons, le plus souvent les nombres de 0 à 255 en
décimal. Les signaux binaires peuvent être transmis à des distances quelconques, mémorisés,
transformés par combinaison de signaux. Les opérations principales sont l'inversion (NOT), le
OU, le ET, le OU Exclusif, l'addition. Appliqués à des mots binaires (juxtaposition de bits), ces
opérations dites logiques permettent de superposer, masquer, inverser des bits dans des mots
binaires. Le ET sera très utilisé pour masquer des bits qui ne sont pas significatifs, et doivent
être mis à zéro. Le OU permet de fusionner deux mots, ou de forcer un certain nombre de bits
à un. Le OU Exclusif XOR permet d'inverser certains bits, alors qui le NOT inverse tous les
bits. L'addition est un peu trop compliquée à expliquer pour le moment.
3 Les Fanions
Les fanions Z N C sont mis à jour à la fin de l’opération.
Z (zero) est activé à 1 si le résultat de l’opération est nul.
Par exemple, Move #0,B va activer Z
N (negatif) est activé si le bit 7, dit «bit de signe» est à 1.
Ceci concerne les nombres négatifs qui seront vus plus
loin, mais cela peut être pratique de savoir que ce bit est
à un (c’est le cas dans l’exemple d’addition ci-contre)
N n’existe pas sur les PIC 10F 12F 16F
C (carry/borrow) est activé si l’addition déborde, ou que
la soustraction s’est terminée par un emprunt.
C est inversé sur les PIC, qui ajoutent le complément
Les instructions Move n’ont pas de raison de modifier le
Carry. Mais pour les PICs, le fanions Z est mis à jour
pour l’instruction Move Reg,W.
4 Opérations logiques
L’opération ET (AND) donne un bit à 1 dans la destination si les deux bits correspondant sont à 1.
On l’a utilisée en page 28 et 38 pour mettre à zéro des bits non utiles (on dit masquer ces bits).
L’opération OU (OR) donne un bit à 1 dans la destination si l’un des deux bits correspondant est à 1.
Par exemple pour savoir si A et B sont tous deux à zéro, on peut écrire
Or A,B ; superpose A et B
Jump,EQ TousLesDeuxAZero
L’opération OU exclusif (XOR) donne un bit à 1 dans la destination si l’un des deux bits correspondant
est à 1, mais pas les deux.
Cette instruction est très utile sur un écran, pour faire passer un pointeur de souris par dessus
l’information, sans la perdre.
Opérations logiques et symboles
5 Opérations à un opérande
L’instruction Clr dest mets tous les bits à zéro. Clr W existe.
L’instruction Not dest inverse tous les bits. Not W n’existe pas, on écrit Xor #-1,W
L’instruction Inc dest ajoute 1. Si le résultat est nul (le compteur a fait un tour), le fanion Z est mis
à 1.
L’instruction Dec dest soustrait 1. Si la valeur initiale est 0, après décrémentation, le résultat est
H’FF (des 1 partout).
Attention, Dec dest,W copie dans W et la valeur augmentée n’est que dans W. De même pour
Not dest,W et Inc dest,W, qui sont des instructions souvent très utiles.
Inc W et Dec W doivent être remplacés par Add #1,W et Add #-1,W
Comment faire pour qu’un compteur se bloque en arrivant au maximum H’FF ?
On teste si le compteur est arrivé à zéro et on décompte pour annuler le comptage :
Inc
A
Jump,NE Next
Dec
A
Next : suite
; saute à Next si fanion Z=0
Comment faire pour qu’un décompteur se bloque à zéro ? De même pour qu’un compteur se
bloque à la valeur H’7F ou à la valeur B’31 (par exemple) ? C’est ce qu’on appelle saturation.
(détails sous www.didel.com/pic/Sature.pdf )
6 Décalages
L’instruction RL dest « Rotate Left » fait tourner le
mot de 8 bits sélectionné sur lui-même. Le bit qui fait
le tour est copié dans le Carry, RR dest « Rotate
Right » fait la même chose dans l’autre sens.
Ces deux instructione n’existent pas dans les PICs
Les instructions RLC « Rotate Left through
Carry » traversent le Carry il faut 9 décalages
pour retrouver la même valeur. RRC « Rotate
Right through Carry » fait la même chose dans
l’autre sens.
Ces instructions permettent par exemple de compter le nombre de bits à un dans le registre A.
On initialise un compteur par 8 et on décale dans la boucle. Chaque fois que le carry est à un, on
incrémente un compteur.
Les instructions RLC dest,W et RRC dest,W existent et ne modifient pas dest, seulement W.
7 Codage
Avec n bits, on peut obtenir 2^n combinaisons différentes, qui peuvent être associées de façon
naturelle ou arbitraire à des nombres ou objets.
La liste de ces combinaisons est en général ordonnée comme l'on compte d'habitude. En
décimal avec 3 chiffres et en mettant les zéros non significatifs, on compte
000 001 002 .. 009 .. 010 011 012 .. 098 099 100 101 .. 999
Chaque nombre peut être associé à un objet, par exemple une maison dans une rue. On sait
bien distinguer d'après leur position les unités, dizaines, centaines, dont le poids est 1, 10 ,100
(puissance des 10).
En binaire, il n'y a que les chiffres 0 et 1, et avec trois bits il n'y a que 2^3= 8 combinaisons:
000 001 010 011 100 101 110 111 que l'on associe aux valeurs 0..7 ou que l'on
considère comme des codes pouvant représenter 8 objets différents. Le poids des bits
(exprimé en décimal) selon leur rang est 1, 2, 4 (puissances de 2).
Si l'on veut compter plus loin, coder plus d'objets, il suffit de prendre plus de bits, en moyenne
3,3 fois plus qu'en décimal, c'est simple. Avec 10 bits, on compte jusqu'à 1023, cela fait 1024
combinaisons, le kilo des informaticiens. Avec 20 bits, c'est un Mega. Avec les futurs
microprocesseurs 64 bits, un mot mémoire peut représenter beaucoup de choses. Avec les
processeurs 8 aussi: il suffit de prendre plusieurs mots consécutifs, selon les besoins. Si l'on
veut compter les secondes dans un mois, environ 2,6 millions, soit un nombre décimal de 7
chiffres, cela donne un nombre de 23 bits. On codera cette durée dans 3 mots de 8 bits,
appelés registres ou variables 8 bits
8 Nombres
Les processeurs travaillent en binaire, par mots de 8 bits pour le PIC. On peut toujours
prendre plusieurs mots de 8 bits pour avoir plus de précision ou plus d'information. Le
programmeur aime bien l'hexadécimal, qui permet d'écrire 2 chiffres plutôt qu'une suite de huit
0 et 1. Le décimal est utilisé pour les paramètres de l'application, car nous y sommes habitués,
et les compteurs, voltmètres, horloges, donnent toujours des valeurs en décimal. La traduction
de décimal en binaire se fait par l'assembleur ou par un programme. Pour les nombres 8 bits,
le tableau suivant donne les correspondances. Pour éviter toute confusion, les nombres
binaires sont précédés de 2'. les nombres hexa de 16'. Les nombres décimaux peuvent être
précédés d'un 10', mais cela n'est pas nécessaire puisque le décimal est la base dite "par
défaut". Le tableau suivant compare quelques valeurs 8 bits dans les 3 systèmes de
numération. Il est important d'être à l'aise avec ces notations. La conversion du binaire en
décimal se fait en tenant compte des poids: les chiffres binaires, en commençant par la droite,
ont les poids 1,2,4,8,16,32,64,128. Le bit de poids fort est parfois considéré comme le bit de
signe, avec une représentation des nombres dite en complément à 2 que nous verrons plus
loin. Ceci ne s'utilise que rarement avec le PIC, qui n'est pas prévu pour faire des calculs. Il
faut toutefois se souvenir que -1 se code 16'FF = 2'11111111 (on dit que c'est le complément
à 2 de 1). Le compteur d'une voiture neuve qui commencerait par faire un kilomètre en marche
arrière afficherait 99999 kilomètres! C'est la représentation naturelle des nombres négatifs,
mais il faut lever l'ambiguité entre positifs et négatifs en mettant une frontière entre deux, en
général à 128 (le bit de poids fort est alors appelé bit de signe.
Par exemple, si on veut coder la vitesse d'un moteur, une solution est de mettre dans une
variable une vitesse positive (entre 0 et 255 ou moins) et dans une autre variable la direction.
L'autre solution n'utilise qu'une variable contenant la vitesse signée. 00000001 est la vitesse
minimale positive, et 11111111 (-1) la vitesse minimale négative. 1000000 est l’arrêt.
Exercice: Ecrire en binaire 16'C4. Ecrire en hexadécimal -6. Quelle est la valeur en décimal de
16'64? Quelle est la valeur en binaire de 20?
9 Nombres négatifs
Si vous prenez une voiture neuve et que vous faites 1 km en marche arrière, le compteur va indiquer
99999 km. De même, si un registre contenant zéro est décrémenté (ou on soustrait 1), il va afficher FF.
C’est la représentation naturelle de nombres négatifs, dite en complément à 2.
On peut aussi travailler avec une représentation signée, en mettant la valeur absolue dans un registre
et le signe dans un autre registre.
Comment savoir si H’FF représente le nombre –1 ou le nombre 255 ? Le processeur ne peut pas vous
aider. Pour lui, c’est 8 bits à un, rien de plus. Le programmeur décide et doit gérer les dépassements
de capacité différemment selon qu’il a mis dans les registres des nombres positifs ou signés (positifs
ou négatifs).
La meilleure représentation est de placer les
nombres 8 bits sur un cercle. Avec les nombres
positifs, si on passe la frontière ente FF et 00, il y a
débordement que le Carry va signaler.
Avec les nombres en complément à 2, la frontière
est entre 7F et 80, quand le bit 7, dit bit de signe,
change.
Si on veut comparer deux nombres, il faut savoir
s’ils sont positifs ou signés.
Les processeurs de plus de 8 bits ont des
instructions qui facilitent la gestion des nombres
négatifs, voire des nombres en virgule flottante.
Avec notre processeur simplifié, il faut tester le bit
de signe N et le Carry pour décider si le résultat
d’une addition ou soustraction est valide.
10 Notion de programme
Imaginons un petit robot qui sait avancer et tourner. Pour lui donner différents comportements,
on peut imaginer une machine qui décode et exécute (on dit interprète) 4 comportements, que
l'on va coder en binaire.
00
Attend une certaine durée
01
Tourne de 90 degrés
10
Avance
11
Stoppe
Pour dessiner un carré, il faut exécuter en séquence
10 00 01 10 00 01 10 00 01 10 00 01 11.
C'est un programme en langage machine. Pour éviter de se perdre dans des bits, on utilisera
des mots clés et c'est un programme (assembleur, compilateur) qui fera la traduction en
langage machine. Il est plus lisible d'écrire
Avance
Attend
Tourne
Avance
Attend
Tourne
Avance
Attend
Tourne
Avance
Attend
Tourne
Stoppe
Remarquons que certaines instructions mettent notre robot dans un mode (Avance, Stoppe).
D'autres instructions durent le temps d'une action (Attend, Tourne). Dans les deux cas, il serait
bon de pouvoir modifier la vitesse ou la durée d'attente (ce qui changerait la dimension du
carré); une instruction doit donc pouvoir avoir un paramètre, qui est soit fixe (le paramètre est
une constante qui fait que le carré dessiné aura toujours un dimension qui dépends du
programme), soit variable (le paramètre est une variable qui permettra par exemple de
dessiner des carrés emboités en incrémentant (ajouter 1) la dimension variable); il faudra donc
rajouter cette instruction qui incrémente, ou plutôt une instruction qui additionne.
Exercice: Comment programmer un 8 (un peu carré bien sûr) ?
11 Fonctionnement du processeur
Un microcontrôleur est formé d'une mémoire contenant les instructions du programme, d'un
séquenceur et d'une mémoire (formée de registres) pour les variables.
Dans le cas du PIC, les instructions sont codées dans une mémoire programme en lecture
seulement de 14 bits (la mémoire dite flash). Un compteur d'adresse (PC Program Counter)
sélectionne l'instruction à exécuter, et passe automatiquement à l'instruction suivante, au
rythme de l'oscillateur (une instruction toutes les microsecondes avec un oscillateur à 4 MHz).
Au "reset", le compteur est remis à zéro et le processeur commence à la première instruction.
Il passe à la suivante sauf si c'est une instruction de saut (Jump, Goto que nous appellerons ici
AllerA), qui permet de continuer le programme à une adresse quelconque, ou recommencer
une séquence d'instructions.
Schéma simplifié du processeur PIC
Le processeur commande un registre de travail W (Work register) et une mémoire en lecture
et écriture pour les registres associés au processeur et au programme de l'utilisateur
(variables). Deux registres, appelés ports communiquent avec l'extérieur. Sur le PIC 16F84, le
Port A a cinq bits et le port B huit, qui peuvent être des entrées ou des sorties.
Les opérations que l'on peut faire sont les opération simples vues dans la figure 1. L'unité de
calcul s'appelle ALU (Arithmetic Logic Unit) et les instructions combinent W et un registre, avec
le résultat dans W ou dans le même registre. Le décodeur d'instruction commande l'aiguillage
et l'opération à effectuer. Ces opérations élémentaires du processeur ne seront décrites que
dans PICG-C; pour permettre de faire plus vite des choses intéressantes sans se perdre dans
toutes les subtilités d'un processeur, les premiers programmes utilisent des groupes
d'instructions (appelés macro-instructions) désignées par un nom explicite.
12 Constantes et variables
Les instructions permettent de copier une valeur constante faisant partie d'une instruction dans
le registre W, de faire une opération sur W (ET, OU, Addition) et d'agir sur un registre, en
combinaison avec W. W et les registres sont comme des tiroirs, dans lesquels on peut mettre
des valeurs. On assignera des noms aux tiroirs (nom des variables) et quand on agira sur une
variable, c'est de son contenu dont il s'agira. Seuls les registres à partir de l'adresse 16'C sont
accessibles à l'utilisateur, mais PICGAB cache ce genre de détails qui dépendent du
processeur. Les numéros de ces registres sont toujours remplacés par des noms, définis par
le fabricant jusqu'à l'adresse 16'B, et par l'utilisateur après.
En résumé, les registres sont comme les tiroirs d'une armoire, le nom de variable associé,
c'est l'étiquette collée sur le tiroir, et le contenu, c'est un mot de 8 bits. Le processeur travaille
avec les numéros de tiroir, mais l'utilisateur se dépèche de coller une étiquette qui correspond
à ce que l'on va ranger dans chaque tiroir. Un tiroir n'est jamais vide. Il contient un mot binaire
qui représente un nombre ou un mot dont certains bits décideront si on allume certaines
lampes ou si on fait tourner un moteur dans un sens ou l'autre. En "ouvrant le tiroir", le
processeur peut lire la valeur, ce qui ne la modifie pas. Il peut copier le contenu de W ou le
résultat d'une opération dans un tiroir voulu.
Par exemple, si le bit 0 de la variable PortA (qui est un registre dont les sorties sont
connectées avec l'extérieur) allume une lampe quand ce bit est à un, il faut écrire
Move #2'00000001,W
Move W,PortA
Evidemment, s'il y a d'autres lampes sur le même PortA, elle vont toutes être éteintes. Avec
les instructions logiques, on évite ce problème: on lit le PortA, on modifie le bit 0 de notre
lampe, et on réécrit la nouvelle valeur dans le PortA
Move PortA,W
Or
#2'00000001,W ; force le bit de poids faible, ne modifie pas les autres
Move W,PortA
Le processeur a une meilleure façon de faire, vue plus loin.
Un saut "conditionnel" est essentiel pour que le programme dépende d'une condition interne
ou externe (Si Egal AllerA). Une caractéristique du PIC est d'avoir une instruction de "skip
conditionnel" qui selon la condition testée, passe par dessus l'instruction suivante. PICG-B
cache cette instruction très efficace et utilise le saut conditionnel si ... allera, plus facile à
comprendre.
Question: comment éteidre cette lampe? Indication: utiliser un ET logique avec le bon masque.
13 Constantes et variables
Les constantes sont des nombres, que le processeur va copier, utiliser pour un masque ou
pour une comparaison. Elles sont connues immédiatement lors de la traduction du programme
(d’où leur nom ‘’valeur immédiate’’), et sont codées dans l'instruction. En CALM, elles sont
précédées du signe # (prononcé valeur). Par exemple #2'1001000 ou #VitesseInitiale, avec la
valeur du symbole définie ailleurs (par un VitesseInitiale = 3 par exemple).
Les variables par contre sont des cases mémoire vides, dans lesquelles le processeur peut lire
et mettre des valeurs. Elles ont toujours un nom, bien que ce nom corresponde à un nombre
attribué par l'assembleur, et que l'on pourrait utiliser ce nombre si on le connaissait. D'où la
nécessité du signe # pour distinguer les valeurs immédiates des variables. Le Basic et le C
distinguent les constantes et variables par le contexte ou par des déclarations initiales.
13 Symboles
L'assembleur CALM impose la contrainte que les noms sont une suite de caractères sans
espace. Ils peuvent inclure des chiffres et les deux signes _ et ? (souligné et point
d'interrogation). Les minuscules et majuscules sont identifiées. Les lettres accentuées ne sont
pas acceptées. Dans nos habitudes, les majuscules sont utilisées pour la première lettre des
mots significatifs, afin d'augmenter la lisibilité.
14 Numérotation des bits
Les bits sont numérotés de la droite vers la gauche. Le bit de droite est le bit 0, le bit de poids
faible, avec un poids 1 (2^0| noté 2**0 pour l'assembleur). Le bit de gauche (dans un mot de 8
bits) est le bit 7, le bit de poids fort, avec le poids 128 (=2**7). La double étoile est utilisée pour
l'exposant. Les signes +, -, *, / ont la même signification qu'en Basic (addition, soustraction,
multiplication, division). Il faut bien comprendre que le programme que l'on écrit est analysé
par un programme (l’assembleur) qui sait mieux calculer que le processeur. Si on écrit
Move #342/5,W
ce programme va effectuer le calcul, trouver 68 (le résultat est 68,4, mais le ,4 est ignoré car le
processeur ne travaille qu'avec des nombres entiers), convertir en binaire et préparer pour le
processeur, qui ne comprends que le binaire, l'instruction Move #2'01000100,W. (les bits 6 et
2 sont à 1, donc la valeur est 2^6+2^2 = 64 + 4 = 68.
15 Action sur des bits
Le PIC est très efficace pour agir sur un bit d'une variable ou registre. Cela s'utilise en
particulier pour tester ou modifier une ligne d'entrée/sortie. Pour désigner un bit, il faut dire
dans quelle variable se trouve ce bit et quel est le numéro du bit (valeur constante immédiate).
Pour adresser la ligne RA3, liée au bit 3 du PortA, il faut écrire PortA:#3. On peut mettre cette
ligne à 1 avec l'instruction Set PortA:#3. Les exemples plus loin permettront de se familiariser
avec cette notation efficace. En PIC-Basic, on écrit High 0 pour activer RB0, mais cela génère
40 instructions et prend 25 microsecondes! L'instruction PIC Set PortB:#0 ne prend qu'une
seule microseconde (avec un oscillateur à 4 Mhz).
16 Instructions, procédures et macros
Le processeur exécute des instructions. Le programme, ensemble de toutes les instructions et
déclarations, est en général décomposé en procédures correspondant aux tâches, fonctions,
groupes d'opérations à exécuter. Une procédure est appelée routine ou macro-instruction en
assembleur, la distinction sera vue plus tard. Le comportement d'une procédure ou macro est
enrichi par des paramètres. Par exemple, la procédure qui commande un moteur a un
paramètre "vitesse" et éventuellement un 2e paramètre "nombre de tours à effectuer à cette
vitesse". Les exigences de l'assembleur CALM sont d'écrire le nom de la procédure sur une
seule ligne (les espaces ou tabulateurs devant sont ignorés), et d'utiliser un ou plusieurs
espaces et/ou tabulateurs avant de donner la liste des paramètres, séparés par une virgule
(l'assembleur accepte des espaces et/ou tabulateurs devant et/ou derrière cette virgule, mais
en général on n'en met pas).
17 Etiquettes
Dans un programme, il faut pouvoir aller à une instruction donnée, pour passer par dessus des
instructions que l'on ne veut pas exécuter à cause d'une condition, ou pour répéter un groupe
d'instructions. L'instruction AllerA (la plupart des langages disent Goto ou Jump) permet de
faire ces sauts. L'instruction destination (l'endroit où on veut aller) est précédée par une
étiquette, c'est à dire un nom vu comme un symbole par l'assembleur, suivi du signe : (deux
points). On le verra dans les programmes.
18 Paramètres par défaut
Ce concept est important. Une procédure est le plus souvent utilisée avec un paramètre
évident (le moteur tourne à sa vitesse maximum), et c'est embêtant de devoir chaque fois
taper ce paramètre. La procédure peut être définie pour que, par défaut d'indication explicite
d'un paramètre, le paramètre "évident" (paramètre par défaut) soit utilisé. S'il y a plusieurs
paramètres dans une procédure, deux virgules consécutives indiquent qu'il y a entre les deux
virgules un paramètre par défaut. Dans les 3 cas suivants, les 1er, 2e, 3e paramètres sont "par
défaut":
Moteur ,Vmax,Distance
Moteur Vmin,,Distance
Moteur Vmin,Vmax, (la dernière virgule peut être omise)
Si on écrit simplement Moteur sans paramètre explicite, les trois paramètres seront pris par
défaut.
L'ordre des paramètres doit être respecté car l'assembleur leur assigne des numéros d'ordre.
La gamme de valeurs peut parfois être vérifiée par l'assembleur (si on donne une valeur trop
grande pour une valeur 8 bits), et il y aura un message d'erreur plus ou moins facile à
interpréter.
Ces 3 dernières sections ont probablement été indigestes. Il est temps de passer à la
pratique !
jdn090819/100925
Téléchargement