11 Avril 2014

Arduino leçon 12 : la communication radio


"transceiver" est un mot-valise qui signifie transmitter-receiver soit en français émetteur-récepteur.
pas FB

Présentation

Les transceivers NRF24L01 ne sont pas des périphériques spécifiques à Arduino. On les trouve pour de nombreuses applications.
Ci dessous, en vert un NRF24L01 et en noir un NRF24L01+

NRF24L01 NRF24L01+

Installation

Divers membres de la communauté Arduino ont écrit des drivers pour ces transceivers.
On utilisera la bibliothèque "Mirf" mais il en existe d'autres.
On la récupère sur cette page :
http://playground.arduino.cc/InterfacingWithHardware/Nrf24L01
On décompresse ce fichier et on place le répertoire "Mirf" dans le répertoire "librairie" de Arduino.

Mirf

Branchements

Branchements de l'alimentation au transceiver

Ce transceiver fonctionne en 3 volts. Le brancher sur le +5 risque de le griller, mais il accepte 5V sur ses entrées logiques. On branche l'entrée VCC du transceiver sur la sortie 3.3 Volts de l'Arduino UNO ou 2009.

Le 3.3V fourni par l'Arduino Mega 2560 est de mauvaise qualité. On ne compte plus le nombre de journées perdues par les utilisateurs à cause de ce défaut, qui n'existe pas sur le 3.3V des cartes UNO ou 2009.

Pour utiliser le transceiver avec une carte MEGA 2560, j'avais essayé de souder un condensateur au tantale sur l'entreé 3 volts du transceiver. Ça allait mieux mais il y avait encore des ratées.
Finalement, j'ai acheté des régulateurs. J'ai choisi des plaquettes contenant un régulateur, des condensateurs, et un potentiomètre de réglage de la tension de sortie.

régulateur
Pensez à ajuster la tension de sortie AVANT de la connecter au transceiver.

Branchements du transceiver à l'Arduino

On branche 7 fils, le 8ème (IRQ) n'étant pas nécessaire pour notre application.

pin out nrf24l01

attention, les connecteurs sont sur la face opposée à celle visible ici et ils ne doivent jamais être mis dans une breadboard.

Le programme

Compte tenu de la complexité des fonctions, on évite de tout réécrire. On se contente de récupérer des programmes sur le net et de les adapter à nos besoins.
J'ai adapté les programmes de DukeXtrem

les variables utilisées par la bibliothèque Mirf

Mirf.payload est le nombre d'octets utiles d'un message.
Mirf.RADDR, adresse de réception est une valeur de 5 octets qui nous identifie
Mirf.TADDR, adresse de transmission est une valeur de 5 octets qui identifie le destinataire de notre message.
Mirff.channel est un canal qui doit être le même pour l'émetteur et le récepteur.
Leurs noms commencent tous par "Mirf." pour les distinguer des variables d'autres bibliothèques.

explication de quelques fonctions de la bibliothèque

Mirf.init() et Mirf.config()
              gèrent la configuration interne du processeur en fonction des variables qu'on a r enseignées juste avant (numéros des broches par exemple ou RADDR...)

void Mirf.dataReady()
              lit un flag qui est SET quand au moins un caractère est arrivé sur le buffer d'entrée.
              Tant que ce flag est à 1, on a au moins un caractère à lire. Quand on les a tous lus, le flag repasse à zéro. (RESET)

void getData(void)
              récupère une donnée de "payload" octets.
Mirf.isSending()
              lit un flag qui est SET pendant qu'on envoie des données. Il est RESET quand on n'a plus rien à envoyer.

Mirf.send()
              envoie "payload" caractères depuis l'adresse passée en paramètres.

le programme client

Il envoie le message "Bonjour." toutes les 15 secondes.
Le reste du temps il attend une réponse.
Chaque seconde il affiche le nombre de secondes écoulées
Quand il reçoit une réponse il l'affiche
Il annonce "time out" s'il n'a rien reçu pendant les 15 secondes.

/*
                  Client.ino

Broches utilisees pour le MEGA 2560
      * MISO -> 50,         * MOSI -> 51       * SCK -> 52
      * CE -> 48             * CSN -> 49
      * GND -> GND        * VCC -> 3 Volts du regulateur
Broches utilisees pour le UNO
      * MISO -> 12,         * MOSI -> 11       * SCK -> 13
      * CE -> 8               * CSN -> 7
      * GND -> GND        * VCC -> 3.3v de la carte UNO
*/


// *--------------------------------*
// Inclure les librairies
// *--------------------------------*
#include <SPI.h> // Pour la gestion du port SPI
#include <Mirf.h> // Pour la gestion de la communication
#include <nRF24L01.h> // Pour les definitions des registres du nRF24L01
#include <MirfHardwareSpiDriver.h> // Pour la communication SPI hardware
// (revient a  utiliser SPI.h mais avec une surcouche en plus)
byte message_aller[20] = "Bonjour";
byte message_retour[20];
byte i ;
boolean echec ;
unsigned long debut, seconde, finQuinze, oldSec;

