Zhichuan I2C Compass

So im trying to get this baby working. My arduino sense the magnetic compass but just read out 0 degrees. It looks like my compass is very similar to the HMC6352 so i tryed different codes and playing with them but no luck.

here is the PDF to my sensor. http://www.robotshop.com/world/PDF/zhichuan-electronics-i2c-compass-manual.pdf

#include <Wire.h> 

int compassAddress = 0x42 >> 1;  // From datasheet compass address is 0x42
                                 // shift the address 1 bit right, the Wire library only needs the 7
                                 // most significant bits for the address
int reading = 0; 

void setup() 
{ 
  Wire.begin();                // join i2c bus (address optional for master) 
  Serial.begin(9600);          // start serial communication at 9600bps 
  pinMode(48, OUTPUT);
  digitalWrite(48, HIGH);
} 
  
void loop() 
{ 
  // step 1: instruct sensor to read echoes 
  Wire.beginTransmission(compassAddress);  // transmit to device
                           // the address specified in the datasheet is 66 (0x42) 
                           // but i2c adressing uses the high 7 bits so it's 33 
  Wire.send('A');          // command sensor to measure angle  
  Wire.endTransmission();  // stop transmitting 
 
  // step 2: wait for readings to happen 
  delay(1000);               // datasheet suggests at least 6000 microseconds 
  
  // step 3: request reading from sensor 
  Wire.requestFrom(compassAddress, 2);  // request 2 bytes from slave device #33 
 
  // step 4: receive reading from sensor 
  if(2 <= Wire.available())     // if two bytes were received 
  { 
    reading = Wire.receive();   // receive high byte (overwrites previous reading) 
    reading = reading << 8;     // shift high byte to be high 8 bits 
    reading += Wire.receive();  // receive low byte as lower 8 bits 
    reading /= 10;
    Serial.println(reading);    // print the reading 
  } 

  delay(2000);                   // wait for half a second 
}

some thoughts:

have you tried int compassAddress = 0x42; - so without the shift ?

IIRC - Wire.endTransmission(); returns a value that can be checked if transmission worked...

Change: Wire.send('A'); // command sensor to measure angle =>

define COMPASS_MEASURE 0x65 // use the hex codes as stated in the PDF

Wire.send(COMPASS_MEASURE);

YOu missed to send command 0x74 or 0x76 on page 3 - start sampling

Im not familiar with eighter arduino or i2c. :)

Without the shift i loose readings from sensor.

Yes the: Wire.send('A'); was one of the things that i didnt understand. I redifined but no luck yet.

Where am i supposed to put the send command 0x76?

Thanks Nooby Karl

Hi Karl,

The best place would be in the setup as one only needs to send this command once I assume. Something like below

#include <Wire.h> 

#define COMPASSADDRESS  (0x42 >> 1)
#define COMPASSCONTRINUOUSMODE 0x76
#define COMPASSREAD 0x65
#define COMPASSPIN 48

void setup() 
{ 
  Wire.begin();                // join i2c bus (address optional for master) 
  Serial.begin(9600);          // start serial communication at 9600bps 
  pinMode(COMPASSPIN , OUTPUT);
  digitalWrite(COMPASSPIN , HIGH);

  // set compass to continuous reading
  Wire.beginTransmission(COMPASSADDRESS );  
  Wire.send(COMPASSCONTRINUOUSMODE );          
  Wire.endTransmission();
} 
  
void loop() 
{ 
  // step 1: instruct sensor to read echoes 
  Wire.beginTransmission(COMPASSADDRESS);  
  Wire.send(COMPASSREAD);          
  Wire.endTransmission(); 
 
  // step 2: wait for readings to happen 
  delay(1000);               // datasheet suggests at least 6000 microseconds 
  
  // step 3: request reading from sensor 
  Wire.requestFrom(COMPASSADDRESS, 2);  // request 2 bytes from slave device
  
  delay(10); 

  // step 4: receive reading from sensor 
  if (2 <= Wire.available())     // if two bytes were received 
  { 
    int reading = Wire.receive();
    reading = reading << 8 
    reading += Wire.receive();  
    Serial.println(reading);    
  } 

  delay(2000);                  
}

Finally getting som numbers out. But doesnt make sense because readings are just for the declination angle. Found a xls dokument stating the second mode (reading the data) should have 3 slave write addresses: 77-65 and 61.

Did my best to paste in a copy of the spreadsheet:

The first mode slave_write_address slave_command function 0X42 0X76 stop continuously update 0X42 0X70 stop cabilation 0X42 0X72 stop 0X42 0X74 stop

The second mode slave_write_address slave_command slave_read_address read_data_h read_data_l 0x42 0x77 0x43 Dh DL sotp 0x42 0x61 0x43 Dh DL sotp 0x42 0x65 0x43 Dh DL sotp

