1、锂电池介绍

锂离子电池由日本索尼公司于1990年最先开发成功。它是把锂离子嵌入碳(石油焦炭和石墨)中形成负极(传统锂电池用锂或锂合金作负极)。正极材料常用LixCoO2 ,也用 LixNiO2 ,和LixMnO4 ,电解液用LiPF6+二乙烯碳酸酯(EC)+二甲基碳酸酯(DMC)。

石油焦炭和石墨作负极材料无毒,且资源充足,锂离子嵌入碳中,克服了锂的高活性,解决了传统锂电池存在的安全问题,正极LixCoO2在充、放电性能和寿命上均能达到较高水平,使成本降低,总之锂离子电池的综合性能提高了。预计21世纪锂离子电池将会占有很大的市场。

锂离子二次电池充、放电时的反应式为LiCoO2+C=Li1-xCoO2+LixC

上图是锂电池容量和电压的对比图,可以看到当容量为0%时,电压最大,容量为100%时,电压最小,容量指的是电池还可以装下多少电量的意思。

过放:锂电池如果电压低于一定的门限,是不能够还原的,就假设,你有一个手机,放着几个月一直没有充电,如果电池电芯没有过放保护,那你的手机想再次充电就不行了。

过充:电池爆炸,大部分因为过充引起的,电芯做的不好,锂电池已经充满电了,没有做好门限保护,导致爆炸,但是爆炸的原因不只是这个,比如充电器短路,手机内部短路。

2、Android电池管理框架

问题:

有时候我们发现我电量50%掉到30%用了一个小时,但是同样的使用方法20%到关机,可能只用了半个小时,这就是涉及电池曲线或者电量器的问题

电池曲线:
有点低成本手机,或者平板电脑,没有电量器,就只能用ADC的值通过自己的算法来调整电池百分比,如果这个电池曲线调整的不好,就会出现上述问题。

电量器:
电量器也是用来计算电量的,但是有个芯片专门做这个事情,理论肯定比上面没有电量器的效果好

Android电池整体框架

2.1. Kernel 层

本层属于电池的驱动部分,负责与硬件进行交互,当电池电量信息发生变化时,生成相应的uevent,上报给用户层。

主要相关代码路径:

2.2. Healthd守护进程

本层在Android中属于Native层,healthd中运行一个系统服务batteryproperties,负责监听Kernel中上报的uevent,对电池电量进行实时监控。

主要相关代码路径:

2.3. BatteryService系统服务

本层提供了C++/Java两套接口来访问batteryproperties系统服务。 
本层的系统服务battery使用Java代码写成,运行在fwk的中SystemServer进程。 
该系统服务的主要作用是:监听batteryproperties服务中的电池信息变化消息,并将该消息以系统广播的形式转发至Android系统中各处。

主要相关代码路径:

\frameworks\native\services\batteryservice\IBatteryPropertiesRegistrar.cpp
\frameworks\native\services\batteryservice\IBatteryPropertiesListener.cpp
\frameworks\native\services\batteryservice\BatteryProperties.cpp
\frameworks\base\core\java\android\os\IBatteryPropertiesRegistrar.aidl
\frameworks\base\core\java\android\os\IBatteryPropertiesListener.aidl
\frameworks\base\core\java\android\os\BatteryProperties.java
\frameworks\base\services\core\java\com\android\server\BatteryService.java

2.4. SystemUI 应用

该部分属于电量上报的最后的环节。其主要工作是:监听系统广播Intent.ACTION_BATTERY_CHANGED,并对UI作出相应更新。

主要相关代码路径

\frameworks\base\packages\SystemUI\src\com\android\systemui\power\PowerUI.java

3、u-boot到kernel关机充电流程

Android充电有很多场景,关机充电是比较重要的一个需要了解的。

开机流程:

充电检测开机流程:

u-boot代码:

在u-boot里面,我们很多时候需要把一些信息传给kernel,目前用到的方法是command_line,

开机方式也是这样的。u-boot代码如下代码如下,kernel解析部分代码请到init/main.c下面去找

以后抽个文章专门说明下

