电源管理芯片MAX17048驱动

电源管理芯片MAX17048驱动


最近调试MAX17048,做个简单的记录。
基于STM32H743

芯片功能

MAX17048为小尺寸、微功耗电池电量计,用于手持及便携产品的锂离子(Li+)电池。
MAX17048配置工作在单节锂电池,MAX17049配置工作在2节串联锂电池,两者都是标准I2C接口通讯。

电路

在这里插入图片描述

配置

打开图形化配置工具Cubemax,选择快速模式以支持400Khz,7Bit地址,开启中断,GPIO上拉
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

代码

/**
 *  @file Voltameter_Port.c
 *
 *  @date 2021-03-04
 *
 *  @author aron566
 *
 *  @copyright Copyright (c) 2021 aron566 <aron566@163.com>.
 *
 *  @brief 电池电量监控接口
 *
 *  @details 1、SCL RISE MIN KEEP 20ns
 *           2、SCL FALL MIN KEEP 20ns
 *           3、写: S. SAddr W. A. MAddr. A. Data0. A. Data1. A. P
 *           4、读: 先写S. SAddr W. A. MAddr. A 再读 Sr. SAddr R. A. Data0. A. Data1. N. P
 *           5、使用Fastmode 最高速率400Khz
 *
 *  @version V1.0
 */
