Hey everyone,
This is my first time trying to interface using I2C, and I seem to be having trouble reading accurate data. I don't quite understand LSB and MSB, so it might be a problem with my bit shifting.
I am trying to use the magnetometer to calculate the magnitude of the Earth's magnetic field, and instead of getting ~500 milligauss the data I get is closer to ~14000 milligauss.
I attached my code below and wondered if anyone had any suggestions.
When using the Wire library, you are reading or writing. You have mixed them together.
See my alternative explanation of the functions of the Wire library.
I suggest to test in setup() the Product ID of the MMC5883.
Thank you for replying!
I have a few questions about I2C:
Do you not use beginTransmission() and endTransmission() when reading in I2C?
Also when reading from a slave device in I2C, how do you specify which register you want to read from using the Wire library?
First, the register-address is written to the sensor with Wire.beginTransmission(), Wire.write(register-address) and Wire.endTransmission().
The sensor will remember that register-address.
Next, the Wire.requestFrom() reads data from the sensor.
I am currently working with the same device. The inaccurate results are definitely because it is not calibrated, it seems complicated from the guides but it's actually very simple. Also, after you read the data in your code you have a Wire.endTransmission(); which should not be there, it is only used when writing to the slave device I believe.
to read data I used something like this:
Wire.beginTransmission(Dev_address);
Wire.write(0x00); //start measuring at xlsb
Wire.endTransmission();
Wire.requestFrom(Dev_address, 6);
if ((devstat & 0x01)==(0x01)){ //check the status register to make sure measurement is done
//read 6 bytes of data, starts at xlsb, internal memory address pointer automatically moves to the next byte
xl = Wire.read();//xlsb
xh = Wire.read();//xmsb
yl = Wire.read();//ylsb
yh = Wire.read();//ymsb
zl = Wire.read();//zlsb
zh = Wire.read();//zmsb
}
To write to the slave:
Wire.beginTransmission(Dev_address);
Wire.write(0x08);//control register 0
Wire.write(0x09);// initiate magnetic field measurement and SET
Wire.endTransmission();
@Koepel, I use the "read" code I posted above but instead of reading the magnetometer data registers, I read just one value from the status register which has the address 0x07 on my device. The status register also has some other information in it but I am only interested in checking if data is available at that time, hence the logical AND to check that the data bit is high.
So, you issue a wire.requestFrom() command regardless of whether data are ready, and don't bother to read the status flag again, after making the requestFrom() call.
Do you think this will work, and is programming practice to recommend to others?
Oops, I just saw this disclaimer:
to read data I used something like this:
Better idea: post complete code that has been tested, and actually works.
I'm having trouble storing the magnetometer data for calibration. I'm trying to use the serial port to transfer the data from the Arduino to Processing and then to a .csv file.
I was wondering if anyone had more user friendly suggestions for moving serial data to a .csv or .exl file for data visualization?
I use a terminal program like TeraTerm or Putty to capture and log serial data, each line formatted with Serial.print(), something like this: "121.3,-225.7,19.5". Add a .csv extension and you are finished.
Or, use PLX-DAQ to capture serial data directly to an Excel spreadsheet.
lsssm:
I am trying to use the magnetometer to calculate the magnitude of the Earth's magnetic field, and instead of getting ~500 milligauss the data I get is closer to ~14000 milligauss.
Hi!
I'm recently working on the same sensor, and reproduced your problem using your code. Notice on page 7 of the datasheet that all bytes are unsigned format, meaning that they are inherently positive, while the sensor can measure both plus and minus 8 Gauss. This suggests that the output 0000 0000 is actually -8000 mGauss, rather than 0 mG. My solution is then subtract 8000 for your computed x, y, z, i.e.:
xm = ((xh<<8) | xl);
x = xm * .25 - 8000;
ym = ((yh<<8) | yl);
y = ym * .25 - 8000;
zm = ((zh<<8) | zl);
z = zm * .25 - 8000;
I'm not exactly certain that this is correct, but this does give a sensible result.