Bus I2C - Comunicación RPI y Arduino

Bus I2C - Comunicación RPI y Arduino

@Shark


https://www.aranacorp.com/es/comunicacion-i2c-entre-raspberry-pi-y-arduino/

-Diagrama

Para establecer la comunicación I2C entre Raspberry Pi y Arduino, necesitamos conectar físicamente el bus que utiliza 3 pines. Una comunicación I2C se define por un bus de dos cables (a veces llamado TWI, Two Wire Interface) y una dirección. Los pines utilizados para la comunicación I2C suelen estar fijados para cada dispositivo. Una en la que se envían los datos (Línea de datos en serie SDA) y otra en la que se envía el reloj de sincronización (Línea de reloj en serie SLC). Los fundamentos de las dos cartas deben estar conectados para establecer una referencia potencial común.

  • SDA BCM2(RPI) <-> SDA A4(Arduino)
  • SCL BCM3(RPI) <-> SCL A5(Arduino)
  • GND (RPI) <-> GND(Arduino)


-Configuración Raspberry Pi

Para usar la interfaz I2C de Raspberry Pi, debe estar habilitada en el menú de configuración. Para ello, introduzca el siguiente comando en una terminal:

sudo raspi-configCopy

En el menú, seleccione «5 – Opciones de interfaz» y luego «P5 I2C» y valide.

Una vez realizada la conexión, puede comprobar los dispositivos conectados al bus tecleando el comando en la terminal:

i2cdetect -y 1Copy

El Raspberry Pi devuelve la lista de direcciones detectadas en el bus.

pi@raspberrypi:~ $ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- 0b -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --  
Copy

Nous allons installer la librairie smbus2 qui permet de Vamos a instalar la biblioteca smbus2 que permite gestionar la comunicación I2C en el lado del Raspberry Pi

pip3 install smbus2
Copy


-Código Python Master

En este tutorial, usaremos el lenguaje Python por el Raspberry Pi. La biblioteca que se utiliza para gestionar la comunicación I2C es la biblioteca smbus2.

#!/usr/bin/env python# -*- coding: utf-8 -*-# Raspberry Pi to Arduino I2C Communication#i2cdetect -y 1#libraryimport sysimport smbus2 as smbus#,smbus2import time# Slave AddressesI2C_SLAVE_ADDRESS = 11 #0x0b ou 11I2C_SLAVE2_ADDRESS = 12I2C_SLAVE3_ADDRESS = 13# This function converts a string to an array of bytes.def ConvertStringsToBytes(src): converted = [] for b in src: converted.append(ord(b)) return converteddef main(args): # Create the I2C bus I2Cbus = smbus.SMBus(1) with smbus.SMBus(1) as I2Cbus: slaveSelect = input("Which Arduino (1-3): ") cmd = input("Enter command: ") if slaveSelect == "1": slaveAddress = I2C_SLAVE_ADDRESS elif slaveSelect == "2": slaveAddress = I2C_SLAVE2_ADDRESS elif slaveSelect == "3": slaveAddress = I2C_SLAVE3_ADDRESS else: # quit if you messed up print(slaveSelect== "1") print(type(slaveSelect)) print("no slave selected") quit() BytesToSend = ConvertStringsToBytes(cmd) print("Sent " + str(slaveAddress) + " the " + str(cmd) + " command.") print(BytesToSend ) I2Cbus.write_i2c_block_data(slaveAddress, 0x00, BytesToSend) time.sleep(0.5) while True: try: data=I2Cbus.read_i2c_block_data(slaveAddress,0x00,16) print("recieve from slave:") print(data) except: print("remote i/o error") time.sleep(0.5) return 0if __name__ == '__main__': try: main(sys.argv) except KeyboardInterrupt: print("program was stopped manually") input()


-Código Arduino Esclavo

La biblioteca utilizada para manejar la comunicación I2C en el lado de Arduino es la biblioteca Wire.h.

#include <Wire.h>

# define I2C_SLAVE_ADDRESS 11 // 12 pour l'esclave 2 et ainsi de suite

#define PAYLOAD_SIZE 2

void setup()
{
  Wire.begin(I2C_SLAVE_ADDRESS);
  Serial.begin(9600); 
  Serial.println("-------------------------------------I am Slave1");
  delay(1000);               
  Wire.onRequest(requestEvents);
  Wire.onReceive(receiveEvents);
}

void loop(){}

int n = 0;

void requestEvents()
{
  Serial.println(F("---> recieved request"));
  Serial.print(F("sending value : "));
  Serial.println(n);
  Wire.write(n);
}

void receiveEvents(int numBytes)
{  
  Serial.println(F("---> recieved events"));
  n = Wire.read();
  Serial.print(numBytes);
  Serial.println(F("bytes recieved"));
  Serial.print(F("recieved value : "));
  Serial.println(n);
}
Copy

-Resultado

La Raspberry Pi envía el comando «slave» al Arduino, y luego recibe una matriz de datos del Arduino.


La placa Arduino recibe el comando «esclavo» y luego envía dos valores actualizados tan pronto como recibe una solicitud de la Raspberry Pi:





-Bus I2C entre placas Arduino

https://www.aranacorp.com/es/administre-multiples-arduino-con-un-bus-i2c/

Con el protocolo I2C, también es posible comunicarse entre diferentes sistemas (sensores, pantalla LCD, Raspberry Pi, etc.). Un ejemplo interesante es la comunicación entre varias placas Arduino. Para esto, necesitamos escribir al menos dos programas, uno para la tarjeta «Maestra» (Maestro) y el otro para las tarjetas «Esclavos».