#ifdef __cplusplus ///<use C compiler
extern "C" {
#endif
/** Includes -----------------------------------------------------------------*/
/* Private includes ----------------------------------------------------------*/
#include "main.h"
#include "Voltameter_Port.h"
/** Private typedef ----------------------------------------------------------*/
/** Private macros -----------------------------------------------------------*/
#define ENABLE_MAX17048_DEBUG   0/**< 启动打印调试*/
/*MAX17048设备I2C地址*/
#define DEV_ADDR                0x6C
/*MAX17048设备I2C写操作地址*/
#define DEV_ADDR_WRITE          (DEV_ADDR|0x00)
/*MAX17048设备I2C读操作地址*/
#define DEV_ADDR_READ           (DEV_ADDR|0x01)

/*MAX17048寄存器地址*/
#define REG_V_CELL              0x02
#define REG_SOC                 0x04
#define REG_MODE                0x06
#define REG_VERSION             0x08
#define REG_HIBRT               0x0A
#define REG_CONFIG              0x0C
#define REG_VALRT               0x14
#define REG_CRATE               0x16
#define REG_V_RESET             0x18
#define REG_STATUS              0x1A
        
#define REG_TABLE               0x40/**< REG RANGE:0x40 to 0x70*/
#define REG_TABLE_END           0x70
        
#define REG_CMD                 0xFE
        
/*16BIT位*/        
#define REG_BIT0                (1U<<0)
#define REG_BIT1                (1U<<1)
#define REG_BIT2                (1U<<2)
#define REG_BIT3                (1U<<3)
#define REG_BIT4                (1U<<4)
#define REG_BIT5                (1U<<5)
#define REG_BIT6                (1U<<6)
#define REG_BIT7                (1U<<7)
#define REG_BIT8                (1U<<8)
#define REG_BIT9                (1U<<9)
#define REG_BIT10               (1U<<10)
#define REG_BIT11               (1U<<11)
#define REG_BIT12               (1U<<12)
#define REG_BIT13               (1U<<13)
#define REG_BIT14               (1U<<14)
#define REG_BIT15               (1U<<15)
/** Private constants --------------------------------------------------------*/
/** Public variables ---------------------------------------------------------*/
extern I2C_HandleTypeDef hi2c1;
/** Private variables --------------------------------------------------------*/
static uint16_t Battery_Soc = 0;/**< 电池电量百分比*/
static uint16_t Battery_Voltage = 0;/**< 电池电压*/
static uint8_t Send_Val_Buf[2];
static uint8_t Reg_Val_Buf[2];
/** Private function prototypes ----------------------------------------------*/
#if ENABLE_MAX17048_DEBUG
static void Display_Alarm_Info(uint8_t Alarm_Value);
#endif
static void I2C_State_Reset(void);
static void Power_On_Reset(void);
static uint16_t Read_Vcell_Update(uint32_t Block_Time);
static uint16_t Read_Soc_Update(uint32_t Block_Time);
/** Private user code --------------------------------------------------------*/
/** Private application code -------------------------------------------------*/
/*******************************************************************************
*
*       Static code
*
********************************************************************************
*/
/**
  ******************************************************************
  * @brief   I2C 异常状态恢复
  * @param   [in]None.
  * @return  None.
  * @author  aron566
  * @version V1.0
  * @date    2021-03-09
  ******************************************************************
  */
static inline void I2C_State_Reset(void)
{
  __HAL_I2C_DISABLE(&hi2c1);
  HAL_Delay(1);
  __HAL_I2C_ENABLE(&hi2c1);
}

/**
  ******************************************************************
  * @brief   MAX17048 报警信息打印
  * @param   [in]None.
  * @return  None.
  * @author  aron566
  * @version V1.0
  * @date    2021-03-08
  ******************************************************************
  */
#if ENABLE_MAX17048_DEBUG
static void Display_Alarm_Info(uint8_t Alarm_Value)
{
  if(Alarm_Value & REG_BIT0)
  {
    printf("POWER ON IC NO CONFIG.\r\n");
  }
  if(Alarm_Value & REG_BIT1)
  {
    printf("VCELL HIGH THAN ALRT.VALRTMAX.\r\n");
  }
  if(Alarm_Value & REG_BIT2)
  {
    printf("VCELL LOW THAN ALRT.VALRTMIN.\r\n");
  }
  if(Alarm_Value & REG_BIT3)
  {
    printf("VOLTAGE RESET.\r\n");
  }
  if(Alarm_Value & REG_BIT4)
  {
    printf("SOC LOW THAN CONFIG.ATHD.\r\n");
  }
  if(Alarm_Value & REG_BIT5)
  {
    printf("SOC CHANGE VALUE ARRIVE %%1.\r\n");
  }
  if(Alarm_Value & REG_BIT6)
  {
    printf("ENABLE VOLTAGE RESET ALARM.\r\n");
  }
}
#endif
/**
  ******************************************************************
  * @brief   MAX17048 上电复位
  * @param   [in]None.
  * @return  None.
  * @author  aron566
  * @version V1.0
  * @date    2021-03-08
  ******************************************************************
  */
static void Power_On_Reset(void)
{
  /*复位上电*/
  uint8_t WriteData[3] = {REG_CMD, 0x54, 0x00};
  HAL_I2C_Master_Transmit(&hi2c1, DEV_ADDR_WRITE, WriteData, 3, 100);
  
  /*Wait*/
  HAL_Delay(100);
  
  /*快速启动*/
  WriteData[0] = REG_MODE;
  WriteData[1] = 0x00;
  WriteData[2] |= REG_BIT6;

  /*使能休眠模式*/
  WriteData[2] |= REG_BIT5;
  HAL_I2C_Master_Transmit(&hi2c1, DEV_ADDR_WRITE, WriteData, 3, 100);
}

/**
  ******************************************************************
  * @brief   清除MAX17048 报警状态
  * @param   [in]None.
  * @return  None.
  * @author  aron566
  * @version V1.0
  * @date    2021-03-04
  ******************************************************************
  */
static void Alarm_State_Reset(void)
{
  uint8_t RegData = 0;
  uint8_t RecData[2] = {0};
  uint8_t SendData[3] = {0};
  
  /*读取报警状态信息*/
  RegData = REG_STATUS;
  HAL_I2C_Master_Transmit(&hi2c1, DEV_ADDR_WRITE, &RegData, 1, 100);
  HAL_I2C_Master_Receive(&hi2c1, DEV_ADDR_READ, RecData, 2, 100);
#if ENABLE_MAX17048_DEBUG  
  printf("Status REG:%02X:VAL:%02X%02X.\r\n", RegData, RecData[0], RecData[1]);
  Display_Alarm_Info(RecData[0]);
#endif
  /*清除报警信息*/
  SendData[0] = RegData;
  SendData[1] = (RecData[0]&(~0x7F));
  SendData[2] = RecData[1];
  HAL_I2C_Master_Transmit(&hi2c1, DEV_ADDR_WRITE, SendData, 3, 100);
#if ENABLE_MAX17048_DEBUG  
  printf("Set Status REG:%02X:VAL:%02X%02X.\r\n", RegData, SendData[1], SendData[2]);
#endif
#if ENABLE_MAX17048_DEBUG  
  HAL_I2C_Master_Transmit(&hi2c1, DEV_ADDR_WRITE, &RegData, 1, 100);
  HAL_I2C_Master_Receive(&hi2c1, DEV_ADDR_READ, RecData, 2, 100);
  printf("After Status REG:%02X:VAL:%02X%02X.\r\n", RegData, RecData[0], RecData[1]);
#endif
  
  /*读取配置信息*/
  RegData = REG_CONFIG;
  HAL_I2C_Master_Transmit(&hi2c1, DEV_ADDR_WRITE, &RegData, 1, 100);
  HAL_I2C_Master_Receive(&hi2c1, DEV_ADDR_READ, RecData, 2, 100);
#if ENABLE_MAX17048_DEBUG  
  printf("Config REG:%02X:VAL:%02X%02X.\r\n", RegData, RecData[0], RecData[1]);
#endif
  /*设置报警阈值 BIT0-4 可设范围1-32% 设置10%则32-10*/
  RecData[1] = ((RecData[1]&0xE0)|(32-10));
  /*清除报警状态位 BIT5*/
  RecData[1] &= (~REG_BIT5);
  SendData[0] = RegData;
  SendData[1] = RecData[0];
  SendData[2] = RecData[1];
  HAL_I2C_Master_Transmit(&hi2c1, DEV_ADDR_WRITE, SendData, 3, 100);
#if ENABLE_MAX17048_DEBUG  
  printf("Set Config REG:%02X:VAL:%02X%02X.\r\n", RegData, SendData[1], SendData[2]);
#endif
#if ENABLE_MAX17048_DEBUG  
  HAL_I2C_Master_Transmit(&hi2c1, DEV_ADDR_WRITE, &RegData, 1, 100);
  HAL_I2C_Master_Receive(&hi2c1, DEV_ADDR_READ, RecData, 2, 100);
  printf("After Config REG:%02X:VAL:%02X%02X.\r\n", RegData, RecData[0], RecData[1]);
#endif

  /*读取版本信息*/
#if ENABLE_MAX17048_DEBUG
  RegData = REG_VERSION;
  HAL_I2C_Master_Transmit(&hi2c1, DEV_ADDR_WRITE, &RegData, 1, 100);
  HAL_I2C_Master_Receive(&hi2c1, DEV_ADDR_READ, RecData, 2, 100);
  printf("Version REG:%02X:VAL:%02X%02X.\r\n", RegData, RecData[0], RecData[1]);
#endif
}

/**
  ******************************************************************
  * @brief   读取MAX17048 Vcell电压数值 78.125uV/Vcell
  * @param   [in]Block_Time 阻塞读取时间
  * @return  电量数据
  * @author  aron566
  * @version V1.0
  * @date    2021-03-04
  ******************************************************************
  */
static uint16_t Read_Vcell_Update(uint32_t Block_Time)
{
  Send_Val_Buf[0] = REG_V_CELL;
  if(Block_Time == 0)
  {
    if(HAL_OK != HAL_I2C_Master_Transmit_IT(&hi2c1, DEV_ADDR_WRITE, Send_Val_Buf, 1))
    {
      return Battery_Voltage;
    }
  }
  else if(Block_Time > 0)
  {
    if(HAL_OK != HAL_I2C_Master_Transmit(&hi2c1, DEV_ADDR_WRITE, Send_Val_Buf, 1, Block_Time))
    {
      return Battery_Voltage;
    }
    if(HAL_OK != HAL_I2C_Master_Receive(&hi2c1, DEV_ADDR_READ, Reg_Val_Buf, 2, Block_Time))
    {
      return Battery_Voltage;
    }
    
    Battery_Voltage = (Reg_Val_Buf[0]<<8)+Reg_Val_Buf[1];
    Battery_Voltage = (uint16_t)(((double)Battery_Voltage * 78.125)/1000000);
    return Battery_Voltage;
  }
  return Battery_Voltage;
}

/**
  ******************************************************************
  * @brief   读取MAX17048 SOC(Battery state of charge)电量数值 1%/256
  * @param   [in]Block_Time 阻塞读取时间
  * @return  电量数据
  * @author  aron566
  * @version V1.0
  * @date    2021-03-04
  ******************************************************************
  */
static uint16_t Read_Soc_Update(uint32_t Block_Time)
{
  Send_Val_Buf[0] = REG_SOC;
  if(Block_Time == 0)
  {
    if(HAL_OK != HAL_I2C_Master_Transmit_IT(&hi2c1, DEV_ADDR_WRITE, Send_Val_Buf, 1))
    {
      return Battery_Soc;
    }
  }
  else if(Block_Time > 0)
  {
    if(HAL_OK != HAL_I2C_Master_Transmit(&hi2c1, DEV_ADDR_WRITE, Send_Val_Buf, 1, Block_Time))
    {
      I2C_State_Reset();
      return Battery_Soc;
    }
    if(HAL_OK != HAL_I2C_Master_Receive(&hi2c1, DEV_ADDR_READ, Reg_Val_Buf, 2, Block_Time))
    {
      return Battery_Soc;
    }
    uint16_t Battery_Soc_Temp = (Reg_Val_Buf[0]<<8) + Reg_Val_Buf[1];
    Battery_Soc_Temp /= 256;
    Battery_Soc = Battery_Soc_Temp > 100?100:Battery_Soc_Temp;
    return Battery_Soc;
  }
  return Battery_Soc;
}

/** Public application code --------------------------------------------------*/
/*******************************************************************************
*
*       Public code
*
********************************************************************************
*/
/**
  ******************************************************************
  * @brief   I2C发送完成回调
  * @param   [in]None.
  * @return  None.
  * @author  aron566
  * @version V1.0
  * @date    2021-03-04
  ******************************************************************
  */
void Voltameter_Port_I2C_MasterTxCpltCallback(void)
{
  /*TODO:READ*/
  HAL_I2C_Master_Receive_IT(&hi2c1, DEV_ADDR_READ, Reg_Val_Buf, 2);
}

/**
  ******************************************************************
  * @brief   I2C接收完成回调
  * @param   [in]None.
  * @return  None.
  * @author  aron566
  * @version V1.0
  * @date    2021-03-04
  ******************************************************************
  */
void Voltameter_Port_I2C_MasterRxCpltCallback(void)
{
  /*TODO:UPDATE VAL*/
  if(Send_Val_Buf[0] == REG_V_CELL)
  {
    uint16_t Battery_Voltage_Temp = (Reg_Val_Buf[0]<<8)+Reg_Val_Buf[1];
    Battery_Voltage_Temp = (uint16_t)(((double)Battery_Voltage_Temp * 78.125)/1000000);
    Battery_Voltage = Battery_Voltage_Temp;
  }
  else if(Send_Val_Buf[0] == REG_SOC)
  {
    uint16_t Battery_Soc_Temp = (Reg_Val_Buf[0]<<8) + Reg_Val_Buf[1];
    Battery_Soc_Temp /= 256;
    Battery_Soc = Battery_Soc_Temp > 100?100:Battery_Soc_Temp;
  }
}

/**
  ******************************************************************
  * @brief   获取电池电量及电压信息
  * @param   [in]None
  * @return  电量数据
  * @author  aron566
  * @version V1.0
  * @date    2021-03-04
  ******************************************************************
  */
uint16_t Voltameter_Port_Get_Battery_Electric_Quantity(void)
{
  Read_Soc_Update(10);
  Read_Vcell_Update(0);
  return Battery_Soc;
}

/**
  ******************************************************************
  * @brief   获取电池充电状态
  * @param   [in]None
  * @return  1 为充电状态
  * @author  aron566
  * @version V1.0
  * @date    2021-03-04
  ******************************************************************
  */
uint8_t Voltameter_Port_Get_Battery_Charge_State(void)
{
  if(HAL_GPIO_ReadPin(BAT_STAT_GPIO_Port, BAT_STAT_Pin) == GPIO_PIN_SET)
  {
    return 1;
  }
  else
  {
    return 0;
  }
}

/**
  ******************************************************************
  * @brief   MAX17048 休眠设置
  * @param   [in]Sleep_En 睡眠使能.
  * @return  None.
  * @author  aron566
  * @version V1.0
  * @date    2021-07-07
  ******************************************************************
  */
void Voltameter_Port_OnOff_Sleep(bool Sleep_En)
{ 
  uint8_t RegData = 0;
  uint8_t RecData[2] = {0};
  uint8_t SendData[3] = {0};

  /*读取配置信息*/
  RegData = REG_CONFIG;
  HAL_I2C_Master_Transmit(&hi2c1, DEV_ADDR_WRITE, &RegData, 1, 100);
  HAL_I2C_Master_Receive(&hi2c1, DEV_ADDR_READ, RecData, 2, 100);
#if ENABLE_MAX17048_DEBUG  
  printf("Config REG:%02X:VAL:%02X%02X.\r\n", RegData, RecData[0], RecData[1]);
#endif

  SendData[1] = RegData;
  SendData[1] = RecData[0];
  SendData[2] = RecData[1];

  if(Sleep_En == true)
  {
    /*进入休眠 config.sleep = 1*/
    SendData[1] |= REG_BIT7;
  }
  else
  {
    /*退出休眠 config.sleep = 0*/
    SendData[1] &= ~REG_BIT7;
  }

  HAL_I2C_Master_Transmit(&hi2c1, DEV_ADDR_WRITE, SendData, 3, 100);
}

/**
  ******************************************************************
  * @brief   电池监控接口初始化
  * @param   [in]None
  * @return  None.
  * @author  aron566
  * @version V1.0
  * @date    2021-03-04
  ******************************************************************
  */
void Voltameter_Port_Init(void)
{
  /*上电复位MAX17048*/
  Power_On_Reset();
  
  /*报警复位*/
  Alarm_State_Reset();
}

#ifdef __cplusplus ///<end extern c
}
#endif
/******************************** End of file *********************************/

