INA226 teljesítmény mérő

Tartalom:

  • INA226 teljesítménymérő felépítése
  • Konfigurációs regiszter beállításai, üzemmódok
  • Beállítás és eredmény kiolvasás programkönyvtárak használata nélkül
  • Példa forráskód

______________________________________________________________________________

A modullal azért kezdtem el foglalkozni, mert akkumulátorok töltése és merítése közben szerettem volna mérni a feszültséget és az áramot. Kezdetben a feszültség és az árammérésre is az Arduino analóg bemeneteit terveztem felhasználni. Ez nem igazán egyszerű, mert az áram mérése problematikus az Arduino analóg bemenetein. Ennek oka, hogy az áramot feszültséggé kell alakítani egy ellenálláson, és ennek a sönt ellenállásnak minél kisebbnek kell lennie, hogy kicsi feszültség essen rajta és ne változtassa meg az áram nagyságát. Közismert tény, hogy a mérés mindíg megváltoztatja a mérendő mennyiséget. Többek között ezért nem tudjuk atomi szinten pontosan megmondani egy részecske sebességét és helyét egyidőben. Vagy a helyét ismerjük, vagy a sebességét! Az egészről Werner Karl Heisenberg határozatlansági relációja tehet, nem a mi hibánk!
Szóval a kicsi ellánáláson kicsi feszülltség esik! Viszont ennek a kicsi feszültségnek a mérésére (millivoltokról van szó) az Arduino nem alkalmas. Miközben kerestem a megoldást, ráakadtam erre a modulra. Lényegi különbség, hogy a sönt feszültség mérési tartománya pont az áhított mV-os tartomány ennél a chip-nél. Nagyon leegyszerűsíti a méréseket, ezért rögvest rendeltem is egyet. Az igazság az, hogy először az INA219 modult találtam meg, ami szerényebb képességekkel bír. Kisebb a beépített AD átalakító felbontása, és az áram méréskor is csak egyik irányba folyhat az áram, tehát csak egyirányú méréseket tesz lehetővé. Ne is beszéljünk róla többet.

Az INA226 technikai adata

Ez az eszköz terhelésen elnyelt energia mérésére lett kifejlesztve. A terhelés lehet egy ellenállás, de mint látni fogjuk lehet pl. egy akkumulátor is, aminek a kapacitását mérhetjük töltés és merítés közben is. A modul képes mérni a terhelés feszültségét, és egy kis méretű sönt ellenállás segítségével az átfolyó áramot. A modulon elhelyezett chip nem tartalmazza a sönt ellenállást, azt külön kell beépíteni. Egy olyan modult szereztem be, amire 0.1 ohm-os söntellenállást építettek. Mivel a söntellenállás feszültség mérésének felső határa +/- 81,92mV (ez az INA226 chip tulajdonsága), tekintélyes 819,2mA méréshatárt lehet megvalósítani ezzel a konkrét modullal. Sejtem, hogy a chip-be beépítettek egy egyenáramú erősítőt is, mert a ~80mV méréshatár elég kicsi egy átlagos AD átalakítónak. A terhelés feszültsége 36V lehet maximum. Nekem lítium akkumulátorok vizsgálatához volt szükség az eszközre, és erre tökéletesen megfelel.

Nézzük meg a chip belső felépítését:

Azért ezt a képet választottam, mert ez elegendően egyszerű a működés megértéséhez, bár mások a rajzon a külső alkatrészek értékei mint az én modulomon. Azt látjuk, hogy egy 2mohm-os sönt ellenálláson keresztül táplálunk egy terhelést. Pl egy elenállást, vagy villanymotort, vagy bármi mást. A chip-ben található analóg kapcsoló felváltva kapcsolgatja az az analóg-digitál átalakítóra (ADC) a sönt ellenállás két pontját, majd a terhelés (Load) két kivezetését, nevezetesen a földet és a terhelés másik kapcsát. Nem rajzolták be, de nyilván közben méréshatárt is vált az ADC, hiszen a terhelés feszültsége az ábrán berajzolt értékekkel 12V, míg a sönt ellenálláson még 10A esetén is 20mV feszültséget lehet mérni. Az ADC egyébként 16 bites, ami igen pontos mérést tesz lehetővé de ekkora átfogáshoz 16 bit is kevés. A sönt feszültség mérésekor ilyen kicsi feszültség tartományban már zavarjelek is keletkezhetnek, ennek szűrésére a gyártó javasol is egy szűrő megoldást:

