嵌入式Linux充电电池管理

一 充电管理原理

话说Linux充电电池管理需要做什么呢?。。。好像一下没想到哦,这个没有标准答案。这个真的是要根据电池的特性来看,不同类型的电池,甚至不同型号的电池可能管理策略都不同。看了一下这次买的电池。4400mAh可充Li-ion锂电池。

查了一下锂电池大概有这些内容。

1. 设置充电参数
充电电压:充电结束电压应设置为4.2V。虽然供电电压为5V,但需要通过充电控制器来精确调节至4.2V以防止过充。
充电电流:常规充电电流可以设置为电池容量的0.5C至1C,即2200mA到4400mA。初始阶段可以使用较高电流(如1C),当电压接近4.2V时降低电流。
2. 充电阶段
恒流充电(CC):开始时使用固定的充电电流(例如4400mA),直到电池电压升至4.2V。
恒压充电(CV):当电池电压达到4.2V时,调整充电器输出,维持电压恒定在4.2V,同时电流会逐渐减小。当充电电流下降至电池容量的10%以下,如440mA,可以认为充电完成。
3. 放电参数
放电截止电压:通常设置为3.0V到3.2V。当电池电压低于此值时,应停止放电以避免过放。
最大放电电流:应依据电池规格设定,通常不应超过1C,除非电池明确支持更高放电率。
4. 保护措施
短路保护:在电池管理系统中集成短路保护,以防意外发生时电池受损。
温度监控:锂电池对温度敏感,充电和放电时应监控电池温度,避免在极端温度下操作。
过充和过放保护:确保电池管理系统可以在电压超出安全范围时断开电池连接。

总结一下就是:

1.涓流充电:涓流充电主要用于对完全放电的电池单元进行预充电。当电池电压低于约3V时,采用涓流充电。其中,C表示电池额定容量对电流的表示,比如电池的容量是1000mAh,1C就是1000mA的充电电流。
2.恒流充电:当电池电压升至涓流充电阈值以上时,开始采用恒流充电。恒流充电电流一般在0.2C-1.0C之间,不一定要求很精确,准恒流即可。
3.恒压充电:当电池电压升至4.2V时,恒压充电开始。恒压充电电流不再改变,此时电池的电压保持恒压。
4.充电终止:随着充电过程的继续,充电电流会逐渐减小。当其降低到0.01C时,可以考虑充电终止。

好像还有过充和过放的管理,以及设备启动电压的管理,这里就不多说啦。

二 实现方案

那么关注的地方就有两块,一个是电池状态的监控,还有一个就是充电电流电压的控制。之前看过一个ESP32的原理图(看看原理图(以ESP32游戏机为例)-CSDN博客),电池管理用的是一颗TP4056,大概是这样的。

用TP4056当然是简单方便,但是也存在设置不灵活的问题,回想最近做的商业级项目,都是可以直接在设备树中配置,应该是没用这种方法。于是参照了GPT的回答,用INA219来做一下精确控制。在这里,状态监控就是INA219,先从取状态说起吧。(怎么控制输出电流电压还没想好。。。)

手焊好INA219,往面包板上一怼,还是用老朋友树莓派3B,接线不麻烦,就不多说了。接上线就开始弄。(如果没有负载,电池的负极是接在树莓派的地,就是最下面黄色那根。切记!)

三 树莓派I2C的使用

这次用了一下树莓派带的I2C工具(可能linux,Android下都能用),真的方便极了。分别是i2cdetect和i2cdump。

先用sudo raspi-config打开I2C。

安装:

sudo apt-get install -y i2c-tools

查看挂载的所有I2C设备命令如下:

sudo i2cdetect -y 1

结果: 

这个好,可以看出地址就是0x40,连设备地址都不用去查了。

然后直接倒0x40的数据:

sudo i2cdump -f -y 1 0x40

结果:

这部分直接裸看就不行了,要么看数据手册,要么要看别人怎么操作的。

这里想用python来解析,但是运行说没有INA219的库,安装又报错。

这样要切换到虚拟环境装就可以了。、

python3 -m venv ~/venv
source ~/venv/bin/activate
pip install pi-ina219
~/venv/bin/python battery.py

battery.py

from ina219 import INA219
from ina219 import DeviceRangeError

SHUNT_OHMS = 0.1  # 根据你的分流电阻修改此值

ina = INA219(SHUNT_OHMS)
ina.configure()

try:
    print("Bus Voltage: %.3f V" % ina.voltage())
    print("Bus Current: %.3f mA" % ina.current())
    print("Power: %.3f mW" % ina.power())
    print("Shunt voltage: %.3f mV" % ina.shunt_voltage())
