= Programmation Arduino = == Objectif == Le but de la séance est d'éctire un programme arduino avec plusieurs tâches, et utilisant plusieurs périphériques. Vous allez lire la valeur de la lumière sur une échelle de 1 à 100 sur un arduino et de l'afficher sur l'écran de l'autre arduino. Il y a donc au moins 2 noeuds, un émetteur et un récepteur. == Documents de référence == * [http://www.nordicsemi.com/eng/Products/2.4GHz-RF/nRF24L01P Site Nordic nRF24L01Plus] * [https://www.sparkfun.com/datasheets/Components/SMD/nRF24L01Pluss_Preliminary_Product_Specification_v1_0.pdf Spécification nRF24L01plus] * [https://github.com/TMRh20/RF24 Repository API TMRh20/RF24] * [http://tmrh20.github.io/RF24/classRF24.html Documentation API TMRh20] * [https://github.com/adafruit/Adafruit_SSD1306 Repository API Ecran OLED] * [https://github.com/adafruit/Adafruit-GFX-Library Repository API Graphique] * [http://www.mon-club-elec.fr/pmwiki_reference_arduino/pmwiki.php?n=Main.ReferenceMaxi Langage Arduino] == Utilisation de l'écran == Nous allons utiliser un écran OLED connecté en I2C, 128x32 **ssd1306** * La bibliothèque de l'écran se trouve en tapant la requête `ssd1306 arduino`[[BR]] à l'adresse [https://github.com/adafruit/Adafruit_SSD1306]. Vous devrez prendre également la bibliothèque GFX à l'adresse [https://github.com/adafruit/Adafruit-GFX-Library] qui est la bibliothèque graphique. Cette bibliothèque fonctionne pour plusieurs types modèles. Vous allez choisir le bon exemple : 128x32 I2C. En outre, vous allez peut-être devoir faire une petite modification dans le code. La ligne au début de '''setup()''' `display.begin(SSD1306_SWITCHCAPVCC, 0x3D);`[[BR]] doit être remplacée par : `display.begin(SSD1306_SWITCHCAPVCC, 0x3C);`[[BR]] Il s'agit de l'adresse de l'écran sur le bus I2C. * Dans l'exemple ci-dessous, nous avons deux tâches communicantes Lumi et Oled1[[BR]] Elles permettent d'afficher la valeur de la photorésistance après une mise à l'échelle entre 0 et 100. * Ajouter une tache qui fait clignoter la led a une frequence d'autant plus rapide de la lumiere est faible. ** Affichage de la lumière sur l'écran OLED** {{{#!c #include #include #include #include // unsigned int waitFor(timer, period) // Timer pour taches périodique // arguments : // - timer : numéro de timer entre 0 et MAX_WAIT_FOR_TIMER-1 // - period : période souhaitée // retour : // - nombre de période écoulée depuis le dernier appel // #define MAX_WAIT_FOR_TIMER 16 unsigned int waitFor(int timer, unsigned long period){ static unsigned long waitForTimer[MAX_WAIT_FOR_TIMER]; unsigned long newTime = micros() / period; int delta = newTime - waitForTimer[timer]; if ( delta < 0 ) delta += 1 + (0xFFFFFFFF / period); if ( delta ) waitForTimer[timer] = newTime; return delta; } // ------------- Configuration des broches #define PIN_LUMI 1 #define OLED_RESET 4 Adafruit_SSD1306 display(OLED_RESET); // ------------- Variables globales pour la communication inter-taches byte lumi, lumiFull; // ------------- Déclaration des tâches void Lumi ( // Echantillonne périodiquement le capteur de lumière et rend sa valeur entre 0 et 99 int timer, unsigned long period, // tâche périodique byte pin, // numéro de la broche lue byte *lumi, // valeur lue comprise entre 0 et 99 byte *lumiFull // drapeau mis à 1 à chaque période après écriture dans lumi ); void Oled1 ( // Affichage de la lumiere byte *mess, // buffer à afficher byte *full // drapeau mis à 1 pour demander l'affichage ); // ------------- Configuration de l'application et des périphériques void setup() { Serial.begin(115200); display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3C (for the 128x32) display.clearDisplay(); display.setTextSize(1); display.setTextColor(WHITE); } // ------------- Connexion des tâches void loop() { Lumi (0,1000000, PIN_LUMI, &lumi, &lumiFull); Oled1 (&lumi, &lumiFull); } // ------------- Définition des tâches void Lumi (int timer, unsigned long period, byte pin, byte *lumi, byte *lumiFull) { if (!waitFor(timer,period)) return; *lumi = map(analogRead(pin),0,1023,0,99); *lumiFull = 1; } void Oled1 (byte *mess, byte *full) { if (! (*full) ) return; *full = 0; Serial.println(*mess); display.clearDisplay(); display.setCursor(0,0); display.print("Lumiere : "); display.println(*mess); display.display(); } }}} == Communication entre Capteurs et Base == Pour cet exercice, vous allez faire communiquer deux arduinos, l'un en capteur, l'autre en afficheur. Pour vous aider, je vais vous donner la structure de l'application. ** Application capteur ** {{{#!c #include #include #include #include #include "RF24.h" #include "printf.h" // unsigned int waitFor(timer, period) // Timer pour taches périodique // arguments : // - timer : numéro de timer entre 0 et MAX_WAIT_FOR_TIMER-1 // - period : période souhaitée // retour : // - nombre de période écoulée depuis le dernier appel // #define MAX_WAIT_FOR_TIMER 16 unsigned int waitFor(int timer, unsigned long period){ static unsigned long waitForTimer[MAX_WAIT_FOR_TIMER]; unsigned long newTime = micros() / period; int delta = newTime - waitForTimer[timer]; if ( delta < 0 ) delta += 1 + (0xFFFFFFFF / period); if ( delta ) waitForTimer[timer] = newTime; return delta; } // Configuration des broches #define PIN_LUMI 1 #define OLED_RESET 4 Adafruit_SSD1306 display(OLED_RESET); RF24 radio(9,10); // radio(CE,CS) byte addresses[][6] = {/* a completer */}; // Variables globales pour la communication inter-taches byte lumi, lumiFull; void Lumi (int timer, unsigned long period, byte pin, byte *lumi, byte *lumiFull) { // a completer } void SensRF (byte *mess, byte *full) { // a completer } void setup() { Serial.begin(115200); display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3C (for the 128x32) display.clearDisplay(); display.setTextSize(1); display.setTextColor(WHITE); printf_begin(); radio.begin(); radio.setPALevel(RF24_PA_LOW); radio.openWritingPipe(addresses[1]); radio.printDetails(); } void loop() { Lumi (0,1000000, PIN_LUMI, &lumi, &lumiFull); SensRF (&lumi, &lumiFull); } }}} ** Application base ** {{{#!c #include #include #include #include #include "RF24.h" #include "printf.h" // unsigned int waitFor(timer, period) // Timer pour taches périodique // arguments : // - timer : numéro de timer entre 0 et MAX_WAIT_FOR_TIMER-1 // - period : période souhaitée // retour : // - nombre de période écoulée depuis le dernier appel // #define MAX_WAIT_FOR_TIMER 16 unsigned int waitFor(int timer, unsigned long period){ static unsigned long waitForTimer[MAX_WAIT_FOR_TIMER]; unsigned long newTime = micros() / period; int delta = newTime - waitForTimer[timer]; if ( delta < 0 ) delta += 1 + (0xFFFFFFFF / period); if ( delta ) waitForTimer[timer] = newTime; return delta; } // Configuration des broches #define PIN_LUMI 1 #define OLED_RESET 4 Adafruit_SSD1306 display(OLED_RESET); RF24 radio(9,10); byte addresses[][6] = {"0Sens","1Sens","2Sens","3Sens","4Node","5Sens"}; // Variables globales pour la communication inter-taches byte lumi, lumiFull; void BaseRF (byte *lumi, byte *lumiFull) { // a completer } void Oled1 (byte *mess, byte *full) { // a completer } void setup() { Serial.begin(115200); display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3C (for the 128x32) display.clearDisplay(); display.setTextSize(1); display.setTextColor(WHITE); printf_begin(); radio.begin(); radio.setPALevel(RF24_PA_LOW); radio.openReadingPipe(1,addresses[1]); radio.startListening(); radio.printDetails(); } void loop() { BaseRF(&lumi, &lumiFull); Oled1 (&lumi, &lumiFull); } }}} == Communication entre Capteurs et Base dans les deux sens == On souhaite réaliser un micro-réseaux avec deux capteurs de lumières et une base qui affiche la valeur des deux capteurs sur l'écran OLED. Mais on veut aussi que la base affiche périodiquement sur chaque capteur la valeur d'un compteur qui s'incrémente. Pour ce faire, il va falloir modifier la manière dont fonctionne les capteurs et la base. Jusqu'à maintenant les capteurs étaient toujours des émetteurs et la base était toujours un récepteur. Désormais, il vont devoir changer de rôle,