Jump to content
  • 0

Measure magnetic field with CMPS2


Hysha

Question

Hello,

i am using the PMOD CMPS2 compass with a Arduino Uno. I am aiming to measure the magnetic field of a current cable with this sensor. I used the example programm and rewrote it a bit so i can show the X,Y and Z component. It always shows me values of maybe 15900 and slightly changing  for X Y and Z. I actually dont know if this is right. And if i hold it to a wire or something the value doesnt change. Any idea what i can do ? 

#define DECLINATION 2.39 // declination Germany, Duisburg

/************************************************************************/

#include <Wire.h> //including library for I2C communication

unsigned char CMPS2_address = 0x30; //I2C address of the device

//store highest, middle and lowest values, x component and y component
float Max[3], Mid[3], Min[3], X, Y, Z;

void setup() {
  Serial.begin(9600); //serial initialization
  //pinMode(13, OUTPUT);
  delay(10);
  CMPS2_init(); //initialize the compass
}

void loop() {
  delay(500);

  //Abrufen und Anzeigen Richtung des Kompass'
  float measured_angle = CMPS2_getHeading();
  /*Serial.print("Heading = ");
  Serial.print(measured_angle);
  Serial.print("°");
  Serial.print('\t');*/

 // CMPS2_decodeHeading(measured_angle);  //get direction
  Serial.print("x=");
  Serial.print(X);
  Serial.print("           y=");
  Serial.print(Y);
  Serial.print("           z=");
  Serial.println(Z);

}

/*void CMPS2_decodeHeading(float measured_angle) {
  //decoding heading angle according to datasheet
  if (measured_angle > 337.25 | measured_angle < 22.5) {
    Serial.println("North");
    digitalWrite(13, HIGH);
  }
  else {
    digitalWrite(13, LOW);
    if (measured_angle > 292.5) {
      Serial.println("North-West");
    }
    else if (measured_angle > 247.5) {
      Serial.println("West");
    }
    else if (measured_angle > 202.5) {
      Serial.println("South-West");
    }
    else if (measured_angle > 157.5) {
      Serial.println("South");
    }
    else if (measured_angle > 112.5) {
      Serial.println("South-East");
    }
    else if (measured_angle > 67.5) {
      Serial.println("East");
    }
    else {
      Serial.println("North-East");
    }
  }
}*/

float CMPS2_getHeading(void) {
  float components[3];
  CMPS2_set(false);   //set the polarity to normal
  CMPS2_read_XYZ();  //read X, Y, Z components of the magnetic field
  components[0] = X;  //save current results
  components[1] = Y;
  components[2]= Z;
  CMPS2_set(true);   //set the polarity to normal
  CMPS2_read_XYZ();  //read X, Y, Z components of the magnetic field

  //eliminate offset from all components
  components[0] = (components[0] - X) / 2.0;
  components[1] = (components[1] - Y) / 2.0;
  components[2] = (components[2] - Z) / 2.0;

  //variables for storing partial results
  float temp0 = 0;
  float temp1 = 0;
  //and for storing the final result
  float deg = 0;

  //calculate heading from components of the magnetic field
  //the formula is different in each quadrant
  if (components[0] < Mid[0])
  {
    if (components[1] > Mid[1])
    {
      //Quadrant 1
      temp0 = components[1] - Mid[1];
      temp1 = Mid[0] - components[0];
      deg = 90 - atan(temp0 / temp1) * (180 / 3.14159);
    }
    else
    {
      //Quadrant 2
      temp0 = Mid[1] - components[1];
      temp1 = Mid[0] - components[0];
      deg = 90 + atan(temp0 / temp1) * (180 / 3.14159);
    }
  }
  else {
    if (components[1] < Mid[1])
    {
      //Quadrant 3
      temp0 = Mid[1] - components[1];
      temp1 = components[0] - Mid[0];
      deg = 270 - atan(temp0 / temp1) * (180 / 3.14159);
    }
    else
    {
      //Quadrant 4
      temp0 = components[1] - Mid[1];
      temp1 = components[0] - Mid[0];
      deg = 270 + atan(temp0 / temp1) * (180 / 3.14159);
    }
  }

  //correct heading
  deg += DECLINATION;
  if (DECLINATION > 0)
  {
    if (deg > 360) {
      deg -= 360;
    }
  }
  else
  {
    if (deg < 0) {
      deg += 360;
    }
  }

  return deg;
}

