= Communication sans fil = == Préambule == Vous devez utiliser la dernière version d'arduino qui se trouve {{{#!bash > /opt/arduino-1.6.8/arduino }}} == 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éicification nRF24L01plus] * [https://github.com/TMRh20/RF24 Repository API TMRh20/RF24] * [http://www.mon-club-elec.fr/pmwiki_reference_arduino/pmwiki.php?n=Main.ReferenceMaxi Langage Arduino] == Travail demandé == Le but de la séance est de lire la valeur de la lumière sur une échelle de 1 à 100 sur un Arduino et de l'afficher sur le terminal d'un PC distant. Il y a donc au moins 2 noeuds, un émetteur et un récepteur. Nous allons aussi voir comment simuler l'exécution de plusieurs tâches périodiques. == Exécution ''multi-tâches'' == Avant de commencer à utiliser les modules nRF24L01+ nous allons 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. Commençeons par exprimer les besoins. Dans une applications pour micro-contrôleur, il est nécessaire : - d'exécuter des tâches périodiquement ; - d'exécuter des tâches lorsque des événements surviennent ; - de mesurer le temps séparant deux événements ; - 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) ; - etc. Chaque tâche est représentée par une fonction qui code son comportement. 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. La fonction loop() demande donc l'exécution des tâches à tour de rôle. Les tâches n'ont pas le droit de conserver le processeur sinon celà crée un blocage du système. La structure générale d'une tâche est la suivante : {{{#!c void tache(arguments) { // test de la condition d'exécution if (evement_attendu_absent) return; // code de la tache .... } }}} 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() prend un numéro de timer (il en faudra autant que de tâches périoodiques) et une période en microsecondes. wairFor() rend 0 tant que le temps écoulé depuis le précédent appel est inférieur à la période en paramètre, sinon il rend le nombre de périodes entières écoulées depuis le dernier appel. {{{#!c // 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; } void Led(int timer, long period, int led) { static int val = 0; if (!waitFor(timer,period)) return; // sort s'il y a moins d'une période écoulée digitalWrite(13,val); val = 1 - val; } void Mess(int timer, long period, const char * mess) { if (!(waitFor(timer,period))) return; Serial.println(mess); } void setup() { pinMode(13,OUTPUT); Serial.begin(115200); } void loop() { Led (0,100000,13); // Led est exécutée toutes les 100ms Mess(1,1000000,"bonjour"); // Mess est exécutée toutes les secondes } }}} == Lecture de la luminosité == == Communication nRF24L01+ == === Le matériel === * Vous allez commencer par faire un schéma du noeud.[[BR]] Les composants nécessaires à un noeud sont : * un Arduino nano * un couple photorésistance, résistance * un capteur sonore * un module **nRF24L01** [[Image(htdocs:jpg/nano.jpg, height=200px)]] [[Image(htdocs:jpg/pinoutNRF24L01.jpg, height=200px)]] [[Image(htdocs:jpg/photoresistance.jpg, height=100px)]] [[Image(htdocs:jpg/resistance.jpg, height=100px)]] === L'usage des bibliothèques Arduino === * Ce qu'il y a de bien dans l'écosystème Arduino, c'est que la volonté de faire simple. En l'occurrence, nous avons deux nouveaux objets, l'écran et le module RF24. Pour les utiliser, nous allons devoir faire appel à des fonctions, mais nous n'allons pas avoir à les écrire. En effet, pour presque tous les "périphériques" existants il existe un et même souvent plusieurs bibliothèques de fonctions écrites par des "amateurs" souvent très doués. En plus, les sources sont ouvertes, et il est donc possible d'adapter ces codes pour des besoins spécifiques. * Les bibliothèques sont trouvées, en général, en tapant sur un moteur de recherche, la requête "nom-du-module Arduino". Les projets sont souvent sur github. Pour faire court, * Vous téléchargez la bibliothèque (un .zip) * Vous ajoutez la bibliothèque dans l'environnement Arduino * Vous lancer l'IDE Arduino et dans le menu '''file/exemples''' vous avez un exemple (souvent plusieurs) de la nouvelle bibliothèque. * Vous en choisissez un, vous le chargez, vous le compilez, vous l'uploadez, vous le testez :-) === Communication de base Sensor - baseSensor === La documentation de la bibliothèque est [http://tmrh20.github.io/RF24/classRF24.html ici] dont voici un résumé : * ` RF24 (uint8_t _cepin, uint8_t _cspin)`[[BR]] Configuration du module radio et du SPI, reçoit les numéros de broche cepin (radio) cspin (SPI Slave Select) * `bool begin (void)`[[BR]] Démarrage du module radio * `void startListening (void)`[[BR]] * `void stopListening (void)`[[BR]] * `bool available (void)`[[BR]] * `void read (void *buf, uint8_t len)`[[BR]] * `bool write (const void *buf, uint8_t len)`[[BR]] * `void openWritingPipe (const uint8_t *address)`[[BR]] * `void openReadingPipe (uint8_t number, const uint8_t *address)`[[BR]] - **sensor** {{{#!c #include #include "RF24.h" #include "printf.h" RF24 radio(9,10); // radio(CE,CS) byte addresses[][6] = {"0Node"}; void setup() { Serial.begin(115200); printf_begin(); radio.begin(); radio.setPALevel(RF24_PA_LOW); radio.openWritingPipe(addresses[0]); radio.printDetails(); delay(1000); } void loop() { Serial.println(F("Now sending !")); unsigned long start_time = millis(); // Take the time, and send it. This will block until complete if (!radio.write( &start_time, sizeof(unsigned long) )){ Serial.println(F("failed!")); } delay(1000); } }}} - baseSensor {{{#!c #include #include "RF24.h" #include "printf.h" RF24 radio(9,10); byte addresses[][6] = {"0Node","1Node","2Node","3Node","4Node","5Node"}; void setup() { Serial.begin(115200); printf_begin(); radio.begin(); radio.setPALevel(RF24_PA_LOW); radio.openReadingPipe(1,addresses[0]); radio.startListening(); } void loop() { unsigned long got_time; if( radio.available()){ radio.read( &got_time, sizeof(unsigned long) ); // Get the payload Serial.println(got_time); } } }}}