OPT3001 Umrechnungsformel / Gleichung?

Ich habe Mühe, eine echte Umrechnungsformel zu finden, um den RAW-Wert in ein sinnvolles Ergebnis umzuwandeln. Ich verwende einen OPT3001- Sensor von TI und ATTiny25 als MUC.

Ich habe ein Beispiel online gefunden, aber es gibt nicht den richtigen Wert in Lux an, die dort verwendete Gleichung lautet wie folgt:

/*Convert to LUX*/
//extract result & exponent data from raw readings
result = raw&0x0FFF;
exponent = (raw>>12)&0x000F;
lux=0.01*pow(2,eksponent)*result;

Dies ergibt laut meinem Luxmeter, den ich als Referenz habe, falsche Werte, und zum Beispiel sagt das Luxmeter 420 Lux im Büro. Die obige Gleichung gibt mir das Ergebnis 110 Lux , was nicht realistisch ist. Der Sensor funktioniert einwandfrei, als ich ihn durch einen neuen ersetzte, um zu 100% zu sagen, dass es sich nicht um ein sensorbezogenes Problem handelt.

Das Ergebnis ist sehr nah, wenn ich nur nehme result = raw&0x0FFF;, aber dann schlägt es bei höheren Werten fehl (wenn ich meinen Sensor unter die Glühbirne der Lampe halte).

Ich glaube nicht, dass es ein Fehler in meinem I2C-Code ist, aber ich werde hier auch den Teil meines Codes für UpdateLight anhängen:

// I2C OPT address
#define OPT_ADDR_W  0x88
#define OPT_ADDR_R  0x89

// I2C OPT registers
#define OPT_RESULT_REG  0x00
#define OPT_CONFIG_REG  0x01

// OPT config bits - automatic full scale mode, 100 ms conversion, single-shot
#define OPT_CONFIGURATION_H 0xC2
#define OPT_CONFIGURATION_L 0x00

void UpdateLight(void)
{
    uint8_t error = 0;
    // start conversion
    I2C_Start();
    error |= I2C_Write(OPT_ADDR_W);
    error |= I2C_Write(OPT_CONFIG_REG);
    error |= I2C_Write(OPT_CONFIGURATION_H);
    error |= I2C_Write(OPT_CONFIGURATION_L);
    I2C_Stop();

    // wait for conversion
    _delay_ms(150);

    // set result register
    I2C_Start();
    error |= I2C_Write(OPT_ADDR_W);
    error |= I2C_Write(OPT_RESULT_REG);
    I2C_Stop();

    // read data and update scratchpad
    I2C_Start();
    error |= I2C_Write(OPT_ADDR_R);
    if (error == 0)
    {
        scratchpad[1] = I2C_Read(1);
        scratchpad[0] = I2C_Read(0);
    }
    else
    {
        // report error value
        scratchpad[1] = 0xFF;
        scratchpad[0] = 0xFF;
    }
    I2C_Stop();
    }

Und das ist meine alte Formel, die ich mir ausgedacht habe, aber sie liefert noch lächerlichere Ergebnisse als die obige aus dem Internet:

   // calculate light ( LUX = (MANTISA << EXPONENT) / 100 )
   light = (int16_t)((float)((uint32_t)((spad[SPAD_MSB] << 8) | spad[SPAD_LSB]) << (uint32_t)((spad[SPAD_MSB] >> 4) & 0x0F)) / (83865.60 / LIGHT_MULTIPLIER));
   debug_printf("L_RAW: %02X%02X\r\n", spad[SPAD_MSB], spad[SPAD_LSB]);
   debug_printf("L_VAL: %d\r\n", light); 

Hinzufügen der Ausgabezeilen der obigen Druckanweisungen:

L: 5460 - 824

L: 5464 - 824

L: 5462 - 824

L: 5462 - 824

Der erste Wert sollte RAW MSB und LSB sein, und der zweite ist der konvertierte Wert in Lux, unter Verwendung der obigen Formel.

Außerdem bin ich überrascht, dass TI im Datenblatt keine Umrechnungsformel angegeben hat?

Jede Hilfe wird sehr geschätzt.

