
投稿日 2014/10/10
TI社のカレント・シャント・モニター INA194の動作を確認してみました。
カレント・シャント・モニター とはシャント抵抗用電流センスアンプのことです。
応用はDC-DCコンバータのような電源や充電器などの電流計測です。

マッチの先にINA194AIDBVR
TI社のデータシートより
手書きパターン設計図
INAシリーズには以下の種類があります。
INA193 20V/V
INA194 50V/V *
INA195 100V/V
INA196 20V/V
INA197 50V/V
INA198 100V/V
INA193からINA195 と、INA196からINA198はセンスピンの+ -の配置が逆になっています。

計測中 Vout = 1.629V(実測) I = 3.000A(補正値)
シャント抵抗は0.01Ω
INA194のゲインは50倍
計算では3.0 x 0.01 x 50 = 1.5V
Voutに0.9208を掛けて補正し、(0.01 x 50)で割る = I
マイコンはPIC 18F4553
ADコンバータはMCP3425 ΔΣ 16bit
簡単に言えば固定ゲインの差動入力のアンプです。
今回取り上げたのはINA194です。ゲインは50倍です。
シャント抵抗の両端の電位差を計測し50倍に増幅してマイコンなどのADコンバータで読み取ります。
例えば0.01Ωのシャント抵抗に1A流れると、両端電圧は0.01Vですが、これを50倍して0.5Vにして出力します。
マイコンのADコンバータのリファレンス電圧が3.3Vとすると、3.3 / (0.01 x 50) = 6.6Aまで計測できることになります。
リファレンス電圧が2.048Vの場合は、 2.048 / (0.01 * 50) = 4.096Aまで計測できる計算になります。
今回は、
シャント抵抗(Rs)に0.01Ω
ADコンバータにMCP3425 16bit ΔΣADコンバータ リファレンス電圧2.048V
マイコンにPIC 18F4553
を使って、INA194の直線性を計測してみました。
電流源の電源は10V(任意でよい)
電流は電子負荷を使用して正確に0Aから4Aまで0.1Aステップで流します。
実装
INA194のパッケージはSOT-23ですから、非常に小型です。実装に苦労します。
銅箔でパターンを作りINA194とシャント抵抗を載せました。

アクリル板の上に銅箔を貼りカッティングして作った基板
よく見えないが中央にINA194
INA194の下をGNDが通過しているが、
心もとないので上空をスズめっき線で接続
上部の白いのがシャント抵抗 0.01Ω
INA194のVoutをMCP3425の電圧入力VIN+につなぎました。
アクリル板は銅箔の上に半田づけするときに注意(熱で溶けます)が必要ですが、この程度なら大丈夫です。アクリル板のようなツルツルした表面であれば、銅箔の細かいカッティングがしやすいです。
INA194の下を銅箔のGNDが通過していますが、細いので最大4A流すのは心配です。このためICの上空をスズメッキ線で結んでいます。(このためINA194がよく見えない)
シャント抵抗の両端をVIN+ VIN-と接続します。
V+ - GND間に電源として3.3Vを加えました。
これでVoutに、シャント抵抗の両端の電位差が50倍になって出力されます。
VoutをMCP3425 16bit ΔΣADコンバータでデジタルに変換します。もちろんPIC内蔵の12bitADコンバータでもよいと思います。
計測
電源を10V(任意でよい)として、0から4AまでのINA194(ゲイン50倍)の出力電圧(Vout)を計測してみました。
シャント抵抗(Rs)は0.01Ωです。
ADコンバータMCP3425のリファレンス電圧は2.048Vです。
0.01 x 4 x 50 = 2.0Vとなり、4Aくらいまでが2.048Vに収まります。

