Need help with extracting compass data from HCM5883L on Combination GPS module

Here is the sketch. It compliles, loads and works fine on the Genuine Mega 2560. The LCD display does not give an accurate heading because it's based on the NMEA sentence extraction from the GPS. However, the GPS module contains an HMC5883L chip that I wish to get accurate heading data from. But I can't find the correct code to access the chip. The module has 2 separate wires for the HMC chip. The wires are currently connected to serial2 ports on the Arduino.

// Connect Deegoo-FPV NEO-N8M gps TX Yellow to serial3 RX pin 15 and gps RX White to TX pin 14
// Connect Deegoo-FPV NEO-M8N compass Brown to serial2 RX pin 17 and compass grey to TX pin 16
// Deegoo-FPV has NEO-N8M & intergated HCM5883L Compass
//Connect I2C LCD 20 x 4 Yellow to SCL Pin 21  Green to SDA Pin 20
// Set Serial3  to 38400
// Set Serial Begin to 9600
// Set Monitor to 9600
#include <TinyGPS++.h>
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
#include <hd44780.h>                       // main hd44780 header
#include <hd44780ioClass/hd44780_I2Cexp.h> // i2c expander i/o class header

hd44780_I2Cexp lcd; // declare lcd object: auto locate & config exapander chip
TinyGPSPlus gps; // create gps object

// LCD geometry
const int LCD_COLS = 20;
const int LCD_ROWS = 4;

void setup()
{
  lcd.begin(LCD_COLS, LCD_ROWS);
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(6, 0);
  lcd.print("Satellite");
  lcd.setCursor(5, 1);
  lcd.print("Acquisition"); 
  lcd.setCursor(5, 2);
  lcd.print("In Progress");
  lcd.setCursor(3, 3);
  lcd.print("Please Wait.....");
  delay(10000);
  lcd.clear();

Serial.begin(9600); // connect serial for debugging
Serial.println("Pending GPS Receive Signal:");
Serial3.begin(38400); // connect gps sensor
}

 
void loop(){
    while(Serial3.available()){ // check for gps data
    if(gps.encode(Serial3.read()))// encode gps data
    { 
    if (gps.satellites.value() > 0) {

    
    //Latitude
    lcd.setCursor(0, 0);
    lcd.print("Latitude:  ");
    lcd.print(gps.location.lat(),6);
    
    //Longitude
    lcd.setCursor(0, 1);
    lcd.print("Longitude:");
    lcd.print(gps.location.lng(),6); 

    //Heading
    lcd.setCursor(0, 2);
    lcd.print("Heading: "); 
    lcd.print(gps.course.deg(),0);
    

    //Speed
    lcd.setCursor(0, 3);
    lcd.print("Speed: "); 
    lcd.print(gps.speed.mph(),1);

    // Number of satellites connected
    lcd.setCursor(11, 3);
    lcd.print(" Sats: "); 
    lcd.print(gps.satellites.value());

    delay(2000);
    
   }
  }
}
}

Please post a link to the module data sheet or product page.

The long obsolete and discontinued HMC5883L chip communicates via I2C, not UART serial.

Well that explains a lot. Now I see that I cannot use the HMC5883L on that device as I am already using the SCL/SDA ports on the Mega. Do you have a better suggestion as to what device I can add for compass data?

No problem, the I2C port is a bus that supports more than one device. Each connected device must have a distinct I2C address.

However, logic level shifters are required when connecting 3.3V sensors like the HMC5883L to 5V Arduinos like the Mega 2560.

Any modern magnetometer will work as a compass. Sparkfun, Adafruit and Pololu (among others) sell hobby modules with the logic level shifters built in.

// Sketch using Arduino Mega 2560 for GPS & Magnetometer outputing to LCD display
// Connect Deegoo-FPV NEO-N8M gps TX Yellow to serial3 RX pin 15 and gps RX White to TX pin 14
//GY-511 - Magnetometer with HCM5883L  SCL to SCL1 on Arduino SDA to SDA1 on Arduino
//Connect I2C LCD 20 x 4 Yellow to SCL Pin 21  Green to SDA Pin 20
// All Data and Clock wires from GPS and Magnetometer connect via EPLZON Full-Duplex Logic Level Shifter
// Set Serial3  to 38400
// Set Serial Begin to 9600
// Set Monitor to 9600

#include <TinyGPS++.h>
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
#include <hd44780.h>                       // main hd44780 header
#include <hd44780ioClass/hd44780_I2Cexp.h> // i2c expander i/o class header

#define Magnetometer_mX0 0x03  
#define Magnetometer_mX1 0x04  
#define Magnetometer_mZ0 0x05  
#define Magnetometer_mZ1 0x06  
#define Magnetometer_mY0 0x07  
#define Magnetometer_mY1 0x08
#define Magnetometer 0x1E //I2C 7bit address of HMC5883L

int mX0, mX1, mX_out;
int mY0, mY1, mY_out;
int mZ0, mZ1, mZ_out;

float heading, headingDegrees, headingFiltered, declination;
float Xm,Ym,Zm;
hd44780_I2Cexp lcd; // declare lcd object: auto locate & config exapander chip
TinyGPSPlus gps; // create gps object

// LCD geometry
const int LCD_COLS = 20;
const int LCD_ROWS = 4;

