0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

INA219 電流電力計測ICの設定 with PIC16F18325

Last updated at Posted at 2024-10-04

シャント抵抗の両端をAD変換して、電流と電圧、電力値を計測表示してくれるIC INA219まとめ

データシートは、2011年度版を参考にしました。2015年版のデータシートが最新の内容になっています。

IMG_4996.JPG
チップ抵抗の値は、文字R100のRは小数点を表すので、0.1Ωになります。INA219は、この抵抗の両端の電圧差を計測して、電流を計算してくれるICです。

IMG_4997.JPG

PIC16F18325を使用。

I2C通信でINA219の測定値を取得し、液晶に表示します。
IMG_4995.JPG

IMG_5002.JPG

回路図
INA219回路図.png

データシートを読み込むわけですが、結構難解でした。

まず、データーシートのP.17,18ページでキャリブレーション値を計算しておきます。
datasheetCal.png

シャント抵抗値は0.1Ω
測定電圧の最大値は32V
電流値の最大は、3.2Aとして計算しました。
※最大電流値をもっと少なくして、たとえば1Aで計算しなおせば、精度が上がります。
IMG_5004.JPG

PICマイコン側で、電流値、電力値を求めるときに必要な値。

上記で求めた値と、バス電圧のLSBを押さえておきます。

電流値のLSB Current_LSB:98uA
キャリブレーション値 Cal:4180(0x1054)
電力値のLSB Power_LSB:1960uW(約2mWとして計算)
バス電圧のLSB 4mV(datasheetより)

INA219がPICマイコンに返信してくる16ビットは、電流値、電圧値、電力値をスケーリングしてプロットした値なので、ただの相対値になっています。この相対値にLSB値を掛けると、欲しい値、電流値等になります。

INA219 busVoltage Resister(02h)の値にLSB 4mVを、
INA219 Power Resister(03h)の値に、LSB 2mWを、
INA219 Current Resister(04h)の値に、LSB 98uAをかけます。

buVoltageレジスタの単位は、mV
Power レジスタの単位は、mW
Current レジスタの単位は、uA
なので、実際の物理量である電流量などは、マイコン側で、LSB値をかけて、計算しています。

計測値の計算
//*****************************************************
//INA219データ計算
//_add:INA219 I2Cスレーブアドレス
//_reg:INA219 レジスタアドレス
//呼び出したデータの種類によってLSB値を掛ける。
//*****************************************************
uint16_t INA219_RegRead(uint8_t _add, uint8_t _reg)
{
    uint16_t ltmp;
    uint32_t lval;
    
    ltmp=I2C1_b2Read(_add,_reg);
    
    switch(_reg)
    {   case 0x02://BusVoltage
            ltmp>>=3;//レジスタ下位3ビットはいらないのでシフト。
            ltmp*=4L;//LSB:4mV
            ltmp/=10;//表示調整
            unit[0]='V';
            break;
        case 0x03://Power
            lval = ltmp;
            lval=lval*20L;//PowerLSB=1.960mW(約2mW) 小数点第1位まで求める。
                          //LSB:2mWを、10倍(表示調整)しておく。
            if(lval>10000)
            {//1000mW以上の時の液晶表示単位
                lval/=1000;
                unit[0]='W';
                unit[1]=' ';
            }
            else
            {//1000mW以下の時の液晶表示単位
                unit[0]='m';
                unit[1]='W';  
            }
            ltmp=lval;
            break;
        case 0x04://current
            lval=ltmp*98L;//LSB:98uA
            ltmp=lval/1000L;
           
            unit[0]='m';
            unit[1]='A';
            
            break;
    }
    return ltmp;   
}


 

INA219の初期化

INA219のレジスタは00hから05hまでの6個だけです。以下の2つのレジスタの値を設定します。

Configration Register(00h)を0x3E67で初期化。
BusVoltageRangeを32Vに設定。PGA(ShuntVoltage only)を'÷8'0b11に設定。
SADCとBADCは、0b1100(16回平均)に設定。
modeは、0b111で、Shunt and Bus,Continuousに設定。

