INA 219 - Strommessung

achim S.

Mitglied
16. Jan. 2010
704
13
18
Berlin Biesdorf
Sprachen
  1. ANSI C
Hallo Gemeinde
Bin gerade dabei eine Strommesung mit dem INA219 aufzubauen. Das Modul für mein System ist fertig und möchte in Betrieb gehen. Das Datenblatt aheb ich schon "studiert". Leider gibt es zahlreche Probleme damit. So z.B. das einstellen der Register, welches Register für was, auslesen der 16 Bit Werte, Kalibrierung usw.
Kennt jemand ein gutes Tut dazu oder Anleitung. Vielleicht auch ein kleines Beispiel in C (nicht Arduino) zum testen und lernen. Bin für jede Hilfe dankbar.

achim
 
Hmm...
bisher hat Dir keiner helfen können - ich selbst kenne den IC nicht.
Was hat Dich denn bewogen, Dich mit genau diesem zu beschäftigen?

Von null(!) anfangend wären meine(!) ersten Schritte:
  • Kommunikation via I²C - antwortet der IC mit einem ACK auf seine Adresse?
  • Auslesen des Configuration Registers (Adresse 0x00). Sollte nach dem PowerUp 0x0399 sein
  • Mode auf Bus Voltage Continous setzen
  • Bus Voltage Register (wiederholt) lesen (Ergebnis ausgeben lassen)
Welche Erfolge konntest Du denn bereits erzielen?
Anmerkungen:
  • der IC besitzt 6 (16bit-)Register (Configuration, Ushunt, Ubus, Pshunt, Ishunt, Calibration)
  • der Schreib-/Lesepointer inkrementiert nicht - einmal gesetzt sollte(!!) sich auf dasselbe Register also wiederholt zugreifen lassen.
  • (welchen Wert dieser Pointer nach dem PowerUp besitzt, ist mir(!) nicht klar (habs nicht gefunden) - im Zweifelsfall also immer erstmal schreiben.
  • Beschreiben kannst Du eines (der beiden beschreibbaren) Register in einem Rutsch (also SLA+W, Register-Adresse, DataMSB, DataLSB) - beim Lesen kann nur das, durch den Pointer referenzierte Register gelesen werden (mit SLA+R, DataMSB, DataLSB)
  • nach dem Schreiben eines Registers benötigt der IC 4µs, um die Werte zu übernehmen.
Wenn bis hier die generelle Kommunikation klar ist, kann man sich mit den Einstellungen im Configurations- und Calibrationsregister auseinandersetzen...
 
Zuletzt bearbeitet:
Hallo
Danke für eure Antworten.
In Arduino Kreisen soll dieser IC sehr weit verbreitet sein. Vom Hersteller gibt es auch ein Demo dazu. Im gesamten Netz beziehen sich alle darauf. Es gibt aber so gut wie keine Erklärung oder so was dazu. Du hast das Datenblatt gut zitiert. Am meisten gefällt mir an diesem IC das er einen so weiten Bereich (relativ) hat. Vom Aufbau und Anwendung passt er sehr gut in mein System. Damit kann ich dann endlich messen warum manche Module an der Grenze arbeiten. Ist mir schon klar das 256 LEDs einiges an Strom brauchen. Aber wieviel zieht ein 3,2 Zoll TFT Farb Display? Das weiteren sind die Register. Möchte lernen damit zu arbeiten und die 16 Bit Wörter zu lesen und zu verarbeiten. Ist allerdings ein recht grosser Umfang.
Der eigentliche Aufbau des ICs ist für Baster schwer zu händeln, da kam mir der Aufbau des Hersteller ganz recht.
- Die Hardware ist komplett aufgebaut und läuft korrekt
- Der IC kann mit einem Bus Scanner die Adresse ausgelesen werden
- der I2C läuft also ohne Probleme. Benutze die Dateien von Peter die sich seht bewährt haben
Leider funktioniert das setzen der Register nicht und es kommen keine Werte zurück.
Habe einen Artikel aus dem englischen gefunden, der die komplette Berechnung erläutert. Ist sehr gut beschrieben. Kenne keinen anderen IC (in dieser Art) der eine Kalibrierung zulässt.
Habe mir die Dateien von Henry runter geladen und werde sie auseinander nehmen. das Problem liegt auch in diesen Dateien. Sind in C++ geschrieben und der Rückbau auf nur C fällt mir halt schwer.
Wieder bin ich bei der Kalibrierung. Habe nichts in den Dateien dazu gefunden (übersehen?)
Daher bin ich sehr dankbar für jede Hilfe dazu

achim
 
hmmm...glaube nicht, das es schwierig werden könnte.
schau dir einfach die werte an, die diese lib in die Register reinschiebt.
integer etc bleiben gleich, da solltest du drauf abheben.
wo werden die variabeln mit welchen werten versehen und wo werden diese hingeschoben?
73 de addi
 
- Der IC kann mit einem Bus Scanner die Adresse ausgelesen werden
- der I2C läuft also ohne Probleme. Benutze die Dateien von Peter die sich seht bewährt haben
Leider funktioniert das setzen der Register nicht und es kommen keine Werte zurück.
Damit bist Du Dir bezüglich der Hardware und der Adresse sicher. Wäre also zu klären, warum Du mit der Bibliothek nicht hinkommst.
Wie gesagt - mein(!) nächster Schritt wäre, erstmal das Konfigurationsregister lesen zu lassen, und zwar mit der final zu verwendenden Leseroutine. Wenn möglich unter Verwendung eines Logicanalyzers.
Zum auslesen mußtest Du übertragen lassen:
Startcondition
SLA+W
0x00
Stopcondition

Um den Pointer auf das Konfigurationsregister zu setzen, dann mindestens 4µs warten, und dann übertragen lassen:
Start
SLA+R
8 Clock-Strobes
8 Clock-Strobes
Stop

Also die Strobes als ein Byte lesen.

Für Euch C-ler mag es natürlich sinniger sein, 'ne vorhandene, funktionierende(!) Bibliothek "auseinanderzunehmen" - ich könnte mich nur bemühen(!), das mithilfe des Datenblattes komplett selbst zu erarbeiten...
In C oder Arduinesisch arbeite ich mich nicht ein...;)
 
