ArduPi-I2C-DataType-CodeArduino

De MCHobby - Wiki
Aller à : navigation, rechercher

MCHobby investit du temps et de l'argent dans la réalisation de traduction et/ou documentation. C'est un travail long et fastidieux réalisé dans l'esprit Open-Source... donc gratuit et librement accessible.
SI vous aimez nos traductions et documentations ALORS aidez nous à en produire plus en achetant vos produits chez MCHobby.

Arduino

Voici ensuite le programme Arduino.

Cette fois-ci, il est sensiblement plus compliqué car il implémente un système de registre de façon logiciel.

Comme déjà précisé, c'est un Slave Listener (esclave qui écoute). Il reçoit des informations en provenance du Raspberry-Pi sur le bus I2C.

Programme SlaveRegisterDataTypes

Le fonctionnement du programme Arduino est identique à celui de l'exemple du Registre dont vous trouverez les détails du fonctionnement ici.

N'oubliez pas d'ouvrir le moniteur série d'Arduino, car une communication série est initialisée pour permettre l'affichage de quelques informations utiles.

Envoi d'une valeur décimale (double)

L'envoi d'une valeur décimale (ex: 5.67) se fait à l'aide du type Double qui est décomposé en 4 octets.

La magie se passe dans la fonction Wire_SendDouble() qui utilise un struct de type union entre Double et byte[4]. Cela permet d'accéder à un même espace mémoire de feux façons différentes:

  • une fois pour y stocker une valeur sous le type double,
  • Une autres fois pour lire chacun des bytes/octets (tronçons de 8 bits) composant ce "type double" qui stock la valeur numérique.

Grâce à cette structure, il est possible de saucissonner un espace mémoire pour l'envoyer sur le bus I2C.

Les 4 octets/bytes sont accessibles comme un tableau... ou un buffer. Il est donc possible d'utiliser directement la méthode Wire.write() pour envoyer le buffer de 4 octets de long sur le bus I2C.

Envoi d'une valeur décimale (float)

Si votre valeur décimale est contenue dans un type float, il faudra faire un transtypage du pointeur (casting) avant l'envoi sur le bus I2C.

Le code d'envoi I2C pour un type double ressemble à ceci

double valeurDouble;
...
valeurDouble = 123.57;
Wire_SendDouble( &valeurDouble );

Le code d'envoi I2C pour un type float ressemble à ceci

float valeurFloat;
...
valeurFloat = 312.777;
Wire_SendDouble( (double*)&valeurFloat );

Code source

 // === ArduPi-I2C ================================================
// Communication entre Arduino et Raspberry Pi via le BUS I2C
// ===============================================================
// Tutoriel: http://mchobby.be/wiki/index.php?title=ArduPi-I2C
//
// Programme Esclave qui Recoit les demandes envoyées par Raspberry Pi
// Le but étant de tester la transmission de type de données entre 
//    Arduino et Raspberry.
// S'utilise avec le programme Arduino MasterWriterDataTypes.py
//
// Ce programme attend des instructions dans le registre de commande
// registre 0x00: registre d'exécution (commande a exécuter)
//    commande 0x00 - nop
//    Commande 0x01 - demande de numero de version (retourne un byte)
//    Commande 0x02 - Retourne un Float avec la valeur 5.67
//    Commande 0x03 - 
// registre 0x01: opérant 1 - non utilisé dans cet exemple 
// registre 0x02: opérant 2 - non utilisé dans cet exemple
//
// Ecrit par D. Meurisse pour MCHobby.be
// www.mchobby.be - Vente de kit et composant Arduino et Raspberry Pi
// Licence CC-BY-SA
//
// Basé sur l'exemple de Nicholas Zambetti <http://www.zambetti.com>
//
#include <Wire.h>

// déclaration des registres
byte regs[3]; 
int regIndex = 0; // Registre à lire ou à écrire.

// copie de la dernière instruction d execution écrite dans
// le registre reg0 pour le traitement asynchrone de
// requestEvent (demande de bytes) 
byte lastExecReq = 0x00; 

void setup()
{
  // Initialisation des registres
  regs[0] = 0x00; // reg0 = registre d'exécution
                  // valeur 0x00 = NOP - No Operation = rien à faire 
  regs[1] = 0x00; 
  regs[2] = 0x00;
  
  // Joindre le Bus I2C avec adresse #4
  Wire.begin(4);
  // enregistrer l'événement 
  //    Lorsque des données sont écrites par le maitre et reçue par l'esclave
  Wire.onReceive(receiveEvent); 
  // enregistrer l'événement 
  //    Lorsque le Maitre demande de lecture de bytes
  Wire.onRequest(requestEvent); 
  
  // Démarrer une communication série
  Serial.begin(19200);           
  Serial.println( F("Bus I2C pret") );
  
  // Definir la broche 13 en sortie
  pinMode( 13, OUTPUT );
  digitalWrite( 13, HIGH );
}