Was ist der Rohwert, den Sie erhalten? Übrigens sieht es (durch das Konvertierungsbeispiel) so aus, dass die Darstellung tatsächlich eine Standard-Gleitkommadarstellung ist.
@EugenSch. Raw1: 5463 , Raw2: 5461 aufgenommen bei Office Light Ambient. Die obige Gleichung gibt mir das Ergebnis 148,16 Lux, was falsch ist. Näher am realen Ergebnis ist es, wenn ich nur result=raw&0x0FFF nehme ... Allerdings versagt dieser dann bei höheren Helligkeiten (Lampe leuchtet darüber). Seltsam..
Die Zahlen sehen verdächtig aus, da 5461 in Hex 0x1555 ist, die abwechselnd Nullen und Einsen sind. Kann es sein, dass du SDA und SCL vertauscht hast?
@EugenSch. Hm. Könnte sein, aber dass ich noch einmal im Labor nachsehen muss, hatte diese Art von Problem nicht erwartet, hüpfte, es sei softwareorientiert. Hier ist ein rohes Beispiel unter Licht: 8437 (hex)
Na ja, wenn Sie einige unterschiedliche Werte haben, sollte die Verbindung wohl in Ordnung sein.
Übrigens, Sie haben die Konfigurationswörter nicht angegeben, es könnte sein, dass Sie nur mit einem anderen Bereich arbeiten, als Sie annehmen.
@EugenSch. Ich habe meine Frage bearbeitet, wenn Sie danach suchen. Sorry, immer noch nicht das beste mit Softwareteil.
@EugenSch. Konfig 0xC200
@Passerby Die Konfig sieht richtig aus, wobei ich mich etwas um die Bits 10:9 kümmere. Ich bin mir nicht ganz sicher, was der "Shutdown" -Modus ist. Vielleicht sollte auf "kontinuierlich" umgestellt werden.
@EugenSch. 10:9 ist mit dieser Konfiguration auf 01 gesetzt. One-Shot/Single-Konvertierungsmodus, das ist normal.
@ Passant Oh, richtig. Eins verpasst..
Sehen Sie sich die E2E-Community von TI an , an der Fachleute von TI normalerweise häufig teilnehmen. Und ich weiß nicht, aber diese Frage ist vielleicht die gleiche wie deine.

Antworten (1)

Auf Seite 20des Datenblattes ist die detaillierte Beschreibung der Berechnung gegeben. Aus dem angegebenen Beispielwert aus den Kommentaren 0x5461erhalten wir den 0x5Wert für den Exponenten, der 0.32 lux per LSB. Die Mantisse ist 0x461oder 1121 in Dezimalzahl. Der resultierende Wert liegt 1121*0.32=358.72luxnahe am erwarteten Bereich.

Der funktionierende Konvertierungscode:

#include <stdio.h>
#include <stdint.h>

int main(void) {
    uint16_t raw = 0x5461;
    uint16_t result, exponent;
    float lux;

    result = raw & 0x0FFF;
    exponent = (raw>>12) & 0x000F;

    lux=0.01*(1<<exponent)*result;

    printf("%f\n", lux);
    return 0;
}

Oder führen Sie es hier aus .

Bitte achten Sie genau auf die verwendeten Datentypen, diese könnten Ihnen ebenfalls Probleme bereitet haben.