welchen Wert dieser Pointer nach dem PowerUp besitzt, ist mir(!) nicht klar (habs nicht gefunden) - im Zweifelsfall also immer erstmal schreiben.
Seite 16, Figure 15 & 16. Es muß immer zuerst geschrieben werden.
(2) Read data is from the last register pointer location. If a new register is desired, the register
pointer must be updated. See Figure 19
(Welchen Bezug das jetzt zu Figure 19 hat ist mit nicht klar)

Die Register 1 bis 4 können nur gelesen werden, also muß man wohl nach schreiben der Adresse und des Registerpointers einen Repeated-Start ausführen um dann das jeweilige Register zu lesen.
mindestens 4µs warten
Das ist wohl nur bei höheren Übertragungsraten relevant, bei 100 kHz dauert ein Bit ja schon 10µs.
(Edit: Steht ja auch im Datenblatt: when using SCL frequencies in excess of 1 MHz)

Es empfiehlt sich, nach der Initialisierung zuerst das Bus Voltage Register (02) zu lesen, weil es das Conversion Ready Bit enthält.
 
Seite 16, Figure 15 & 16. Es muß immer zuerst geschrieben werden.
(2) Read data is from the last register pointer location. If a new register is desired, the register
pointer must be updated. See Figure 19
Und nochmal genauer:
If repeated reads from the same register are desired, it is not necessary to continually send the register pointer bytes; the INA219 retains the register pointer value until it is changed by the next write operation.
Beim Schreiben (SLA+W) ist das erste gesendete Byte (nach SLA+W) immer der (neue) Pointer; ein eventuell folgendes Word wird in das damit referenzierte Register geschrieben.
Beim Lesen hingegen wird sofort nach dem SLA+R gelesen, und zwar das Register, wo der Pointer grad hinzeigt. Soll ein anderes Register gelesen werden, muß vorher der Pointer umgeschrieben werden, sonst kannst Du aber das Register beliebig oft lesen (ohne den jedesmal Pointer neu zu schreiben).
Der Pointer besitzt wie gesagt kein Autoinkrement/-dekrement.
Streng nach dem Datenblatt muß also der Pointer vor dem ersten Lesen beschrieben werden - aber irgendwohin sollte der Pointer ja nach dem Powerup zeigen. Möglicherweise auf irgendwas zufälliges, möglicherweise 0x00. Mich würde übrigens nicht wundern, wenn da sogar nur die minderwertigsten drei Bit relevant sind.
Welchen Bezug das jetzt zu Figure 19 hat ist mit nicht klar
Ich denke, daß damit
Figure 18. Typical Register Pointer Set
gemeint ist...
Die Register 1 bis 4 können nur gelesen werden, also muß man wohl nach schreiben der Adresse und des Registerpointers einen Repeated-Start ausführen um dann das jeweilige Register zu lesen.
Jedes Register kannst Du lesen, indem Du erst den Pointer auf die Adresse setzt (Start, SLA+W, Adresse, Stop) und danach das Register liest (Start, SLA+R, Readbyte, Readbyte, Stop).
Zum repeatet Start gibt es keine Figure, aber auf Seite 14/15 findet sich:
When reading from the INA219, the last value stored in the register pointer by a write operation determines which register is read during a read operation. To change the register pointer for a read operation, a new value must be written to the register pointer. This write is accomplished by issuing a slave address byte with the R/W bit LOW, followed by the register pointer byte. No additional data are required. The master then generates a START condition and sends the slave address byte with the R/W bit HIGH to initiate the read command. The next byte is transmitted by the slave and is the most significant byte of the register indicated by the register pointer. This byte is followed by an Acknowledge from the master; then the slave transmits the least significant byte.
Den Start nach dem Pointer schreiben könnte man auch als repeated start verstehen - Stops werden ja leider nicht weiter erwähnt. Möglicherweise muß aber vor dem Start wirklich'n Stop kommen, also zwei Telegramme...
Benutze die Dateien von Peter die sich seht bewährt haben
Leider funktioniert das setzen der Register nicht und es kommen keine Werte zurück.

