--[[ @module exchg @summary exchg扩展库 @version 1.0 @date 2025.08.08 @author 王世豪 @usage -- 应用场景 本扩展库适用于Air8000/Air7000/Air6000等集成了内置电池充电方案的模组型号; Air8000/Air7000/Air6000内置的充电IC为YHM2712,exchg扩展库基于本充电IC进行设计; -- 用法实例 本扩展库对外提供了以下5个接口: 1)开启充电 exchg.start() 2)关闭充电 exchg.stop() 3)设置电池的充电截止电压,电池容量,充电电流 exchg.setup(v_battery, cap_battery, i_charge) 4)获取充电系统状态信息 exchg.status() 5)注册事件回调函数 exchg.on(func) 其中,开启充电 exchg.start() 和 关闭充电 exchg.stop() 默认自动执行,用户可以不用操作; 当碰到某些需要手动关闭或开启充电功能的场景时,大家可以自行控制,当前仅为预留; 以下为exchg扩展库四个函数的详细说明及代码实现: 1、开启充电 必须在task中运行,最大阻塞时间大概为700ms, 阻塞主要由sys.waitUntil("YHM27XX_REG", 500)和sys.wait(200)产生。 @api exchg.start() @return boolean: true=成功, false=失败 2、关闭充电 必须在task中运行,最大阻塞时间大概为700ms, 阻塞主要由sys.waitUntil("YHM27XX_REG", 500)和sys.wait(200)产生。 @api exchg.stop() @return boolean: true=成功, false=失败 3、设置电池的充电截止电压,电池容量,充电电流 必须在task中运行,最大阻塞时间大概为700ms, 阻塞主要由sys.waitUntil("YHM27XX_REG", 500)和sys.wait(200)产生。 @api exchg.setup(v_battery, cap_battery, i_charge) @param number v_battery: 电池充电截止电压(单位:mV), 取值范围:4200或4350可选, 必须传入。 @param number cap_battery: 电池容量(单位:mAh), 取值范围:>= 100,必须传入。 @param string i_charge: 充电电流, 取值范围:exchg.CCMIN(最小电流) 或 exchg.CCDEFAULT(默认电流) 或 exchg.CCMAX(),三个可选参数,不传入时默认值为exchg.CCDEFAULT。 @return boolean: true=成功, false=失败 @usage exchg.setup(4200, 400, exchg.CCMIN) -- 设置电池充电截止电压为4.2V, 电池容量为400mAh, 充电电流为最小电流 4、获取充电系统状态信息 必须在task中运行,最大阻塞时间(包括超时重试时间)大概为20s。 该函数用于获取当前充电系统的完整状态,包括电池电压、充电阶段、充电状态、电池在位状态、充电器在位状态以及IC过热状态等信息。 其中充电器是否在位,中断触发,触发回调事件为CHARGER_STATE_EVENT,附带的参数 true表示充电器在位,false表示充电器不在位。 @api exchg.status() @return table 状态信息表 { result = boolean, -- true: 成功, false: 失败 vbat_voltage = number, -- 电池电压值(单位:mV),特殊值含义: -- -1: 当前阶段不需要测量 -- -2: 电压测量失败 -- -3: 仅充电器就绪(无电池) charge_stage = number, -- 当前充电阶段描述,可能值: -- 0 : 放电模式 -- 1 : 预充电模式 -- 2 : 涓流充电 -- 3 : 恒流快速充电 -- 4 : 预留状态 -- 5 : 恒压快速充电 -- 6 : 预留状态 -- 7 : 充电完成 -- 8 : 未知状态 charge_complete = boolean, -- true: 充电完成, false: 充电未完成 battery_present = boolean, -- true: 电池在位, false: 电池不在位 charger_present = boolean, -- true: 充电器在位, false: 充电器不在位 ic_overheat = boolean -- true: 充电IC过热, false: 充电IC未过热 } 5、注册事件回调函数 @api exchg.on(func) @function: 回调方法,回调时传入参数有exchg.OVERHEAT, exchg.CHARGER_IN, exchg.CHARGER_OUT @return nil 无返回值 @usage local function exchg_callback(event) if event == exchg.OVERHEAT then log.info("警告:设备温度过高!") elseif event == exchg.CHARGER_IN then log.info("充电器已插入") elseif event == exchg.CHARGER_OUT then log.info("充电器已拔出") end end -- 注册回调 exchg.on(exchg_callback) 示例: local function exchg_task_func() exchg.setup(4200, 400) while true do local status = exchg.status() if status.result then log.info("电池电压:", status.vbat_voltage, "充电阶段:", status.charge_stage, "充电是否完成:", status.charge_complete, "电池在位:", status.battery_present, "充电器在位:", status.charger_present, "IC过热:", status.ic_overheat) end sys.wait(20000) end end -- 事件回调函数 local function exchg_callback(event) if event == exchg.OVERHEAT then log.info("警告:设备温度过高!") elseif event == exchg.CHARGER_IN then log.info("充电器已插入") elseif event == exchg.CHARGER_OUT then log.info("充电器已拔出") end end -- 注册回调 exchg.on(exchg_callback) sys.taskInit(exchg_task_func) ]] local exchg = {} -- yhm2712 cmd引脚, 传入nil表示根据模组型号自动选择 local gpio_pin = nil --yhm2712芯片地址 local sensor_addr = 0x04 --电压控制寄存器地址 local V_ctrl_register = 0x00 -- read/write --电流控制寄存器地址 local I_ctrl_register = 0x01 -- read/write --模式寄存器地址 local mode_register = 0x02 -- read/write --配置寄存器,默认为0x00 local config_register = 0x03 -- read/write --状态寄存器 local status1_register = 0x05 -- read only local status2_register = 0x06 -- read only --id寄存器 local id_register = 0x08 -- read only --充电电压参数,默认门限电压为4.35V local set_4V2 = 0x04 --4.2V local set_4V35 = 0x64 --4.35V local set_4V = 0xE4 --4V --充电电流参数,默认充电电流为175mA,即0.5倍*250=175mA local set_0I2 = 0x20 --0.2倍,0.2*250=50mA local set_0I5 = 0x00 --0.5倍,0.5*250=125mA local set_0I7 = 0x40 --0.7倍,0.7*250=175mA local set_0I9 = 0x60 --0.9倍,0.9*250=225mA local set_I = 0x80 -- 1倍,1.0*250=250mA local set_1I5 = 0xA0 --1.5倍,1.5*250=375mA local set_2I = 0xC0 -- 2倍,2.0*250=500mA local set_3I = 0xE0 -- 3倍,3*250=750mA -- 实际电流值(mA)到十六进制参数的映射 local current_to_register = { [50] = set_0I2, [125] = set_0I5, [175] = set_0I7, [225] = set_0I9, [250] = set_I, [375] = set_1I5, [500] = set_2I, [750] = set_3I } -- 检测USB状态,测VBUS脚(即gpio.WAKEUP1) local vbus_pin = gpio.WAKEUP1 -- 是否正在充电 local is_charge = false -- 是否仅充电器在位 local charger_only = false -- 电池电压采样值数组 local nochg_t = {} -- nochg_t 最大长度限制 local AVR_MAX = 10 local callback = nil -- 充电门限电压设置,默认4.35V local voltage_setting = set_4V35 -- 充电电流常量 exchg.CCMIN = "MIN" -- 恒流充电MIN电流模式 exchg.CCMAX = "MAX" -- 恒流充电MAX电流模式 exchg.CCDEFAULT = "DEFAULT" -- 恒流充电默认电流模式,电流大小处于Min和Max之间 -- 定义事件常量 exchg.OVERHEAT = 1 -- 温度过热事件 exchg.CHARGER_IN = 2 -- 充电器插入事件 exchg.CHARGER_OUT = 3 -- 充电器拔出事件 -- 使用表格存储不同容量和模式下的电流值 local current_table = { [100] = {[exchg.CCMIN] = 50, [exchg.CCDEFAULT] = 50, [exchg.CCMAX] = 50}, [200] = {[exchg.CCMIN] = 50, [exchg.CCDEFAULT] = 125, [exchg.CCMAX] = 125}, [300] = {[exchg.CCMIN] = 50, [exchg.CCDEFAULT] = 175, [exchg.CCMAX] = 175}, [400] = {[exchg.CCMIN] = 50, [exchg.CCDEFAULT] = 225, [exchg.CCMAX] = 225}, [500] = {[exchg.CCMIN] = 50, [exchg.CCDEFAULT] = 250, [exchg.CCMAX] = 250}, [600] = {[exchg.CCMIN] = 50, [exchg.CCDEFAULT] = 250, [exchg.CCMAX] = 375}, [700] = {[exchg.CCMIN] = 50, [exchg.CCDEFAULT] = 375, [exchg.CCMAX] = 500}, [800] = {[exchg.CCMIN] = 50, [exchg.CCDEFAULT] = 375, [exchg.CCMAX] = 500}, [900] = {[exchg.CCMIN] = 50, [exchg.CCDEFAULT] = 375, [exchg.CCMAX] = 500}, [1000] = {[exchg.CCMIN] = 50, [exchg.CCDEFAULT] = 500, [exchg.CCMAX] = 750} } --[[ 注册exchg事件回调 @api exchg.on(func) @function 回调方法,回调时传入参数有exchg.OVERHEAT, exchg.CHARGER_IN, exchg.CHARGER_OUT @return nil 无返回值 @usage local function exchg_callback(event) if event == exchg.OVERHEAT then log.info("警告:设备温度过高!") elseif event == exchg.CHARGER_IN then log.info("充电器已插入") elseif event == exchg.CHARGER_OUT then log.info("充电器已拔出") end end -- 注册回调 exchg.on(exchg_callback) --]] function exchg.on(cb) callback = cb end -- 内部事件触发函数 local function notify_event(event) if callback then callback(event) end end -- 查找最接近的电池容量标准值(最小100mAh),使用四舍五入规则 local function get_closest_capacity(capacity) -- 四舍五入到最近的100的倍数 local rounded = math.floor(capacity / 100 + 0.5) * 100 -- 确保结果不小于100mAh rounded = math.max(100, rounded) return rounded end --[[ 设置电池充电截止电压,电池容量,充电电流(必须在task中运行,最大阻塞时间大概为700ms, 阻塞主要由sys.waitUntil("YHM27XX_REG", 500)和sys.wait(200)产生。) @api exchg.setup(v_battery, cap_battery, i_charge) @number v_battery: 电池充电截止电压, 取值范围:4200或4350可选, 单位(mV), 必须传入。 @number cap_battery: 电池容量, 取值范围:>= 100, 单位(mAh),必须传入。 @string i_charge: 充电电流, 取值范围:exchg.CCMIN(最小电流) 或 exchg.CCDEFAULT(默认电流) 或 exchg.CCMAX(最大电流),三个可选参数,不传入时默认值为exchg.CCDEFAULT。 @return boolean: true=成功, false=失败 @usage exchg.setup(4200, 400, exchg.CCMIN) -- 设置电池充电截止电压为4.2V, 电池容量为400mAh, 充电电流为最小电流 ]] function exchg.setup(v_battery, cap_battery, i_charge) -- 验证电池电压 if v_battery ~= 4200 and v_battery ~= 4350 then log.error("exchg", "无效的电池电压,必须是 4200 (4.20V) 或 4350 (4.35V)") return false end -- 验证电池容量范围 if type(cap_battery) ~= "number" or cap_battery < 100 then log.error("exchg", "电池容量过低, 小于100mAh") return false end -- 获取最接近的标准容量值 local closest_capacity = get_closest_capacity(cap_battery) -- 处理充电电流参数,默认为CCDEFAULT local charge_current = i_charge or exchg.CCDEFAULT -- 验证充电电流参数 if i_charge ~= nil and charge_current ~= exchg.CCMIN and charge_current ~= exchg.CCDEFAULT and charge_current ~= exchg.CCMAX then log.error("exchg", "无效的充电电流参数,必须是 exchg.CCMIN、exchg.CCDEFAULT 或 exchg.CCMAX,已使用默认值") charge_current = exchg.CCDEFAULT -- 重置为默认值 end -- 获取电流值,如果容量超过1000mAh,则使用1000mAh的配置 local actual_capacity = math.min(closest_capacity, 1000) local actual_current = current_table[actual_capacity][charge_current] -- 根据实际电流值获取对应的十六进制参数 local current_register_value = current_to_register[actual_current] if not current_register_value then log.error("exchg", "未找到对应电流值的寄存器参数: " .. actual_current) return false end -- 读取芯片ID,验证通信是否正常 local result, data = pm.chgcmd(gpio_pin, sensor_addr, id_register) if not result then log.error("exchg", "无法读取芯片ID, 通信失败") return false end -- 设置电池充电截止电压 voltage_setting = v_battery == 4200 and set_4V2 or set_4V35 result,data = pm.chgcmd(gpio_pin, sensor_addr, V_ctrl_register, voltage_setting) if not result then log.error("exchg", "设置电池充电截止电压失败") return false end -- 设置充电电流 result,data = pm.chgcmd(gpio_pin, sensor_addr, I_ctrl_register, current_register_value) if not result then log.error("exchg", "设置电池充电电流失败") return false end sys.wait(200) -- 写入命令之后等待200ms再去读取寄存器数据,必须要等待,否则会有读取寄存器失败的可能。 -- 请求寄存器数据 pm.chginfo(gpio_pin, sensor_addr) local reg_result, reg_data = sys.waitUntil("YHM27XX_REG", 500) if reg_result and reg_data then local V_value = reg_data:byte(1) local I_value = reg_data:byte(2) -- 验证设置是否生效 if V_value == voltage_setting and I_value == current_register_value then return true else log.warn("exchg.setup未生效, 请检查是否支持yhm27xx") return false end else log.error("exchg.setup" .. "0x04寄存器数据获取失败") return false end end --[[ 开始充电(必须在task中运行,最大阻塞时间大概为700ms, 阻塞主要由sys.waitUntil("YHM27XX_REG", 500)和sys.wait(200)产生。) @api exchg.start() @return boolean: true=成功, false=失败 @usage exchg.start() -- 开始充电 ]] function exchg.start() -- 读取芯片ID,验证通信是否正常 local result, data = pm.chgcmd(gpio_pin, sensor_addr, id_register) if not result then log.error("exchg", "无法读取芯片ID, 通信失败") return false end sys.wait(200) -- 写入命令之后等待200ms再去读取寄存器数据,必须要等待,否则会有读取寄存器失败的可能。 -- 开启充电前先查询ic温度,如果过热,则不执行开启充电功能 pm.chginfo(gpio_pin, sensor_addr) result, data = sys.waitUntil("YHM27XX_REG", 500) if not result or not data or #data < 6 then log.error("exchg.start1" .. "0x04寄存器数据获取失败") return false end -- 提取0x05寄存器的第3位(从0开始计数) -- 过热标志位为1,表示温度>120℃ -- 过热标志位为0,表示温度<120℃ local overheat = (data:byte(6) & 0x08) ~= 0 if overheat then log.error("exchg.start" .. "ic温度过高,不执行充电功能") return false end -- 开始充电 result = pm.chgcmd(gpio_pin, sensor_addr, mode_register, 0xA8) if not result then log.error("exchg.start", "开始充电失败") return false end sys.wait(200) -- 写入命令之后等待200ms再去读取寄存器数据,必须要等待,否则会有读取寄存器失败的可能。 -- 请求寄存器数据 pm.chginfo(gpio_pin, sensor_addr) local reg_result, reg_data = sys.waitUntil("YHM27XX_REG", 500) if reg_result and reg_data then if reg_data:byte(3) == 160 then log.info("exchg.start 生效") return true else log.warn("exchg.start 未生效, 请检查是否支持yhm27xx") return false end else log.error("exchg.start2" .. "0x04寄存器数据获取失败") return false end end --[[ 停止充电(必须在task中运行,最大阻塞时间大概为700ms, 阻塞主要由sys.waitUntil("YHM27XX_REG", 500)和sys.wait(200)产生。) @api exchg.stop() @return boolean: true=成功, false=失败 @usage exchg.stop() -- 停止充电 ]] function exchg.stop() -- 读取芯片ID,验证通信是否正常 local result = pm.chgcmd(gpio_pin, sensor_addr, id_register) if not result then log.error("exchg", "无法读取芯片ID, 通信失败") return false end result = pm.chgcmd(gpio_pin, sensor_addr, mode_register, 0xF8) if not result then log.error("exchg.stop", "停止充电失败") return false end sys.wait(200) -- 写入命令之后等待200ms再去读取寄存器数据,必须要等待,否则会有读取寄存器失败的可能。 -- 请求寄存器数据 pm.chginfo(gpio_pin, sensor_addr) local reg_result, reg_data = sys.waitUntil("YHM27XX_REG", 500) if reg_result and reg_data then if reg_data:byte(3) == 240 then log.info("exchg.stop 生效") return true else log.warn("exchg.stop 未生效, 请检查是否支持yhm27xx") return false end else log.error("exchg.stop" .. "0x04寄存器数据获取失败") return false end end -- 检测电池是否在位 local function check_battery_exists() local switch_count = 0 local last_status = nil local loop_count = 0 local total_loops = 50 -- 50次循环, 每次循环至少100ms for loop_count = 1, total_loops do -- log.debug("当前循环", loop_count, "/", total_loops) -- 发送读取请求 pm.chginfo(gpio_pin, sensor_addr) local result, data = sys.waitUntil("YHM27XX_REG", 200) -- 存储解析后的寄存器数据 local Data_reg = {} if result and data then for i=1,9 do Data_reg[i] = data:byte(i) end -- 提取Data_reg[7](对应0x06寄存器)的7:4 位 -- 1. 使用0xF0(二进制1111 0000)进行按位与操作,保留高4位 -- 2. 右移4位将结果转换为十进制 local current_status = (Data_reg[7] & 0xF0) >> 4 -- log.debug("状态:", current_status) -- 只关注状态12(1100)和13(1101) if current_status == 12 or current_status == 13 then if last_status ~= nil and last_status ~= current_status then switch_count = switch_count + 1 -- log.debug("状态切换", last_status, "->", current_status, "次数:", switch_count) -- 达到切换阈值提前退出 if switch_count >= 2 then -- log.info("电池判定", "不在位(频繁切换)") return false end end last_status = current_status else last_status = nil end else log.error("check_battery_exists", "0x04寄存器数据获取失败") last_status = nil end -- 确保每次循环间隔至少100ms if loop_count < total_loops then sys.wait(100) end end -- log.debug("检测结束", "切换次数:", switch_count) if switch_count >= 2 then return false else return true end end --[[ 获取当前的充电阶段状态 -- 充电状态说明: -- 0 (000): 放电模式 -- 1 (001): 预充电模式 -- 2 (010): 涓流充电 -- 3 (011): 恒流快速充电 -- 4 (100): 预留状态 -- 5 (101): 恒压快速充电 -- 6 (110): 预留状态 -- 7 (111): 充电完成 ]] local function get_charge_status() pm.chginfo(gpio_pin, sensor_addr) local result, data = sys.waitUntil("YHM27XX_REG", 500) -- 存储解析后的寄存器数据 local Data_reg = {} if result and data then for i=1,9 do Data_reg[i] = data:byte(i) end -- 提取充电状态信息 -- 充电状态位于0x05寄存器(对应Data_reg[6])的高3位(第7-5位) -- 1. 使用0xE0(二进制1110 0000)进行按位与操作,保留高3位 -- 2. 右移5位,将高3位移到最低位 local charge_status = (Data_reg[6] & 0xE0) >> 5 return charge_status else log.error("get_charge_status", "0x04寄存器数据获取失败") return nil end end -- 查询充电ic是否过热 local overheat_check_timer = nil local function check_over_heat() pm.chginfo(gpio_pin, sensor_addr) local result, data = sys.waitUntil("YHM27XX_REG", 500) if not result or not data or #data < 6 then log.error("check_over_heat", "0x04寄存器数据获取失败") return false end -- 提取0x05寄存器的第3位(从0开始计数) -- 过热标志位为1,表示温度>120℃ -- 过热标志位为0,表示温度<120℃ local overheat = (data:byte(6) & 0x08) ~= 0 if overheat then -- 充电IC过热, 大于120℃, 停止充电! exchg.stop() notify_event(exchg.OVERHEAT) -- 如果已有定时器在运行,先停止 if overheat_check_timer then sys.timerStop(overheat_check_timer) overheat_check_timer = nil end -- 启动定时器,10分钟后再次检查 overheat_check_timer = sys.timerStart(check_over_heat, 10 * 60 * 1000) else -- 温度正常 if overheat_check_timer then -- 停止定时器(因为温度已恢复,不再需要检查) sys.timerStop(overheat_check_timer) overheat_check_timer = nil -- 重新启动充电 exchg.start() end end return true, overheat end -- 启用或禁用SYS_TRACK电压跟随功能 0x01寄存器 function set_sys_track(enable) if type(enable) ~= "boolean" then log.error("set_sys_track: 无效的enable参数,必须是布尔值") return false end local reg_addr = 0x01 -- SYS_TRACK所在寄存器地址 local reg_value = 0x00 -- 初始值 local max_retry = 3 -- 最大重试次数 local retry_count = 0 -- 重试计数 -- 读取当前寄存器值 while retry_count <= max_retry do pm.chginfo(gpio_pin, sensor_addr) local result, data = sys.waitUntil("YHM27XX_REG", 500) local Data_reg={} if result then -- 将data按字节解析到Data_reg数组 for i=1, #data do Data_reg[i] = data:byte(i) end reg_value = Data_reg[2] break else retry_count = retry_count + 1 log.warn("set_sys_track: 读取寄存器失败,正在重试 (" .. retry_count .. "/" .. max_retry .. ")") if retry_count > max_retry then log.error("set_sys_track: 超过最大重试次数,读取寄存器失败") return false end sys.wait(100) end end -- 保存原始值,用于比较 local original_value = reg_value -- 设置SYS_TRACK位 (bit 1) if enable then reg_value = reg_value | 0x02 -- 设置bit 1为1 (0x02 = 00000010) else reg_value = reg_value & 0xFD -- 设置bit 1为0 (0xFD = 11111101) end -- 如果值没有变化,不需要写入 if reg_value == original_value then -- log.info("set_sys_track: SYS_TRACK" .. (enable and "启用" or "禁用") .. "状态已保持,无需写入") return true end -- log.info("set_sys_track: 修改后寄存器值", string.format("0x%02X", reg_value)) -- 写入新值 retry_count = 0 while retry_count <= max_retry do local result, data = pm.chgcmd(gpio_pin, sensor_addr, reg_addr, reg_value) if result then -- log.info("set_sys_track: SYS_TRACK" .. (enable and "启用" or "禁用") .. "成功") return true else retry_count = retry_count + 1 log.warn("set_sys_track: 写入寄存器失败,正在重试 (" .. retry_count .. "/" .. max_retry .. ")") if retry_count > max_retry then log.error("set_sys_track: 超过最大重试次数,写入寄存器失败") return false end sys.wait(100) -- 重试前等待100ms end end end -- 中断检测充电器是否在位(通过检测VBUS引脚的电平来判断充电器是否在位),并对外发布CHARGER_STATE_EVENT事件 local function check_charger() if gpio.get(vbus_pin) == 0 then if is_charge then is_charge = false notify_event(exchg.CHARGER_OUT) end else if not is_charge then is_charge = true notify_event(exchg.CHARGER_IN) end end end -- 初始化GPIO中断 gpio.debounce(vbus_pin, 500, 1) -- 消抖 gpio.setup(vbus_pin, check_charger, gpio.PULLUP, gpio.BOTH) -- 上拉电阻+双沿触发 check_charger() -- 初始检测 -- 向滑动窗口数组添加新的电压采样值,并计算窗口内的平均值, 用于平滑电压采样数据 local function append_vadc(v) -- 如果窗口已满(达到最大长度 AVR_MAX) if #nochg_t >= AVR_MAX then -- 添加新值到窗口末尾 table.insert(nochg_t, v) -- 移除窗口最前面的旧值 table.remove(nochg_t, 1) else -- 窗口未满时,用当前值填充整个窗口 -- 这确保初始化阶段也存在有效的平均值 while #nochg_t < AVR_MAX do table.insert(nochg_t, v) end end -- 计算窗口内所有值的总和 local totv = 0 local min_val = nochg_t[1] local max_val = nochg_t[1] for i = 1, #nochg_t do totv = totv + nochg_t[i] if nochg_t[i] < min_val then min_val = nochg_t[i] end if nochg_t[i] > max_val then max_val = nochg_t[i] end end -- 计算平均值:去掉一个最大值和一个最小值 local count = #nochg_t local avg -- 当窗口大小小于3时,无法去掉最大最小值 if count < 3 then avg = totv // count else avg = (totv - min_val - max_val) // (count - 2) end log.info("append_vadc", totv, count, avg) return avg end -- 获取电池电压 local function check_battery(param) adc.open(adc.CH_VBAT) -- 打开ADC通道 local vbat = adc.get(adc.CH_VBAT) -- 读取电压 adc.close(adc.CH_VBAT) -- 关闭ADC通道 -- -- 计算采集电压的平均值,去掉一个最大值和一个最小值 -- vbat = append_vadc(vbat) if param then vbat = math.floor(vbat / param + 0.5) end return vbat end --[[ 获取充电系统状态信息(必须在task中运行,最大阻塞时间(包括超时重试时间)大概为20s)。该函数用于获取当前充电系统的完整状态,包括电池电压、充电阶段、充电状态、电池在位状态、充电器在位状态以及IC过热状态等信息。其中充电器是否在位,中断触发,触发回调事件为CHARGER_STATE_EVENT,附带的参数 true表示充电器在位,false表示充电器不在位。 @api exchg.status() @return table 状态信息表 { result = boolean, -- true: 成功, false: 失败 vbat_voltage = number, -- 电池电压值(单位:mV),特殊值含义: -- -1: 当前阶段不需要测量 -- -2: 电压测量失败 -- -3: 仅充电器就绪(无电池) charge_stage = number, -- 当前充电阶段描述,可能值: -- 0 : 放电模式 -- 1 : 预充电模式 -- 2 : 涓流充电 -- 3 : 恒流快速充电 -- 4 : 预留状态 -- 5 : 恒压快速充电 -- 6 : 预留状态 -- 7 : 充电完成 -- 8 : 未知状态 charge_complete = boolean, -- true: 充电完成, false: 充电未完成 battery_present = boolean, -- true: 电池在位, false: 电池不在位 charger_present = boolean, -- true: 充电器在位, false: 充电器不在位 ic_overheat = boolean -- true: 充电IC过热, false: 充电IC未过热 } @usage local status = exchg.status() if status.result then log.info("电池电压:", status.vbat_voltage, "充电阶段:", status.charge_stage, "充电是否完成:", status.charge_complete, "电池在位:", status.battery_present, "充电器在位:", status.charger_present, "IC过热:", status.ic_overheat) end --]] function exchg.status() -- 初始化所有状态 local status = { result = true, vbat_voltage = 0, charge_stage = 8, charge_complete = false, battery_present = false, charger_present = is_charge, ic_overheat = false, } -- 1. 检查电池是否在位 status.battery_present = check_battery_exists() sys.wait(100) -- yhm27xx操作之间必须延时一段时间 -- 2. 检查充电IC是否过热 local overheat_success, overheat_temp = check_over_heat() if overheat_success then status.ic_overheat = overheat_temp else log.warn("充电IC温度检测失败") status.result = false end sys.wait(100) -- yhm27xx操作之间必须延时一段时间 -- 3. 获取充电阶段 local stage_temp = get_charge_status() if stage_temp then status.charge_stage = stage_temp else log.warn("充电阶段检测失败") status.result = false end -- 4. 在特定阶段测量电池电压 if status.battery_present then if charger_only then local result = pm.chgcmd(gpio_pin, sensor_addr, V_ctrl_register, voltage_setting) charger_only = false end -- 预充电或涓流充电阶段不测量电压 if status.charge_stage == 1 or status.charge_stage == 2 then -- 设置特殊电压值表示未测量 status.vbat_voltage = -1 log.info("当前阶段:", status.charge_stage, "当前电压过低,正在涓流充电阶段努力充电中..., 请保持充电器连接") -- 恒流/恒压阶段,打开电压跟随功能测量电池电压 elseif status.charge_stage == 3 or status.charge_stage == 5 then -- 打开电压跟随功能 local result = set_sys_track(true) if result then local vbat = check_battery(1.053) status.vbat_voltage = vbat sys.wait(100) set_sys_track(false) -- 测量完关闭电压跟随功能 else log.warn("无法打开电压跟随功能") -- 测量失败 status.vbat_voltage = -2 status.result = false end -- 充电完成 elseif status.charge_stage == 7 then local vbat = check_battery(1.03) status.vbat_voltage = vbat -- 放电模式 elseif status.charge_stage == 0 then local vbat = check_battery() status.vbat_voltage = vbat else -- 只做提示,不测量电压 status.vbat_voltage = -1 end elseif status.charger_present then -- 充电器在位,电池不在位, Vreg设置为4V,这样Vsys=1.03*4.0V=4.1V, 在模组的电压舒适区 local result = pm.chgcmd(gpio_pin, sensor_addr, V_ctrl_register, set_4V) if not result then log.warn("仅充电器在位时, Vreg设置为4V失败") status.result = false end -- 标记当前状态为"充电器在位但电池不在位" charger_only = true -- 更新状态值 status.vbat_voltage = -3 status.charge_stage = 8 status.charge_complete = false status.battery_present = false end -- 5. 判断充电是否完成 status.charge_complete = (status.charge_stage == 7) return status end -- sys.taskInit(function() -- -- 连续ADC 电路稳定后,连续采集10次作为初始均值成员 -- for i = 1, AVR_MAX do -- check_battery() -- sys.wait(200) -- end -- end) return exchg