Nekem erre nem volt szükségem, ha néha beinduló hűtőgép, vagy feleségem vasalója generál egy extra feszültségcsúcsot, az beleveszik a rengeteg mérési adatba.

Az INA226 a söntfeszültséget előjelesen méri, ami azt jelenti, hogy a terhelés a föld és a terhelés, valamint a tápfesz pozitív pólusa és a terhelés közé is kerülhet. Ehhez is találtam magyarázó ábrát:

Számomra ez azért volt nagyon jó hír (az INA219 még nem rendelkezett ezzel a tulajdonsággal), mert a terhelés az esetemben egy akkumulátor, amire töltőt kapcsolok, vagy a töltő helyére egy terhelő ellenállást, amivel merítem az akkut. Nyilván az áram töltéskor befelé folyik az akkuba, merítéskor pedig kifelé az akkumulátorból. Így a söntfeszültség előjele azt is jelzi, hogy éppen töltök vagy merítek. Az akkumulátor egyébként az első ábra szerint lesz bekötve az ottani terhelés helyére. A sönt ellenállás pedig a modulon beépített 0.1ohm.

Bent az chip-ben még van némi kiszolgáló elektronika, ami megvalósít egy I2C kapcsolatot, és van néhány regisztere, ahová a mérési eredmények kerülnek, illetve a mérést meghatározó paramétereket lehet beállítani. A regiszterek 16 bitesek. Tekintve, hogy 16 bites az AD átalakító, ez nem is csoda. Természetesen konfigurációs regiszter is 16 bites, amit két lépésben lehet az I2C buszon keresztül írni:

Az egyes bitek jelentése:

RST – ha 1-et írunk bele, a chip reseteli magát (ekkor a bit 0-ra áll vissza)
AVG0-2 – A mérések száma, ezeket átlagolja a chip
VBUSCT0-2 – A Vbus feszültség konverziós ideje (140mikrosec – 8,244milisec)
VSHCT0-2 – A sönt feszültség konverziós ideje (140mikrosec – 8,244milisec)
MODE1-3 – A mérési módok (folyamatos, triggerelt, power down mód)

Az értékek beállítása nagyon egyszerű. Ha zajos környezetben dolgozunk, mérjünk sokat és átlagoljunk. A mérési idő növelése is javítja a pontosságot. Azonban a két érték beállítása hatalmas mérési időket eredményezhet. 1024 x 8,244millisec=8,4 sec. Tehát, ha túlzásba visszük, egy-egy mérés hosszú másodpercekig tart. Saját felhasználásomban úgy gondoltam, hogy elég lesz 4 mérés és 1,1msec mérési idő. Megírtam a lejjebb található programot, rákötöttem a bemenetekre egy akkumulátort terhelő ellenállással, és mivel a mért értékek stabilan ismételték magukat, úgy gondoltam ez nekem tökéletes. Kipróbáltam 1 db 140mikrosec-es mérést is, ott már az utolsó számjegy időnként megváltozott, tehát a zaj elkezdte befolyásolni a mérési eredményt.
A működési módot folyamatosra állítottam, ami szintén leegyszerűsíti a programot, mert csak ki kell olvasni a mérési eredményt egy tetszőleges időpontban, és a legutolsó mérés eredménye mindig rendelkezésre áll. Lehetne időnként elindítani egy mérést, megvárni az eredményt és kiolvasni, de ez már egy bonyolultabb program. Annak, aki kísérletezgetni szeretne, remek táblázatok vannak a katalógusokban. Segítségül itt a lényeg:

Az utolsó táblázatból látható, hogy a chip-et el lehet küldeni alvásba. Elemes tápláláskor ez fontos szempont lehet. Alvó módban 2-3mikroA az áramfelvétele. Folyamatos mérés esetén pedig kevesebb mint 0,5mA. Ezeket az értékeket katalógusból olvastam ki.

