Comunicación I2C entre Arduino y STM32

En esta entrada aprenderemos como enviar variables desde un STM32F103 (Blue Pill) a un Arduino Nano vía I2C. Por utilizar un ejemplo real y que pueda tener utilidad, enviaremos por I2C las lecturas de un sensor MPU6050: el STM32 hará lecturas del sensor MPU6050 y las enviara al Arduino Nano vía I2C para que este las enseñe por comunicación serie.

Comunicación I2C entre STM32 y Arduino

Comprar STM32    Comprar Arduino Nano   

Conexión entre MPU6050, STM32 y Arduino 

La placa STM32 tiene dos puertos I2C, por lo que utilizaremos uno para leer el sensor MPU6050, y el otro para comunicarnos con el Arduino Nano:

  • PB11 (STM32),  I2C2    ⇒  SDA (MPU6050)
  • PB10 (STM32), I2C2    ⇒  SCL (MPU6050)
  • PB6 (STM32),   I2C1    ⇒  A5 (Arduino Nano)
  • PB7 (STM32),   I2C1    ⇒  A4 (Arduino Nano)

Envío de variables vía I2C

El proceso para enviar variables por I2C consta de dos partes:

  1. Descomponer cada variable en bytes.
  2. Enviar por I2C cada byte por separado, uno a uno.

En este ejemplo vamos a transmitir 6 variables de 2 bytes (las lecturas del MPU6050), 12 bytes en total. Para ello, guardaremos estas 6 variables en un array y utilizar un bucle for para recorrerlo, descomponiendo en cada iteración cada variable en sus correspondientes 2 bytes, y enviando cada byte uno a uno por I2C. Este es el código necesario para enviar cada paquete de 6 variables, y que cargaremos en el STM32:

  Wire.beginTransmission(4);                       // Comenzar transmision con dirección 4
  for (int i = 0; i < 6; i++) {                    // Recorrer una a una las variables a enviar
    byte* variables_byte = (byte*)&variables[i];   // Transformar cada variable a bytes
    Wire.write(variables_byte, 2);                 // Enviar cada variable (2 bytes)
  }
  Wire.endTransmission();                          // Terminar transmision con dirección 4

Para recibir estas variables (Arduino Nano) utilizaremos esta línea de código. Para recibir las variables utilizaremos también un bucle for, donde en cada iteración volveremos a recomponer cada variable a partir de los paquetes de 2 bytes que recibamos. En este ejemplo, necesitamos un bucle for con 6 iteraciones, una por cada variables que esperamos recibir:

while (Wire.available() < 6 * 2)delay(1);
for (int i = 0; i < 6; i++) variables_NANO[i] = Wire.read() | Wire.read() << 8;

Como veis, el receptor tiene que saber de antemano cuantas variables y de qué tamaño espera recibir. 

Software completo

  • Emisor (STM32)

#include <Wire.h>                  // I2C1 para comunicación con Arduino Nano
TwoWire HWire (2, I2C_FAST_MODE);  // I2C2 para comunicación con MPU6050

#define gyro_address 0x68
int16_t gyro_x, gyro_y, gyro_z, temperature;
int16_t acc_x, acc_y, acc_z;
int16_t variables_STM32[6];
int32_t loop_timer;

void setup() {
  Wire.setClock(400000);     // Velocidad 400kHz
  Wire.begin();              // Inicializar I2C1

  HWire.setClock(400000);    // Velocidad 400kHz
  HWire.begin();             // Inicializar I2C2

  Serial.begin(115200);      // Inicializar comunicacion serie
  init_gyro();               // Inicializar MPU
}

void loop() {

  // Ejecutamos el loop cada 4ms
  while (micros() - loop_timer < 4000);
  loop_timer = micros();

  // Leer MPU
  MPU_6050();

  // Generar array con las lecturas del MPU6050
  variables_STM32[0] = acc_x;
  variables_STM32[1] = acc_y;
  variables_STM32[2] = acc_z;
  variables_STM32[3] = gyro_x;
  variables_STM32[4] = gyro_y;
  variables_STM32[5] = gyro_z;

  Serial.print(variables_STM32[0]);
  Serial.print("\t");
  Serial.print(variables_STM32[1]);
  Serial.print("\t");
  Serial.print(variables_STM32[2]);
  Serial.print("\t");
  Serial.print(variables_STM32[3]);
  Serial.print("\t");
  Serial.print(variables_STM32[4]);
  Serial.print("\t");
  Serial.println(variables_STM32[5]);

  Wire.beginTransmission(4);                           // Comenzar transmision con dirección 4
  for (int i = 0; i < 6; i++) {                        // Recorrer una a una las variables a enviar
    byte* variables_byte = (byte*)&variables_STM32[i]; // Transformar cada variable a bytes
    Wire.write(variables_byte, 2);                     // Enviar cada variable (2 bytes)
  }
  Wire.endTransmission();                              // Terminar transmision con dirección 4
}

//================= Leer MPU6050
void MPU_6050() {
  HWire.beginTransmission(0x68);
  HWire.write(0x3B);
  HWire.endTransmission();
  HWire.requestFrom(0x68, 14);
  while (HWire.available() < 14);
  acc_x = HWire.read() << 8 | HWire.read();
  acc_y = HWire.read() << 8 | HWire.read();
  acc_z = HWire.read() << 8 | HWire.read();
  temperature = HWire.read() << 8 | HWire.read();
  gyro_x = HWire.read() << 8 | HWire.read();
  gyro_y = HWire.read() << 8 | HWire.read();
  gyro_z = HWire.read() << 8 | HWire.read();
}

//================= Subrutina inicilialización (solo se ejecuta una vez al iniciar el programa)
void init_gyro() {
  HWire.beginTransmission(0x68);
  HWire.write(0x6B);
  HWire.write(0x00);
  HWire.endTransmission();
  //Configure the accelerometer (+/-8g)
  HWire.beginTransmission(0x68);
  HWire.write(0x1C);
  HWire.write(0x10);
  HWire.endTransmission();
  //Configure the gyro (500dps full scale)
  HWire.beginTransmission(0x68);
  HWire.write(0x1B);
  HWire.write(0x08);
  HWire.endTransmission();
}
  • Receptor (Arduino Nano)

#include <Wire.h>

int16_t variables_NANO[6];

void setup() {
  Wire.begin(4);           // Asignamos la dirección 4 al Arduino Nano
  Wire.setClock(400000);   // Velocidad 400kHz

  Wire.onReceive(receiveEvent); // Necesario para recibir datos por I2C

  Serial.begin(115200);
}

void loop() {

  // Hasta no recibir 6*2 = 12 bytes, no hacer nada
  while (Wire.available() < 6 * 2)delay(1);
  // Recomponer cada variable a partir de cada paquete de 2 bytes
  for (int i = 0; i < 6; i++) variables_NANO[i] = Wire.read() | Wire.read() << 8;

  // Visualizar variables recibidas
  Serial.print(variables_NANO[0]);
  Serial.print("\t");
  Serial.print(variables_NANO[1]);
  Serial.print("\t");
  Serial.print(variables_NANO[2]);
  Serial.print("\t");
  Serial.print(variables_NANO[3]);
  Serial.print("\t");
  Serial.print(variables_NANO[4]);
  Serial.print("\t");
  Serial.println(variables_NANO[5]);
}

void receiveEvent(int howMany) {
}

Añadir un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *