Go Down

Topic: Zhichuan I2C Compass (Read 3198 times) previous topic - next topic

Wracul

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

Code: [Select]
#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
}


robtillaart

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
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Wracul

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






robtillaart

Hi Karl,

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

Code: [Select]

#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);                 
}

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Wracul

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


Wracul

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

Code: [Select]
#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);
}




Go Up