The third mode slave_write_address slave_command write_data_h write_data_l 0x42 0x60 Dh Dl stop 0x42 0x64 Dh Dl stop

Karl

Im still having trouble getting some sane readings out of it. Anybody got one working properly?
Im using this code.

#include "Wire.h"

int ZCCAddress = 0x42;
int slaveAddress;             
byte headingData[2];
 unsigned int headingValue;
 unsigned int heading=0;
      int declData[2];
      int deviationData[2];
 unsigned int headFin;
 byte inverted;
  
void setup()


{
  
  slaveAddress = ZCCAddress >> 1;   //arduino uses 7-bit addresses instead of the manufacturer's 8. So shift right by 1!
  Serial.begin(38400);
          Wire.begin();
          
           int a=declination();
          int b=deviation();
          void calibration();
            Serial.println("Declinazione");
      Serial.println(a);
        Serial.println("deviazione");
            Serial.println(b);
  } 



   
void loop()
{ 

  Wire.beginTransmission(slaveAddress);

 Wire.send(0x77);      //print Direction data
 delay(25);
                              
   Wire.endTransmission();


  Wire.requestFrom(slaveAddress, 2);      
  int i = 0;

 
 while(Wire.available() && i < 2) 
  {  
   headingData[i] = Wire.receive();
    i++;
   }
   
   
   if (i==2)  // All bytes received?
    {
      
headingValue=(headingData[1] | (headingData[0]<<8));

int z;
for(z=15; z>8; z--){

headFin=bitClear(headingValue,z);

}
  
  
  byte dir;
  int x=0;
  byte head1;
#include "Wire.h"

int ZCCAddress = 0x42;
int slaveAddress;             
byte headingData[2];
 unsigned int headingValue;
 unsigned int heading=0;
      int declData[2];
      int deviationData[2];
 unsigned int headFin;
  byte inverted;
  
  int declination()  {
  
  int decl;
  Wire.beginTransmission(slaveAddress);
  Wire.send(0x60);
  Wire.send(0x00);         //  these bytes represent
  Wire.send(0x02);         //  your angle of magnetic declination (depends on place)
  delay(100);
  Wire.send(0x61);
  Wire.endTransmission();

  int i=0;
  Wire.requestFrom(slaveAddress, 2); 
  while(Wire.available() && i < 2) 
{  
  declData[i] = Wire.receive();
  i++;
} 
  
  decl=declData[1] | (declData[0]<<8);

  return decl;    //printing the decl.

} 
   
  int deviation(){
  int devi; 
  Wire.beginTransmission(slaveAddress);
  Wire.send(0x64);                      
  Wire.send(0x00);        //these bytes represent
  Wire.send(0x01);        //your angle of magnetic deviation
  delay(100);
  Wire.send(0x65);
  Wire.endTransmission();
 
  int i=0;
  Wire.requestFrom(slaveAddress, 2); 
  while(Wire.available() && i < 2) 
{  
  deviationData[i] = Wire.receive();
  i++;
} 

  devi=deviationData[1] | (deviationData[0]<<8);
  return devi;   //print it out
}
  

void setup()
{
  
  slaveAddress = ZCCAddress >> 1;   //arduino uses 7-bit addresses instead of the manufacturer's 8. So shift right by 1!
  Serial.begin(9600);
          Wire.begin();
          
           int a=declination();
          int b=deviation();
          void calibration();
            Serial.println("DECLINATION");
      Serial.println(a);
        Serial.println("DEVIATION");
            Serial.println(b);
} 

void loop()
{ 

  Wire.beginTransmission(slaveAddress);

 Wire.send(0x77);      //print Direction data
 delay(25);
                              
   Wire.endTransmission();

  Wire.requestFrom(slaveAddress, 2);      
  int i = 0;
 
 while(Wire.available() && i < 2) 
{  
   headingData[i] = Wire.receive();
    i++;
}
      
   if (i==2)  // All bytes received?
{
      
headingValue=(headingData[1] | (headingData[0]<<8));

int z;
for(z=15; z>8; z--){

headFin=bitClear(headingValue,z);
  
}
    
  byte dir;
  int x=0;
  byte head1;
  head1=headingData[0]>>1;
  for(x=7; x>2; x--){
  
    dir=bitClear(head1,x);
    
}
if(dir==B00000000){
  Serial.print("N ");  
}
if(dir==B00000001){
  Serial.print("N-E ");  
}
if(dir==B00000010){
  Serial.print("E ");  
}
if(dir==B00000011){
  Serial.print("S-E ");  
}
if(dir==B00000100){
  Serial.print("S ");  
}
if(dir==B00000101){
  Serial.print("S-V ");  
}
if(dir==B00000110){
  Serial.print("V ");  
}
if(dir==B00000111){
  Serial.print("N-V ");  
} 

  Serial.print(headingValue);
  Serial.println(" Deg");
   }
   else
   Serial.print("ERROR");
   
   delay(1000);
}