ADXL335 Accelerometer on an Arduino

I picked up an ADXL335 accelerometer in a packaging designed to fit onto a solder-less breadboard so that I could interface it to my Arduino. I had a few time-consuming problems interfacing with it because I’m not used to reading chip data sheets.

My assumption was that you’d deliver voltage to it, and it would spit out an analog signal that could be easy translated to acceleration using some constant factor. This isn’t exactly the case. The output resolution, milliVolts per g (1 g = Earth gravity), and voltage bias, is dependent on the voltage delivered to the power pin. I think in hindsight this makes sense, but the data sheet phrases this, and a few other things very peculiarly. I’m fairly inexperienced reading chip data sheets.

The data sheet is here (PDF). On the third page is pretty much everything you need to know to get useful data out of it, and the rest of the doc is stuff most hobbyist level people don’t care about, like how it behaves in different temperatures, and noise expectancy.

The phrase “RATIOMETRIC” shows up a few times. What this means is that a few of the specs are dependent on the power delivered to the chip. The sensitivity (mV/g) is stated to be ratiometric, and the example they give is that when you deliver 3V to the power supply, the sensitivity is 300 mV/g. In a later section called “Use with operating voltages other than 3V” it gives the example of 360 mV/g with a 3.6V power supply, and 195 mV/g with a 2V power supply. You can pretty much gather that the sensitivity in mV/g is the power supply voltage divided by 10. More or less.

Another ratiometric value is the “0g bias”. I don’t do a whole lot of analog electronics stuff, so this took me a bit to figure out. The accelerometer chip can detect negative acceleration, but it doesn’t output a negative voltage signal. What you do is consider the middle point of the power supply voltage range the 0 point. My power supply voltage is 3.3V, so I have to treat 1.6V as the zero point. You’ll add have to subtract that zero point from any voltage reading to get the actual mV/g value.

Here’s some numbers to drive the point home. My power supply is 3.3V, which is 3300 mV. 3300 divided by 10 is 330, so the chip is going to deliver 330 mV per 1g of acceleration. If I have the module on my table with the z-axis point up, it’s going to have 1g of acceleration applied to it, since it’s going to just read the pull of the Earth’s gravity and no other force. The chip’s zero point is the middle of the power supply range, 1.6V (1600 mV), so the actual voltage value it’s going to output for 1g of acceleration is 1930 mV, or 1.93 Volts. Since I know all this, I only need to subtract the zero point voltage to get the true value of 330 mV.

If I turn my accelerometer upside-down, it’s going to feel -1g of force. The voltage it would output would be 1.27V. When you subtract the zero point voltage you get -330 mV, which comes out to -1g.

Anyways, here’s the Arduino code that gets values for the X, Y, and Z axis spit out in units of g.

//Quick accelerometer test
//X is on A0; Y is on A1; Z is on A2

//Analog input pins 0, 1, and 2
//are what I send the x,y, and z
//accelerometer outputs to, respectively
int xAxisPin = A0;
int yAxisPin = A1;
int zAxisPin = A2;

//Variables to hold the returned
//ADC data from the analog input
//pins
int xAxisValADC = 0;
int yAxisValADC = 0;
int zAxisValADC = 0;

//Variables to hold the voltage
//values after converting from ADC
//units to mV
float xAxisValmV = 0;
float yAxisValmV = 0;
float zAxisValmV = 0;

//My Arduino Uno has a 10-bit
//AD converter, with a max value
//of 1023
int ADCMaxVal = 1023;

//The AD converter voltage
//is powered by 5V
float mVMaxVal = 5000;

//I measured the power going to the
//accelerometer as actually being 
//3230 mV, so I use this value to 
//define the mid-point
float supplyMidPointmV = 3230 / 2;

//Since the supply is actually 3230
//mV, I know the output will be 323mV
//per 1g detected
int mVperg = 323;

//Multiply any acquired ADC value
//by mVPerADC to convert to mV
float mVPerADC = mVMaxVal / ADCMaxVal;

void setup()
{
  Serial.begin(9600);
  
  //I don't know if setting them to
  //input is necessary, but I do it
  //anyways.
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  pinMode(A2, INPUT);
  
}

