一般手机设计待机电量时, 比如有**4格5档(4-3-2-1-0)**的电量指示。
由于要考虑到电池使用一段时间(比如1年)后, 其放电平台会降低,上述的比例肯定会失调。
所以需要考虑一点点这方面的余量.以新电池的60%-40%-20%-5%这样的比例进行设计。
4.20V~3.90V满格
3.90V~3.80V三格
3.80V~3.72V两格
3.72V~3.65V一格
3.65以下,低电压告警。
虽然在使用新电池时, 第一格会待机比较长的时间, 最后一格待机比较短。但是当这个电池使用个一年半载后, 其容量分布就比较接近均分的情况。
mAh:电池容量的计量单位;
库仑的国际标准单位为电流乘于时间的安培秒. 1mAh=0.001安培*3600秒=3.6安培秒=3.6库仑;
库仑计的芯片,即电量计量芯片是装在手机电池里面的,通常是与锂离子电池的保护线路设计在一起。
基本原理:芯片上集成了一个取样电阻,当流过不同电流后产生不同的压差,芯片就对这个电压(实际转换为电流)和时间进行积分,得到用户使用时的正确电量(注意,电量的单位是mAh),该芯片通过实时积分得到容量以后,把容量(单位是mAh)数据存储在芯片的EEPROM中,并根据手机的需求,通过通讯线传递给手机.那么手机就得到了这块电池的准确容量。
在库仑计芯片的存储器里面通常有如下的基本电池信息
▲电池的初始容量(mAh),即额定容量,一个电池完全充放后得到的容量
▲电池的当前容量(mAh),处于使用状态是的电池容量
▲当前流经的电流(mA),即手机的电流损耗
例子:一块额定容量为600mAh的电池,如果当前电池容量只有456mAh,手机就显示
456/600=76%;
电池额定容量调整
1、电池循环充电次数(电池使用率)会影响到电池的额定容量
如:比如初始容量是600mAh的电池,在100次循环以后,其实际容量已经变成500mAh了,如果在进行容量显示是仍然按照600mAh这个数来计算的话,势必造成电池永远充不饱这个问题.。
解决措施:库仑计的里面还有一个容量对使用次数调整的算法,会根据电池循环次数调整其实际容量。
2、电池使用温度会影响到电池的可用容量
如:比如在25度时,电池可以得到几乎100%的可用容量,而在0度是,电池只能放出80%的可用容量。
解决措施:库仑计里面还有一个容量对温度调整的算法,会根据电池的实际温度进行可用容量调整;
请您定期的对你所用的电池进行一次完全的充分,以便库仑计进行容量调整和归一化的进行.确保库仑计一直工作在最佳状态。
基于LTC2941芯片进行库仑计法检测电池电量 对于这个将不会做过多的说明;一切的说明都不如直接看芯片手册;总的来说就是使用IIC通信进行读写芯片中相应的寄存器;
这里只做简要说明,具体看后面上传的中英文芯片数据手册;
1)、LTC2941芯片寄存器
A:状态寄存器;
B:控制寄存器;
C:累积电荷寄存器(高八位);
D:累积电荷寄存器(低八位);
E:充电阈值高MSB;
F:充电阈值高LSB;
G:充电阈值低MSB;
H:充电阈值低LSB;
(寄存器的描述请看手册)
2)、电池容量计算公式
QBAT = qLSB(C*256 + D)
Qlsb:累积电荷(寄存器C,D)的最低有效位(qLSB);
Rsense:外部检测电阻值;
M:可编程的预分频器(1-128);
Imax:应用的最大电流;
请注意,当预分频器设置为其默认值M =128时,1mAh = 3.6A•s=3.6C(库仑)。
3)、IIC驱动程序;
//系统时钟为24M时 //count = 200时,时间约等于100us void delayNop(u32 count) {while(count -- > 0){__NOP();} } 123456789
注意:经过测试,该IIC通讯读写有问题;建议自己修改,但是下面的LTC2941的时序没有问题;
/*****************************IIC通信协议***************************/ #define _IIC11 #define _IIC20 #define IIC1_SCLPB6 #define IIC1_SDAPB7 #define IIC2_SCLPB10 #define IIC2_SDAPB11 #if _IIC1 #define SDA_IN(){GPIOB->CRL &= 0X0FFFFFFF; GPIOB->CRL |= (u32)8<<28;} #define SDA_OUT(){GPIOB->CRL &= 0X0FFFFFFF; GPIOB->CRL |= (u32)3<<28;} #endif #if _IIC2 #define SDA_IN(){GPIOB->CRH &= 0XFFFF0FFF; GPIOB->CRH |= (u32)8<<12;} #define SDA_OUT(){GPIOB->CRH &= 0XFFFF0FFF; GPIOB->CRH |= (u32)3<<12;} #endif #define IIC1_SCL_HighwriteGpioHigh(IIC1_SCL) #define IIC1_SCL_LowwriteGpioLow(IIC1_SCL) #define IIC1_SDA_HighwriteGpioHigh(IIC1_SDA) #define IIC1_SDA_LowwriteGpioLow(IIC1_SDA) #define IIC2_SCL_HighwriteGpioHigh(IIC2_SCL) #define IIC2_SCL_LowwriteGpioLow(IIC2_SCL) #define IIC2_SDA_HighwriteGpioHigh(IIC2_SDA) #define IIC2_SDA_LowwriteGpioLow(IIC2_SDA) void iicStart(void) {SDA_OUT(); //sda线输出IIC1_SCL_High;IIC1_SDA_High;delayNop(2);IIC1_SDA_Low;delayNop(2);IIC1_SCL_Low; //钳住I2C总线,准备发送或接收数据 } void iicStop(void) {SDA_OUT(); //sda线输出IIC1_SDA_Low;IIC1_SCL_Low;delayNop(2);IIC1_SCL_High;IIC1_SDA_High;delayNop(2); } u8 iicWaitAck(void) {u8 errorAck = 0;SDA_IN();IIC1_SCL_High;delayNop(2);IIC1_SDA_High;delayNop(2);while( GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_7) == Bit_SET ){errorAck++;if(errorAck > 250){iicStop();return 0;}}IIC1_SCL_Low;return 1; } //产生应答 void iicACK(void) {IIC1_SCL_Low;SDA_OUT();IIC1_SDA_Low;delayNop(2);IIC1_SCL_High;delayNop(2);IIC1_SCL_Low; } void iicNOack(void) {IIC1_SCL_Low;SDA_OUT();IIC1_SDA_High;delayNop(2);IIC1_SCL_High;delayNop(2);IIC1_SCL_Low; } void iicWrite_Byte(u8 byte) {u8 i;SDA_OUT();IIC1_SCL_Low;for(i = 0; i < 8; i++){if( (byte&0x80) == 0x80 ){IIC1_SDA_High;}else{IIC1_SDA_Low;}byte <<= 1;delayNop(2);IIC1_SCL_High;delayNop(2);IIC1_SCL_Low;delayNop(2);} } //读1个字节(高位开始读),ack=1时,发送ACK,ack=0,发送nACK //在C语言中x<<=1等于x=x<<1,是把x左移1位以后值保存回x里,x发生变化了 u8 iicRead_Byte(unsigned char ack) {u8 i;u8 recvByte = 0;SDA_IN();for(i = 0; i < 8; i++){IIC1_SCL_Low;delayNop(2);recvByte <<= 1;//高位开始读,所以左移if( GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_7) == Bit_SET ){recvByte |= 0x01;}delayNop(2);}if(ack){iicACK();}else{iicNOack();}return recvByte; }
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153/***************************** LTC2941 ***************************/ #define ADDR_DeviceWrite0xC8 #define ADDR_DeviceRead0xC9 //A:状态寄存器 #define ADDR_A0x00 //B:控制寄存器 #define ADDR_B0x01 //CD:累积电荷寄存器 #define ADDR_C0x02 #define ADDR_D0x03 //EF:充电阀值高 #define ADDR_E0x04 #define ADDR_F0x05 //GH:充电阀值低 #define ADDR_G0x06 #define ADDR_H0x07 //对寄存器B进行写0xFC操作; //警报电压:3v(11) //预分频:128(111) //充电完成模式(10); //关掉模拟;(0) void LTC2941_writeB(u8 data) {iicStart();iicWrite_Byte(ADDR_DeviceWrite);//11001000delayNop(5);if(iicWaitAck() == 0 ){iicStop();return;}iicWrite_Byte(ADDR_B);//o1hdelayNop(5);if(iicWaitAck() == 0 ){iicStop();return;}iicWrite_Byte(data);delayNop(5);if(iicWaitAck() == 0 ){iicStop();return;}iicStop(); } //对寄存器CD EF GF 进行写操作; //CD默认:7FFF; 充电完成后:FFFF //EF:电池满电量提醒:4200mv //GH:电池低电量提醒:3600mv void LTC2941_writeTwoByte(u8 addrRegister, u8 Qmsb, u8 Qlsb) {iicStart();iicWrite_Byte(ADDR_DeviceWrite);//11001000delayNop(3);if(iicWaitAck() == 0 ){iicStop();return;}iicWrite_Byte(addrRegister);//o2h / 04h / 06hdelayNop(3);if(iicWaitAck() == 0 ){iicStop();return;}iicWrite_Byte(Qmsb);delayNop(3);if(iicWaitAck() == 0 ){iicStop();return;}iicWrite_Byte(Qlsb);delayNop(5);if(iicWaitAck() == 0 ){iicStop();return;}iicStop(); } //A[7]:芯片识别; 1 : LTC2941; 0 : LTC2942; //A[5]:指示累积电荷的值达到顶部或底部。 //A[3]:指示累积电荷值超过了电荷阈值上限。 //A[2]:指示累积电荷值下降到电量阈值下限以下。 //A[1]:VBAT警报指示电池电压(SENSE-)下降低于选定的VBAT阈值。 //A[0]: u8 LTC2941_readA(void) {u8 receByte = 0;iicStart();iicWrite_Byte(ADDR_DeviceWrite);//11001000delayNop(5);if(iicWaitAck() == 0 ){iicStop();return 0;}iicWrite_Byte(ADDR_A);//o0hdelayNop(5);if(iicWaitAck() == 0 ){iicStop();return 0;}iicStart();iicWrite_Byte(ADDR_DeviceRead);//11001001delayNop(5);if(iicWaitAck() == 0 ){iicStop();return 0;}receByte = iicRead_Byte(0);iicStop();return receByte; } u16 LTC2941_readTwoByte(u8 addrRegister) {u16 receTwoByte = 0;u16 Qmsb = 0;u8 Qlsb = 0;iicStart();iicWrite_Byte(ADDR_DeviceWrite);//11001000delayNop(3);if(iicWaitAck() == 0 ){iicStop();return 0;}iicWrite_Byte(addrRegister);//o2h / 04h / 06hdelayNop(3);if(iicWaitAck() == 0 ){iicStop();return 0;}iicStart();iicWrite_Byte(ADDR_DeviceRead);//11001001delayNop(3);if(iicWaitAck() == 0 ){iicStop();return 0;}Qmsb = iicRead_Byte(1);Qlsb= iicRead_Byte(0);iicStop();receTwoByte = (Qmsb<<8) | Qlsb;return receTwoByte; } float Qlsb = 0; float QBAT = 0; float Rsense = 50; float M = 128; void getbatteryCapacity(void) {u16 recvData = 0;u8 C = 0;u8 D = 0;recvData = LTC2941_readTwoByte(ADDR_C);C = recvData >> 8;D = recvData&0x00ff;Qlsb = 0.085*(50/Rsense)*(M/128);QBAT = Qlsb*recvData;//得到电荷量后,进行电量显示 } //电池百分比:当前电量值除以总额度电量值; u8 getbatteryPercent(void) {u16 currentBAT = 0;//当前电量值u16 rateBAT = 0;//额定电量值currentBAT = LTC2941_readTwoByte(ADDR_C);rateBAT = LTC2941_readTwoByte(ADDR_E);return (u8)currentBAT/rateBAT; } void batteryWarn(void) {u8 receA = 0;u8 batteryHigh;u8 batteryLow;u8 batteryVeryLow;receA = LTC2941_readA();batteryVeryLow = (receA&0x02);batteryLow = (receA&0x04);batteryHigh = (receA&0x08);if(batteryLow){//低电量提醒}if(batteryHigh){//电池满电状态}if(batteryVeryLow){//警报指示电池电压(SENSE-)下降低于选定的VBAT阈值。} }
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241相关知识
如何检测土壤肥力(检测方法汇总)
病原微生物检测方法
土壤肥力检测方法和检测标准
病原微生物检测 微生物检测 分子生物学方法 飞凡检测 第三方检测机构
流感病毒检测方法研究进展
过敏源检测的方法
微生物检测方法知多少
农药残留检测方法
植物检疫 螨类检测方法
过敏原检测方法有哪些
网址: 电池电量检测方法 https://m.huajiangbk.com/newsview894893.html
上一篇: 【时序逻辑电路】——计数器 |
下一篇: 数字集成电路 |