Linux i2c C-language example INA219 power monitoring chips

include <stdio.h>

include <stdlib.h>

include <linux/i2c-dev.h>

include <fcntl.h>

include <string.h>

include <sys/ioctl.h>

include <sys/types.h>

include <sys/stat.h>

include <unistd.h>

int fd;
int addr1 = 0x44;
int addr2 = 0x45;
char *i2cbus= "/dev/i2c-0";

unsigned char buf[32]; // Buffer for i2c data being read/written

int read_register(int addr, unsigned char reg, unsigned char mask, unsigned char sh)
{

    short value;

    if ((fd = open(i2cbus, O_RDWR)) < 0) {
            fprintf(stderr,"Failed to open i2c port\n");
            exit(1);
    }
   
    if (ioctl(fd, I2C_SLAVE, addr) < 0) {
            fprintf(stderr,"Unable to get bus access to talk to INA219 at %X\n",addr);
            exit(1);
    }

    buf[0] = reg;

    if ((write(fd, buf, 1)) != 1) {
            fprintf(stderr,"Error sending register address %d to %X\n",reg,addr);
            exit(1);
    }

    if (read(fd, buf, 2) != 2) {
            fprintf(stderr,"Unable to read from register %d on %X\n",reg,addr);
            exit(1);
    }

    close(fd);

    if (mask != 0 ) buf[1] &= mask;

    value = ( (buf[0] << 8) | buf[1]);

    if (sh != 0 ) return (int)(value << sh);
      else return (int)(value);

}

int read_register_trig(int addr, unsigned char reg, unsigned char mask, unsigned char sh)
{

    short value;

    if ((fd = open(i2cbus, O_RDWR)) < 0) {
            fprintf(stderr,"Failed to open i2c port\n");
            exit(1);
    }
   
    if (ioctl(fd, I2C_SLAVE, addr) < 0) {
            fprintf(stderr,"Unable to get bus access to talk to INA219 at %X\n",addr);
            exit(1);
    }

    // trigger conversion:
    buf[0] = 0;           // config reg
    buf[1] = 0b00001111;  // upper 8 bits
    buf[2] = 0b11111111;  // lower 8 bits

    if ((write(fd, buf, 3)) != 3) {
            fprintf(stderr,"Error writing to config register\n");
            exit(1);
    }

    usleep(68000);

    buf[0] = reg;

    if ((write(fd, buf, 1)) != 1) {
            fprintf(stderr,"Error sending register address %d to %X\n",reg,addr);
            exit(1);
    }

    if (read(fd, buf, 2) != 2) {
            fprintf(stderr,"Unable to read from register %d on %X\n",reg,addr);
            exit(1);
    }

    close(fd);

    if (mask != 0 ) buf[1] &= mask;

    value = ( (buf[0] << 8) | buf[1]);

    if (sh != 0 ) return (int)(value << sh);
      else return (int)(value);

}