Voutは実測値
Vout(Cal Rs = 0.01Ω)はRs 0.01Ωでの計算値(Ideal)
Vout(Cal Rs = 0.010843Ω)はRsを0.010843Ωとした計算値 実測と一致
(グラフには無いがGAINを54.21622に補正しても同じ)
Vout(実測値)にk=0.9208を掛けて傾きを補正 計算値に一致
直線性に問題はない
何でもそうですが、誤差はつきものです。
まず誤差無し、つまりRs = 0.01Ω ゲイン = 50ぴったりとして計算しておきます。
電流の計算式は、Rsを50倍してVoutを割ったものと同じなので、
I = Vout / (0.01 x 50)です。
たとえばVoutが1.5Vだとすると 1.5 / (0.01 x 50) = 3.0A と計算できます。
ところが実測で3.0A流した時のVoutが1.629Vですので、
Rsを0.010843Ωに補正(ゲインは50とする)して計算すると約3.0Aとなります。
(こういう補正はエクセルのゴールシークが便利です)
1.629 / (0.010843 x 50) = 3.0005
一方、INA194のゲインに誤差がある場合も考えられます。
グラフには描いていませんが、Rsが誤差無しの0.01Ωとした場合、ゲインを54.21622に補正しても同様な結果が得られます。
1.629 / (0.01 x 54.21622) = 3.005
実際にはどちらに誤差があるのか、このままではわかりませんが、それを知る必要はありません。
実際の補正では、簡単に傾きを変える補正値(k)を掛けてしまいます。
今回は0.9208をかければ補正できます。 1.629 x 0.9208 = 1.5
電流に換算するのは、(0.01 x 50) = 0.2 で割るだけです。
1.5 / (0.01 x 50) = 3.0A
このように直線性さえ確保されていれば、簡単に補正計算できます。
ソースコード
補正は0.9208を掛けて行っています。
main.c
#include <xc.h>
#include <p18f4553.h>
#include <stdio.h>
#include <math.h>
#pragma config CPUDIV = OSC4_PLL6 //[Primary Oscillator Src: /2][96 MHz PLL Src: /3]
#pragma config PLLDIV = 5 //Divide by 5 (20 MHz oscillator input)
#pragma config USBDIV = 2 //USB clock source comes from the 96 MHz PLL divided by 2
#pragma config FCMEN = OFF //Fail-Safe Clock Monitor disabled
#pragma config IESO = OFF //Oscillator Switchover mode disabled
#pragma config FOSC = HS //HS oscillator (HS)
#pragma config PWRT = OFF //PWRT disabled
#pragma config VREGEN = OFF //USB voltage regulator disabled
#pragma config BORV = 3 //Minimum setting
#pragma config BOR = ON //Brown-out Reset enabled in hardware only (SBOREN is disabled)
#pragma config WDTPS = 32768 //1:32768
#pragma config WDT = OFF //WDT disabled (control is placed on the SWDTEN bit)
#pragma config CCP2MX = OFF //CCP2 input/output is multiplexed with RB3
#pragma config PBADEN = OFF //PORTB<4:0> pins are configured as digital I/O on Reset
#pragma config MCLRE = ON //MCLR pin enabled; RE3 input pin disabled
#pragma config LPT1OSC = OFF //Timer1 configured for higher power operation
#pragma config STVREN = ON //Stack full/underflow will cause Reset
#pragma config DEBUG = OFF //Background debugger disabled, RB6 and RB7 configured as general purpose I/O pins
#pragma config ICPRT = OFF //ICPORT disabled
#pragma config LVP = OFF //Single-Supply ICSP disabled
#pragma config XINST = OFF //Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
#pragma config CP0 = OFF //Block 0 (000800-001FFFh) is not code-protected
#pragma config CP1 = OFF //Block 1 (002000-003FFFh) is not code-protected
#pragma config CP2 = OFF //Block 2 (004000-005FFFh) is not code-protected
#pragma config CP3 = OFF //Block 3 (006000-007FFFh) is not code-protected
#pragma config CPB = OFF //Boot block (000000-0007FFh) is not code-protected
#pragma config CPD = OFF //Data EEPROM is not code-protected
#pragma config WRT0 = OFF //Block 0 (000800-001FFFh) is not write-protected
#pragma config WRT1 = OFF //Block 1 (002000-003FFFh) is not write-protected
#pragma config WRT2 = OFF //Block 2 (004000-005FFFh) is not write-protected
#pragma config WRT3 = OFF //Block 3 (006000-007FFFh) is not write-protected
#pragma config WRTB = OFF //Boot block (000000-0007FFh) is not write-protected
#pragma config WRTC = OFF //Configuration registers (300000-3000FFh) are not write-protected
#pragma config WRTD = OFF //Data EEPROM is not write-protected
#pragma config EBTR0 = OFF //Block 0 (000800-001FFFh) is not protected from table reads executed in other blocks
#pragma config EBTR1 = OFF //Block 1 (002000-003FFFh) is not protected from table reads executed in other blocks
#pragma config EBTR2 = OFF //Block 2 (004000-005FFFh) is not protected from table reads executed in other blocks
#pragma config EBTR3 = OFF //Block 3 (006000-007FFFh) is not protected from table reads executed in other blocks
#pragma config EBTRB = OFF //Boot block (000000-0007FFh) is not protected from table reads executed in other blocks
#define LED PORTEbits.RE2 //Sens Time
void i2c_init(void);
void i2c_enable(void);
void lcd_init(void);
void lcd_clear(void);
void lcd_write(unsigned char, unsigned char, const unsigned char*);
void MCP3425_Set_configuration(unsigned char);
void MCP3425_Get_data_configuration(unsigned char *);
#define _XTAL_FREQ 5000000 //__delay_ms
void delay_us(int time){
int i;
for(i = 0; i < time; i++) __delay_us(1);
}
void delay_ms(int time){
int i;
for(i = 0; i < time; i++) __delay_ms(1);
}
void i2c_init(void)
{
SSPCON1bits.SSPEN = 0;
SSPCON1bits.SSPM = 8; // I2C Master mode Clock = Fosc/(4 * (SSPADD + 1))
SSPADD = 11; // 100KHz
TRISBbits.TRISB1 = 1; // SCL
TRISBbits.TRISB0 = 1; // SDA
SSPCON1bits.SSPEN = 1; // Enable the I2C module
}
void init(void){
OSCCONbits.SCS = 0; //Primary OSC 10MHz
ADCON1 = 0b00001111; // All Digital
CMCON = 0b00000111; // No Comparator
TRISA = 0b00000000;
TRISB = 0b00000000;
TRISC = 0b00000000;
TRISD = 0b00000000;
TRISE = 0b00000011;
LATA = 0b00000000;
LATB = 0b00000000;
LATC = 0b00000000;
LATD = 0b00000000;
LATE = 0b00000000;
}
void main(void){
unsigned char get_value_byte[3];
unsigned int get_value_int;
float get_value_float, temp;
float ntc_r;
char string[10];
init();
i2c_init();
lcd_init();
lcd_clear();
lcd_write(0, 0, "Vout ");
while(1){
LED = 1;
MCP3425_Set_configuration(0b10001000); //Continuous mode, 15SPS(16bit), Gain x1
delay_ms(1);
MCP3425_Get_data_configuration(get_value_byte);
get_value_int = get_value_byte[0] << 8 | get_value_byte[1];
get_value_float = (((float)get_value_int * 2.048) / 32768);
sprintf(string, "%8.3f", get_value_float); //Vout(V)
lcd_write(0, 0, string);
sprintf(string, "%8.3f", (get_value_float * 0.9208 / (0.01 * 50)); //I(A)
lcd_write(0, 1, string);
LED = 0;
delay_ms(500);
} //while
} //main
i2c_mcp3425.c
#include <xc.h>
#include <p18f4553.h>
#define MCP3425_I2C_ADDR 0xD0
#define WRITE_MODE 0x00
#define READ_MODE 0x01
#define PROVE PORTCbits.RC0 //Prove
void delay_us(int);
void delay_ms(int);
void MCP3425_Set_configuration(unsigned char data);
void MCP3425_Get_data_configuration(unsigned char *get_value);
void MCP3425_Set_configuration(unsigned char byte){
SSPCON2bits.SEN = 1;
while(SSPCON2bits.SEN == 1);
SSPBUF = MCP3425_I2C_ADDR | WRITE_MODE;
while(SSPSTATbits.BF);
delay_us(1);
if (SSPCON2bits.ACKSTAT){
SSPCON2bits.PEN = 1;
while(SSPCON2bits.PEN);
return;
}
SSPBUF = byte;
while(SSPSTATbits.BF);
delay_us(1);
if (SSPCON2bits.ACKSTAT){
SSPCON2bits.PEN = 1;
while(SSPCON2bits.PEN);
return;
}
delay_us(1);
SSPCON2bits.PEN = 1;
while(SSPCON2bits.PEN);
return;
}
void MCP3425_Get_data_configuration(unsigned char *get_value){
PROVE = 1;
SSPCON2bits.SEN = 1;
while(SSPCON2bits.SEN == 1);
SSPBUF = MCP3425_I2C_ADDR | READ_MODE;
while(SSPSTATbits.BF);
delay_us(1);
if (SSPCON2bits.ACKSTAT){
SSPCON2bits.PEN = 1;
while(SSPCON2bits.PEN);
return;
}
delay_us(1);
SSPCON2bits.RCEN = 1;
while(SSPCON2bits.RCEN);
while(SSPSTATbits.BF == 0);
SSPCON2bits.ACKEN = 1;
get_value[0] = SSPBUF;
delay_us(1);
SSPCON2bits.RCEN = 1;
while(SSPCON2bits.RCEN);
while(SSPSTATbits.BF == 0);
SSPCON2bits.ACKEN = 1;
get_value[1] = SSPBUF;
delay_us(1);
SSPCON2bits.RCEN = 1;
while(SSPCON2bits.RCEN);
while(SSPSTATbits.BF == 0);
SSPCON2bits.ACKEN = 1;
get_value[2] = SSPBUF;
delay_us(1);
SSPCON2bits.PEN = 1;
while(SSPCON2bits.PEN);
PROVE = 0;
return;
}
(JF1VRR)