Lássuk a további regisztereket:

Mint látható van bőven mit megtudni a chip-ről! Mivel a „Shunt volrage” és a „Bus voltage” regiszterekbe kerülnek a mérési eredmények, a többi regiszter már leszármaztatott adat. Van egy riasztási funkció is, ami a chip „Alert” kimenetén jelez, ha elértek az adatok egy beállított értéket. A „Calibration factor” regiszterben meg lehet adni egy értéket, ami alapján kiszámolja a chip az áramot és a teljesítményt. Ez azért kell, mert a „Shunt voltage” regiszterben nem az áramot kapjuk meg, hanem a sönt ellenálláson eső feszültséget. A sönt ellenállás értékét pedig nem tudja a chip, meg kell neki mondani valahol. Az adatlapok ennek az értéknek a számítását pontosan példákkal leírják, de nekem nagyon nehézkesnek tűnt a használata, így hamar feladtam a használatát. Főleg az okozott gondot, hogy a mért feszültség abszolút értékben nem volt pontos. A “bus voltage” regiszterből kiolvasott számot 1,25mV-al kell megszorozni, hogy V-ban kapjuk meg a feszültséget. A kiszámított akkumulátor feszültség tekintélyes értékben eltért a valóságtól. Esetemben 0,9526-al kellett megszorozni, hogy a méregdrága preciziós multiméterem által mért feszültséget kapjam meg. Azonban ezt a konstanssal történő szorzást elvégezve a teljes tartományban pontos értéket kaptam, bár csak 0 és 12V között ellenőriztem néhány ponton. Ezen problémák miatt gyorsan feladtam a belső számítások lehetőségét, mindent magam számoltam ki a programban.
Érdekes lehetőség még a riasztások használata. Ezt elméletben tudtam volna használni, hiszen akkumulátor töltést a 4.2 V-os határ elérésekor meg kell szakítani (a merítést 2.5V-nál), de ezt is egyszerűbb volt a programban megvalósítani. Ha valakinek ezek a lehetőségek fontosak, akkor rossz helyen jár. Rengeteg cikket találtam azonban a neten, ahol ezeket a tulajdonságokat kivesézik.

A chip I2C címét is be lehet állítani. Szerencsére nekem csak egy ilyen eszközöm van, ezért hagyhattam az alapértelmezett értéken, aza nem kelett pákával forasztgatni a modul jobboldali képén látható A0 és A1 kivezetéseket. Őrült kicsik!

Természetesen van programkönyvtár, nem is egy. A képről látható néhány példa:

Többet is kipróbáltam a programkönyvtárak közül. Közös jellemző, hogy irdatlan sok függvényt kell megérteni. Bár nagyon kényelmes ezeket használni, engem bosszantottak. Szó szerint órákat töltöttem a könyvtárak megismerésével és a használat megtanulásával. Ennek oka, hogy a függvények megértéséhez meg kellett ismerni a chip működését, mindazt amit fentebb leírtam. Gondoltam egyet, és azt amire szükségem volt, megírtam magam. Ez nem nagy kunszt, mert mindössze egy alap beállításra, és a két mérési eredmény regiszter kiolvasására volt szükség. Az I2C busz használata már egyébként is ujjgyakorlat, így 10 perc alatt megcsináltam, miután eldöntöttem, hogy mit akarok. Nagyon egyszerű dolgot akartam. A setup() ben beállítani az üzemmódot (4 mérés átlaga, 1,1msec mérési idővel, és folyamatos mérés), valamint a mért adatok kiolvasása. Alább a forráskód! A setup()ben beállítok, a loop()-ban mérek és kijelzek! Ennyi az egész. Nem szempont, de a program így jóval kisebb lett! Alább a forráskód! Sok a komment, biztosan meg lehet belőle érteni mindent.

#include<Wire.h>           
int i2c_cim=0x44;
unsigned int fesz,aram;
byte MSByte = 0, LSByte = 0;