Calibration Register(05h)に上記で計算した値4180(0x1054)をセット

main.c

// PIC16F18325 Configuration Bit Settings

// 'C' source line config statements

// CONFIG1
#pragma config FEXTOSC = OFF    // FEXTOSC External Oscillator mode Selection bits (Oscillator not enabled)
#pragma config RSTOSC = HFINT1  // Power-up default value for COSC bits (HFINTOSC (1MHz))
#pragma config CLKOUTEN = OFF   // Clock Out Enable bit (CLKOUT function is disabled; I/O or oscillator function on OSC2)
#pragma config CSWEN = ON      // Clock Switch Enable bit (The NOSC and NDIV bits cannot be changed by user software)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)

// CONFIG2
#pragma config MCLRE = ON     // Master Clear Enable bit (MCLR/VPP pin function is digital input; MCLR internally disabled; Weak pull-up under control of port pin's WPU control bit.)
#pragma config PWRTE = OFF       // Power-up Timer Enable bit (PWRT enabled)
#pragma config WDTE = OFF       // Watchdog Timer Enable bits (WDT disabled; SWDTEN is ignored)
#pragma config LPBOREN = OFF    // Low-power BOR enable bit (ULPBOR disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable bits (Brown-out Reset disabled)
#pragma config BORV = LOW       // Brown-out Reset Voltage selection bit (Brown-out voltage (Vbor) set to 2.45V)
#pragma config PPS1WAY = ON     // PPSLOCK bit One-Way Set Enable bit (The PPSLOCK bit can be cleared and set only once; PPS registers remain locked after one clear/set cycle)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable bit (Stack Overflow or Underflow will cause a Reset)
#pragma config DEBUG = OFF      // Debugger enable bit (Background debugger disabled)

// CONFIG3
#pragma config WRT = OFF        // User NVM self-write protection bits (Write protection off)
#pragma config LVP = ON        // Low Voltage Programming Enable bit (High Voltage on MCLR/VPP must be used for programming.)

// CONFIG4
#pragma config CP = OFF         // User NVM Program Memory Code Protection bit (User NVM code protection disabled)
#pragma config CPD = OFF        // Data NVM Memory Code Protection bit (Data NVM code protection disabled)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.



#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "myLibrary18325.h"

#include "I2C_MSSP1.h"
#include "SSD1306.h"
#include "INA219.h"

#define LED2 RA2

#define nonPrint

uint8_t val;
uint8_t flag;
void Port_init(void);

void delay10ms(uint16_t num);
void SSD1306_Print(uint16_t ival);
void SSD1306_PrintS(uint16_t sval,uint16_t cal);
void SSD1306_Print2(uint16_t ival);
void SSD1306_Print3(uint16_t ival);
uint8_t ioc_flag;
uint8_t ioc_val;

void __interrupt()isr()
{  
    if(PIR0bits.TMR0IF)
    {     
        tm0.cnt[0]++;
       
               
        if(tm0.cnt[0]==3)
        {
            tm0.up=T0_UP;
            
            tm0.cnt[0]=0;
        }else
        {
            TMR0L=0x61;//100ms
            PIR0bits.TMR0IF=0;
        } 
    }      
}


