Transmettre un Float/Double par I2C entre Arduino et Raspberry

Nous avons complété notre tutoriel de communication I2C entre Raspberry et Arduino.... cette fois nous nous sommes penchés sur le transport des valeurs décimales.
Tutoriel ArduPi - communication I2C entre Raspberry et Adruino
Ce complément de tutoriel fut créé pour répondre au besoin spécifique d'un client ayant besoin d'envoyer la température d'une sonde DS18B20 d'un Arduino vers Raspberry-Pi via le bus I2C.
Transporter efficacement une valeur telle que 25.30°c (un float ou double) entre un Arduino et un Raspberry Pi sur un bus I2C n'est pas si simple que cela.
Ce tuto met également en oeuvre le concept des registres sur un Arduino (abordé dans ce tutoriel sur I2C) et déjà exploité dans l'exemple des registres ci-avant.
Dans le tutoriel: 
  • Raspberry Pi est le MASTER WRITER
    Pi est donc le maître de la communication envoyant ses instructions.
  • Arduino est le SLAVE LISTENER (esclave qui écoute)
    Il attend donc les instructions envoyée sur le bus I2C.
Détail du raccordement entre Raspberry Pi et Arduino
dans notre tutoriel ArduPi-I2C

Mais comment faire voyager une valeur décimale entre ces deux modes?

La réponse se trouve ci-dessous (et en détail dans notre tutoriel)?

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

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

La magie se passe dans la fonction Wire_SendDouble().

// 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 );
}

La fonction Wire_SendDouble() 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.
Côté Raspberry-Pi
En s'appuyant sur la librairie Adafruit_I2C, la réception des bytes se résume à une simple instruction

import time
import struct
from Adafruit_I2C import Adafruit_I2C

i2c = Adafruit_I2C( 0x04 )

# --- Demander une valeur décimale ---
# Transfert d'un type DOUBLE

# demander l'opération de reception d'un float, placer 0x02 dans le
# le registre d'exécution 0
i2c.write8( 0x00, 0x02 )
time.sleep(0.100)
i2c.debug = True

# Lire 4 octets pour recevoir le Float.
# Doit recevoir les valeurs [164, 112, 181, 64]
#
lstData =  i2c.readList( 0x00, 4 )


Et quelques instructions plus loin, la transformation en valeur décimale est presque tout aussi simple:

# transformer en string pour unpack
sData = ''
for aByte in lstData:
        sData = sData + chr(aByte)

f_data, = struct.unpack('<f',sData)
print f_data # Affiche la valeur en Float.


Tutoriel complet
Aimez-vous nos tutoriel?
MCHobby investi 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.