void init_conf_cal(int addr, unsigned int Cal)
{

    if ((fd = open(i2cbus, O_RDWR)) < 0) {
            fprintf(stderr,"Failed to open i2c port\n");
            exit(1);
    }
   
    if (ioctl(fd, I2C_SLAVE, addr) < 0) {
            fprintf(stderr,"Unable to get bus access to talk to INA219 at %X\n",addr);
            exit(1);
    }
   
    // set config register

    // bit 15: (0) RESET
    // bit 14: (0) n/c
    // bit 13: (0) 0=16V range, 1=32V
    // bit 12/11: (01) PG1/PG0: Shunt voltage gain
    //           00 = 1, +/- 40mV fullscale
    //       ->  01 = 2, +/- 80mV fullscale  80mV/.01ohm = 8A FS
    //           10 = 4, +/-160mV fullscale
    //           11 = 8, +/-320mV fullscale
    // bits 10,9,8,7: (1111) BADC: bus ADC resolution, samples to average
    // bit 6,5,4,3:   (1111) SADC: shunt ADC resolution, samples to average
    // bits 2,1,0:    (111)  Op Mode: Shunt & Bus, continuous
    //                 011 = shunt & bus, triggered

    buf[0] = 0;           // config reg
    buf[1] = 0b00001111;  // upper 8 bits
    buf[2] = 0b11111111;  // lower 8 bits

    if ((write(fd, buf, 3)) != 3) {
            fprintf(stderr,"Error writing to config register\n");
            exit(1);
    }

    // CALIBRATION REGISTER  (REG 5)
    // =============================
    // VBUS_MAX   = 32V   (set above)
    // VSHUNT_MAX = 0.08V (gain 8)
    // RSHUNT     = 0.01 ohm

    // MaxPossible_I = VSHUNT_MAX / RSHUNT = 8.0A
    // MaxExpected_I = 8.0A, same

    // MinLSB = MaxExpected_I/32767 = .000244148
    // MaxLSB = MaxExpected_I/4096  = .001953125

    // CurrrentLSB = MinLSB for now = .00024414807580797753

    // Cal = trunc (0.04096 / (Current_LSB * RSHUNT))
    // Cal = 16776

    // Cal = 16776;

    buf[0] = 5;        // calibration register
    buf[1] = ((Cal & 0xFF00) >> 8);
    buf[2] = (Cal & 0xFF);

    if ((write(fd, buf, 3)) != 3) {
            fprintf(stderr,"Error writing to config register\n");
            exit(1);
    }

    // Calculate Power LSB:
    // PowerLSB = 20 * CurrentLSB
    // PowerLSB = .0048829615161595506 (4.89 mW per bit)
    //
    // Compute max current & shunt voltage values before overflow
    //
    // Max_Current_Overflow = min(CurrentLSB*32767,MaxPossible_I) = 8.0 A
    //
    // Max_ShuntVoltage = Max_Current_Overflow * RSHUNT = .08V
    //  (clamp to VSHUNT_MAX if greater)
    //
    // Compute max power
    // MaxPower = Max_Current_Overflow * VBUS_MAX
    // MaxPower = 8.0A * 32V = 256.0W

    close(fd);

}

