conectar dos acelerómetros digitales ADXL345 a Arduino Uno

Hola.
soy nuevo en el universo arduino y quería saber si es posible conectar dos acelerómetros digitales (ADXL345) al mismo arduino. Uno solo ya lo he conectado al puerto i2c y recibo datos perfectamente pero el segundo sensor no se como conectarlo.

saludos.

Hola:

Parece que si. El protocolo I2C es especificando la dirección del dispositivo esclavo. (y no sirve que sea la misma para dos dispositivos distintos). Pero si conectas a masa el pin 12 de la segunda placa cambia la dirección de esta.
O sea conectas todos en serie mas pin 12 a masa de la segunda placa.

Screen Shot 2015-02-17 at 12.16.55 .png

Hola y gracias perrociego.

no estoy utilizando el pin 12 para nada. con un solo ADXL345, conecto los pines SCL y SDA del sensor a los pines 15 y 16 del arduino uno. el código es el siguiente:

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_ADXL345_U.h>

/* Assign a unique ID to this sensor at the same time */
Adafruit_ADXL345_Unified accel = Adafruit_ADXL345_Unified(12345);

void displaySensorDetails(void)
{
 sensor_t sensor;
 accel.getSensor(&sensor);

 Serial.println("------------------------------------");
 Serial.print  ("Sensor:       "); Serial.println(sensor.name);
 Serial.print  ("Driver Ver:   "); Serial.println(sensor.version);
 Serial.print  ("Unique ID:    "); Serial.println(sensor.sensor_id);
 Serial.print  ("Max Value:    "); Serial.print(sensor.max_value); Serial.println(" m/s^2");
 Serial.print  ("Min Value:    "); Serial.print(sensor.min_value); Serial.println(" m/s^2");
 Serial.print  ("Resolution:   "); Serial.print(sensor.resolution); Serial.println(" m/s^2");  
 Serial.println("------------------------------------");
 Serial.println("");
 delay(500);

}

void displayDataRate(void)
{
 Serial.print  ("Data Rate:    "); 
 
 switch(accel.getDataRate())
 {
   case ADXL345_DATARATE_3200_HZ:
     Serial.print  ("3200 "); 
     break;
   case ADXL345_DATARATE_1600_HZ:
     Serial.print  ("1600 "); 
     break;
   case ADXL345_DATARATE_800_HZ:
     Serial.print  ("800 "); 
     break;
   case ADXL345_DATARATE_400_HZ:
     Serial.print  ("400 "); 
     break;
   case ADXL345_DATARATE_200_HZ:
     Serial.print  ("200 "); 
     break;
   case ADXL345_DATARATE_100_HZ:
     Serial.print  ("100 "); 
     break;
   case ADXL345_DATARATE_50_HZ:
     Serial.print  ("50 "); 
     break;
   case ADXL345_DATARATE_25_HZ:
     Serial.print  ("25 "); 
     break;
   case ADXL345_DATARATE_12_5_HZ:
     Serial.print  ("12.5 "); 
     break;
   case ADXL345_DATARATE_6_25HZ:
     Serial.print  ("6.25 "); 
     break;
   case ADXL345_DATARATE_3_13_HZ:
     Serial.print  ("3.13 "); 
     break;
   case ADXL345_DATARATE_1_56_HZ:
     Serial.print  ("1.56 "); 
     break;
   case ADXL345_DATARATE_0_78_HZ:
     Serial.print  ("0.78 "); 
     break;
   case ADXL345_DATARATE_0_39_HZ:
     Serial.print  ("0.39 "); 
     break;
   case ADXL345_DATARATE_0_20_HZ:
     Serial.print  ("0.20 "); 
     break;
   case ADXL345_DATARATE_0_10_HZ:
     Serial.print  ("0.10 "); 
     break;
   default:
     Serial.print  ("???? "); 
     break;
 }  
 Serial.println(" Hz");  
}

void displayRange(void)
{
 Serial.print  ("Range:         +/- "); 
 
 switch(accel.getRange())
 {
   case ADXL345_RANGE_16_G:
     Serial.print  ("16 "); 
     break;
   case ADXL345_RANGE_8_G:
     Serial.print  ("8 "); 
     break;
   case ADXL345_RANGE_4_G:
     Serial.print  ("4 "); 
     break;
   case ADXL345_RANGE_2_G:
     Serial.print  ("2 "); 
     break;
   default:
     Serial.print  ("?? "); 
     break;
 }  
 Serial.println(" g");  
}

