Location: Home / Projects / Arduino Language: en

Arduino

This page is about Arduino stuff.

Using I2C

Compass

Source code for Magnetic Compass Sensor HDMM01

Header

Download CompassHDMM01.h

#ifndef COMPASS_HDMM01_h
#define COMPASS_HDMM01_h

#include <Arduino.h>
#include "TypesLib.h"


class CompassHDMM01
{
  public:
    static const int HDMM01_1 = 0x30;
    static const int HDMM01_2 = 0x32;
    static const int HDMM01_3 = 0x34;
    static const int HDMM01_4 = 0x36;
    
    static const byte TAKE_MEASURE = 0x01;
    static const byte SET_COIL = 0x02;
    static const byte RESET_COIL = 0x04;
    
    int i2addr;
    Vec2i offs;
    double declination;
    
    CompassHDMM01(int i2addr);
    void resetSetCoil();
    Vec2i getReading(bool resetCoil);
    void calibrateMinMax(long num, long t, bool resetCoil);
    void calibrateAvg(long num, long t, bool resetCoil);
    void calibrateLS(long num, long t, bool resetCoil);
    
    // calculate the angle of the magnetic field in grad
    // 0 Deg = North
    // 90 Deg = East
    // +-180 Deg = South
    // -90 Deg = West
    template <typename T> 
    double calcAngleDeg(Vec2<T> const &reading)
    {
      double angle = atan2(reading.y, reading.x) * 180.0 / 3.1415927410 + declination;
      return angle;
    }

    // calculate the angle of the magnetic field in rads
    // 0 Rad = North
    // PI/2 Rad = East
    // +-PI Rad = South
    // -PI/2 Rad = West
    template <typename T> 
    double calcAngleRad(Vec2<T> const &reading)
    {
      double angle = atan2(reading.y, reading.x) + declination * PI / 180.0;
      return angle;
    }

    // caclulate the strenght of the magnetic field in gauss
    static double calcStrength(Vec2i const &reading)
    {
      double x = (double)reading.x / 512.0;
      double y = (double)reading.y / 512.0;   
      double strength = sqrt(x*x + y*y);
      return strength;
    }
    
    // converts the reading to gauss
    static Vec2d convertGauss(Vec2i const &reading)
    {
      Vec2d gauss;
      gauss.x = (double)reading.x / 512.0;
      gauss.y = (double)reading.y / 512.0;   
      return gauss;
    }
};

#endif

Source

Download CompassHDMM01.cpp

#include <Wire.h>
#include "CompassHDMM01.h"

// Constructor
CompassHDMM01::CompassHDMM01(int i2addr)
{
  this->i2addr = i2addr;
  
  // set offset do default value
  // 2048 is the value for zero field.
  offs.x = 2048;
  offs.y = 2048;
  
  declination = 0.0;
}

// Reset and Set coils
void CompassHDMM01::resetSetCoil()
{   
  // reset coil
  Wire.beginTransmission(i2addr);
  Wire.write(0x00);
  Wire.write(RESET_COIL);
  Wire.endTransmission();
  delay(1);
  
  // set coil 
  Wire.beginTransmission(i2addr);
  Wire.write(0x00);
  Wire.write(SET_COIL);
  Wire.endTransmission();
  delay(1);  
}

// Readout compass values
Vec2i CompassHDMM01::getReading(bool resetCoil)
{
  Vec2i reading;
  byte MsbX,LsbX,MsbY,LsbY;
  int x,y;
  
  if (resetCoil)
  {
    resetSetCoil();
  }
  
  // take measurement
  Wire.beginTransmission(i2addr);
  Wire.write(0x00); // write to address 0x00
  Wire.write(TAKE_MEASURE);
  Wire.endTransmission();
   
  delay(5);
  
  // read data
  Wire.beginTransmission(i2addr);
  Wire.write(0x01); // read from address 0x01
  Wire.requestFrom(i2addr, 4);

  while(Wire.available() < 4);
  MsbX = Wire.read();
  LsbX = Wire.read();
  MsbY = Wire.read();
  LsbY = Wire.read();
  Wire.endTransmission();
  
  reading.x=(((MsbX & 0x0f) << 8) | LsbX) - offs.x;
  reading.y=(((MsbY & 0x0f) << 8) | LsbY) - offs.y;  
  
  return reading;
}

// Calibrate between min and max values.
void CompassHDMM01::calibrateMinMax(long num, long t, bool resetCoil)
{
  Vec2<int> min, max;
  Vec2i reading;
  
  min = max = getReading(resetCoil);
  
  for (int i=0; i < num; i++)
  {
    reading = getReading(resetCoil);
    if (reading.x < min.x)
    {
       min.x = reading.x;
    }  
    else if (reading.x > max.x)
    {
      max.x = reading.x;
    }
    
    if (reading.y < min.y)
    {
       min.y = reading.y;
    }  
    else if (reading.y > max.y)
    {
      max.y = reading.y;
    }
    delay(t);
  }
  
  offs.x += (min.x + max.x) / 2;
  offs.y += (min.y + max.y) / 2;  
}

// Calibreate compass by averaging all points.
// Not good. Works only with constant rotation speed.
void CompassHDMM01::calibrateAvg(long num, long t, bool resetCoil)
{
  Vec2<long> sum;
  Vec2i reading;
  
  sum.x = 0;
  sum.y = 0;
  
  for (int i=0; i < num; i++)
  {
    reading = getReading(resetCoil);
    sum.x += reading.x;
    sum.y += reading.y;
    delay(t);
  }
  
  offs.x += (sum.x) / num;
  offs.y += (sum.y) / num;
}