关于电量补偿

芯片带配置温补的区域,不过温度检测的区域为电池温度,可能条件不允许。

#define RCOMP0                  0x97/**< 温度补偿值*/
static int8_t Rcomp = RCOMP0;
/**
  ******************************************************************
  * @brief   温度补偿
  * @param   [in]Temperatur 电池温度.
  * @return  None.
  * @author  aron566
  * @version V1.0
  * @date    2021-04-16
  ******************************************************************
  */
void MAX17048_Driver_Compensate(float Temperature)
{
  uint8_t RegData = 0;
  uint8_t RecData[2] = {0};
  uint8_t SendData[3] = {0};
  
  if(Temperature > 20) 
  {
    Rcomp = (int8_t)(RCOMP0 + (Temperature - 20) * -0.5);
  }
  else 
  {
    Rcomp = (int8_t)(RCOMP0 + (Temperature - 20) * -5.0);
  }
  
  /*读取配置数据*/
  RegData = REG_CONFIG;
  HAL_I2C_Master_Transmit(MAX17048_I2C_HANDLE, DEV_ADDR_WRITE, &RegData, 1, 100);
  HAL_I2C_Master_Receive(MAX17048_I2C_HANDLE, DEV_ADDR_READ, RecData, 2, 100);
  
  /*设置温度补偿RCOMP*/
  SendData[0] = RegData;
  SendData[1] = (uint8_t)Rcomp;
  SendData[2] = RecData[1];
  HAL_I2C_Master_Transmit(MAX17048_I2C_HANDLE, DEV_ADDR_WRITE, SendData, 3, 100);
}