void setup(void) 
{
 Serial.begin(9600);
 Serial.println("Accelerometer Test"); Serial.println("");
 
 /* Initialise the sensor */
 if(!accel.begin())
 {
   /* There was a problem detecting the ADXL345 ... check your connections */
   Serial.println("Ooops, no ADXL345 detected ... Check your wiring!");
   while(1);
 }

 /* Set the range to whatever is appropriate for your project */
 accel.setRange(ADXL345_RANGE_16_G);
 // displaySetRange(ADXL345_RANGE_8_G);
 // displaySetRange(ADXL345_RANGE_4_G);
 // displaySetRange(ADXL345_RANGE_2_G);
 
 /* Display some basic information on this sensor */
 displaySensorDetails();
 
 /* Display additional settings (outside the scope of sensor_t) */
 displayDataRate();
 displayRange();
 Serial.println("");
}

void loop(void) 
{
 /* Get a new sensor event */ 
 sensors_event_t event; 
 accel.getEvent(&event);

 /* Display the results (acceleration is measured in m/s^2) */
 /*Serial.print("X: ");*/ Serial.print(event.acceleration.x); Serial.print("  ");
 /*Serial.print("Y: ");*/ Serial.print(event.acceleration.y); Serial.print("  ");
 /*Serial.print("Z: ");*/ Serial.print(event.acceleration.z); Serial.println("  ");//Serial.println("m/s^2 ");
 delay(500);
}

Ahora quiero conectar un segundo sensor (ADXL345) al mismo arduino y no se como conectarlo. Dices de conectarlo en serie el segundo sensor con el primero?? Lo del pin 12 no lo entiendo.

Hola oscar2015, date una vuelta por las normas del foro y luego edita tu código por favor. Recuerda usar tags para imagenes, enlaces.

Veamos tu problema.

  1. Solución 1:
    De la hoja de datos del ADXL345

Rev. D | Page 15 of 40
SERIAL COMMUNICATIONS
I2C and SPI digital communications are available. In both cases, the ADXL345 operates as a slave. I2C mode is enabled if the CS pin is tied high to VDD I/O. The CS pin should always be tied high to VDD I/O or be driven by an external controller because there is no default mode if the CS pin is left unconnected. Therefore, not taking these precautions may result in an inability to communicate with the part. In SPI mode, the CS pin is controlled by the bus master. In both SPI and I2C modes of operation, data transmitted from the ADXL345 to the master device should be ignored during writes to the ADXL345.

Entonces una forma simple es destinar un pin de salida del Arduino para habilitar el chip deseado con CS en HIGH para el dispositivio 1 y otro I/O para el CS del segundo ADXL345. Simple no?

  1. Solución 2.
    El ADXL345 es SPI de modo que puedes usar ambos en paraleo y de nuevo elegirlos con CS high.

  2. Solución 3

With the ALT ADDRESS pin high, the 7-bit I2C address for the device is 0x1D, followed by the R/W bit. This translates to 0x3A for a write and 0x3B for a read. An alternate I2C address of 0x53 (followed by the R/W bit) can be chosen by grounding the ALT ADDRESS pin (Pin 12). This translates to 0xA6 for a write and 0xA7 for a read.

Si usas el pin ALT ADDRESS en 1 o HIGH, la dirección será 0x1D
Si usas el pin ALT ADDRESS en 0 o LOW, la dirección será 0x53

Oscar:

Dije serie, no, corrijo, en paralelo.

La idea del protocolo I2C es poder conectar varias pequeñas placas periféricas con solo cuatro cables, VCC, GND, SDA y SCL. Va todo uno detrás de otro a los mismos cuatro cables, por eso cada periférico (esclavo) tiene que tener una dirección distinta, y el master (el Arduino) llama a cada uno por su dirección.
Como tenes dos placas iguales tienen en principio la misma dirección. Eso esta resuelto (es bastante común esto) con un pin extra en la placa, que si lo conectas a VCC es una dirección y si lo conectas a masa otra.
Y si tenes una tercera por este lado no funciona.

El incansable Surbyte aporta que también lo podes conectar con otro protocolo, SPI, que yo no use nunca. Es competencia del anterior pero creo que superior, al menos mas caro. En este caso van tres cable en paralelo y uno especial único para cada periférico con lo cual el master llama.

No especificas que Arduino estas usando, pero si es el DUE podes (creo) armar doble linea I2C o sea hasta 4 de estos periféricos. Mas la enorme cantidad que podes por SPI. Y mas multiplexando, etc.

Y después hay que programarlo. Je je.