Sie denken also, dass der Wert 5461¸ und andere keine HEX-Werte sind? Sie betrachten sie als Dezimalwerte? Ich dachte, das wären HEX-Werte
Ich frage mich immer noch, woher diese 110 Lux kommen, wenn ich die falschen Werte eingebe, bekomme ich nur 27 Lux ... Aber ja, Endianness ist eine große Falle bei der Datenübertragung, ich denke, jeder stolpert darüber.
Ich weiß nicht, du sagst es mir. Wie lesen Sie sie?
Ich habe den Teil des Codes hinzugefügt, wo ich den Rohwert umwandle und ihn dann ausdrucke.
@AndroidNFC Wenn es keinen Hinweis gibt (wie hex oder 0x oder _h), werden die meisten Leute sie als Dezimal lesen. Wenn Sie diese Werte als Hex nehmen, erhalten Sie 360 ​​Lux und nicht 148 Lux, wie in Ihrem Kommentar angegeben.
Was genau sind die Ausgaben der Drucke?
@Arsenal Ich habe erwähnt, dass ich noch nicht sehr gut im Programmieren bin, daher könnte der Code aufgrund der Hilfe des Internets und anderer etwas chaotisch sein. Aber wie ich verstanden habe, sollten die gedruckten Werte in HEY sein. Mit der obigen Gleichung in meiner Frage (der ersten) erhalte ich den Wert 148 Lux = 0,01 * 2exp5 * 463
@EugenSch. Nach meinem Verständnis und aus dem Datenblatt sollten sie die MSB- und LSB-Bytes sein.
Ich meine die eigentlichen Ausgangsleitungen, können Sie sie zeigen? Wie auch immer, das Ergebnis aus dieser Zahl sollte in jedem Fall 360 Lux sein, was im Bereich liegen könnte.
@AndroidNFC Vergiss in deiner Berechnung nicht, dass sie 463in Hex sind.
Ich denke, der Endianness-Teil der Antwort ist irrelevant, als.
@Arsenal und Eugene Ich habe meine Frage bearbeitet und die Ausgabe von Druckanweisungen hinzugefügt.
Die Antwort wurde so bearbeitet, dass sie nur den relevanten Teil enthält.
@EugenSch. Könnten Sie mir einen C-Code aus dem von Ihnen geposteten Datenblattteil zur Verfügung stellen? Ich bin mir nicht sicher, wie ich die 15: 12-Bits aus meinem Ergebnis auswählen soll, damit ich das laut Datenblatt als Exponent speichern kann.
Schau dir die Aktualisierung an.
@EugenSch. Danke für das Update. Könnten Sie mir bitte erklären, warum die UND-Verknüpfungen erforderlich sind? (Ich bin neu in C, ich entwickle hauptsächlich Android-Apps, wollte aber ein elektronischeres Projekt machen.)
Es ist zu weit gefasst für Kommentare und off-topic für die Antwort. Schau hier
Vielen Dank! Ich werde Ihre Antwort akzeptieren, aber ich kann mit meinem Lux-Meter immer noch nicht in die Nähe der Werte kommen, wenn Sie den Hex-Wert 843B versuchen. Ich bekomme 2772,48 Lux und das Lux-Meter sagte 1864 Lux.
Leider kann ich Ihnen mit den bereitgestellten Daten nicht helfen. Vergessen Sie nicht, dass dies luxein subjektives Maß ist (angepasst an das menschliche Auge), das neben der Intensität stark von den Wellenlängen beeinflusst wird. Sie müssen also bei der Messung unbedingt für beide Sensoren identische Bedingungen schaffen. Und Sie können einen kontinuierlichen Test durchführen, um zu überprüfen, wie sich die Werte ändern, wenn das Licht erhöht oder verringert wird. Wenn sie sich allmählich ohne große Sprünge ändern, ist dies ein guter Hinweis darauf, dass sie korrekt gemessen wurden (bis zur Vorspannung des Sensors..)
@AndroidNFC Ihr Referenz-Luxmeter und der OPT3001 haben möglicherweise unterschiedliche Winkelreaktionen, wodurch sie unterschiedliche Messwerte erhalten. Schauen Sie sich Seite 8 an, auf der Sie die normalisierte Reaktion gegenüber dem Winkel sehen können. Wenn sie unterschiedlich sind, erhalten Sie unterschiedliche Messwerte.
@Arsenal und Eugene, könnte vielleicht stimmen, weil ich sie zum Beispiel auch nicht schön identisch unter der Lampe platzieren könnte. Und ich habe den Sensor tatsächlich näher an der Lampe als am Messgerät platziert. Wenn Sie also sagen, dass er wirklich empfindlich ist, könnte dies diese Unterschiede erklären!
Das Ergebnis (in Einheiten von 0,01 Lux) ist der Bruchteil, multipliziert mit 2^n, wobei n der Exponent ist. In Lots von 0,01 Lux können Sie also einfach result = fraction_part << n verwenden; wobei n der Exponent ist. (N Bits nach rechts verschieben ist dasselbe wie mit 2^n multiplizieren). Also result = (fraction_part << n) / 100 für ganze Lux; und wobei n = der Exponententeil.