Wie liest man Daten von diesem Sensor?

Ich verwende den Magnetometer-IC MLX90393 von Melexis. Genauer gesagt verwende ich das Breakout Board von Sparkfun . Ich bin noch ein Programmieranfänger und versuche zum ersten Mal, Daten über I2C auszulesen. Ich habe darauf geachtet, langsam voranzukommen (beginnend mit dem Umschalten von LEDs, dann dem Schreiben auf LCDs usw.) und möchte mich jetzt an der Wahrnehmung versuchen. Damit tue ich mich allerdings wirklich schwer. Ich habe das I2C-Protokoll viele Male gelesen, um zu versuchen, mich damit zurechtzufinden, und ich glaube, ich beginne damit.

Ich verwende ein STM32F303K8 Nucleo-Board, um mit dem IC zu kommunizieren. Ich verwende ein standardmäßiges serielles 16x2-LDC, um Informationen anzuzeigen. Die IDE, die ich verwende, ist mbed (es ist kostenlos und ich habe es schon einmal verwendet, und es ist nicht kompliziert und erfordert nichts anderes als einen PC, ein Nucleo-Board und ein USB-Kabel)

Im Moment möchte ich nur die Daten lesen können. Ich habe auf der mbed-Website nach Beispielcodes für den Anfang gesucht und keine gefunden. Ich kann nicht einmal eine Bibliothek finden, obwohl ihre Kurzanleitung (kann keinen Link finden, es lädt nur automatisch ein PDF herunter) behauptet, dass es eine auf der mbed-Site gibt. Ich konnte 2 an anderer Stelle finden, eine HIER von GitHub und eine HIER für ESP32. Das Problem ist, dass dies beide Beispiele für die Verwendung unterschiedlicher Geräte sind. Der ESP32 ist für den Arduino geschrieben, und ich möchte nicht für immer mit Arduino stecken bleiben, also würde ich das lieber nicht verwenden. Ich habe versucht, es für die Verwendung mit mbed zu konvertieren, aber offensichtlich war ich nicht erfolgreich. Ich habe das gleiche mit dem GitHub-Code versucht, war aber auch damit erfolglos.

Beim Durchgehen dieser beiden Beispiele habe ich versucht, sie zu entschlüsseln und für die Verwendung in mbed zu konvertieren, und bin auf den folgenden Code gekommen:

CODE AUF AKTUELLE VERSION AKTUALISIERT.

#include "mbed.h"

int addr = 0x0C <<1; // 8bit I2C address

I2C i2c(PB_7 , PB_6);   //sda, scl

Serial pc(PA_9, PA_10); //Tx/Rx

int main()
{
    char config [4];
    char data[7] = {0};

    config[0] = 0x60;
    config[1] = 0x00;
    config[2] = 0x5C;
    config[3] = 0x00;

    i2c.write(addr, config, 4, false);

    i2c.read(addr, data, 1);

    config[0] = 0x60;
    config[1] = 0x02;
    config[2] = 0xB4;
    config[3] = 0x02;

    i2c.write(addr, config, 4, false);

    i2c.read(addr, data, 1);

    wait(0.25);

    while (1) {

        config[0] = 0x3E; // Single measurement mode, ZYX enabled

        i2c.write(addr, config, 1, false);
        i2c.read(addr, data, 1);

        wait(0.1);

        config[0] = 0x4E;

        i2c.write(addr, config, 1, false); // Read command, followed by ZYX bits set
        i2c.read(addr, data, 7); 

        if(i2c.read(addr, data, 7) == !7) {
            printf("ERROR \n");
        } else {
            int xMag = i2c.read(data[1] * 256 + data[2]);
            int yMag = i2c.read(data[3] * 256 + data[4]);
            int zMag = i2c.read(data[5] * 256 + data[6]);

            printf("X Axis = %d \n", xMag);
            printf("Y Axis = %d \n", yMag);
            printf("Z Axis = %d \n", zMag);
        }
        wait(5);
    }
}

Ich habe den Arduino-Code auf der STM32-Hardware ausgeführt und es geschafft, die Daten auf einem seriellen Monitor anzuzeigen. Wenn ich meinen Code ausführe, bekomme ich -1 auf allen 3 Achsen gelesen.

Ich habe die Datenzeilen erfasst und kann bestätigen, dass die SDA- und SCL-Zeilen mit denen des funktionierenden Arduino-Codes übereinstimmen, sodass der Großteil davon funktioniert. Es scheint, dass ich die Daten falsch entziffere oder falsch zeige. Einer dieser 2 als serieller Monitor zeigt das Falsche an. Das heißt, bis hierhin ist alles richtig:

