Atelier du 29 janvier 2008
La programmation c'est si simple : atelier 2
Comment ça marche?:
Il est possible d'écrire des programmes en utilisant plusieurs langages, le code machine qui est natif au CPU que nous utilisons sera peut-être difficile pour nous à utiliser. Il existe des interpréteurs qui effectueront la traduction de nos commandes en code machine, ce qui simplifiera notre tâche de programmeur. Ces interpréteurs utiliseront un langage qui s'approche de l'anglais en entrée et généreront du code hexadécimal compatible avec notre processeur. Parmi les plus utilisés, on retrouve l'assembleur, le basic, le langage C. Prenons notre exemple d'addition du chapitre précédent et regardons les étapes (commandes) que nous devront soumettre au processeur.
Le CPU doit regarder son unité d'entrée et
"lire" la valeur présente
Conserver cette valeur "lue" dans une case mémoire.

Le CPU doit regarder son unité d'entrée et
"lire" la valeur présente
Conserver cette valeur "lue" dans une case mémoire.

Transférer le contenu de la case mémoire dans son accumulateur arithmétique
Additionner le deuxième nombre.

Conserver le résultat obtenu, dans une autre case mémoire.

Transférer le contenu de la case mémoire dans son unité de sortie.

Supposons maintenant que nous écrivons ce programme pour un processeur simple n'ayant que quelques fonctions. Les codes utilisés pour les différentes commandes seront incluses dans les fiches techniques de ce processeur. Supposons un CPU qui utilise les commandes suivantes.
0- Lire l'unité d'entrée dans le tampon (buffer)
1- Emmagasiner le buffer dans la case mémoire #
2- Charger l'accumulateur avec la case mémoire #
3- Additionner l'accumulateur avec la case mémoire #
4- Soustraire de l'accumulateur le contenu de la case mémoire #
5- Emmagasiner le contenu de l'accumulateur dans la case mémoire #
6- Imprimer le contenu de la case mémoire #
7- Arrêt
Notre programme devrait s'écrire comme suit; 0, 1-1, 0, 1-2, 2-1, 3-2, 5-3, 6-3, 7. Ce qui nous donne, lire le premier chiffre, l'emmagasiner dans la case 1, lire le deuxième chiffre, l'emmagasiner dans la case 2, charger l'accumulateur avec le contenu de la case 1, Additionner le contenu de la case 2, emmagasiner le contenu de l'accumulateur dans la case 3, Imprimer le contenu de la case 3, Arrêter. Si une des étapes est omise, le résultat sera affecté.
Si nous utilisons un autre langage comme le basic, le programme s'écrirait comme suit:
INPUT A   (première variable lue, qui sera emmagasiné dans une case mémoire appelée A)
INPUT B  (deuxième variable lue, qui sera emmagasiné dans une case mémoire appelée B)
C= A+B    (Le résultat de l'addition, sera emmagasiné dans une case mémoire appelée C)
PRINT C   (Le résultat est imprimé)
END             (fin)
Vous pouvez voir que l'utilisation d'un interpréteur, peut grandement nous simplifier la tâche!! En effet le compilateur traduira INPUT A, par 0, 1-1, il choisiras lui-même dans quel case mémoire cette valeur lue sera emmagasinée et il établira une relation entre cette case mémoire et notre variable A. Il interprétera de la même façon INPUT B, par 0, 1-2, en plaçant la deuxième valeur dans une case appelée B. La troisième commande est la plus intéressante, C= A+B, cette dernière fera pratiquement tout le travail, elle additionne A et B et emmagasine le résultat dans la case C. Finalement on dirige le résultat vers l'unité de sortie avant l'arrêt.
L'utilisation d'un interpréteur, quoi que très efficace, peut dans certains cas ralentir le processus d'opération. En effet l'interpréteur chargera en mémoire plusieurs parcelles de programme, qui ne sont pas utiles pour notre programme d'addition. Ces fonctions supplémentaires utiliseront du temps de processeur, qui sera par le fait même ralenti. Quand nous avons besoin d'un système qui fonctionne en temps réel, nous devront peut-être utiliser le code machine. Dans la majorité des cas, compte tenu de la vitesse des processeurs modernes, cela est négligeable. La plupart des processeurs peuvent traiter un million d'instructions par seconde (MIPS) et parmi les plus puissants, quelque milliards d'opération par seconde. Très souvent le processeur sera ralenti par des mécanismes beaucoup plus lents, comme le clavier, l'affichage et les ports de communications.
Ce processeur est vraiment très simple, en n'ayant que 7 commandes, la plupart des CPU possèdent au moins 256 commandes, le nombre de commandes étant limité majoritairement par la largeur du "BUS". La plupart de ces commandes effectuent des transferts de données entre les différents registres de contrôle, la mémoire et les unités d'entrée/sorties. Des fonctions mathématiques, logiques, des processus de comparaison et de décision.
Si nous regardons le schéma interne d'un processeur (tableau 8) nous verrons les mécanismes qui s'offre à nous. Grâce à nos instructions nous pourrons contrôler la façon que les données se déplacent à l'intérieur de notre processeur. Notre programme sera emmagasiné dans un endroit bien précis de la mémoire et notre processeur effectueras les tâches séquentiellement, une après l'autre, dans l'ordre qu'ils seront entrés. Si nous voulons modifier cet ordre, nous aurons besoin de fonctions nous permettant de changer cet ordre, des sauts conditionnels.
Nous verrons dans le chapitre suivant, comment prendre contrôle sur ces millions de transistors, pour effectuer ce que l'on désire. Chaque processeur étant construit différemment, il faudra s'ajuster, en consultant les données techniques des manufacturiers, pour adapter ou modifier nos programmes.

Tableau 8

Flash program memory: Lieu ou est emmagasiné de façon permanente, notre programme
Program counter: Registre qui tient compte de l'ordre des opérations à effectuer
RAM: Mémoire volatile pour conserver temporairement nos données (variables)
PORT A, PORT B: Unités d'entrée / sortie
ALU: Arithmetic logical unit, prends en charge tous nos calculs
W register: Registre tampon (buffer)
Timer 0,1, 2: Registres (compteurs) utilitaires qui peuvent générer des interruptions
USART: Universal serial asynchronous receiver and transmitter (port série)
MUX: Multiplexeur, agissant comme des commutateurs
Comment on fait ça?
Il existe plusieurs sorte de programmeur informatique; le génie, le méthodique et le "gosseux". Le génie peut analyser une tâche a accomplir, écrire le code (qu'il connait par cœur!), le charge dans l'ordinateur et ça marche du premier coup sans bavures. Si ça existerait on l'aurait rencontré. Le "gosseux" passe généralement beaucoup plus de temps que le génie et fini par avoir un programme qui fonctionne, pas trop mal, en considérant les heures de travail. En général il fait une étude sommaire du problème à résoudre et commence à écrire des pages de code, en suivant grosso-modo les instructions du manufacturier, et après il débogue, il débogue…Jusqu'à ce qu'il arrive à la version 40.6 et qu'il juge que c'est satisfaisant, de toute façon, il est tanné. Le dernier type semble plus intéressant, il utilise une méthode simple mais efficace, c'est ce modèle que nous allons tenter de suivre.
Cette méthode peut varier d'un individu à l'autre, dépendamment de ses connaissances, mais le contenu de la méthode reste le même. Cette méthode nous permettra d'analyser, la meilleure façon de générer le code machine, en utilisant les outils à notre portée.
1- Prendre connaissance du problème à résoudre
2- Analyser l'utilisation des entrées / sorties
3- Est-ce que l'on doit interfacer des LCD, claviers, afficheurs?
4- Est-ce que le programme doit agir en temps réel?
5- Sur quel CPU, le code rouleras?
6- Faire un ordinogramme
7- Est-ce possible de faire des modules?
8- Écrire le code, en suivant la syntaxe de l'interpréteur.
9- Charger le code dans le CPU
10- Savourer la victoire!
1-Prendre connaissance du problème à résoudre
Le problème lui-même fait parti de la solution, il est important d'analyser les informations contenues dans ce qui nous est demandé, pour trouver une solution pratique. C'est peut-être l'étape la plus cruciale de notre travail. Plusieurs personnes se retrouveront avec une page blanche devant eux et ne sauront pas par quel bout commencer. Supposons le problème suivant : Faire un traducteur binaire à décimal et hexadécimal, les entrées seront par commutateurs et la sortie sur LCD. Déjà on peut voir que nous auront au moins huit commutateurs d'entrée, un neuvième pourrait servir de touche d'exécution (enter). Ce neuvième commutateur n'est pas spécifié dans les données du problème, mais pourrait être une amélioration que l'on décide d'ajouter. La sortie se feras sur un afficheur LCD, est-ce que nous avons les données techniques de cet afficheur? Combien de lignes de sortie auront nous besoin pour le contrôler? Quel sont les commandes compatibles avec ce type d'afficheur? Comment voulons-nous présenter les informations sur l'afficheur et quel est sa dimension (caractères/lignes)?
Pour le but de l'exercice supposons que l'afficheur est compatible avec ceux déjà utilisé par le groupe, c.-à-d. un afficheur de 16 caractères /2 lignes, de la famille Hitachi 44780.
L'affichage souhaité sera sur 2 lignes:                 BIN:__0101__0101 (_ = espace)
                                                                   DEC:_085 HEX:_55
2-Analyser l'utilisation des entrées / sorties
Notre module d'affichage requiert 6 lignes de sorties et nous avons besoin de huit ou neuf lignes d'entrées pour les données. Le total nous donne 14 ou 15 lignes selon le cas. Sur un PIC™ 16F628 le port B possède des résistances de "pullups" (reliées à VCC). Nous pouvons se servir de cette caractéristique à notre avantage, ce qui nous épargneras des composantes extérieures. De plus ce port B est le seul qui possède huit bits, pouvant servir autant en entrée qu'en sortie. Le port A pourras nous servir pour l'affichage, car il comporte six bits utilisant des I /O conventionnels, un bit en entrée seulement (RA5, /MCLR) et un bit "Open Drain" (RA4) qui ne peut nous donner 5 volts à la sortie, sans résistance externe. Vous voyez ici l'importance de vérifier les informations techniques des manufacturier, avant de se lancer dans l'écriture du programme lui-même. Une simple vérification pourras vous éviter de tourner en rond pendant des lunes.

Tableau 9

Le montage proposé n'est qu'une des façons possibles d'assembler nos projet, nous utiliseront celui-ci pour les fins d'exercice. Dans ce montage il est important de noter que le port B servira d'entrée pour les données, donc nous devrons placer dans le programme, la commande qui active les "pullups". Autre fait à remarquer, quand les interrupteurs seront en-haut (on), la valeur logique qui se présentera au port B sera un zéro (ground). De la même façon quand l'interrupteur sera en bas (off), cette valeur logique sera un (vcc). Sommes-nous d'accord sur ce fonctionnement? Il serait peut-être souhaitable que le contraire se produise; en-haut = 1 (high) et en bas =0 (low). Sans modifier les branchements matériels, nous pourrons dans notre programme, inverser le résultat de la lecture du port B, c.-à-d. que les 1 deviendront des 0 et les zéros deviendront des 1. Vous venez de prendre votre première décision "software" pour contourner un problème matériel.
Nous utiliseront le port A, pour contrôler l'afficheur LCD. Comme nous ne pouvons nous servir des pattes RA4 et RA5 convenablement en sortie, ils nous restent six I / O pour faire le travail. Cette situation est idéale nous avons besoin de six lignes de sortie pour contrôler le LCD. Mais il y a un mais, les pattes RA6 et RA7 servent normalement pour l'utilisation d'un cristal externe, si nous voulons se servir de ces pattes, nous devront utiliser l'horloge interne du PIC™. Si cela nous convient, en admettant que la précision de l'horloge n'est pas un problème, le montage proposé est adéquat et le choix du CPU est valable. Comme le LCD peut-être utilisé en mode 4 bits (DB4-DB7), seulement 4 lignes de I / O seront nécessaires, heureusement nous n'en avons pas en surplus! J'ai pris soins d'aligner les bits du LCD avec le port A, c.-à-d. que le LSB du LCD est branché sur le LSB du port A. Cet arrangement nous sauvera des étapes lors de l'écriture à l'affichage.
3-Est-ce que l'on doit interfacer des LCD, claviers, afficheurs?
Une bonne partie de ce travail à été effectué dans l'étape 2. Par contre il serait intéressant à ce moment-ci de ramasser de l'information sur cet afficheur. Quelle sont les commandes pour utiliser cet afficheur, comment doit-on l'initialiser, comment pouvons-nous effacer l'affichage, comment changerons-nous de ligne? Toutes ces choses nous seront utiles quand nous commencerons la programmation. Dans cette étape vous devez prendre en considération tous les dispositifs, qui viendront s'attacher au CPU, les commutateurs, les "LEDS", le haut-parleur, etc… Chacun de ces dispositifs, nous obligeras de vérifier les spécifications de ces items, pour s'assurer qu'ils fonctionneront adéquatement, sans dépasser les limites du CPU. Par exemple il est impensable de contrôler la bobine d'un relais fonctionnant sur 12 volts directement par une patte du PIC™. Celui-ci ne peut accepter des voltages supérieurs à 5 volts (VCC) et il ne peut
pas donner le courant nécessaire pour activer le relais, nous devront ajouter un transistor pour réussir un tel montage.
4-Est-ce que le programme doit agir en temps réel?
Dans le cas qui nous préoccupe, il n'est pas essentiel que le travail soit fait en temps réel. Nous attendrons que l'opérateur modifie la position des commutateurs, pour générer un nouvel affichage. Si par contre nous effectuons un programme d'horloge, ou de chronomètre, notre horloge interne ne peut conserver une stabilité adéquate, il faudra nous servir d'un cristal externe. La plupart des programmes qui doivent agir en temps réel, doivent réagir sur le champ à une donnée extérieure et réagir dans la milliseconde qui suit, dans notre cas, ce n'est pas essentiel.
5- Sur quel CPU, le code roulera?
Ceci pourrait être la première chose à déterminer, ce choix nous imposeras des limitations, de vitesse, du nombre d'entrées / sorties, la grosseur de la mémoire (RAM, FLASH, EEPROM) et la largeur du bus. Si nous choisissons par exemple un PIC™ 16F628, il sera pratique d'avoir accès au document technique gracieusement fourni par le manufacturier. Est-ce que ce PIC™ possède assez de mémoire pour notre programme, on devrait peut-être utiliser un 16F648 à la place. Est-ce que ce PIC possède suffisamment d'entrée / sorties? A quelle vitesse notre programme à besoin d'opérer, est-ce que nous avons besoin de précision? Pour l'instant le choix du CPU semble convenable, pour faire la tâche planifiée. Qu'arrive-t-il si nous désirons ajouter une fonction qui nécessite une patte supplémentaire? Devrons-nous recommencer à zéro? Dans ce cas précis il nous reste une patte libre RA4 qui nous laisse un peu de latitude pour des ajouts. Le programme en soit ne sera pas trop volumineux, compte tenu du travail à effectuer, donc la mémoire FLASH du 16F628 devrait être amplement suffisante.