except DeviceRangeError as e:
    # 当前流超出INA219的测量范围
    print(e)

这样很快就可以读出来电压:

这里有个要注意的地方。只是测量电压的话,电池的正极是接INA219的VIN+,但是负极不是接VIN-(!!!),有负载的话才能接VIN-。没有负载的话是接在树莓派的地。。。刚刚就是接错了差点没把手烫起泡。。。

四 做成内核驱动

最后还是换成内核驱动来做吧。

battery.dts

/dts-v1/;
/plugin/;

/ {
    compatible = "brcm,bcm2835";

    fragment@0 {
        target = <&i2c1>;  // 确认I2C接口,可能需要根据实际情况调整
        __overlay__ {
            #address-cells = <1>;
            #size-cells = <0>;

            ina219@40 {
                compatible = "ti,ina219";
                reg = <0x40>;  // INA219设备的I2C地址
                shunt-resistor = <10000>;  // 分流电阻的值,单位微欧姆
            };
        };
    };
};

battery.c

#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/slab.h>

#define INA219_ADDR 0x40 // INA219 I2C地址
#define INA219_REG_BUS_VOLTAGE 0x02 // INA219电压寄存器地址

static struct i2c_client *ina219_client;

// 读取电压函数
static int read_battery_voltage(void)
{
    int ret;
    u16 voltage_raw;
    struct i2c_msg msgs[2];
    u8 reg = INA219_REG_BUS_VOLTAGE;
    u8 buf[2];

    // 向INA219的电压寄存器发送读取请求
    msgs[0].addr = ina219_client->addr;
    msgs[0].flags = 0; // 写
    msgs[0].len = 1;
    msgs[0].buf = &reg;

    // 读取返回的数据
    msgs[1].addr = ina219_client->addr;
    msgs[1].flags = I2C_M_RD; // 读
    msgs[1].len = 2;
    msgs[1].buf = buf;

    ret = i2c_transfer(ina219_client->adapter, msgs, 2);
    if (ret < 0) {
        pr_err("read INA219 Voltage failed.\n");
        return ret;
    }

    // 计算电压值
    voltage_raw = (buf[0] << 8) | buf[1];
    voltage_raw >>= 3; // 去掉3位右移

    // 返回以毫伏为单位的电压
    return voltage_raw * 4;
}

struct ina219_data {
    struct i2c_client *client;
    int shunt_resistor;
};

static int ina219_probe(struct i2c_client *client) {
    /*struct ina219_data *data;
    printk(KERN_CRIT "ina219_probe.\n");
    data = kzalloc(sizeof(struct ina219_data), GFP_KERNEL);
    if (!data)
        return -ENOMEM;

    data->client = client;
    // Assuming device property read is already correct
    if (device_property_read_u32(&client->dev, "shunt-resistor", &data->shunt_resistor)) {
        data->shunt_resistor = 10000;  // default value
    }

    i2c_set_clientdata(client, data);
    printk(KERN_INFO "INA219 at address %x initialized\n", client->addr); */
    ina219_client = client;
    pr_info("INA219 ina219_probe\n");

    // 读取并打印电压
    int voltage_mv = read_battery_voltage();
    if (voltage_mv >= 0) {
        pr_info("Bus Voltage: %d mV\n", voltage_mv);
    }

    return 0;
}

static void ina219_remove(struct i2c_client *client) {
    struct ina219_data *data = i2c_get_clientdata(client);
    kfree(data);
    printk(KERN_INFO "INA219 at address %x removed\n", client->addr);
}