int main(int argc, char** argv)
{
  
    uint8_t ret,tmp[3];
    uint16_t val16[6];
    
    uint32_t longval;
    int32_t longval1;
    //Oscillator
    OSCCON1bits.NOSC=0b110;
    OSCCON1bits.NDIV=0b000;
    OSCFRQbits.HFFRQ=0b101; //100:8MHz 101:12Mhz
    __delay_ms(500);
    //initial--------------------------------------
    Port_init();
    I2C1_Reg_Init();
    Timer0_INIT();
    SSD1306_initialize();
            
    //Configration Resistor------------------------
    //32VRange, /8, 12bitsADC
    tmp[0]=0x00;
    tmp[1]=0x3E;//(24.9.30)
    tmp[2]=0x67;
    tmp[0]=I2C1_bnWrite(INA219add,tmp,3);
    
    //Caribration Resistor-------------------------
    tmp[0]=0x05;
    
#define MaxCurrent3_2Amax2
    
#ifdef MaxCurrent1Amax
    tmp[1]=0x33;
    tmp[2]=0x9C;
#endif    
    
#ifdef MaxCurrent2Amax
    tmp[1]=0x1A;
    tmp[2]=0x3A;
#endif
#ifdef MaxCurrent3Amax
    tmp[1]=0x11;
    tmp[2]=0x79;
#endif
#ifdef MaxCurrent3_2Amax
    tmp[1]=0x10;
    tmp[2]=0x54;
#endif
#ifdef MaxCurrent3_2Amax2
    tmp[1]=0x10;
    tmp[2]=0xCC;
#endif    
    
    tmp[0]=I2C1_bnWrite(INA219add,tmp,3);
    
    Interrupt_START();
    while(1)
    {
      
       
       if(tm0.up==T0_UP)
       {
            INTCONbits.GIE=0;
            INTCONbits.PEIE=0;
            tm0.up=T0_STOP;
            
            //電流表示
            val16[4]=INA219_RegRead(INA219add,0x04);
            SSD1306_Print(val16[4]);
            
            val16[1]=INA219_RegRead(INA219add,0x01);
            val16[5]=INA219_RegRead(INA219add,0x05);
            SSD1306_PrintS(val16[1],val16[5]);
            
            //電圧表示
            val16[2]=INA219_RegRead(INA219add,0x02);
            SSD1306_Print2(val16[2]);
            
            
            //電力表示
            val16[3]=INA219_RegRead(INA219add,0x03);
            SSD1306_Print3(val16[3]);
            
            PIE1bits.TMR1IE=1;
            INTCONbits.GIE=1;
       }
          

    }
    return (EXIT_SUCCESS);
}

void Port_init(void)
{
    //Port init--------- 
    //PORTA initialize
    TRISA = 0x08;   //RA3:MCLR
    ODCONA = 0x00;  //When anODCONA bit is set, the corresponding port output becomes an open-drain driver capable of sinking current only.
    ANSELA = 0x00;
    WPUA =0x00;
    PORTA=0x00;

    //PORTC initialize
    TRISC = 0x03;//RC0;SCL RC1:SDA
    ODCONC =0x00;
    ANSELC=0x00;
    WPUC=0x00;
    PORTC=0x00;
    LATC =0x00;
    
//PPS init-----------------------    
    PPSLOCK = 0x55;
    PPSLOCK = 0xAA;
    PPSLOCKbits.PPSLOCKED = 0;
  
    //I2C RC0:SCL1 RC1:SDA1
    SSP1CLKPPS=0x10;
    SSP1DATPPS=0x11;
    RC0PPS=0x18;
    RC1PPS=0x19;
    TRISC0=1;
    TRISC1=1;
    
    PPSLOCK = 0x55;
    PPSLOCK = 0xAA;
    PPSLOCKbits.PPSLOCKED = 1;
//PPS re-Locked---------------------
}

void delay10ms(uint16_t num)
{
    do{
        __delay_ms(10);
        num--;
    }while(num>0);
}


uint8_t hpt=12;

//電流値表示
void SSD1306_Print(uint16_t ival)
{
    uint8_t page;
    char txt[30];
    
    page=1;
    sprintf(txt,"I:\n");
    SSD1306_Print6(page,hpt+0,txt);
    
    page=0;
    sprintf(txt,"%4d\n",ival);
    SSD1306_Print12(page,hpt+6*2+1,txt);
    sprintf(txt,"  \n");
    SSD1306_Print6(page,hpt+6*2+1+12*4+1,txt);
    sprintf(txt,"mA\n");
    SSD1306_Print6(page+1,hpt+6*2+1+12*4+1,txt);   
}