Una comunicación I2C se define mediante un bus de dos hilos (a veces llamado TWI, interfaz de dos hilos) y una dirección. Los pines utilizados por la comunicación I2C generalmente son fijos para cada dispositivo. Uno en el que se envían los datos (línea de datos en serie SDA) y en el otro el reloj de sincronización (línea de reloj en serie SLC).

Pines I2C / TWI:

  • Uno, Ethernet A4 (SDA), A5 (SCL)
  • Mega2560 20 (SDA), 21 (SCL)
  • Leonardo 2 (SDA), 3 (SCL)
  • Due 20 (SDA), 21 (SCL), SDA1, SCL1

En este ejemplo utilizamos una placa Arduino Uno, por lo que los pines A4 y A5.

Para que las dos tarjetas se comuniquen entre sí, deben estar conectadas correctamente (A4 con A4 y A5 con A5) y no olvides conectar las tierras (GND) como se muestra en el siguiente diagrama.

Precaución: si los pines A4 y A5 están conectados a los pines de una tarjeta sin alimentación, el código se congelará en el momento de la transmisión.


Generalmente, una tarjeta enviará información (Escritor) y otra la recibirá (Lector).


-Código de configuración del bus I2C

La biblioteca Wire.h le permite definir fácilmente la comunicación en serie en el bus I2C. Las funciones son similares a la biblioteca en serie.

  • Wire.begin () inicializa la dirección del dispositivo. El argumento de función puede estar vacío para dispositivos maestros
  • Wire.write () le permite enviar bytes.
  • Wire.requestFrom () maneja la función de recepción de solicitud
  • Wire.beginTransmission () comienza a transmitir datos y define el receptor.
  • Wire.endTransmission finaliza la transmisión de datos
  • Wire.onRequest () maneja la función de recepción de solicitud
  • Wire.onRecieve () gestiona la función de recepción de datos


-Código de la tarjeta «Master»

#include <Wire.h>

# define I2C_SLAVE1_ADDRESS 11
# define I2C_SLAVE2_ADDRESS 12

#define PAYLOAD_SIZE 2

int n=0;

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

  Serial.println(F("-------------------------------------I am the Master"));
  delay(1000);

  //Request value of n to slave
  Wire.requestFrom(I2C_SLAVE1_ADDRESS, 1);   
  n = Wire.read(); 
  Serial.print(F("recieved value : "));
  Serial.println(n);

  //Send value 12 to slave
  Wire.beginTransmission(I2C_SLAVE1_ADDRESS); 
  Wire.write(12); 
   Serial.print(F("sending value : "));
  Serial.println(12);              
  Wire.endTransmission();   

  Serial.print(" ");

  //Request value of n to slave after change
  Wire.requestFrom(I2C_SLAVE1_ADDRESS, 1); 
  n = Wire.read();
  Serial.print(F(" new recieved value : "));
  Serial.println(n); 
}


void loop()
{
  delay(100);
}

Copy


-Código de tarjeta «esclavo»

#include <Wire.h>

# define I2C_SLAVE_ADDRESS 11 // 12 pour l'esclave 2 et ainsi de suite

#define PAYLOAD_SIZE 2

void setup()
{
  Wire.begin(I2C_SLAVE_ADDRESS);
  Serial.begin(9600); 
  Serial.println("-------------------------------------I am Slave1");
  delay(1000);               
  Wire.onRequest(requestEvents);
  Wire.onReceive(receiveEvents);
}

void loop(){}

int n = 0;

void requestEvents()
{
  Serial.println(F("---> recieved request"));
  Serial.print(F("sending value : "));
  Serial.println(n);
  Wire.write(n);
}

void receiveEvents(int numBytes)
{  
  Serial.println(F("---> recieved events"));
  n = Wire.read();
  Serial.print(numBytes);
  Serial.println(F("bytes recieved"));
  Serial.print(F("recieved value : "));
  Serial.println(n);
}
Copy

Abra el monitor en serie de la tarjeta esclava antes que el monitor de la tarjeta maestra.

En el monitor en serie de la tarjeta «Master»:

En el monitor en serie de la tarjeta «Slave 1»:

Podemos ver que las dos tarjetas están intercambiando información. Es muy fácil extender este ejemplo a varias placas Arduino (Leonardo, Mini, etc.) adaptando el cableado y la dirección de los componentes en el código «Esclavo».


-Código para identificar los dispositivos conectados al bus I2C

Una buena prueba para saber si sus dispositivos se comunican bien entre sí es usar el siguiente código (I2CScanner) que devuelve todas las direcciones de los dispositivos conectados a la tarjeta Master.

    #include <Wire.h>
    
    
   void setup()
   {
     Wire.begin();
     Serial.begin(9600);
     while (!Serial);             // Leonardo: wait for serial monitor
     Serial.println(F("\nI2C Scanner"));
   }
    
    
   void loop()
   {
     byte error, address;
     int nDevices;
    
     Serial.println(F("Scanning..."));
    
     nDevices = 0;
     for(address = 1; address < 127; address++ )
     {
       // The i2c_scanner uses the return value of
       // the Write.endTransmisstion to see if
       // a device did acknowledge to the address.
         Wire.beginTransmission(address);
         error = Wire.endTransmission();
         
       
       if (error == 0)
       {
         Serial.print("I2C device found at address 0x");
         if (address<16)
           Serial.print("0");
         Serial.print(address,HEX);
         Serial.println("  !");
    
         nDevices++;
       }
       else if (error==4)
       {
         Serial.print("Unknown error at address 0x");
         if (address<16)
           Serial.print("0");
         Serial.println(address,HEX);
       }    
     }
     if (nDevices == 0)
       Serial.println(F("No I2C devices found\n"));
     else
       Serial.println(F("done\n"));
    
     delay(5000);           // wait 5 seconds for next scan
   }
Copy













Report Page