Fork me on GitHub

29/12/13

PIC: HMC5883 - Magnetômetro de 3 Eixos

PIC: HMC5883 - Magnetômetro de 3 Eixos


 HMC5883 é um magnetômetro digital de 3 eixos projetado para detecção de campos magnéticos. O sensor tem um alcance em larga escala de ± 8 Gauss e uma resolução de até 5 miliGauss.



A comunicação com o HMC5883L é simples e tudo feito através de uma interface I2C.


No próximo post, iremos criar uma bússola digital, isso mostrará em que direção esta apontando em graus. Ao ler 0° estará apontando para o polo norte magnético, e 180° quando estamos apontando para o polo sul magnético.



Como a bússola detecta campos magnéticos, qualquer material ferroso por perto pode afetar consideravelmente sua saída ( Estou vendo mais um projeto aí! Que tal fazermos um detector de metais?  ).


REGISTROS


Configuration Register A: É usado para configurar o dispositivo para a fixação da taxa de saída de dados e configuração de medição.

Configuration Register B: Ajusta o ganho do dispositivo.

Mode Register: Este registo é utilizado para selecionar o modo de funcionamento do dispositivo. (Medição Continua ou Medição Simples).

Data Output Register: Esses registros armazenam o resultado da medição da saída de dados.

Identification Register: É usado para identificar o dispositivo.

BIBLIOTECA


#include <built_in.h>
//Para utilizar o software_i2c...ou o i2c interno
#ifdef USE_HMC5883_SOFT_I2C
 #define HMC5883_I2C_Wr Soft_I2C_Write
 #define HMC5883_I2C_Rd Soft_I2C_Read
 #define HMC5883_I2C_Stop Soft_I2C_Stop
 #define HMC5883_I2C_Start Soft_I2C_Start
 #define HMC5883_I2C_Repeated_Start Soft_I2C_Start
#else
 #define HMC5883_I2C_Wr I2C1_Wr
 #define HMC5883_I2C_Rd I2C1_Rd
 #define HMC5883_I2C_Stop I2C1_Stop
 #define HMC5883_I2C_Start I2C1_Start
 #define HMC5883_I2C_Repeated_Start I2C1_Repeated_Start
#endif

#define CONFIGURATION_REG_A  0x00
#define CONFIGURATION_REG_B  0x01
#define MODE_REG  0x02
#define DATA_OUTPUT_REG  0x03
#define STATUS_REG  0x09
#define IDENTIFICATION_REG_A 0x0A
#define IDENTIFICATION_REG_B 0x0B
#define IDENTIFICATION_REG_C 0x0C

//Scale
#define _088Ga   0
#define _13Ga   32
#define _19Ga   64
#define _25Ga   96
#define _40Ga   128
#define _47Ga   160
#define _56Ga   192
#define _81Ga   224

#define HMC5883_ADDRESS  0x3C

typedef struct
{
  float X;
  float Z;
  float Y;
  unsigned Angle;
  unsigned MagneticField;
}HCM5883_Magnetometer;

static float hmc5883_scale;

void HMC5883_Init()
{
 hmc5883_scale = 0.92;
 HMC5883_I2C_Start();
 HMC5883_I2C_Wr( HMC5883_ADDRESS );
 HMC5883_I2C_Wr( CONFIGURATION_REG_B );
 HMC5883_I2C_Wr( 32 );
 HMC5883_I2C_Wr( 0x00 ); //Continuo
 HMC5883_I2C_Stop();
}
          
void HMC5883_Read( HCM5883_Magnetometer *Mag ) 
{
signed int tmp;
float heading;
unsigned magF[3];
 
 HMC5883_I2C_Start();
 HMC5883_I2C_Wr( HMC5883_ADDRESS );
 HMC5883_I2C_Wr( DATA_OUTPUT_REG );
 HMC5883_I2C_Repeated_Start();
 HMC5883_I2C_Wr( HMC5883_ADDRESS | 1 );
 
 Hi(tmp) = HMC5883_I2C_Rd(1);
 Lo(tmp) = HMC5883_I2C_Rd(1);
 Mag->X = (tmp * hmc5883_scale);
 Hi(tmp) = HMC5883_I2C_Rd(1);
 Lo(tmp) = HMC5883_I2C_Rd(1);
 Mag->Z = (tmp * hmc5883_scale);
 Hi(tmp) = HMC5883_I2C_Rd(1);
 Lo(tmp) = HMC5883_I2C_Rd(0);
 Mag->Y = (tmp * hmc5883_scale);
 HMC5883_I2C_Stop();
 
 heading = atan2( Mag->Y, Mag->X );
 //heading += declinationAngle; //http://www.magnetic-declination.com/
 
 
 if( heading < 0 )
 {
  heading += 6.283185307;
 }
  
 Mag->Angle = ((heading * 180) / 3.141592654);
 
 magF[0] = Mag->X / 10;
 magF[1] = Mag->Y / 10;
 magF[2] = Mag->Z / 10;
 Mag->MagneticField = sqrt( (magF[0]*magF[0]) + (magF[1]*magF[1]) + (magF[2]*magF[2]) ); //uT
 
}

