mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik [AVR] MLX90609 Temperatur berechnen


Autor: Patrick L. (crashdemon)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich habe eine Schaltung aufgebaut bei der ich mittels SPI den Gyro 
MLX90609 von Melexis auslesen, das ganze hängt an einem Atmel8, da der 
Drehratensensor einen eingebauten Temperatursensor verfügt der ebenfalls 
per SPI ausgelesen werden kann,  will ich diesen nutzen um bei 
Temperaturschwankunken meine Messwerte anzupassen, nur leider werde ich 
aus dem Datenblatt nicht ganz schlau.

Meine Funktion sieht zurzeit so aus, allerdings kommen damit nur 
unrealistische Temperaturen zustande.
[c]
/******** Gyro Temperatur ermitteln ********/
int16_t GyroTemp(void)
{
  int16_t iTemp = 0; // Berechnete Temperatur
  uint16_t iTempRaw = 0; // Rohdaten des Temperatursensors

  GyroAdcSetMode(1); // 2. Modi setzen, ADC Wandlung (Temp. Messung)
  GyroTempSetMode(&iTempRaw); // 3. Ergebnis der Messung lesen

  iTemp = (iTempRaw - 0x3F0) + 273; // Temperatur des Gyros

  return iTemp;
}
[c]

Vllt. gibt es ja hier jemanden im Forum der diesen Sensor erfolgreich 
einsetzt, der mir dabei helfen könnte.

Autor: Patrick L. (crashdemon)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hat denn keiner eine idee?

