Bonjour, on a vu la structure d'un programme C, et les principales structures de commandes. On va parler maintenant des types de données, 8, 16, 32 bits, et qui s'appliquent aux variables et aux tableaux. Revenons d'abord à la structure du microcontrôleur. Donc, on a vu le bus 8 bits, l'unité arithmétique, les registres et, si on a une structure 8 bits, on peut très bien, au niveau des variables, prendre, plusieurs mots successifs, pour avoir, par exemple 32 bits. Et, au niveau du calcul, couper le mot 32 bits en tranches, et puis faire plusieurs opérations successives, pour, une opération 32 bits. Alors évidemment actuellement, les transistors, se sont miniaturisés et on parle de processeurs 16 et 32 bits. Le bus est plus large, les registres sont plus longs, l'unité arithmétique est à la bonne largeur, les variables aussi. Et si, maintenant on veut travailler avec 8 bits, et bien on va utiliser, une partie des variables et des mémoires. Et, vu du C, cela ne nous concerne pas. Simplement, le compilateur aura plus de travail pour couper les mots en morceaux, ou ignorer certaines parties de l'information. Donc on va travailler fonctionnellement, avec des types de données, le plus simple, et bien, c'est un type 1 bit, vrai, faux. C'est celui qu'on trouve dans des comparaisons, qu'on appelle les types booléens; qui évidemment, étant donné qu'on n'a pas des bascules qui traînent un peu partout dans le processeur, on a des mots binaires, les variables booléennes, que l'on ne déclarera jamais en fait, sont représentées sous forme d'un 0 pour faux, et puis d'un différent de 0, pour vrai. En général on prend la valeur 1, mais des opérations peuvent très bien conduire à des valeurs différentes, qui seront considérées comme vraies. Alors, pour les calculs, la représentation de l'information, on utilise le mot byte, 8 bits, on l'a déjà vu, une valeur entre 0 et 255, que l'on peut représenter sous forme d'un cercle. Si on incrémente et qu'on déborde, et bien, on recommence, ça vous avez vu. Et puis maintenant, au niveau des applications, on va déclarer les types bytes. Là je veux clignoter un certain nombre de fois, et je vais faire une boucle for, dans lequel il faudra un compteur, la variable i, et tant que je n'ai pas atteint mon nombre de clignotements, je vais faire mon petit clignotement, ici, et incrémenter le compteur, pour cette condition. Alors, le type char, a été défini historiquement, pour représenter des caractères qui sont entre 0 et 127, et, pour une raison surprenante, qui peut dépendre encore du compilateur, il est considéré comme signé, et c'est parfois prudent d'écrire signed char, et puis pour un byte, unsigned char. Donc, voilà alors, la représentation peut se faire aussi sur un cercle, avec les nombres négatifs qui sont sur cette moitié du cercle, et c'est au niveau de la transition ici, que l'additionneur pourra signaler des erreurs, mais, votre programme, sauf programmation assez astucieuse, ne se préoccupe pas du tout de ce genre de dépassement de capacité, qui sont très difficiles à bien gérer. Alors, un petit quizz, pour voir si vous avez bien compris, je définis un char ss, donc un nombre 8 bits signé, qui vaut 200, un nombre 8 bits non signé, qui vaut 200 également, et je me trouve dans une instruction avec un if. Est-ce que ss, est identique à bb? Est-ce que cette expression est vraie ou fausse? Alors, voilà les réponses possibles, réfléchissez un instant. Alors, si vous avez répondu "not accepted", je serais assez satisfait, puisque on a défini ici, un ss égal 200, qui est en fait sur le cercle des nombres arithmétiques du 8 bits, le processeur ne voit que des bits et des nombres, donc le 200 va se trouver à peu près par là; et puis, dans cette partie-là, et bien, on a des nombres négatifs, ça correspond en fait à moins 57. Donc, un bon compilateur devrait vous poser la question : Est-ce que vous avez bien compris ce que c'était un nombre signé? Puisque ici, vous avez écrit une valeur, qui n'est pas une valeur positive, elles sont limitées, à 127, comme on l'a vu. Alors, en fait le compilateur s'en fiche, et on a le choix de savoir si c'est vrai ou faux. Alors, on doit comparer cette valeur moins 57, avec, la valeur 200. Si on représente ça sur un axe, et bien vous avez 0, 200, et puis, ça semblerait assez logique de dire, il y a ici jusqu'à moins 128, et on va trouver ici le 57. Alors là, c'est évident que 200 est supérieur à moins 57, et qu'ils sont différents. Alors est-ce que vraiment le compilateur, raisonne comme moi? Je suis prudent. Je n'ai pas lu les 600 pages des spécifications du C, donc je vais préférer écrire un petit programme, et puis mettre derrière cette instruction if, allumer la lettre si c'est vrai, éteindre une lettre si c'est faux; et, je pourrais être sûr que mon interprétation est correcte. Donc ça c'est une technique qu'il faut toujours utiliser, écrire des petits programmes, pour vérifier qu'on a bien compris. Vous avez naturellement les types 16 bits et 32 bits, qui s'appellent word, int, alors, le int est abondamment utilisé dans Arduino, parce que on ne veut pas expliquer trop de choses, et puis, c'est le type passe partout. En général, on travaille avec des mots qui sont relativement courts, donc on ne voit pas la différence, entre entier positif et entier signé, tant que le 16 bits n'est pas retouché, vous avez, les longs qui sont signés et qu'il faut appeler unsigned long, quand vous voulez récupérer ces derniers bits. Et, comme petit exemple de l'utilisation assez rare du long, vous avez, une primitive d'Arduino, ce n'est pas du C, c'est les compilateurs Arduino et compatibles, qui ont rajouté un petit programme, qui utilise une ressource interne du processeur, pour calculer le temps à partir du reset. Donc au moment où vous lâchez le processeur, vous avez la valeur 0, et ensuite, ça incrémente de 1 toutes les millisecondes, et vous pouvez mesurer le temps écoulé. Donc là, et bien, on utilise ça assez souvent, comme vous le faites quand vous partez en voiture, vous regardez l'heure du départ, vous regardez l'heure d'arrivée, et puis, le temps de parcours qui vous intéresse, et bien, c'est une bête différence. Donc, il nous faudra définir dans le type long, le temps, le temps précédent, le temps de départ, et puis on va calculer le temps écoulé, avec une soustraction. Donc on va mémoriser le temps actuel, on a déjà mémorisé le temps précédent, on fait la différence. Et si maintenant, on continue le voyage, et qu'on veut de nouveau connaître le temps, on remémorise le temps actuel dans la variable. Alors, vous me direz, tiens, on pourrait économiser une variable, parce que, je peux faire ma soustraction, en regardant ma montre, plutôt que d'avoir déjà copié l'heure sur un bout de papier ou dans ma mémoire. Donc on pourrait écrire directement millis moins previous time, et puis réinitialiser le nouveau temps, avec millis. Alors, ce que j'aimerais vous faire remarquer, c'est que, entre ces deux instructions, le temps n'est pas le même, puisque il a fallu exécuter un certain nombre d'instructions, pour analyser cette ligne, et commencer en analysant un certain nombre, avant de transférer le temps. Donc, ça, ça peut être 10, 20 instructions du processeur, donc, 5, 10 microsecondes, qu'on peut considérer comme tout à fait négligeables. Mais, attention, si vous avez autorisé les interruptions, et c'est ça qui arrivera dans des applications intéressantes, vous pouvez avoir une interruption qui surgit entre ces deux instructions, et, c'est comme avec votre PC, et bien tout à coup votre clavier est mort, parce qu'il y a les interruptions qui font que, on ne s'occupe plus de votre programme principal. Donc, dans ce cas-là, évidemment, si vous avez plusieurs millisecondes, voir des secondes d'attente, ça va complètement fausser les mesures de temps, alors qu'ici on a fait une photographie précise à un instant, et puis, on a copié la variable. Bien, parlons un petit peu des tableaux de variables. Alors, une variable, on vient de le voir, on peut la déclarer avec son point virgule à la fin, et puis on peut lui assigner une valeur qui sera valable au début du programme, qui peut être transformée par la suite, puisque, si j'écris dans le programme var 2 égal 33, et bien, j'ai réinitialisé cette variable à une nouvelle valeur. Alors maintenant, c'est assez pratique d'avoir des tableaux de variables, de ne pas devoir numéroter variable 1, 2, 3, alors que ça va ensemble, donc, si on écrit tableau crochet 4, et bien, vous réservez 4 fois 16 bits signés et c'est déclaré, vous pouvez donner des valeurs, à ces 4 modes 16 bits, et le compilateur est assez intelligent pour compter et puis mémoriser, que, il y a la valeur 4 ici, dans cet index, on parle de d'indexage dans un tableau, et maintenant je peux, en écrivant xx égal tableau crochets 2, je peux aller chercher le deuxième élément mais souvenez-vous qu'on compte toujours en binaire à partir de zéro, donc je vais récupérer la valeur 33. Et puis maintenant je peux aussi assigner une valeur dans mon tableau, écrire tableau 4 égal 15, et ce qui va se passer là, ben, mon 4, vous remarquez qu'il est en-dehors du tableau, le compilateur C, ne va en général rien dire du tout, il va aller mettre dans la position mémoire suivante, la valeur 15 et va peut-être écraser une variable que vous utilisez dans le programme et ce sera une merveilleuse plantée, donc il n'est pas conseillé de le faire, mais, c'est facile à surveiller. Application pour un tableau : on veut jouer quelques notes. Et puis on va mettre ces notes dans un tableau pour dire, ben, si je veux un ré, ben la fréquence est de 247 hertz. Alors en fait, ce qu'on devra programmer, c'est une période, puisqu'il faudra attirer le haut-parleur, la membrane du haut-parleur, la relâcher, et faire ça avec une période que l'on peut déterminer à partir de la fréquence. Alors devoir chaque fois calculer cette période, est absurde, même si le temps était raisonnable, il nous faut faire un tableau, autant mettre dans ce tableau directement les périodes, et c'est, on a donné un nom explicite, les périodes des notes do, ré, mi, fa, qui vont se trouver dans les positions 0, 1, 2, 3. Donc maintenant je peux définir mon tableau en disant, iii nombres entiers, période note, j'ai quatre notes que j'ai calculées et puis je peux maintenant faire une boucle for puisqu'il faudra que je répète beaucoup de fois cette période qui dure 4 microsecondes, 4 millisecondes, pardon là mon tableau est en microsecondes, pour avoir une note que l'on peut entendre pendant une seconde au moins. Donc on va faire un compteur qui va travailler avec la demi-période, et puis pour changer l'état du haut-parleur. Alors de nouveau il y a deux choses qui devraient vous choquer, le petit point-virgule, ça c'est traditionnel, et puis il y a surtout ce 1, qui est là, alors que ce que je voudrais, c'est avoir quelque chose, un nom explicite qui me dit de quoi il s'agit. Donc ça c'est facile de faire un define, et puis de dire ben, define, ré, 1, et il y a une facilité de, d'Arduino, et du C, qui est une énumération, le nom n'est pas essentiel, mais j'ai mon énumération ici, j'ai donné l'équivalence entre des noms que je comprends et des numéros d'ordre que mon processeur va comprendre. Pourquoi est-ce que j'ai écrit doo? Ben c'est à cause du do, do while, hein, c'est un mot réservé par le C, et vous le voyez à l'éditeur il est coloré alors que les noms que vous définissez vous-mêmes ne sont pas colorés, donc si vous définissez, si vous mettez do là-dedans vous aurez un message d'erreur naturel. Bien, autre application qui est souvent documentée sur internet, vous voulez allumer un affichage, set seg1, c'est le nom habituel de ces segments, et là vous trouvez comme exemple de programmation, il faut commencer par dire que les pins sur lesquels le processeur est câblé sont sortis, alors les pins 2, 3, 4, jusqu'à 9 dans l'ordre sont utilisés et sont programmés en sortie. Et puis là, je ne me souviens plus du commentaire qu'il y avait avant mais je devine que le a est câblé sur la pin 2, le b sur la pin 3, ça semblerait assez logique, et évidemment, je préfèrerais que ça soit documenté un petit peu mieux, qu'on dise define segment a sur la pin 2, segment b sur la pin 3, comme ça on sait exactement ce qui a été câblé, et maintenant puisqu'on vient de parler des tableaux de données, ben, là ça me fait vraiment penser à un tableau, et puis je vais le définir, en disant, c'est mes numéros de pins, segment a, segment b, segment 3, donc j'ai défini ici 2, 3, 4, mais je reconnais de quoi il s'agit, heu, ça me fait un tableau de 7, et puis maintenent, je peux écrire une boucle for, en disant je pars avec i égal zéro, et j'écris pinMode, pin de zéro, OUTPUT,pin de zëro ça veut dire que je vais chercher dans ce tableau le segment a, qui a été défini comme étant pin numéro 2, donc j'exécute exactement cette instruction avec pinMode, pin crochets zéro, OUTPUT, et puis évidemment avec la boucle for je prends 1, je prends 2, je prends 3, l'ordre, les numéros de pins n'ont pas du tout besoin d'être dans un ordre croissant, j'ai défini ici les pins qui peuvent être absolument quelconques. Donc voilà une écriture qui est beaucoup plus élégante, et, on peut aller plus loin, parce que j'ai défini mes pins, je peux définir le digit 7 comme étant un tableau. Dans ce tableau, j'ai a, b, c, qui sont actifs, allumés, ça ne veut pas dire que je vais mettre un 5 volts ou un 0 volt, c'est à un autre niveau qu'on réfléchira à ça, et puis ensuite là des segments qui sont éteints. Et puis maintenent, ben, pour allumer ce digit, je peux faire une petite boucle for, où au lieu de faire du pinMode comme tout à l'heure, et bien je vais faire un digitalWrite, pour dire ben, dans la pin numéro zéro, par exemple, je vais mettre l'état du segment zéro. Donc on retrouve le i ici, mais une fois dans un tableau une fois dans l'autre. Alors maintenant, ben, accrochez vos ceintures! Parce que je vais définir un tableau bidimentionnel. J'ai 10 digits à représenter, et dans chaque digit j'ai 8 bits. Donc voilà mon tableau, vous reconnaissez le 7, il est là, là je le définis comme un seul élément, mais maintenant je peux l'indexer, et puis je pourrai venir avec un programme adéquat, sélectionner le 7, qui sera une variable qui vaut 7, et puis balayer pour afficher. Donc là, ben, j'ai fait un petit programme pour afficher les chiffres dans l'ordre, for, ça ça sera, le compteur de chiffres, on termine par un delay d'une seconde comme ça ben on verra 0, 1, 2, 3, affichés pendant une seconde, et puis on a une deuxième for boucle à l'intérieur qui va balayer les segments ici pour les mettre à 1 ou à 0, ça c'est le digitalWrite qui agit sur des bits, il y a d'autres façons d'agir sur des bits, on les verra, qui sont compatibles avec le C, ça c'est compatible avec Arduino, mais ça nous donne une écriture assez élégante dans le fond où on va balayer la bonne ligne du tableau, et étant donné qu'on a une deuxième boucle for et bien on va afficher tous les chiffres successifs, heu, il y a apparamment une petite erreur, qui est, vous reconnaissez, c'est qu'ici j'ai oublié qu'il y avait 10 chiffres, de 0 jusqu'à 9, donc il faut que je mettes un 10 ici, je reviens sur cette table, qui permet d'afficher les, les digits, les chiffres de 0 à 9. Vous n'avez peut-être pas réalisé que, cette séquence de 1 et de 0, ce ne sont pas des bits, mais ce sont des bytes, des mots de 8 bits. Donc cette table prend 8 fois 10 positions en mémoire, 80 bytes, et si sans réfléchir, vous évcrivez int ici, et bien vous aurez 160 bytes utilisés en mémoire. Donc c'est clair que, on va éviter de programmer comme cela, on verra comment, supprimer en fait les virgules, supprimer un seul mot de 8 bits pour chaque digit, appliquer ces bits directement sur les segments, et être beaucoup plus efficaces. Alors encore une chose : en écrivant byte digit, ou int digit, vous réservez de la place en mémoire. En mémoire variable. Si vous précisez const, et bien vous allez définir des constantes et c'est clair qu'on ne va pas s'amuser à modifier des segments pendant l'exécution, donc en écrivant const, cette information va passer dans l'espace programme, qui a dix fois plus de place que l'espace des variables, et c'est la façon la plus efficace de procéder, déclarer const toutes les fois que vous avez des constantes. Donc vous voyez que, le C permet des écritures qui sont, heu tout à fait compactes et intéressantes, et puis c'est ce que l'on va continuer à découvrir en interagissant avec différents types de matériel.