top of page

カレント・シャント・モニター INA194

投稿日 2014/10/10

TI社のカレント・シャント・モニター INA194の動作を確認してみました。

 

カレント・シャント・モニター とはシャント抵抗用電流センスアンプのことです。

応用はDC-DCコンバータのような電源や充電器などの電流計測です。

18f4553_ina194_0.jpg

マッチの先に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はセンスピンの+ -の配置が逆になっています。

18f4553_ina194_1.jpg

 計測中 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とシャント抵抗を載せました。

18f4553_ina194_2.jpg

アクリル板の上に銅箔を貼りカッティングして作った基板

よく見えないが中央に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に収まります。

18f4553_ina194_3.jpg

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)

bottom of page