main (int argc, char **argv) {

    int r,v;

    if ( (argc == 3) && (argv[1][0]=='-') && (argv[1][1]=='i') ) {
      init_conf_cal(addr1,atoi(argv[2]));
      init_conf_cal(addr2,atoi(argv[2]));
      fprintf(stderr,"Initialization complete\n");
    }
    else if ( (argc == 2) && (argv[1][0]=='-') && (argv[1][1]=='d') ) {
      r=0;
      printf("a%X r%d = %d",addr1,r,read_register_trig(addr1,r,0,0));
      putchar('\t');
      printf("a%X r%d = %d",addr2,r,read_register_trig(addr2,r,0,0));
      putchar('\n');
      for(r=1;r<=5;r++) {
            printf("a%X r%d = %d",addr1,r,read_register(addr1,r,0,0));
            putchar('\t');
            printf("a%X r%d = %d",addr2,r,read_register(addr2,r,0,0));
            putchar('\n');
      }
    }
    else if ( (argc == 2) && (argv[1][0]=='-') && (argv[1][1]=='v') ) {
            printf("V_a: %5.3f\tV_b: %5.3f\n",
             (float)read_register_trig(addr2,2,0xF8,0)*1/2000,
             (float)read_register_trig(addr1,2,0xF8,0)*1/2000);
    }
    else if ( (argc == 2) && (argv[1][0]=='-') && (argv[1][1]=='a') ) {
            printf("A_a: %5.3f\tA_b: %5.3f\n",
             (float)read_register_trig(addr2,1,0,2)*8/32767,
             (float)read_register_trig(addr1,1,0,2)*8/32767);
    }
    else if ( (argc == 2) && (argv[1][0]=='-') && (argv[1][1]=='A') ) {
            printf("A_a: %5.3f\tA_b: %5.3f\n",
             (float)read_register_trig(addr2,4,0,2)*2/32767,
             (float)read_register_trig(addr1,4,0,2)*2/32767);
    }
    else if ( ( argc == 1 ) || \
              ( (argc == 2) && (argv[1][0]=='-') && (argv[1][1]=='p') ) ) {
            printf("P_a: %5.3f\tP_b: %5.3f\n",
             (float)read_register_trig(addr2,3,0,0)*20*8/32767,
             (float)read_register_trig(addr1,3,0,0)*20*8/32767);
    }
    else if ( (argc == 2) && (argv[1][0]=='-') && (argv[1][1]=='w') ) {
            float v1,v2,a1,a2;
            char cf;
            v1=(float)read_register_trig(addr2,2,0xF8,0)*1/2000;
            v2=(float)read_register_trig(addr1,2,0xF8,0)*1/2000;
            a1=(float)read_register(addr2,4,0,2)*2/32767;
            a2=(float)read_register(addr1,4,0,2)*2/32767;
            if (a1 > 0 && a2 > 0) cf=(v1>v2 ? 'X' : 'x');
             else if (a1 > 0)     cf=(v1>v2 ? 'V' : 'v');
             else                 cf=(v1>v2 ? 'B' : 'b');
            printf("%4.2f%c %3.1f",
                    (v1>v2 ? v1 : v2), cf, (a1*v1 + a2*v2));
    }
    else if ( (argc == 2) && (argv[1][0]=='-') && (argv[1][1]=='W') ) {
            float v1,v2,p1,p2,a1,a2;
            v1=(float)read_register_trig(addr2,2,0xF8,0)*1/2000;
            v2=(float)read_register_trig(addr1,2,0xF8,0)*1/2000;
            a1=(float)read_register(addr2,4,0,2)*2/32767;
            a2=(float)read_register(addr1,4,0,2)*2/32767;
            p1=(float)read_register(addr2,3,0,0)*20*8/32767;
            p2=(float)read_register(addr1,3,0,0)*20*8/32767;
            printf("%4.2f%c %4.2f %4.2f [%4.2f %4.2f]",
                    (v1>v2 ? v1 : v2),
                    (v1>v2 ? 'V' : 'v'),
                    a1*v1,a2*v2,p1,p2);
    }
    else if ( (argc == 2) && (argv[1][0]>='0') && (argv[1][0]<='9') ) {
      r = atoi(argv[1]);
      if (r >= 0 && r <= 5) {
        printf("a%X r%d = %d",addr1,r,read_register_trig(addr1,r,0,0));
        putchar('\t');
        printf("a%X r%d = %d",addr2,r,read_register_trig(addr2,r,0,0));
        putchar('\n');
      }
      else {
        fprintf(stderr,"Invalid register.\n");
        exit(1);
      }
    }
    else {
      fprintf(stderr,"Usage: %s <-i | -d | -[vaApw] | reg_number, 0-5>\n",argv[0]);
      exit(1);
    }
    exit(0);

}

标签:none

已有 4 条评论

  1. markscat markscat

    您好
    請問一下,如果我的ic設定的位址是在40的話的話,是否要修改是否要修改addr1或addr2?

  2. markscat markscat

    您好:
    因為您的程式看來,是用兩顆來做測試,而且程式的控制比較複雜,所以我改寫了一下main的部份
    int main(int argc, char **argv)
    {
    float p1,a1;

    //v1=(float)read_register(addr1,2,0xF8,0)*1/2000;
    a1=(float)read_register(addr1,4,0,2)*2/32767;
    p1=(float)read_register(addr1,3,0,0)*20*8/32767;
    printf("%4.2f A, power= %4.2f w/n",a1,p1);
    exit(0);
    }
    現在我卡住的地方是,執行的時候會出現『Error sending register address 4 to 40』的訊息。

    我的ina219的位址是在40(我用i2ctools確認過),所以理論上i2c的位址是正確的,請問是否是因為我的樹莓派有什麼東西缺了,才導致我的執行上有問題?

    1. 估计程序有问题

添加新评论