Android系统充电系统介绍-预防手机充电爆炸

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/467586.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux物理内存初始化

背景Read the fucking source code! --By 鲁迅A picture is worth a thousand words. --By 高尔基说明&#xff1a;Kernel版本&#xff1a;4.14ARM64处理器&#xff0c;Contex-A53&#xff0c;双核使用工具&#xff1a;Source Insight 3.5&#xff0c; Visio1. 介绍让我们思考…

mysql中%3c%3e和=_Grafana+Prometheus 监控 MySQL

架构图环境IP环境需装软件192.168.0.237mysql-5.7.20node_exporter-0.15.2.linux-amd64.tar.gzmysqld_exporter-0.10.0.linux-amd64.tar.gz192.168.0.248grafanaprometheusprometheus-2.1.0.linux-amd64.tar.gznode_exporter-0.15.2.linux-amd64.tar.gzgrafana-4.6.3.linux-x64…

Linux CentOS7.0 (01)在Vmvare Workstation上 安装配置

一、新建虚拟机 1、创建新的虚拟机 -》 默认典型 -》选择安装介质 2、指定虚拟机名称、安装目录、磁盘容量大小 点击 “完成”&#xff0c;创建虚拟机&#xff01; 随后虚拟机将自动启动安装过程。 二、安装linux 1、选择 English、English&#xff08;United States&#xff0…

i=1,为什么 (++i)+(++i)=6?

源码#include "stdio.h"int main(void) {int i 1;printf("%d\n",(i) (i));return 0; }执行weiqifabsp-ubuntu1804:~/c/undif$ gcc g.c && ./a.out 6 weiqifabsp-ubuntu1804:~/c/undif$为什么出现这个鬼现象&#xff1f;原因很简单&#xff0c;C语…

Android-HIDL实例解析

HIDL 简介“HAL interface definition language or HIDL (pronounced “hide-l”) is an interface description language (IDL) to specify the interface between a HAL and its users. It allows specifying types and method calls, collected into interfaces and package…

子矩阵(NOIP2014 普及组第四题)

描述 给出如下定义&#xff1a; 子矩阵&#xff1a;从一个矩阵当中选取某些行和某些列交叉位置所组成的新矩阵&#xff08;保持行与 列的相对顺序&#xff09;被称为原矩阵的一个子矩阵。 例如&#xff0c;下面左图中选取第 2、4 行和第 2、4、5 列交叉位置的元素得到一个 2*3 …

linux spinlock/rwlock/seqlock原理剖析(基于ARM64)

背景Kernel版本&#xff1a;4.14ARM64处理器&#xff0c;Contex-A53&#xff0c;双核使用工具&#xff1a;Source Insight 3.5&#xff0c; Visio1. 概述吹起并发机制研究的进攻号角了&#xff01;作为第一篇文章&#xff0c;应该提纲挈领的介绍下并发。什么是并发&#xff0c;…

爸爸都老了

今天是父亲节&#xff0c;早上韦泽楠去上绘画课&#xff0c;我睡了个回笼觉&#xff0c;一觉睡到了十一点。起来的时候老婆买了新鲜的荔枝和龙眼&#xff0c;当然我没有马上吃&#xff0c;我不是一个随便的男人&#xff0c;我刷了牙&#xff0c;洗了脸&#xff0c;再回到客厅慢…

java输出日志_java代码中如何正确使用loggger日志输出

java代码中如何正确使用loggger日志输出发布时间&#xff1a;2019-06-28作者&#xff1a;spider阅读(2980)当你遇到问题的时候&#xff0c;只能通过debug功能来确定问题&#xff0c;你应该考虑打日志&#xff0c;良好的系统&#xff0c;是可以通过日志进行问题定为的。使用slf4…

大学的多级放大电路,你交给老师了吗?

第一章 设计任务1.1项目名称&#xff1a;设计三极管多级音频放大电路本项目的主要内容是设计并实现三极管多级音频放大功能。该电路将所学习的三极管基本放大电路与功率放大电路有机结合。1.2项目设计说明&#xff08;1&#xff09;设计任务和要求使用常见的小功率三极管设计一…