Muchas gracias a surbyte y perrociego por vuestra ayuda.
he puesto los dos sensores en paralelo y utilizo el pin CS de cada uno para seleccionar uno u otro. Lo he probado con un pequeño sketch que selecciona uno y despues lo modificado para que seleccione el otro y funciona.
Ahora me queda realizar un sketch que tome datos de ellos (primero de uno y después del otro) lo más rápido posible. Iré comentando como va.

Gracias .

A oscar2015
Ni cuenta te daras del cambio de uno a otro cuando tomes valores.
Ya verás.

A Perrociego:

perrociego:
El incansable Surbyte aporta que también lo podes conectar con otro protocolo, SPI, que yo no use nunca. Es competencia del anterior pero creo que superior, al menos mas caro. En este caso van tres cable en paralelo y uno especial único para cada periférico con lo cual el master llama.

Yo solo leí la hoja de datos y por eso sugerí lo que se desprende de ella.

Tambien di las pautas de como usarlo con i2C que no mencionaste perrociego jajaja
Siempre hay que ir a la fuente.

Hola.

Después de un par de semanas en las que he estado ocupado vuelvo con este pequeño proyecto y acabarlo de una vez. Pero estoy teniendo algunos problemas:

He decidido utilizar SPI para conectar los dos sensores en paralelo porque necesito que la comunicación sea lo más rápida posible:

SDO → Pin 11 (MOSI)
SDA → Pin 12 (MISO)
SCL → Pin 13 (SCK)

El CS de cada sensor lo conecto a los pines 9 y 10 del arduino uno respectivamente.
He simplificado el código para que sea más fácil de depurar e irlo ampliando poco a poco:

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_ADXL345_U.h>
#include <SPI.h>

/* Assign a unique ID to this sensor at the same time */
Adafruit_ADXL345_Unified accel_1 = Adafruit_ADXL345_Unified(13,12,11,10);
Adafruit_ADXL345_Unified accel_2 = Adafruit_ADXL345_Unified(13,12,11,9);

const int s1=10;
const int s2=9;

void setup(void) 
{
  SPI.begin();
  Serial.begin(9600);
  Serial.println("Accelerometer Test"); Serial.println("");
  pinMode(s1,OUTPUT);
  pinMode(s2,OUTPUT);
  digitalWrite(s1,HIGH);
  digitalWrite(s2,LOW);
  
  /* Initialise the sensor */
  if(!accel_1.begin())
  {
    /* There was a problem detecting the ADXL345 ... check your connections */
    Serial.println("Ooops, no ADXL345 detected ... Check your wiring!");
    while(1);
  }

  /* Set the range to whatever is appropriate for your project */
  accel_1.setRange(ADXL345_RANGE_16_G);
 
  Serial.println("");
}

void loop(void) 
{
  /* Get a new sensor event */ 
  sensors_event_t event; 
  accel_1.getEvent(&event);
 
  /* Display the results (acceleration is measured in m/s^2) */
  Serial.print("X: "); Serial.print(event.acceleration.x); Serial.print("  ");
  Serial.print("Y: "); Serial.print(event.acceleration.y); Serial.print("  ");
  Serial.print("Z: "); Serial.print(event.acceleration.z); Serial.print("  ");Serial.println("m/s^2 ");
  delay(500);
}

Cuando abro el monitor del puerto serie aparece el mensage de que no detecta el ADXL245:

"Ooops, no ADXL345 detected ... Check your wiring!"

ahhh falta una resistencia a vcc desde el CS de cada dispositivo. para asegurarte que estan dehabilitados.
luego te pongo una imagen.
Una R de 10k a 5V y a CS de cada dispositivo. Se selecciona activo bajo.

Muchas gracias por vuestra ayuda.

He hecho algunos cambios en el código y ahora funciona perfectamente.

Dejo el código a continuación por si a alguien le sirve.

//Add the SPI library so we can communicate with the ADXL345 sensor
#include <SPI.h>

//Assign the Chip Select signal to pin 10.
int CS=10;
int CS2=8;

unsigned long time;

//This is a list of some of the registers available on the ADXL345.
//To learn more about these and the rest of the registers on the ADXL345, read the datasheet!
char POWER_CTL = 0x2D;	//Power Control Register
char DATA_FORMAT = 0x31;
char DATAX0 = 0x32;	//X-Axis Data 0
char DATAX1 = 0x33;	//X-Axis Data 1
char DATAY0 = 0x34;	//Y-Axis Data 0
char DATAY1 = 0x35;	//Y-Axis Data 1
char DATAZ0 = 0x36;	//Z-Axis Data 0
char DATAZ1 = 0x37;	//Z-Axis Data 1