if(i2c.read(addr, data, 7) == !7) {
                printf("ERROR \n");
            } else {
                int xMag = i2c.read(data[1] * 256 + data[2]);
                int yMag = i2c.read(data[3] * 256 + data[4]);
                int zMag = i2c.read(data[5] * 256 + data[6]);

                printf("X Axis = %d \n", xMag);
                printf("Y Axis = %d \n", yMag);
                printf("Z Axis = %d \n", zMag);
            }

Dieses Bit scheint nicht das zu tun, was es sollte. Alles andere funktioniert wie es sollte, die richtigen Register werden gelesen und beschrieben und die Daten werden zurückgesendet. Ich habe dies bestätigt, indem ich die Signale mit der Arduino-Codeversion verglichen habe, die funktioniert .

Bevor Sie fragen „Können Sie dieses Bit erfassen“ oder „Können Sie das messen“, lesen Sie bitte die vollständigen Chatprotokolle HIER und HIER , die alles zeigen, was ich bisher getan habe, um bis zu diesem Punkt zu gelangen.

Ich muss nur wissen, wie ich das letzte Bit zum Laufen bekomme, um die Informationen korrekt anzuzeigen.

Kommentare sind nicht für längere Diskussionen gedacht; Diese Konversation wurde in den Chat verschoben .
Bitte geben Sie Ihre Hardware-Verkabelung und Ihren Schaltplan ein
@MKS die Verkabelung ist nicht das Problem. Lies die Frage. Die gleiche Hardware funktionierte gut, wenn die Arduino-IDE verwendet wurde, es wurde der mbed-Code verwendet, um es zum Laufen zu bringen, was nicht funktionierte. Der Grund, warum ich die Arduino-Sprache und IDE verwendet habe, war, dies zu überprüfen. Sie können STM-Nucleo-Boards mit Arduino verwenden, wenn Sie einige Dateien in die Arduino-IDE importieren. Das habe ich getan, um es zu verifizieren. Bitte lesen Sie die ganze Frage gründlich durch
Setzen Sie einen Bereich auf die I2C-Uhr und die Datenleitungen, um einen Hinweis darauf zu erhalten, was Ihr Code tut.
@EE_social Da es mein erstes Mal mit I2C ist, bin ich mir nicht 100% sicher, was richtig ist. Ich habe es untersucht und gesehen, wie die SDA- und SCL-Linien Sachen gemacht haben, ob es richtig war oder nicht, ist eine andere Geschichte! Kannst du etwas an der Codeübersetzung falsch sehen?
Können Sie eine Bereichserfassung von SCL, SDA posten?
@EE_socal Wenn Sie die Chat-Seite zu meiner anderen Frage überprüfen möchten, gibt es eine Diskussion, die dies ebenfalls betrifft, können Sie sich gerne anschließen
Dort habe ich viel mehr Informationen, es ist ein ähnliches Thema, konzentriert sich jedoch auf den i2c-Scannercode, der wahrscheinlich Hinweise enthält, wie dies zu beantworten ist. Ich habe dort auch Oszilloskop-Messwerte, serielle Monitor-Messwerte und andere solche Dinge
Hi, ein Punkt, der mir gerade aufgefallen ist (und ich werde ihn hier kommentieren, anstatt ihn nur im Chatprotokoll zu belassen), betrifft die I2C-Adresse des Sensors. Seine standardmäßige 7-Bit-I2C-Adresse ist 0x0C. Das bedeutet, dass seine 8-Bit-Adresse 0x0C << 1 = 0x18 ist. Das bedeutet, dass die Quellcodezeile: const int addr = 0x0C; // 8bit I2C addressfalsch ist, da die Variable addrdirekt in I2C-Funktionsaufrufen (mehrere) wie übergeben wird. Wie i2c.write(addr, config, 4);wir aus dem Chat wissen, kann es jedoch andere Probleme geben (z Diese Adresse richtig zu bekommen, wird Teil jeder Lösung sein :-)
@SamGibson Ich bin mir sicher, dass ich das irgendwann versucht habe ... Aber ich kann mich nicht erinnern, wie es gelaufen ist! Ich werde es morgen noch einmal versuchen, aber ich bin mir sicher, dass ich irgendwo gelesen habe, dass Sie ihm die 0x0C-Adresse geben können ... Ich könnte mich aber irren. Danke dafür, ich berichte morgen, wenn ich es ausprobiert habe!
@Curious - Vielleicht war das vor dem Entfernen der Lötbrücken? Ich vermute, du hattest mehrere Probleme. Diese (absichtlichen) Lötbrücken auf dem Nucleo sind mit Pins verbunden, die die mbed-Software nicht deaktiviert hat, was zu diesem komischen 2-V-Pegel führt. Dann ist da noch die aktuelle Sorge um die mbed I2C-Aufrufe (noch in Diskussion). Dann ist da noch die Adresse (mit dem Sparkfun-Tippfehler!). Beachten Sie, wie der Code in dieser Frage den Wert von addrdirekt übergibt. Das heißt addrmuss 0x18 sein. Alternativ könnten Sie addr << 1in den Aufrufen auch 0x0C verwenden und müssen i2c.write()dann 0x0C sein. addrFang dich morgen.
@SamGibson ja, das wäre es gewesen, bevor die Lötverbindungen entfernt wurden! Guter Punkt. Ich lasse Sie wissen, wie ich vorankomme.
@SamGibson Nun, ich habe es versucht .... Ich bekomme immer noch einen Fehler bei den Messwerten :( Wahrscheinlich ein bisschen mehr dazu! Schätze, wir sehen uns dann wieder im Chat bei der anderen Frage!

Antworten (2)

In Zusammenarbeit mit dem OP und aufbauend auf der Untersuchung, die in meiner Antwort auf diese verwandte Frage " I2C-Scanner funktioniert nicht richtig " erklärt wurde, mussten zuerst dieselben zwei Probleme behoben werden:

  • Entlöten Sie die Lötbrücken SB16 und SB18 der STM32F303K8 Nucleo-32 (NUCLEO-F303K8) Platine, wenn Sie Mbed I2C-Funktionen verwenden.
  • Verwenden Sie den "erweiterten" Mbed-Aufruf mit 4 Parametern i2c.write()mit dem STM32F303K8 Nucleo-32-Board.

Wie in einer anderen Antwort erwähnt, wäre ein Logikanalysator in dieser Situation hilfreich (und sollte nach Möglichkeit verwendet werden). Die folgenden Probleme wurden innerhalb der begrenzten verfügbaren Zeit ohne Verwendung eines gefunden und behoben:

  • Die korrekte 7-Bit-I2C-Adresse des Sensors ist 0x0C, aber die Mbed-I2C-Aufrufe wollen die 8-Bit-Version.

    Frühere Versionen des Codes wurden durch einen Druckfehler in den SparkFun-Dokumenten für ihr Breakout-Board mit diesem Sensor in die Irre geführt, wo sie sagten, die Adresse sei 0xC0.

    Einige Codeversionen haben diesen I2C-Adresswert auch nicht nach links verschoben, aber die Mbed-I2C-Funktionen möchten, dass die Adresse als 8-Bit-Version an sie übergeben wird (z. B. 0x18 in diesem Fall). 0x0C << 1Die Lösung bestand also darin, es entweder als oder 0x18(dasselbe) an die Mbed I2C-Aufrufe weiterzugeben .

  • Wie in dieser anderen verknüpften Frage erwähnt, ist der I2C-Zugriff mit diesem STM32F303K8 Nucleo-Board nur erfolgreich, wenn das Mbed i2c.write()und i2c.read()die Funktionen mit (bis zu) 4 Parametern (3 erforderlich, 4. optional) verwendet werden und nicht stattdessen die einzelnen Parameter i2c.write()und Aufrufe der unteren Ebene verwendet werden i2c.read().

  • An diesem Punkt konnte das OP beim Vergleich der I2C-Busaktivität im Umfang zwischen dem Arduino-Code und dem Mbed-Code erkennen, dass die I2C-Busaktivität jetzt identisch war, bis zu dem Punkt, an dem die Messung durch den Sensor ausgelöst wurde. Damit blieb das letzte Problem beim Auslesen und Anzeigen der Werte vom Sensor im Mbed-Code.

    Als ich in diesen Teil des Codes schaute, entfernte ich den Teil, der mehrmals vom Sensor gelesen wurde, und suchte nach einem falschen Rückgabecode. Daher habe ich einen Teil des ursprünglichen Codes geändert von:

config[0] = 0x4E;

i2c.write(addr, config, 1, false); // Read command, followed by ZYX bits set
i2c.read(addr, data, 7); 

if(i2c.read(addr, data, 7) == !7) {
printf("ERROR \n"); 
} else { 
int xMag = i2c.read(data[1] * 256 + data[2]); 
int yMag = i2c.read(data[3] * 256 + data[4]); 
int zMag = i2c.read(data[5] * 256 + data[6]); 

printf("X Axis = %d \n", xMag); 
printf("Y Axis = %d \n", yMag); 
printf("Z Axis = %d \n", zMag); 
}

Zu

config[0] = 0x4E; 

i2c.write(addr, config, 1, false); // Read command, followed by ZYX bits set 
i2c.read(addr, data, 7); 

int xMag = ((data[1] * 256) + data[2]); 
int yMag = ((data[3] * 256) + data[4]); 
int zMag = ((data[5] * 256) + data[6]); 

printf("X Axis = %d \n", xMag); 
printf("Y Axis = %d \n", yMag); 
printf("Z Axis = %d \n", zMag);

Die vollständige Version des Arbeitscodes lautet also:

#include "mbed.h" 

int addr = 0x0C <<1; // 8bit I2C address 

I2C i2c(PB_9 , PB_8); //sda, scl 

Serial pc(PA_2, PA_3); //Tx/Rx 

int main() 
{ 
char config [4]; 
char data[7] = {0}; 

config[0] = 0x60; 
config[1] = 0x00; 
config[2] = 0x5C; 
config[3] = 0x00; 

i2c.write(addr, config, 4, false); 

i2c.read(addr, data, 1); 

config[0] = 0x60; 
config[1] = 0x02; 
config[2] = 0xB4; 
config[3] = 0x02; 

i2c.write(addr, config, 4, false); 

i2c.read(addr, data, 1); 

wait(0.25); 

while (1) { 

config[0] = 0x3E; // Single measurement mode, ZYX enabled 

i2c.write(addr, config, 1, false); 
i2c.read(addr, data, 1); 

wait(0.1); 

config[0] = 0x4E; 

i2c.write(addr, config, 1, false); // Read command, followed by ZYX bits set 
i2c.read(addr, data, 7); 

int xMag = ((data[1] * 256) + data[2]); 
int yMag = ((data[3] * 256) + data[4]); 
int zMag = ((data[5] * 256) + data[6]); 

printf("X Axis = %d \n", xMag); 
printf("Y Axis = %d \n", yMag); 
printf("Z Axis = %d \n", zMag); 

wait(5); 
} 
}

Mit diesem Mbed-Code erzeugt der Sensor eine korrekte Ausgabe, ähnlich wie der funktionierende Arduino-Code, und der Punkt der Frage war, zu diesem Stadium zu gelangen. Der Code kann dann als Ausgangspunkt verwendet und mit Fehlerprüfung und Statusberichten usw. verbessert werden.

Auch hier können weitere Untersuchungen des I2C-Verhaltens der Mbed-Bibliotheken und des Sensors mit einem Logikanalysator durchgeführt werden, wenn ein Analysator (und mehr Zeit) verfügbar ist.

Anstatt zu raten und willkürlich krampfhafte Änderungen an Ihrem Code vorzunehmen, sollten Sie sich einen billigen ($ 7) Logikanalysator von eBay besorgen, für den Sie kostenlose Software und I2C-Decoder herunterladen und I2C-Traces von Ihrem Hardwarebus erhalten.

Geben Sie hier die Bildbeschreibung ein

Sie sehen sofort, ob Ihre Adresse korrekt ist oder nicht und wie das Gerät reagiert (oder nicht).

Viele teurere digitale Allzweck-Oszilloskope haben heutzutage I2C-Decoder, aber das 7-Dollar-Gerät macht seine Arbeit gut.

Sie beginnen mit eingebettetem Design, was bedeutet, Hardware-Signalisierung zu erzeugen. Die Verwendung von Hardware-Tools zur Untersuchung der resultierenden Signale ist ein Muss. Dies sollte Ihr Ausgangspunkt sein, alles andere ist zweitrangig. Wenn Sie einige Minuten lang in die erfasste Spur schauen, sparen Sie Tage des "Random Engineering".

Danke für die Antwort. Ich kann in so etwas investieren. Am Ende gab es mehrere Probleme damit, aber ich habe es geschafft, einen I2C-Scanner auszuführen, um schließlich die richtige Adresse zu erhalten, und ich habe alle Signale hin und her geprüft und sie mit den Arduino-Signalen (die funktioniert haben) verglichen, um schließlich dazu zu gelangen Punkt. Es war nicht gerade alles Rätselraten und zufällige Änderungen am Code. Wenn Sie die Chat-Protokolle gelesen hätten, hätten Sie gesehen, dass ziemlich viel Aufwand in die Fehlersuche gesteckt wurde. Nicht nur Vermutungen
@Curious, ja, Sie haben sich große Mühe gegeben, den Code zu portieren und zu debuggen. Mein Punkt ist, dass ein einfacher Zweidraht-I2C-Logikanalysator, der sofort decodierte Pakete und alle damit verbundenen Fehler (fehlende Start-Stopps, ACKs/NAKs) anzeigt, Ihren Debug-Aufwand um Größenordnungen reduzieren würde.
Ja angenommen. Es hätte auch geholfen, eine IDE mit Haltepunkten zu haben. Mbed ist zum Debuggen ziemlich nutzlos. Am Ende habe ich alle Bytes durchgesehen, die an und von gesendet wurden, um ACK- und NACK-Symbole zu finden, zu überprüfen, welche Adressen auf einem Oszilloskop geschrieben / gelesen wurden usw. Ich stimme zu, einer davon wäre eine gute Investition, also +1 für diesen Vorschlag