A tiny bit of explanations first, but you can jump to the drawings if you're bored, and also grab the sources from the bottom of the post. So, what's special about connecting two ADXLs? The fact that the communication between Arduino and the ADXLs is carried out by the means of the I2C protocol and the Arduino Wire library which basically implements this protocol. The Wire library uses analog pins 4 and 5 (20 and 21 on Arduino Mega) as the data and clock pins respectively. Each I2C device - in our case both ADXLs - needs to be connected to both pins. Which means both devices have to be connected to Arduino's data and clock pins. How does the Arduino tell them apart though? Well, the I2C protocol has a property called device address, which lets the master device talk to a specific device that's connected to the data and clock pins by pointing out it's address.
The ADXL345 datasheet says on page 10 tells us that the ADXL may have two addresses, depending on how you wire it. These addresses are 0x53 and 0x1D. The addresses altering is made by changing the HIGH/LOW state of the ADXL SDO pin. In my previous ADXL post I've wired it so that it responds to address 0x53, by grounding the SDO pin (setting it to LOW):
But here we need to connect another ADXL to the same Arduino, so we need another address, that's why we're applying voltage to the SDO pin, setting it to HIGH:
Ok, with that done let's take a look at the code that makes this stuff work. I won't go in detail through basic ADXL345/Arduino interaction because I've done that here, I'll just point out the differences between connecting one and two ADXLs.
This is the write function (it will be used for both devices):
void writeTo(int device, byte address, byte val) { Wire.beginTransmission(device); //start transmission to device Wire.write(address); // send register address Wire.write(val); // send value to write Wire.endTransmission(); //end transmission }
This is the read function (it will be used for both devices):
void readFrom(int device, byte address, int num, byte buff[]) { Wire.beginTransmission(device); //start transmission to device Wire.write(address); //sends address to read from Wire.endTransmission(); //end transmission Wire.beginTransmission(device); //start transmission to device Wire.requestFrom(device, num); // request 6 bytes from device int i = 0; while(Wire.available()) //device may send less than requested (abnormal) { buff[i] = Wire.read(); // receive a byte i++; } Wire.endTransmission(); //end transmission }
Now the interesting parts.
#include <Wire.h> #define DEVICE_A (0x1D) //first ADXL345 device address #define DEVICE_B (0x53) //second ADXL345 device address #define TO_READ (6) //num of bytes we are going to read each time (two bytes for each axis) byte buff[TO_READ] ; //6 bytes buffer for saving data read from the device char str[512]; //string buffer to transform data before sending it to the serial port void setup() { Wire.begin(); // join i2c bus (address optional for master) Serial.begin(9600); // start serial for output //Turning on the both ADXL345s writeTo(DEVICE_A, 0x2D, 24); writeTo(DEVICE_B, 0x2D, 24); }What's interesting here? First of all we define two addresses, one for each device, and we send the ON command to each device separately (the writeTo() lines).
Now let's see the actual readings from the devices:
int regAddress = 0x32; //first axis-acceleration-data register on the ADXL345 int xa = 0, ya = 0, za = 0; int xb = 0, yb = 0, zb = 0; void loop() { readFrom(DEVICE_A, regAddress, TO_READ, buff); //read the acceleration data from the ADXL345 //each axis reading comes in 10 bit resolution, ie 2 bytes. Least Significat Byte first!! //thus we are converting both bytes in to one int xa = (((int)buff[1]) << 8) | buff[0]; ya = (((int)buff[3])<< 8) | buff[2]; za = (((int)buff[5]) << 8) | buff[4]; readFrom(DEVICE_B, regAddress, TO_READ, buff); //read the acceleration data from the second ADXL345 xb = (((int)buff[1]) << 8) | buff[0]; yb = (((int)buff[3])<< 8) | buff[2]; zb = (((int)buff[5]) << 8) | buff[4]; //we send the x y z values as a string to the serial port sprintf(str, "%d %d %d %d %d %d", xa, ya, za, xb, yb, zb); Serial.print(str); Serial.write(10); //It appears that delay is needed in order not to clog the port delay(15); }Ok, first we have defined the variables needed for reading - the address that we want to read from (it's the same for both devices, because they're two instances of the same device). And then we define the vars we want to store that data in. Now, in the loop we perform a reading from DEVICE_A, convert the data that we got in the buff variables to the respective axes vars, and then do the same reading only from DEVICE_B, and again, store the data and voilà, we pack the data in to a nice string and send it away through the serial port!
Well, me thinks that that's it :) give me a shout if you have questions or find errors.
Thy sources
With great pleasure I found your post, as I (am too old to become a coder I) was looking for such an solution!.
ReplyDeleteNow I've run into some ?wiring? issue: when connecting the SDO to 3V3 (the right ADXL), all lEDs go out and the monitor doesn't give any new lines.
Switching the ADXL's shows that both sensors are not broken.
Do you have any suggestion?
thx Cor
Hi Cor :)
DeleteIf all LEDs go out it might mean that you are shorting the circuit when connecting the second SDO to 3v3 - maybe putting it in GND by mistake?
Hello Euristic,
ReplyDeleteI also think that somewhere I must have misconnected a wire. As a test I made:
the left ADXL SDO connect to 3V3
the right ADXL SDO connect to GND.
When doing so: All LED's go of and no readings at the serial monitor
When disconnecting the left ADXL SDO from 3V3, then the lights go on again.
As the "problem" shifted from right to left, I think that my wiring of both ADXL's is conform drawing, and are working individually. But not yet together...
When you plug them individually they work? Are you using different breadboards for that, or simply cutting the power off for each one?
Deleteindividually: ADXL left SDO GND : works
ReplyDeleteindividually: ADXL right SDO GND : works
individually: ADXL left or right SDO 3V3 : LEDs out = doesn't work
I use one breadboard, I have both ADXL's connected with ribbon cables
If you like I can send you a few pictures of how I wired.
you can send your email adres to cor@vanmarion.net
thx
Cor
Cool, I'll contact you via email
Deletedid you figure it out? Ive got two working individualy, but not both at the same time :(
DeleteAny luck getting both to work? I'm having basically the same problem, when I connect both, nothing works, but individually they work.
ReplyDeleteI have the 0x53 device's SDO floating. I plan to ground it to test if that's the issue. I also am not using the resisitors for sda and scl.
@Jeff hi there :)
DeleteMaybe you should wire the elements just as described on the scheme? I just did to re-test the whole thing and it works like a charm.
You sir are correct!
Deleteadding the ground on 0x53 didn't matter, but the resistors are needed. Individually they aren't, but when you run both, you need the resistors.
Thanks for posting this, the wiring diagram is helpful.
I'm using the code from: https://github.com/jrowberg/i2cdevlib
it's the only library I found that doesn't hard code the device address, and also has nice functions to handle all the config and interupts
please give me a solution to programm ADXL345 with arduino
ReplyDelete@Khawla do you need help with anything specific?
DeleteYou can also email me: livefast.codeyoung at gmail dot com
Hi! in this article you have connected 2 ADXL345, and how to connect 3 pieces?
ReplyDeleteHi Sergey,
Deleteas there are only two possible addresses for the ADXLs, you can either reimplement the Wire library (probably a bad idea!) so it uses other in/out ports than Analog4/5. Or you could use another arduino to the readings of the 3rd/4th ADXL. There might be another way, but I can't really think of one.
Hey Buddy!
ReplyDeleteThe thing is i want the accelerometers to read different readings based on their relative motions in whatever directions. However this does not seem to be the case.
What is happening is the values of xb,yb,zb are shown as values of xa,ya,za in the very next instance and it keeps on repeating. i want the vales of xa,ya,za to be completely different than xb,yb,zb and different in every instance.
could you please help me out?
Appreciate it. Thanks for the code and connections bud! Really helped
Yo. Are yo usure you're using the right code? You can download the complete source code from here:
Deletehttp://www.cookietroll.com/blogfiles/adxl/two_adxls.ino
Well, same problem for me. I also do not read anything coherent from Z axis, just a 511 number.
DeleteThank in advance!
This comment has been removed by the author.
ReplyDeletehello friend,can you help me to replace ADXL335 with ADXL345
ReplyDeleteI need to replace this in my project
what changes should i make to program
contact me:karthik18.rk@gmail.com
Hello,
ReplyDeleteThanks for your post. It is really helpfull and works perfectly. However, I would like to understand what are the resistances used for?
I can't find and understand why you are using them for.
Thanks in advance
Hi,
Deletethe resistors are used because that's how the right way to connect the ADXL345 is described in the datasheet. So, wasn't my decision :)
Hi Euristic,
DeleteThanks for you quick answer! :-)
Hi Euristic,
ReplyDeleteCan I request for a clearer picture of your wiring ?
I desperately needs this for my final year project. I tried following your photo but it doesnt work.
Here is my email: thisisyuketin@gmail.com
You wrote .."These addresses are 0x53 and 0xD1."
ReplyDeleteIt is 0x53 and 1D. Just a small typo - Please fix it.
Fixed. Thanks!
DeleteCan you please provide the code for ADXL335? what is the device address or I2C address for ADXL335?.Please forward it to my mail.
ReplyDeleteuttiugesh@gmail.com
Can we calculate the difference between the two angles received??
ReplyDeleteYes definitely, just subtract xa from xb, ya from yb etc and you'll get your difference.
DeleteThank you for your response.
ReplyDeleteI'm Under Construction a device
To read the angles of the body joints
Below is attached the address
if possible, help me in doing
https://deskgram.net/explore/tags/bikefit
https://business.facebook.com/pg/STTSystems/posts/
Hi, How can I apply this to my 4 servos? I tried to copy this and made some additional codes for the 4 servos to function but the result was not good. Only one command works for both adxl345 and not the different command. Can you help?
ReplyDeleteDepends on the servos. Not so sure you can use my code as is, probably needs tweaking and heavily depends on what's written in the servo's datasheet.
Delete