Forum: Mikrocontroller und Digitale Elektronik ATMega8: HDMM01 Sensor auslesen über I2C(Atmel)


von hilfesuchender (Gast)


Lesenswert?

Hallo,

ich arbeite im Moment an einem Hochschulprojekt, indem das Kompassmodul 
HDMM01 von Pollin auf einem Schrittmotor angebracht werden soll. So soll 
ein digitaler Kompass gebaut werden.

Da ich ein kompletter Neuling auf diesem Gebiet bin, tue ich mir mit dem 
Auslesen des Sensors über I2C sehr schwer. Eventuell findet sich hier 
jemand, der in der Lage ist mir grobe Schnitzer aufzuzeigen. Ich freue 
mich über jegliche Hilfe.
Hier mein Code:

#define F_CPU 3686400UL
#include <avr/io.h>
#include <compat/twi.h>
#include <util/delay.h>
#include "i2cmaster.h"

#define F_SCL 100000L //100 kHz
#define Kompass (0x60) //Adresse HDMM01

//==============================================Initialisierung
void I2C_init(void)
{
  TWSR = 0;
  TWBR = ((F_CPU/F_SCL)-16)/2;
}
//=================================================

//===============================================start
unsigned char I2C_start(unsigned char address)
{
  uint8_t twst;

  TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);

  while(!(TWCR & (1<<TWINT)))
  ;

  twst = TW_STATUS & 0xF8;
  if((twst!=TW_START) && (twst!=TW_REP_START)) return 1;

  TWDR = address;
  TWCR = (1<<TWINT) | (1<<TWEN);

  while(!(TWCR & (1<<TWINT)))
  ;

  twst = TW_STATUS & 0xF8;
  if ((twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK)) return 1;

  return 0;
}
//==================================================

//==================================================Write
unsigned char I2C_write(unsigned char data)
{
  uint8_t twst;

  TWDR = data;
  TWCR = (1<<TWINT) | (1<<TWEN);

  while(!(TWCR & (1<<TWINT)))
  ;

  twst = TW_STATUS & 0xF8;
  if(twst != TW_MT_DATA_ACK) return 1;

  return 0;
}
//=================================================

//=================================================Stop
void I2C_stop(void)
{
  TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);

  while(TWCR & (1<<TWSTO))
  ;
}
//====================================================

//====================================================
unsigned char I2C_readAck(void)
{
  TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
  while(!(TWCR & (1<<TWINT)));

  return TWDR;

}
//====================================================
unsigned char I2C_readNak(void)
{
  TWCR = (1<<TWINT) | (1<<TWEN);
  while(!(TWCR & (1<<TWINT)));

  return TWDR;

}
//====================================================

//============================================Lesen des Kompass
int KompassRead (void)
{
  unsigned int data;
  I2C_start(Kompass + I2C_WRITE);// Set device address at write mode.
  I2C_write(0x00);        // Write 0x00 and 0x31 to I2C data bus.
  I2C_write(0xF1);        // These two bytes measure the angle (return 
the value of the angle).
  I2C_stop();

  I2C_start(Kompass + I2C_WRITE);// Set device address and write mode
  I2C_write(0x01);
  I2C_stop();

  I2C_start(Kompass + I2C_READ);  // Set device address and read mode
  data = (I2C_readAck() << 8);  // Read the Most Significant Byte (MSB) 
from the compass.
  data += I2C_readNak();      // Read the Low Significant Byte (LSB) 
from the compass.
  I2C_stop();

  return (data); //Return the degrees value (16-bit integer from 
0-3650).
}

int main(void)
{
  PORTC = 0xFF;
  I2C_init();

  char data[16];
  unsigned int compass;
  unsigned char length;

  while(1)
  {
    /*compass = KompassRead();
    itoa(compass, data, 10);
    length = strlen(data);
    data[length + 1] = 0x00;
    data[length] = data[length - 1];
    data[length - 1] = '.';
    if(length == 1)
    {
      data[3] = 0;
      data[2] = data[1];
      data[1] = '.';
      data[0] = '0';

    }*/
    /*lcd_goto_xy(0,1);// x = horizontal, y = vertical (line).
    lcd_puts(data);
    placeEmptyCharacters(data,5);*/
    }

  }

Vielen Dank schon mal im Voraus!!

von Nico (nico123)


Lesenswert?

Probiere den Code doc heinfach aus, oder hast Du das schon!?
Wo liegt das Problem, gibt es Fehler?

von Kirsch (Gast)


Lesenswert?

Ich kann nur abraten den HDMM01 zu verwendet.
Er Misst das Magnetfeld nur auf 2-Achsen, das heißt das Modul muss immer 
Waagerecht liegen.

Außerdem gibt es nur die Raw-Werte aus. Die Richtung musst du über 
trigonometrische Funktionen selber bestimmen.
Um Kalibrierung musst du dich auch kümmern, das heißt:
Mehrmals im Kreis drehen, und MIN/MAX Werte der beiden Achsen bestimmen.
Damit Offset und Skalierung der Achsen bestimmen.
Mit den Korrigierten Werte kann mit der atan2-Funktion der Winkel 
bestimmt werden.

Auf einem µC hat man eventuell keine trigonometrische Funktionen, dass 
heiß du musst dir deine atan2-Funktion selber bauen, (z. B. mit Hilfe 
von Approximation und Lookup-Tabellen)


Zu I2C Ansteuerung:
Du sendest eine 0
Danach liest du 5 Bytes

Für die Bedeutung der 5 Bytes schau dir das Datenblatt an

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.