Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 5 of 5

Thread: Teensy3 with the HMC5883L

  1. #1
    Junior Member
    Join Date
    Nov 2012
    Posts
    5

    Teensy3 with the HMC5883L

    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/Tu...rduino-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

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,965
    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.

  3. #3
    Senior Member
    Join Date
    Nov 2012
    Location
    Boston, MA, USA
    Posts
    1,103
    That should do it. From the data sheet, p.15 :
    The value stored in these two registers is a 16-bit value in 2’s complement form, whose range is 0xF800 to 0x07FF

  4. #4
    Junior Member
    Join Date
    Nov 2012
    Posts
    5
    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.

  5. #5
    Junior Member
    Join Date
    Dec 2013
    Location
    Eugene, OR
    Posts
    1

    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!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •