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.
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);
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);
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.
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:
1 | /******** Gyro Temperatur ermitteln ********/
|
2 | float GyroTemp(void) |
3 | {
|
4 | float iTemp = 0.0; // Berechnete Temperatur |
5 | uint16_t iTempRaw = 0; // Rohdaten des Temperatursensors |
6 | |
7 | GyroAdcSetMode(1); // 2. Modi setzen, ADC Wandlung (Temp. Messung) |
8 | GyroTempSetMode(&iTempRaw); // 3. Ergebnis der Messung lesen |
9 | |
10 | //iTemp = (iTempRaw - 0x3F0) + 273; // Temperatur des Gyros in Grad Celsius
|
11 | iTemp = 25 + (iTempRaw - (1408 << 1)) / (2 * 6.4); // Temperatur des Gyros in Grad Celsius |
12 | |
13 | return iTemp; |
14 | }
|
Also iTempRaw sind die Messwerte die er roh vom Gyro kriegt, entsprechende Funktion sieht so aus:
1 | /******** ADC Temperatur Messung starten ********/
|
2 | uint16_t GyroTempSetMode(uint16_t* ptValue) |
3 | {
|
4 | uint8_t ucCommand = 0; |
5 | uint16_t unStatus = 0; |
6 | |
7 | ucCommand = GYRO_ADCC; |
8 | ucCommand |= (1 << 2); |
9 | ucCommand |= (1 << 3); |
10 | |
11 | PORTB &= ~(1 << PB2); // Den entsprechenden Sensor selektieren |
12 | |
13 | SPI_SendByte(ucCommand); // Befehl senden |
14 | unStatus = SPI_TransferWord(0xFF); // Antwort holen |
15 | |
16 | while(!unStatus & (1 << 15)) |
17 | {
|
18 | unStatus = SPI_TransferWord(0xFF); |
19 | }
|
20 | |
21 | PORTB |= (1 << PB2); // Den entsprechenden Sensor deselektieren |
22 | |
23 | _delay_us(250); // 250us warten damit der Sensor richtig arbeiten kann |
24 | |
25 | //*ptValue = ((unStatus & 0x0FFF) >> 1); // 12Bit ausmaskieren und um 1Bit nach rechts schieben
|
26 | *ptValue = ((unStatus >> 1) & 0x0FFF); |
27 | |
28 | return unStatus; |
29 | }
|
und hier noch die Modi auswahl:
1 | /******** ADC Drehraten / Temperatur Messung starten ********/
|
2 | uint16_t GyroAdcSetMode(uint8_t channel) // Wenn channel == 1, Temperaturmessung |
3 | {
|
4 | uint8_t ucCommand = 0; |
5 | uint16_t unStatus = 0; |
6 | |
7 | ucCommand = GYRO_ADCC; |
8 | ucCommand |= (1 << 2); |
9 | |
10 | if(channel == 1) |
11 | {
|
12 | ucCommand |= (1 << 3); |
13 | }
|
14 | |
15 | PORTB &= ~(1 << PB2); // Den entsprechenden Sensor selektieren |
16 | |
17 | SPI_SendByte(ucCommand); // Befehl senden |
18 | unStatus = SPI_TransferWord(0xFF); // Antwort holen |
19 | |
20 | while(!unStatus & (1 << 15)) |
21 | {
|
22 | unStatus = SPI_TransferWord(0xFF); |
23 | }
|
24 | |
25 | PORTB |= (1 << PB2); // Den entsprechenden Sensor deselektieren |
26 | |
27 | _delay_us(250); // 250us warten damit der Sensor richtig arbeiten kann |
28 | |
29 | return unStatus; |
30 | }
|
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.
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);
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?
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.
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.
1 | /******** ADC Temperatur Messung starten ********/
|
2 | uint16_t GyroTempSetMode(uint16_t* ptValue) |
3 | {
|
4 | uint8_t ucCommand = 0; |
5 | uint16_t unStatus = 0; |
6 | |
7 | ucCommand = GYRO_ADCC; |
8 | ucCommand |= (1 << 2); |
9 | ucCommand |= (1 << 3); |
10 | |
11 | PORTB &= ~(1 << PB2); // Den entsprechenden Sensor selektieren |
12 | |
13 | SPI_SendByte(ucCommand); // Befehl senden |
14 | unStatus = SPI_TransferWord(0xFF); // Antwort holen |
15 | |
16 | while(!unStatus & (1 << 15)) |
17 | {
|
18 | unStatus = SPI_TransferWord(0xFF); |
19 | }
|
20 | |
21 | PORTB |= (1 << PB2); // Den entsprechenden Sensor deselektieren |
22 | |
23 | _delay_us(250); // 250us warten damit der Sensor richtig arbeiten kann |
24 | |
25 | //*ptValue = ((unStatus & 0x0FFF) >> 1); // 12Bit ausmaskieren und um 1Bit nach rechts schieben
|
26 | *ptValue = ((unStatus >> 1) & 0x0FFF); |
27 | |
28 | return unStatus; |
29 | }
|
1 | /******** Gyro Temperatur ermitteln ********/
|
2 | float GyroTemp(void) |
3 | {
|
4 | float iTemp = 0.0; // Berechnete Temperatur |
5 | int16_t iTempRaw = 0; // Rohdaten des Temperatursensors |
6 | |
7 | GyroAdcSetMode(1); // 2. Modi setzen, ADC Wandlung (Temp. Messung) |
8 | GyroTempSetMode(&iTempRaw); // 3. Ergebnis der Messung lesen |
9 | |
10 | //iTemp = (iTempRaw - 0x3F0) + 273; // Temperatur des Gyros in Grad Celsius
|
11 | iTemp = 25 + (iTempRaw - 1408) / (2 * 6.4); // Temperatur des Gyros in Grad Celsius |
12 | |
13 | return iTemp; |
14 | }
|
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.
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.
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.
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.