//This buffer will hold values read from the ADXL345 registers.
unsigned char values[10];
unsigned char values2[10];
//These variables will be used to hold the x,y and z axis accelerometer values.
int x,y,z;
double xg,yg,zg;

void setup(){ 
  //Initiate an SPI communication instance.
  SPI.begin();
  //Configure the SPI connection for the ADXL345.
  SPI.setDataMode(SPI_MODE3);
  //Create a serial connection to display the data on the terminal.
  Serial.begin(9600);
  
  //Set up the Chip Select pin to be an output from the Arduino.
  pinMode(CS, OUTPUT);
  pinMode(CS2, OUTPUT);
  digitalWrite(CS,HIGH);
  digitalWrite(CS2,HIGH);
  
  //Before communication starts, the Chip Select pin needs to be set high.
  
  //Put the first ADXL345 into +/- 16G range by writing the value 0x01 to the DATA_FORMAT register.
  writeRegister(DATA_FORMAT, 0x03);
  //Put the first ADXL345 into Measurement Mode by writing 0x08 to the POWER_CTL register.
  writeRegister(POWER_CTL, 0x08);  //Measurement mode  
  delay(100);
  
  //Put the second ADXL345 into +/- 16G range by writing the value 0x01 to the DATA_FORMAT register.
  writeRegister_2(DATA_FORMAT, 0x03);
  //Put the second ADXL345 into Measurement Mode by writing 0x08 to the POWER_CTL register.
  writeRegister_2(POWER_CTL, 0x08);  //Measurement mode  
  delay(100);
 
  
}

void loop(){
  //Reading 6 bytes of data starting at register DATAX0 will retrieve the x,y and z acceleration values from the ADXL345.
  //The results of the read operation will get stored to the values[] buffer.
  readRegister(DATAX0, 6, values);

  //The ADXL345 gives 10-bit acceleration values, but they are stored as bytes (8-bits). To get the full value, two bytes must be combined for each axis.
  //The X value is stored in values[0] and values[1].
  x =(int)( ( ( ( unsigned int )( values[1]&255 )) << 8 ) | (unsigned int)(values[0])&255);
  //The Y value is stored in values[2] and values[3].
  y = (int)( ( ( ( unsigned int )( values[3]&255 )) << 8 ) | (unsigned int)(values[2])&255); 
 
  
  xg=x*0.0078*4*9.81;
  yg=y*0.0078*4*9.81;
  
  //Print the results to the terminal.
  time=millis();
  Serial.print(time);
  Serial.print(" ");
  Serial.print(xg);
  Serial.print(" ");
  Serial.print(yg);
  Serial.print(" ");  
  delay(1); 
  
  ////////////////////////////////second sensor//////////////////////////////////////
   readRegister_2(DATAX0, 6, values);

  //The ADXL345 gives 10-bit acceleration values, but they are stored as bytes (8-bits). To get the full value, two bytes must be combined for each axis.
  //The X value is stored in values[0] and values[1].
  
  x =(int)( ( ( ( unsigned int )( values[1]&255 )) << 8 ) | (unsigned int)(values[0])&255);
  //The Y value is stored in values[2] and values[3].
  y = (int)( ( ( ( unsigned int )( values[3]&255 )) << 8 ) | (unsigned int)(values[2])&255); 
  //The Z value is stored in values[4] and values[5].
     
  xg=x*0.0078*4*9.81;
  yg=y*0.0078*4*9.81;
 
  //Print the results to the terminal.
  time=millis();
  Serial.print(time);
  Serial.print(" ");
  Serial.print(xg);
  Serial.print(" ");
  Serial.println(yg);
  delay(1);
  /////////////////////////////////////////////////////////////////////
  
}

//This function will write a value to a register on the ADXL345.
//Parameters:
//  char registerAddress - The register to write a value to
//  char value - The value to be written to the specified register.
void writeRegister(char registerAddress, char value){
  //Set Chip Select pin low to signal the beginning of an SPI packet.
  digitalWrite(CS, LOW);
  //Transfer the register address over SPI.
  SPI.transfer(registerAddress);
  //Transfer the desired register value over SPI.
  SPI.transfer(value);
  //Set the Chip Select pin high to signal the end of an SPI packet.
  digitalWrite(CS, HIGH);
}