void HMC5883_SetScale( char scale )
{
   switch( scale )
   {
 case   0: hmc5883_scale = 0.73; break;
 case  32: hmc5883_scale = 0.92; break;
 case  64: hmc5883_scale = 1.22; break;
 case  96: hmc5883_scale = 1.52; break;
 case 128: hmc5883_scale = 2.27; break;
 case 160: hmc5883_scale = 2.56; break;
 case 192: hmc5883_scale = 3.03; break;
 case 224: hmc5883_scale = 4.35; break;
 default:  hmc5883_scale = 0.92; break;
   }
   
   HMC5883_I2C_Start();
   HMC5883_I2C_Wr( HMC5883_ADDRESS );
   HMC5883_I2C_Wr( CONFIGURATION_REG_B );
   HMC5883_I2C_Wr( scale );
   HMC5883_I2C_Stop();
}

EXEMPLO:
/*
   Projeto: Leitura do Sensor HMC5883 e Display Nokia3310
   Autor: Tiago Henrique
*/

//Habilitar as seguintes bibliotecas:
// - I2C
// - Conversions e C_String

//Bibliotecas salvas em um arquivo externo
#include "hmc5883.h"
#include "nokia3310.h" //procure no blog a biblioteca!!!

sbit Nokia_SCE at RB3_Bit;
sbit Nokia_RST at RB4_Bit;
sbit Nokia_DC at RB5_Bit;
sbit Nokia_MOSI at RB6_Bit;
sbit Nokia_CLK at RB7_Bit;
sbit Nokia_SCE_Direction at TRISB3_Bit;
sbit Nokia_RST_Direction at TRISB4_Bit;
sbit Nokia_DC_Direction at TRISB5_Bit;
sbit Nokia_MOSI_Direction at TRISB6_Bit;
sbit Nokia_CLK_Direction at TRISB7_Bit;

HCM5883_Magnetometer Mag;
char msg[12];

void main() 
{
    Nokia_Init(); //inicia o display
    Nokia_Clear(); //limpa a tela do display
    ADCON1 = 0x0F; //desativa o canal analogico
    I2C1_Init(); //Inicializa o módulo I2C
    HMC5883_Init(); //inicializa o sensor
    CMCON = 7; //desativa os comparadores analogicos
    
    while(1)
    {
        //Faz a leitura do sensor
        HMC5883_Read( &Mag );

        //Converte o valor do "eixo X"  para string
        IntToStr( Mag.X, msg );
        Nokia_Set_Cursor(0,0); //Seta a posicao do cursor
        Nokia_Out( "X: ", BLACK ); 
        LTrim(msg); //Limpa os espaços a esquerda
        Nokia_Out( msg, BLACK ); //Imprime na tela
        
        IntToStr( Mag.Y, msg );
        Nokia_Set_Cursor(0,1);
        Nokia_Out( "Y: ", BLACK );
        LTrim(msg);
        Nokia_Out( msg, BLACK );
        
        IntToStr( Mag.Z, msg );
        Nokia_Set_Cursor(0,2);
        Nokia_Out( "Z: ", BLACK );
        LTrim(msg);
        Nokia_Out( msg, BLACK );
        
        WordToStr( Mag.Angle, msg );
        Nokia_Set_Cursor(0,3);
        Nokia_Out( "A: ", BLACK );
        LTrim(msg);
        Nokia_Out( msg, BLACK );

        WordToStr( Mag.MagneticField, msg );
        Nokia_Set_Cursor(0,4);
        Nokia_Out( "M: ", BLACK );
        LTrim(msg);
        Nokia_Out( msg, BLACK );
        Nokia_Out( "uT", BLACK );

        Delay_ms(500);
    }
}

4 comentários:

  1. Primeiramente queria elogiar pelo competência e qualidade do blog :)... caro amigo, eu baixei o modelo simulavel do arduino uno para o proteus... muito bom mesmo!!! esse HMC5883L tem no proteus tbm? eh simulavel? como faço para baixar?

    ResponderExcluir
    Respostas
    1. Muito obrigado!!
      Seria bom se pudesse simular, mas é só um modelo.
      Abraços.

      Excluir
  2. Excelente página com projetos incríveis. Estou tendo um problema na leitura dos dados que só consegue ser contínuo quando o endereço 03 (X MSB) tem o valor 255. Qual a grande besteira que estou fazendo? A ideia é montar um anemômetro com indicação de sentido do vento.

    Eduardo

    ResponderExcluir
    Respostas
    1. Estou tentando fazer a mesma coisa você teve sucesso?
      o anemômetro está funcionando para dar a indicação do vento estou com alguns problemas
      se pode me ajudar entre em contato. Obrigado
      pascoal.forgiarini@hotmail.com

      Excluir

Postagens Relacionadas!!