//シャント電圧表示
void SSD1306_PrintS(uint16_t sval, uint16_t cal)
{
    uint8_t page;
    char txt[30];
    
    page=2;
    sprintf(txt,"%6u\n",sval);
    SSD1306_Print6(page,hpt+0,txt);
    sprintf(txt,"%6u\n",cal);
    SSD1306_Print6(page,hpt+6*6+10,txt);
    
}


//電圧表示
void SSD1306_Print2(uint16_t ival)
{
    uint8_t page;
    char txt[30];
    
    page=4;
    sprintf(txt,"V:\n");
    SSD1306_Print6(page,hpt+0,txt);
    
    page=3;
    sprintf(txt,"%2ld.%02ld\n",ival/100L, ival%100L);
    SSD1306_Print12(page,hpt+6*2+1,txt);
    
    sprintf(txt,"V\n");
    SSD1306_Print6(page+1,hpt+6*2+1+12*5+1,txt);
}

//電力表示
void SSD1306_Print3(uint16_t ival)
{
    uint8_t page;
    char txt[30];
     
    
    page=7;
    sprintf(txt,"Pw:\n");
    SSD1306_Print6(page,hpt+0,txt);
    
    page=6;
    sprintf(txt,"%4ld.%ld\n",ival/10L,ival%10L);
    //sprintf(txt,"%6ld\n",ival);
    SSD1306_Print12(page,hpt+6*3+1,txt);
    
    sprintf(txt,"%c%c\n",unit[0],unit[1]);
    SSD1306_Print6(page+1,hpt+6*3+1+12*6
            +1,txt);
}
INA219.h
#ifndef INA219_H
#define	INA219_H

#ifdef	__cplusplus
extern "C" {
#endif
    
#include <xc.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "I2C_MSSP1.h"

    
//#define MaxCurrent1Amax
//#define  MaxCurrent3_2Amax
#define MaxCurrent3_2Amax2
   
uint8_t dec[5];
uint8_t unit[3];//??????
uint8_t u_digit;//???

uint8_t INA219add=0x80;

uint16_t INA219_RegRead(uint8_t _add, uint8_t _reg);


#ifdef	__cplusplus
}
#endif

#endif	/* INA219_H */
INA219.c

#include "INA219.h"

//*****************************************************
//INA219データ計算
//_add:INA219 I2Cスレーブアドレス
//_reg:INA219 レジスタアドレス
//呼び出したデータの種類によってLSB値を掛ける。
//*****************************************************
uint16_t INA219_RegRead(uint8_t _add, uint8_t _reg)
{
    uint16_t ltmp;
    uint32_t lval;
    
    ltmp=I2C1_b2Read(_add,_reg);
    
    switch(_reg)
    {   case 0x02://BusPower
            ltmp>>=3;//レジスタ3ビットはいらないのでシフト。
            ltmp*=4L;//LSB:4mV
            ltmp/=10;//表示調整
            unit[0]='V';
            break;
        case 0x03://Power
            lval = ltmp;

#ifdef MaxCurrent1Amax
            lval=lval*6L;//PowerLSB=1.960mW 小数点第1位まで求める。
                          //2mW×10倍しておく。
#endif

#ifdef MaxCurrent3_2Amax2
            lval=lval*20L;//PowerLSB=1.960mW 小数点第1位まで求める。
                          //2mW×10倍しておく。
#endif
            if(lval>10000)
            {//1000mW以上の時の液晶表示単位
                lval/=1000;
                unit[0]='W';
                unit[1]=' ';
            }
            else
            {//1000mW以下の時の液晶表示単位
                unit[0]='m';
                unit[1]='W';  
            }
            ltmp=lval;
            break;
        case 0x04://current
#ifdef MaxCurrent1Amax            
            lval=ltmp*30L;//LSB:98uA(MaxExpectedCurrent:1A)
#endif            
#ifdef MaxCurrent3_2Amax2
            lval=ltmp*98L;//LSB:98uA(MaxExpectedCurrent:3.2A)
#endif              
            ltmp=lval/1000L;
            //液晶表示単位をセット。
            unit[0]='m';
            unit[1]='A';
            
            break;
    }
    return ltmp;   
}


0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?