说明书中bq4050的默认设备地址为0x16。
很多人做i2c的时候,是这样操作的: (0x16<<1)|0x01 ,通过这样的方式来设置读写位为1,也就是读取,但是不知道是我这个电池的问题还是什么的,说明书中的0x16这个地址位其实是包含了读写位的,也就是说写的地址是0x16,读的地址是0x17,如果左移的话,地址反而不对了。
更坑到我的是我用的atmel atmega 4809的芯片,直接调用系统的硬件i2c发送,会自动左移1位,也就是说,0x16发送出来变成0x2c了,那么这时候,就要反其道而行,先右移1位,变成0xb,然后调用系统的硬件i2c函数,发送出来就变成0x16了。
#define slave_adr 0x0b
i2c_error_t I2C_0_do_transfer(uint8_t adr, uint8_t *data, uint8_t size)
{
/* timeout is used to get out of twim_release, when there is no device connected to the bus*/
uint16_t timeout = I2C_TIMEOUT;
transfer_descriptor_t d = {data, size};
while (I2C_BUSY == I2C_0_open(slave_adr) && --timeout)
; // sit here until we get the bus..
if (!timeout)
return I2C_BUSY;
// This callback specifies what to do after the first write operation has completed
// The parameters to the callback are bundled together in the aggregate data type d.
I2C_0_set_data_complete_callback(I2C_0_read_handler, &d);
// If we get an address NACK, then try again by sending SLA+W
I2C_0_set_address_nack_callback(i2c_cb_restart_write, NULL);
// Transmit specified number of bytes
I2C_0_set_buffer((void *)&adr, 1);
// Start a Write operation
I2C_0_master_operation(false);
timeout = I2C_TIMEOUT;
while (I2C_BUSY == I2C_0_close() && --timeout)
; // sit here until finished.
if (!timeout)
return I2C_FAIL;
return I2C_NOERR;
}
uint16_t I2C_get_Capacity(void)
{
uint16_t value;
I2C_0_do_transfer(0x0D, read_data, 2);
value = read_data[1];
value <<= 8;
value += read_data[0];
return value;
}
uint16_t I2C_get_Voltage(void)
{
uint16_t value;
I2C_0_do_transfer(0x09, read_data, 2);
value = read_data[1];
value <<= 8;
value += read_data[0];
return value;
}
int16_t I2C_get_Current(void)
{
int16_t value;
I2C_0_do_transfer(0x0a, read_data, 2);
value = read_data[1];
value <<= 8;
value += read_data[0];
return value;
}
下面分析一下读取到的时序
电量Capacity
注:红色字体为master发送,蓝色字体为slave发送
0x16(写入) ack
0 0 0 1 0 1 1 0 0
0x0d(电量地址) ack
0 0 0 0 1 1 0 1 0
0x17(读取) ack
0 0 0 1 0 1 1 1 0
0x33(电量51%) ack
0 0 1 1 0 0 1 1 0
0x0(电量0%) nack
0 0 0 0 0 0 0 0 1
至此电量读取过程结束
电压Voltage
注:红色字体为master发送,蓝色字体为slave发送
0x16(写入) ack
0 0 0 1 0 1 1 0 0
0x09(电压地址) ack
0 0 0 0 1 0 0 1 0
0x17(读取) ack
0 0 0 1 0 1 1 1 0
0x73 ack
0 1 1 1 0 0 1 1 0
0x1c nack
0 0 0 0 0 0 0 0 1
至此电压读取过程结束
返回的数据位小端模式,即0x1c73,转换为10进制为7283,即7.283V
电流Current
注:红色字体为master发送,蓝色字体为slave发送
0x16(写入) ack
0 0 0 1 0 1 1 0 0
0x0A(电流地址) ack
0 0 0 0 1 0 1 0 0
0x17(读取) ack
0 0 0 1 0 1 1 1 0
0x1c ack
0 0 0 1 1 1 0 0 0
0xfd nack
1 1 1 1 1 1 0 1 1
至此电流读取过程结束
返回的数据位小端模式,即0xfd1c,转换为10进制为64796,难道电流有64.796A?
注意这个数是有符号数,是个负数,使用的是补码,先转化到反码为0xfd1b,再转换为原码为-740,所谓最终我们测到的电流是-740mA。
注意:负数是电池放电,正数是电池充电