void loop()
{
  //Read the x, y, and z values from
  //the analog input pins
  xAxisValADC = analogRead(xAxisPin);
  yAxisValADC = analogRead(yAxisPin);
  zAxisValADC = analogRead(zAxisPin);
  
  //Convert the ADC values to millivolts
  xAxisValmV = xAxisValADC * mVPerADC;
  yAxisValmV = yAxisValADC * mVPerADC;
  zAxisValmV = zAxisValADC * mVPerADC;
  
  //This could be prettier. What's happening is the mid-point
  //voltage value is subtracted from the voltage recorded
  //from the analog input, and then that value is divided
  //by how many millivolts per g the accelerometer is
  //ouputing. This results in the value being printed
  //in units of g.
  Serial.print((xAxisValmV - supplyMidPointmV) / mVperg);
  Serial.print("\t");
  Serial.print((yAxisValmV - supplyMidPointmV) / mVperg);
  Serial.print("\t");
  Serial.print((zAxisValmV - supplyMidPointmV) / mVperg);
  Serial.print("\t");   
  
  Serial.println();
  
  delay(100);
}

It’s a bit verbose, but I wanted to be super clear about what is going on.

I dumped 20 seconds of gathered data into a .txt file and used Excel to make this pretty graph.

accelchart

For the first few seconds it’s just sitting on the table, so the z-axis is at 1g, and the x and y-axis are at about 0 (these aren’t calibrated readings, but it’s good enough). You can see when I pick it up and shake it around a bit, then put it back on the table. Neat.

The motivation for writing this post is because it took me about an hour to reconcile the info in the data sheet with the values I was reading on the analog inputs. It was hard to find anything useful online that stated plainly what you need to do on the Arduino end. Hopefully this helps someone out.

Post a comment or message me on Twitter (@cheydrick) if you have any questions.

This entry was posted in Uncategorized and tagged . Bookmark the permalink.