Zu den 4µs: achim hat nicht geschrieben wie schnell er unterwegs ist. Die Länge der Pause soll mindestens 4µs betragen. Wenn die bereits durch das Protokoll gesichert sind, klar. Aber grundsätzlich stört 'ne längere Pause nicht, und achim will erstmal überhaupt was lesen...
(wobei das eh nur die Übernahme der gesendeten Werte in die beschreibbaren Register betrifft.)
Wenn das Konfigurationsregister erfolgreich ausgelesen werden konnte, würde ich als nächstes das Kalibrationsregister lesen (0x00 wäre zu erwarten), anschließend mit irgend'nem anderen Wert beschreiben, und diesen dann zurücklesen lassen...
 
irgendwohin sollte der Pointer ja nach dem Powerup zeigen. Möglicherweise auf irgendwas zufälliges, möglicherweise 0x00.
Spielt im Prinzip keine Rolle. Um irgendwas sinnvolles mit dem Teil anzufangen (es interessieren üblicherweise wenigstens der Strom und oft auch noch die Leistung), müssen eh zuerst das Calibrationregister und meistens auch noch das Configurationregister beschrieben werden.

Das mit Figure 19 ist wohl ein Druckfehler. Auf Seite 14 steht schon:
Accessing a particular register on the INA219 is accomplished by writing the appropriate value to the register pointer. Refer to Table 2 for a complete list of registers and corresponding addresses. The value for the register pointer as shown in Figure 18 is the first byte transferred after the slave address byte with the R/W bit LOW. Every write operation to the INA219 requires a value for the register pointer
Den Start nach dem Pointer schreiben könnte man auch als repeated start verstehen - Stops werden ja leider nicht weiter erwähnt. Möglicherweise muß aber vor dem Start wirklich'n Stop kommen, also zwei Telegramme...
In Figure 18 wird nach dem Registerpointer ein Stop gesendet. Wird wohl beides gehen. Wenn kein Stop gesendet wird, wird Start als Repeated Start angesehen und anschließend wird sowieso die Adresse mit R-Bit (R/W = high) gesendet und dann werden die beiden zu lesenden Bytes empfangen.
Zu den 4µs: achim hat nicht geschrieben wie schnell er unterwegs ist.
Nein, aber vermutlich nicht mit mehr als 1MHz. Denn dazu müßte er erstmal in den High-Speed-Mode umgeschaltet haben. ;)
8.5.6.1 High-Speed I2C Mode

When the bus is idle, both the SDA and SCL lines are pulled high by the pull-up devices. The master generates a start condition followed by a valid serial byte containing high-speed (HS) master code 00001XXX . This transmission is made in fast (400 kbps) or standard (100 kbps) (F/S) mode at no more than 400 kbps. The INA219 does not acknowledge the HS master code, but does recognize it and switches its internal filters to support 2.56 Mbps operation.
The master then generates a repeated start condition (a repeated start condition has the same timing as the start condition). … Instead of using a stop condition, repeated start conditions should be used to secure the bus in HS-mode. A stop condition ends the HS-mode…
 
