MAX17043/MAX17044为结构紧凑、低成本、主机侧电量计,用于手持及便携产品的锂离子(Li+)电池的电量计量。MAX17043配置为单节锂电池计量,MAX17044配置为两节2S电池组计量。
MAX17043/MAX17044采用成熟的Li+电池建模方案(称为ModelGauge™),在整个充/放电过程中连续跟踪电池的相对充电状态(SOC)。与传统的电量计不同,ModelGauge算法省去了电池的再学习过程以及外部检流电阻。器件提供温度补偿,使得µC与器件之间的交互操作降至最少。
需要注意的是,MAX17043仅支持单节锂电池计量或者锂电池的并联计量,常见的18650单节或者并联多节都是可以的。MAX17043不带电池保护功能,所以在18650锂电池的输出端需要先接锂电池保护板,再将保护板的输出接到MAX17043上。
max17043_iic.h
#ifndef __MAX17043_IIC_H_
#define __MAX17043_IIC_H_
#include <STC8.H>
#define MAX17043_SCL P43
#define MAX17043_SDA P44
void MAX17043_IIC_Start();
void MAX17043_IIC_Stop();
void MAX17043_IIC_WriteACK(unsigned char ack);
unsigned char MAX17043_IIC_WaitACK();
void MAX17043_IIC_WriteByte(unsigned char wdata);
unsigned char MAX17043_IIC_ReadByte();
#endif
max17043_iic.c
#include "max17043_iic.h"
#include "intrins.h"
static void MAX17043_Delay()
{
unsigned char i;
_nop_();
_nop_();
i = 20;
while(--i);
}
void MAX17043_IIC_Start()
{
MAX17043_SDA = 1;
MAX17043_SCL = 1;
MAX17043_Delay();
MAX17043_SDA = 0;
MAX17043_Delay();
MAX17043_SCL = 0;
}
void MAX17043_IIC_Stop()
{
MAX17043_SDA = 0;
MAX17043_SCL = 0;
MAX17043_Delay();
MAX17043_SCL = 1;
MAX17043_Delay();
MAX17043_SDA = 1;
MAX17043_Delay();
}
void MAX17043_IIC_WriteACK(unsigned char ack)
{
MAX17043_SDA = ack;
MAX17043_Delay();
MAX17043_SCL = 1;
MAX17043_Delay();
MAX17043_SCL = 0;
}
unsigned char MAX17043_IIC_WaitACK()
{
unsigned char errtime = 50;
MAX17043_Delay(); /*读ACK*/
MAX17043_SCL = 1;
while(MAX17043_SDA)
{
errtime--;
if(!errtime)
{
MAX17043_IIC_Stop();
return 0;
}
}
MAX17043_SCL = 0;
MAX17043_Delay();
return 1;
}
void MAX17043_IIC_WriteByte(unsigned char wdata)
{
unsigned char i;
for(i=0; i<8; i++)
{
MAX17043_SDA = wdata&0x80;
wdata <<= 1;
MAX17043_SCL = 1;
MAX17043_Delay();
MAX17043_SCL = 0;
}
}
unsigned char MAX17043_IIC_ReadByte()
{
unsigned char i, bytedata;
MAX17043_SDA = 1;
for(i=0; i<8; i++)
{
MAX17043_SCL = 1;
bytedata <<= 1;
bytedata |= MAX17043_SDA;
MAX17043_SCL = 0;
MAX17043_Delay();
}
return bytedata;
}
max17043.h
#ifndef __MAX17043_H_
#define __MAX17043_H_
#define MAX17043_WRITE_ADDR 0x6C
#define MAX17043_READ_ADDR 0x6D
#define MAX17043_VCELL_MSB 0x02
#define MAX17043_VCELL_LSB 0x03
#define MAX17043_SOC_MSB 0x04
#define MAX17043_SOC_LSB 0x05
#define MAX17043_MODE_MSB 0x06
#define MAX17043_MODE_LSB 0x07
#define MAX17043_VERSION_MSB 0x08
#define MAX17043_VERSION_LSB 0x09
#define MAX17043_CONFIG_MSB 0x0C
#define MAX17043_CONFIG_LSB 0x0D
#define MAX17043_COMMAND_MSB 0xFE
#define MAX17043_COMMAND_LSB 0xFF
#define MAX17043_ALT P32
#define MAX17043_QST P40
float MAX17043_GetBatteryPercent();
void MAX17043_QuickStart();
void MAX17043_EnterSleepMode();
void MAX17043_Restart();
void MAX17043_ClearAlert();
void MAX17043_SetAlertThreshold(unsigned char threshold);
#endif
max17043.c
#include "max17043.h"
#include "max17043_iic.h"
#include "debug.h"
#include "intrins.h"
static void MAX17043_Delayms(unsigned int ms) //@24.000MHz
{
unsigned char i, j;
while(ms)
{
_nop_();
i = 32;
j = 40;
do
{
while (--j);
} while (--i);
ms--;
}
}
// 写寄存器,MAX17043写入的时候地址会自动增,所以可以连续写
// addr:芯片寄存器起始地址
// buf:写数组值
// count:写的长度
// lastBitAck: 最后写的字节写完之后,主机是否发送应答
//
// 返回:0--写入失败,1--写入成功
static unsigned char MAX17043_WriteReg(unsigned char addr, unsigned char *buf, unsigned char count, unsigned char lastBitAck)
{
unsigned char ret;
unsigned char i;
MAX17043_IIC_Start();
MAX17043_IIC_WriteByte(MAX17043_WRITE_ADDR);
ret = MAX17043_IIC_WaitACK();
if(!ret)
{
Debug_UartSendStr("MAX17043: Write AddrCMD error, device not ack!\r\n");
return 0;
}
MAX17043_IIC_WriteByte(addr);
ret = MAX17043_IIC_WaitACK();
if(!ret)
{
Debug_UartSendStr("MAX17043: Write Addr error, device not ack!\r\n");
return 0;
}
for(i=0; i<count; i++)
{
MAX17043_IIC_WriteByte(buf[i]); /*写数据*/
if(i < count-1 || lastBitAck)
{
ret = MAX17043_IIC_WaitACK();
if(!ret)
{
Debug_UartSendStr("MAX17043: Write data error, device not ack!\r\n");
return 0;
}
}
}
MAX17043_IIC_Stop();
return 1;
}
// 读寄存器,MAX17043读取的时候地址会自动增,所以可以连续读
// addr:芯片寄存器起始地址
// buf:读取存放数组
// count:读的长度
//
// 返回:0--读取失败,1--读取成功
static unsigned char MAX17043_ReadReg(unsigned char address, unsigned char * buf, unsigned char count) /*多字节*/
{
unsigned char ret;
unsigned char i;
MAX17043_IIC_Start();
MAX17043_IIC_WriteByte(MAX17043_WRITE_ADDR); //写命令
ret = MAX17043_IIC_WaitACK();
if(!ret)
{
Debug_UartSendStr("MAX17043: Write AddrCMD error, device not ack!\r\n");
return 0;
}
MAX17043_IIC_WriteByte(address); //写地址
ret = MAX17043_IIC_WaitACK();
if(!ret)
{
Debug_UartSendStr("MAX17043: Write AddrCMD error, device not ack!\r\n");
return 0;
}
MAX17043_IIC_Start();
MAX17043_IIC_WriteByte(MAX17043_READ_ADDR); //读命令
ret = MAX17043_IIC_WaitACK();
if(!ret)
{
Debug_UartSendStr("MAX17043: Write ReadCMD error, device not ack!\r\n");
return 0;
}
for(i=0; i<count; i++)
{
*buf++ = MAX17043_IIC_ReadByte();
if(i < count-1)
{
MAX17043_IIC_WriteACK(0);
}
else
{
MAX17043_IIC_WriteACK(1);
}
}
MAX17043_IIC_Stop();
return 1;
}
// 获取百分比单位的电池剩余电量
float MAX17043_GetBatteryPercent()
{
unsigned char buf[2] = {0};
float percent = 0.0;
MAX17043_ReadReg(MAX17043_SOC_MSB, buf, sizeof(buf));
percent = buf[0] + buf[1]/256.0; // buf[0]是1%精度的剩余电量
// buf[1]是1/256%精度的剩余电量
return percent;
}
// 快速启动
// 这里使用了硬件直接在QST引脚给上升沿的方式
// 也可以向MAX17043写寄存器的方式实现,参考数据手册
void MAX17043_QuickStart()
{
MAX17043_QST = 0;
MAX17043_Delayms(2);
MAX17043_QST = 1;
MAX17043_Delayms(2);
}
// 进入睡眠模式
// 这里将SCL和SDA拉低2.5s进入睡眠模式
// 同样也可以写寄存器使之进入睡眠模式
void MAX17043_EnterSleepMode()
{
MAX17043_SCL = 0;
MAX17043_SDA = 0;
MAX17043_Delayms(2600);
}
// 重启,效果和断电重启一样
void MAX17043_Restart()
{
unsigned char buf[2] = {0x00, 0x54};
// 最后一位写入的时候,MAX17043是不应答的,需要注意
MAX17043_WriteReg(MAX17043_COMMAND_MSB, buf, sizeof(buf), 0);
}
// 设置电量警报阈值
// threshold:整数百分比单位的阈值,范围是32~1,也就是32%~1%之间
void MAX17043_SetAlertThreshold(unsigned char threshold)
{
unsigned char buf[2] = {0x97, 0x1C};
if(threshold > 0x1f) // 如果阈值大于32%,那么限制成32%
{
threshold = 0x1f;
}
buf[1] = (0x1F - threshold) | 0x20; // 设置成寄存器格式,并打开中断
// 最后一位写入的时候,MAX17043会应答
MAX17043_WriteReg(MAX17043_CONFIG_MSB, buf, sizeof(buf), 1);
}
// 清除阈值电量中断标志位
void MAX17043_ClearAlert()
{
unsigned char buf[2] = {0x97, 0x1C};
MAX17043_ReadReg(MAX17043_CONFIG_MSB, buf, sizeof(buf));
buf[1] &= 0xDF;
MAX17043_WriteReg(MAX17043_CONFIG_MSB, buf, sizeof(buf), 1);
}