void setup(){
      Serial.begin(9600); // initialisation du port serie

      // --------------------------------------
      // Configuration des broches CSN et CE :
      Mirf.cePin = 48 ; // 8 pour UNO
      Mirf.csnPin = 49 ; // 7 pour UNO
      // configuration du SPI : utiliser le port SPI hardware
      Mirf.spi = &MirfHardwareSpi;
      Mirf.init(); // initialisation du module

      // ---------------------------------------------------
      // canal et longueur utile doivent être identiques
      // pour le client et le serveur
      Mirf.channel = 12;
      Mirf.payload = 7; // taille utile de la donnee transmise
      // -------------------------------------------------------
      // Configuration des adresses de reception et d'emission
      Mirf.setRADDR((byte *)"clie1"); // adresse de reception du module (de 5 octets)
      Mirf.setTADDR((byte *)"serv1"); // adresse vers laquelle on transmet (de 5 octets)
      Mirf.config(); // ecriture de la configuration

      Serial.println("Programme Client seance du 14 Juin.");
      Serial.println("init OK");
      finQuinze = 0 ;
}

void loop(){
      // Envoi du message toutes les 15 secondes
      if ( millis() > finQuinze ) {
            envoiBonjour();
      }
      // --------------------------------
      // Si on recoit un message
      if (Mirf.dataReady()) {
            echec = false ;
            Mirf.getData((byte *) &message_retour);
            Serial.println(" ");
            Serial.print("Retour apres ");
            Serial.print(millis() - debut);
            Serial.println(" ms");
            Serial.print("On a recu : ");
            for ( i = 0 ; i < Mirf.payload ; i++) {
                  Serial.write(message_retour[i]);
            }
            Serial.println();
            Serial.println("-----------------------------------");
      }             // sortie de if DataReady
      else {
            // on va afficher le comptage des secondes
            seconde = int (( millis() - debut )) / 1000 ;
            if (seconde > oldSec) {
                  Serial.print ( seconde) ;
                  Serial.print ( " " ) ;
                  oldSec = seconde ;
            }       //       sortie du if
      }             //       sortie du else
}                   //       sortie de la loop


void envoiBonjour(void) {
      Serial.println(" ");
      if (echec){
            Serial.println("------- Time out ------- ");
      }
      Serial.println();
      Serial.println("Debut envoi");
      // ----------------------------------
      Mirf.send((byte *)&message_aller); // valeur que l'on veut envoyer
      while(Mirf.isSending()){
            // on attend que le message soit envoye
      }
      Serial.println("Envoi Ok");
      Serial.println("Attente retour ...");
      debut = millis() ;
      finQuinze = debut + 15000 ;
      oldSec = 0 ;
      echec = true ;
}

le programme serveur

Il attend un message.
Quand il en reçoit un,
     il l'affiche
     il attend 3 secondes
     il répond "Bonsoir."
     il se remet à attendre.

/*

      Serveur_11_Avril.ino
     
Broches utilisees pour le MEGA 2560
      * MISO -> 50, * MOSI -> 51 * SCK -> 52
      * CE -> 48 * CSN -> 49
      * GND -> GND * VCC -> 3 Volts du regulateur
Broches utilisees pour le UNO
      * MISO -> 12 * MOSI -> 11 * SCK -> 13
      * CE -> 8 * CSN -> 7
      * GND -> GND * VCC -> 3.3v de la carte UNO
*/

#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>

byte zone_recep[20];
byte zone_renvoi[20]="Bonsoir";
byte i;
     

void setup(){
     Serial.begin(9600);

     Mirf.cePin = 48; // 8 pour UNO
     Mirf.csnPin = 49; // 7 pour UNO
     Mirf.spi = &MirfHardwareSpi;
     Mirf.init();

     // canal et payload doivent etre identiques aux 2 modules
     Mirf.channel = 12;
     Mirf.payload = 7 ;
     Mirf.setRADDR((byte *)"serv1"); // Reception = notre propre adresse
     Mirf.setTADDR((byte *)"clie1"); // Transmission = adresse du destinataire
     Mirf.config();
     Serial.println("Programme Serveur seance du 14 Juin.");
     Serial.println("Init Ok...");
}

void loop(){
     //Si un message a ete recu et aucun message n'est en cours d'emission,
     if( Mirf.dataReady() && !Mirf.isSending() ){
            Mirf.getData(zone_recep); // on recupere le message
     
            Serial.print("On a recu : ");
            for (i=0 ; i < Mirf.payload ; i++) {
                  Serial.write(zone_recep[i]); // write affiche le caractere
            }
      Serial.println(" ");
     
      Serial.print("On renvoie : ");
      for ( i=0 ; i < Mirf.payload ; i++) {
            Serial.write(zone_renvoi[i]);
      }
      Serial.println(" apres 3 secondes.");
      delay(3000);
      Mirf.send(zone_renvoi); // On envoie notre reponse

      // On boucle tant que le message n'a pas ete envoye
      while(Mirf.isSending()){
            delay(10);
      }

      // info pour l'écran (plus tard envisager lcd)
      Serial.println("Renvoi OK.");
      Serial.println("-----------------------------------");
      Serial.println();
     }
}
     

et voici le résultat sur les 2 moniteurs :

écran du client écran du serveur

mauvais branchement

Si un transceiver est mal branché ou absent, Arduino reçoit (ou plutot croit recevoir) des données en permanence. Il s'agit soit de bits à 0 formant des octets de valeur 0 non affichables, soit des bits à 1 formant des octets de valeur 255 affichables sous forme de ÿ.









haut de la page
flèche gauche Page Précédente : ULA             page suivante : suite sur le transceiver flèche droite

Valid XHTML 1.0 Transitional