举个栗子~位操作到底有什么用【库仑计芯片MAX17043】

2023-12-29 13:41:58

首先吐槽各个平台在卖的五花八门的库仑计芯片EV board,前后试了估计有4家不同的货,终于DFRobot给出最稳定也是最符合MAX17043说明书描述的效果。

本篇继续水,描述一下位操作的一个普遍用法,就是读写各类测量芯片。此处就拿MAX17043举个例子。先流水账黄色箭头,再叨叨两句print。

整体代码:

'''!
  @file DFRobot_MAX17043.py
  @copyright   Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
  @license     The MIT License (MIT)
  @author [ouki.wang](ouki.wang@dfrobot.com)
  @version  V1.0
  @date  2018-4-14
  @url https://github.com/DFRobot/DFRobot_MAX17043
'''
import time
from machine import I2C, Pin
## Get I2C bus
i2c = I2C(scl = Pin(1), sda = Pin(0), freq=400000, id=0)

MAX17043_ADDR = 0x36 # may regard it as api address for read/write on the max17043
MAX17043_VCELL = 0x02
MAX17043_SOC = 0x04
MAX17043_MODE = 0x06
MAX17043_VERSION = 0x08
MAX17043_CONFIG = 0x0c
MAX17043_COMMAND = 0xfe

class DFRobot_MAX17043():  
  def __init__(self):
    '''!
      @brief create MAX17043 object
      @return MAX17043 object
    '''
    pass
  def begin(self):
    '''!
      @brief MAX17043 begin and test moudle
      @return initialization result:
      @retval 0     successful
      @retval -1     faild
    '''
    self._write16(MAX17043_COMMAND, 0x5400)
    time.sleep(0.01)
    if self._read16(MAX17043_CONFIG) == 0x971c:
      self._write16(MAX17043_MODE, 0x4000)  # 开始quick start mode
      time.sleep(0.01)
      self._write16(MAX17043_CONFIG, 0x9700)
      return 0
    else:
      return -1      
  def read_voltage(self):
    '''!
      @brief read battery voltage in mV
      @return voltage in mV
    '''
    return (1.25 * (self._read16(MAX17043_VCELL) >> 4))
  def read_percentage(self):
    '''!
      @brief read battery remaining capacity in percentage
      @return battery remaining capacity in percentage
    '''
    tmp = self._read16(MAX17043_SOC)
    return ((tmp >> 8) + 0.003906 * (tmp & 0x00ff)) 
  def _write16(self, reg, dat):
    buf = bytearray(2)
    buf[0] = dat >> 8
    buf[1] = dat & 0x00ff
    i2c.writeto_mem(MAX17043_ADDR, reg, buf)    
  def _read16(self, reg):
    buf = i2c.readfrom_mem(MAX17043_ADDR, reg, 2)
    return ((buf[0] << 8) | buf[1])  

gauge = DFRobot_MAX17043()
rslt = gauge.begin()  
while rslt != 0:
  print('gauge begin failed')
  time.sleep(2)
  rslt = gauge.begin()
print('gauge begin successful')
while True:
  time.sleep(2)
  print('voltage: ' + str(gauge.read_voltage()) + 'mV')
  print('percentage: ' + str(round(gauge.read_percentage(), 2)) + '%')

黄色箭头,执行顺序,首先初始化一个对应对象名为gauge,然后查看芯片状态rslt。

gauge = DFRobot_MAX17043()
rslt = gauge.begin() ?
while rslt != 0:
? print('gauge begin failed')
? time.sleep(2)
? rslt = gauge.begin()
print('gauge begin successful')

# 进入begin函数:

? def begin(self):
? ? '''!
? ? ? @brief MAX17043 begin and test moudle
? ? ? @return initialization result:
? ? ? @retval 0 ? ? successful
? ? ? @retval -1 ? ? faild
? ? '''
? ? self._write16(MAX17043_COMMAND, 0x5400)
? ? time.sleep(0.01)
? ? if self._read16(MAX17043_CONFIG) == 0x971c:
? ? ? self._write16(MAX17043_MODE, 0x4000) ?# 开始quick start mode
? ? ? time.sleep(0.01)
? ? ? self._write16(MAX17043_CONFIG, 0x9700)
? ? ? return 0
? ? else:
? ? ? return -1