static const struct of_device_id ina219_of_match[] = {
    { .compatible = "ti,ina219" },
    { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, ina219_of_match);

static const struct i2c_device_id ina219_id[] = {
    { "ina219", 0 },
    { }
};
MODULE_DEVICE_TABLE(i2c, ina219_id);

static struct i2c_driver ina219_driver = {
    .driver = {
        .name = "ina219",
        .of_match_table = of_match_ptr(ina219_of_match),
        .owner = THIS_MODULE,
    },
    .probe = ina219_probe,
    .remove = ina219_remove,
    .id_table = ina219_id,
};

module_i2c_driver(ina219_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("fanged");
MODULE_DESCRIPTION("INA219 Driver for Raspberry Pi");

Makefile

obj-m += battery.o

all:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

执行命令如下:

make
sudo dtc -I dts battery.dts -o battery.dtbo
sudo dtoverlay battery.dtbo
sudo insmod battery.ko
sudo rmmod battery.ko

马上就能看到电池的电压:

详细关于这个I2C的部分,可以参考我之前写的:总线学习1--I2C_ssd1315 修改i2c从机地址-CSDN博客

此外,关于Linux内核中的I2C使用,可以参考这个:

树莓派3B内核使用I2C-CSDN博客

=================================================

五 遗漏的部分

因为重点还是在软件,毕竟本人还是软件出身,而且现在也主要是学习为主,所以这次只做了电池电压监控。查了一下,如果要做充电的电源和电压控制,还要继续采购和外挂设备。

首先就是DC-DC,如果是高端一点的芯片,那么可以走I2C来控制。如果是普通的,那么就要全部走MOS管来控制,就是图中下面那个。

MOS管是通过PWM来控制,说是可以同时控制电流和电压,具体怎么搞还不是很清楚。

专业点的可以看看树莓派的电池HAT,PiJuice。

PiJuice/Hardware at master · PiSupply/PiJuice · GitHub

用的STM32来做主控,不能更高端了。

  1. Microcontroller is an ST Micro STM32F030CCT6 ARM Cortex-M0, 48MHz, F64KB, R8KB, I2C, SPI, USART, 2.4-3.6V
  2. Charge IC - BQ24160RGET Charger IC Lithium-Ion/Polymer, 2.5A, 4.2-10V
  3. Fuel gauge IC - LC709203FQH-01TWG Battery Fuel Gauge, 1-Cell Li-ion, 2.8%
  4. High side power-distribution switch - NCP380LMUAJAATBG Fixed/Adjustable Current‐Limiting Power‐Distribution Switch
  5. EEPROM - CAT24C32WI-GT3 EEPROM, I2C, 32KBIT, 400KHZ, 1V7-5V5

六 参考

在树莓派3B上使用电池供电需要考虑多个方面,包括电源管理、硬件连接和软件配置。以下是详细的步骤和建议:

1. 选择合适的电池
树莓派3B需要5V的电源供电,通常电流需求在2.5A左右。常见的电池选择包括:

锂聚合物电池(LiPo):需要一个降压转换器(如UBEC)将电压降到5V。
USB电池组(Power Bank):大多数USB电池组输出5V,可以直接使用。
2. 硬件连接
使用锂聚合物电池
选择电池:选择一个3.7V的LiPo电池。
降压转换器:使用一个降压转换器(如UBEC)将电池电压降到5V。
连接电池和转换器:将电池连接到降压转换器的输入端。
连接树莓派:将降压转换器的输出端连接到树莓派的5V和GND引脚。
使用USB电池组
选择电池组:选择一个输出5V、2.5A的USB电池组。
连接树莓派:使用USB线将电池组连接到树莓派的电源接口。
3. 电源管理
为了更好地管理电池供电,可以考虑以下措施:

电池监控:使用电池监控模块(如INA219)监控电池电压和电流。
低电量警告:设置低电量警告,防止电池过度放电。
4. 软件配置
安装电池监控软件
如果使用电池监控模块,可以安装相关的软件包来读取电池状态。


sudo apt-get update

sudo apt-get install python3-smbus i2c-tools

启用I2C接口
编辑配置文件:

sudo raspi-config

选择接口选项:
选择 Interfacing Options
选择 I2C
选择 Yes 启用I2C接口
重启树莓派:

sudo reboot

编写电池监控脚本
以下是一个使用Python读取INA219模块数据的示例脚本:


import smbus

import time

# INA219 I2C地址

INA219_ADDRESS = 0x40

# 初始化I2C总线

bus = smbus.SMBus(1)

def read_voltage():

# 读取电压寄存器

voltage_reg = bus.read_word_data(INA219_ADDRESS, 0x02)

# 交换字节顺序

voltage = ((voltage_reg & 0xFF) << 8) | (voltage_reg >> 8)

# 转换为电压值

voltage = voltage * 0.001

return voltage

while True:

voltage = read_voltage()

print(f"Battery Voltage: {voltage:.2f} V")

time.sleep(1)

5. 优化电源消耗
为了延长电池寿命,可以采取以下措施:

禁用不必要的服务:禁用不必要的系统服务和进程。
降低CPU频率:通过动态频率调节(DVFS)降低CPU频率。
关闭未使用的外设:关闭未使用的外设(如HDMI、WiFi、蓝牙)。
禁用不必要的服务

sudo systemctl disable <service_name>

降低CPU频率
编辑 /boot/config.txt 文件,添加以下行:
arm_freq=600

关闭HDMI
/opt/vc/bin/tvservice -o

总结
通过选择合适的电池、正确连接硬件、安装电池监控软件和优化电源消耗,可以在树莓派3B上实现稳定的电池供电。上述步骤提供了一个全面的指南,帮助你在树莓派上实现电池供电。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值