Arduino Playground is read-only starting December 31st, 2018. For more info please look at this Forum Post

Parallax HM55B Compass Sensor

Get angle to North here is all you need: HM55B

Keywords

arduino parallax sensorset HM55B Kompass

short description

With the parallax Hitachi HM55B compass sensor you can get angle to north. The code below is using the math library so on arduino amd8 you will get less memory. Maybe a lookup table does the job for you better.

The code gives you status x-strength y-strength and angle in degree.

CORRECTION! P6 == Din + Dout pin 1 and 2 == arduino pin 10!

Code

/*
/////////////////////////////////
Htachi HM55B Compass
parallax (#)

AUTHOR:   kiilo kiilo@kiilo.org
License:  https://creativecommons.org/licenses/by-nc-sa/2.5/ch/

https://parallax.com/Store/Microcontrollers/BASICStampModules/tabid/134/txtSearch/hm55b/List/1/ProductID/98/Default.aspx?SortField=ProductName%2cProductName
https://sage.medienkunst.ch/tiki-index.php?page=HowTo_Arduino_Parallax_HM55B_Kompass
https://playground.arduino.cc/HM55B

/////////////////////////////////
*/
#include <math.h> // (no semicolon)
//// VARS
byte CLK_pin = 8;
byte EN_pin = 9;
byte DIO_pin = 10;

int X_Data = 0;
int Y_Data = 0;
int angle;

//// FUNCTIONS

void ShiftOut(int Value, int BitsCount) {
  for(int i = BitsCount; i >= 0; i--) {
    digitalWrite(CLK_pin, LOW);
    if ((Value & 1 << i) == ( 1 << i)) {
      digitalWrite(DIO_pin, HIGH);
      //Serial.print("1");
    }
    else {
      digitalWrite(DIO_pin, LOW);
      //Serial.print("0");
    }
    digitalWrite(CLK_pin, HIGH);
    delayMicroseconds(1);
  }
//Serial.print(" ");
}

int ShiftIn(int BitsCount) {
  int ShiftIn_result;
    ShiftIn_result = 0;
    pinMode(DIO_pin, INPUT);
    for(int i = BitsCount; i >= 0; i--) {
      digitalWrite(CLK_pin, HIGH);
      delayMicroseconds(1);
      if (digitalRead(DIO_pin) == HIGH) {
        ShiftIn_result = (ShiftIn_result << 1) + 1; 
        //Serial.print("x");
      }
      else {
        ShiftIn_result = (ShiftIn_result << 1) + 0;
        //Serial.print("_");
      }
      digitalWrite(CLK_pin, LOW);
      delayMicroseconds(1);
    }
  //Serial.print(":");

// below is difficult to understand:
// if bit 11 is Set the value is negative
// the representation of negative values you
// have to add B11111000 in the upper Byte of
// the integer.
// see: https://en.wikipedia.org/wiki/Two%27s_complement
  if ((ShiftIn_result & 1 << 11) == 1 << 11) {
    ShiftIn_result = (B11111000 << 8) | ShiftIn_result; 
  }


  return ShiftIn_result;
}

void HM55B_Reset() {
  pinMode(DIO_pin, OUTPUT);
  digitalWrite(EN_pin, LOW);
  ShiftOut(B0000, 3);
  digitalWrite(EN_pin, HIGH);
}

void HM55B_StartMeasurementCommand() {
  pinMode(DIO_pin, OUTPUT);
  digitalWrite(EN_pin, LOW);
  ShiftOut(B1000, 3);
  digitalWrite(EN_pin, HIGH);
}

int HM55B_ReadCommand() {
  int result = 0;
  pinMode(DIO_pin, OUTPUT);
  digitalWrite(EN_pin, LOW);
  ShiftOut(B1100, 3);
  result = ShiftIn(3);
  return result;
}


void setup() {
  Serial.begin(115200);
  pinMode(EN_pin, OUTPUT);
  pinMode(CLK_pin, OUTPUT);
  pinMode(DIO_pin, INPUT);

  HM55B_Reset();
}

void loop() {
  HM55B_StartMeasurementCommand(); // necessary!!
  delay(40); // the data is 40ms later ready
  Serial.print(HM55B_ReadCommand()); // read data and print Status
  Serial.print(" ");  
  X_Data = ShiftIn(11); // Field strength in X
  Y_Data = ShiftIn(11); // and Y direction
  Serial.print(X_Data); // print X strength
  Serial.print(" ");
  Serial.print(Y_Data); // print Y strength
  Serial.print(" ");
  digitalWrite(EN_pin, HIGH); // ok deselect chip
  angle = 180 * (atan2(-1 * Y_Data , X_Data) / M_PI); // angle is atan( -y/x) !!!
  Serial.print(angle); // print angle
  Serial.println("");

}


Links

Author

kiilo AT kiilo DOT org

FAQ

shematic drawing and code differs?

you found a bug, yes the shematic is wrong if pin 10 is the DIO_pin - as defined in the code - it should be pin 10 in reality of course.

how to check connections?

Do you have a multimeter? Check systematicly:

  • between pin 3 and arduino GND (0V) is a connection, (multimeter 0 Ohm or beeper) I saw in courses a lot of people forget about connecting GND.
  • dont forget the orange bridges in the photo :-) the usual breadboards have an electrical gap there. (you dont have 5V below then)
  • between pin 3 and pin 6 at the compass module there are 5V (4.9 -5.1 is ok also)
  • is there a bridge connection between 1 and 2 at the compass module,(beeper check)
  • CLK pin 4 is connected to arduino pin 8
  • /EN pin 5 is connected to arduino pin 9

Overview howto connect to arduino decimillia?

PINs as metioned in the first picture are:

  • P4 == /EN pin 5 == arduino pin 9
  • P5 == CLK pin 4 == arduino pin 8
  • P6 == Din + Dout pin 1 and 2 == arduino pin 10

  • compass GND pin 3 == arduino GND
  • compass VDD pin 6 == arduino 5V

Idont have a multimeter?

if you dont have a multimeter check 5V with an LED + a 330 Ohm resistor (330 -1000 Ohm ok also) - short leg of LED points to GND

-)-- -LED+ ---------- =resistor= -(+

make a big arduino any difference?

small arduino or decimilia shouldnt make any difference.But having wires flying around is another source of trouble.