(03.06.2016 12:15 )sisc schrieb: In meinem Programm (siehe Anhang MCP2221.vi) funktionieren folgende Funktionen: "open" und "set speed"; zumindest erhalte ich dabei keine Fehlermeldungen.
Mir ist nicht ganz klar, welche Informationen die Funktion "Write" benötigt. Insbesondere ist mir nicht klar, welche Angaben und in welchem Format
"i2ctxdata" gefüttert werden sollte. Zudem sehe ich vor, einen Pointer Slide für die Steuerung der LED Lichtintensität (in diesem Beispiel GRÜN) zu nutzen.
Ich habe versucht, das Feld mit den volatile und non-volatile Angaben des Gerätebauers (siehe settings.pdf) mittels string array einzubinden, doch eine
Verbindung des string arrays mit "write" ist nicht möglich. Dürfte ich die Frage in die Runde werfen, wie ich den Bereich "write" gestalten müsste; insbesondere welche Informationen das Feld "i2ctxdata" benötigt? Besten Dank im Voraus! sisc
Erst einmal, die MCP Library had einen Bug!! Das handle, das alle Funktionen verbindet ist ein Pointer, kein unsigned int. Für 32 bit LabVIEW würde das zwar kein Problem sein, denn dort ist sizeof(int32_t) == sizeof(void*). In 64 bit LabVIEW ist aber sizeof(void*) == sizeof(int64_t).
Also müssen alle Call Library Nodes umkonfiguriert werden, wobei dieser Parameter jeweils statt eines 32 Bit Integers in einen Pointersized Integer verändert werden muss und alle LabVIEW-Kontrolls für die Handles müssen als 64 Bit Integer ausgeführt sein.
Zudem hat der, der diese Library generiert hat sich wieder mal voll auf den Import Library Wizard verlassen und danach gar nichts mehr daran gemacht. Es wäre sinnvoll um das Interface zu überarbeiten und einige Dinge zu vereinfachen.
Beispielsweise führt die Write Funktion völlig unnötig den Parameter bytesToWrite heraus. Da würde man besser aus der i2cTxData die Länge bestimmen und diesem Parameter diesen Wert übergeben. Zudem ist es ziemlich unsinnig um diesen Writebuffer wieder aus der Funktion herauszuführen.
Das sähe dann so aus:
Und eigentlich geht es hier um binäre Daten. C kennt keinen eigenen Datentyp für Strings. char ist typischerweise ein Byte (das ist von C nicht strikt vorgegeben obwohl das für alle bekannten gegenwärtigen C Compiler so ist, aber C lässt ausdrücklich zu, dass ein char jede für die CPU sinnvolle Grösse haben darf und es gab in der Vergangenheit CPUs die 9 bits pro Dateneinheit besassen und ein C Compiler benützte dann auch 9 bits für einen char).
Ein Byte-Array ist deshalb ein Array of chars, und da ein ANSI Character in 8 bits passt wird auch ein ANSI-String als Byte-Array implementiert.
Da in diesem Fall binäre Daten über I2C verschickt werden und eigentlich nie Strings, wäre es deshalb sinnvoller um auch an der LabVIEW Seite ein Array of Unsigned 8 bit Integers zu verwenden. Damit würde auch der Fehler den Du hier begangen hast weniger schnell passieren.
Was das Device will sind zwei Bytes mit den Werten 0x70 und 0xFF. Was Du zu verschicken versuchst ist der String "70 FF" und das ist in ASCII Codierung 5 Bytes mit den Werten 0x37, 0x30, 0x20, 0x46, 0x46. Und um es alles noch viel schlimmer zu machen, sagst Du der Funktion, dass sie 8 Bytes verschicken soll, gibst ihr aber nur 5 und dann werden da halt einfach 3 zufällige Werte aus dem Speicher mitgeschikt, die direkt hinter dem Buffer den der String belegt im Speicher liegen.
Dann kommt die Read Funktion! Ein klarer Fall von blind das vom Import Library Wizard erzeugte VI benützen. Die Funktion probiert soviele Bytes in den Readbuffer zu kopieren wie man ihr in bytesToRead sagt. Zwar ist die Call Library Funktion so konfiguriert dass Sie einen Buffer von 8192!!!!!! Bytes reserviert. Das verhindert zwar dass es eine Exception wegen Speicherverletzung geben kann, ist aber für eine Funktion wie I2C wo man maximal 255 Bytes lesen kann ziemlich extremer Overkill. Zudem scannt LabVIEW für Strings die als C Strings an eine DLL übergeben werden nach der Ausführung dieser Funktion den Stringbuffer nach einem NULL Byte und schneidet dort den String ab. Da I2C aber binäre Daten hat, ist es sehr gut möglich dass da NULL Bytes zurückkommen und dass auch dahinter noch gültige Bytes im Buffer sind. Durch diesen Parameter als Bytearray zu behandeln wird diese NULL Byte Termination nicht vorgenommen.
Ich hätte die so implementiert:
Und dann muss man natürlich das Datensheet gut lesen. Dort steht scheinbar, dass das erste Byte die Led adressiert, wobei man da nonvolatile und volatile wählen kann. nonvolatile bedeutet dass es im Speicher abgespeichert wird der auch bei ausgeschaltetem Strom seine Daten behält und wahrscheinlich wird dann beim wieder Einschalten dieser Wert gelesen und verwendet bis ein anderer programmiert wird. volatile ist flüchtiger Speicher, das heisst was man dort hineinschreibt beeinflusst zwar die Led direkt aber ist nach Abschalten der Speisung vergessen. Du musst also abhängig von der Farbe der Led deinen Schieberwert zwischen 0 und 100 in einen Bytewert für das 2te Byte skalieren. Also für die rote Led zum Beispiel 0% =~ 0x70 und 100% = 0xFF. Das ist dann nur annähernd korrekt da aus der Tabelle eindeutig ersichtlich ist dass die Skalierung nicht linear ist. Du könntest hier ein Polynomfit machen und mittels eines entsprechenden Poynoms, zweiter oder dritter Ordnung eine besser übereinstimmung erreichen, aber ich denke mal dass das etwas Overkill sein könnte.