第十四节TypeScript 联合类型

1、简介 联合类型可以通过管道&#xff08;|&#xff09;将变量设置多种类型&#xff0c;赋值时可以根据设置的类型来赋值。 注意&#xff1a;只能赋值指定的类型&#xff0c;如果赋值其它类型就会报错的。 2、创建联合类型的语法格式&#xff1a; Type1|Type2|Type3 实例&a…

Linux进程调度器-基础

背景Read the fucking source code! --By 鲁迅A picture is worth a thousand words. --By 高尔基说明&#xff1a;Kernel版本&#xff1a;4.14ARM64处理器&#xff0c;Contex-A53&#xff0c;双核使用工具&#xff1a;Source Insight 3.5&#xff0c; Visio1. 概述从这篇文章…

每天学习点--------第五天(2017-10-9) 摘要: 常用的集合

今天学习 java.util下面的软件包 包含 collection框架、遗留的coolection类、事件模型、日期和时间设施、国际化和各种工具类&#xff08;字符串标记生成器、随机数生成器和位数组&#xff09; 一、Collenction<.E> 接口 转载于:https://www.cnblogs.com/hanxue112253/p/…

Linux内存,先看这篇文章

内存大小计算我们拿32位系统来举个栗子2^32 ‭4,294,967,296‬ bytes‭4,294,967,296‬ bytes / 1024 ‭4,194,304‬ kbytes4,194,304‬ kbytes / 1024 ‭4,096‬ M‭4,096‬ M /1024 4G物理内存如何分页&#xff1f;分段和分页计算机内存管理的两种方式&#xff0c;这里我…

cloudstack java api_CloudStack API编程指引

前言本文阐述为CloudStack编写新API或者更新已存在API时应遵循的约定和编程指引。参考文档(暂略)介绍当你需要为CS添加新的API时&#xff0c;需要创建一个Request类和Response类(或者在扩展CS API功能时它的API Responese已经定义的情况下重用已经存在的API Response类)。编写C…

在ODM公司要不要跳槽到创业公司

读者朋友提问&#xff1a; 发哥&#xff0c;我现在在手机odm公司做指纹模块做了两三个月&#xff0c;基本天天加班到十点以后&#xff0c;后面要被调到camera团队&#xff0c;但是从这几个月的经历来看&#xff0c;感觉学到的不多&#xff0c;代码都是供应商写的&#xff0c;很…

安卓系统应用启动流程分析

随着移动开发的兴起&#xff0c;安卓系统的重要性愈加突显。本文简要介绍安卓系统上应用启动流程&#xff0c;对于应用开发、系统定制以及性能优化人员来说&#xff0c;熟悉应用启动流程会使得在今后的工作中更加得心应手&#xff0c;做到知其然&#xff0c;知其所以然。本文主…

物联网通信协议全解析

随着物联网设备数量的持续增加&#xff0c;这些设备之间的通信或连接已成为一个重要的思考课题。通信对物联网来说十分常用且关键&#xff0c;无论是近距离无线传输技术还是移动通信技术&#xff0c;都影响着物联网的发展。而在通信中&#xff0c;通信协议尤其重要&#xff0c;…

【长沙集训】2017.10.10

Adore 1.1 问题描述 小 w 偶然间遇到了一个 DAG。 这个 DAG 有 m 层&#xff0c;第一层只有1个源点&#xff0c;最后一层只有1个汇点&#xff0c;剩下的每一层都有 k 个 节点。 现在小 w 每次可以取反第 i(1 < i < n − 1) 层和第 i 1 层之间的连边。也就是把原本从 (i,…

Linux中断子系统之Workqueue

背景说明Kernel版本&#xff1a;4.14ARM64处理器&#xff0c;Contex-A53&#xff0c;双核使用工具&#xff1a;Source Insight 3.5&#xff0c; Visio1. 概述Workqueue工作队列是利用内核线程来异步执行工作任务的通用机制&#xff1b;Workqueue工作队列可以用作中断处理的Bott…