// Calibrating compass with Least Sqare Method for circles.
// Yes, it is black magic.
void CompassHDMM01::calibrateLS(long num, long t, bool resetCoil)
{
  Vec2i reading;
  
  /* Matrix B
  a b c
  b e f
  c f i  
  */
  long long Ba = 0;
  long long Bb = 0;
  long long Bc = 0;
  long long Be = 0;
  long long Bf = 0;
  long long Bi = 0;
  long long y;
  
  // Vector C [x y z]
  long long Cx = 0;
  long long Cy = 0;
  long long Cz = 0;
  
  // Vector Z [x y z]
  long long Zx;
  long long Zy;
  long long Zz;
  
  // start meassurement
  for (int i=0; i < num; i++)
  {
    reading = getReading(resetCoil);
    /* DEBUG 
    Serial.print("new Vector<double>(");
    Serial.print(reading.x);
    Serial.print(",");
    Serial.print(reading.y);
    Serial.println("),");
    */
    
    Ba += reading.x * reading.x;
    Bb += reading.x * reading.y;
    Bc += reading.x;
    Be += reading.y * reading.y;
    Bf += reading.y;
                            
    y = reading.x * reading.x + reading.y * reading.y;
    Cx += reading.x * y;
    Cy += reading.y * y;
    Cz += y;
    
    delay(t);
  }
  Bi = num;
  
  // Solve B * z = c
  // Calculate det(B)
  long long det = Ba * (Be * Bi - Bf * Bf)
            -Bb * (Bb * Bi - Bf * Bc)
            +Bc * (Bb * Bf - Be * Bc);            
  /* DEBUG
  Serial.print("det:");
  Serial.println((long)(det/1000000));
  */
  
  // Calculate z = B^-1 * c
  Zx = (( Be * Bi - Bf * Bf) * Cx
        +(Bc * Bf - Bb * Bi) * Cy
        +(Bb * Bf - Bc * Be) * Cz) / det;
  Zy = (( Bf * Bc - Bb * Bi) * Cx
        +(Ba * Bi - Bc * Bc) * Cy
        +(Bc * Bb - Ba * Bf) * Cz) / det;
  Zz = (( Bb * Bf - Be * Bc) * Cx
        +(Bb * Bc - Ba * Bf) * Cy
        +(Ba * Be - Bb * Bb) * Cz) / det;
        
  offs.x += Zx / 2;
  offs.y += Zy / 2;
  //double r = sqrt(Zz + (Zx * Zx + Zy * Zy) / 4);
  /* DEBUG
  Serial.print("r:");
  Serial.println(r, 3);
  */
}

Humidity Sensor

Source code for Hummidity Sensor HH10D

Header

Download HumidityHH10D.h

#ifndef HUMIDITY_HH10D_H
#define HUMIDITY_HH10D_H

#include <Arduino.h>
#include "TypesLib.h"
#include <Wire.h>

class HumidityHH10D
{
public:
  static const int HH10D = 0x51;

  int i2addr;
  int freqIRQ;
  int sens;
  int offs;
  double freq;
  bool freqReady;
  
  HumidityHH10D(int i2addr, int freqIRQ);
  void getCoeff();
  double calcRH(double freq);
  void startFreq(long timeSpan);

protected:  
  static unsigned long cnt;
  static unsigned long startTime;
  static unsigned long timeSpan;  
  static HumidityHH10D* cur;
  
  static void interrupt()
  {
     cnt++;
     if (millis() >= (startTime + timeSpan))
     {
       unsigned long time = millis();
       detachInterrupt(cur->freqIRQ);
       /*
       Serial.print("cnt:");
       Serial.print(cnt);
       Serial.print(" time:");
       Serial.println(time-startTime);
       */
       cur->freq = (double)cnt * 500.0 / (double)(time - startTime);
       cur->freqReady = true;  
       cur = NULL;     
     }
  }

};

#endif

Source

Download HumidityHH10D.cpp

#include "HumidityHH10D.h"
#include <Wire.h>

HumidityHH10D::HumidityHH10D(int i2addr, int freqIRQ)
{
  this->i2addr = i2addr;
  this->freqIRQ = freqIRQ;
}

void HumidityHH10D::getCoeff()
{
  byte offs_lsb = 0, offs_msb = 0, sens_lsb = 0, sens_msb = 0;
 
  Wire.beginTransmission(i2addr);
  Wire.write(0x0A);
  Wire.endTransmission();

  Wire.requestFrom(i2addr, 2);
  if (Wire.available())
    sens_msb = Wire.read();
  if (Wire.available())
    sens_lsb = Wire.read();

  Wire.beginTransmission(i2addr);
  Wire.write(0x0C);
  Wire.endTransmission();
  
  Wire.requestFrom(i2addr, 2);
  
  if (Wire.available())
    offs_msb = Wire.read();
  if (Wire.available())
    offs_lsb = Wire.read();
  
  sens = (sens_msb << 8) | sens_lsb;
  offs = (offs_msb << 8) | offs_lsb;
}

double HumidityHH10D::calcRH(double freq)
{
  double rh = ((double)offs - (double)freq) * (double)sens / 4096.0;
  return rh;
}

unsigned long HumidityHH10D::cnt = 0;
unsigned long HumidityHH10D::startTime = 0;
unsigned long HumidityHH10D::timeSpan = 0;
HumidityHH10D* HumidityHH10D::cur = NULL;

void HumidityHH10D::startFreq(long timeSpan)
{
  if (HumidityHH10D::cur == NULL)
  {
    freqReady = false;
    HumidityHH10D::cnt = 0;
    HumidityHH10D::startTime = millis();
    HumidityHH10D::timeSpan = timeSpan;
    HumidityHH10D::cur = this;
    attachInterrupt(freqIRQ, interrupt, CHANGE);
  }
}

Comments