From 93bd786d6f464226543fffcca7c42b2f8c72d45f Mon Sep 17 00:00:00 2001 From: Jordan McConnell Date: Fri, 18 Jul 2014 16:26:14 -0600 Subject: [PATCH] Added Arduino library with 2 example sketches --- libraries/SFE_HMC6343_Library/SFE_HMC6343.cpp | 248 ++++++++++++++++++ libraries/SFE_HMC6343_Library/SFE_HMC6343.h | 122 +++++++++ .../HMC6343_advanced/HMC6343_advanced.ino | 168 ++++++++++++ .../HMC6343_basics/HMC6343_basics.ino | 110 ++++++++ 4 files changed, 648 insertions(+) create mode 100644 libraries/SFE_HMC6343_Library/SFE_HMC6343.cpp create mode 100644 libraries/SFE_HMC6343_Library/SFE_HMC6343.h create mode 100644 libraries/SFE_HMC6343_Library/examples/HMC6343_advanced/HMC6343_advanced.ino create mode 100644 libraries/SFE_HMC6343_Library/examples/HMC6343_basics/HMC6343_basics.ino diff --git a/libraries/SFE_HMC6343_Library/SFE_HMC6343.cpp b/libraries/SFE_HMC6343_Library/SFE_HMC6343.cpp new file mode 100644 index 0000000..9df94b0 --- /dev/null +++ b/libraries/SFE_HMC6343_Library/SFE_HMC6343.cpp @@ -0,0 +1,248 @@ +/****************************************************************************** +SFE_HMC6343.cpp +Core implementation file for the HMC6343 3-axis compass library. +Jordan McConnell @ SparkFun Electronics +17 July 2014 +https://github.com/sparkfun/HMC6343_Breakout + +This file implements the functions of the SFE_HMC6343 sensor class as well as +providing documentation on what each library function does. + +Developed/Tested with: +Arduino Uno +Arduino IDE 1.0.5 & 1.5.2 + +This code is beerware; if you see me (or any other SparkFun employee) at the +local, and you've found our code helpful, please buy us a round! +Distributed as-is; no warranty is given. +******************************************************************************/ + +#include "SFE_HMC6343.h" + +// Constructor - Creates sensor object, sets I2C address, and initializes sensor variables +SFE_HMC6343::SFE_HMC6343() +{ + _addr = HMC6343_I2C_ADDR; + + heading = pitch = roll = 0; + magX = magY = magZ = 0; + accelX = accelY = accelZ = 0; + temperature = 0; + + clearRawData(); +} + +// Destructor - Deletes sensor object +SFE_HMC6343::~SFE_HMC6343() +{ + +} + +// Initialize - returns true if successful +// Starts Wire/I2C Communication +// Verifies sensor is there by checking its I2C Address in its EEPROM +bool SFE_HMC6343::init() +{ + bool ret = true; + uint8_t data = 0x00; + + // Start I2C + Wire.begin(); + + // Check for device by reading I2C address from EEPROM + data = readEEPROM(SLAVE_ADDR); + + // Check if value read in EEPROM is the expected value for the HMC6343 I2C address + if (!(data == 0x32)) + { + ret = false; // Init failed, EEPROM did not read expected I2C address value + } + + return ret; +} + +// Send the HMC6343 a command to read the raw magnetometer values +// Store these values in the integers magX, magY, and magZ +void SFE_HMC6343::readMag() +{ + readGeneric(POST_MAG, &magX, &magY, &magZ); +} + +// Send the HMC6343 a command to read the raw accelerometer values +// Store these values in the integers accelX, accelY, and accelZ +void SFE_HMC6343::readAccel() +{ + readGeneric(POST_ACCEL, &accelX, &accelY, &accelZ); +} + +// Send the HMC6343 a command to read the raw calculated heading values +// Store these values in the integers heading, pitch, and roll +void SFE_HMC6343::readHeading() +{ + readGeneric(POST_HEADING, &heading, &pitch, &roll); +} + +// Send the HMC6343 a command to read the raw calculated tilt values +// Store these values in the integers pitch, roll, and temperature +void SFE_HMC6343::readTilt() +{ + readGeneric(POST_TILT, &pitch, &roll, &temperature); +} + +// Generic function which sends the HMC6343 a specified command +// It then collects 6 bytes of data via I2C and consolidates it into three integers +// whose addresses are passed to the function by the above read commands +void SFE_HMC6343::readGeneric(uint8_t command, int* first, int* second, int* third) +{ + sendCommand(command); // Send specified I2C command to HMC6343 + delay(1); // Delay response time + + clearRawData(); // Clear object's rawData[] array before storing new values in the array + + // Wait for a 6 byte response via I2C and store them in rawData[] array + Wire.beginTransmission(_addr); + Wire.requestFrom(_addr,(uint8_t)6); // Request the 6 bytes of data (MSB comes first) + uint8_t i = 0; + while(Wire.available() && i < 6) + { + rawData[i] = (uint8_t)Wire.read(); + i++; + } + Wire.endTransmission(); + + // Convert 6 bytes received into 3 integers + *first = rawData[0] << 8; // MSB + *first |= rawData[1]; // LSB + *second = rawData[2] << 8; + *second |= rawData[3]; + *third = rawData[4] << 8; + *third |= rawData[5]; +} + +// Send specified I2C command to HMC6343 +void SFE_HMC6343::sendCommand(uint8_t command) +{ + Wire.beginTransmission(_addr); + Wire.write(command); + Wire.endTransmission(); +} + +// Send enter standby mode I2C command to HMC6343 +void SFE_HMC6343::enterStandby() +{ + sendCommand(ENTER_STANDBY); +} + +// Send exit standby (enter run) mode I2C command to HMC6343 +void SFE_HMC6343::exitStandby() +{ + sendCommand(ENTER_RUN); +} + +// Send enter sleep mode I2C command to HMC6343 +void SFE_HMC6343::enterSleep() +{ + sendCommand(ENTER_SLEEP); +} + +// Send exit sleep mode I2C command to HMC6343 +void SFE_HMC6343::exitSleep() +{ + sendCommand(EXIT_SLEEP); +} + +// Send enter calibration mode I2C command to HMC6343 +void SFE_HMC6343::enterCalMode() +{ + sendCommand(ENTER_CAL); +} + +// Send exit calibration mode I2C command to HMC6343 +void SFE_HMC6343::exitCalMode() +{ + sendCommand(EXIT_CAL); +} + +// Set the physical orientation of the HMC6343 IC to either LEVEL, SIDEWAYS, or FLATFRONT +// This allows the IC to calculate a proper heading, pitch, and roll in tenths of degrees +// LEVEL X = forward, +Z = up (default) +// SIDEWAYS X = forward, +Y = up +// FLATFRONT Z = forward, -X = up +void SFE_HMC6343::setOrientation(uint8_t orientation) +{ + if (orientation == LEVEL) + { + sendCommand(ORIENT_LEVEL); + } + else if (orientation == SIDEWAYS) + { + sendCommand(ORIENT_SIDEWAYS); + } + else if (orientation == FLATFRONT) + { + sendCommand(ORIENT_FLATFRONT); + } +} + +// Send the I2C command to reset the processor on the HMC6343 +void SFE_HMC6343::reset() +{ + sendCommand(RESET); +} + +// Send the I2C command to read the OPMode1 status register of the HMC6343 +// The register informs you of current calculation status, filter status, modes enabled and what orientation +// Refer to the HMC6343 datasheet for bit specifics +uint8_t SFE_HMC6343::readOPMode1() +{ + uint8_t opmode1 = 0x00; + + sendCommand(POST_OPMODE1); + delay(1); + + Wire.beginTransmission(_addr); + Wire.requestFrom(_addr,(uint8_t)1); + opmode1 = (uint8_t)Wire.read(); + Wire.endTransmission(); + + return opmode1; +} + +// Send a command to the HMC6343 to read a specified register of the EEPROM +uint8_t SFE_HMC6343::readEEPROM(uint8_t reg) +{ + uint8_t data = 0x00; + + Wire.beginTransmission(_addr); + Wire.write(READ_EEPROM); + Wire.write(reg); + Wire.endTransmission(); + + delay(10); + + Wire.beginTransmission(_addr); + Wire.requestFrom(_addr,(uint8_t)1); + data = (uint8_t)Wire.read(); + Wire.endTransmission(); + + return data; +} + +// Send a command to the HMC6343 to write a specified register of the EEPROM +void SFE_HMC6343::writeEEPROM(uint8_t reg, uint8_t data) +{ + Wire.beginTransmission(_addr); + Wire.write(WRITE_EEPROM); + Wire.write(reg); + Wire.write(data); + Wire.endTransmission(); +} + +// Clears the sensor object's rawData[] array, used before taking new measurements +void SFE_HMC6343::clearRawData() +{ + for (uint8_t i = 0; i < 6; i++) + { + rawData[i] = 0; + } +} \ No newline at end of file diff --git a/libraries/SFE_HMC6343_Library/SFE_HMC6343.h b/libraries/SFE_HMC6343_Library/SFE_HMC6343.h new file mode 100644 index 0000000..213f970 --- /dev/null +++ b/libraries/SFE_HMC6343_Library/SFE_HMC6343.h @@ -0,0 +1,122 @@ +/****************************************************************************** +SFE_HMC6343.h +Core header file for the HMC6343 3-axis compass library. +Jordan McConnell @ SparkFun Electronics +17 July 2014 +https://github.com/sparkfun/HMC6343_Breakout + +This header file declares the SFE_HMC6343 sensor class as well as its various +functions and variables. It also defines sensor specifics including register +addresses and sensor commands. + +Developed/Tested with: +Arduino Uno +Arduino IDE 1.0.5 & 1.5.2 + +This code is beerware; if you see me (or any other SparkFun employee) at the +local, and you've found our code helpful, please buy us a round! +Distributed as-is; no warranty is given. +******************************************************************************/ + +#ifndef SFE_HMC6343_h +#define SFE_HMC6343_h + +#include "Arduino.h" +#include "Wire.h" + +// HMC6343 I2C Address (0x32 >> 1 = 0x19) +#define HMC6343_I2C_ADDR 0x19 + +// HMC6343 Registers +#define SLAVE_ADDR 0x00 +#define SW_VERSION 0x02 +#define OP_MODE1 0x04 +#define OP_MODE2 0x05 +#define SN_LSB 0x06 +#define SN_MSB 0x07 +#define DATE_CODE_YY 0x08 +#define DATE_CODE_WW 0x09 +#define DEVIATION_LSB 0x0A +#define DEVIATION_MSB 0x0B +#define VARIATION_LSB 0x0C +#define VARIATION_MSB 0x0D +#define XOFFSET_LSB 0x0E +#define XOFFSET_MSB 0x0F +#define YOFFSET_LSB 0x10 +#define YOFFSET_MSB 0x11 +#define ZOFFSET_LSB 0x12 +#define ZOFFSET_MSB 0x13 +#define FILTER_LSB 0x14 +#define FILTER_MSB 0x15 + +// HMC6343 Commands +#define POST_ACCEL 0x40 +#define POST_MAG 0x45 +#define POST_HEADING 0x50 +#define POST_TILT 0x55 +#define POST_OPMODE1 0x65 +#define ENTER_CAL 0x71 +#define ORIENT_LEVEL 0x72 +#define ORIENT_SIDEWAYS 0x73 +#define ORIENT_FLATFRONT 0x74 +#define ENTER_RUN 0x75 +#define ENTER_STANDBY 0x76 +#define EXIT_CAL 0x7E +#define RESET 0x82 +#define ENTER_SLEEP 0x83 +#define EXIT_SLEEP 0x84 +#define READ_EEPROM 0xE1 +#define WRITE_EEPROM 0xF1 + +// HMC6343 Orientations +#define LEVEL 0 // X = forward, +Z = up (default) +#define SIDEWAYS 1 // X = forward, +Y = up +#define FLATFRONT 2 // Z = forward, -X = up + +class SFE_HMC6343 +{ + public: + SFE_HMC6343(); + ~SFE_HMC6343(); + + int heading, pitch, roll; + int magX, magY, magZ; + int accelX, accelY, accelZ; + int temperature; + + bool init(); + + void readMag(); + void readAccel(); + void readHeading(); + void readTilt(); + + void enterStandby(); + void exitStandby(); + + void enterSleep(); + void exitSleep(); + + void enterCalMode(); + void exitCalMode(); + + void setOrientation(uint8_t orientation); + + void reset(); + + uint8_t readOPMode1(); + + uint8_t readEEPROM(uint8_t reg); + void writeEEPROM(uint8_t reg, uint8_t data); + + private: + uint8_t _addr; + + uint8_t rawData[6]; + void clearRawData(); + + void sendCommand(uint8_t command); + void readGeneric(uint8_t command, int* first, int* second, int* third); +}; + +#endif \ No newline at end of file diff --git a/libraries/SFE_HMC6343_Library/examples/HMC6343_advanced/HMC6343_advanced.ino b/libraries/SFE_HMC6343_Library/examples/HMC6343_advanced/HMC6343_advanced.ino new file mode 100644 index 0000000..f0e85c0 --- /dev/null +++ b/libraries/SFE_HMC6343_Library/examples/HMC6343_advanced/HMC6343_advanced.ino @@ -0,0 +1,168 @@ +/****************************************************************************** +HMC6343_advanced.ino +Example to demo the extended features of the HMC6343 3-axis compass library. +Jordan McConnell @ SparkFun Electronics +17 July 2014 +https://github.com/sparkfun/HMC6343_Breakout + +This example declares an SFE_HMC6343 object called compass. The object/sensor +is initialized and if the initialization fails, the sensor could not +be found and read from successfully. + +Each time through the main loop(), the following features are demo'ed: + +Reading/printing raw 3-axis magnetometer values +Reading/printing raw 'tilt' values (pitch, roll, and temperature) +Entering and exiting standby mode (4.5mA draw in run mode, 1.0mA in standby) +Entering and exiting sleep mode (10uA draw in sleep mode) +Setting the physical orientation of the HMC6343 IC (which affects heading/tilt readings) +Reading the primary status register, OPMode1 +Reading and writing the EEPROM registers of the sensor +Resetting the processor of the HMC6343 (commented out by default) +Entering and exiting user calibration mode (commented out by default) + +The HMC6343 breakout board needs to be powered with 3.3V and uses I2C to talk +to the microcontroller. If you're using a 5V microcontroller board, such as +the standard Arduino UNO, you'll need a Logic Level Converter for the I2C lines, +such as SparkFun's BOB-12009. + +Developed/Tested with: +Arduino Uno +Arduino IDE 1.0.5 & 1.5.2 + +Requires: +SFE_HMC6343_Library + +This code is beerware. +Distributed as-is; no warranty is given. +******************************************************************************/ + +// Libraries for I2C and the HMC6343 sensor +#include +#include "SFE_HMC6343.h" + +SFE_HMC6343 compass; // Declare the sensor object + +void setup() +{ + // Start serial communication at 115200 baud + Serial.begin(115200); + + // Give the HMC6343 a half second to wake up + delay(500); + + // Initialize the HMC6343 and verify its physical presence + if (!compass.init()) + { + Serial.println("Sensor Initialization Failed\n\r"); // Report failure, is the sensor wiring correct? + } +} + +void loop() +{ + // Read and print the raw magnetometer values for the x, y, and z axis of the sensor + compass.readMag(); + printMagData(); + + // Read and print the raw tilt values (pitch, roll, and temperature) of the sensor + compass.readTilt(); + printTiltData(); + + + // Enter and exit standby mode (4.5mA draw in run mode, 1.0mA in standby) + // HMC6343 requires 1 ms before it can receive commands after switching modes + compass.enterStandby(); + delay(1); + compass.exitStandby(); // Exit standby, enter run mode (default) + delay(1); + + // Enter and exit sleep mode (4.5mA draw in run mode, 10uA in sleep) + // HMC6343 requires 1ms after entering sleep and 20ms after exiting before it's able to receive new commmands + compass.enterSleep(); + delay(1); + compass.exitSleep(); + delay(20); + + // Set orientation of the HMC6343 IC so heading, pitch, and roll calculations are correct + // Possible orientations: + // LEVEL X = forward, +Z = up (default) + // SIDEWAYS X = forward, +Y = up + // FLATFRONT Z = forward, -X = up + compass.setOrientation(LEVEL); + delay(1); // 1 ms before sensor can receive commands after setting orientation + + // Read the OPMode1 status register of the HMC6343 + // The register informs you of current calculation status, filter status, modes enabled and the orientation selected + // Refer to the HMC6343 datasheet for bit specifics + byte opmode1 = compass.readOPMode1(); + Serial.print("OP Mode 1: "); + Serial.println(opmode1,BIN); + + // Read and print the Serial Number of the HMC6343 IC from its EEPROM + // EEPROM register list can be found in SFE_HMC6343.h or the datasheet + // EEPROM reads require 10ms afterward before the sensor is able to receive another command + int sn = compass.readEEPROM(SN_LSB); + delay(10); + sn |= (compass.readEEPROM(SN_MSB) << 8); + delay(10); + Serial.print("HMC6343 IC Serial Number: "); + Serial.println(sn,HEX); + Serial.println(); + + // Write the filter value (used for weighted averages of sensor reads) to the EEPROM of the HMC6343 + // FILTER_LSB register can be set between 0x00 and 0x0F + // It averages the last X sensor readings (filter register value) with the latest reading + // Example: if set to 4 (instead of default 0), it would average the last 4 readings with the latest reading + // for sensor values such as heading with the last 4 for a total of a second average (5Hz) + compass.writeEEPROM(FILTER_LSB, 0); // 0x00-0x0F, default is 0x00 + delay(10); // 10ms before sensor can accept commands after writing to the EEPROM + // To actually enable the filter, the filter bit must be set in OPMode1 register: 0bxx1xxxxx + //compass.writeEEPROM(OP_MODE1, 0x31); // Enable filter (default OPMODE1 + filter enable bit set) + //compass.writeEEPROM(OP_MODE1, 0x11); // Default, filter disabled (0bxx010001) + //delay(10); + + /* + // Reset the processor of the HMC6343 + // Sensor requires 500ms before it can receive more commands after a reset + compass.reset(); + delay(500); + */ + + /* + // Enter and exit user calibration mode + // Refer to datasheet for further instructions of how to use this mode + // Requires 1ms after entering and 50ms after exiting calibration before sensor can receive new commands + compass.enterCalMode(); + delay(1); + compass.exitCalMode(); + delay(50); + */ + + delay(2000); // Wait an arbitrary amount of seconds +} + +// Print the raw magnetometer values for the x, y, and z axis of the sensor +void printMagData() +{ + Serial.println("Raw Magnetometer Data:"); + Serial.print("X: "); + Serial.println(compass.magX); + Serial.print("Y: "); + Serial.println(compass.magY); + Serial.print("Z: "); + Serial.println(compass.magZ); + Serial.println(); +} + +// Print the raw tilt values (pitch, roll, and temperature) of the sensor +void printTiltData() +{ + Serial.println("Raw Tilt Data:"); + Serial.print("Pitch: "); + Serial.println(compass.pitch); + Serial.print("Roll: "); + Serial.println(compass.roll); + Serial.print("Temperature: "); + Serial.println(compass.temperature); + Serial.println(); +} diff --git a/libraries/SFE_HMC6343_Library/examples/HMC6343_basics/HMC6343_basics.ino b/libraries/SFE_HMC6343_Library/examples/HMC6343_basics/HMC6343_basics.ino new file mode 100644 index 0000000..e1511fd --- /dev/null +++ b/libraries/SFE_HMC6343_Library/examples/HMC6343_basics/HMC6343_basics.ino @@ -0,0 +1,110 @@ +/****************************************************************************** +HMC6343_basics.ino +Simple example for using the HMC6343 3-axis compass library. +Jordan McConnell @ SparkFun Electronics +17 July 2014 +https://github.com/sparkfun/HMC6343_Breakout + +This example declares an SFE_HMC6343 object called compass. The object/sensor +is initialized and if the initialization fails, the sensor could not +be found and read from successfully. + +Each time through the loop, heading values (heading, pitch, and roll) and +accelerometer values (accelX, accelY, accelZ) are read from the sensor. They +are then printed to the Serial Monitor at 115200 baud. The raw sensor values +are printed as well as scaled values in readable units (degrees and g forces). + +The HMC6343 breakout board needs to be powered with 3.3V and uses I2C to talk +to the microcontroller. If you're using a 5V microcontroller board, such as +the standard Arduino UNO, you'll need a Logic Level Converter for the I2C lines, +such as SparkFun's BOB-12009. + +Developed/Tested with: +Arduino Uno +Arduino IDE 1.0.5 & 1.5.2 + +Requires: +SFE_HMC6343_Library + +This code is beerware. +Distributed as-is; no warranty is given. +******************************************************************************/ + +// Libraries for I2C and the HMC6343 sensor +#include +#include "SFE_HMC6343.h" + +SFE_HMC6343 compass; // Declare the sensor object + +void setup() +{ + // Start serial communication at 115200 baud + Serial.begin(115200); + + // Give the HMC6343 a half second to wake up + delay(500); + + // Initialize the HMC6343 and verify its physical presence + if (!compass.init()) + { + Serial.println("Sensor Initialization Failed\n\r"); // Report failure, is the sensor wiring correct? + } +} + +void loop() +{ + // Read, calculate, and print the heading, pitch, and roll from the sensor + compass.readHeading(); + printHeadingData(); + + // Read, calculate, and print the acceleration on the x, y, and z axis of the sensor + compass.readAccel(); + printAccelData(); + + // Wait for two seconds + delay(2000); // Minimum delay of 200ms (HMC6343 has 5Hz sensor reads/calculations) +} + +// Print both the raw values of the compass heading, pitch, and roll +// as well as calculate and print the compass values in degrees +// Sample Output: +// Heading Data (Raw value, in degrees): +// Heading: 3249 324.90° +// Pitch: 28 2.80° +// Roll: 24 2.40° +void printHeadingData() +{ + Serial.println("Heading Data (Raw value, in degrees):"); + Serial.print("Heading: "); + Serial.print(compass.heading); Serial.print(" "); // Print raw heading value + Serial.print((float) compass.heading/10.0);Serial.write(176);Serial.println(); // Print heading in degrees + Serial.print("Pitch: "); + Serial.print(compass.pitch); Serial.print(" "); + Serial.print((float) compass.pitch/10.0);Serial.write(176);Serial.println(); + Serial.print("Roll: "); + Serial.print(compass.roll); Serial.print(" "); + Serial.print((float) compass.roll/10.0);Serial.write(176);Serial.println(); + Serial.println(); +} + +// Print both the raw values of the compass acceleration measured on each axis +// as well as calculate and print the accelerations in g forces +// Sample Output: +// Accelerometer Data (Raw value, in g forces): +// X: -52 -0.05g +// Y: -44 -0.04g +// Z: -1047 -1.02g +void printAccelData() +{ + Serial.println("Accelerometer Data (Raw value, in g forces):"); + Serial.print("X: "); + Serial.print(compass.accelX); Serial.print(" "); // Print raw acceleration measurement on x axis + Serial.print((float) compass.accelX/1024.0);Serial.println("g"); // Print x axis acceleration measurement in g forces + Serial.print("Y: "); + Serial.print(compass.accelY); Serial.print(" "); + Serial.print((float) compass.accelY/1024.0);Serial.println("g"); + Serial.print("Z: "); + Serial.print(compass.accelZ); Serial.print(" "); + Serial.print((float) compass.accelZ/1024.0);Serial.println("g"); + Serial.println(); +}