libraries / Mitov / Mitov_HMC5883_Compass.hon commit Added final version of code (649c546)
   1////////////////////////////////////////////////////////////////////////////////
   2//                                                                            //
   3//     This software is supplied under the terms of a license agreement or    //
   4//     nondisclosure agreement with Mitov Software and may not be copied      //
   5//     or disclosed except in accordance with the terms of that agreement.    //
   6//         Copyright(c) 2002-2016 Mitov Software. All Rights Reserved.        //
   7//                                                                            //
   8////////////////////////////////////////////////////////////////////////////////
   9
  10#ifndef _MITOV_HMC5883L_h
  11#define _MITOV_HMC5883L_h
  12
  13#include <Mitov.h>
  14#include <Wire.h> //I2C Arduino Library
  15
  16namespace Mitov
  17{
  18
  19        const byte HMC5883L_Address = 0x1E;
  20        const byte HMC5883L_StatusRegister = 9;
  21        const byte HMC5883L_ModeRegister = 2;
  22        const byte HMC5883_REGISTER_MAG_CRA_REG_M = 0x00;
  23        const byte HMC5883_REGISTER_MAG_CRB_REG_M = 0x01;
  24        const byte HMC5883_REGISTER_MAG_OUT_X_H_M = 0x03;
  25//---------------------------------------------------------------------------
  26        enum HMC5883L_AveragedSamples { cas1, cas2, cas4, cas8 };
  27        enum HMC5883L_Bias { cbNone, cbPositive, cbNegative };
  28        enum HMC5883L_Gain { cg1370, cg1090, cg820, cg660, cg440, cg390, cg330, cg230 };
  29//---------------------------------------------------------------------------
  30        class HMC5883L_Compass : public Mitov::EnabledComponent, public Mitov::ClockingSupport
  31        {
  32                typedef Mitov::EnabledComponent inherited;
  33
  34        public:
  35                OpenWire::TypedSourcePin<float> XOutputPin;
  36                OpenWire::TypedSourcePin<float> YOutputPin;
  37                OpenWire::TypedSourcePin<float> ZOutputPin;
  38
  39        public:
  40                HMC5883L_AveragedSamples        AveragedSamples : 2;
  41                HMC5883L_Bias                           Bias : 2;
  42                HMC5883L_Gain                           Gain : 3;
  43                bool                                            Idle : 1;
  44
  45        protected:
  46                bool    FClocked : 1;
  47                bool    FChangeOnly : 1;
  48
  49        public:
  50                void SetIdle( bool AValue )
  51                {
  52                        if( Idle == AValue )
  53                                return;
  54
  55                        Idle = AValue;
  56                        SetIntIdle();
  57                }
  58
  59        protected:
  60                float   FScale;
  61
  62        protected:
  63                void SetIntIdle()
  64                {
  65                        if( Idle )
  66                                WriteTo( HMC5883L_Address, 0b11 ); // Idle
  67
  68                        else
  69                                WriteTo( HMC5883L_Address, 0b00 ); // Single measurement mode                           
  70//                              WriteTo( HMC5883L_Address, 0b01 ); // Single measurement mode                           
  71                }
  72
  73                bool DataAvailable()
  74                {
  75                        StartReadFrom( HMC5883L_StatusRegister, 1 );
  76
  77                        uint8_t AStatus = Wire.read();
  78                        return( AStatus & 1 );
  79                }
  80
  81                void ReadCompass()
  82                {
  83                        if( ! Enabled )
  84                                return;
  85
  86                        if( ! DataAvailable() )
  87                                return;
  88
  89                        FClocked = false;
  90
  91                        StartReadFrom( HMC5883_REGISTER_MAG_OUT_X_H_M, 6 );
  92
  93                        union T16BitData
  94                        {
  95                                uint8_t Bytes[ 2 ];
  96                                int16_t Value;
  97                        };
  98
  99                        T16BitData A16BitValue;
 100                        float AValue;
 101
 102                        A16BitValue.Bytes[ 1 ] = Wire.read();
 103                        A16BitValue.Bytes[ 0 ] = Wire.read();
 104
 105/*
 106                        float _magData_x = ((int16_t)A16BitValue.Bytes[ 0 ] ) | (((int16_t)A16BitValue.Bytes[ 1 ] ) << 8);
 107
 108                        if( A16BitValue.Value != _magData_x )
 109                        {
 110                                Serial.print( A16BitValue.Value ); Serial.print( " " ); Serial.println( _magData_x );
 111                        }
 112*/
 113//                      A16BitValue.Bytes[ 0 ] = 0;
 114//                      A16BitValue.Bytes[ 1 ] = 0;
 115
 116//                      Serial.print( "Scale: " ); Serial.println( FScale );
 117//                      Serial.print( "Value: " ); Serial.print( A16BitValue.Bytes[ 0 ] ); Serial.print( " " ); Serial.println( A16BitValue.Bytes[ 1 ] );
 118//                      Serial.print( "Value: " ); Serial.println( A16BitValue.Value );
 119                        AValue = A16BitValue.Value * FScale;
 120
 121                        XOutputPin.SetValue( AValue, FChangeOnly );
 122
 123                        A16BitValue.Bytes[ 1 ] = Wire.read();
 124                        A16BitValue.Bytes[ 0 ] = Wire.read();
 125
 126                        AValue = A16BitValue.Value * FScale;
 127
 128                        ZOutputPin.SetValue( AValue, FChangeOnly );
 129
 130                        A16BitValue.Bytes[ 1 ] = Wire.read();
 131                        A16BitValue.Bytes[ 0 ] = Wire.read();
 132
 133                        AValue = A16BitValue.Value * FScale;
 134
 135                        YOutputPin.SetValue( AValue, FChangeOnly );
 136
 137                        FChangeOnly = true;
 138                }
 139
 140                virtual void DoClockReceive( void *_Data ) override
 141                {
 142                        FClocked = true;
 143                        ReadCompass();
 144                }
 145
 146        protected:
 147                void WriteTo( byte ARegister, byte AData )
 148                {
 149//                      Serial.print( "WriteTo :" ); Serial.print( ARegister ); Serial.print( " " ); Serial.println( AData );
 150                        Wire.beginTransmission( HMC5883L_Address );
 151                        Wire.write( ARegister );
 152                        Wire.write( AData );
 153                        Wire.endTransmission();
 154                }
 155
 156                void StartReadFrom( byte ARegister, byte ALength )
 157                {
 158//                      Serial.print( "StartReadFrom :" ); Serial.print( ARegister ); Serial.print( " " ); Serial.println( ALength );
 159                        Wire.beginTransmission( HMC5883L_Address );
 160                        Wire.write( ARegister );
 161                        Wire.endTransmission();
 162
 163                        Wire.requestFrom( HMC5883L_Address, ALength );
 164                        while (Wire.available() < ALength);
 165                }
 166
 167                virtual void SystemStart() override
 168                {
 169                        uint8_t AValue;
 170
 171                        WriteTo( HMC5883L_ModeRegister, 0 );
 172
 173                        AValue = ( Bias & 0b11 ) + (( AveragedSamples & 0b11 ) << 5 );
 174                        WriteTo( HMC5883_REGISTER_MAG_CRA_REG_M, AValue );
 175
 176                        AValue = ( Gain & 0b111 ) << 5;
 177                        WriteTo( HMC5883_REGISTER_MAG_CRB_REG_M, AValue );
 178//                      Serial.println( AValue );
 179//                      delay( 10000 );
 180
 181                        switch( Gain )
 182                        {
 183                                case cg1370: FScale = 0.73; break;
 184                                case cg1090: FScale = 0.92; break;
 185                                case cg820: FScale = 1.22; break;
 186                                case cg660: FScale = 1.52; break;
 187                                case cg440: FScale = 2.27; break;
 188                                case cg390: FScale = 2.56; break;
 189                                case cg330: FScale = 3.03; break;
 190                                case cg230: FScale = 4.35; break;
 191                        }
 192
 193                        SetIntIdle();
 194                        inherited::SystemStart();
 195                }
 196
 197                virtual void SystemLoopBegin( unsigned long currentMicros ) override
 198                {
 199                        if( Enabled )
 200                                if( FClocked || ( ! ClockInputPin.IsConnected() ))
 201                                        ReadCompass();
 202
 203                        inherited::SystemLoopBegin( currentMicros );
 204                }
 205
 206        public:
 207                HMC5883L_Compass() :
 208                        FClocked( false ),
 209                        FChangeOnly( false ),
 210                        AveragedSamples( cas1 ),
 211                        Bias( cbNone ),
 212                        Gain( cg1090 ),
 213                        Idle( false )
 214                {
 215                }
 216        };
 217}
 218
 219#endif