Autor: Henry (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
int16_t sValue; // das ist der Wert wie er aus dem Sensor kommt
float fValue; // Temperatur in Celsius

fValue = 25 + (sValue - (1408 << 1)) / (2 * 6.4);

Autor: Patrick L. (crashdemon)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Henry wrote:
> int16_t sValue; // das ist der Wert wie er aus dem Sensor kommt
> float fValue; // Temperatur in Celsius
>
> fValue = 25 + (sValue - (1408 << 1)) / (2 * 6.4);

Danke für die Antwort, habe es mal mit der Formel ausprobiert hat aber 
leider nicht funktioniert, hab diese ein wenig angepasst, da ich die 
300°/s variante benutze.
Leider werden mir werte wie 9945 angezeigt, die sich auch nicht ändern, 
bei z.B. anpusten des Sensors, könntest du mir vllt. einmal erläutern 
wie sich deine Formel zusammensetzt, bzw wie du auf die Werte kommst, da 
im Datenblatt  ja nur eine Formel für die Berechnung der Temperatur bei 
werten die vom ADC kommen, steht.

fValue = 25 + (sValue - (1408 << 1)) / (2 * 3.2);

Autor: Henry (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe das einfach nur aus meinem Programm kopiert und das 
funktioniert. Die 300° Variante benutze ich auch. Da rein denken ist mir 
aber zu mühevoll. Ich habe da auch einige Zeit gegrübelt.

Hast du sValue als signed 16 Bit deklariert?
Hast du die Statusbits des Messwerts gelöscht? sValue &= 0x0FFF;
Wartest du bis der Gyro ADC fertig ist?
Das muss (2 * 6.4) heißen.

Autor: Patrick L. (crashdemon)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Henry wrote:
> Ich habe das einfach nur aus meinem Programm kopiert und das
> funktioniert. Die 300° Variante benutze ich auch. Da rein denken ist mir
> aber zu mühevoll. Ich habe da auch einige Zeit gegrübelt.
>
> Hast du sValue als signed 16 Bit deklariert?
> Hast du die Statusbits des Messwerts gelöscht? sValue &= 0x0FFF;
> Wartest du bis der Gyro ADC fertig ist?
> Das muss (2 * 6.4) heißen.

So sieht meine funktion aus:
/******** Gyro Temperatur ermitteln ********/
float GyroTemp(void)
{
  float iTemp = 0.0; // Berechnete Temperatur
  uint16_t iTempRaw = 0; // Rohdaten des Temperatursensors

  GyroAdcSetMode(1); // 2. Modi setzen, ADC Wandlung (Temp. Messung)
  GyroTempSetMode(&iTempRaw); // 3. Ergebnis der Messung lesen

  //iTemp = (iTempRaw - 0x3F0) + 273; // Temperatur des Gyros in Grad Celsius
  iTemp = 25 + (iTempRaw - (1408 << 1)) / (2 * 6.4); // Temperatur des Gyros in Grad Celsius

  return iTemp;
}

Also iTempRaw sind die Messwerte die er roh vom Gyro kriegt, 
entsprechende Funktion sieht so aus:
/******** ADC Temperatur Messung starten ********/
uint16_t GyroTempSetMode(uint16_t* ptValue)
{
     uint8_t ucCommand = 0;
     uint16_t unStatus = 0;

  ucCommand = GYRO_ADCC;
  ucCommand |= (1 << 2);
  ucCommand |= (1 << 3);

     PORTB &= ~(1 << PB2); // Den entsprechenden Sensor selektieren

     SPI_SendByte(ucCommand); // Befehl senden
     unStatus = SPI_TransferWord(0xFF); // Antwort holen

  while(!unStatus & (1 << 15))
  {
    unStatus = SPI_TransferWord(0xFF);  
  }

  PORTB |= (1 << PB2); // Den entsprechenden Sensor deselektieren

  _delay_us(250); // 250us warten damit der Sensor richtig arbeiten kann

  //*ptValue = ((unStatus & 0x0FFF) >> 1); // 12Bit ausmaskieren und um 1Bit nach rechts schieben
  *ptValue = ((unStatus >> 1) & 0x0FFF); 

  return unStatus;
} 

und hier noch die Modi auswahl:
/******** ADC Drehraten / Temperatur Messung starten ********/
uint16_t GyroAdcSetMode(uint8_t channel) // Wenn channel == 1, Temperaturmessung
{
     uint8_t ucCommand = 0;
     uint16_t unStatus = 0;

  ucCommand = GYRO_ADCC;
  ucCommand |= (1 << 2);

  if(channel == 1)
  {
    ucCommand |= (1 << 3);
  }

     PORTB &= ~(1 << PB2); // Den entsprechenden Sensor selektieren

     SPI_SendByte(ucCommand); // Befehl senden
     unStatus = SPI_TransferWord(0xFF); // Antwort holen

  while(!unStatus & (1 << 15))
  {
    unStatus = SPI_TransferWord(0xFF);  
  }

  PORTB |= (1 << PB2); // Den entsprechenden Sensor deselektieren

  _delay_us(250); // 250us warten damit der Sensor richtig arbeiten kann

     return unStatus;
}

Statusbits des Messwerts werden ausmaskiert (ptValue = ((unStatus >> 1) 
& 0x0FFF)).
Ich warte bis ADC umwandlung fertig ist, 3.2 habe ich jetzt wieder in 
6.4 zurückgeändert, jetzt kommt als Temperatur 4985 raus.

Autor: Henry (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zwei Dinge sehe ich auf die Schnelle.

1.
uint16_t iTempRaw = 0;

iTempRaw muss als int16_t  deklariert sein damit die Berechnung 
funktioniert.

2.
*ptValue = ((unStatus >> 1) & 0x0FFF);

mach das Shift weg und schreibe:

*ptValue = unStatus & 0x0FFF;

oder mach es mit Shift und schreibe:

iTemp = 25 + (iTempRaw - 1408) / (2 * 3.2);

Autor: Patrick L. (crashdemon)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Henry wrote:
> Zwei Dinge sehe ich auf die Schnelle.
>
> 1.
> uint16_t iTempRaw = 0;
>
> iTempRaw muss als int16_t  deklariert sein damit die Berechnung
> funktioniert.
>
> 2.
> *ptValue = ((unStatus >> 1) & 0x0FFF);
>
> mach das Shift weg und schreibe:
>
> *ptValue = unStatus & 0x0FFF;
>
> oder mach es mit Shift und schreibe:
>
> iTemp = 25 + (iTempRaw - 1408) / (2 * 3.2);

Habe iTempRaw jetzt als int16_t deklariert kann aber nicht 
nachvollziehen,
warum das so sein muss, ausscheinlich hat das meinen Messwert aber zum 
positiven verbessert, habe auf meiner anzeige jetzt -24 stehen, jetzt 
noch mit -1 multiplizieren dann müsste das ja die richtige Temperatur 
sein, jedoch kommt mir diese Temperaturmessung sehr träge vor, da sich 
der angezeigte Wert auch nach anpusten nicht verändert, ist das bei dir 
auch so?

Was ich noch nicht so ganz verstehe wie du auf den Wert 1408 kommst?

Autor: Henry (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das mit dem -1 Multiplizieren ist doch nur geraten.

Zeig nochmals den Kode von GyroTempSetMode() und GyroTemp().

Hast du auch meinen 2. Hinweis mit dem Shift realisiert?



Der Sensor verbraucht ziemlich viel Strom und heizt sich auf. Das 
Anpusten ist da wirkungslos. Warum willst du temperaturkompensieren? Das 
wird doch schon intern gemacht.

Autor: Patrick L. (crashdemon)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Henry wrote:
> Das mit dem -1 Multiplizieren ist doch nur geraten.
>
> Zeig nochmals den Kode von GyroTempSetMode() und GyroTemp().
>
> Hast du auch meinen 2. Hinweis mit dem Shift realisiert?
>
>
> Der Sensor verbraucht ziemlich viel Strom und heizt sich auf. Das
> Anpusten ist da wirkungslos. Warum willst du temperaturkompensieren? Das
> wird doch schon intern gemacht.
/******** ADC Temperatur Messung starten ********/
uint16_t GyroTempSetMode(uint16_t* ptValue)
{
     uint8_t ucCommand = 0;
     uint16_t unStatus = 0;

  ucCommand = GYRO_ADCC;
  ucCommand |= (1 << 2);
  ucCommand |= (1 << 3);

     PORTB &= ~(1 << PB2); // Den entsprechenden Sensor selektieren

     SPI_SendByte(ucCommand); // Befehl senden
     unStatus = SPI_TransferWord(0xFF); // Antwort holen

  while(!unStatus & (1 << 15))
  {
    unStatus = SPI_TransferWord(0xFF);  
  }

  PORTB |= (1 << PB2); // Den entsprechenden Sensor deselektieren

  _delay_us(250); // 250us warten damit der Sensor richtig arbeiten kann

  //*ptValue = ((unStatus & 0x0FFF) >> 1); // 12Bit ausmaskieren und um 1Bit nach rechts schieben
  *ptValue = ((unStatus >> 1) & 0x0FFF); 

  return unStatus;
}
/******** Gyro Temperatur ermitteln ********/
float GyroTemp(void)
{
  float iTemp = 0.0; // Berechnete Temperatur
  int16_t iTempRaw = 0; // Rohdaten des Temperatursensors

  GyroAdcSetMode(1); // 2. Modi setzen, ADC Wandlung (Temp. Messung)
  GyroTempSetMode(&iTempRaw); // 3. Ergebnis der Messung lesen

  //iTemp = (iTempRaw - 0x3F0) + 273; // Temperatur des Gyros in Grad Celsius
  iTemp = 25 + (iTempRaw - 1408) / (2 * 6.4); // Temperatur des Gyros in Grad Celsius

  return iTemp;
}

So hier nochmal der aktuelle Code, habe hoffentlich das Shifting so 
umgesetzt wie du das meintest.
Der MLX ist ja von Haus aus schon recht Temperaturstabil, ich will aber 
möglichst auch eine Sotfwarebasierende Temperaturkompensation einbauen, 
um auf etwaige Abweichungen der Messwerte reagieren zu können.

Autor: Henry (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Deine erste Zeile ist besser:

*ptValue = (unStatus & 0x0FFF) >> 1;
// *ptValue = (unStatus >> 1) & 0x0FFF;


Weil du mit Shift arbeitest muss der Faktor

(2 * 3.2)

heißen.

Autor: Patrick L. (crashdemon)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Henry wrote:
> Deine erste Zeile ist besser:
>
> *ptValue = (unStatus & 0x0FFF) >> 1;
> // *ptValue = (unStatus >> 1) & 0x0FFF;
>
>
> Weil du mit Shift arbeitest muss der Faktor
>
> (2 * 3.2)
>
> heißen.

Hat sich schon erledigt lag alles an einem dummen Fehler meinerseits, da 
ich keinen überblich über meine eingesetzten Funktionen hatte, 
GyroAdcSetMode und  GyroTempSetMode habe ein und dasselbe getan, nämlich 
den Modus des Gyros auf Temperatur Sensor Signal zu stellen. An dieser 
stelle dann trotzdem vielen danke für die unterstützung.

Autor: bruecke1982 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo ich habe eure Artikel Aufmerksam gelesen und habe einige fragen 
zum MLX90609, bezüglich der Initialisierung.
Ich arbeite gerade an meiner Bachelorarbeit und versuche Verzweifelt den 
MLX90609 zum laufen zu bekommen. Ich bekomme leider nur ab und zu 
sinvolle Daten, habe mich nach der Anleitung von Melexis gerichtet. 
Leider habe ich sehr oft Hardware Error Melexis berücksichtigt dies zwar 
in seinen Programmen, sagt aber nicht was man tun soll um diese zu 
vermeiden. Ich habe schon alles ausprobiert, neuinitialisierung, in den 
Schlafmodus schicken->wieder aufwecken.
Ich habe beide methoden probiert Zeitliches abwarten durch eine delay 
funktion oder abfrage des MSB und EOC. Das Ergebniss ist immer dasselbe, 
ab und zu sind mal alle Abfragen "WAHR" doch meist nicht. Es gibt 
nirgens eine vollständige Initiallisierungsbeschreibung.
Meine Hauptfrage ist erstmal funktioniert das gerät reibungslos mit 
eurer init?
Ich wäre euch sehr dankbar wenn ihr mir helfen könnt.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.