HMC5883L Digital Compass Library
Fork of HMC5883L by
Revision 3:f14ad02770e4, committed 2018-05-30
- Comitter:
- brunohorta
- Date:
- Wed May 30 19:14:58 2018 +0000
- Parent:
- 2:bbc9ad18fd3e
- Commit message:
- ble
Changed in this revision
HMC5883L.cpp | Show annotated file Show diff for this revision Revisions of this file |
HMC5883L.h | Show annotated file Show diff for this revision Revisions of this file |
diff -r bbc9ad18fd3e -r f14ad02770e4 HMC5883L.cpp --- a/HMC5883L.cpp Wed Aug 05 13:16:12 2015 +0000 +++ b/HMC5883L.cpp Wed May 30 19:14:58 2018 +0000 @@ -1,80 +1,11 @@ -/* HMC5883L Digital Compass Library -* -* @author: Baser Kandehir -* @date: August 5, 2015 -* @license: MIT license -* -* Copyright (c) 2015, Baser Kandehir, baser.kandehir@ieee.metu.edu.tr -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -* THE SOFTWARE. -* -*/ - -// Some part of the code is adapted from Adafruit HMC5883 library #include "HMC5883L.h" - -/* NUCLEO F411RE board */ -static I2C i2c(D14, D15); // setup i2c (SDA,SCL) +static I2C i2c(p4, p2); // setup i2c (SDA,SCL) -static float Gauss_LSB_XY = 1100.0F; // Varies with gain -static float Gauss_LSB_Z = 980.0F; // Varies with gain - -void HMC5883L::setMagGain(MagGain gain) -{ - writeByte(HMC5883L_ADDRESS, CONFIG_B, (int8_t)gain); - - switch(gain) - { - case MagGain_13: - Gauss_LSB_XY = 1100; - Gauss_LSB_Z = 980; - break; - case MagGain_19: - Gauss_LSB_XY = 855; - Gauss_LSB_Z = 760; - break; - case MagGain_25: - Gauss_LSB_XY = 670; - Gauss_LSB_Z = 600; - break; - case MagGain_40: - Gauss_LSB_XY = 450; - Gauss_LSB_Z = 400; - break; - case MagGain_47: - Gauss_LSB_XY = 400; - Gauss_LSB_Z = 255; - break; - case MagGain_56: - Gauss_LSB_XY = 330; - Gauss_LSB_Z = 295; - break; - case MagGain_81: - Gauss_LSB_XY = 230; - Gauss_LSB_Z = 205; - break; - } -} + uint16_t mode; +float declination_offset_radians; -void HMC5883L::writeByte(uint8_t address, uint8_t regAddress, uint8_t data) -{ +void HMC5883L::writeByte(uint8_t address, uint8_t regAddress, uint8_t data){ char data_write[2]; data_write[0]=regAddress; // I2C sends MSB first. Namely >>|regAddress|>>|data| data_write[1]=data; @@ -101,16 +32,111 @@ dest[i]=data[i]; } -void HMC5883L::init() -{ +void HMC5883L::init(){ + declination_offset_radians = 0 - (( 54 + (1/60 * 4) ) * (M_PI / 180)); + mode = COMPASS_CONTINUOUS | COMPASS_SCALE_130 | COMPASS_VERTICAL_X_EAST; writeByte(HMC5883L_ADDRESS, CONFIG_A, 0x78); // Number of samples averaged: 8, Data output rate: 75 Hz - writeByte(HMC5883L_ADDRESS, MODE, 0x00); // Continuous-Measurement Mode - setMagGain(MagGain_13); + writeByte(HMC5883L_ADDRESS, MODE, mode & 0x03); // Continuous-Measurement Mode wait_ms(10); } +void HMC5883L::setScale( uint16_t scale ){ + // Scale is the bits marked S in mode + // xxxxxxxxxxxSSSMM + mode = (mode & ~0x1C) | (scale & 0x1C); + writeByte(HMC5883L_ADDRESS,CONFIG_B, (( mode >> 2 ) & 0x07) << 5); +} -void HMC5883L::readMagData(float* dest) +/** Set the orientation to one of COMPASS_HORIZONTAL_X_NORTH + * through COMPASS_VERTICAL_Y_WEST + * + */ + +void HMC5883L::setOrientation( uint16_t orientation ) { + // Orientation is the bits marked XXXYYYZZZ in mode + // xxXXXYYYZZZxxxxx + mode = (mode & ~0x3FE0) | (orientation & 0x3FE0); +} + +float s_mag_north, s_mag_west; +double HMC5883L::getHeading(){ + + float sample[3]; + readMagData(sample); + + + + float heading; + + // Determine which of the Axes to use for North and West (when compass is "pointing" north) + float mag_north, mag_west = -100000; + + switch((mode >> 5) & 0x07 ) + { + case COMPASS_NORTH: mag_north = sample[2]; break; + case COMPASS_SOUTH: mag_north = 0-sample[2]; break; + case COMPASS_WEST: mag_west = sample[2]; break; + case COMPASS_EAST: mag_west = 0-sample[2]; break; + + // Don't care + case COMPASS_UP: + case COMPASS_DOWN: + break; + } + + // Y = bits 3 - 5 + switch(((mode >> 5) >> 3) & 0x07 ) + { + case COMPASS_NORTH: mag_north = sample[1]; break; + case COMPASS_SOUTH: mag_north = 0-sample[1]; ; break; + case COMPASS_WEST: mag_west = sample[1]; break; + case COMPASS_EAST: mag_west = 0-sample[1]; break; + + // Don't care + case COMPASS_UP: + case COMPASS_DOWN: + break; + } + + // X = bits 6 - 8 + switch(((mode >> 5) >> 6) & 0x07 ) + { + case COMPASS_NORTH: mag_north = sample[0]; break; + case COMPASS_SOUTH: mag_north = 0-sample[0]; break; + case COMPASS_WEST: mag_west = sample[0]; break; + case COMPASS_EAST: mag_west = 0-sample[0]; break; + + // Don't care + case COMPASS_UP: + case COMPASS_DOWN: + break; + } + if(s_mag_north == -100000) { + s_mag_north = mag_north; + } + if(s_mag_west == -100000) { + s_mag_west = mag_west; + } + // calculate heading from the north and west magnetic axes + heading = atan2(mag_west - s_mag_west, mag_north- s_mag_north); + // Adjust the heading by the declination + heading += declination_offset_radians; + + // Correct for when signs are reversed. + if(heading < 0) + heading += 2*M_PI; + + // Check for wrap due to addition of declination. + if(heading > 2*M_PI) + heading -= 2*M_PI; + + // Convert radians to degrees for readability. + heading = heading * 180/M_PI; + return heading ; +} + + +void HMC5883L::readMagData(float* dest){ uint8_t rawData[6]; // x,y,z mag data /* Read six raw data registers sequentially and write them into data array */ @@ -121,36 +147,5 @@ dest[2] = (int16_t)(((int16_t)rawData[2]<<8) | rawData[3]); // MAG_ZOUT dest[1] = (int16_t)(((int16_t)rawData[4]<<8) | rawData[5]); // MAG_YOUT - /* Convert raw data to magnetic field values in microtesla */ - dest[0] = dest[0] / Gauss_LSB_XY * GAUSS_TO_MICROTESLA; - dest[1] = dest[1] / Gauss_LSB_XY * GAUSS_TO_MICROTESLA; - dest[2] = dest[2] / Gauss_LSB_Z * GAUSS_TO_MICROTESLA; -} -double HMC5883L::getHeading() -{ - float magData[3]; - readMagData(magData); - - /* Calculate the heading while Z axis of the module is pointing up */ - double heading = atan2(magData[1], magData[0]); - - // After calculating heading declination angle should be added to heading which is the error of the magnetic field in specific location. - // declinationAngle can be found here http://www.magnetic-declination.com/ - // For Ankara (my location) declinationAngle is ~5.5 degrees (0.096 radians) - float declinationAngle = 0.096; - heading += declinationAngle; - - // Correct for when signs are reversed. - if(heading < 0) - heading += 2*PI; - - // Check for wrap due to addition of declination. - if(heading > 2*PI) - heading -= 2*PI; - - /* Convert radian to degrees */ - heading = heading * 180 / PI; - - return heading; -} +} \ No newline at end of file
diff -r bbc9ad18fd3e -r f14ad02770e4 HMC5883L.h --- a/HMC5883L.h Wed Aug 05 13:16:12 2015 +0000 +++ b/HMC5883L.h Wed May 30 19:14:58 2018 +0000 @@ -28,8 +28,7 @@ #include "mbed.h" #include "math.h" -#include "ledControl.h" - +#define M_PI 3.14159265359 #define PI 3.14159265359 #define GAUSS_TO_MICROTESLA 100 #define HMC5883L_ADDRESS 0x3C @@ -48,8 +47,37 @@ #define ID_A 0x0A #define ID_B 0x0B #define ID_C 0x0C +#define COMPASS_SCALE_088 0x00 << 2 +#define COMPASS_SCALE_130 0x01 << 2 +#define COMPASS_SCALE_190 0x02 << 2 +#define COMPASS_SCALE_250 0x03 << 2 +#define COMPASS_SCALE_400 0x04 << 2 +#define COMPASS_SCALE_470 0x05 << 2 +#define COMPASS_SCALE_560 0x06 << 2 +#define COMPASS_SCALE_810 0x07 << 2 +// xxXXXYYYZZZxxxxx +// ORIENTATION: +#define COMPASS_NORTH 0x00 +#define COMPASS_SOUTH 0x01 +#define COMPASS_WEST 0x02 +#define COMPASS_EAST 0x03 +#define COMPASS_UP 0x04 +#define COMPASS_DOWN 0x05 +#define COMPASS_CONTINUOUS 0x00 +#define COMPASS_SINGLE 0x01 +#define COMPASS_IDLE 0x02 + + +// When "pointing" north, define the direction of each of the silkscreen'd arrows +// (imagine the Z arrow points out of the top of the device) only N/S/E/W are allowed +#define COMPASS_HORIZONTAL_X_NORTH ( (COMPASS_NORTH << 6) | (COMPASS_WEST << 3) | COMPASS_UP ) << 5 +#define COMPASS_HORIZONTAL_Y_NORTH ( (COMPASS_EAST << 6) | (COMPASS_NORTH << 3) | COMPASS_UP ) << 5 +#define COMPASS_VERTICAL_X_EAST ( (COMPASS_EAST << 6) | (COMPASS_UP << 3) | COMPASS_SOUTH ) << 5 +#define COMPASS_VERTICAL_Y_WEST ( (COMPASS_UP << 6) | (COMPASS_WEST << 3) | COMPASS_SOUTH ) << 5 /* Magnetometer Gain Settings */ + + enum MagGain { MagGain_088 = 0x00, // +/- 0.88 Ga @@ -68,8 +96,10 @@ void init(); double getHeading(); void readMagData(float* dest); + void setScale(uint16_t sampling_mode ); + void setOrientation(uint16_t sampling_mode ); private: - void setMagGain(MagGain gain); + void writeByte(uint8_t address, uint8_t regAddress, uint8_t data); char readByte(uint8_t address, uint8_t regAddress); void readBytes(uint8_t address, uint8_t regAddress, uint8_t byteNum, uint8_t* dest);