void setup() {
  Wire.begin();                 // I2C kommunikáció inicializálása, nincs cím, ezért master
  Serial.begin(9600);

  Wire.beginTransmission(i2c_cim);
  if(Wire.endTransmission()){
    Serial.println("INA226 nincs jelen");
  }
  //configurációs regiszter bitek
  //D15-reset
  //D11-D9 - átlagolásszám, Értékek: 1=0b00,4=0b001,16=0b010,64=0b011,128=0b100,256=0b101,512=0b110,1024=0b111
  //D8-D6 - Vbus konv. idő, Értékek: 140us=0b000,204us=0b001,332us=0b010,588us=0b011,1100us=0b100,2116us=0b101,4156us=0b110,8244us=0b111
  //D5-D3 - Shönt konv. idő, Értékek: 140us=0b000,204us=0b001,332us=0b010,588us=0b011,1100us=0b100,2116us=0b101,4156us=0b110,8244us=0b111
  //D2-D0 - Működési mód: folyamatos mérés=0b111, indított mérés=0b011,
  //chip alaphelyzetbe állítása
  Wire.beginTransmission(i2c_cim);  //megszólítjuk az eszközt
  Wire.write(0x00);                 //a státus regisztert fogjuk írni
  Wire.write(0x80);                 //beállítjuk a D15 reset bitet 1-re, többi bit közömbös
  Wire.write(0x00);                 //a státus regiszter 16 bites, ezért kell egy következő byte-ot is írni
  Wire.endTransmission();           //vége a kommunikációnak
  //Beállítjuk a chip mérési paramétereit: folyamatos mérés, átlagolás 4, mérési idő 1,1ms
  Wire.beginTransmission(i2c_cim);  //megszólítjuk az eszközt
  Wire.write(0x00);                 //a státus regisztert fogjuk írni
  //segéd ábra a paraméter bitek megtalálásához
  //0b0000aaav     a-átlagolási idő bitek, v-Vbus konverziós idő
  //0bvvsssmmm     v-Vbus konverziós idő, s-sönt konverziós idő, m-működési mód
  Wire.write(0b00000011);           //két byte-on küldünk ki mindent, pont a Vbus konv. időnél
  Wire.write(0b00100111);           //törte ketté
  Wire.endTransmission();
  delay(20);                        //hagyunk időt eg mérésre (4 x 1.1msec kell), különben a legelső eredmény kiolvasás eredménye 0-lesz
}

void loop() {
  Wire.beginTransmission(i2c_cim);  //megszólítjuk az eszközt
  Wire.write(0x01);                 //a sönt feszültség regisztert fogjuk olvasni
  Wire.endTransmission();           //kommunikáció lezárása
  Wire.requestFrom(i2c_cim,2);      //2 byte-ot várunk az INA226-tól (16 bites a regiszter)
  if(Wire.available()){             
    MSByte = Wire.read();           //kiolvassuk az első byte-ot
    LSByte = Wire.read();           //kiolvassuk a második byte-ot
    aram = (MSByte<<8) + LSByte;    //a két byte-ból csinálunk egy 16 bites számot, és ez az eredmény
  }
  Wire.beginTransmission(i2c_cim);  //megszólítjuk az eszközt
  Wire.write(0x02);                 //a Vbus feszültség regisztert fogjuk olvasni
  Wire.endTransmission();           //kommunikáció lezárása
  Wire.requestFrom(i2c_cim,2);      //2 byte-ot várunk az INA226-tól (16 bites a regiszter)
  if(Wire.available()){
    MSByte = Wire.read();           //kiolvassuk az első byte-ot
    LSByte = Wire.read();           //kiolvassuk a második byte-ot
    fesz = (MSByte<<8) + LSByte;    //a két byte-ból csinálunk egy 16 bites számot, és ez az eredmény
  }
  //Eredmények kiírása
  Serial.print((fesz*1.25)/1000,3);Serial.println(" V");             //egy bit eltérés 1,25mV feszültséget jelent
  Serial.print(((aram*0.0000025)/0.1)*1000,2);Serial.println(" mA"); //egy bit eltérés 2,5mikroV feszültséget jelent
                                                                     //sönt ellenállás 0,1 ohm
  delay(2000);
}

Mennyire volt hasznos amit olvastál?

Kattints egy csillagra az értékeléshez!

Szövegesen is leírhatod véleményedet!