Haloo an alle
Erst mal die gute Nachricht, das Teil mit INA219 läuft ohne Probleme. Kann bereits den Strom (über Shunt) und die Spannung auslesen. Eine vergleichende Messung aber ergeben das es Abweichungen von bis zu 20% gibt. Die Messung der Leistung ist nicht möglich bzw. bringt immer eine 0. Im Teil 8.6 in der Tabelöle ich unter 2 angebeben das erst die Grösse des Shunts eingegeben werden muss. Es ist auch eine Formel angegeben (8.5.1). Das rechnen ist kein Problem. Doch wo muss das Ergebnis eingegeben werden. Das mit dem Auslesen der 16 Bit und das Berechnen klappt soweit. Mache es so:


CodeBox C
// Spannungsmessung
       i2c_start(adr_ina219);                   // Angabe Adresse
       i2c_write(0x02);                       // Register Spannung
       i2c_stop();
       i2c_start(adr_ina219 +1);               // Auslesen Adresse + 1
       msb_spannung = i2c_readAck();           //...speichere oberes Bit
       lsb_spannung = i2c_readNak();           //...speichere unteres Bit
       i2c_stop();
       spannung_wrd = (msb_spannung << 8 | lsb_spannung);  // Zusammensetzung von o. & u. Byte
       spannung_anz = spannung_wrd / 2;       // Wert Spannung / 2

ist zwar ein bisschen umständlich und geht auch einfacher. Kommt alles noch.
Doch wie und wo gebe ich das Ergebnis der Rechnung ein und wie mache ich das Kalibrieren? (Schreiben einer 16 Bit Zahl und Position im Register)

LG Achim
 
Doch wie und wo gebe ich das Ergebnis der Rechnung ein und wie mache ich das Kalibrieren? (Schreiben einer 16 Bit Zahl und Position im Register)
Wie genau meinst du das?
Du kannst dir doch eine Funktion schreiben, der übergibst du den "AD - Wert" und lässt entweder diese Funktion in einen "globalen Puffer" schreiben oder lässt dir dieses Ergebniss zurück liefern.

Meinst du den "kalibrations Ablauf" oder das errechnen der Offset Werte?
 
ein bisschen umständlich und geht auch einfacher. Kommt alles noch.
Eigentlich mußt Du doch bis hier gar nicht rechnen. Der Sensor liefert die Shunt-Spannung als binäre 16bit-Zahl. Negative Zahlen zusätzlich im Zweierkomplement. Das ist nichts anderes als ein vorzeichenbehafteter 16bit-Integer. (wobei das letzte Bit 10µV entspricht)

Die AVR arbeiten grundsätzlich mit 8 Bit. Ob ein Byte als vorzeichenloses Byte, vorzeichenbehaftetes Byte, ASCII, Teil eines Words, Integers, Strings, single,... ist, ist Sache der Verwendung. In einer Hochsprache weist Du der Variable deswegen einen Variablentypen zu, damit der Compiler(!) weiß, welche Instruktionen er verwenden soll.
Alles was keinem Byte entspricht, setzt der Compiler also aus (ggf mehreren) Byte(s) um/zusammen. Einen vorzeichenbehafteten 16bit-Integer (Int16 ? ) also aus zwei Bytes.

Du müßtest also nur einen 16bit-Integer allokieren, und dem oberem Byte das erste empfangene Byte zuweisen, dem Unteren das Zweite.

Du hast in etwa folgendes:
Du willst eine zweistellige Dezimalzahl von mir empfangen, und die in ein Heft schreiben (linke Seite Zehner, rechte Seite Einer). Ich kann Dir die Ziffern aber nur nacheinander schicken. Ich sende also 'ne "4" als Zehner. Du legst die Temporär ab. Ich sende 'ne "2". Du legst die temporär ab.
Jetzt rechnest Du 10*4+2=42 (meinetwegen schiebst Du die 4 auch eine Dezimalstelle nach links und addierst 2 -> 42). Dann läßt Du das in Dein Heft schreiben - dabei wird das wieder in Zehner und einer zerpflückt, der Zehner ("4") landet auf der linken, der Einer ("2") auf der rechten Seite...

Du könntest nach dem Empfang der "4" (Zehner) diese aber auch gleich auf die linke Seite (=high) schreiben, die "2" (Einer) auf die rechte (=low). Ohne zu rechnen.
 