begin函数干的活,在说明书里的文字描述,

首先把0x5400,写到了0xFE的位置。根据POR的描述:

Power-On Reset (POR)

Writing a value of 5400h to the COMMAND register caus- es the MAX17043/MAX17044 to completely reset as if power had been removed. The reset occurs when the last bit has been clocked in. The IC does not respond with an I2C ACK after this command sequence.

接下来检查CONFIG这个地址的状态,是不是拿到0x971C。拿不到这个值,说明芯片状态异常,不适合读数。

CONFIG Register

The CONFIG register compensates the ModelGauge algorithm, controls the alert interrupt feature, and forces the IC into Sleep mode through software. The format of CONFIG is shown in Figure 5.

CONFIG

CONFIG is an 8-bit value that can be adjusted to opti- mize IC performance for different lithium chemistries or different operating temperatures. Contact Maxim for instructions for optimization. The power-up default value for CONFIG is 97h.

所以0x9710应该是睡眠模式,我们要打开它,所以begin函数的最后,改写了0x9710变为0x9700(the power-up default value);

那么这时候芯片开始正式工作了。

接下来再过第一句简单的print,

print('voltage: ' + str(gauge.read_voltage()) + 'mV') #找到read_voltage看看它忙啥。

? def read_voltage(self):
? ? '''!
? ? ? @brief read battery voltage in mV
? ? ? @return voltage in mV
? ? '''
? ? return (1.25 * (self._read16(MAX17043_VCELL) >> 4)) #继续找_read16

? def _read16(self, reg):
? ? buf = i2c.readfrom_mem(MAX17043_ADDR, reg, 2) #继续找i2c.readfrom_mem
? ? return ((buf[0] << 8) | buf[1])?

#来自class I2C – a two-wire serial protocol — MicroPython latest documentation

i2c.readfrom_mem(42, 8, 3)      
# read 3 bytes from memory of peripheral 42,
#   starting at memory-address 8 in the peripheral

所以这里就是在0x36这个元器件的读写口,第2个寄存器地址(也就是VCELL),读取2个bytes;可视化一下它拿到了啥?

VCELL Register

Battery voltage is measured at the CELL pin input with respect to GND over a 0 to 5.00V range for the MAX17043 and 0 to 10.00V for the MAX17044 with resolutions of 1.25mV and 2.50mV, respectively. The A/D calculates the average cell voltage for a period of 125ms after IC POR and then for a period of 500ms for every cycle afterwards. The VCELL register requires 500ms to update after exiting Sleep mode. The result is placed in the VCELL register at the end of each conver- sion period. Figure 3 shows the VCELL register format.

接下来为何要做这些个数据位操作应该就是这个芯片的算法专利部分,datasheet里面是不提的。

#出处:How does the Android estimate the battery level without a current sensor? - Android Enthusiasts Stack Exchange

Battery level estimation is usually performed by a special “fuel gauge” chip; different phone models use different chips. E.g., Samsung GT-I8150 (Galaxy W), according to the?kernel config, uses the?Maxim MAX17043?chip, which, according to?its datasheet, does not have any inputs to measure the current?— it has only a battery voltage sensor. According to the manufacturer's description, this chip uses “a sophisticated Li+ battery-modeling scheme, called ModelGauge? to track the battery’s relative state-of-charge (SOC) continuously over a widely varying charge/discharge profile”. Some information is available in the datasheet, but details of this “ModelGauge” scheme do not seem to be publicly available.

大概就干了这么个事儿:

注意print出来的都是十进制数字。

实际运算就是:

CE: 11001110

B0: 10110000

CE << 8: 1100111000000000

B0:? ? ? ? ? 0000000010110000

或操作下,

1100111010110000

十进制下,它就是52912

接下来拿着这个2进制数字,继续右移4位,>>4,就是扔掉4位二进制的位置,得到

0000110011101011。

这个数字在10进制里面是3307。

拿着3307去乘以resolution(1.25mv) 所谓的精度,得到了电压。

文章来源:https://blog.csdn.net/u011410413/article/details/135281248
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。