| 1 | = Programmation Arduino = |
| 2 | |
| 3 | == Préambule == |
| 4 | |
| 5 | Vous devez utiliser la version d'arduino qui se trouve : |
| 6 | {{{#!bash |
| 7 | > /opt/arduino-1.6.8/arduino |
| 8 | }}} |
| 9 | |
| 10 | Les documents nécessaires se trouvent : |
| 11 | - [https://github.com/adafruit/Adafruit_SSD1306 Repository API Ecran OLED] |
| 12 | - [https://github.com/adafruit/Adafruit-GFX-Library Repository API Graphique] |
| 13 | - [http://www.mon-club-elec.fr/pmwiki_reference_arduino/pmwiki.php?n=Main.ReferenceMaxi Langage Arduino] |
| 14 | |
| 15 | == Objectif == |
| 16 | |
| 17 | Le but de cette séance est de faire de la programmation sur Arduino en utilisant 3 entrées-sorties : |
| 18 | - La LED présente sur le module. |
| 19 | - L'écran OLED |
| 20 | - Le port série qui relie le module et le PC. |
| 21 | |
| 22 | Nous voulons aussi expérimenter la programmation "multi-tâches". Les guillemets expriment le fait qu'il s'agit plus d'une structure du programme que d'une vraie programmation multi-tâches dans la mesure où il n'y a pas de système d'exploitation. Toutefois, les "tâches" seront programmées de sorte à être indépendantes de leur contexte d'utilisation et elles seront "ordonnancées" par la fonction loop(). |
| 23 | |
| 24 | == Exécution ''multi-tâches'' == |
| 25 | |
| 26 | Nous allons docnc voir comment il est possible de programmer des applications multi-tâches coopératives dans l'environnement Arduino sans pour autant alors les services d'un OS. Le code a été volontairement simplifié à l'extrême afin de bien comprendre le principe. |
| 27 | |
| 28 | Commençons par exprimer les besoins. Dans une applications pour micro-contrôleur, il est nécessaire : |
| 29 | - d'exécuter des tâches périodiquement ; |
| 30 | - d'exécuter des tâches lorsque des événements surviennent ; |
| 31 | - de mesurer le temps séparant deux événements ; |
| 32 | - de synchroniser l'exécution de deux tâches (une tâche T1 s'exécute et produit des données qui sont récupérées par une tache T2) ; |
| 33 | - etc. |
| 34 | |
| 35 | Chaque tâche est représentée par une fonction qui code son comportement. |
| 36 | Dans l'environnement Arduino, la fonction loop() s'exécute en boucle, c'est elle qui va séquencer l'exécution des tâches. |
| 37 | La fonction loop() demande donc l'exécution des tâches à tour de rôle. |
| 38 | Les tâches n'ont pas le droit de conserver le processeur sinon celà crée un blocage du système. |
| 39 | La structure générale d'une tâche est la suivante : |
| 40 | |
| 41 | {{{#!c |
| 42 | void tache(arguments) { |
| 43 | // test de la condition d'exécution |
| 44 | if (evement_attendu_absent) return; |
| 45 | // code de la tache |
| 46 | .... |
| 47 | } |
| 48 | }}} |
| 49 | |
| 50 | Pour les tâches périodiques, nous pouvons écrire une fonction qui exploite un timer interne du processeur qui s'incrémente chaque microseconde. Cette fonction nommée `waitFor(int timer, unsigned long period)` prend deux paramètres `timer` et `period`. Le premier un numéro de timer (il en faudra autant que de tâches périoodiques). Le second est une période en microsecondes. |
| 51 | |
| 52 | `wairFor()` peut être appelée aussi souvent que nécessaire, elle rend 1 une seule fois par période (second paramètre). |
| 53 | Si elle n'est pas appelée pendant longtemps alors elle rend le nombre de périodes qui se sont écoulées. |
| 54 | |
| 55 | Dans l'application suivante nous avons deux tâches périodiques `Led()` et `Mess()`. |
| 56 | La première fait clignoter une led dont le numéro est passé en paramètre à 5Hz. |
| 57 | La seconde affiche bonjour à une fois par seconde. |
| 58 | {{{#!c |
| 59 | // -------------------------------------------------------------------------------------------------------------------- |
| 60 | // Multi-tâches cooperatives : solution basique |
| 61 | // -------------------------------------------------------------------------------------------------------------------- |
| 62 | |
| 63 | // unsigned int waitFor(timer, period) |
| 64 | // Timer pour taches périodique |
| 65 | // arguments : |
| 66 | // - timer : numéro de timer entre 0 et MAX_WAIT_FOR_TIMER-1 |
| 67 | // - period : période souhaitée |
| 68 | // retour : |
| 69 | // - nombre de période écoulée depuis le dernier appel |
| 70 | // |
| 71 | #define MAX_WAIT_FOR_TIMER 16 |
| 72 | unsigned int waitFor(int timer, unsigned long period){ |
| 73 | static unsigned long waitForTimer[MAX_WAIT_FOR_TIMER]; |
| 74 | unsigned long newTime = micros() / period; // numéro de la période modulo 2^32 |
| 75 | int delta = newTime - waitForTimer[timer]; // delta entre la période courante et celle enregistrée |
| 76 | if ( delta < 0 ) delta += 1 + (0xFFFFFFFF / period); // en cas de dépassement du nombre de périodes possibles sur 2^32 |
| 77 | if ( delta ) waitForTimer[timer] = newTime; // enregistrement du nouveau numéro de période |
| 78 | return delta; |
| 79 | } |
| 80 | |
| 81 | void Led(int timer, long period, byte led) { |
| 82 | static byte val = 0; // valeur à mettre sur la led |
| 83 | if (!waitFor(timer,period)) return; // sort s'il y a moins d'une période écoulée |
| 84 | digitalWrite(led,val); // ecriture |
| 85 | val = 1 - val; // changement d'état |
| 86 | } |
| 87 | |
| 88 | void Mess(int timer, long period, const char * mess) { |
| 89 | if (!(waitFor(timer,period))) return; // sort s'il y a moins d'une période écoulée |
| 90 | Serial.println(mess); // affichage du message |
| 91 | } |
| 92 | |
| 93 | void setup() { |
| 94 | pinMode(13,OUTPUT); // initialisation de la direction de la broche |
| 95 | Serial.begin(115200); // initialisation du débit de la liaison série |
| 96 | } |
| 97 | |
| 98 | void loop() { |
| 99 | Led (0,100000,13); // Led est exécutée toutes les 100ms |
| 100 | Mess(1,1000000,"bonjour"); // Mess est exécutée toutes les secondes |
| 101 | } |
| 102 | }}} |
| 103 | |
| 104 | == Utilisation de l'écran == |
| 105 | |
| 106 | Nous allons utiliser un écran OLED connecté en I2C, 128x32 **ssd1306** |
| 107 | - La bibliothèque de l'écran se trouve en tapant la requête `ssd1306 arduino`[[BR]] à l'adresse |
| 108 | [https://github.com/adafruit/Adafruit_SSD1306]. |
| 109 | Vous devrez prendre également la bibliothèque GFX à l'adresse [https://github.com/adafruit/Adafruit-GFX-Library] |
| 110 | qui est la bibliothèque graphique. |
| 111 | - Vous pouvez exécuter l'exemple proposé dans la bibliothèque. Cette bibliothèque fonctionne pour plusieurs |
| 112 | types modèles. Vous allez choisir le bon exemple : 128x32 I2C. |
| 113 | |
| 114 | **Questions** : |
| 115 | - Quel est le numéro de l'abonné I2C de l'écran ? |
| 116 | - Modifier le programme initial pour afficher "bonjour" sur l'Oled toutes les 2 secondes sans changer le comportement de existant. |
| 117 | |
| 118 | |
| 119 | |