Changes between Version 2 and Version 3 of SujetTP5-2017


Ignore:
Timestamp:
Mar 3, 2017, 7:24:49 AM (8 years ago)
Author:
franck
Comment:

l

Legend:

Unmodified
Added
Removed
Modified
  • SujetTP5-2017

    v2 v3  
    44
    55=== Récupération de la bibliothèque du NRF24L01 ===
     6
     7Si nous voulons continuer à cross compiler, il faut installer la librairie qui va permettre de contrôler le module NRF24L01. Il existe plusieurs librairies. Celle choisie à le mérite d'être disponible dans l'environnement raspberry et arduino. C'est-à-dire que lorsque vous aurez compris comment l'utiliser avec la raspberry pi, le passage sur Arduino sera facile.
    68
    79 * Aller sur le site https://github.com/tmrh20/RF24
     
    1517$ make install
    1618}}}
    17  * Vérification que la library est installée
     19 * Vérification que la library est installée.
    1820{{{#!bash
    1921$ ls $HOME/rf24
     
    2123}}}
    2224
    23 Vous devez utiliser la dernière version d'arduino qui se trouve
    24 {{{#!bash
    25 > /opt/arduino-1.6.8/arduino
    26 }}}
     25La bibliothèque a été installée sur les cartes raspberry pi car la bibliothèque est dynamique et non pas statique, donc il faut la bibliothèque sur la raspberry pi.
    2726
    28 == Documents de référence ==
     27== Documents de référence du module NRF24L01 ==
    2928
    3029 * [http://www.nordicsemi.com/eng/Products/2.4GHz-RF/nRF24L01P Site Nordic nRF24L01Plus]
     
    3534== Travail demandé ==
    3635
    37 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.
     36Le but de la séance est de lire la valeur envoyée par l'Arduino et de l'afficher sur le terminal de la raspberry. Il y a donc au moins 2 noeuds, un émetteur et un récepteur.
    3837Nous allons aussi voir comment simuler l'exécution de plusieurs tâches périodiques.
    3938
    40 == Exécution ''multi-tâches'' ==
    41 
    42 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.
    43 
    44 Commençeons par exprimer les besoins. Dans une applications pour micro-contrôleur, il est nécessaire :
    45 - d'exécuter des tâches périodiquement ;
    46 - d'exécuter des tâches lorsque des événements surviennent ;
    47 - de mesurer le temps séparant deux événements ;
    48 - 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) ;
    49 - etc.
    50 
    51 Chaque tâche est représentée par une fonction qui code son comportement.
    52 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.
    53 La fonction loop() demande donc l'exécution des tâches à tour de rôle.
    54 Les tâches n'ont pas le droit de conserver le processeur sinon celà crée un blocage du système.
    55 La structure générale d'une tâche est la suivante :
    56 
    57 {{{#!c
    58 void tache(arguments) {
    59    // test de la condition d'exécution
    60    if (evement_attendu_absent) return;
    61    // code de la tache
    62    ....
    63 }
    64 }}}
    65 
    66 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.
    67 
    68 `wairFor()` peut être appelée aussi souvent que nécessaire, elle rend 1 une seule fois par période (second paramètre).
    69 Si elle n'est pas appelée pendant longtemps alors elle rend le nombre de périodes qui se sont écoulées.
    70 
    71 Dans l'application suivante nous avons deux tâches périodiques `Led()` et `Mess()`.
    72 La première fait clignoter une led dont le numéro est passé en paramètre à 5Hz.
    73 La seconde affiche bonjour à une fois par seconde.
    74 {{{#!c
    75 // unsigned int waitFor(timer, period)
    76 // Timer pour taches périodique
    77 // arguments :
    78 //  - timer  : numéro de timer entre 0 et MAX_WAIT_FOR_TIMER-1
    79 //  - period : période souhaitée
    80 // retour :
    81 //  - nombre de période écoulée depuis le dernier appel
    82 //
    83 #define MAX_WAIT_FOR_TIMER 16
    84 unsigned int waitFor(int timer, unsigned long period){
    85   static unsigned long waitForTimer[MAX_WAIT_FOR_TIMER];
    86   unsigned long newTime = micros() / period;              // numéro de la période modulo 2^32
    87   int delta = newTime - waitForTimer[timer];              // delta entre la période courante et celle enregistrée
    88   if ( delta < 0 ) delta += 1 + (0xFFFFFFFF / period);    // en cas de dépassement du nombre de périodes possibles sur 2^32
    89   if ( delta ) waitForTimer[timer] = newTime;             // enregistrement du nouveau numéro de période
    90   return delta;
    91 }
    92 
    93 void Led(int timer, long period, byte led) {
    94   static byte val = 0;                                    // valeur à mettre sur la led
    95   if (!waitFor(timer,period)) return;                     // sort s'il y a moins d'une période écoulée
    96   digitalWrite(13,val);                                   // ecriture
    97   val = 1 - val;                                          // changement d'état
    98 }
    99 
    100 void Mess(int timer, long period, const char * mess) {
    101   if (!(waitFor(timer,period))) return;                   // sort s'il y a moins d'une période écoulée
    102   Serial.println(mess);                                   // affichage du message
    103 }
    104 
    105 void setup() {
    106   pinMode(13,OUTPUT);                                     // initialisation de la direction de la broche
    107   Serial.begin(115200);                                   // initialisation du débit de la liaison série
    108 }
    109 
    110 void loop() {
    111   Led (0,100000,13);                                      // Led est exécutée toutes les 100ms
    112   Mess(1,1000000,"bonjour");                              // Mess est exécutée toutes les secondes
    113 }
    114 }}}
    115 
    116 Dans la pratique, les tâches des applications communiquent entre elles. Nous pouvons le faire ici en passant par des variables globales dont les adresses sont passées en paramètres des tâches. Ce dernier point est important, il faut absolument que les variables globales ne soient pas directement utilisées par les fonctions de tâches mais toujours passées explicitement en paramètre ceci afin de faciliter la mise au point ET permettre d'avoir plusieurs instances de la même tâche.
    117 
    118 Dans l'exemple qui suit, nous avons ajouter une tâche !GetKbd qui lit un message au clavier et le place dans un buffer nommé mess.
    119 C'est la tâche Mess qui fera l'affichage.
    120 Les deux tâches se synchronisent en utilisant une case mémoire nommée full dont la valeur peut prendre deux états:
    121 - 0 = le buffer ne contient pas de message, le buffer appartient à !GetKbd qui le remplit à chaque nouveau caractère
    122 - 1 = le buffer contient un message, le buffer appatient à Mess qui le lit et l'affiche
    123 
    124 La case full est mise à 1 par !GetKbd et mise à 0 par Mess.
    125 
    126 Il y a une autre communication entre !GetKbd et Led que je vous laisse analyser
    127 
    128 {{{#!c
    129 // unsigned int waitFor(timer, period)
    130 // Timer pour taches périodique
    131 // arguments :
    132 //  - timer  : numéro de timer entre 0 et MAX_WAIT_FOR_TIMER-1
    133 //  - period : période souhaitée
    134 // retour :
    135 //  - nombre de période écoulée depuis le dernier appel
    136 //
    137 #define MAX_WAIT_FOR_TIMER 16
    138 unsigned int waitFor(int timer, unsigned long period){
    139   static unsigned long waitForTimer[MAX_WAIT_FOR_TIMER];
    140   unsigned long newTime = micros() / period;
    141   int delta = newTime - waitForTimer[timer];
    142   if ( delta < 0 ) delta += 1 + (0xFFFFFFFF / period);   
    143   if ( delta ) waitForTimer[timer] = newTime;
    144   return delta;
    145 }
    146 
    147 // Variables globales pour la communication inter-taches
    148 char mess[32];
    149 byte full;
    150 byte onled = 1;
    151 
    152 void Led (int timer, long period, byte led, byte *on) {
    153   static int val = 0;
    154   if (!waitFor(timer,period)) return; // sort s'il y a moins d'une période écoulée
    155   if (*on == 0) {
    156     val = 0;
    157   }
    158   digitalWrite(13,val);
    159   val = 1 - val;
    160 }
    161 
    162 void Mess (byte *full, char * mess) {
    163   if (! (*full) ) return;
    164   *full = 0;
    165   Serial.println(mess);
    166 }
    167 
    168 void setup () {
    169   pinMode(13,OUTPUT);
    170   Serial.begin(115200);
    171 }
    172 
    173 void GetKbd (byte *full, char * mess, byte len, byte *on) {
    174   static byte index = 0;
    175   if (!Serial.available()) return;
    176   char c = Serial.read();
    177   mess[index++] = c;
    178   if (c == '\n') {
    179     mess[index-1] = 0;
    180     index = 0;
    181     *full = 1;
    182     *on = (strcmp(mess,"on")==0) ? 1
    183         : (strcmp(mess,"off")==0) ? 0
    184         : *on;
    185        
    186   } else if (index == len) {
    187     index--;
    188   }
    189 }
    190 
    191 void loop() {
    192   Led (0,100000,13, &onled);           // Led est exécutée toutes les 100ms
    193   Mess (&full, mess);           // mess est un buffer d'echange avec getkbd et full une bascule de synchro
    194   GetKbd (&full, mess, sizeof(mess), &onled);
    195 }
    196 }}}
    19739
    19840== Lecture de la luminosité ==