#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 电源管理模块(INA226) 提供电压、电流监测和充电状态检测 """ import config from logger_manager import logger_manager def write_register(reg, value): """写入INA226寄存器""" from hardware import hardware_manager data = [(value >> 8) & 0xFF, value & 0xFF] hardware_manager.bus.writeto_mem(config.INA226_ADDR, reg, bytes(data)) def read_register(reg): """读取INA226寄存器""" from hardware import hardware_manager data = hardware_manager.bus.readfrom_mem(config.INA226_ADDR, reg, 2) return (data[0] << 8) | data[1] def init_ina226(): """初始化 INA226 芯片:配置模式 + 校准值""" write_register(config.REG_CONFIGURATION, 0x4527) write_register(config.REG_CALIBRATION, config.CALIBRATION_VALUE) def get_bus_voltage(): """读取总线电压(单位:V)""" raw = read_register(config.REG_BUS_VOLTAGE) return raw * 1.25 / 1000 def get_current(): """ 读取电流(单位:mA) 正数表示充电,负数表示放电 INA226 电流计算公式: Current = (Current Register Value) × Current_LSB Current_LSB = 0.001 × CALIBRATION_VALUE / 4096 """ try: raw = read_register(config.REG_CURRENT) # INA226 电流寄存器是16位有符号整数 # 最高位是符号位:0=正(充电),1=负(放电) # 计算 Current_LSB(根据 CALIBRATION_VALUE) current_lsb = 0.001 * config.CALIBRATION_VALUE / 4096 # 单位:A # 处理有符号数:如果最高位为1,转换为负数 if raw & 0x8000: # 最高位为1,表示负数(放电) signed_raw = raw - 0x10000 # 转换为有符号整数 else: # 最高位为0,表示正数(充电) signed_raw = raw # 转换为毫安 current_ma = signed_raw * current_lsb * 1000 return current_ma except Exception as e: logger = logger_manager.logger if logger: logger.error(f"[INA226] 读取电流失败: {e}") else: print(f"[INA226] 读取电流失败: {e}") return 0.0 def is_charging(threshold_ma=10.0): """ 检测是否在充电(通过电流方向判断) Args: threshold_ma: 电流阈值(毫安),超过此值认为在充电,默认10mA Returns: True: 正在充电 False: 未充电或读取失败 """ try: current = get_current() is_charge = current > threshold_ma return is_charge except Exception as e: logger = logger_manager.logger if logger: logger.error(f"[CHARGE] 检测充电状态失败: {e}") else: print(f"[CHARGE] 检测充电状态失败: {e}") return False def voltage_to_percent(voltage): """根据电压估算电池百分比(查表插值)""" points = [ (4.20, 100), (4.10, 95), (4.05, 85), (4.00, 75), (3.95, 65), (3.90, 55), (3.85, 45), (3.80, 35), (3.75, 25), (3.70, 15), (3.65, 5), (3.60, 0) ] if voltage >= points[0][0]: return 100 if voltage <= points[-1][0]: return 0 for i in range(len(points) - 1): v1, p1 = points[i] v2, p2 = points[i + 1] if voltage >= v2: ratio = (voltage - v1) / (v2 - v1) percent = p1 + (p2 - p1) * ratio return max(0, min(100, int(round(percent)))) return 0