void loop()
{
  // Si NOP alors rien à faire
  if( regs[0] == 0x00 ) {
    delay(100);
    return;
  }
  
  // Exécution de l'opération
  /* Serial.println( F("--- Traitement Requete ---") );
  Serial.print( F("reg0 = ") );
  Serial.println( regs[0], DEC );
  Serial.print( F("reg1 = ") );
  Serial.println( regs[1], DEC );
  Serial.print( F("reg2 = ") );
  Serial.println( regs[2], DEC );
  */
 
  switch( regs[0] ){
    case 0x01 : // demande de version (rien à faire)
      break;
    case 0x02 : // demande de valeur Float (rien à faire, l'operation et retour de donnée est exécuté à la demande de réponse)
      break;
    /* Issu d'un autre exemple 
    
    case 0x03 : // Activer/désactiver Pin 13 en fct de la valeur du registre 0x01
      if( regs[1] > 0 )
         digitalWrite( 13, HIGH );
      else
         digitalWrite( 13, LOW ); 
      break;
    */
  } 

  // reset to NOP
  regs[0] = 0x00;  
}

// Fonction qui est exécutée lorsque des données sont envoyées par le Maître.
// Cette fonction est enregistrée comme une événement ("event" en anglais), voir la fonction setup()
void receiveEvent(int howMany)
{
  int byteCounter = 0;
 
  // Pour faire du debug... mais attention cela peut planter
  //    la réception!
  //
  //Serial.println(F("---- LECTURE ---"));
  //Serial.print(F("Numbre de Bytes: "));
  //Serial.println( howMany );

  // Lire tous les octets sauf le dernier
  while( byteCounter < howMany ) 
  {
    // lecture de l'octet
    byte b = Wire.read();     
    byteCounter += 1;
    
    //Serial.println( b, DEC );
     
    if( byteCounter == 1 ){   // Byte #1 = Numéro de registre
       regIndex = b;
    } 
    else {                    // Byte #2 = Valeur a stocker dans le registre
       switch(regIndex) {
         case 0:
           regs[0] = b;
           // maintenir une copie du dernier reg0 pour 
           // traitement d'une réponse via requestEvent (demande de byte)
           lastExecReq = b; 
           break;
         case 1: 
           regs[1] = b;
           break;
         case 2:
           regs[2] = b;
           break;   
       } 
    }
    
    
  } // fin WHILE
}


// Fonction outil décomposant un double en array de Bytes 
// et envoyant les données sur le bus I2C
//
// Basé sur le code obtenu ici:
//      http://stackoverflow.com/questions/12664826/sending-float-type-data-from-arduino-to-python
void Wire_SendDouble( double* d){
  
    // Permet de partager deux types distinct sur un meme espace
    // memoire
    union Sharedblock
    {
        byte part[4]; // utiliser char parts[4] pour port série
        double data;

    } mon_block;
    
    mon_block.data = *d;
    
    /* 
    pour... 
      mon_block.data = 5.67
    le tableau part[x] vaut...
      mon_block.part[0] = 164;
      mon_block.part[1] = 112;
      mon_block.part[2] = 181;
      mon_block.part[3] = 64;
      
    Ce sont les valeurs que l'on doit retrouver de l'autre cote du BUS I2C
    */
        
    Wire.write( mon_block.part, 4 );
}

double valeurDouble;

// Fonction est activé lorsque le Maitre fait une demande de lecture.
// 
void requestEvent()
{
  // Deboggage - Activer les lignes suivantes peut perturber fortement 
  //    l'échange I2C... a utiliser avec circonspection.
  //
  //   Serial.print( "Lecture registre: " );
  //   Serial.println( regIndex );
  
  // Quel registre est-il lu???
  switch( regIndex ){ 
 
    case 0x00: // lecture registre 0 
          // la réponse depend de la dernière opération d'exécution demandée 
          //    par l'intermédiaire du registre d'exécution (reg 0x00).
          switch( lastExecReq ) {
            case 0x01: // demande de version
              // current version = v3
              Wire.write( 0x11 ); 
              break;
              
            case 0x02: // Retourne un Float
              valeurDouble = 5.67;   
              // essayer aussi avec 
              //    valeurDouble = 128.1245;

              // Décompose la valeur en Bytes et l'envoi sur I2C
              Wire_SendDouble( &valeurDouble );
              break;
          
            default:
              Wire.write( 0xFF ); // ecrire 255 = il y a un problème! 
          }
          break;
     
    default: // lecture autre registre 
      Wire.write( 0xFF ); // ecrire 255 = il y a un problème
  }  
  
}

Ecrit par Meurisse D. pour mchobby.be

Toute référence, mention ou extrait de cette traduction doit être explicitement accompagné du texte suivant : «  Traduction par MCHobby (www.MCHobby.be) - Vente de kit et composants » avec un lien vers la source (donc cette page) et ce quelque soit le média utilisé.

L'utilisation commercial de la traduction (texte) et/ou réalisation, même partielle, pourrait être soumis à redevance. Dans tous les cas de figures, vous devez également obtenir l'accord du(des) détenteur initial des droits. Celui de MC Hobby s'arrêtant au travail de traduction proprement dit.