Air201-LuatOS-如何使用电源管理功能
一、电源管理介绍
电源管理是电子设备中非常重要的一部分,尤其是在移动设备和嵌入式系统中。它直接关系到设备的能效、续航时间和整体性能。以下是关于电源管理的一些基本知识和常见概念的介绍。
1.1 电源管理的定义
电源管理指的是在电子设备内部合理利用和调节电源,以保证各个组件在最佳运行条件下工作,同时延长设备的使用时间和确保能量的有效利用。
1.2 电源管理的目标
- 延长电池寿命:通过有效的充放电管理,使电池在使用过程中更长久地保持能量。
- 优化能耗:监测各个部件的能耗,减少不必要的能量消耗。
- 提供稳定的电力供给:确保设备在不同的负载和环境条件下都能稳定工作。
1.3 常见术语
- Vbat(电池电压):指设备中电池当前的电压值,通常用于评估电池的状态。
- 电池电量百分比:代表电池当前剩余能量的百分比,通常用于用户界面显示。
- 充电状态:指设备是否正在充电,影响电池电量的监测和管理策略。
- 电池放电曲线:描述不同电压下电池剩余电量的关系,帮助计算电量百分比。
- 电池调节电压:电池在充放电过程中,可以通过一定控制策略或电路设计,维持电池电压在一定范围内的稳定。Air201 的电池电压上限值默认为 4.2V,可在代码中自行更改电池电压阈值。
- 快速充电:快速充电是一种技术,它允许电池在较短时间内充入更多电量。快速充电技术包括恒流充电与恒压充电。在快速充电的恒流阶段,充电器会以一个固定的电流给电池充电,直到电池电压达到一个预设的电压值(Air201 默认为 4.2V),随后切换至恒压模式,此时电流逐渐减小,直到电池充满后停止充电。
1.4 常见功能
- 电量监测:通过 ADC(模数转换)读取电池电压,定期更新电量状态。
- 充电检测:利用 GPIO 中断检测充电状态,判断电池是否处于充电状态。
- 自动关机:根据电量百分比自动关闭设备,以防止电池过度放电。
- 过压保护:当充电到达电池电压阈值时会自动停止充电,待剩余电量与满电量相差超过 120mA 时恢复充电。
- 用户接口:通过长按电源键执行关机命令,提升用户体验。
- 路径管理:当插入 USB 既可以给锂电池充电,同时也可以给主板供电
1.5 实践中的应用
在实际应用中,电源管理代码通常涉及多个功能模块,包括初始化电源,实时监测电量,响应用户操作和维护设备状态。一个良好的电源管理系统能够显著提高设备的性能和用户满意度。
通过合理的电源管理策略,用户不仅可以延长设备的使用时间,还可以确保设备在关键时刻的稳定性和可靠性。在编写电源管理程序时,应充分考虑设备的使用场景和用户的需求。
二、演示功能概述
在本演示中,我们将展示电源管理系统的核心功能模块,以及如何通过不同的技术手段实现有效的电源管理。这些功能旨在提升设备的性能和用户体验,以下是主要演示功能的概述:
1. 电量监测:本系统通过 ADC(模数转换器)实时读取电池电压,并定期更新电量状态。通过精确监测电池电压,可以让用户清晰掌握当前电池剩余电量,避免意外关机带来的困扰。
2. 充电检测:系统利用 GPIO 中断技术,能够快速检测电池的充电状态。当设备连接到电源时,将自动判断电池是否在充电状态,并相应地调整电源管理策略,以优化充电效率和电池寿命。
3. 自动关机:根据监测到的电量百分比,该系统能够在电量过低时自动关机,以防止电池过度放电。这种智能管理能够保护电池,延长其使用寿命,确保设备在低电量时不会意外关机。
4. 用户接口:系统提供了便捷的用户交互接口,用户可以通过长按电源键实现关机操作。提升用户体验的同时,确保用户可以方便地控制设备的电源状态。
通过这些功能的实现,用户不仅可以延长设备的使用时间,还能够保证设备在关键时刻的稳定性和可靠性。在实际应用中,这些功能能够有效地提升设备性能,满足用户对电源管理的需求。
三、演示硬件环境
3.1 开发板
本文以 Air201 开发板 为例,Air201 开发套件如下图所示:
淘宝购买链接:Air201 开发套件淘宝购买链接 ;
此开发套件的详细使用说明参考:Air201 产品手册 中的 Air201 硬件手册 和 Air201 的 LuatOS 快速入门。
3.2 SIM 卡
在中国大陆环境下,使用移动,电信,联通的物联网卡或者手机卡都可以。
3.3 PC 电脑
PC 电脑推荐使用 Windows10 及以上版本。
3.4 数据通信线
1. USB 转 Type-C 数据线
它的一端是 USB 接口,另一端是 Type-C 接口。
四、演示软件环境
4.1 Luatools 下载调试工具
Luatools 工具由合宙推出,支持最新固件获取、固件打包、trace 打印及单机烧录等功能。
工具使用说明参考:Luatools 下载和详细使用
4.2 获取固件及源码
1. 底层 core 下载地址:SDK& Demo - luatos@air201 - 合宙文档中心
本文使用的固件版本为 LuatOS-SoC_V2002_Air201.soc 。
2. demo 位置
本 demo 的主要功能是对电池管理系统的控制和监测
demo 位置参考:https://gitee.com/openLuat/LuatOS-Air201/tree/master/demo/pm
五、软硬件资料
5.1 电池充电器说明
注意注意,锂电池与锂离子电池不是同一种电池。锂电池是一个统称,而锂离子电池是锂电池的其中一种类型。
Air201 选用了一款高度集成的单电池锂离子电池充电器,该充电器具有系统电源路径管理,可供空间有限的便携式应用使用。功能具有涓流充电、恒流充电、恒压充电、充电终止和自动充电。而且可以自动调节充电电流与充电电压,或者进入其他模式。
5.1.1 锂电池充电过程
锂离子电池的充电过程可概括为四个阶段:涓流充电、恒流充电、恒压充电以及充电终止。以下为这四个阶段的详细介绍。
1. 涓流充电:
涓流充电用于先对完全放电的电池单元进行预充,也叫恢复性充电。在电池电压低于 3V 左右时,先采用最大 0.1C 的恒定电流对电池进行充电。(C 是充放电倍率,表示电池在单位时间内充放电电流与电池额定容量的比值。例如,一个电池的额定容量是 1000mAh,1C 就表示以 1000mA 的电流在单位时间内进行充放电,也表示电池在一小时内完全充放电。)
2. 恒流充电:
在涓流充电之后,当电池电压上升到涓流充电阈值以上时,此时提高充电电流从而进行恒流充电。这个阶段的电流通常在 0.2C~1.0C 之间,电池电压随着恒流充电过程在逐步升高。恒流充电时的电流并不要求十分精确,准恒定电流也可以。
当在线性充电器设计中,电流经常会随着电池电压的上升而上升,应尽量减轻传输晶体管上的散热问题。选择大于 1.0C 的恒流充电并不会缩短整个充电充电周期时间,这种做法是不可取的。
当以更高电流进行充电时,由于电极反应的过压以及电池内部阻抗上的电压上升,电池电压会更快速地上升。恒流充电阶段就会变短,同时下面恒压充电阶段的时间会相应增加,因此总的充电周期时间并不会缩短。
3. 恒压充电:
当电池电压上升到 4.2V(默认值)时,恒流充电结束,开始恒压充电阶段。在此阶段,电流会根据电芯的饱和程度逐渐减少,直到达到一个很小的值,可称为判满电流值时,充电终止。
4. 充电终止:
与镍电池不同,此时不建议对锂离子电池进行连续涓流充电。连续涓流充电会导致金属锂出现极板电镀效应。从而使电池不稳定,并且极大可能导致突然的自动快速解体。
这个阶段有两种典型的充电终止方法:一种是采用最小充电电流判断,当恒压充电阶段的充电电流减小到判满电流值时终止充电;另一种是从恒压充电阶段开始计时,持续充电两个小时后终止充电过程。Air201 选择的电池充电器充电终止方法为第一种。
5. 充电恢复说明:
充电终止后,当电池放电后剩余电量与满电量相差超过 120mV 时会恢复充电,转为恒压充电阶段。
5.1.2 锂电池放电说明
由于锂电池内部结构所致,在放电时锂电池不能全部移向正极,必须要保留一部分锂离子在负极,从而保证在下次充电时锂离子能够畅通地嵌入通道。否则,电池寿命将会大大缩短。
1. 放电电压平台:
锂电池在放电过程中,电压会保持在一个相对稳定的范围内,这个范围被称为放电电压平台。对于大多数锂电池来说,这个平台大约在 3.7V 到 3.0V 之间。
2. 放电电流:
放电电流是指电池在放电过程中的电流强度。放电电流的大小会直接影响到电池的放电时间和寿命。大电流放电时会导致电池温度升高,也可能会缩短电池寿命。(锂电池放电电流不应超过电池容量的 3 倍,例如 1000mAH 电池,放电电流应严格控制在 3A 以内,否则会导致电池损坏。)
3. 放电截止电压:
为了保证锂电池放电后石墨层中仍留有部分锂离子,就需要严格限制最低放电截止电压,也就是要避免过放电。当电池电压降到这个值时,电池应停止放电。对于大多数锂电池,这个截止电压大约是 2.5V 到 3.0V。
Air201 在代码中已经设置当电池电量低于 30% 且两分钟内没有充电时自动关机。
4. 放电效率:
放电效率是指电池放电过程中电能转换的效率。锂电池放电效率可达到 90% 以上。
5. 放电深度:
放电深度是指电池放电时放电量与电池总容量的比率。即放电深度=(放电量/电池总容量)*100% 。(例如,如果一个电池的总容量是 1000mAh,放电到 500mAh,那么放电深度就是 50%。)
6. 放电速率:
放电速率是指电池单位时间内放电时放电量与电池额定容量的比值,用充放电倍率 C 表示。(例如,一个电池的额定容量为 1000mAh,如果用 200mA 的电流进行放电,其放电倍率为 0.2C,因为 200mA/1000mAh=0.2。)
7. 温度影响:
锂电池的放电性能受温度影响较大。在低温下,电池的放电性能会下降,而在高温下,电池的寿命可能会缩短。
8. 循环寿命:
锂电池的循环寿命是指电池可以经历的充放电次数。一般来说,锂电池的循环寿命可以达到几百到几千次,具体还要取决于电池的类型、使用条件和放电深度。
9. 自放电:
锂电池即使在不使用的情况下也会进行自动放电,这种现象称为自放电。锂电池的自放电率相对较低,通常每月 1% 到 2%。
5.2 sensor 库介绍
sensor 库是一个传感器操作库,用于在 LuatOS 环境中处理各种传感器的数据交互。它支持多个传感器的操作,包括 DS18B20 温度传感器、DHT11/DHT12 温湿度传感器、HX711 称重传感器、CS1237 传感器、WS2812B RGB LED 灯带以及 SC12A 触摸传感器等。
此为 sensor 库 API 接口介绍 ,大家可自行参考测试。
5.3 Air201 开发板烧录说明
5.3.1 选择固件和脚本
1. 打开 Luatools_v3 工具
2. 点击 项目管理测试
3. 根据图示操作
注意,大家只需要跟着做到第四步即可,第五步跟着后面的操作再做。
5.3.2 烧录
1. 将 Air201 开发板通过 USB 数据线连接至电脑,如下图所示:
由于 Air201 单板子没有复位键和 BOOT 键,所以数据线与 Air201 开发板之间还需要接一个 USB_BOOT 板,不过大家放心,Air201 套件里已经包括了 USB_BOOT 板,不需要单独购买。 而且特别注意,USB_BOOT 板在接 Air201 开发板时不用区分正反。
2. 根据下方操作进行烧录
此时就需要大家先点击 Luatools 工具上的
下载脚本
或下载底层和脚本
,再执行下方操作了。
开发板处于未开机状态:此时先按住下载模式按键(BOOT 键)不放,再长按开机键(POW 键)开机,若不出意外开发板将会进入下载模式,Luatools 工具下载进度条会开始跑,这时便可以松开 BOOT 键和 POW 键,等到工具提示下载完成即可。
开发板已经处于开机状态:此时可以先按住 BOOT 键不放,再短按复位键(RST 键)后开发板会重启并进入下载模式。
5.3.3 不同模式下的端口显示
1. 正常开机模式
2. 下载模式
六、功能验证
6.1 ChargeICLogic.lua 中代码介绍
该文件中的代码无需修改,大家直接调用这个文件就行。
6.1.1 代码说明
该文件中的代码是一个用 Lua 编写的脚本,主要用于与充电 IC(集成电路)进行交互,进行状态监测和控制。
6.1.2 代码逐步解析
1. 注释部分:
这段注释用于指出代码的主要功能,即处理充电 IC 相关的逻辑。
--[[
充电IC的相关逻辑
]]
2. 电池上限电压表:
此部分定义了电池上限电压的不同设置值。
Vreg
表包含多个十六进制数,每个数对应不同的电池上限电压。在 V_CTRL 寄存器中,前四位用来设置电池上限电压,其余位可以用作其他设置。默认情况下,其他位为 0。
local Vreg = {
'0x00', -- 4.2V
...
'0xF8', -- 4.1V
}
3. 快速充电电流表:
这部分定义了快速充电电流的设置值。
Ichg
表中列出的十六进制数对应于不同充电电流的设置。在 I_CTRL 寄存器中,前三位是设置快速充电电流的,其余位是其他设置,默认为 0; 该电流值是通过电阻 Rsns 计算得出的,Air201 的 Rsns 值为 1KΩ,经过公式计算后得出Ireg=500mA
。
local Ichg = {
'0x00', -- 0.5×Ireg
'0x20', -- 0.2×Ireg
...
}
4. GPIO 引脚初始化:
获取一个 GPIO 引脚并对其进行设置。
pcb.chargeCmdPin()
用于获取充电命令引脚,gpio.setup
将引脚GPIO1
设置为输出模式,且初始化电平为高,同时启用内部上拉。
local gpio_pin = pcb.chargeCmdPin()
gpio.setup(gpio_pin, 1, gpio.PULLUP)
5. 任务初始化:
这部分是主任务的初始化。首先等待 1000 毫秒,然后通过
sensor.yhm27xx
函数与传感器进行通信,以获取设备信息。后面再进行传感器设备中各寄存器参数配置。
sys.taskInit(function()
sys.wait(1000)
...
end)
6. 传感器数据读取:
通过
sensor.yhm27xx
函数调用来读取传感器的数据。 参数说明:gpi``o_pin
是传感器对应引脚,0x04
是传感器设备 ID,0x08
是设备信息寄存器的地址。等待 200 毫秒等待数据返回。
local result, data = sensor.yhm27xx(gpio_pin, 0x04, 0x08)
sys.wait(200)
7. 设备存在检查:
当检测到传感器存在时,会进行进一步的设置。此时根据不同寄存器的地址设置不同功能。
if result == true and data ~= nil then
log.info("yhm27xxx", "yhm27xx存在--")
...
end
8. 电压跟随与快速充电电流设置:
读取 I_CTRL 寄存器并设置电压跟随与快速充电电流。如果操作成功,将会再次读取配置寄存器并确认设置结果,记录相关的日志信息。 参数说明:
gpio_pin
是传感器对应引脚,0x04
是芯片设备 ID 号,0x01
是 I_CTRL 寄存器地址,0x02
是设置电压跟随与快速充电电流为 0.5×Ireg。 特别说明:若需要在同一寄存器中设置多个参数,则需要将参数值进行或运算。(例如,要设置电压跟随和快速充电电流为 0.5×Ireg,则参数值为 0x02+0x00=0x02 。快速充电电流表可参考下方表格)I_CTRL 寄存器地址前三位是设置快速充电电流,其余位是其他设置,默认为 0; Ireg 是电阻 Rsns 配置的电流值,Air201 的电阻 Rsns 值为 1KΩ,通过公式 Ireg=500/Rsns,得出 Ireg=500mA。
配置编号 | 快速充电电流值 | 配置编号 | 快速充电电流值 |
---|---|---|---|
0x00(默认) | 0.5×Ireg = 250mA | 0x80 | 1.0×Ireg = 500mA |
0x20 | 0.2×Ireg = 100mA | 0xA0 | 1.5×Ireg = 750mA |
0x40 | 0.7×Ireg = 350mA | 0xC0 | 2.0×Ireg = 1000mA |
0x60 | 0.9×Ireg = 450mA | 0xE0 | 3.0×Ireg = 1500mA |
result = sensor.yhm27xx(gpio_pin, 0x04, 0x01, 0x02)
9. 电池上限电压设置:
读取 V_CTRL 寄存器并设置电池上限电压。如果操作成功,将会再次读取配置寄存器并确认设置结果,记录相关的日志信息。 参数说明:
gpio_pin
是传感器对应引脚,0x04
是芯片设备 ID 号,0x00
是 V_CTRL 寄存器地址,0x00
是设置电池上限电压为 4.2V,可参考下方表格。
配置编号 | 上限电压 | 配置编号 | 上限电压 | 配置编号 | 上限电压 | 配置编号 | 上限电压 |
---|---|---|---|---|---|---|---|
0x00 | 4.2V | 0x40 | 4.3V | 0x80 | 4.4V | 0xC0 | 4.5V |
0x10 | 4.225V | 0x50 | 4.325V | 0x90 | 4.425V | 0xD0 | 4.525V |
0x20 | 4.25V | 0x60(默认) | 4.35V | 0xA0 | 4.45V | 0xE0 | 4V |
0x30 | 4.275V | 0x70 | 4.375V | 0xB0 | 4.475V | 0xF8 | 4.1V |
result = sensor.yhm27xx(gpio_pin, 0x04, 0x00, 0x00)
10. 异常处理:
如果在读取传感器信息时返回结果为假,则说明传感器不存在,记录警告日志。
else
log.warn("yhm27xxx", "yhm27xx不存在")
6.1.3 总结说明
这段代码的主要功能是与充电 IC 进行交互以监控其状态,配置其控制参数,并在不同情况下记录相关的日志信息。通过这种方式,系统能够检测充电 IC 的存在与状态,并进行相应的初始化与配置,以确保充电过程的正常进行。全程使用异步任务管理,提升系统响应能力。
6.2 pcb.lua 中代码介绍
该文件中的代码无需修改,大家直接调用这个文件就行。
6.2.1 代码说明
这段 Lua 代码定义了一个名为 pcb
的模块,其主要功能是管理和操作硬件的某些特性,特别是与 PCB(印刷电路板)相关的设置和状态。
6.2.2 代码逐步解析
1. 模块初始化和变量定义:
这里定义了一个表
pcb
,用于存放后续的函数。定义了存储系统的 OTP 区域和硬件的默认版本号以及出厂测试结果的初始值。
local pcb = {}
local otpZone = 2 -- OTP 存储区的编号
local hversion = "1.0.3" -- 默认版本号
local test = false -- 初始出厂测试结果
2. 读取 OTP 存储区和解析硬件版本号的函数:
loadParam
函数首先检查 OTP 是否存在,然后读取 OTP 存储区中的数据,解码 JSON 格式的数据以获取硬件版本号和出厂测试结果。若解码失败或缺少数据,则根据设备型号进行版本号的设置。
local function loadParam()
if not otp then
return
end
local len = otp.read(otpZone, 0, 1)
local otpdata = otp.read(otpZone, 1, string.byte(len))
local obj, result, errMsg = json.decode(otpdata)
...
end
loadParam()
3. GNSS 电源控制功能:
此函数根据硬件版本控制 GNSS 模块的电源状态。通过 GPIO 接口进行电源的开启或关闭。
function pcb.gnssPower(onoff)
if hversion == "1.0.2" then
gpio.setup(2, onoff and 1 or 0)
gpio.setup(26, onoff and 1 or 0)
gpio.setup(27, onoff and 1 or 0)
elseif hversion == "1.0.3" then
gpio.setup(25, onoff and 1 or 0)
gpio.setup(26, onoff and 1 or 0)
end
end
4. ES8311 电源引脚的获取:
根据硬件版本返回 ES8311 控制器对应的电源引脚。
function pcb.es8311PowerPin()
if hversion == "1.0.2" then
return 25
elseif hversion == "1.0.3" then
return 2
end
end
5. 充电 IC CMD 引脚的获取:
此函数根据硬件版本返回充电 IC 的命令引脚。
function pcb.chargeCmdPin()
if hversion == "1.0.2" then
return 20
elseif hversion == "1.0.3" then
return 27
end
end
6. 出厂测试结果获取及版本号管理:
提供了获取当前硬件版本号和出厂测试结果的方法,以及设置硬件版本号的功能。
function pcb.test()
return test
end
function pcb.hver()
return hversion
end
function pcb.sethver(ver)
hversion = ver
end
6.2.3 总结说明
整段代码的主要功能是提供对印刷电路板(PCB)相关硬件配置和状态的管理。通过读取 OTP 存储区,程序能够获取设备的特定参数(如版本号和出厂测试结果)。此外,它还实现对 GNSS 电源、ES8311 音频编解码器以及充电 IC 的控制接口,根据不同的硬件版本提供不同的引脚控制方案。
6.3 batteryManage.lua 中代码介绍
6.3.1 代码说明
这段代码是一个电池管理模块的实现,主要用于监控和管理电池状态,包括电压检测、充电状态判断、电量计算和自动关机功能。
6.3.2 代码逐步解析
1. 模块定义
创建一个名为
M
的模块,定义模块名称为“batteryManage”。
local M = {}
M.moduleName = "batteryManage"
2. 引入库
引入了
sys
和sysplus
库,这些库提供了系统和附加功能的支持。
sys = require "sys"
sysplus = require "sysplus"
3. 初始化状态变量
M.vbat
: 当前电池电压。M.batteryPercent
: 电池电量百分比,初始为 50。M.isCharge
: 标识是否正在充电。M.BATTERY_UPDATE_INTERVAL
: 电池信息更新的时间间隔(秒)。M.noChargeDuration
: 记录未插入电源的时间。M.CHARGE_THRESHOLD_TIME
: 未充电持续时间的阈值(2 分钟)。M.blueLed
和M.redLed
: 用于设置蓝灯和红灯的状态,分别用 GPIO 接口进行控制。
M.vbat = 0
M.batteryPercent = 50
M.isCharge = false
M.BATTERY_UPDATE_INTERVAL = 10
M.noChargeDuration = 0
M.CHARGE_THRESHOLD_TIME = 120
M.blueLed = gpio.setup(1, 0)
M.redLed = gpio.setup(16, 0)
4. 电池放电曲线
定义一个电池放电曲线数组,该数组存储对应电量的电压值,用于通过电压推算电量百分比。
M.battery = {4175, 4128, ... , 3269}
5. 重置未充电时长
重置未充电计时器的函数。
function M.resetNoChargeDuration()
M.noChargeDuration = 0
end
6. 关机函数
该函数用于发布关机信号,以请求系统关机。
function M.powerOff()
log.info("powerOff", "关机")
sys.publish("SYS_SHUTDOWN")
end
7. 充电状态检测
使用 GPIO 中断回调来检测充电状态,如果通过 GPIO 引脚检测到充电状态发生变化,将更新充电状态并检查电池状态。
function M.chargeCheck()
...
end
8. 电量百分比计算
根据当前电压
M.vbat
计算电池百分比。如果电压在放电曲线数组的范围内,则返回相应的电量百分比。
function M.mathBatteryPercent()
...
end
9. 定期检查电池状态
定期更新电池电量,读取电压并计算电量。如果电量低于 30%,且没有插入电源的时间超过 2 分钟,则调用关机函数。
function M.checkBattery()
...
end
10. 长按电源键关机
实现了长按电源键的关机逻辑,按下电源键 3 秒后进行关机,松开时取消关机。
function M.pwrkeyCb()
...
end
6.3.3 总结说明
整体而言,该模块负责监控电池的电压和充电状态。它能够定期更新电量百分比,并在必要时自动关机。此外,该模块还允许用户通过长按电源键来手动关机。其主要功能是确保设备在电量过低时保护系统不受损坏,同时提供充电状态的实时反馈。
6.3 main.lua 中代码介绍
6.3.1 代码说明
该文件中的代码使用 Lua 语言编写,主要用于管理和监控设备的电源和电池状态。
6.3.2 代码逐步解析
1. 项目和版本信息
这部分定义了项目名称和版本,并记录日志信息,便于后续的调试和维护。
PROJECT = "demo"
VERSION = "1.0.0"
log.info("main", PROJECT, VERSION)
2. 库的引入
在这里,引入了多个必要的库文件,包括系统管理库
sys
、电路板库pcb
、充电逻辑库和电池管理库。通过这些库,程序可以实现对系统的控制和管理。 特别说明:主要功能代码已经模块化到 batteryManage 库文件中。
sys = require "sys"
sysplus = require "sysplus"
pcb = require "pcb"
require "ChargeICLogic"
batteryManage = require "batteryManage"
3. 开机防抖
这部分代码用于防止开机时的抖动,并点亮红色指示灯,以表明设备正在启动。
pm.power(pm.PWK_MODE, true)
batteryManage.redLed(1) -- 默认开机时红灯亮
4. GPIO 设置
通过
gpio.setup
配置了两个引脚:一个用于监测充电状态,另一个用于电源键的回调。
gpio.setup(40, batteryManage.chargeCheck, gpio.PULLDOWN, gpio.BOTH) -- 充电状态引脚
gpio.setup(46, batteryManage.pwrkeyCb, gpio.PULLUP, gpio.BOTH) -- 电源键引脚
5. 关机处理
这段代码订阅了系统关机事件,当设备接收到关机信号时,会调用
pm.shutdown()
函数进行安全关机。
sys.subscribe("SYS_SHUTDOWN", function()
pm.shutdown()
end)
6. 启动初始检查
在系统启动时,首先进行一次电池充电状态检查,并设置一个定时器,每 60 秒更新一次电池电量信息。
batteryManage.chargeCheck()
sys.timerLoopStart(batteryManage.checkBattery, batteryManage.BATTERY_UPDATE_INTERVAL * 1000) --每60s更新一次电池电量
7. 日志输出
此段代码设置了一个定时器,每隔 5 秒输出一次当前电池状态的日志信息,包括电压、电池电量及充电状态,便于监控和调试。
sys.timerLoopStart(function()
log.info(batteryManage.moduleName, "当前电压:", batteryManage.vbat, "电池电量:", batteryManage.batteryPercent, "%", "充电状态:", batteryManage.isCharge and "正在充电" or "未充电")
end, 5000) -- 每5s打印一次状态信息
8. 程序运行
最后,
sys.run()
函数用于启动系统的主循环,让程序保持运行状态。
sys.run()
6.3.3 总结说明
该代码的主要功能是管理和监控嵌入式设备的电源与电池状态,具备开机防抖、充电状态检测、定时更新电池电量和记录日志等功能。
6.4 完整代码展示
此处只展示
batteryManage.lua
和main.lua
。其余完整代码请下载源码查看。
batteryManage.lua
local M = {}
M.moduleName = "batteryManage"
-- 引入必要的库文件(lua编写), 内部库不需要require
sys = require "sys"
sysplus = require "sysplus"
-- 当前vbat电压
M.vbat = 0
-- 电池电量百分比
M.batteryPercent = 50
-- 是否正在充电
M.isCharge = false
-- 电池电量更新间隔,单位为秒
M.BATTERY_UPDATE_INTERVAL = 10
-- 记录未插入电源的持续时间
M.noChargeDuration = 0
-- 充电阈值时间,单位为秒
M.CHARGE_THRESHOLD_TIME = 120
-- 蓝灯状态
M.blueLed = gpio.setup(1, 0)
-- 红灯状态
M.redLed = gpio.setup(16, 0)
-- 电池放电曲线(根据您的需求调整)
M.battery = {4175, 4128, 4108, 4093, 4079, 4067, 4055, 4043, 4031, 4019, 4007, 3995, 3984, 3971, 3960, 3947, 3936, 3924, 3913, 3901, 3890, 3878, 3866, 3856, 3845, 3834, 3823, 3812, 3801, 3790, 3781, 3769, 3758, 3749, 3738, 3728, 3718, 3708, 3699, 3688, 3679, 3671, 3661, 3652, 3644, 3636, 3628,
3620, 3613, 3605, 3599, 3592, 3585, 3579, 3573, 3568, 3562, 3557, 3552, 3547, 3542, 3537, 3532, 3527, 3523, 3519, 3515, 3510, 3505, 3501, 3497, 3492, 3488, 3484, 3479, 3475, 3470, 3466, 3461, 3457, 3452, 3447, 3442, 3436, 3431, 3425, 3420, 3414, 3408, 3401, 3394, 3387, 3379, 3371,
3362, 3352, 3341, 3327, 3312, 3294, 3269}
function M.resetNoChargeDuration()
M.noChargeDuration = 0 -- 重置未充电计时器
end
-- 发布关机消息,进行关机
function M.powerOff()
log.info("powerOff", "关机")
sys.publish("SYS_SHUTDOWN")
end
-- gpio中断回调(用于充电状态检测)
function M.chargeCheck()
-- 检测充电状态
if gpio.get(40) == 0 then
M.blueLed(0)
if M.isCharge then
M.isCharge = false
M.checkBattery() -- 检查电池状态
end
else
M.blueLed(1)
if not M.isCharge then
M.isCharge = true
M.checkBattery() -- 检查电池状态
end
end
end
-- 通过当前电压推算电量百分比
function M.mathBatteryPercent()
if M.vbat >= M.battery[1] then
return 100
end
if M.vbat <= M.battery[#M.battery] then
return 0
end
for i = 1, #M.battery do
if M.vbat <= M.battery[i] and M.vbat > M.battery[i + 1] then
return (100 - i)
end
end
end
-- 电池电量周期性更新,60s更新一次,且如果电量低于30%,并且2分钟没有插入电源,则关机
function M.checkBattery()
adc.open(adc.CH_VBAT) -- 打开ADC通道
local tmp = adc.get(adc.CH_VBAT) -- 读取VBAT电压
adc.close(adc.CH_VBAT) -- 关闭ADC通道
if M.vbat == 0 then -- 初始值
M.vbat = tmp
else
if tmp - M.vbat > 100 then
log.info("vbat", "电压跳变!!!", M.vbat, "-->", tmp)
M.vbat = M.vbat + 5
else
M.vbat = tmp
end
end
M.batteryPercent = M.mathBatteryPercent() -- 计算电池百分比
if M.batteryPercent <= 30 then
if M.isCharge then
M.resetNoChargeDuration() -- 如果正在充电,重置计时器
else
M.noChargeDuration = M.noChargeDuration + M.BATTERY_UPDATE_INTERVAL -- 未充电计时器累加
if M.noChargeDuration >= M.CHARGE_THRESHOLD_TIME then
M.powerOff() -- 如果未插入电源超过2分钟,则关机
end
end
else
M.resetNoChargeDuration() -- 电量正常,重置计时器
end
end
-- 长按电源键关机
function M.pwrkeyCb()
if gpio.get(46) == 1 then
log.info("按键丢手")
if sys.timerIsActive(M.powerOff) then
sys.timerStop(M.powerOff)
sys.publish("EXIT_FLYMODE") -- 取消关机
end
else
log.info("按键按下")
sys.timerStart(M.powerOff, 3000) -- 长按3秒关机
end
end
return M
main.lua
-- LuaTools需要PROJECT和VERSION这两个信息
PROJECT = "demo"
VERSION = "1.0.0"
log.info("main", PROJECT, VERSION)
-- 引入必要的库文件(lua编写), 内部库不需要require
sys = require "sys"
sysplus = require "sysplus"
pcb = require "pcb"
require "ChargeICLogic"
batteryManage = require "batteryManage"
-- 开机防抖
pm.power(pm.PWK_MODE, true)
batteryManage.redLed(1) -- 默认开机时红灯亮
-- GPIO 设置
gpio.setup(40, batteryManage.chargeCheck, gpio.PULLDOWN, gpio.BOTH) -- 充电状态引脚
gpio.setup(46, batteryManage.pwrkeyCb, gpio.PULLUP, gpio.BOTH) -- 电源键引脚
-- 关机
sys.subscribe("SYS_SHUTDOWN", function()
pm.shutdown()
end)
-- 启动初始检查
batteryManage.chargeCheck()
sys.timerLoopStart(batteryManage.checkBattery, batteryManage.BATTERY_UPDATE_INTERVAL * 1000) --每60s更新一次电池电量
-- 日志信息输出(可选)
sys.timerLoopStart(function()
log.info(batteryManage.moduleName, "当前电压:", batteryManage.vbat, "电池电量:", batteryManage.batteryPercent, "%", "充电状态:", batteryManage.isCharge and "正在充电" or "未充电")
end, 5000) -- 每5s打印一次状态信息
-- 用户代码已结束---------------------------------------------
-- 结尾总是这一句
sys.run()
6.5 运行结果展示
通过 Luatoos 工具查看
七、总结
本文介绍了电源管理系统的基本概念、目标以及在实际应用中的实现方式。通过深入分析电源管理的各个功能模块,我们了解了电量监测、充电检测、自动关机和用户接口等关键功能。这些功能共同构成了一个高效且智能的电源管理系统,能够显著提升设备的性能和用户满意度。
在电源管理实践中,合理的策略和有效的代码实施是成功的关键。通过实时监测电池状态和智能控制电源操作,不仅能够延长设备的使用时间,还能确保设备在关键时刻的稳定性与可靠性。这对于以移动设备和嵌入式系统为主的应用场景尤其重要。
未来,我们可以继续探索更为先进的电源管理技术,比如基于人工智能的预测分析和优化算法,以便进一步提高电源管理的智能化水平。这将为设备的使用者带来更佳的体验,使电源管理成为每一款电子设备中不可或缺的一部分。
八、扩展
九、常见问题
1. 设备无法开启或频繁自动关机
检查电池电量是否低于安全工作水平,确保设备充电。如果电量很低,请连接电源并充电一段时间再尝试开机。
2. 电池电量显示不准确
确保电池电压监测模块正常工作,检查 ADC 通道是否正确配置。如有必要,重新校准电池电量百分比计算的映射表。
3. 充电状态无法正确识别
检查充电检测的 GPIO 引脚连接是否正常,确认是否存在接触不良或线路损坏的问题。此外,确保所用充电器和数据线与设备兼容。
4. 系统在充电时无法正常运行
检查是否有其他程序或任务占用过多资源,导致系统不稳定。可以考虑优化系统任务的优先级或关闭不必要的功能模块。
5. 长按电源键无反应
确认电源键的 GPIO 引脚连接正常,确保其可被正常识别。如果仍然无效,请检查相关代码对电源键的事件处理是否正确。
6. 设备发热严重
设备发热可能是由于充电速率过高或设备运行负载过重引起的。建议降低负载、优化代码,或调整充电策略。
7. 无法更新固件或脚本
检查 USB 连接是否正常,确保 Luatools 工具正确识别设备。注意遵循烧录步骤,并确保所用的固件版本与硬件兼容。
给读者的话
本篇文章由
马梦阳
开发; 本篇文章描述的内容,如果有错误、细节缺失、细节不清晰或者其他任何问题,总之就是无法解决您遇到的问题; 请登录合宙技术交流论坛,点击 此处放文档链接 用截图标注 + 文字描述的方式跟帖回复,记录清楚您发现的问题; 我们会迅速核实并且修改文档; 同时也会为您累计找错积分,您还可能赢取月度找错奖金!