Hi, I am trying to write a program that reads the values from a three axis accelerometer (adxl330 from sparkfun) and then prints the "g" value through the serial monitor. I know that the adxl330 is ratiometric but I'm not sure what the equation is to take the value I get from analogRead() and say how many g's it is.
I built a small DC-DC converter to reduce the arduino's 5V down to 3V to power the adxl330. At rest my voltmeter reads x=1.49V, y=1.54, z=1.82 volts. The analogRead() values are around 315, 325, 390 for x,y,z. This makes sense because the 10-bit ADC on the arduino follows the equation (voltage/5)*(2^10).
I think the equation to convert to g's is (outputvoltage - 0g_voltage)/0.3
Does anyone know if this is the correct way to do it?
I have the same type accelerometer, and I find I need to calibrate each axis for -1, 0, and 1 G. You can do this by orienting the accelerometer with each axis pointing up, down, or sideways, and averaging a large number of samples. Ideally, 0 should be -3 G, 511 should be zero G and 1023 should be +3 G, but I find they're each a little different.
I should have mentioned that aref needs to be connected to 3v to use the entire 0-1023 range. Otherwise 1023 will mean 5v and -3 to +3G will in the first 3/5 of that range.
Thx Drd. I was wondering why my 0g position was reading ~315 instead of 512, but I never set AREF to 3V so I guess that explains it.
How many samples do you take and average? I had not thought of that. Have you made anything interesting with your accelerometer? These little things are cool.
Edit- How do you set AREF to 3V? I just connected the AREF pin to my 3V output but the pin still reads 5V on my meter. Do I have to configure AREF in my program?
What I tried was 512 samples at 20 ms apart, and use a long variable to accumulate it into, so as not to overflow a 16-bit int. I'm wanting to make a IMU to take flying, mainly for attitude reference. These little sensors are very neat! I'm also using some ADRSX401 gyro/rate sensors, which are 5v devices, so the aref thing gets complicated.
If you are doing IMU stuff, there's good info over Spark Fun forum.
No! The 330 is a 3v device, so don't feed it 5v - you might fry it. If you aren't reading any 5v analog devices I think you can connect the 3v to aref. Be careful - I don't know your situation, and I might be wrong.
I'll look for better information, and get back to you.
Only connecting AREF to 3V doesn't work without doing something to the code. My AREF pin is 5V on its own, but when I connect the 3V it does nothing and actually 'overrides' my 3V bus so that anything else connected to it now sees 5V.
According to Massimo:
The aref works like this...
When you do analogue to digital conversion the arduino board uses the 5V supply as a reference. this means that any voltage between 0 and 5v is represented as numbers between 0 and 1024. If the signal you are measuring never reaches 5V it is possible to change the reference to an internal 2.5 v source and this divides the space between 0 and 2.5v in 1024 steps effectively doubling the resolution. If this still doesn't work for you then you can ask the processor to use an external voltage applied to aref. if you find a super stable 1V refernce source this will give you 1milli volt resolution for the ADC. this is used only in special applications because at that resolution the noise becomes a big issue etc etc
switching reference voltage requires adding a few lines of C code to your arduino code.
Summarising : changing your aref is advised only if you have good grasp of analogue electronics otherwise it's a mess..
Now if only I could figure out what these lines of code are.
Mellis informed me that I don't need to modify wiring.c and can make the needed modifications to the ADMUX register in my setup function, I just had to add the following definitions to my program:
Now that I have the ADC values does anyone know how to calculate the g value?
The equation should be: gvalue = [(ADCvalue * 3) / 1024 - 1.5] / 0.3
but I don't know how to program these fractional calculations.
I can't figure out how to handle fractions since I only have int variables :-?
I have nearly finished my code. I tried following nrollands idea for my calculations and in theory it should work, at least it does when I test it on my calculator. However I'm getting strange results that I don't understand. An example is it sometimes displays something like "589 = 0.-22g" and the digit in front of the decimal point is always 0 when it should change to 1,2,3...
Here is my code:
//Definitions needed to for cbi (clear bit) and sbi (set bit)
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
#define zerog_x 531 //X ADC value in the zero G position & is theoretically 512
#define calconst 1087//constant used when converting ADC values to g's
//variables
int xadc=0; //X ADC value
int yadc=0; //Y ADC value
int zadc=0; //Z ADC value
long xGval=0; //X g value
int num1=0; //digit in front of decimal place
int num2=0; //digits after decimal place
void setup() {
cbi(ADMUX, REFS1); //set a2d reference voltage to external AREF pin ...
cbi(ADMUX, REFS0); //... so that ADC uses 3V instead of 5V
Serial.begin(9600); // use the serial port to send values back to the PC
}
void loop() {
xadc=analogRead(0); //read x-axis values from analog in 0
yadc=analogRead(1); //read y-axis values from analog in 1
zadc=analogRead(2); //read z-axis values from analog in 2
delay(1);
xadc+=analogRead(0);
xadc = xadc / 2; //take an average for accuracy & less error
yadc+=analogRead(1);
yadc = yadc / 2;
zadc+=analogRead(2);
zadc = zadc / 2;
if(xadc < zerog_x){ //calculations for negative g values
xGval = calconst*(xadc-zerog_x);
xGval = abs(xGval);
xGval = xGval>>10;
num1=xGval/100;
num2=xGval%100;
Serial.print(xadc);
Serial.print("= -");
Serial.print(num1);
Serial.print(".");
Serial.print(num2);
Serial.println("g");
}
else{ //calculations for positive g values
xGval = calconst*(xadc-zerog_x);
xGval = xGval>>10;
num1=xGval/100;
num2=xGval%100;
Serial.print(xadc);
Serial.print("= ");
Serial.print(num1);
Serial.print(".");
Serial.print(num2);
Serial.println("g"); // should look like: "xadc= num1.num2 g"
}
delay(1000); //slow down so its easier to read the serial monitor
Serial.println();
}
Any suggestions? I know my coding style is not very good, but I'm learning