26 Responses to ADXL335 Accelerometer on an Arduino

  1. Mark Riad says:

    wonderful ! can i use the output values to determine the speed of an object ?

  2. Wags says:

    Did the data that you gathered come from serial print? if not where ? Did you simply dump data the data and excel did the formatting or is that a step you have to do with each row and column? Thank you for this article very very helpful 11/10

  3. Yes, the data came from the serial print lines in the listed code. I printed out “/t” in between the readings, which inserts a tab. Excel knows how to import tab delimited text and can automatically put the readings into columns. I could have also used a comma to delimit the data.

    Glad you liked the article; let me know if you have any other questions.

  4. Wags says:

    Thanks again for your fast reply, I am a high school student new to Arduino so excuse the simple questions …when you say you “dumped” the data into a txt file did you do this separately or did you use a plx-daq, program and if so where in the code would I put instructions? Is there any order to which I open first Excel or my arduino board/code. It is a nice graph have you tried different baud rates or delay settings to smooth things out? Do you think it would make any difference in sentivities. Thanks again for the post and response!

  5. Sure thing. I can’t remember how I got the data into a text file in this particular project, but it would have been one of two ways. I either copied the output from the serial monitor that’s part of the Arduino IDE, or I wrote a Python program to connect to the Arduino and save the data to a text file. All of my Arduino stuff is sitting on a shelf at work – I’ll dig it up on Monday and replicate the results so I can be more specific.

    Increasing the baud rate or the delay won’t affect the sensitivity (more on that later), but it would affect the max vibration frequency I could detect. The delay of 100 milliseconds means I’m sampling at 10 times a second, or 10 Hz. There’s a rule (called the Nyquist frequency) that says you have to sample data at least twice as fast as the frequency of interest. So at a 10 Hz sampling rate, I can only (barely) capture a 5 Hz vibration safely. Any other higher frequencies will be garbled (or aliased).

    The sensitivity of the accelerometer is a product of the power supply voltage, and the bit depth of the A/D converter. If I needed more sensitivity I think I’d start with using an A/D converter with 16 bits of resolution. The Arduino only has 10 bits, which is pretty good for most purposes.

  6. I think I did just copy/paste from the serial monitor into Excel. I just tried it and it worked.

    The fancier way would be to write a receiver program on the PC to read what the Arduino is outputting over the serial line. That’s not so hard to do in Python. It depends on what you’re trying to do.

    I use Arduino boards at work, but instead of reading serial data from them, I send serial data to them. They read the serial data and parse out the commands and to various things, like turn power on/off to some devices and send control signals to others.

  7. Upik Jamil says:

    I’m still confused about the power going to accelerometer, how do you determine the value is 3230mV? and what the function midpoint?

    • I used a multi-meter to read the actual voltage powering the accelerometer.

      The midpoint between 0 mV and 3230 mV is the voltage that is output by the accelerometer when the acceleration is 0 G. Knowing this is required to calculate the actual G value.

  8. DShah says:

    Hey, Thank you for this project. I am planning to use same sensor for my project. I want to know that, is this code helpful for acceleration measurement of falling object ? I also want to know that can I detect that, at what acceleration falling object hit the ground?

    • Sure. The code samples just print out what acceleration is measured by the sensor.

      Here’s a copy/paste from Wikipedia’s article on accelerometers: “…an accelerometer at rest on the surface of the Earth will measure an acceleration due to Earth’s gravity, straight upwards (by definition) of g ≈ 9.81 m/s2. By contrast, accelerometers in free fall (falling toward the center of the Earth at a rate of about 9.81 m/s2) will measure zero.”

  9. XIAOCHENG says:

    If I want to use ADXL335 to judge object movement status like walking or stationary, how to achieve this? Could you give me some advice?

  10. khalid1990 says:

    Hey sir …did this cod give me the final results of accelerations in x,y,z .? and this is meaning I don’t have to make calibration process ?.
    did your excel result show for z +axis up direction ?
    thank u …

  11. sjors says:

    I was wondering if you ever tried sampling at the maximum frequency, so 1600hz for the x and y-axes, and 550 for the z-axis. The datasheet says that adding a capacitor per axes in parallel would increase this sampling. However, I have tried this and unfortunately without result. So my main two questions are, do you have any experience with this so yes how did you do it, and secondly how can i accurately measure the sampling frequency of the sensor (and of my script?)? I am quite new at this 🙂

  12. Anonymous says:

    Still works, thanks!

  13. mark says:

    hi this is really useful thanks… question though, how about 4 accelerometers simultaneously? is that doable? and what about sample rate? I’m looking for a project that would focus on one sudden impact so would want the sample rate as high as possible, sorry if i sound dumb, but this isn’t my thing, asking for daughter.

    Many thanks in advance.

    • The accelerometer I used for this post sends data to the analog inputs on the Arduino board. Each accelerometer has three analog outputs (x/y/z) so four accelerometers would need twelve inputs on the Arduino. The Arduino Uno I used only has six analog inputs, so that model wouldn’t work. Other Arduino models have more analog inputs.

      There are accelerometers that send output digitally through SPI or I2C, which require fewer connections, and there are even accelerometers that have impact detection built in. Getting those communication protocols set up is more technically challenging than simply reading analog data, though. Sparkfun has a good writeup for the digital version of the accelerometer I used – https://learn.sparkfun.com/tutorials/adxl345-hookup-guide

      I think the max sampling rate on analog inputs is around 9 kHz, but any other processing (serial output, etc) would slow that down – https://arduino.stackexchange.com/questions/699/how-do-i-know-the-sampling-frequency/701#701

      If I was in a time crunch and only had the model of Arduino and accelerometer I had on hand for this post, I’d solve the problem with two Arduinos, each with two accelerometers attached.

  14. Anonymous says:

    Hi,
    I am working with ADXL345 and got the data output but i wanted to know if you can help me how to do FFT using Python on this signal obtained? 🙂

    Thanks in advance

  15. Anonymous says:

    Thanks i shall go through it… 🙂

  16. Jonathan Acharya says:

    how do i change x, y, z axis into a graph as it is showed in the above article, and also please tell me if that graph appends automatically?

    • If I recall (this was over three years ago) I copy/pasted the data from the Arduino Serial Monitor into a .txt file, then imported the .txt file into Excel. Not automatic at all.

  17. Anonymous says:

    Do you think it would be possible to sample the mV input to the accelerometer using another analog pin and assign that value to the mVperg variable? I might kind of act as a reference voltage. That might improve accuracy a bit?
    I haven’t measured the output voltage stability of an arduino supply, so I am just kind of guessing.
    Not sure, but it may account for variations in the input voltage to the accelerometer as loads change on the Arduino.

  18. Anonymous says:

    What is the sampling frequency of ADXL335 in Z direction? If I want to increase how do I increase the sampling frequency from 23Hz to 550 Hz?

    • The ADXL335 is an analog device, and doesn’t have a sampling rate. The sampling rate of the Arduino, which is doing the analog-to-digital conversion, is somewhat controllable. The sampling rate in my example is set by the 100 millisecond delay – roughly 10 Hz I guess? It’s hard to tell how long the samples actually take to acquire. Change that delay and it should change the sampling rate.

Leave a reply to Chris Heydrick Cancel reply