手动补偿90%-100%电量区域

/*充电耗时记录*/
typedef struct rectification
{
  uint32_t Start_Time_Sec;
  // uint32_t End_Time_Sec;
  // uint32_t Next_Time_Sec;
  // uint32_t Elapsed;
  uint16_t Compensation_Soc;
}RECTIFICATION_Typedef_t;

/*设备参考实测功率*/
#define DEVICE_REF_POWER        150   /**< 150mA/h*/
#define BATTERY_CAPACITY        1000  /**< 1000mAh*/
#define CAN_USE_MIN_TOTAL       (BATTERY_CAPACITY*60/DEVICE_REF_POWER)

/*电量时间补偿记录*/
static RECTIFICATION_Typedef_t E_Record[11] = {0};

/**
  ******************************************************************
  * @brief   修正补偿MAX17048 SOC(Battery state of charge)电量数值
  * @param   [in]Current_Soc 当前电量数值
  * @return  修正后电量数据
  * @author  aron566
  * @version V1.0
  * @date    2021-04-22
  ******************************************************************
  */
static uint16_t Soc_Compensation(uint16_t Current_Soc)
{
  static uint16_t last_soc_val = 0;
  uint16_t range_num = Current_Soc - 90;

  /*无需补偿*/
  if(Current_Soc == 100)
  {
    return Current_Soc;
  }

  /*充电中进行补偿运算*/
  if(last_soc_val != Current_Soc && Current_Soc >= 90 && MAX17048_Driver_Get_Battery_Charge_State() == 1)
  {
    E_Record[range_num].Start_Time_Sec = Timer_Port_Get_Current_Time(TIMER_SEC);
    E_Record[range_num].Compensation_Soc = Current_Soc;
    last_soc_val = Current_Soc;
    return Current_Soc;
  }

  if(last_soc_val == Current_Soc && Current_Soc >= 90 && MAX17048_Driver_Get_Battery_Charge_State() == 1)
  {
    /*电量值在90%区域,补偿*/
    if(range_num < 2)
    {
      if((Timer_Port_Get_Current_Time(TIMER_SEC) - E_Record[range_num].Start_Time_Sec) > 60*30)
      {
        E_Record[range_num].Start_Time_Sec = Timer_Port_Get_Current_Time(TIMER_SEC);
        E_Record[range_num].Compensation_Soc += 1;
      }
    }
    else
    {
      uint32_t ref_time = E_Record[range_num].Start_Time_Sec - E_Record[range_num-1].Start_Time_Sec;
      uint32_t elapsed_time = Timer_Port_Get_Current_Time(TIMER_SEC) - E_Record[range_num].Start_Time_Sec;
      if(elapsed_time > ref_time && elapsed_time > 2*ref_time)
      {
        E_Record[range_num].Start_Time_Sec = Timer_Port_Get_Current_Time(TIMER_SEC);
        E_Record[range_num-1].Start_Time_Sec = E_Record[range_num].Start_Time_Sec - ref_time;
        E_Record[range_num].Compensation_Soc += 1;
      }
    }
    E_Record[range_num].Compensation_Soc = E_Record[range_num].Compensation_Soc >= 100?100:E_Record[range_num].Compensation_Soc;
    return E_Record[range_num].Compensation_Soc;
  }

  /*电量值在90%区域,放电电量控制*/
  if(Current_Soc >= 90 && MAX17048_Driver_Get_Battery_Charge_State() == 0)
  {
    /*属修正值*/
    if(E_Record[range_num].Compensation_Soc > Current_Soc)
    {
      /*计算耗电时间*/
      uint32_t elapsed_time_min = (Timer_Port_Get_Current_Time(TIMER_SEC) - E_Record[range_num].Start_Time_Sec)/60;
      float pow = (float)elapsed_time_min/(float)CAN_USE_MIN_TOTAL;
      E_Record[range_num].Compensation_Soc = (uint16_t)((float)E_Record[range_num].Compensation_Soc - (100.f * pow));
      E_Record[range_num].Compensation_Soc = E_Record[range_num].Compensation_Soc < Current_Soc?Current_Soc:E_Record[range_num].Compensation_Soc;
      return E_Record[range_num].Compensation_Soc;
    }
  }
  return Current_Soc;
}
  • 8
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 25
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

aron566

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值