Compass sensor library

Dependents:   compassDemo weather_station_proj weather_station_project weather_station_proj_v1_2

Committer:
acracan
Date:
Fri Jun 15 12:22:40 2018 +0000
Revision:
0:cffff4c45a14
Child:
1:fb6804e865fd
Adaptation from Arduino HMC5983 library

Who changed what in which revision?

UserRevisionLine numberNew contents of line
acracan 0:cffff4c45a14 1 /*
acracan 0:cffff4c45a14 2 * HMC5983.cpp - library header
acracan 0:cffff4c45a14 3 *
acracan 0:cffff4c45a14 4 * simple library for the HMC5983 sensor from Honeywell
acracan 0:cffff4c45a14 5 * adaptation form MBED from the Arduino library
acracan 0:cffff4c45a14 6 *
acracan 0:cffff4c45a14 7 * (c) 2014 Korneliusz Jarzebski, www.jarzebski.pl
acracan 0:cffff4c45a14 8 * (c) 2014 David Cuartielles, Arduino LLC
acracan 0:cffff4c45a14 9 * (c) 2016 Abel Romero, www.abelromero.com
acracan 0:cffff4c45a14 10 * (c) 2018 Arcadie Cracan
acracan 0:cffff4c45a14 11 */
acracan 0:cffff4c45a14 12
acracan 0:cffff4c45a14 13 // MISSING: EARTH DECLINATION ANGLE
acracan 0:cffff4c45a14 14 // In other words, we are not making any compensation for the earth's north pole location vs the magnetic measurement
acracan 0:cffff4c45a14 15
acracan 0:cffff4c45a14 16 #include "HMC5983.h"
acracan 0:cffff4c45a14 17 #include <new>
acracan 0:cffff4c45a14 18
acracan 0:cffff4c45a14 19 HMC5983::HMC5983(PinName sda, PinName scl) : i2c_(*reinterpret_cast<I2C*>(i2cRaw))
acracan 0:cffff4c45a14 20 {
acracan 0:cffff4c45a14 21 // Placement new to avoid additional heap memory allocation.
acracan 0:cffff4c45a14 22 new(i2cRaw) I2C(sda, scl);
acracan 0:cffff4c45a14 23
acracan 0:cffff4c45a14 24 init();
acracan 0:cffff4c45a14 25 }
acracan 0:cffff4c45a14 26
acracan 0:cffff4c45a14 27 HMC5983::HMC5983(I2C &i2c): i2c_(i2c){
acracan 0:cffff4c45a14 28 init();
acracan 0:cffff4c45a14 29 }
acracan 0:cffff4c45a14 30
acracan 0:cffff4c45a14 31 bool HMC5983::init()
acracan 0:cffff4c45a14 32 {
acracan 0:cffff4c45a14 33 if ((fastRegister8(HMC5983_REG_IDENT_A) != 0x48)
acracan 0:cffff4c45a14 34 || (fastRegister8(HMC5983_REG_IDENT_B) != 0x34)
acracan 0:cffff4c45a14 35 || (fastRegister8(HMC5983_REG_IDENT_C) != 0x33)) {
acracan 0:cffff4c45a14 36 return false;
acracan 0:cffff4c45a14 37 }
acracan 0:cffff4c45a14 38
acracan 0:cffff4c45a14 39 // Set Gain Range
acracan 0:cffff4c45a14 40 setRange(HMC5983_RANGE_8_1GA);
acracan 0:cffff4c45a14 41 // Set DataRate 220Hz ~4.5ms
acracan 0:cffff4c45a14 42 setDataRate(HMC5983_DATARATE_220HZ);
acracan 0:cffff4c45a14 43 // Set number of samples to average
acracan 0:cffff4c45a14 44 setSampleAverages(HMC5983_SAMPLEAVERAGE_2);
acracan 0:cffff4c45a14 45 // Set Mode
acracan 0:cffff4c45a14 46 setMeasurementMode(HMC5983_CONTINOUS);
acracan 0:cffff4c45a14 47
acracan 0:cffff4c45a14 48 // Setup DRDY int
acracan 0:cffff4c45a14 49 // if (ISR_callback != NULL) {
acracan 0:cffff4c45a14 50 // pinMode(3, INPUT_PULLUP);
acracan 0:cffff4c45a14 51 // attachInterrupt(digitalPinToInterrupt(3), ISR_callback, FALLING);
acracan 0:cffff4c45a14 52 // }
acracan 0:cffff4c45a14 53 return true;
acracan 0:cffff4c45a14 54 }
acracan 0:cffff4c45a14 55
acracan 0:cffff4c45a14 56 /*
acracan 0:cffff4c45a14 57 From datasheet for the HMC5983
acracan 0:cffff4c45a14 58 Below is an example of a (power-on) initialization process for “continuous-measurement mode” via I2C interface:
acracan 0:cffff4c45a14 59 1. Write CRA (00) – send 0x3C 0x00 0x70 (8-average, 15 Hz default or any other rate, normal measurement)
acracan 0:cffff4c45a14 60 2. Write CRB (01) – send 0x3C 0x01 0xA0 (Gain=5, or any other desired gain)
acracan 0:cffff4c45a14 61 3. For each measurement query:
acracan 0:cffff4c45a14 62 Write Mode (02) – send 0x3C 0x02 0x01 (Single-measurement mode)
acracan 0:cffff4c45a14 63 Wait 6 ms or monitor status register or DRDY hardware interrupt pin
acracan 0:cffff4c45a14 64 Send 0x3D 0x06 (Read all 6 bytes. If gain is changed then this data set is using previous gain)
acracan 0:cffff4c45a14 65 Convert three 16-bit 2’s compliment hex values to decimal values and assign to X, Z, Y, respectively.
acracan 0:cffff4c45a14 66 (Self addition:)
acracan 0:cffff4c45a14 67 4. Convert the magnetic information into a compass value
acracan 0:cffff4c45a14 68 REGARDING THE CALCULATION OF THE ACTUAL HEADING VALUE
acracan 0:cffff4c45a14 69 From AN-203 http://www51.honeywell.com/aero/common/documents/myaerospacecatalog-documents/Defense_Brochures-documents/Magnetic__Literature_Application_notes-documents/AN203_Compass_Heading_Using_Magnetometers.pdf
acracan 0:cffff4c45a14 70 The magnetic compass heading can be determined (in degrees) from the magnetometer's x and y readings by using the
acracan 0:cffff4c45a14 71 following set of equations:
acracan 0:cffff4c45a14 72 Direction (y>0) = 90 - [arcTAN(x/y)]*180/PI
acracan 0:cffff4c45a14 73 Direction (y<0) = 270 - [arcTAN(x/y)]*180/PI
acracan 0:cffff4c45a14 74 Direction (y=0, x<0) = 180.0
acracan 0:cffff4c45a14 75 Direction (y=0, x>0) = 0.0
acracan 0:cffff4c45a14 76 */
acracan 0:cffff4c45a14 77
acracan 0:cffff4c45a14 78 void HMC5983::setRange(hmc5983_range_t range) {
acracan 0:cffff4c45a14 79
acracan 0:cffff4c45a14 80 writeRegister8(HMC5983_REG_CONFIG_B, range << 5);
acracan 0:cffff4c45a14 81 }
acracan 0:cffff4c45a14 82
acracan 0:cffff4c45a14 83 hmc5983_range_t HMC5983::getRange(void)
acracan 0:cffff4c45a14 84 {
acracan 0:cffff4c45a14 85 return (hmc5983_range_t)((readRegister8(HMC5983_REG_CONFIG_B) >> 5));
acracan 0:cffff4c45a14 86 }
acracan 0:cffff4c45a14 87
acracan 0:cffff4c45a14 88 void HMC5983::setMeasurementMode(hmc5983_mode_t mode) {
acracan 0:cffff4c45a14 89 uint8_t value;
acracan 0:cffff4c45a14 90
acracan 0:cffff4c45a14 91 value = readRegister8(HMC5983_REG_MODE);
acracan 0:cffff4c45a14 92 value &= 0b11111100;
acracan 0:cffff4c45a14 93 value |= mode;
acracan 0:cffff4c45a14 94
acracan 0:cffff4c45a14 95 writeRegister8(HMC5983_REG_MODE, value);
acracan 0:cffff4c45a14 96 }
acracan 0:cffff4c45a14 97
acracan 0:cffff4c45a14 98 hmc5983_mode_t HMC5983::getMeasurementMode(void) {
acracan 0:cffff4c45a14 99 uint8_t value;
acracan 0:cffff4c45a14 100
acracan 0:cffff4c45a14 101 value = readRegister8(HMC5983_REG_MODE);
acracan 0:cffff4c45a14 102 value &= 0b00000011;
acracan 0:cffff4c45a14 103
acracan 0:cffff4c45a14 104 return (hmc5983_mode_t)value;
acracan 0:cffff4c45a14 105 }
acracan 0:cffff4c45a14 106
acracan 0:cffff4c45a14 107 void HMC5983::setDataRate(hmc5983_dataRate_t dataRate) {
acracan 0:cffff4c45a14 108 uint8_t value;
acracan 0:cffff4c45a14 109
acracan 0:cffff4c45a14 110 value = readRegister8(HMC5983_REG_CONFIG_A);
acracan 0:cffff4c45a14 111 value &= 0b11100011;
acracan 0:cffff4c45a14 112 value |= (dataRate << 2);
acracan 0:cffff4c45a14 113
acracan 0:cffff4c45a14 114 writeRegister8(HMC5983_REG_CONFIG_A, value);
acracan 0:cffff4c45a14 115 }
acracan 0:cffff4c45a14 116
acracan 0:cffff4c45a14 117 hmc5983_dataRate_t HMC5983::getDataRate(void) {
acracan 0:cffff4c45a14 118 uint8_t value;
acracan 0:cffff4c45a14 119
acracan 0:cffff4c45a14 120 value = readRegister8(HMC5983_REG_CONFIG_A);
acracan 0:cffff4c45a14 121 value &= 0b00011100;
acracan 0:cffff4c45a14 122 value >>= 2;
acracan 0:cffff4c45a14 123
acracan 0:cffff4c45a14 124 return (hmc5983_dataRate_t)value;
acracan 0:cffff4c45a14 125 }
acracan 0:cffff4c45a14 126
acracan 0:cffff4c45a14 127 void HMC5983::setSampleAverages(hmc5983_sampleAverages_t sampleAverages) {
acracan 0:cffff4c45a14 128 uint8_t value;
acracan 0:cffff4c45a14 129
acracan 0:cffff4c45a14 130 value = readRegister8(HMC5983_REG_CONFIG_A);
acracan 0:cffff4c45a14 131 value &= 0b10011111;
acracan 0:cffff4c45a14 132 value |= (sampleAverages << 5);
acracan 0:cffff4c45a14 133
acracan 0:cffff4c45a14 134 writeRegister8(HMC5983_REG_CONFIG_A, value);
acracan 0:cffff4c45a14 135 }
acracan 0:cffff4c45a14 136
acracan 0:cffff4c45a14 137 hmc5983_sampleAverages_t HMC5983::getSampleAverages(void) {
acracan 0:cffff4c45a14 138 uint8_t value;
acracan 0:cffff4c45a14 139
acracan 0:cffff4c45a14 140 value = readRegister8(HMC5983_REG_CONFIG_A);
acracan 0:cffff4c45a14 141 value &= 0b01100000;
acracan 0:cffff4c45a14 142 value >>= 5;
acracan 0:cffff4c45a14 143
acracan 0:cffff4c45a14 144 return (hmc5983_sampleAverages_t)value;
acracan 0:cffff4c45a14 145 }
acracan 0:cffff4c45a14 146
acracan 0:cffff4c45a14 147 // Write byte to register
acracan 0:cffff4c45a14 148 void HMC5983::writeRegister8(uint8_t reg, uint8_t value) {
acracan 0:cffff4c45a14 149 char cmd[2];
acracan 0:cffff4c45a14 150
acracan 0:cffff4c45a14 151 cmd[0] = reg;
acracan 0:cffff4c45a14 152 cmd[1] = value;
acracan 0:cffff4c45a14 153 i2c_.write(HMC5983_ADDRESS, cmd, 2);
acracan 0:cffff4c45a14 154 }
acracan 0:cffff4c45a14 155
acracan 0:cffff4c45a14 156 // Read byte to register
acracan 0:cffff4c45a14 157 uint8_t HMC5983::fastRegister8(uint8_t reg) {
acracan 0:cffff4c45a14 158 uint8_t value;
acracan 0:cffff4c45a14 159
acracan 0:cffff4c45a14 160 i2c_.write(HMC5983_ADDRESS, (char *)&reg, 1);
acracan 0:cffff4c45a14 161 i2c_.read(HMC5983_ADDRESS, (char *)&value, 1);
acracan 0:cffff4c45a14 162
acracan 0:cffff4c45a14 163 return value;
acracan 0:cffff4c45a14 164 }
acracan 0:cffff4c45a14 165
acracan 0:cffff4c45a14 166 // Read byte from register
acracan 0:cffff4c45a14 167 uint8_t HMC5983::readRegister8(uint8_t reg) {
acracan 0:cffff4c45a14 168 uint8_t value;
acracan 0:cffff4c45a14 169
acracan 0:cffff4c45a14 170 i2c_.write(HMC5983_ADDRESS, (char *)&reg, 1);
acracan 0:cffff4c45a14 171 i2c_.read(HMC5983_ADDRESS, (char *)&value, 1);
acracan 0:cffff4c45a14 172
acracan 0:cffff4c45a14 173 return value;
acracan 0:cffff4c45a14 174
acracan 0:cffff4c45a14 175 // Wire.requestFrom(HMC5983_ADDRESS, 1);
acracan 0:cffff4c45a14 176 // while(!Wire.available()) {};
acracan 0:cffff4c45a14 177 // value = Wire.read();
acracan 0:cffff4c45a14 178 }
acracan 0:cffff4c45a14 179
acracan 0:cffff4c45a14 180 // Read word from register
acracan 0:cffff4c45a14 181 int16_t HMC5983::readRegister16(uint8_t reg) {
acracan 0:cffff4c45a14 182 int16_t value;
acracan 0:cffff4c45a14 183 char resp[2];
acracan 0:cffff4c45a14 184
acracan 0:cffff4c45a14 185 i2c_.write(HMC5983_ADDRESS, (char *)&reg, 1);
acracan 0:cffff4c45a14 186 i2c_.read(HMC5983_ADDRESS, resp, 2);
acracan 0:cffff4c45a14 187
acracan 0:cffff4c45a14 188 // Wire.requestFrom(HMC5983_ADDRESS, 2);
acracan 0:cffff4c45a14 189 // while(!Wire.available()) {};
acracan 0:cffff4c45a14 190
acracan 0:cffff4c45a14 191 value = (uint8_t)resp[0] << 8 | (uint8_t)resp[1];
acracan 0:cffff4c45a14 192
acracan 0:cffff4c45a14 193 return value;
acracan 0:cffff4c45a14 194 }
acracan 0:cffff4c45a14 195
acracan 0:cffff4c45a14 196 double HMC5983::read() {
acracan 0:cffff4c45a14 197 // the values for X, Y & Z must be read in X, Z & Y order.
acracan 0:cffff4c45a14 198 char data[6];
acracan 0:cffff4c45a14 199 writeRegister8(HMC5983_OUT_X_MSB, 0); // Select MSB X register
acracan 0:cffff4c45a14 200 i2c_.read(HMC5983_ADDRESS, data, 6);
acracan 0:cffff4c45a14 201 uint8_t X_MSB = data[0];
acracan 0:cffff4c45a14 202 uint8_t X_LSB = data[1];
acracan 0:cffff4c45a14 203 uint8_t Z_MSB = data[2];
acracan 0:cffff4c45a14 204 uint8_t Z_LSB = data[3];
acracan 0:cffff4c45a14 205 uint8_t Y_MSB = data[4];
acracan 0:cffff4c45a14 206 uint8_t Y_LSB = data[5];
acracan 0:cffff4c45a14 207
acracan 0:cffff4c45a14 208 // compose byte for X, Y, Z's LSB & MSB 8bit registers
acracan 0:cffff4c45a14 209 int16_t HX = (uint16_t(X_MSB) << 8) | X_LSB;
acracan 0:cffff4c45a14 210 int16_t HZ = (uint16_t(Z_MSB) << 8) | Z_LSB;
acracan 0:cffff4c45a14 211 int16_t HY = (uint16_t(Y_MSB) << 8) | Y_LSB;
acracan 0:cffff4c45a14 212
acracan 0:cffff4c45a14 213 // convert the numbers to fit the
acracan 0:cffff4c45a14 214 // if (HX > 0x07FF) HX = 0xFFFF - HX;
acracan 0:cffff4c45a14 215 // if (HZ > 0x07FF) HZ = 0xFFFF - HZ;
acracan 0:cffff4c45a14 216 // if (HY > 0x07FF) HY = 0xFFFF - HY;
acracan 0:cffff4c45a14 217
acracan 0:cffff4c45a14 218 // declare the heading variable we'll be returning
acracan 0:cffff4c45a14 219 double H = 0;
acracan 0:cffff4c45a14 220
acracan 0:cffff4c45a14 221 // this is the correct way, fixed from original David's work.
acracan 0:cffff4c45a14 222 // corrected following datasheet and his own comments...xD
acracan 0:cffff4c45a14 223 // even corrected from datasheet, the 90-270 angle is a bit confusing, but the 360º are captured.
acracan 0:cffff4c45a14 224 if (HY > 0) H = 90.0 - atan(double(HX) / HY) * 180.0 / M_PI;
acracan 0:cffff4c45a14 225 if (HY < 0) H = 270.0 - atan(double(HX) / HY) * 180.0 / M_PI;
acracan 0:cffff4c45a14 226 if (HY == 0 && HX < 0) H = 180;
acracan 0:cffff4c45a14 227 if (HY == 0 && HX > 0) H = 0;
acracan 0:cffff4c45a14 228
acracan 0:cffff4c45a14 229 // point to first data register (from datasheet). Only for continuous-measurement mode.
acracan 0:cffff4c45a14 230 // Wire.requestFrom(HMC5983_ADDRESS, 0x03);
acracan 0:cffff4c45a14 231
acracan 0:cffff4c45a14 232 return H;
acracan 0:cffff4c45a14 233 }