void setup()
{
  lcd.begin(LCD_COLS, LCD_ROWS);
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(6, 0);
  lcd.print("Satellite");
  lcd.setCursor(5, 1);
  lcd.print("Acquisition"); 
  lcd.setCursor(5, 2);
  lcd.print("In Progress");
  lcd.setCursor(3, 3);
  lcd.print("Please Wait.....");
  delay(10000);
  lcd.clear();



//Initialize Serial and I2C communications
  Serial3.begin(38400); // connect gps sensor
  Serial.begin(9600);
  Wire.begin();
 
  delay(100);
  
  Wire.beginTransmission(Magnetometer); 
  Wire.write(0x02); // Select mode register
  Wire.write(0x00); // Continuous measurement mode
  Wire.endTransmission();
  
}

 
void loop(){
  
    while(Serial3.available()){ // check for gps data
    if(gps.encode(Serial3.read()))// encode gps data
    { 
    if (gps.satellites.value() > 0) {
 
    
    //Latitude
    lcd.setCursor(0, 0);
    lcd.print("Latitude:  ");
    lcd.print(gps.location.lat(),6);
    
    //Longitude
    lcd.setCursor(0, 1);
    lcd.print("Longitude:");
    lcd.print(gps.location.lng(),6); 

    //Heading
    lcd.setCursor(0, 2);
    lcd.print("Heading: "); 
    lcd.print(gps.course.deg(),0);
    

    //Speed
    lcd.setCursor(0, 3);
    lcd.print("Speed: "); 
    lcd.print(gps.speed.mph(),1);

    // Number of satellites connected
    lcd.setCursor(11, 3);
    lcd.print(" Sats: "); 
    lcd.print(gps.satellites.value());

    delay(2000);
    }

   {   
    //---- X-Axis
  Wire.beginTransmission(Magnetometer); // transmit to device
  Wire.write(Magnetometer_mX1);
  Wire.endTransmission();
  Wire.requestFrom(Magnetometer,1); 
  if(Wire.available()<=1)   
  {
    mX0 = Wire.read();
  }
  Wire.beginTransmission(Magnetometer); // transmit to device
  Wire.write(Magnetometer_mX0);
  Wire.endTransmission();
  Wire.requestFrom(Magnetometer,1); 
  if(Wire.available()<=1)   
  {
    mX1 = Wire.read();
  }

  //---- Y-Axis
  Wire.beginTransmission(Magnetometer); // transmit to device
  Wire.write(Magnetometer_mY1);
  Wire.endTransmission();
  Wire.requestFrom(Magnetometer,1); 
  if(Wire.available()<=1)   
  {
    mY0 = Wire.read();
  }
  Wire.beginTransmission(Magnetometer); // transmit to device
  Wire.write(Magnetometer_mY0);
  Wire.endTransmission();
  Wire.requestFrom(Magnetometer,1); 
  if(Wire.available()<=1)   
  {
    mY1 = Wire.read();
  }
  
  //---- Z-Axis
  Wire.beginTransmission(Magnetometer); // transmit to device
  Wire.write(Magnetometer_mZ1);
  Wire.endTransmission();
  Wire.requestFrom(Magnetometer,1); 
  if(Wire.available()<=1)   
  {
    mZ0 = Wire.read();
  }
  Wire.beginTransmission(Magnetometer); // transmit to device
  Wire.write(Magnetometer_mZ0);
  Wire.endTransmission();
  Wire.requestFrom(Magnetometer,1); 
  if(Wire.available()<=1)   
  {
    mZ1 = Wire.read();
  }
  
  //---- X-Axis
  mX1=mX1<<8;
  mX_out =mX0+mX1; // Raw data
  // From the datasheet: 0.92 mG/digit
  Xm = mX_out*0.00092; // Gauss unit
  //* Earth magnetic field ranges from 0.25 to 0.65 Gauss, so these are the values that we need to get approximately.

  //---- Y-Axis
  mY1=mY1<<8;
  mY_out =mY0+mY1;
  Ym = mY_out*0.00092;

  //---- Z-Axis
  mZ1=mZ1<<8;
  mZ_out =mZ0+mZ1;
  Zm = mZ_out*0.00092;

  //Calculating Heading
  heading = atan2(Ym, Xm);
 
  // Correcting the heading with the declination angle depending on your location
  // You can find your declination angle at: http://www.ngdc.noaa.gov/geomag-web/
  // At my location it's 13 degrees => 0.226 rad
  declination = 0.226; 
  heading += declination;
  
  // Correcting when signs are reveresed
  if(heading <0) heading += 2*PI;

  // Correcting due to the addition of the declination angle
  if(heading > 2*PI)heading -= 2*PI;

  headingDegrees = heading * 180/PI; // The heading in Degrees unit

  // Smoothing the output angle / Low pass filter 
  headingFiltered = headingFiltered*0.85 + headingDegrees*0.15;

  //Sending the heading value through the Serial Port to Processing IDE
  Serial.println(headingFiltered);
  //lcd.print(gps.course.deg(),0);

  
  delay(50);
}
    
   }
  }
}


So there is the code I'm using. The GPS works fine. The magnetometer works fine. But when I combine them the LCD goes blank. It compiles with no errors. At the moment the magnetometer outputs to the serial monitor instead of the LCD. It looks to me like Serial3 never becomes available so the sketch exits the loop and only the mag gives the correct output to the monitor. If I remove all the mag code, the output to the lcd looks perfect.

The posted code does not compile without errors. There are too many brackets "{".

It looks to me like Serial3 never becomes available

That is easy enough to check and fix. GPS units output NMEA sentences regardless of whether they have a satellite fix. Put in Serial.print statements to make sure.

With TinyGPS++, the following is not the correct way to determine whether you have a valid location. Study the example code and documentation more carefully.

    if (gps.satellites.value() > 0) {

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.