Teensy3 with the HMC5883L

Status
Not open for further replies.

Katsu

Member
Hello, I poked around searching for this issue, and I found one other person asking it a while ago with no response, I figured I would try my hand..

I've got an HMC5883L hooked up to my teensy3. It's transmitting data that changes as I rotate the magnetometer, but it sometimes gives data as following when using the example code from https://www.loveelectronics.co.uk/Tutorials/8/hmc5883l-tutorial-and-arduino-library
The data looks like this:
Raw: 65500 65283 64830 Scaled: 65500.00 65283.00 64830.00 Heading: 0.54 Radians 31.15 Degrees
Raw: 65501 65282 64830 Scaled: 65501.00 65282.00 64830.00 Heading: 0.54 Radians 31.15 Degrees
Raw: 65498 65285 64829 Scaled: 65498.00 65285.00 64829.00 Heading: 0.54 Radians 31.16 Degrees
Raw: 65499 65281 64830 Scaled: 65499.00 65281.00 64830.00 Heading: 0.54 Radians 31.15 Degrees

The raw values are close enough to certain integer max values, and definitely not correct values for the device from what I've seen of it. In their demos there are values that are negative, but all of mine seem to be from 0 to 65535, which seems to indicate it's reading those values as unsigned ints. The values are from MagnetometerRaw's struct:
Code:
struct MagnetometerRaw
{
	int XAxis;
	int YAxis;
	int ZAxis;
};

Generated in the teensyduino IDE from this call:
Code:
MagnetometerRaw raw = compass.ReadRawAxis();

Which is from the following in the library:
Code:
MagnetometerRaw HMC5883L::ReadRawAxis()
{
  uint8_t* buffer = Read(DataRegisterBegin, 6);
  MagnetometerRaw raw = MagnetometerRaw();
  raw.XAxis = (buffer[0] << 8) | buffer[1];
  raw.ZAxis = (buffer[2] << 8) | buffer[3];
  raw.YAxis = (buffer[4] << 8) | buffer[5];
  return raw;
}

uint8_t* HMC5883L::Read(int address, int length)
{
  Wire.beginTransmission(HMC5883L_Address);
  Wire.send(address);
  Wire.endTransmission();
  
  Wire.beginTransmission(HMC5883L_Address);
  Wire.requestFrom(HMC5883L_Address, length);

  uint8_t buffer[length];
  if(Wire.available() == length)
  {
	  for(uint8_t i = 0; i < length; i++)
	  {
		  buffer[i] = Wire.receive();
	  }
  }
  Wire.endTransmission();

  return buffer;
}

I am not exactly sure, but it looks to me like the data is being read into an unsigned int array, which is bit shifted into the int variables. I don't know how the site was getting negative values from this, but I don't entirely understand the code, I hope this is sufficient information. Is there something going on here that I can easily fix?

Thanks
 
Try changing the struct to this:

Code:
struct MagnetometerRaw
{
	int16_t XAxis;
	int16_t YAxis;
	int16_t ZAxis;
};

If this works, please send the fix back to the library author, so they can update their code.
 
That did the trick, I'll pass the information on to the original publisher. Thanks a million! I'll also send a PM to the other person who posted about this issue back in November.
 
N003 needz help plz!

