I posted some of this in an earlier reply that hasn't shown up yet in the forum (stuck in moderation?).
Basically the problem is the address you need to use for the device. Instead of 0x42, you need to use 0x21 (only the most significant 7 bits). The TWI library
left-shifts the address you supply by one bit, and then OR's the read/write bit. To compensate, you need to shift the address one bit to the
right. This is not specific to the HMC6352. You need to do this with any I2C device you try to interface with (at least with Arduino 0007). Maybe this will be fixed (or at least a little more friendly) in Arduino 0008.
Here's some working code for an HMC6352 and a Arduino USB (rev. C) with an ATMega168 using Arduino 0007. Connect analog 4 to SDA, analog 5 to SCL. Don't forget to put pull-up resistors on both lines! (I used 10K originally but was getting a little noise and switched to 4.7K).
Code: Select all#include <Wire.h>
int HMC6352Address = 0x42;
int slaveAddress; // This is calculated in the setup() function
int ledPin = 13;
boolean ledState = false;
byte headingData[2];
int i, headingValue;
void setup()
{
// Shift the device's documented slave address (0x42) 1 bit right
// This compensates for how the TWI library only wants the
// 7 most significant bits (with the high bit padded with 0)
slaveAddress = HMC6352Address >> 1; // This results in 0x21 as the address to pass to TWI
Serial.begin(9600);
pinMode(ledPin, OUTPUT); // Set the LED pin as output
Wire.begin();
}
void loop()
{
// Flash the LED on pin 13 just to show that something is happening
// Also serves as an indication that we're not "stuck" waiting for TWI data
ledState = !ledState;
if (ledState) {
digitalWrite(ledPin,HIGH);
}
else
{
digitalWrite(ledPin,LOW);
}
// Send a "A" command to the HMC6352
// This requests the current heading data
Wire.beginTransmission(slaveAddress);
Wire.send("A"); // The "Get Data" command
Wire.endTransmission();
delay(10); // The HMC6352 needs at least a 70us (microsecond) delay
// after this command. Using 10ms just makes it safe
// Read the 2 heading bytes, MSB first
// The resulting 16bit word is the compass heading in 10th's of a degree
// For example: a heading of 1345 would be 134.5 degrees
Wire.requestFrom(slaveAddress, 2); // Request the 2 byte heading (MSB comes first)
i = 0;
while(Wire.available() && i < 2)
{
headingData[i] = Wire.receive();
i++;
}
headingValue = headingData[0]*256 + headingData[1]; // Put the MSB and LSB together
Serial.print("Current heading: ");
Serial.print(int (headingValue / 10)); // The whole number part of the heading
Serial.print(".");
Serial.print(int (headingValue % 10)); // The fractional part of the heading
Serial.println(" degrees");
delay(500);
}
Hope this helps.