//This function will read a certain number of registers starting from a specified address and store their values in a buffer.
//Parameters:
//  char registerAddress - The register addresse to start the read sequence from.
//  int numBytes - The number of registers that should be read.
//  char * values - A pointer to a buffer where the results of the operation should be stored.
void readRegister(char registerAddress, int numBytes, unsigned char * values){
  //Since we're performing a read operation, the most significant bit of the register address should be set.
  char address = 0x80 | registerAddress;
  //If we're doing a multi-byte read, bit 6 needs to be set as well.
  if(numBytes > 1)address = address | 0x40;
  
  //Set the Chip select pin low to start an SPI packet.
  
  
  digitalWrite(CS, LOW);
  
  //Transfer the starting register address that needs to be read.
  SPI.transfer(address);
  //Continue to read registers until we've read the number specified, storing the results to the input buffer.
  for(int i=0; i<numBytes; i++){
    values[i] = SPI.transfer(0x00);
  }
  //Set the Chips Select pin high to end the SPI packet.
  digitalWrite(CS, HIGH);
  
}

void writeRegister_2(char registerAddress, char value){
  //Set Chip Select pin low to signal the beginning of an SPI packet.
 
  digitalWrite(CS2, LOW);
  //Transfer the register address over SPI.
  SPI.transfer(registerAddress);
  //Transfer the desired register value over SPI.
  SPI.transfer(value);
  //Set the Chip Select pin high to signal the end of an SPI packet.
  digitalWrite(CS2, HIGH);
}

//This function will read a certain number of registers starting from a specified address and store their values in a buffer.
//Parameters:
//  char registerAddress - The register addresse to start the read sequence from.
//  int numBytes - The number of registers that should be read.
//  char * values - A pointer to a buffer where the results of the operation should be stored.
void readRegister_2(char registerAddress, int numBytes, unsigned char * values2){
  //Since we're performing a read operation, the most significant bit of the register address should be set.
  char address = 0x80 | registerAddress;
  //If we're doing a multi-byte read, bit 6 needs to be set as well.
  if(numBytes > 1)address = address | 0x40;
  
  //Set the Chip select pin low to start an SPI packet.
  digitalWrite(CS2, LOW);
  
  //digitalWrite(CS, HIGH);
  
  //Transfer the starting register address that needs to be read.
  SPI.transfer(address);
  //Continue to read registers until we've read the number specified, storing the results to the input buffer.
  for(int i=0; i<numBytes; i++){
    values2[i] = SPI.transfer(0x00);
  }
  //Set the Chips Select pin high to end the SPI packet.
  digitalWrite(CS2, HIGH);
  
}

En el código solo aparecen dos ejes, eso es porque para lo que yo lo quiero solo necesito dos ejes.

Hola Oscar. estoy revisando tu foro. Tendras un mail donde me pueda comunicar contigo?....feliz dia!

Mar 11, 2015, 10:34 am fecha de la última respuesta.

Hola!!

Soy nueva también en arduino y justamente también estoy intentando conectar dos acelerómetros ADXL345, pero a una Leonardo. Utilizo los pines SCL y SDA de este arduino, que esta placa los tiene, pero no me funciona. ¿Debería hacer más cambios?

Con un acelerómetro sí me va.

Gracias!!!!!!

Eso ocurre porque debes cambiarle a un ADXL345 la dirección. Mira el post#3 donde explico justamente eso.

Hola buenas!!
Muy interesante el artículo.
Yo tengo un problema similar, aunque en mi caso se trata de conectar un acelerómetro ADXL345(de Adafruit) y un reloj RTC DS1307(de Sparkfun) ambos mediante protocolo I2C a una placa Arduino UNO y usando las librerías de ambos fabricantes.
El problema es que aunque ambos funcionan perfectamente por separado, al conectar la señal SDA del RTC, el acelerómetro deja de funcionar. Ya he probado a conectar resistencias de pull UP y comprobar que ambos dispositivos no comparten direcciones según datasheet. Ademas (no se si tendrá que ver) usando un sencillo sketch para escanear el bus me dice la dirección que tiene el ADXL345, pero cuando conecto el RTC no me la dice simplemente se que da escaneando infinitamente.
¿Se os ocurre que mas podría probar?? surbyte confío en ti!!!
Gracias por adelantado

El ADXL345 según su hoja de datos se alimenta entre 2 y 3.6V que en términos prácticos 3.3V por lo tanto tu problema es que el RTC trabaja a 5V de modo que tienes un problema de niveles.
Tu solución es usar un adaptador de niveles para el ADXL345. Como no has dicho nada más, yo supongo que lo tienes en forma de chip ahora si tienes un módulo verifica que esto no este implementado. Pero considerando que falla debo concluir que no.
Este circuito

resolverá el problema, pero lo usas solo para el ADXL345 y tu conexión HIGH SIDE es la que conectas al BUS I2C.
El lado Low Side ira al ADXL345