| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852 |
- --[[
- @module exchg
- @summary exchg扩展库
- @version 1.0
- @date 2025.11.25
- @author 王世豪
- @usage
- -- 应用场景
- 本扩展库适用于Air8000/8000G/8000XB/8000GB等集成了内置电池充电方案的模组型号;
- Air8000/8000G/8000XB/8000GB内置的充电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
|