The following line of code produces no error message, but after uploading to the teensy it becomes unresponsive (i.e. the "teensy3.0 on usb/cu....etc dissappears from the serial port list.

Code:
MagnetometerScaled scaled = compass.ReadScaledAxis(); //scaled values from compass.

I have the following function for setting up the HMC:

Code:
void setupHMC5883L(){
  //Setup the HMC5883L, and check for errors
  //int error;  
  error = compass.SetScale(1.3); //Set the scale of the compass.
  if(error != 0) Serial.println(compass.GetErrorText(error)); //check if there is an error, and print if so

  error = compass.SetMeasurementMode(Measurement_Continuous); // Set the measurement mode to Continuous
  if(error != 0) Serial.println(compass.GetErrorText(error)); //check if there is an error, and print if so
}

This is all taken from the HMC5883 example code, and I've tried editing the magnetometerRaw struct in the HMC5883L.h file as Paul showed above to this:

Code:
struct MagnetometerRaw
{
	int16_t XAxis;
	int16_t YAxis;
	int16_t ZAxis;
};

Anyways, if none of this helps, here is the entire sketch (I'm using the arduino ide).
Code:
#include <Wire.h>

#include <HMC5883L.h>



HMC5883L compass;
// Create an IntervalTimer object 
int error = 0;
IntervalTimer myTimer;

//const int ledPin = LED_BUILTIN;  // the pin with a LED
//int ledState = LOW;
//volatile unsigned long blinkCount = 0;
int heading;
int e_H;
int e_L;
int a_H;
int a_L;
int d_H;
int d_L;
int g_H;
int g_L;
int F1_H;
int F1_L;
int F2_H;
int F2_L;
int F3_H;
int F3_L;
int F4_H;
int F4_L;
int Button1;
int Button2;
int Button3;
int Button4;
int dirp;
const int nothing = 0;
int Xaxis;
int Yaxis;
int Zaxis;

const int ID_E = 0x10;
const int ID_A = 0x20;
const int ID_D = 0x30;
const int ID_G = 0x40;
const int ID_F1 = 0x50;
const int ID_F2 = 0x60;
const int ID_F3 = 0x70;
const int ID_F4 = 0x80;
const int ID_Button1 = 0x90;
const int ID_Button2 = 0xA0;
const int ID_Button3 = 0xB0;
const int ID_Button4 = 0xC0;
const int ID_Compass = 0xD0;
//const int ID_Y = 0xE0;
//const int ID_Z = 0xF0;


const int buttonPin1 = 3;
const int buttonPin2 = 5;
const int buttonPin3 = 7;
const int buttonPin4 = 9;

void setup(void) {
  //pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
  analogReadRes(16); // Increase ADC resolution
  myTimer.begin(sendData, 20000);  // sendData to run every 20 milliseconds
  pinMode(buttonPin1, INPUT);
  pinMode(buttonPin2, INPUT);
  pinMode(buttonPin3, INPUT);
  pinMode(buttonPin4, INPUT);
  pinMode(13, OUTPUT);    
  digitalWrite(13, HIGH);
  //Setup the HMC5883L, and check for errors
  //int error;  
  //error = compass.SetScale(1.3); //Set the scale of the compass.
  //if(error != 0) Serial.println(compass.GetErrorText(error)); //check if there is an error, and print if so

  //error = compass.SetMeasurementMode(Measurement_Continuous); // Set the measurement mode to Continuous
  //if(error != 0) Serial.println(compass.GetErrorText(error)); //check if there is an error, and print if so

  
}

void setupHMC5883L(){
  //Setup the HMC5883L, and check for errors
  //int error;  
  error = compass.SetScale(1.3); //Set the scale of the compass.
  if(error != 0) Serial.println(compass.GetErrorText(error)); //check if there is an error, and print if so

  error = compass.SetMeasurementMode(Measurement_Continuous); // Set the measurement mode to Continuous
  if(error != 0) Serial.println(compass.GetErrorText(error)); //check if there is an error, and print if so
}

// functions called by IntervalTimer should be short, run as quickly as
// possible, and should avoid calling other functions if possible.
void sendData(void) {
  /*if (ledState == LOW) {
    ledState = HIGH;
    blinkCount = blinkCount + 1;  // increase when LED turns on
  } else {
    ledState = LOW;
  }*/
 // digitalWrite(ledPin, ledState);
 
 e_H = e_L >> 8;
 a_H = a_L >> 8;
 d_H = d_L >> 8;
 g_H = g_L >> 8;
 F1_H = F1_L >> 8; 
 F2_H = F2_L >> 8; 
 F3_H = F3_L >> 8; 
 F4_H = F4_L >> 8; 

 
 
    Serial.write(ID_E);
    Serial.write(e_H);
    Serial.write(e_L);
    
    Serial.write(ID_A);
    Serial.write(a_H);
    Serial.write(a_L);
    
    Serial.write(ID_D);
    Serial.write(d_H);
    Serial.write(d_L);
    
    Serial.write(ID_G);
    Serial.write(g_H);
    Serial.write(g_L);
    
    Serial.write(ID_F1);
    Serial.write(F1_H);
    Serial.write(F1_L);
    
    Serial.write(ID_F2);
    Serial.write(F2_H);
    Serial.write(F2_L);
    
    Serial.write(ID_F3);
    Serial.write(F3_H);
    Serial.write(F3_L);
    
    Serial.write(ID_F4);
    Serial.write(F4_H);
    Serial.write(F4_L);
    
    Serial.write(ID_Button1);
    Serial.write(Button1);
    Serial.write(nothing);
    
    Serial.write(ID_Button2);
    Serial.write(Button2);
    Serial.write(nothing);
    
    Serial.write(ID_Button3);
    Serial.write(Button3);
    Serial.write(nothing);
    
    Serial.write(ID_Button4);
    Serial.write(Button4);
    Serial.write(nothing);
    
    Serial.write(ID_Compass);
    Serial.write(heading);
    Serial.write(nothing);
}

// The main program will print the blink count
// to the Arduino Serial Monitor
void loop(void) {
 // unsigned long blinkCopy;  // holds a copy of the blinkCount

  // to read a variable which the interrupt code writes, we
  // must temporarily disable interrupts, to be sure it will
  // not change while we are reading.  To minimize the time
  // with interrupts off, just quickly make a copy, and then
  // use the copy while allowing the interrupt to keep working.
  noInterrupts();
  //blinkCopy = blinkCount;
  e_L = analogRead(A0);
  a_L = analogRead(A1);
  d_L = analogRead(A2);
  g_L = analogRead(A3);
  F1_L = analogRead(A6);
  F2_L = analogRead(A7);
  F3_L = analogRead(A8);
  F4_L = analogRead(A9);
  Button1 = digitalRead(buttonPin1);
  Button2 = digitalRead(buttonPin2);
  Button3 = digitalRead(buttonPin3);
  Button4 = digitalRead(buttonPin4);
  
  
  MagnetometerScaled scaled = compass.ReadScaledAxis(); //scaled values from compass.
  //heading = atan2(scaled.YAxis, scaled.XAxis);

  // Correct for when signs are reversed.
  //if(heading < 0) heading += 2*PI;
  //if(heading > 2*PI) heading -= 2*PI;

  //return heading * RAD_TO_DEG; //radians to degrees
  //dirp = heading * RAD_TO_DEG;
  
  interrupts();

 // Serial.print("blinkCount = ");
 // Serial.println(blinkCopy);
  //delay(100);
}

All of the buttons, analogreads, and Serial.writes were working fine before I added the compass to the project. Thanks a bunch! Teensy wooh!
 
Status
Not open for further replies.
Back
Top