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);
}
您好
請問一下,如果我的ic設定的位址是在40的話的話,是否要修改是否要修改addr1或addr2?
要的
您好:
因為您的程式看來,是用兩顆來做測試,而且程式的控制比較複雜,所以我改寫了一下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的位址是正確的,請問是否是因為我的樹莓派有什麼東西缺了,才導致我的執行上有問題?
估计程序有问题