510 #ifdef CONFIG_RK_SDCARD_BOOT_EN
511     if (StorageSDCardUpdateMode()) { /* sdcard undate */
512         snprintf(command_line, sizeof(command_line),
513                 "%s %s", command_line, "sdfwupdate");
514     }
515 #endif
516
517 #ifdef CONFIG_RK_UMS_BOOT_EN
518     if (StorageUMSUpdateMode()) { /* ums update */
519         snprintf(command_line, sizeof(command_line),
520                 "%s %s", command_line, "usbfwupdate");
521     }
522 #endif
523
524 #ifdef CONFIG_POWER_RK818
525     if (is_rk81x_fg_init() != 0) {
526         snprintf(command_line, sizeof(command_line),
527                 "%s %s", command_line, "loader_charged");
528     }
529 #endif
530     if (charge) {
531         snprintf(command_line, sizeof(command_line),
532                 "%s %s", command_line, "androidboot.mode=charger");
533     }
534
535 #if defined(CONFIG_LCD) && defined(CONFIG_RK_FB_DDREND)
536     /*
537      * uboot fb commandline: uboot_logo=<size>@<address>[:<offset>]
538      * size - fb size, address - fb address, offset - kernel bmp logo offset.
539      * offset is optional, depend on resource image has kernel_logo.bmp.
540      */
541     if (g_logo_on_state != 0) {
542         snprintf(command_line, sizeof(command_line),
543                 "%s uboot_logo=0x%08x@0x%08lx", command_line, CONFIG_RK_LCD_SIZE, gd->fb_base);
544 #if defined(CONFIG_KERNEL_LOGO)
545         if (g_rk_fb_size != -1)
546             snprintf(command_line, sizeof(command_line),
547                     "%s:0x%08x", command_line, g_rk_fb_size);
548 #endif /* CONFIG_KERNEL_LOGO */
549     }
550 #endif /* CONFIG_RK_FB_DDREND */
551
552 #if defined(CONFIG_RK_DEVICEINFO)
553     if (g_is_devinfo_load)
554         snprintf(command_line, sizeof(command_line),
555              "%s stb_devinfo=0x%08x@0x%08x",
556              command_line, SZ_8K, CONFIG_RKHDMI_PARAM_ADDR);
557 #endif /* CONFIG_RK_DEVICEINFO*/
558
559     snprintf(command_line, sizeof(command_line),
"./common/cmd_bootrk.c" 709L, 19309C

4、充电电流

电池充电有几个阶段

在软件上需要根据电池厂家的的不同阶段来给设置充电电流大小。

举个栗子:

我们用USB先连接PC机给手机充电,这时候适配器不是DC模式,充电电流如果设置过大,就会导致PC蓝屏。

而不同的电源适配器,D+ D- 的状态不同,被识别的状态也不一样,流程也会不同。

之前做的一个功能是,在恒压充电下,为了提高充电速度,我每间隔50ma提高充电电流,同时去检查电池两端的电压大小,如果电压降低到一定程度,就不会再增加充电电流。

5、kernel充电曲线代码

上面提到的问题,如果没有电量器的情况下,我们需要用数组来计算电池百分比,贴上这部分代码给大家看看,这部分代码可以适用于很多地方。

static struct batt_vol_cal  batt_table[BATT_NUM] = {{3400,3520},{3610,3715},{3672,3790},{3705,3825},{3734,3841},{3764,3864},{3808,3930},{3845,3997},{3964,4047},{4034,4144},{4120,4200},
};
static int rk29_adc_battery_voltage_to_capacity(struct rk29_adc_battery_data *bat, int BatVoltage)
{int i = 0;int capacity = 0;struct batt_vol_cal *p;p = batt_table;if (rk29_adc_battery_get_charge_level(bat)){  //chargeif(BatVoltage >= (p[BATT_NUM - 1].charge_vol)){capacity = 100;}   else{if(BatVoltage <= (p[0].charge_vol)){capacity = 0;}else{for(i = 0; i < BATT_NUM - 1; i++){if(((p[i].charge_vol) <= BatVoltage) && (BatVoltage < (p[i+1].charge_vol))){capacity =  i * 10 + ((BatVoltage - p[i].charge_vol) * 10) / (p[i+1].charge_vol- p[i].charge_vol);break;}}}  }}else{  //dischargeif(BatVoltage >= (p[BATT_NUM - 1].dis_charge_vol)){capacity = 100;}   else{if(BatVoltage <= (p[0].dis_charge_vol)){capacity = 0;}else{for(i = 0; i < BATT_NUM - 1; i++){if(((p[i].dis_charge_vol) <= BatVoltage) && (BatVoltage < (p[i+1].dis_charge_vol))){capacity =   i * 10 + ((BatVoltage - p[i].dis_charge_vol) * 10) / (p[i+1].dis_charge_vol- p[i].dis_charge_vol); ;break;}}}  }}return capacity;
}static void rk29_adc_battery_capacity_samples(struct rk29_adc_battery_data *bat)
{int capacity = 0;struct rk29_adc_battery_platform_data *pdata = bat->pdata;//充放电状态变化后,Buffer填满之前,不更新if (bat->bat_status_cnt < NUM_VOLTAGE_SAMPLE)  {bat->gBatCapacityDisChargeCnt = 0;bat->gBatCapacityChargeCnt    = 0;return;}capacity = rk29_adc_battery_voltage_to_capacity(bat, bat->bat_voltage);if (rk29_adc_battery_get_charge_level(bat)){if (capacity > bat->bat_capacity){//实际采样到的容量比显示的容量大,逐级上升if (++(bat->gBatCapacityDisChargeCnt) >= NUM_CHARGE_MIN_SAMPLE){bat->gBatCapacityDisChargeCnt  = 0;if (bat->bat_capacity < 99){bat->bat_capacity++;bat->bat_change  = 1;}}bat->gBatCapacityChargeCnt = 0;}else{  //   实际的容量比采样比 显示的容量小bat->gBatCapacityDisChargeCnt = 0;(bat->gBatCapacityChargeCnt)++;if (pdata->charge_ok_pin != INVALID_GPIO){if (gpio_get_value(pdata->charge_ok_pin) == pdata->charge_ok_level){//检测到电池充满标志,同时长时间内充电电压无变化,开始启动计时充电,快速上升容量if (bat->gBatCapacityChargeCnt >= NUM_CHARGE_MIN_SAMPLE){bat->gBatCapacityChargeCnt = 0;if (bat->bat_capacity < 99){bat->bat_capacity++;bat->bat_change  = 1;}}}else{
#if 0                    if (capacity > capacitytmp){//过程中如果电压有增长,定时器复位,防止定时器模拟充电比实际充电快gBatCapacityChargeCnt = 0;}else if (/*bat->bat_capacity >= 85) &&*/ (gBatCapacityChargeCnt > NUM_CHARGE_MAX_SAMPLE)){gBatCapacityChargeCnt = (NUM_CHARGE_MAX_SAMPLE - NUM_CHARGE_MID_SAMPLE);if (bat->bat_capacity < 99){bat->bat_capacity++;bat->bat_change  = 1;}}}
#else            //  防止电池老化后出现冲不满的情况,if (capacity > bat->capacitytmp){//过程中如果电压有增长,定时器复位,防止定时器模拟充电比实际充电快bat->gBatCapacityChargeCnt = 0;}else{if ((bat->bat_capacity >= 85) &&((bat->gBatCapacityChargeCnt) > NUM_CHARGE_MAX_SAMPLE)){bat->gBatCapacityChargeCnt = (NUM_CHARGE_MAX_SAMPLE - NUM_CHARGE_MID_SAMPLE);if (bat->bat_capacity < 99){bat->bat_capacity++;bat->bat_change  = 1;}}}}
#endif}else{//没有充电满检测脚,长时间内电压无变化,定时器模拟充电if (capacity > bat->capacitytmp){//过程中如果电压有增长,定时器复位,防止定时器模拟充电比实际充电快bat->gBatCapacityChargeCnt = 0;}else{if ((bat->bat_capacity >= 85) &&(bat->gBatCapacityChargeCnt > NUM_CHARGE_MAX_SAMPLE)){bat->gBatCapacityChargeCnt = (NUM_CHARGE_MAX_SAMPLE - NUM_CHARGE_MID_SAMPLE);if (bat->bat_capacity < 99){bat->bat_capacity++;bat->bat_change  = 1;}}}}            }}    else{   //放电时,只允许电压下降if (capacity < bat->bat_capacity){if (++(bat->gBatCapacityDisChargeCnt) >= NUM_DISCHARGE_MIN_SAMPLE){bat->gBatCapacityDisChargeCnt = 0;if (bat->bat_capacity > 0){bat->bat_capacity-- ;bat->bat_change  = 1;}}}else{bat->gBatCapacityDisChargeCnt = 0;}bat->gBatCapacityChargeCnt = 0;}bat->capacitytmp = capacity;
}

好了今天就这么多,具体问题还是要具体分析去看代码

推荐阅读:

专辑|Linux文章汇总

专辑|程序人生

嵌入式Linux

微信扫描二维码,关注我的公众号

Android系统充电系统介绍-预防手机充电爆炸相关推荐

  1. 边充电边玩手机会爆炸吗?

    边充电边玩手机会爆炸吗,回答这个问题,咱们先来看看手机爆炸的原因. 大部分的手机爆炸案例基本都是以下四种情况. 1.电芯机械损坏 电芯机械损坏,比如被锐器刺穿,拆装不当等等,这个也会导致内部短路.iP ...

  2. android 手机充电慢,导致手机充电太慢的四大原因及解决方法【图文教程】

    导语:在生活中,手机已经成为我们必不可少的一个工具,不论是娱乐还是工作都需要用到手机,手机给我们的生活带来了很多的便利,但是手机充电也成为我们的一个心头大患,很多关键时刻它就会没电,而且有些小伙伴还会 ...

  3. 安卓手机充电慢_手机充电慢?这些常识你可能还不知道

    手机用久了充电越来越慢?是电池不耐用了还是充电的姿势不对?看看下面的充电常识,这些你都知道吗? 使用非原装充电器 购买新手机时,配备的充电器是最适合手机充电的.如果使用非原装充电器,兼容性可能导致充电 ...

  4. android 系统(34)--关机充电图标修改

    关机充电图标修改 关机充电图标修改 关机充电main函数 函数set_draw_anim_mode 函数pthread_mutex_init 函数bootlogo_init 函数alarm_contr ...

  5. 华为充电显示android 是怎么回事,华为手机充电提示音教程如何改?Android设置换充电提示音教程...

    自苹果ios14充电提示音火了之后,很多安卓手机也增加了这个功能,比如vivo和OPPO,而其它厂牌的手机需要下载软件才能更改充电提示音,还是比较麻烦的,安卓手机充电提示音怎么设置?下面带来全面介绍. ...

  6. Android怎么自定义充电铃声,安卓手机充电提示音怎么改 Android设置换充电提示音教程...

    自苹果ios14充电提示音火了之后,很多安卓手机也增加了这个功能,比如vivo和OPPO,而其它厂牌的手机需要下载软件才能更改充电提示音,还是比较麻烦的,安卓手机充电提示音怎么设置?下面带来全面介绍. ...

  7. Android怎么自定义充电铃声,安卓手机充电提示音怎么修改?安卓充电提示音怎么设置自定义...

    最近苹果ios14可以自定义充电提示音了,相信很多安卓手机的用户朋友们也想要设置,那么安卓修改充电提示音怎么弄呢?安卓自定义充电提示音在哪设置呢?下面小编就为大家带来相关介绍,感兴趣的朋友们快来一起了 ...

  8. android 手机充电慢,华为手机充电慢怎么办?6个小妙招让手机快速充满电

    有些小伙伴反馈说自己的手机充电慢.充不进电,小编这就为你支招. 华为手机充电慢怎么办?6个小妙招让手机快速充满电 1.关机充电.在开机情况下充电,手机一边耗电一边充电,导致充电变慢.若希望充电速度更快 ...

  9. android 手机充电慢,安卓手机充电慢是怎么回事

    很多人的手机都是在使用一年到两年后出现手机电池不耐用或者手机充电出现问题,一般出现这种问题的原因可能多是由于电池老化或者是充电器等问题导致的.本篇文章告诉大家手机充电慢解决方法,希望对大家有所帮助. ...

最新文章

  1. 接口中可以有静态方法吗?
  2. websocket探究
  3. Spring自动扫描组件
  4. PHP 显示本机的外网IP
  5. EssentialC++
  6. OpenShift 4 Hands-on Lab (12) 使用配置参数和环境变量
  7. leetcode之每日温度
  8. ftp服务器、文件夹中带点文件删除方法
  9. 推荐系统实践:基于数据集MovieLens构造简单推荐系统
  10. 抖音api开放平台对接_抖音开放一键发布功能 第三方内容可分享至抖音
  11. mathtype下载之后word工具栏不出现
  12. python哥德巴赫猜想
  13. Laravel:whereIn子查询
  14. OCTAFX滑点滑到令人发指 现在出金也不给出金是黑平台无疑了
  15. IIS 支持 flv文件播放 (浏览器中可打开一flv文件)
  16. 【蓝桥杯】每日一题冲刺国赛
  17. K-Means聚类分析广告投放效果的改进(数据标准化、最佳K值的确定)
  18. 深入浅出安卓,如何从零学好移动开发
  19. 你知道常用在PCB线路板上的元器件有哪些吗?2021-08-13
  20. Java Swing实现动态图片

热门文章

  1. 基于nginx实现缓存功能及uptream模块详细使用方法
  2. 安装perl5.10.0
  3. 安装MyEclipse得心得
  4. 重写laravel的request的校验器
  5. 五分钟实现SpringBoot快速入门
  6. flink整合java,Flink使用SideOutPut替换Split实现分流
  7. 《操作系统》OS学习(十):进程控制
  8. dev gridview 打印列数过多_R语言:如何将多张统计图绘制在一张上面
  9. python compare excel_python简单操作excle的方法
  10. 八皇后问题分析与Java实现