Das Problem liegt in der Leistungsmessung. Strom und Spannung wird angezeigt. Später möchte ich auch die Register dazu einsttellen und den Messbereich einzuängen.
Nach dem Datenblatt wird das Register für die Leistungsmessung mit 0 vorbelegt. Dadurch kommt nur eine 0 bei der Abfrage raus. Im Datenblatt steht auch, das ich erst den R Shunt angeben muus und dazu steht eine Formel drin. Das Ergebnis muss in das Konfigurationsregister eingetragen werden. Unterschiedliche Bereich habe ich nach den Angaben gemacht. Beispiel

0000 00x1 1101 1111
16V, 40mV, 12 Bit, 8 Samples, Mode

0011 10x0 0110 1111
32V, 320mV, 9 Bit, 32 Samples, Mode

Dies Angaben muss ich ins Konfi Register schreiben. Wen ich mich nicht verlesen habe muss die Berechnung bzw. Angabe der Werte darauf berechnet werden. Wie übertrage ich diese Zahl ins Register 00?
Dann kommt noch die Berechnung des Cali.. Register

LG achim
 
@achim S.
Du musst also 2 Bytes ins Konfigurationsregister schreiben, richtig?

Du schreibst dir jetzt einfach eine Funktion die entweder jeweils 2 Bytes ( uint8_t ) oder ein Word ( uint16_t ).
Dann baust du dir entweder mit einem Makro oder co. ein Kommandowort.

Oder du benutzt eine Struktur.

Bsp.:



CodeBox C
typedef struct
{
uint8_t samples :1;
uint8_t mode :4;
usw.
}ina219_t;

typedef union
{
 ina219_t cnfg;
uint8_t all;
}ina219_u;

ina219_u ina219;

// Konfiguriere Mode
ina219.cnfg.mode = WAS_AUCH_IMMER

uint8_t writeCnfgReg( ina219_u *cmd )
{
// schreibe die Daten in das Register, I2C oder co.
i2c_write( cmd.all );
}
 
Dein Code ist leider in C++. Das klappt nicht bei mir. Hatte s jetzt so gemacht. Zeigt zwar keine Fehler, geht aber auch nicht.


CodeBox C
#define con_var 0x386F

i2c_start(adr_ina219);                   // Angabe Adresse
   i2c_write(0x00);                       // Register Spannung
   i2c_write(con_var >> 8);                       // Register Spannung
   i2c_write(con_var & 0xFF);                       // Register Spannung
   i2c_stop();

Da scheint was nicht zu stimmen

achim
 
Dein Code ist leider in C++. Das klappt nicht bei mir. Hatte s jetzt so gemacht. Zeigt zwar keine Fehler, geht aber auch nicht.
Das ist C und kein C++.

#define con_var 0x386F i2c_start(adr_ina219); // Angabe Adresse i2c_write(0x00); // Register Spannung i2c_write(con_var >> 8); // Register Spannung i2c_write(con_var & 0xFF); // Register Spannung i2c_stop();
Probiere lieber mal..



CodeBox C
   i2c_write( (con_var & 0xFF00) >> 8);                       // Register Spannung
   i2c_write( con_var & 0x00FF )


Habe es gerade getestet. So funktioniert es.


CodeBox C
typedef struct
{
   uint8_t samples :1;
   uint8_t mode :4;
}ina219_t;
typedef union
{
     ina219_t cnfg;
   uint8_t all;
}ina219_u;
ina219_u ina219;

uint8_t writeCnfgReg( ina219_u *cmd )
{
   printf("%d", cmd.all );
}
 
Bei diesem Code bekomme ich keine Fehlermedung



CodeBox C
i2c_write( (con_var & 0xFF00) >> 8);                       // Register Spannung
i2c_write( con_var & 0x00FF )

das andere Stück ist mir von der Funktion nicht klar. Du vrwendest hier union. Da muss ich es^rst mal das Buch befragen.
Habe das andere eingegeben. Hatte vorher nach DB studiert und die Zahle rausgesucht. Leider hat das in der Anzeige keinerlei änderung zur Folge. vollkommen unklar
Es soll ein 16 Bit wort übertragen werden auf das Register Null. Das 16 Bit Wort wird zerlegt in 2 x 8 Bit und nacheinadner übetragen.

achim
 
Kannst du denn nach einem POR folgenden Wert ermitteln "0x399F" ?
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)