//reads measurements in mG
void CMPS2_read_XYZ(void) {
  //command internal control register 0 bit 0 (measure)
  Wire.beginTransmission(CMPS2_address);
  Wire.write(0x07);
  Wire.write(0x01);
  Wire.endTransmission();
  delay(8);

  //wait for measurement to be completed
  bool flag = false;
  while (!flag) {
    //jump to status register
    Wire.beginTransmission(CMPS2_address);
    Wire.write(0x06);
    Wire.endTransmission();

    //read its value
    Wire.requestFrom(CMPS2_address, (uint8_t)1);
    int temporal = 0;
    if (Wire.available()) {
      temporal = Wire.read();
    }

    //if the last bit is 1, data is ready
    temporal &= 1;
    if (temporal != 0) {
      flag = true;
    }
  }

  //move address pointer to first address
  Wire.beginTransmission(CMPS2_address);
  Wire.write(0x00);
  Wire.endTransmission();

  //save data
  Wire.requestFrom(CMPS2_address, (uint8_t)6);
  byte tmp[6] = {0, 0, 0, 0, 0, 0}; //array for raw data
  if (Wire.available()) {
    for (int i = 0; i < 6; i++) {
      tmp[i] = Wire.read(); //save it
    }
  }

  //initialize array for data
  float measured_data[3];

  //reconstruct raw data
  measured_data[0] = 1.0 * (int)(tmp[1] << 8 | tmp[0]); //x
  measured_data[1] = 1.0 * (int)(tmp[3] << 8 | tmp[2]); //y
  measured_data[2] = 1.0 * (int)(tmp[5] << 8 | tmp[4]); //z
  
  //convert raw data to mG
  for (int i = 0; i < 3; i++) {
    measured_data[i] = 0.48828125 * (float)measured_data[i];
  }

  X = measured_data[0];
  Y = measured_data[1];
  Z = measured_data[2];

  //correct minimum, mid and maximum values
  if (measured_data[0] > Max[0]) { //x max
    Max[0] = measured_data[0];
  }
  if (measured_data[0] < Min[0]) { //x min
    Min[0] = measured_data[0];
  }
  if (measured_data[1] > Max[1]) { //y max
    Max[1] = measured_data[1];
  }
  if (measured_data[1] < Min[1]) { //y min
    Min[1] = measured_data[1];
  }
   if (measured_data[2] > Max[2]) { //z max
    Max[2] = measured_data[1];
  }
  if (measured_data[2] < Min[2]) { //z min
    Min[2] = measured_data[1];
  }
  for (int i = 0; i < 3; i++) { //mid
    Mid[i] = (Max[i] + Min[i]) / 2;
  }

  return;
}

//Kompass initalisieren
void CMPS2_init(void) {
  Wire.begin(); // I2C initialisieren 

  //command internal control register 0 for set operation
  Wire.beginTransmission(CMPS2_address);
  Wire.write(0x07);
  Wire.write(0x20);
  Wire.endTransmission();
  delay(10);

  //command internal control register 1 to 16 bit resolution, 8ms measurement time
  Wire.beginTransmission(CMPS2_address);
  Wire.write(0x08);
  Wire.write(0x00);
  Wire.endTransmission();
  delay(10);

  //Minimum, Maximum und Mittelwert definieren
  for (int i = 0; i < 3; i++) {
    Max[i] = -32768;  //smallest int on 16 bits
    Min[i] = 32767;  //largest int on 16 bits
    Mid[i] = 0;
  }
}

//sets/resets the sensor, changing the magnetic polarity of the sensing element
void CMPS2_set(bool reset) {
  //command internal control register 0 bit 7 (capacitor recharge)
  Wire.beginTransmission(CMPS2_address);
  Wire.write(0x07);
  Wire.write(0x80);
  Wire.endTransmission();
  delay(50);

  if (reset) {
    //command internal control register 0 bit 6 (reset)
    Wire.beginTransmission(CMPS2_address);
    Wire.write(0x07);
    Wire.write(0x40);
    Wire.endTransmission();
    delay(10);
  }
  else {
    //command internal control register 0 bit 5 (set)
    Wire.beginTransmission(CMPS2_address);
    Wire.write(0x07);
    Wire.write(0x20);
    Wire.endTransmission();
    delay(10);
  }
  return;
}

 

Link to comment
Share on other sites

0 answers to this question

Recommended Posts

There have been no answers to this question yet

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...